Home | History | Annotate | Line # | Download | only in i2c
i2c.c revision 1.20
      1  1.20   xtraeme /*	$NetBSD: i2c.c,v 1.20 2008/05/04 15:26:29 xtraeme Exp $	*/
      2   1.1   thorpej 
      3   1.1   thorpej /*
      4   1.1   thorpej  * Copyright (c) 2003 Wasabi Systems, Inc.
      5   1.1   thorpej  * All rights reserved.
      6   1.1   thorpej  *
      7   1.1   thorpej  * Written by Jason R. Thorpe for Wasabi Systems, Inc.
      8   1.1   thorpej  *
      9   1.1   thorpej  * Redistribution and use in source and binary forms, with or without
     10   1.1   thorpej  * modification, are permitted provided that the following conditions
     11   1.1   thorpej  * are met:
     12   1.1   thorpej  * 1. Redistributions of source code must retain the above copyright
     13   1.1   thorpej  *    notice, this list of conditions and the following disclaimer.
     14   1.1   thorpej  * 2. Redistributions in binary form must reproduce the above copyright
     15   1.1   thorpej  *    notice, this list of conditions and the following disclaimer in the
     16   1.1   thorpej  *    documentation and/or other materials provided with the distribution.
     17   1.1   thorpej  * 3. All advertising materials mentioning features or use of this software
     18   1.1   thorpej  *    must display the following acknowledgement:
     19   1.1   thorpej  *      This product includes software developed for the NetBSD Project by
     20   1.1   thorpej  *      Wasabi Systems, Inc.
     21   1.1   thorpej  * 4. The name of Wasabi Systems, Inc. may not be used to endorse
     22   1.1   thorpej  *    or promote products derived from this software without specific prior
     23   1.1   thorpej  *    written permission.
     24   1.1   thorpej  *
     25   1.1   thorpej  * THIS SOFTWARE IS PROVIDED BY WASABI SYSTEMS, INC. ``AS IS'' AND
     26   1.1   thorpej  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
     27   1.1   thorpej  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     28   1.1   thorpej  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL WASABI SYSTEMS, INC
     29   1.1   thorpej  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
     30   1.1   thorpej  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
     31   1.1   thorpej  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
     32   1.1   thorpej  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
     33   1.1   thorpej  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
     34   1.1   thorpej  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
     35   1.1   thorpej  * POSSIBILITY OF SUCH DAMAGE.
     36   1.1   thorpej  */
     37   1.1   thorpej 
     38  1.18     lukem #include <sys/cdefs.h>
     39  1.20   xtraeme __KERNEL_RCSID(0, "$NetBSD: i2c.c,v 1.20 2008/05/04 15:26:29 xtraeme Exp $");
     40  1.18     lukem 
     41   1.1   thorpej #include <sys/param.h>
     42   1.1   thorpej #include <sys/systm.h>
     43   1.1   thorpej #include <sys/device.h>
     44   1.1   thorpej #include <sys/event.h>
     45   1.1   thorpej #include <sys/conf.h>
     46  1.11  jmcneill #include <sys/malloc.h>
     47  1.11  jmcneill #include <sys/kthread.h>
     48  1.11  jmcneill #include <sys/proc.h>
     49  1.11  jmcneill #include <sys/kernel.h>
     50   1.1   thorpej 
     51   1.1   thorpej #include <dev/i2c/i2cvar.h>
     52   1.1   thorpej 
     53   1.1   thorpej #include "locators.h"
     54   1.1   thorpej 
     55   1.1   thorpej struct iic_softc {
     56   1.1   thorpej 	i2c_tag_t sc_tag;
     57   1.6  jmcneill 	int sc_type;
     58   1.1   thorpej };
     59   1.1   thorpej 
     60  1.11  jmcneill static void	iic_smbus_intr_thread(void *);
     61  1.11  jmcneill 
     62   1.1   thorpej int
     63  1.10  christos iicbus_print(void *aux, const char *pnp)
     64   1.1   thorpej {
     65   1.1   thorpej 
     66   1.1   thorpej 	if (pnp != NULL)
     67   1.8  drochner 		aprint_normal("iic at %s", pnp);
     68   1.1   thorpej 
     69   1.1   thorpej 	return (UNCONF);
     70   1.1   thorpej }
     71   1.1   thorpej 
     72   1.1   thorpej static int
     73  1.10  christos iic_print(void *aux, const char *pnp)
     74   1.1   thorpej {
     75   1.1   thorpej 	struct i2c_attach_args *ia = aux;
     76   1.1   thorpej 
     77   1.6  jmcneill 	if (ia->ia_addr != (i2c_addr_t)-1)
     78   1.6  jmcneill 		aprint_normal(" addr 0x%x", ia->ia_addr);
     79   1.1   thorpej 
     80   1.1   thorpej 	return (UNCONF);
     81   1.1   thorpej }
     82   1.1   thorpej 
     83   1.1   thorpej static int
     84  1.20   xtraeme iic_search(device_t parent, cfdata_t cf, const int *ldesc, void *aux)
     85   1.1   thorpej {
     86  1.20   xtraeme 	struct iic_softc *sc = device_private(parent);
     87   1.1   thorpej 	struct i2c_attach_args ia;
     88   1.1   thorpej 
     89   1.1   thorpej 	ia.ia_tag = sc->sc_tag;
     90   1.1   thorpej 	ia.ia_addr = cf->cf_loc[IICCF_ADDR];
     91   1.1   thorpej 	ia.ia_size = cf->cf_loc[IICCF_SIZE];
     92   1.6  jmcneill 	ia.ia_type = sc->sc_type;
     93   1.1   thorpej 
     94   1.1   thorpej 	if (config_match(parent, cf, &ia) > 0)
     95   1.1   thorpej 		config_attach(parent, cf, &ia, iic_print);
     96   1.1   thorpej 
     97   1.1   thorpej 	return (0);
     98   1.1   thorpej }
     99   1.1   thorpej 
    100   1.1   thorpej static int
    101  1.20   xtraeme iic_match(device_t parent, cfdata_t cf, void *aux)
    102   1.1   thorpej {
    103   1.1   thorpej 
    104   1.8  drochner 	return (1);
    105   1.1   thorpej }
    106   1.1   thorpej 
    107   1.1   thorpej static void
    108  1.20   xtraeme iic_attach(device_t parent, device_t self, void *aux)
    109   1.1   thorpej {
    110   1.7   thorpej 	struct iic_softc *sc = device_private(self);
    111   1.1   thorpej 	struct i2cbus_attach_args *iba = aux;
    112  1.14        ad 	i2c_tag_t ic;
    113  1.14        ad 	int rv;
    114   1.1   thorpej 
    115   1.1   thorpej 	aprint_naive(": I2C bus\n");
    116   1.1   thorpej 	aprint_normal(": I2C bus\n");
    117   1.1   thorpej 
    118   1.1   thorpej 	sc->sc_tag = iba->iba_tag;
    119   1.6  jmcneill 	sc->sc_type = iba->iba_type;
    120  1.14        ad 	ic = sc->sc_tag;
    121  1.19    cegger 	ic->ic_devname = device_xname(self);
    122  1.11  jmcneill 
    123  1.13  jmcneill 	LIST_INIT(&(sc->sc_tag->ic_list));
    124  1.13  jmcneill 	LIST_INIT(&(sc->sc_tag->ic_proc_list));
    125  1.14        ad 
    126  1.14        ad 	rv = kthread_create(PRI_NONE, 0, NULL, iic_smbus_intr_thread,
    127  1.14        ad 	    ic, &ic->ic_intr_thread, "%s", ic->ic_devname);
    128  1.14        ad 	if (rv)
    129  1.20   xtraeme 		aprint_error_dev(self, "unable to create intr thread\n");
    130   1.1   thorpej 
    131  1.16     joerg #if notyet
    132  1.15       riz 	if (sc->sc_type == I2C_TYPE_SMBUS) {
    133  1.16     joerg 		int found = 0;
    134  1.16     joerg 		i2c_addr_t addr;
    135  1.16     joerg 		uint8_t cmd = 0, val;
    136  1.16     joerg 
    137  1.15       riz 		for (addr = 0x0; addr < 0x80; addr++) {
    138  1.15       riz 			iic_acquire_bus(ic, 0);
    139  1.15       riz 			if (iic_exec(ic, I2C_OP_READ_WITH_STOP, addr,
    140  1.15       riz 			    &cmd, 1, &val, 1, 0) == 0) {
    141  1.15       riz 				if (found == 0)
    142  1.15       riz 					aprint_normal("%s: devices at",
    143  1.15       riz 							ic->ic_devname);
    144  1.15       riz 				found++;
    145  1.15       riz 				aprint_normal(" 0x%02x", addr);
    146  1.15       riz 			}
    147  1.15       riz 			iic_release_bus(ic, 0);
    148  1.15       riz 		}
    149  1.15       riz 		if (found == 0)
    150  1.15       riz 			aprint_normal("%s: no devices found", ic->ic_devname);
    151  1.15       riz 		aprint_normal("\n");
    152  1.15       riz 	}
    153  1.16     joerg #endif
    154  1.15       riz 
    155  1.17  jmcneill 	if (!pmf_device_register(self, NULL, NULL))
    156  1.17  jmcneill 		aprint_error_dev(self, "couldn't establish power handler\n");
    157  1.17  jmcneill 
    158   1.1   thorpej 	/*
    159   1.2       wiz 	 * Attach all i2c devices described in the kernel
    160   1.1   thorpej 	 * configuration file.
    161   1.1   thorpej 	 */
    162   1.3  drochner 	config_search_ia(iic_search, self, "iic", NULL);
    163   1.1   thorpej }
    164   1.1   thorpej 
    165  1.11  jmcneill static void
    166  1.14        ad iic_smbus_intr_thread(void *aux)
    167  1.11  jmcneill {
    168  1.11  jmcneill 	i2c_tag_t ic;
    169  1.11  jmcneill 	struct ic_intr_list *il;
    170  1.11  jmcneill 	int rv;
    171  1.11  jmcneill 
    172  1.11  jmcneill 	ic = (i2c_tag_t)aux;
    173  1.11  jmcneill 	ic->ic_running = 1;
    174  1.11  jmcneill 	ic->ic_pending = 0;
    175  1.11  jmcneill 
    176  1.11  jmcneill 	while (ic->ic_running) {
    177  1.11  jmcneill 		if (ic->ic_pending == 0)
    178  1.11  jmcneill 			rv = tsleep(ic, PZERO, "iicintr", hz);
    179  1.11  jmcneill 		if (ic->ic_pending > 0) {
    180  1.11  jmcneill 			LIST_FOREACH(il, &(ic->ic_proc_list), il_next) {
    181  1.11  jmcneill 				(*il->il_intr)(il->il_intrarg);
    182  1.11  jmcneill 			}
    183  1.11  jmcneill 			ic->ic_pending--;
    184  1.11  jmcneill 		}
    185  1.11  jmcneill 	}
    186  1.11  jmcneill 
    187  1.11  jmcneill 	kthread_exit(0);
    188  1.11  jmcneill }
    189  1.11  jmcneill 
    190  1.11  jmcneill void *
    191  1.11  jmcneill iic_smbus_intr_establish(i2c_tag_t ic, int (*intr)(void *), void *intrarg)
    192  1.11  jmcneill {
    193  1.11  jmcneill 	struct ic_intr_list *il;
    194  1.11  jmcneill 
    195  1.11  jmcneill 	il = malloc(sizeof(struct ic_intr_list), M_DEVBUF, M_WAITOK);
    196  1.11  jmcneill 	if (il == NULL)
    197  1.11  jmcneill 		return NULL;
    198  1.11  jmcneill 
    199  1.11  jmcneill 	il->il_intr = intr;
    200  1.11  jmcneill 	il->il_intrarg = intrarg;
    201  1.11  jmcneill 
    202  1.11  jmcneill 	LIST_INSERT_HEAD(&(ic->ic_list), il, il_next);
    203  1.11  jmcneill 
    204  1.11  jmcneill 	return il;
    205  1.11  jmcneill }
    206  1.11  jmcneill 
    207  1.11  jmcneill void
    208  1.11  jmcneill iic_smbus_intr_disestablish(i2c_tag_t ic, void *hdl)
    209  1.11  jmcneill {
    210  1.11  jmcneill 	struct ic_intr_list *il;
    211  1.11  jmcneill 
    212  1.11  jmcneill 	il = (struct ic_intr_list *)hdl;
    213  1.11  jmcneill 
    214  1.11  jmcneill 	LIST_REMOVE(il, il_next);
    215  1.11  jmcneill 	free(il, M_DEVBUF);
    216  1.11  jmcneill 
    217  1.11  jmcneill 	return;
    218  1.11  jmcneill }
    219  1.11  jmcneill 
    220  1.11  jmcneill void *
    221  1.11  jmcneill iic_smbus_intr_establish_proc(i2c_tag_t ic, int (*intr)(void *), void *intrarg)
    222  1.11  jmcneill {
    223  1.11  jmcneill 	struct ic_intr_list *il;
    224  1.11  jmcneill 
    225  1.11  jmcneill 	il = malloc(sizeof(struct ic_intr_list), M_DEVBUF, M_WAITOK);
    226  1.11  jmcneill 	if (il == NULL)
    227  1.11  jmcneill 		return NULL;
    228  1.11  jmcneill 
    229  1.11  jmcneill 	il->il_intr = intr;
    230  1.11  jmcneill 	il->il_intrarg = intrarg;
    231  1.11  jmcneill 
    232  1.11  jmcneill 	LIST_INSERT_HEAD(&(ic->ic_proc_list), il, il_next);
    233  1.11  jmcneill 
    234  1.11  jmcneill 	return il;
    235  1.11  jmcneill }
    236  1.11  jmcneill 
    237  1.11  jmcneill void
    238  1.11  jmcneill iic_smbus_intr_disestablish_proc(i2c_tag_t ic, void *hdl)
    239  1.11  jmcneill {
    240  1.11  jmcneill 	struct ic_intr_list *il;
    241  1.11  jmcneill 
    242  1.11  jmcneill 	il = (struct ic_intr_list *)hdl;
    243  1.11  jmcneill 
    244  1.11  jmcneill 	LIST_REMOVE(il, il_next);
    245  1.11  jmcneill 	free(il, M_DEVBUF);
    246  1.11  jmcneill 
    247  1.11  jmcneill 	return;
    248  1.11  jmcneill }
    249  1.11  jmcneill 
    250  1.11  jmcneill int
    251  1.11  jmcneill iic_smbus_intr(i2c_tag_t ic)
    252  1.11  jmcneill {
    253  1.11  jmcneill 	struct ic_intr_list *il;
    254  1.11  jmcneill 
    255  1.11  jmcneill 	LIST_FOREACH(il, &(ic->ic_list), il_next) {
    256  1.11  jmcneill 		(*il->il_intr)(il->il_intrarg);
    257  1.11  jmcneill 	}
    258  1.11  jmcneill 
    259  1.11  jmcneill 	ic->ic_pending++;
    260  1.11  jmcneill 	wakeup(ic);
    261  1.11  jmcneill 
    262  1.11  jmcneill 	return 1;
    263  1.11  jmcneill }
    264  1.11  jmcneill 
    265  1.20   xtraeme CFATTACH_DECL_NEW(iic, sizeof(struct iic_softc),
    266   1.1   thorpej     iic_match, iic_attach, NULL, NULL);
    267