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" : "");

Reply via email to