Module Name: src Committed By: thorpej Date: Thu Jun 7 05:54:24 UTC 2018
Modified Files: src/sys/dev/i2c: i2c.c i2cvar.h tsl256x.c Log Message: Adjust come defaults: - Initial gain -> 16x - auto_gain -> true To generate a diff of this commit: cvs rdiff -u -r1.58 -r1.59 src/sys/dev/i2c/i2c.c cvs rdiff -u -r1.10 -r1.11 src/sys/dev/i2c/i2cvar.h cvs rdiff -u -r1.2 -r1.3 src/sys/dev/i2c/tsl256x.c Please note that diffs are not public domain; they are subject to the copyright notices on the relevant files.
Modified files: Index: src/sys/dev/i2c/i2c.c diff -u src/sys/dev/i2c/i2c.c:1.58 src/sys/dev/i2c/i2c.c:1.59 --- src/sys/dev/i2c/i2c.c:1.58 Tue May 15 02:02:18 2018 +++ src/sys/dev/i2c/i2c.c Thu Jun 7 05:54:23 2018 @@ -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 @@ __KERNEL_RCSID(0, "$NetBSD: i2c.c,v 1.58 #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 @@ iic_print(void *aux, const char *pnp) 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 @@ iic_search(device_t parent, cfdata_t cf, 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 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; - if (config_match(parent, cf, &ia) > 0) - sc->sc_devices[ia.ia_addr] = - config_attach(parent, cf, &ia, iic_print); + sc->sc_devices[ia.ia_addr] = + config_attach(parent, cf, &ia, iic_print); } return 0; @@ -209,6 +407,7 @@ iic_attach(device_t parent, device_t sel 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; Index: src/sys/dev/i2c/i2cvar.h diff -u src/sys/dev/i2c/i2cvar.h:1.10 src/sys/dev/i2c/i2cvar.h:1.11 --- src/sys/dev/i2c/i2cvar.h:1.10 Sun Dec 10 16:53:32 2017 +++ src/sys/dev/i2c/i2cvar.h Thu Jun 7 05:54:23 2018 @@ -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" +#define I2C_PROBE_STRATEGY_RECEIVE_BYTE \ + "smbus-receive-byte" +#define I2C_PROBE_STRATEGY_NONE \ + "none" + +#define I2C_PROP_INDIRECT_DEVICE_WHITELIST \ + "i2c-indirect-device-whitelist" + /* value is a prop_array of prop_strings */ + struct ic_intr_list { LIST_ENTRY(ic_intr_list) il_next; int (*il_intr)(void *); @@ -147,6 +161,23 @@ struct i2c_attach_args { int iicbus_print(void *, const char *); int iic_compat_match(struct i2c_attach_args*, const char **); +/* + * Constants to indicate the quality of a match made by a driver's + * match routine, from lowest to higest: + * + * -- Address only; no other checks were made. + * + * -- Address + device probed and recognized. + * + * -- Direct-config match by "compatible" string. + * + * -- Direct-config match by specific driver name. + */ +#define I2C_MATCH_ADDRESS_ONLY 1 +#define I2C_MATCH_ADDRESS_AND_PROBE 2 +#define I2C_MATCH_DIRECT_COMPATIBLE 10 +#define I2C_MATCH_DIRECT_SPECIFIC 50 + #ifdef _I2C_PRIVATE /* * Macros used internally by the i2c framework. Index: src/sys/dev/i2c/tsl256x.c diff -u src/sys/dev/i2c/tsl256x.c:1.2 src/sys/dev/i2c/tsl256x.c:1.3 --- src/sys/dev/i2c/tsl256x.c:1.2 Sun May 27 14:03:56 2018 +++ src/sys/dev/i2c/tsl256x.c Thu Jun 7 05:54:23 2018 @@ -1,4 +1,4 @@ -/* $NetBSD: tsl256x.c,v 1.2 2018/05/27 14:03:56 thorpej Exp $ */ +/* $NetBSD: tsl256x.c,v 1.3 2018/06/07 05:54:23 thorpej Exp $ */ /*- * Copyright (c) 2018 Jason R. Thorpe @@ -27,7 +27,7 @@ */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: tsl256x.c,v 1.2 2018/05/27 14:03:56 thorpej Exp $"); +__KERNEL_RCSID(0, "$NetBSD: tsl256x.c,v 1.3 2018/06/07 05:54:23 thorpej Exp $"); #include <sys/param.h> #include <sys/systm.h> @@ -189,7 +189,8 @@ tsllux_attach(device_t parent, device_t sc->sc_cs_package ? " (CS package)" : ""); /* Inititalize timing to reasonable defaults. */ - sc->sc_gain = TIMING_GAIN_1X; + sc->sc_auto_gain = true; + sc->sc_gain = TIMING_GAIN_16X; if (tsllux_set_integration_time(sc, TIMING_INTEG_101ms)) { aprint_error_dev(self, ": unable to set integration time\n"); goto out;