Source-Changes-HG archive

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

[src/trunk]: src/sys/dev/i2c Adjust come defaults:



details:   https://anonhg.NetBSD.org/src/rev/d5d32156898c
branches:  trunk
changeset: 323289:d5d32156898c
user:      thorpej <thorpej%NetBSD.org@localhost>
date:      Thu Jun 07 05:54:23 2018 +0000

description:
Adjust come defaults:
- Initial gain -> 16x
- auto_gain -> true

diffstat:

 sys/dev/i2c/i2c.c     |  227 ++++++++++++++++++++++++++++++++++++++++++++++---
 sys/dev/i2c/i2cvar.h  |   33 +++++++-
 sys/dev/i2c/tsl256x.c |    7 +-
 3 files changed, 249 insertions(+), 18 deletions(-)

diffs (truncated from 364 to 300 lines):

diff -r b783d534895a -r d5d32156898c sys/dev/i2c/i2c.c
--- a/sys/dev/i2c/i2c.c Thu Jun 07 05:48:29 2018 +0000
+++ b/sys/dev/i2c/i2c.c Thu Jun 07 05:54:23 2018 +0000
@@ -1,4 +1,4 @@
-/*     $NetBSD: i2c.c,v 1.58 2018/05/15 02:02:18 thorpej Exp $ */
+/*     $NetBSD: i2c.c,v 1.59 2018/06/07 05:54:23 thorpej Exp $ */
 
 /*
  * Copyright (c) 2003 Wasabi Systems, Inc.
@@ -40,7 +40,7 @@
 #endif
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: i2c.c,v 1.58 2018/05/15 02:02:18 thorpej Exp $");
+__KERNEL_RCSID(0, "$NetBSD: i2c.c,v 1.59 2018/06/07 05:54:23 thorpej Exp $");
 
 #include <sys/param.h>
 #include <sys/systm.h>
@@ -67,6 +67,7 @@
 #endif
 
 struct iic_softc {
+       device_t sc_dev;
        i2c_tag_t sc_tag;
        int sc_type;
        device_t sc_devices[I2C_MAX_ADDR + 1];
@@ -127,21 +128,160 @@
        return UNCONF;
 }
 
+static bool
+iic_is_special_address(i2c_addr_t addr)
+{
+
+       /*
+        * See: https://www.i2c-bus.org/addressing/
+        */
+
+       /* General Call (read) / Start Byte (write) */
+       if (addr == 0x00)
+               return (true);
+
+       /* CBUS Addresses */
+       if (addr == 0x01)
+               return (true);
+
+       /* Reserved for Different Bus Formats */
+       if (addr == 0x02)
+               return (true);
+
+       /* Reserved for future purposes */
+       if (addr == 0x03)
+               return (true);
+
+       /* High Speed Master Code */
+       if ((addr & 0x7c) == 0x04)
+               return (true);
+
+       /* 10-bit Slave Addressing prefix */
+       if ((addr & 0x7c) == 0x78)
+               return (true);
+       
+       /* Reserved for future purposes */
+       if ((addr & 0x7c) == 0x7c)
+               return (true);
+       
+       return (false);
+}
+
+static int
+iic_probe_none(struct iic_softc *sc,
+              const struct i2c_attach_args *ia, int flags)
+{
+
+       return (0);
+}
+
+static int
+iic_probe_smbus_quick_write(struct iic_softc *sc,
+                           const struct i2c_attach_args *ia, int flags)
+{
+       int error;
+
+       if ((error = iic_acquire_bus(ia->ia_tag, flags)) == 0) {
+               error = iic_smbus_quick_write(ia->ia_tag, ia->ia_addr, flags);
+       }
+       (void) iic_release_bus(ia->ia_tag, flags);
+
+       return (error);
+}
+
+static int
+iic_probe_smbus_receive_byte(struct iic_softc *sc,
+                            const struct i2c_attach_args *ia, int flags)
+{
+       int error;
+
+       if ((error = iic_acquire_bus(ia->ia_tag, flags)) == 0) {
+               uint8_t dummy;
+
+               error = iic_smbus_receive_byte(ia->ia_tag, ia->ia_addr,
+                                              &dummy, flags);
+       }
+       (void) iic_release_bus(ia->ia_tag, flags);
+
+       return (error);
+}
+
+static bool
+iic_indirect_driver_is_whitelisted(struct iic_softc *sc, cfdata_t cf)
+{
+       prop_object_iterator_t iter;
+       prop_array_t whitelist;
+       prop_string_t pstr;
+       prop_type_t ptype;
+       bool rv = false;
+
+       whitelist = prop_dictionary_get(device_properties(sc->sc_dev),
+                                       I2C_PROP_INDIRECT_DEVICE_WHITELIST);
+       if (whitelist == NULL) {
+               /* No whitelist -> everything allowed */
+               return (true);
+       }
+
+       if ((ptype = prop_object_type(whitelist)) != PROP_TYPE_ARRAY) {
+               aprint_error_dev(sc->sc_dev,
+                   "invalid property type (%d) for '%s'; must be array (%d)\n",
+                   ptype, I2C_PROP_INDIRECT_DEVICE_WHITELIST, PROP_TYPE_ARRAY);
+               return (false);
+       }
+
+       iter = prop_array_iterator(whitelist);
+       while ((pstr = prop_object_iterator_next(iter)) != NULL) {
+               if (prop_string_equals_cstring(pstr, cf->cf_name)) {
+                       rv = true;
+                       break;
+               }
+       }
+       prop_object_iterator_release(iter);
+
+       return (rv);
+}
+
 static int
 iic_search(device_t parent, cfdata_t cf, const int *ldesc, void *aux)
 {
        struct iic_softc *sc = device_private(parent);
        struct i2c_attach_args ia;
+       int (*probe_func)(struct iic_softc *,
+                         const struct i2c_attach_args *, int);
+       prop_string_t pstr;
+       i2c_addr_t first_addr, last_addr;
 
        /*
-        * I2C doesn't have any regular probing capability.  If we
-        * encounter a cfdata with a wild-carded address or a wild-
-        * carded parent spec, we skip them because they can only
-        * be used for direct-coniguration.
+        * Before we do any more work, consult the allowed-driver
+        * white-list for this bus (if any).
         */
-       if (cf->cf_loc[IICCF_ADDR] == IICCF_ADDR_DEFAULT ||
-           cf->cf_pspec->cfp_unit == DVUNIT_ANY)
-               return 0;
+       if (iic_indirect_driver_is_whitelisted(sc, cf) == false)
+               return (0);
+
+       /* default to "quick write". */
+       probe_func = iic_probe_smbus_quick_write;
+
+       pstr = prop_dictionary_get(device_properties(sc->sc_dev),
+                                  I2C_PROP_INDIRECT_PROBE_STRATEGY);
+       if (pstr == NULL) {
+               /* Use the default. */
+       } else if (prop_string_equals_cstring(pstr,
+                                       I2C_PROBE_STRATEGY_QUICK_WRITE)) {
+               probe_func = iic_probe_smbus_quick_write;
+       } else if (prop_string_equals_cstring(pstr,
+                                       I2C_PROBE_STRATEGY_RECEIVE_BYTE)) {
+               probe_func = iic_probe_smbus_receive_byte;
+       } else if (prop_string_equals_cstring(pstr,
+                                       I2C_PROBE_STRATEGY_NONE)) {
+               probe_func = iic_probe_none;
+       } else {
+               aprint_error_dev(sc->sc_dev,
+                       "unknown probe strategy '%s'; defaulting to '%s'\n",
+                       prop_string_cstring_nocopy(pstr),
+                       I2C_PROBE_STRATEGY_QUICK_WRITE);
+
+               /* Use the default. */
+       }
 
        ia.ia_tag = sc->sc_tag;
        ia.ia_size = cf->cf_loc[IICCF_SIZE];
@@ -152,16 +292,74 @@
        ia.ia_compat = NULL;
        ia.ia_prop = NULL;
 
-       for (ia.ia_addr = 0; ia.ia_addr <= I2C_MAX_ADDR; ia.ia_addr++) {
+       if (cf->cf_loc[IICCF_ADDR] == IICCF_ADDR_DEFAULT) {
+               /*
+                * This particular config directive has
+                * wildcarded the address, so we will
+                * scan the entire bus for it.
+                */
+               first_addr = 0;
+               last_addr = I2C_MAX_ADDR;
+       } else {
+               /*
+                * This config directive hard-wires the i2c
+                * bus address for the device, so there is
+                * no need to go poking around at any other
+                * addresses.
+                */
+               if (cf->cf_loc[IICCF_ADDR] < 0 ||
+                   cf->cf_loc[IICCF_ADDR] > I2C_MAX_ADDR) {
+                       /* Invalid config directive! */
+                       return (0);
+               }
+               first_addr = last_addr = cf->cf_loc[IICCF_ADDR];
+       }
+
+       for (ia.ia_addr = first_addr; ia.ia_addr <= last_addr; ia.ia_addr++) {
+               int error, match_result;
+
+               /*
+                * Skip I2C addresses that are reserved for
+                * special purposes.
+                */
+               if (iic_is_special_address(ia.ia_addr))
+                       continue;
+
+               /*
+                * Skip addresses where a device is already attached.
+                */
                if (sc->sc_devices[ia.ia_addr] != NULL)
                        continue;
 
-               if (cf->cf_loc[IICCF_ADDR] != ia.ia_addr)
+               /*
+                * Call the "match" routine for the device.  If that
+                * returns success, then call the probe strategy
+                * function.
+                *
+                * We do it in this order because i2c devices tend
+                * to be found at a small number of possible addresses
+                * (e.g. read-time clocks that are only ever found at
+                * 0x68).  This gives the driver a chance to skip any
+                * address that are not valid for the device, saving
+                * us from having to poke at the bus to see if anything
+                * is there.
+                */
+               match_result = config_match(parent, cf, &ia);
+               if (match_result <= 0)
                        continue;
 
-               if (config_match(parent, cf, &ia) > 0)
-                       sc->sc_devices[ia.ia_addr] =
-                           config_attach(parent, cf, &ia, iic_print);
+               /*
+                * If the quality of the match by the driver was low
+                * (i.e. matched on being a valid address only, didn't
+                * perform any hardware probe), invoke our probe routine
+                * to see if it looks like something is really there.
+                */
+               if (match_result == I2C_MATCH_ADDRESS_ONLY &&
+                   (error = (*probe_func)(sc, &ia, I2C_F_POLL)) != 0)
+                       continue;
+
+               sc->sc_devices[ia.ia_addr] =
+                   config_attach(parent, cf, &ia, iic_print);
        }
 
        return 0;
@@ -209,6 +407,7 @@
        aprint_naive("\n");
        aprint_normal(": I2C bus\n");
 
+       sc->sc_dev = self;
        sc->sc_tag = iba->iba_tag;
        sc->sc_type = iba->iba_type;
        ic = sc->sc_tag;
diff -r b783d534895a -r d5d32156898c sys/dev/i2c/i2cvar.h
--- a/sys/dev/i2c/i2cvar.h      Thu Jun 07 05:48:29 2018 +0000
+++ b/sys/dev/i2c/i2cvar.h      Thu Jun 07 05:54:23 2018 +0000
@@ -1,4 +1,4 @@
-/*     $NetBSD: i2cvar.h,v 1.10 2017/12/10 16:53:32 bouyer Exp $       */
+/*     $NetBSD: i2cvar.h,v 1.11 2018/06/07 05:54:23 thorpej Exp $      */
 
 /*
  * Copyright (c) 2003 Wasabi Systems, Inc.
@@ -49,6 +49,20 @@
 #define        I2C_F_POLL              0x08    /* poll, don't sleep */
 #define        I2C_F_PEC               0x10    /* smbus packet error checking */
 
+/* i2c bus instance properties */
+#define        I2C_PROP_INDIRECT_PROBE_STRATEGY        \
+                               "i2c-indirect-probe-strategy"
+#define        I2C_PROBE_STRATEGY_QUICK_WRITE          \
+                               "smbus-quick-write"



Home | Main Index | Thread Index | Old Index