Module Name: src Committed By: thorpej Date: Sat Jun 16 21:28:07 UTC 2018
Modified Files: src/sys/dev/i2c: ds1307.c Log Message: More cleanup to i2c autoconfiguration: - Get all of the drivers onto the new match quality constants. - Introduce a new helper function, iic_use_direct_match(), that has all of the logic for direct-config matching. If it returns true, the driver returns the match result (which may be 0). If it returns false, the driver does indirect-config matching. - iic_compat_match() now returns a weighted match quality; matches to lower-indexed "compatible" device property are more-specific matches, and return a better match quality accordingly. In addition to the above: - Add support for direct-config matching this driver based on "compatible" properties. - Address-only matching is now done based on the specific addresses the requested model supports. - "compatible" property can specify to the driver which model is to be used, so that using config "flags" directives aren't required in the direct-config case. XXX More changes coming that require re-factoring some other code. To generate a diff of this commit: cvs rdiff -u -r1.25 -r1.26 src/sys/dev/i2c/ds1307.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/ds1307.c diff -u src/sys/dev/i2c/ds1307.c:1.25 src/sys/dev/i2c/ds1307.c:1.26 --- src/sys/dev/i2c/ds1307.c:1.25 Sat Oct 28 04:53:55 2017 +++ src/sys/dev/i2c/ds1307.c Sat Jun 16 21:28:07 2018 @@ -1,4 +1,4 @@ -/* $NetBSD: ds1307.c,v 1.25 2017/10/28 04:53:55 riastradh Exp $ */ +/* $NetBSD: ds1307.c,v 1.26 2018/06/16 21:28:07 thorpej Exp $ */ /* * Copyright (c) 2003 Wasabi Systems, Inc. @@ -36,7 +36,7 @@ */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: ds1307.c,v 1.25 2017/10/28 04:53:55 riastradh Exp $"); +__KERNEL_RCSID(0, "$NetBSD: ds1307.c,v 1.26 2018/06/16 21:28:07 thorpej Exp $"); #include <sys/param.h> #include <sys/systm.h> @@ -56,6 +56,8 @@ __KERNEL_RCSID(0, "$NetBSD: ds1307.c,v 1 #include "ioconf.h" struct dsrtc_model { + const char **dm_compats; + const i2c_addr_t *dm_valid_addrs; uint16_t dm_model; uint8_t dm_ch_reg; uint8_t dm_ch_value; @@ -74,8 +76,23 @@ struct dsrtc_model { #define DSRTC_FLAG_CLOCK_HOLD_REVERSED 0x20 }; +static const char *ds1307_compats[] = { "dallas,ds1307", "maxim,ds1307", NULL }; +static const char *ds1339_compats[] = { "dallas,ds1339", "maxim,ds1339", NULL }; +static const char *ds1340_compats[] = { "dallas,ds1340", "maxim,ds1340", NULL }; +static const char *ds1672_compats[] = { "dallas,ds1672", "maxim,ds1672", NULL }; +static const char *ds3231_compats[] = { "dallas,ds3231", "maxim,ds3231", NULL }; +static const char *ds3232_compats[] = { "dallas,ds3232", "maxim,ds3232", NULL }; + + /* XXX vendor prefix */ +static const char *mcp7940_compats[] = { "microchip,mcp7940", NULL }; + +static const i2c_addr_t ds1307_valid_addrs[] = { DS1307_ADDR, 0 }; +static const i2c_addr_t mcp7940_valid_addrs[] = { MCP7940_ADDR, 0 }; + static const struct dsrtc_model dsrtc_models[] = { { + .dm_compats = ds1307_compats, + .dm_valid_addrs = ds1307_valid_addrs, .dm_model = 1307, .dm_ch_reg = DSXXXX_SECONDS, .dm_ch_value = DS1307_SECONDS_CH, @@ -85,11 +102,15 @@ static const struct dsrtc_model dsrtc_mo .dm_nvram_size = DS1307_NVRAM_SIZE, .dm_flags = DSRTC_FLAG_BCD | DSRTC_FLAG_CLOCK_HOLD, }, { + .dm_compats = ds1339_compats, + .dm_valid_addrs = ds1307_valid_addrs, .dm_model = 1339, .dm_rtc_start = DS1339_RTC_START, .dm_rtc_size = DS1339_RTC_SIZE, .dm_flags = DSRTC_FLAG_BCD, }, { + .dm_compats = ds1340_compats, + .dm_valid_addrs = ds1307_valid_addrs, .dm_model = 1340, .dm_ch_reg = DSXXXX_SECONDS, .dm_ch_value = DS1340_SECONDS_EOSC, @@ -97,6 +118,8 @@ static const struct dsrtc_model dsrtc_mo .dm_rtc_size = DS1340_RTC_SIZE, .dm_flags = DSRTC_FLAG_BCD, }, { + .dm_compats = ds1672_compats, + .dm_valid_addrs = ds1307_valid_addrs, .dm_model = 1672, .dm_rtc_start = DS1672_RTC_START, .dm_rtc_size = DS1672_RTC_SIZE, @@ -104,6 +127,8 @@ static const struct dsrtc_model dsrtc_mo .dm_ch_value = DS1672_CONTROL_CH, .dm_flags = 0, }, { + .dm_compats = ds3231_compats, + .dm_valid_addrs = ds1307_valid_addrs, .dm_model = 3231, .dm_rtc_start = DS3232_RTC_START, .dm_rtc_size = DS3232_RTC_SIZE, @@ -114,6 +139,8 @@ static const struct dsrtc_model dsrtc_mo */ .dm_flags = DSRTC_FLAG_BCD | DSRTC_FLAG_TEMP, }, { + .dm_compats = ds3232_compats, + .dm_valid_addrs = ds1307_valid_addrs, .dm_model = 3232, .dm_rtc_start = DS3232_RTC_START, .dm_rtc_size = DS3232_RTC_SIZE, @@ -122,6 +149,8 @@ static const struct dsrtc_model dsrtc_mo .dm_flags = DSRTC_FLAG_BCD, }, { /* MCP7940 */ + .dm_compats = mcp7940_compats, + .dm_valid_addrs = mcp7940_valid_addrs, .dm_model = 7940, .dm_rtc_start = DS1307_RTC_START, .dm_rtc_size = DS1307_RTC_SIZE, @@ -187,7 +216,7 @@ static int dsrtc_read_temp(struct dsrtc_ static void dsrtc_refresh(struct sysmon_envsys *, envsys_data_t *); static const struct dsrtc_model * -dsrtc_model(u_int model) +dsrtc_model_by_number(u_int model) { /* no model given, assume it's a DS1307 (the first one) */ if (model == 0) @@ -201,20 +230,71 @@ dsrtc_model(u_int model) return NULL; } +static const struct dsrtc_model * +dsrtc_model_by_compat(const struct i2c_attach_args *ia) +{ + const struct dsrtc_model *best_model = NULL, *dm; + int best_match = 0, match_result; + + for (dm = dsrtc_models; + dm < dsrtc_models + __arraycount(dsrtc_models); dm++) { + match_result = iic_compat_match(ia, dm->dm_compats); + if (match_result > best_match) { + best_match = match_result; + best_model = dm; + } + } + return best_model; +} + +static bool +dsrtc_direct_match(const struct i2c_attach_args *ia, const cfdata_t cf, + int *best_matchp) +{ + const struct dsrtc_model *dm; + int best_match = 0, match_result; + + for (dm = dsrtc_models; + dm < dsrtc_models + __arraycount(dsrtc_models); dm++) { + if (iic_use_direct_match(ia, cf, dm->dm_compats, + &match_result) == false) + return false; + if (match_result > best_match) + best_match = match_result; + } + + *best_matchp = best_match; + return true; +} + +static bool +dsrtc_is_valid_addr_for_model(const struct dsrtc_model *dm, i2c_addr_t addr) +{ + + for (int i = 0; dm->dm_valid_addrs[i] != 0; i++) { + if (addr == dm->dm_valid_addrs[i]) + return true; + } + return false; +} + static int dsrtc_match(device_t parent, cfdata_t cf, void *arg) { struct i2c_attach_args *ia = arg; + const struct dsrtc_model *dm; + int match_result; + + if (dsrtc_direct_match(ia, cf, &match_result)) + return match_result; + + dm = dsrtc_model_by_number(cf->cf_flags & 0xffff); + if (dm == NULL) + return 0; + + if (dsrtc_is_valid_addr_for_model(dm, ia->ia_addr)) + return I2C_MATCH_ADDRESS_ONLY; - if (ia->ia_name) { - /* direct config - check name */ - if (strcmp(ia->ia_name, "dsrtc") == 0) - return 1; - } else { - /* indirect config - check typical address */ - if (ia->ia_addr == DS1307_ADDR || ia->ia_addr == MCP7940_ADDR) - return dsrtc_model(cf->cf_flags & 0xffff) != NULL; - } return 0; } @@ -223,8 +303,15 @@ dsrtc_attach(device_t parent, device_t s { struct dsrtc_softc *sc = device_private(self); struct i2c_attach_args *ia = arg; - const struct dsrtc_model * const dm = - dsrtc_model(device_cfdata(self)->cf_flags); + const struct dsrtc_model *dm; + + if ((dm = dsrtc_model_by_compat(ia)) == NULL) + dm = dsrtc_model_by_number(device_cfdata(self)->cf_flags); + + if (dm == NULL) { + aprint_error(": unable to determine model!\n"); + return; + } aprint_naive(": Real-time Clock%s\n", dm->dm_nvram_size > 0 ? "/NVRAM" : "");