Module Name:    src
Committed By:   brad
Date:           Fri Nov 12 15:12:11 UTC 2021

Modified Files:
        src/share/man/man4: si70xxtemp.4
        src/sys/dev/i2c: si70xx.c

Log Message:
Fix the serial number handling of the HTU21D chip and probably others.
Increase the number of read attempts as the HTU21D and probably others
do not respond as fast the actual SI70xx chip can.


To generate a diff of this commit:
cvs rdiff -u -r1.6 -r1.7 src/share/man/man4/si70xxtemp.4
cvs rdiff -u -r1.9 -r1.10 src/sys/dev/i2c/si70xx.c

Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.

Modified files:

Index: src/share/man/man4/si70xxtemp.4
diff -u src/share/man/man4/si70xxtemp.4:1.6 src/share/man/man4/si70xxtemp.4:1.7
--- src/share/man/man4/si70xxtemp.4:1.6	Thu Nov 11 14:24:24 2021
+++ src/share/man/man4/si70xxtemp.4	Fri Nov 12 15:12:11 2021
@@ -1,4 +1,4 @@
-.\" $NetBSD: si70xxtemp.4,v 1.6 2021/11/11 14:24:24 wiz Exp $
+.\" $NetBSD: si70xxtemp.4,v 1.7 2021/11/12 15:12:11 brad Exp $
 .\"
 .\" Copyright (c) 2017 Brad Spencer <b...@anduin.eldar.org>
 .\"
@@ -72,7 +72,7 @@ and then another read command is sent to
 Depending on the resolution, and other factors, the wait time varies.
 The driver will attempt to read back the values readattempts number of
 times.
-The default is 25 which should be more than enough for most purposes.
+The default is 40 which should be enough for most purposes.
 There is an initial wait of 10,500 microseconds followed by
 a additional 1,000 microseconds per read attempt.
 .El

Index: src/sys/dev/i2c/si70xx.c
diff -u src/sys/dev/i2c/si70xx.c:1.9 src/sys/dev/i2c/si70xx.c:1.10
--- src/sys/dev/i2c/si70xx.c:1.9	Thu Nov 11 14:16:04 2021
+++ src/sys/dev/i2c/si70xx.c	Fri Nov 12 15:12:11 2021
@@ -1,4 +1,4 @@
-/*	$NetBSD: si70xx.c,v 1.9 2021/11/11 14:16:04 brad Exp $	*/
+/*	$NetBSD: si70xx.c,v 1.10 2021/11/12 15:12:11 brad Exp $	*/
 
 /*
  * Copyright (c) 2017 Brad Spencer <b...@anduin.eldar.org>
@@ -17,7 +17,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: si70xx.c,v 1.9 2021/11/11 14:16:04 brad Exp $");
+__KERNEL_RCSID(0, "$NetBSD: si70xx.c,v 1.10 2021/11/12 15:12:11 brad Exp $");
 
 /*
   Driver for the Silicon Labs SI7013/SI7020/SI7021, HTU21D and SHT21
@@ -609,6 +609,7 @@ si70xx_attach(device_t parent, device_t 
 	uint8_t testcrcpt1[4];
 	uint8_t testcrcpt2[4];
 	uint8_t crc1 = 0, crc2 = 0;
+	bool validcrcpt1, validcrcpt2;
 	uint8_t readcrc1 = 0, readcrc2 = 0;
 	uint8_t fwversion = 0, model, heaterregister;
 
@@ -622,7 +623,7 @@ si70xx_attach(device_t parent, device_t 
 #ifdef HAVE_I2C_EXECV
 	sc->sc_clockstretch = 2048;
 #endif
-	sc->sc_readattempts = 25;
+	sc->sc_readattempts = 40;
 	sc->sc_ignorecrc = false;
 	sc->sc_sme = NULL;
 	sc->sc_noheater = false;
@@ -665,11 +666,24 @@ si70xx_attach(device_t parent, device_t 
 	testcrcpt1[3] = buf[6];
 	readcrc1 = buf[7];
 	crc1 = si70xx_crc(testcrcpt1, 4);
+	/* A "real" SI70xx has the CRC cover the entire first part of the
+	 * serial number.  An HTU21D has the CRC broken out into each
+	 * part of the serial number.
+	 */
+	validcrcpt1 = (readcrc1 == crc1);
+	if (! validcrcpt1) {
+		validcrcpt1 = (si70xx_crc(&testcrcpt1[0],1) == buf[1] &&
+		    si70xx_crc(&testcrcpt1[1],1) == buf[3] &&
+		    si70xx_crc(&testcrcpt1[2],1) == buf[5] &&
+		    si70xx_crc(&testcrcpt1[3],1) == buf[7]);
+		DPRINTF(sc, 2, ("%s: Part 1 SN CRC was not valid for real type, "
+		    "check clone: %d\n", device_xname(sc->sc_dev), validcrcpt1));
+	}
 
 	DPRINTF(sc, 2, ("%s: read 1 values: %02x%02x%02x%02x%02x%02x%02x%02x "
-	    "- %02x\n", device_xname(sc->sc_dev), buf[0], buf[1],
+	    "- %02x -- %d\n", device_xname(sc->sc_dev), buf[0], buf[1],
 	    buf[2], buf[3], buf[4], buf[5], buf[6], buf[7],
-	    crc1));
+	    crc1, validcrcpt1));
 
 	error = si70xx_cmd2(sc, SI70XX_READ_ID_PT2A, SI70XX_READ_ID_PT2B,
 	    buf, 8);
@@ -684,16 +698,30 @@ si70xx_attach(device_t parent, device_t 
 	testcrcpt2[3] = buf[4];
 	readcrc2 = buf[5];
 	crc2 = si70xx_crc(testcrcpt2, 4);
+	/* It is even stranger for this part of the serial number.  A "real"
+	 * SI70XX will have a single CRC for the entire second part, but
+	 * an HTU21D has a CRC for each word in this case.
+	 *
+	 * The datasheet actually agrees with the HTU21D case, and not the "real"
+	 * chip.
+	 */
+	validcrcpt2 = (readcrc2 == crc2);
+	if (! validcrcpt2) {
+		validcrcpt2 = (si70xx_crc(&testcrcpt2[0],2) == buf[2] &&
+		    si70xx_crc(&testcrcpt2[2],2) == buf[5]);
+		DPRINTF(sc, 2, ("%s: Part 2 SN CRC was not valid for real type, "
+		    "check clone: %d\n", device_xname(sc->sc_dev), validcrcpt2));
+	}
 
-	DPRINTF(sc, 2, ("%s: read 2 values: %02x%02x%02x%02x%02x%02x - %02x\n",
+	DPRINTF(sc, 2, ("%s: read 2 values: %02x%02x%02x%02x%02x%02x - %02x -- %d\n",
 	    device_xname(sc->sc_dev), buf[0], buf[1], buf[2],
-	    buf[3], buf[4], buf[5], crc2));
+	    buf[3], buf[4], buf[5], crc2, validcrcpt2));
 
 	error = si70xx_cmd2(sc, SI70XX_READ_FW_VERA, SI70XX_READ_FW_VERB,
 	    buf, 8);
 
 	if (error) {
-		aprint_error_dev(self, "Failed to read firmware version: %d\n",
+		aprint_error_dev(self, "Failed to read firmware version: Error %d\n",
 		    error);
 		sc->sc_nofw = true;
 	}
@@ -706,7 +734,7 @@ si70xx_attach(device_t parent, device_t 
 	error = si70xx_cmd1(sc, SI70XX_READ_HEATER_REG, &heaterregister, 1);
 
 	if (error) {
-		aprint_error_dev(self, "Failed to read heater register: %d\n",
+		aprint_error_dev(self, "Failed to read heater register: Error %d\n",
 		    error);
 		sc->sc_noheater = true;
 	}
@@ -759,11 +787,6 @@ si70xx_attach(device_t parent, device_t 
 		sc->sc_sme = NULL;
 		return;
 	}
-	if (ecount != 0) {
-		aprint_normal_dev(self, "Could not read model, "
-		    "probably an HTU21D\n");
-		return;
-	}
 
 	char modelstr[64];
 	switch (model) {
@@ -800,7 +823,7 @@ si70xx_attach(device_t parent, device_t 
 	    modelstr, fwversionstr, testcrcpt1[0], testcrcpt1[1],
 	    testcrcpt1[2], testcrcpt1[3], testcrcpt2[0], testcrcpt2[1],
 	    testcrcpt2[2], testcrcpt2[3],
-	    (crc1 == readcrc1 && crc2 == readcrc2) ? "\n" : " (bad crc)\n");
+	    (validcrcpt1 && validcrcpt2) ? "\n" : " (bad crc)\n");
 	return;
 out:
 	sysmon_envsys_destroy(sc->sc_sme);

Reply via email to