Source-Changes-HG archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

[src/trunk]: src/sys/dev/i2c Generic (device property based) framework for op...



details:   https://anonhg.NetBSD.org/src/rev/fe568d958ec7
branches:  trunk
changeset: 752506:fe568d958ec7
user:      martin <martin%NetBSD.org@localhost>
date:      Sun Feb 28 11:34:42 2010 +0000

description:
Generic (device property based) framework for optional direct configuration
of i2c devices, as discussed on tech-kern.

diffstat:

 sys/dev/i2c/i2c.c    |  136 ++++++++++++++++++++++++++++++++++++++++++++++++--
 sys/dev/i2c/i2cvar.h |   19 ++++++-
 2 files changed, 147 insertions(+), 8 deletions(-)

diffs (223 lines):

diff -r 527333fa0a62 -r fe568d958ec7 sys/dev/i2c/i2c.c
--- a/sys/dev/i2c/i2c.c Sun Feb 28 11:06:59 2010 +0000
+++ b/sys/dev/i2c/i2c.c Sun Feb 28 11:34:42 2010 +0000
@@ -1,4 +1,4 @@
-/*     $NetBSD: i2c.c,v 1.23 2009/02/03 16:41:31 pgoyette Exp $        */
+/*     $NetBSD: i2c.c,v 1.24 2010/02/28 11:34:42 martin Exp $  */
 
 /*
  * Copyright (c) 2003 Wasabi Systems, Inc.
@@ -36,7 +36,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: i2c.c,v 1.23 2009/02/03 16:41:31 pgoyette Exp $");
+__KERNEL_RCSID(0, "$NetBSD: i2c.c,v 1.24 2010/02/28 11:34:42 martin Exp $");
 
 #include <sys/param.h>
 #include <sys/systm.h>
@@ -59,6 +59,8 @@
 };
 
 static void    iic_smbus_intr_thread(void *);
+static void    iic_fill_compat(struct i2c_attach_args*, const char*,
+                       size_t, char **);
 
 int
 iicbus_print(void *aux, const char *pnp)
@@ -71,6 +73,20 @@
 }
 
 static int
+iic_print_direct(void *aux, const char *pnp)
+{
+       struct i2c_attach_args *ia = aux;
+
+       if (pnp != NULL)
+               aprint_normal("%s at %s addr 0x%02x", ia->ia_name, pnp,
+                       ia->ia_addr);
+       else
+               aprint_normal(" addr 0x%02x", ia->ia_addr);
+
+       return UNCONF;
+}
+
+static int
 iic_print(void *aux, const char *pnp)
 {
        struct i2c_attach_args *ia = aux;
@@ -110,6 +126,8 @@
 {
        struct iic_softc *sc = device_private(self);
        struct i2cbus_attach_args *iba = aux;
+       prop_array_t child_devices;
+       char *buf;
        i2c_tag_t ic;
        int rv;
 
@@ -196,11 +214,65 @@
        if (!pmf_device_register(self, NULL, NULL))
                aprint_error_dev(self, "couldn't establish power handler\n");
 
-       /*
-        * Attach all i2c devices described in the kernel
-        * configuration file.
-        */
-       config_search_ia(iic_search, self, "iic", NULL);
+       child_devices = prop_dictionary_get(device_properties(parent),
+               "i2c-child-devices");
+       if (child_devices) {
+               unsigned int i, count;
+               prop_dictionary_t dev;
+               prop_data_t cdata;
+               uint32_t addr, size;
+               uint64_t cookie;
+               const char *name;
+               struct i2c_attach_args ia;
+               int loc[2];
+
+               memset(loc, 0, sizeof loc);
+               count = prop_array_count(child_devices);
+               for (i = 0; i < count; i++) {
+                       dev = prop_array_get(child_devices, i);
+                       if (!dev) continue;
+                       if (!prop_dictionary_get_cstring_nocopy(
+                           dev, "name", &name))
+                               continue;
+                       if (!prop_dictionary_get_uint32(dev, "addr", &addr))
+                               continue;
+                       if (!prop_dictionary_get_uint64(dev, "cookie", &cookie))
+                               cookie = 0;
+                       loc[0] = addr;
+                       if (prop_dictionary_get_uint32(dev, "size", &size))
+                               loc[1] = size;
+                       else
+                               loc[1] = -1;
+
+                       memset(&ia, 0, sizeof ia);
+                       ia.ia_addr = addr;
+                       ia.ia_type = sc->sc_type;
+                       ia.ia_tag = ic;
+                       ia.ia_name = name;
+                       ia.ia_cookie = cookie;
+
+                       buf = NULL;
+                       cdata = prop_dictionary_get(dev, "compatible");
+                       if (cdata)
+                               iic_fill_compat(&ia,
+                                   prop_data_data_nocopy(cdata),
+                                   prop_data_size(cdata), &buf);
+
+                       config_found_sm_loc(self, "iic", loc, &ia,
+                           iic_print_direct, NULL);
+
+                       if (ia.ia_compat)
+                               free(ia.ia_compat, M_TEMP);
+                       if (buf)
+                               free(buf, M_TEMP);
+               }
+       } else {
+               /*
+                * Attach all i2c devices described in the kernel
+                * configuration file.
+                */
+               config_search_ia(iic_search, self, "iic", NULL);
+       }
 }
 
 static void
@@ -303,5 +375,55 @@
        return 1;
 }
 
+static void
+iic_fill_compat(struct i2c_attach_args *ia, const char *compat, size_t len,
+       char **buffer)
+{
+       int count, i;
+       const char *c, *start, **ptr;
+
+       *buffer = NULL;
+       for (i = count = 0, c = compat; i < len; i++, c++)
+               if (*c == 0)
+                       count++;
+       count += 2;
+       ptr = malloc(sizeof(char*)*count, M_TEMP, M_WAITOK);
+       if (!ptr) return;
+
+       for (i = count = 0, start = c = compat; i < len; i++, c++) {
+               if (*c == 0) {
+                       ptr[count++] = start;
+                       start = c+1;
+               }
+       }
+       if (start < compat+len) {
+               /* last string not 0 terminated */
+               size_t l = c-start;
+               *buffer = malloc(l+1, M_TEMP, M_WAITOK);
+               memcpy(*buffer, start, l);
+               (*buffer)[l] = 0;
+               ptr[count++] = *buffer;
+       }
+       ptr[count] = NULL;
+
+       ia->ia_compat = ptr;
+       ia->ia_ncompat = count;
+}
+
+int
+iic_compat_match(struct i2c_attach_args *ia, const char ** compats)
+{
+       int i;
+
+       for (; compats && *compats; compats++) {
+               for (i = 0; i < ia->ia_ncompat; i++) {
+                       if (strcmp(*compats, ia->ia_compat[i]) == 0)
+                               return 1;
+               }
+       }
+       return 0;
+}
+
+
 CFATTACH_DECL_NEW(iic, sizeof(struct iic_softc),
     iic_match, iic_attach, NULL, NULL);
diff -r 527333fa0a62 -r fe568d958ec7 sys/dev/i2c/i2cvar.h
--- a/sys/dev/i2c/i2cvar.h      Sun Feb 28 11:06:59 2010 +0000
+++ b/sys/dev/i2c/i2cvar.h      Sun Feb 28 11:34:42 2010 +0000
@@ -1,4 +1,4 @@
-/*     $NetBSD: i2cvar.h,v 1.6 2007/07/09 21:00:33 ad Exp $    */
+/*     $NetBSD: i2cvar.h,v 1.7 2010/02/28 11:34:42 martin Exp $        */
 
 /*
  * Copyright (c) 2003 Wasabi Systems, Inc.
@@ -118,12 +118,29 @@
        i2c_addr_t      ia_addr;        /* address of device */
        int             ia_size;        /* size (for EEPROMs) */
        int             ia_type;        /* bus type */
+       /* only set if using direct config */
+       const char *    ia_name;        /* name of the device */
+       int             ia_ncompat;     /* number of pointers in the
+                                          ia_compat array */
+       const char **   ia_compat;      /* chip names */
+       /*
+        * The following is of limited usefullness and should only be used
+        * in rare cases where we realy know what we are doing. Example:
+        * a machine depended i2c driver (located in sys/arch/$arch/dev)
+        * needing to access some firmware properties.
+        * Depending on the firmware in use, an identifier for the device
+        * may be present. Example: on OpenFirmware machines the device
+        * tree OF node - if available. This info is hard to transport
+        * down to MD drivers through the MI i2c bus otherwise.
+        */
+       uintptr_t       ia_cookie;      /* OF node in openfirmware machines */
 };
 
 /*
  * API presented to i2c controllers.
  */
 int    iicbus_print(void *, const char *);
+int    iic_compat_match(struct i2c_attach_args*, const char **);
 
 #ifdef _I2C_PRIVATE
 /*



Home | Main Index | Thread Index | Old Index