Fri Nov 12 15:12:11 2021 UTC ()
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.


(brad)
diff -r1.6 -r1.7 src/share/man/man4/si70xxtemp.4
diff -r1.9 -r1.10 src/sys/dev/i2c/si70xx.c

cvs diff -r1.6 -r1.7 src/share/man/man4/si70xxtemp.4 (expand / switch to unified diff)

--- src/share/man/man4/si70xxtemp.4 2021/11/11 14:24:24 1.6
+++ src/share/man/man4/si70xxtemp.4 2021/11/12 15:12:11 1.7
@@ -1,14 +1,14 @@ @@ -1,14 +1,14 @@
1.\" $NetBSD: si70xxtemp.4,v 1.6 2021/11/11 14:24:24 wiz Exp $ 1.\" $NetBSD: si70xxtemp.4,v 1.7 2021/11/12 15:12:11 brad Exp $
2.\" 2.\"
3.\" Copyright (c) 2017 Brad Spencer <brad@anduin.eldar.org> 3.\" Copyright (c) 2017 Brad Spencer <brad@anduin.eldar.org>
4.\" 4.\"
5.\" Permission to use, copy, modify, and distribute this software for any 5.\" Permission to use, copy, modify, and distribute this software for any
6.\" purpose with or without fee is hereby granted, provided that the above 6.\" purpose with or without fee is hereby granted, provided that the above
7.\" copyright notice and this permission notice appear in all copies. 7.\" copyright notice and this permission notice appear in all copies.
8.\" 8.\"
9.\" THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 9.\" THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10.\" WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 10.\" WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11.\" MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 11.\" MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12.\" ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 12.\" ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13.\" WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 13.\" WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14.\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 14.\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
@@ -62,27 +62,27 @@ Some HTU21D chips do not support a heate @@ -62,27 +62,27 @@ Some HTU21D chips do not support a heate
62These chips are detected and the heater features of the driver will 62These chips are detected and the heater features of the driver will
63be disabled. 63be disabled.
64.It hw.si70xxtemp0.debug 64.It hw.si70xxtemp0.debug
65If the driver is compiled with 65If the driver is compiled with
66.Dv SI70XX_DEBUG , 66.Dv SI70XX_DEBUG ,
67this node will appear and can be used to set the debugging level. 67this node will appear and can be used to set the debugging level.
68.It hw.si70xxtemp0.readattempts 68.It hw.si70xxtemp0.readattempts
69To read %RH or temperature the driver uses a No Hold Master command. 69To read %RH or temperature the driver uses a No Hold Master command.
70This command needs to be sent to the device, a wait must then occur 70This command needs to be sent to the device, a wait must then occur
71and then another read command is sent to read back the values. 71and then another read command is sent to read back the values.
72Depending on the resolution, and other factors, the wait time varies. 72Depending on the resolution, and other factors, the wait time varies.
73The driver will attempt to read back the values readattempts number of 73The driver will attempt to read back the values readattempts number of
74times. 74times.
75The default is 25 which should be more than enough for most purposes. 75The default is 40 which should be enough for most purposes.
76There is an initial wait of 10,500 microseconds followed by 76There is an initial wait of 10,500 microseconds followed by
77a additional 1,000 microseconds per read attempt. 77a additional 1,000 microseconds per read attempt.
78.El 78.El
79.Sh SEE ALSO 79.Sh SEE ALSO
80.Xr envsys 4 , 80.Xr envsys 4 ,
81.Xr iic 4 , 81.Xr iic 4 ,
82.Xr envstat 8 , 82.Xr envstat 8 ,
83.Xr sysctl 8 83.Xr sysctl 8
84.Sh HISTORY 84.Sh HISTORY
85The 85The
86.Nm 86.Nm
87driver first appeared in 87driver first appeared in
88.Nx 8.0 . 88.Nx 8.0 .

cvs diff -r1.9 -r1.10 src/sys/dev/i2c/si70xx.c (expand / switch to unified diff)

--- src/sys/dev/i2c/si70xx.c 2021/11/11 14:16:04 1.9
+++ src/sys/dev/i2c/si70xx.c 2021/11/12 15:12:11 1.10
@@ -1,33 +1,33 @@ @@ -1,33 +1,33 @@
1/* $NetBSD: si70xx.c,v 1.9 2021/11/11 14:16:04 brad Exp $ */ 1/* $NetBSD: si70xx.c,v 1.10 2021/11/12 15:12:11 brad Exp $ */
2 2
3/* 3/*
4 * Copyright (c) 2017 Brad Spencer <brad@anduin.eldar.org> 4 * Copyright (c) 2017 Brad Spencer <brad@anduin.eldar.org>
5 * 5 *
6 * Permission to use, copy, modify, and distribute this software for any 6 * Permission to use, copy, modify, and distribute this software for any
7 * purpose with or without fee is hereby granted, provided that the above 7 * purpose with or without fee is hereby granted, provided that the above
8 * copyright notice and this permission notice appear in all copies. 8 * copyright notice and this permission notice appear in all copies.
9 * 9 *
10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17 */ 17 */
18 18
19#include <sys/cdefs.h> 19#include <sys/cdefs.h>
20__KERNEL_RCSID(0, "$NetBSD: si70xx.c,v 1.9 2021/11/11 14:16:04 brad Exp $"); 20__KERNEL_RCSID(0, "$NetBSD: si70xx.c,v 1.10 2021/11/12 15:12:11 brad Exp $");
21 21
22/* 22/*
23 Driver for the Silicon Labs SI7013/SI7020/SI7021, HTU21D and SHT21 23 Driver for the Silicon Labs SI7013/SI7020/SI7021, HTU21D and SHT21
24*/ 24*/
25 25
26#include <sys/param.h> 26#include <sys/param.h>
27#include <sys/systm.h> 27#include <sys/systm.h>
28#include <sys/kernel.h> 28#include <sys/kernel.h>
29#include <sys/device.h> 29#include <sys/device.h>
30#include <sys/module.h> 30#include <sys/module.h>
31#include <sys/sysctl.h> 31#include <sys/sysctl.h>
32#include <sys/mutex.h> 32#include <sys/mutex.h>
33 33
@@ -599,40 +599,41 @@ si70xx_match(device_t parent, cfdata_t m @@ -599,40 +599,41 @@ si70xx_match(device_t parent, cfdata_t m
599} 599}
600 600
601static void 601static void
602si70xx_attach(device_t parent, device_t self, void *aux) 602si70xx_attach(device_t parent, device_t self, void *aux)
603{ 603{
604 struct si70xx_sc *sc; 604 struct si70xx_sc *sc;
605 struct i2c_attach_args *ia; 605 struct i2c_attach_args *ia;
606 int error, i; 606 int error, i;
607 int ecount = 0; 607 int ecount = 0;
608 uint8_t buf[8]; 608 uint8_t buf[8];
609 uint8_t testcrcpt1[4]; 609 uint8_t testcrcpt1[4];
610 uint8_t testcrcpt2[4]; 610 uint8_t testcrcpt2[4];
611 uint8_t crc1 = 0, crc2 = 0; 611 uint8_t crc1 = 0, crc2 = 0;
 612 bool validcrcpt1, validcrcpt2;
612 uint8_t readcrc1 = 0, readcrc2 = 0; 613 uint8_t readcrc1 = 0, readcrc2 = 0;
613 uint8_t fwversion = 0, model, heaterregister; 614 uint8_t fwversion = 0, model, heaterregister;
614 615
615 ia = aux; 616 ia = aux;
616 sc = device_private(self); 617 sc = device_private(self);
617 618
618 sc->sc_dev = self; 619 sc->sc_dev = self;
619 sc->sc_tag = ia->ia_tag; 620 sc->sc_tag = ia->ia_tag;
620 sc->sc_addr = ia->ia_addr; 621 sc->sc_addr = ia->ia_addr;
621 sc->sc_si70xxdebug = 0; 622 sc->sc_si70xxdebug = 0;
622#ifdef HAVE_I2C_EXECV 623#ifdef HAVE_I2C_EXECV
623 sc->sc_clockstretch = 2048; 624 sc->sc_clockstretch = 2048;
624#endif 625#endif
625 sc->sc_readattempts = 25; 626 sc->sc_readattempts = 40;
626 sc->sc_ignorecrc = false; 627 sc->sc_ignorecrc = false;
627 sc->sc_sme = NULL; 628 sc->sc_sme = NULL;
628 sc->sc_noheater = false; 629 sc->sc_noheater = false;
629 sc->sc_nofw = false; 630 sc->sc_nofw = false;
630 631
631 aprint_normal("\n"); 632 aprint_normal("\n");
632 633
633 mutex_init(&sc->sc_mutex, MUTEX_DEFAULT, IPL_NONE); 634 mutex_init(&sc->sc_mutex, MUTEX_DEFAULT, IPL_NONE);
634 sc->sc_numsensors = __arraycount(si70xx_sensors); 635 sc->sc_numsensors = __arraycount(si70xx_sensors);
635 636
636 if ((sc->sc_sme = sysmon_envsys_create()) == NULL) { 637 if ((sc->sc_sme = sysmon_envsys_create()) == NULL) {
637 aprint_error_dev(self, 638 aprint_error_dev(self,
638 "Unable to create sysmon structure\n"); 639 "Unable to create sysmon structure\n");
@@ -655,68 +656,95 @@ si70xx_attach(device_t parent, device_t  @@ -655,68 +656,95 @@ si70xx_attach(device_t parent, device_t
655 error = si70xx_cmd2(sc, SI70XX_READ_ID_PT1A, SI70XX_READ_ID_PT1B, 656 error = si70xx_cmd2(sc, SI70XX_READ_ID_PT1A, SI70XX_READ_ID_PT1B,
656 buf, 8); 657 buf, 8);
657 if (error) { 658 if (error) {
658 aprint_error_dev(self, "Failed to read first part of ID: %d\n", 659 aprint_error_dev(self, "Failed to read first part of ID: %d\n",
659 error); 660 error);
660 ecount++; 661 ecount++;
661 } 662 }
662 testcrcpt1[0] = buf[0]; 663 testcrcpt1[0] = buf[0];
663 testcrcpt1[1] = buf[2]; 664 testcrcpt1[1] = buf[2];
664 testcrcpt1[2] = buf[4]; 665 testcrcpt1[2] = buf[4];
665 testcrcpt1[3] = buf[6]; 666 testcrcpt1[3] = buf[6];
666 readcrc1 = buf[7]; 667 readcrc1 = buf[7];
667 crc1 = si70xx_crc(testcrcpt1, 4); 668 crc1 = si70xx_crc(testcrcpt1, 4);
 669 /* A "real" SI70xx has the CRC cover the entire first part of the
 670 * serial number. An HTU21D has the CRC broken out into each
 671 * part of the serial number.
 672 */
 673 validcrcpt1 = (readcrc1 == crc1);
 674 if (! validcrcpt1) {
 675 validcrcpt1 = (si70xx_crc(&testcrcpt1[0],1) == buf[1] &&
 676 si70xx_crc(&testcrcpt1[1],1) == buf[3] &&
 677 si70xx_crc(&testcrcpt1[2],1) == buf[5] &&
 678 si70xx_crc(&testcrcpt1[3],1) == buf[7]);
 679 DPRINTF(sc, 2, ("%s: Part 1 SN CRC was not valid for real type, "
 680 "check clone: %d\n", device_xname(sc->sc_dev), validcrcpt1));
 681 }
668 682
669 DPRINTF(sc, 2, ("%s: read 1 values: %02x%02x%02x%02x%02x%02x%02x%02x " 683 DPRINTF(sc, 2, ("%s: read 1 values: %02x%02x%02x%02x%02x%02x%02x%02x "
670 "- %02x\n", device_xname(sc->sc_dev), buf[0], buf[1], 684 "- %02x -- %d\n", device_xname(sc->sc_dev), buf[0], buf[1],
671 buf[2], buf[3], buf[4], buf[5], buf[6], buf[7], 685 buf[2], buf[3], buf[4], buf[5], buf[6], buf[7],
672 crc1)); 686 crc1, validcrcpt1));
673 687
674 error = si70xx_cmd2(sc, SI70XX_READ_ID_PT2A, SI70XX_READ_ID_PT2B, 688 error = si70xx_cmd2(sc, SI70XX_READ_ID_PT2A, SI70XX_READ_ID_PT2B,
675 buf, 8); 689 buf, 8);
676 if (error != 0) { 690 if (error != 0) {
677 aprint_error_dev(self, "Failed to read second part of ID: %d\n", 691 aprint_error_dev(self, "Failed to read second part of ID: %d\n",
678 error); 692 error);
679 ecount++; 693 ecount++;
680 } 694 }
681 model = testcrcpt2[0] = buf[0]; 695 model = testcrcpt2[0] = buf[0];
682 testcrcpt2[1] = buf[1]; 696 testcrcpt2[1] = buf[1];
683 testcrcpt2[2] = buf[3]; 697 testcrcpt2[2] = buf[3];
684 testcrcpt2[3] = buf[4]; 698 testcrcpt2[3] = buf[4];
685 readcrc2 = buf[5]; 699 readcrc2 = buf[5];
686 crc2 = si70xx_crc(testcrcpt2, 4); 700 crc2 = si70xx_crc(testcrcpt2, 4);
 701 /* It is even stranger for this part of the serial number. A "real"
 702 * SI70XX will have a single CRC for the entire second part, but
 703 * an HTU21D has a CRC for each word in this case.
 704 *
 705 * The datasheet actually agrees with the HTU21D case, and not the "real"
 706 * chip.
 707 */
 708 validcrcpt2 = (readcrc2 == crc2);
 709 if (! validcrcpt2) {
 710 validcrcpt2 = (si70xx_crc(&testcrcpt2[0],2) == buf[2] &&
 711 si70xx_crc(&testcrcpt2[2],2) == buf[5]);
 712 DPRINTF(sc, 2, ("%s: Part 2 SN CRC was not valid for real type, "
 713 "check clone: %d\n", device_xname(sc->sc_dev), validcrcpt2));
 714 }
687 715
688 DPRINTF(sc, 2, ("%s: read 2 values: %02x%02x%02x%02x%02x%02x - %02x\n", 716 DPRINTF(sc, 2, ("%s: read 2 values: %02x%02x%02x%02x%02x%02x - %02x -- %d\n",
689 device_xname(sc->sc_dev), buf[0], buf[1], buf[2], 717 device_xname(sc->sc_dev), buf[0], buf[1], buf[2],
690 buf[3], buf[4], buf[5], crc2)); 718 buf[3], buf[4], buf[5], crc2, validcrcpt2));
691 719
692 error = si70xx_cmd2(sc, SI70XX_READ_FW_VERA, SI70XX_READ_FW_VERB, 720 error = si70xx_cmd2(sc, SI70XX_READ_FW_VERA, SI70XX_READ_FW_VERB,
693 buf, 8); 721 buf, 8);
694 722
695 if (error) { 723 if (error) {
696 aprint_error_dev(self, "Failed to read firmware version: %d\n", 724 aprint_error_dev(self, "Failed to read firmware version: Error %d\n",
697 error); 725 error);
698 sc->sc_nofw = true; 726 sc->sc_nofw = true;
699 } 727 }
700 if (! sc->sc_nofw) { 728 if (! sc->sc_nofw) {
701 fwversion = buf[0]; 729 fwversion = buf[0];
702 DPRINTF(sc, 2, ("%s: read fw values: %#x\n", device_xname(sc->sc_dev), 730 DPRINTF(sc, 2, ("%s: read fw values: %#x\n", device_xname(sc->sc_dev),
703 fwversion)); 731 fwversion));
704 } 732 }
705 733
706 error = si70xx_cmd1(sc, SI70XX_READ_HEATER_REG, &heaterregister, 1); 734 error = si70xx_cmd1(sc, SI70XX_READ_HEATER_REG, &heaterregister, 1);
707 735
708 if (error) { 736 if (error) {
709 aprint_error_dev(self, "Failed to read heater register: %d\n", 737 aprint_error_dev(self, "Failed to read heater register: Error %d\n",
710 error); 738 error);
711 sc->sc_noheater = true; 739 sc->sc_noheater = true;
712 } 740 }
713 741
714 error = si70xx_update_status(sc); 742 error = si70xx_update_status(sc);
715 743
716 iic_release_bus(sc->sc_tag, 0); 744 iic_release_bus(sc->sc_tag, 0);
717 745
718 if ((error = si70xx_sysctl_init(sc)) != 0) { 746 if ((error = si70xx_sysctl_init(sc)) != 0) {
719 aprint_error_dev(self, "Can't setup sysctl tree (%d)\n", error); 747 aprint_error_dev(self, "Can't setup sysctl tree (%d)\n", error);
720 goto out; 748 goto out;
721 } 749 }
722 750
@@ -749,31 +777,26 @@ si70xx_attach(device_t parent, device_t  @@ -749,31 +777,26 @@ si70xx_attach(device_t parent, device_t
749 sc->sc_sme->sme_name = device_xname(sc->sc_dev); 777 sc->sc_sme->sme_name = device_xname(sc->sc_dev);
750 sc->sc_sme->sme_cookie = sc; 778 sc->sc_sme->sme_cookie = sc;
751 sc->sc_sme->sme_refresh = si70xx_refresh; 779 sc->sc_sme->sme_refresh = si70xx_refresh;
752 780
753 DPRINTF(sc, 2, ("si70xx_attach: registering with envsys\n")); 781 DPRINTF(sc, 2, ("si70xx_attach: registering with envsys\n"));
754 782
755 if (sysmon_envsys_register(sc->sc_sme)) { 783 if (sysmon_envsys_register(sc->sc_sme)) {
756 aprint_error_dev(self, 784 aprint_error_dev(self,
757 "unable to register with sysmon\n"); 785 "unable to register with sysmon\n");
758 sysmon_envsys_destroy(sc->sc_sme); 786 sysmon_envsys_destroy(sc->sc_sme);
759 sc->sc_sme = NULL; 787 sc->sc_sme = NULL;
760 return; 788 return;
761 } 789 }
762 if (ecount != 0) { 
763 aprint_normal_dev(self, "Could not read model, " 
764 "probably an HTU21D\n"); 
765 return; 
766 } 
767 790
768 char modelstr[64]; 791 char modelstr[64];
769 switch (model) { 792 switch (model) {
770 case 0: 793 case 0:
771 case 0xff: 794 case 0xff:
772 snprintf(modelstr, sizeof(modelstr), "Engineering Sample"); 795 snprintf(modelstr, sizeof(modelstr), "Engineering Sample");
773 break; 796 break;
774 case 13: 797 case 13:
775 case 20: 798 case 20:
776 case 21: 799 case 21:
777 snprintf(modelstr, sizeof(modelstr), "SI70%d", model); 800 snprintf(modelstr, sizeof(modelstr), "SI70%d", model);
778 break; 801 break;
779 default: 802 default:
@@ -790,27 +813,27 @@ si70xx_attach(device_t parent, device_t  @@ -790,27 +813,27 @@ si70xx_attach(device_t parent, device_t
790 fwversionstr = "2.0"; 813 fwversionstr = "2.0";
791 break; 814 break;
792 default: 815 default:
793 fwversionstr = "unknown"; 816 fwversionstr = "unknown";
794 break; 817 break;
795 } 818 }
796 819
797 aprint_normal_dev(self, "Silicon Labs Model: %s, " 820 aprint_normal_dev(self, "Silicon Labs Model: %s, "
798 "Firmware version: %s, " 821 "Firmware version: %s, "
799 "Serial number: %02x%02x%02x%02x%02x%02x%02x%02x%s", 822 "Serial number: %02x%02x%02x%02x%02x%02x%02x%02x%s",
800 modelstr, fwversionstr, testcrcpt1[0], testcrcpt1[1], 823 modelstr, fwversionstr, testcrcpt1[0], testcrcpt1[1],
801 testcrcpt1[2], testcrcpt1[3], testcrcpt2[0], testcrcpt2[1], 824 testcrcpt1[2], testcrcpt1[3], testcrcpt2[0], testcrcpt2[1],
802 testcrcpt2[2], testcrcpt2[3], 825 testcrcpt2[2], testcrcpt2[3],
803 (crc1 == readcrc1 && crc2 == readcrc2) ? "\n" : " (bad crc)\n"); 826 (validcrcpt1 && validcrcpt2) ? "\n" : " (bad crc)\n");
804 return; 827 return;
805out: 828out:
806 sysmon_envsys_destroy(sc->sc_sme); 829 sysmon_envsys_destroy(sc->sc_sme);
807 sc->sc_sme = NULL; 830 sc->sc_sme = NULL;
808} 831}
809 832
810static int 833static int
811si70xx_exec(struct si70xx_sc *sc, uint8_t cmd, envsys_data_t *edata) 834si70xx_exec(struct si70xx_sc *sc, uint8_t cmd, envsys_data_t *edata)
812{ 835{
813 int error; 836 int error;
814 int xdelay; 837 int xdelay;
815 const char *name; 838 const char *name;
816 int64_t mul, offs; 839 int64_t mul, offs;