Home | History | Annotate | Line # | Download | only in i2c
i2c.c revision 1.14
      1  1.14        ad /*	$NetBSD: i2c.c,v 1.14 2007/07/09 21:00:32 ad 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.1   thorpej #include <sys/param.h>
     39   1.1   thorpej #include <sys/systm.h>
     40   1.1   thorpej #include <sys/device.h>
     41   1.1   thorpej #include <sys/event.h>
     42   1.1   thorpej #include <sys/conf.h>
     43  1.11  jmcneill #include <sys/malloc.h>
     44  1.11  jmcneill #include <sys/kthread.h>
     45  1.11  jmcneill #include <sys/proc.h>
     46  1.11  jmcneill #include <sys/kernel.h>
     47   1.1   thorpej 
     48   1.1   thorpej #include <dev/i2c/i2cvar.h>
     49   1.1   thorpej 
     50   1.1   thorpej #include "locators.h"
     51   1.1   thorpej 
     52   1.1   thorpej struct iic_softc {
     53   1.1   thorpej 	struct device sc_dev;
     54   1.1   thorpej 	i2c_tag_t sc_tag;
     55   1.6  jmcneill 	int sc_type;
     56   1.1   thorpej };
     57   1.1   thorpej 
     58  1.11  jmcneill static void	iic_smbus_intr_thread(void *);
     59  1.11  jmcneill 
     60   1.1   thorpej int
     61  1.10  christos iicbus_print(void *aux, const char *pnp)
     62   1.1   thorpej {
     63   1.1   thorpej 
     64   1.1   thorpej 	if (pnp != NULL)
     65   1.8  drochner 		aprint_normal("iic at %s", pnp);
     66   1.1   thorpej 
     67   1.1   thorpej 	return (UNCONF);
     68   1.1   thorpej }
     69   1.1   thorpej 
     70   1.1   thorpej static int
     71  1.10  christos iic_print(void *aux, const char *pnp)
     72   1.1   thorpej {
     73   1.1   thorpej 	struct i2c_attach_args *ia = aux;
     74   1.1   thorpej 
     75   1.6  jmcneill 	if (ia->ia_addr != (i2c_addr_t)-1)
     76   1.6  jmcneill 		aprint_normal(" addr 0x%x", ia->ia_addr);
     77   1.1   thorpej 
     78   1.1   thorpej 	return (UNCONF);
     79   1.1   thorpej }
     80   1.1   thorpej 
     81   1.1   thorpej static int
     82   1.3  drochner iic_search(struct device *parent, struct cfdata *cf,
     83  1.10  christos     const int *ldesc, void *aux)
     84   1.1   thorpej {
     85   1.1   thorpej 	struct iic_softc *sc = (void *) parent;
     86   1.1   thorpej 	struct i2c_attach_args ia;
     87   1.1   thorpej 
     88   1.1   thorpej 	ia.ia_tag = sc->sc_tag;
     89   1.1   thorpej 	ia.ia_addr = cf->cf_loc[IICCF_ADDR];
     90   1.1   thorpej 	ia.ia_size = cf->cf_loc[IICCF_SIZE];
     91   1.6  jmcneill 	ia.ia_type = sc->sc_type;
     92   1.1   thorpej 
     93   1.1   thorpej 	if (config_match(parent, cf, &ia) > 0)
     94   1.1   thorpej 		config_attach(parent, cf, &ia, iic_print);
     95   1.1   thorpej 
     96   1.1   thorpej 	return (0);
     97   1.1   thorpej }
     98   1.1   thorpej 
     99   1.1   thorpej static int
    100  1.10  christos iic_match(struct device *parent, struct cfdata *cf,
    101  1.10  christos     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.10  christos iic_attach(struct device *parent, struct device *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.14        ad 	ic->ic_devname = self->dv_xname;
    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.14        ad 		printf("%s: unable to create intr thread\n", ic->ic_devname);
    130   1.1   thorpej 
    131   1.1   thorpej 	/*
    132   1.2       wiz 	 * Attach all i2c devices described in the kernel
    133   1.1   thorpej 	 * configuration file.
    134   1.1   thorpej 	 */
    135   1.3  drochner 	config_search_ia(iic_search, self, "iic", NULL);
    136   1.1   thorpej }
    137   1.1   thorpej 
    138  1.11  jmcneill static void
    139  1.14        ad iic_smbus_intr_thread(void *aux)
    140  1.11  jmcneill {
    141  1.11  jmcneill 	i2c_tag_t ic;
    142  1.11  jmcneill 	struct ic_intr_list *il;
    143  1.11  jmcneill 	int rv;
    144  1.11  jmcneill 
    145  1.11  jmcneill 	ic = (i2c_tag_t)aux;
    146  1.11  jmcneill 	ic->ic_running = 1;
    147  1.11  jmcneill 	ic->ic_pending = 0;
    148  1.11  jmcneill 
    149  1.11  jmcneill 	while (ic->ic_running) {
    150  1.11  jmcneill 		if (ic->ic_pending == 0)
    151  1.11  jmcneill 			rv = tsleep(ic, PZERO, "iicintr", hz);
    152  1.11  jmcneill 		if (ic->ic_pending > 0) {
    153  1.11  jmcneill 			LIST_FOREACH(il, &(ic->ic_proc_list), il_next) {
    154  1.11  jmcneill 				(*il->il_intr)(il->il_intrarg);
    155  1.11  jmcneill 			}
    156  1.11  jmcneill 			ic->ic_pending--;
    157  1.11  jmcneill 		}
    158  1.11  jmcneill 	}
    159  1.11  jmcneill 
    160  1.11  jmcneill 	kthread_exit(0);
    161  1.11  jmcneill }
    162  1.11  jmcneill 
    163  1.11  jmcneill void *
    164  1.11  jmcneill iic_smbus_intr_establish(i2c_tag_t ic, int (*intr)(void *), void *intrarg)
    165  1.11  jmcneill {
    166  1.11  jmcneill 	struct ic_intr_list *il;
    167  1.11  jmcneill 
    168  1.11  jmcneill 	il = malloc(sizeof(struct ic_intr_list), M_DEVBUF, M_WAITOK);
    169  1.11  jmcneill 	if (il == NULL)
    170  1.11  jmcneill 		return NULL;
    171  1.11  jmcneill 
    172  1.11  jmcneill 	il->il_intr = intr;
    173  1.11  jmcneill 	il->il_intrarg = intrarg;
    174  1.11  jmcneill 
    175  1.11  jmcneill 	LIST_INSERT_HEAD(&(ic->ic_list), il, il_next);
    176  1.11  jmcneill 
    177  1.11  jmcneill 	return il;
    178  1.11  jmcneill }
    179  1.11  jmcneill 
    180  1.11  jmcneill void
    181  1.11  jmcneill iic_smbus_intr_disestablish(i2c_tag_t ic, void *hdl)
    182  1.11  jmcneill {
    183  1.11  jmcneill 	struct ic_intr_list *il;
    184  1.11  jmcneill 
    185  1.11  jmcneill 	il = (struct ic_intr_list *)hdl;
    186  1.11  jmcneill 
    187  1.11  jmcneill 	LIST_REMOVE(il, il_next);
    188  1.11  jmcneill 	free(il, M_DEVBUF);
    189  1.11  jmcneill 
    190  1.11  jmcneill 	return;
    191  1.11  jmcneill }
    192  1.11  jmcneill 
    193  1.11  jmcneill void *
    194  1.11  jmcneill iic_smbus_intr_establish_proc(i2c_tag_t ic, int (*intr)(void *), void *intrarg)
    195  1.11  jmcneill {
    196  1.11  jmcneill 	struct ic_intr_list *il;
    197  1.11  jmcneill 
    198  1.11  jmcneill 	il = malloc(sizeof(struct ic_intr_list), M_DEVBUF, M_WAITOK);
    199  1.11  jmcneill 	if (il == NULL)
    200  1.11  jmcneill 		return NULL;
    201  1.11  jmcneill 
    202  1.11  jmcneill 	il->il_intr = intr;
    203  1.11  jmcneill 	il->il_intrarg = intrarg;
    204  1.11  jmcneill 
    205  1.11  jmcneill 	LIST_INSERT_HEAD(&(ic->ic_proc_list), il, il_next);
    206  1.11  jmcneill 
    207  1.11  jmcneill 	return il;
    208  1.11  jmcneill }
    209  1.11  jmcneill 
    210  1.11  jmcneill void
    211  1.11  jmcneill iic_smbus_intr_disestablish_proc(i2c_tag_t ic, void *hdl)
    212  1.11  jmcneill {
    213  1.11  jmcneill 	struct ic_intr_list *il;
    214  1.11  jmcneill 
    215  1.11  jmcneill 	il = (struct ic_intr_list *)hdl;
    216  1.11  jmcneill 
    217  1.11  jmcneill 	LIST_REMOVE(il, il_next);
    218  1.11  jmcneill 	free(il, M_DEVBUF);
    219  1.11  jmcneill 
    220  1.11  jmcneill 	return;
    221  1.11  jmcneill }
    222  1.11  jmcneill 
    223  1.11  jmcneill int
    224  1.11  jmcneill iic_smbus_intr(i2c_tag_t ic)
    225  1.11  jmcneill {
    226  1.11  jmcneill 	struct ic_intr_list *il;
    227  1.11  jmcneill 
    228  1.11  jmcneill 	LIST_FOREACH(il, &(ic->ic_list), il_next) {
    229  1.11  jmcneill 		(*il->il_intr)(il->il_intrarg);
    230  1.11  jmcneill 	}
    231  1.11  jmcneill 
    232  1.11  jmcneill 	ic->ic_pending++;
    233  1.11  jmcneill 	wakeup(ic);
    234  1.11  jmcneill 
    235  1.11  jmcneill 	return 1;
    236  1.11  jmcneill }
    237  1.11  jmcneill 
    238   1.1   thorpej CFATTACH_DECL(iic, sizeof(struct iic_softc),
    239   1.1   thorpej     iic_match, iic_attach, NULL, NULL);
    240