Module Name:    src
Committed By:   brad
Date:           Sun Oct  3 17:27:02 UTC 2021

Modified Files:
        src/distrib/sets/lists/man: mi
        src/distrib/sets/lists/modules: mi
        src/share/man/man4: Makefile
        src/sys/dev/i2c: files.i2c
        src/sys/modules: Makefile
Added Files:
        src/share/man/man4: sht4xtemp.4
        src/sys/dev/i2c: sht4x.c sht4xreg.h sht4xvar.h
        src/sys/modules/sht4xtemp: Makefile sht4xtemp.ioconf

Log Message:
A driver for the Sensirion SHT40/SHT41/SHT45 temperature and humidity
sensor.  An example of this chip is:

https://www.adafruit.com/product/4885

This is a lower cost chip that provides higher then usual precision
according to the data sheet.  This driver supports all of the published
functions that the chip has.


To generate a diff of this commit:
cvs rdiff -u -r1.1725 -r1.1726 src/distrib/sets/lists/man/mi
cvs rdiff -u -r1.146 -r1.147 src/distrib/sets/lists/modules/mi
cvs rdiff -u -r1.715 -r1.716 src/share/man/man4/Makefile
cvs rdiff -u -r0 -r1.1 src/share/man/man4/sht4xtemp.4
cvs rdiff -u -r1.116 -r1.117 src/sys/dev/i2c/files.i2c
cvs rdiff -u -r0 -r1.1 src/sys/dev/i2c/sht4x.c src/sys/dev/i2c/sht4xreg.h \
    src/sys/dev/i2c/sht4xvar.h
cvs rdiff -u -r1.256 -r1.257 src/sys/modules/Makefile
cvs rdiff -u -r0 -r1.1 src/sys/modules/sht4xtemp/Makefile \
    src/sys/modules/sht4xtemp/sht4xtemp.ioconf

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

Modified files:

Index: src/distrib/sets/lists/man/mi
diff -u src/distrib/sets/lists/man/mi:1.1725 src/distrib/sets/lists/man/mi:1.1726
--- src/distrib/sets/lists/man/mi:1.1725	Sun Aug  1 21:56:26 2021
+++ src/distrib/sets/lists/man/mi	Sun Oct  3 17:27:02 2021
@@ -1,4 +1,4 @@
-# $NetBSD: mi,v 1.1725 2021/08/01 21:56:26 andvar Exp $
+# $NetBSD: mi,v 1.1726 2021/10/03 17:27:02 brad Exp $
 #
 # Note: don't delete entries from here - mark them as "obsolete" instead.
 #
@@ -1723,6 +1723,7 @@
 ./usr/share/man/cat4/shb.0			man-sys-catman		.cat
 ./usr/share/man/cat4/shmif.0			man-sys-catman		.cat
 ./usr/share/man/cat4/shpcic.0			man-sys-catman		.cat
+./usr/share/man/cat4/sht4xtemp.0		man-sys-catman		.cat
 ./usr/share/man/cat4/si.0			man-sys-catman		.cat
 ./usr/share/man/cat4/si70xxtemp.0		man-sys-catman		.cat
 ./usr/share/man/cat4/siisata.0			man-sys-catman		.cat
@@ -4896,6 +4897,7 @@
 ./usr/share/man/html4/shb.html			man-sys-htmlman		html
 ./usr/share/man/html4/shmif.html		man-sys-htmlman		html
 ./usr/share/man/html4/shpcic.html		man-sys-htmlman		html
+./usr/share/man/html4/sht4xtemp.html		man-sys-htmlman		html
 ./usr/share/man/html4/si.html			man-sys-htmlman		html
 ./usr/share/man/html4/si70xxtemp.html		man-sys-htmlman		html
 ./usr/share/man/html4/siisata.html		man-sys-htmlman		html
@@ -7975,6 +7977,7 @@
 ./usr/share/man/man4/shb.4			man-sys-man		.man
 ./usr/share/man/man4/shmif.4			man-sys-man		.man
 ./usr/share/man/man4/shpcic.4			man-sys-man		.man
+./usr/share/man/man4/sht4xtemp.4		man-sys-man		.man
 ./usr/share/man/man4/si.4			man-sys-man		.man
 ./usr/share/man/man4/si70xxtemp.4		man-sys-man		.man
 ./usr/share/man/man4/siisata.4			man-sys-man		.man

Index: src/distrib/sets/lists/modules/mi
diff -u src/distrib/sets/lists/modules/mi:1.146 src/distrib/sets/lists/modules/mi:1.147
--- src/distrib/sets/lists/modules/mi:1.146	Sat Sep 11 16:10:37 2021
+++ src/distrib/sets/lists/modules/mi	Sun Oct  3 17:27:02 2021
@@ -1,4 +1,4 @@
-# $NetBSD: mi,v 1.146 2021/09/11 16:10:37 pgoyette Exp $
+# $NetBSD: mi,v 1.147 2021/10/03 17:27:02 brad Exp $
 #
 # Note: don't delete entries from here - mark them as "obsolete" instead.
 #
@@ -397,6 +397,8 @@
 ./@MODULEDIR@/securelevel/securelevel.kmod	modules-base-kernel	kmod
 ./@MODULEDIR@/sequencer				modules-base-kernel	kmod
 ./@MODULEDIR@/sequencer/sequencer.kmod		modules-base-kernel	kmod
+./@MODULEDIR@/sht4xtemp				modules-base-kernel     kmod
+./@MODULEDIR@/sht4xtemp/sht4xtemp.kmod		modules-base-kernel     kmod
 ./@MODULEDIR@/si70xxtemp			modules-base-kernel	kmod
 ./@MODULEDIR@/si70xxtemp/si70xxtemp.kmod	modules-base-kernel	kmod
 ./@MODULEDIR@/skipjack				modules-base-kernel	kmod

Index: src/share/man/man4/Makefile
diff -u src/share/man/man4/Makefile:1.715 src/share/man/man4/Makefile:1.716
--- src/share/man/man4/Makefile:1.715	Sun Aug  1 21:56:27 2021
+++ src/share/man/man4/Makefile	Sun Oct  3 17:27:02 2021
@@ -1,4 +1,4 @@
-#	$NetBSD: Makefile,v 1.715 2021/08/01 21:56:27 andvar Exp $
+#	$NetBSD: Makefile,v 1.716 2021/10/03 17:27:02 brad Exp $
 #	@(#)Makefile	8.1 (Berkeley) 6/18/93
 
 MAN=	aac.4 ac97.4 acardide.4 aceride.4 acphy.4 \
@@ -56,7 +56,7 @@ MAN=	aac.4 ac97.4 acardide.4 aceride.4 a
 	rnd.4 route.4 rs5c372rtc.4 rtk.4 rtsx.4 rtw.4 rtwn.4 rum.4 run.4 \
 	s390rtc.4 satalink.4 sbus.4 schide.4 \
 	scsi.4 sctp.4 sd.4 se.4 seeprom.4 sem.4 \
-	ses.4 sf.4 sfb.4 sgsmix.4 shb.4 shmif.4 shpcic.4 si70xxtemp.4 \
+	ses.4 sf.4 sfb.4 sgsmix.4 shb.4 shmif.4 shpcic.4 sht4xtemp.4 si70xxtemp.4 \
 	siisata.4 siop.4 sip.4 siside.4 sk.4 sl.4 slide.4 \
 	sm.4 smscphy.4 smsh.4 sn.4 sony.4 spc.4 speaker.4 spif.4 sqphy.4 \
 	srt.4 ss.4 \

Index: src/sys/dev/i2c/files.i2c
diff -u src/sys/dev/i2c/files.i2c:1.116 src/sys/dev/i2c/files.i2c:1.117
--- src/sys/dev/i2c/files.i2c:1.116	Tue Jul 27 20:23:41 2021
+++ src/sys/dev/i2c/files.i2c	Sun Oct  3 17:27:02 2021
@@ -1,4 +1,4 @@
-#	$NetBSD: files.i2c,v 1.116 2021/07/27 20:23:41 macallan Exp $
+#	$NetBSD: files.i2c,v 1.117 2021/10/03 17:27:02 brad Exp $
 
 obsolete defflag	opt_i2cbus.h		I2C_SCAN
 define	i2cbus { }
@@ -395,6 +395,11 @@ device	cwfg: sysmon_envsys
 attach	cwfg at iic
 file	dev/i2c/cwfg.c				cwfg
 
+# Sensirion SHT40/SHT41/SHT45 Temperature and Humidity sensor
+device sht4xtemp
+attach sht4xtemp at iic
+file dev/i2c/sht4x.c				sht4xtemp
+
 # Philips PCA955x GPIO
 device	pcagpio: leds
 attach	pcagpio at iic

Index: src/sys/modules/Makefile
diff -u src/sys/modules/Makefile:1.256 src/sys/modules/Makefile:1.257
--- src/sys/modules/Makefile:1.256	Sat Sep 25 17:55:37 2021
+++ src/sys/modules/Makefile	Sun Oct  3 17:27:02 2021
@@ -1,4 +1,4 @@
-#	$NetBSD: Makefile,v 1.256 2021/09/25 17:55:37 maya Exp $
+#	$NetBSD: Makefile,v 1.257 2021/10/03 17:27:02 brad Exp $
 
 .include <bsd.own.mk>
 
@@ -69,6 +69,7 @@ SUBDIR+=	hfs
 SUBDIR+=	hythygtemp
 SUBDIR+=	si70xxtemp
 SUBDIR+=	am2315temp
+SUBDIR+=	sht4xtemp
 SUBDIR+=	i2cexec
 SUBDIR+=	i2c_bitbang
 SUBDIR+=	if_agr

Added files:

Index: src/share/man/man4/sht4xtemp.4
diff -u /dev/null src/share/man/man4/sht4xtemp.4:1.1
--- /dev/null	Sun Oct  3 17:27:03 2021
+++ src/share/man/man4/sht4xtemp.4	Sun Oct  3 17:27:02 2021
@@ -0,0 +1,93 @@
+.\" $NetBSD: sht4xtemp.4,v 1.1 2021/10/03 17:27:02 brad Exp $
+.\"
+.\" Copyright (c) 2021 Brad Spencer <b...@anduin.eldar.org>
+.\"
+.\" Permission to use, copy, modify, and distribute this software for any
+.\" purpose with or without fee is hereby granted, provided that the above
+.\" copyright notice and this permission notice appear in all copies.
+.\"
+.\" THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+.\" WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+.\" MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+.\" ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+.\" WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+.\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+.\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+.\"
+.Dd September 28th, 2021
+.Dt SHT4XTEMP 4
+.Os
+.Sh NAME
+.Nm sht4xtemp
+.Nd Driver for Sensirion SHT40/SHT41/SHT45 sensor chip via I2C bus
+.Sh SYNOPSIS
+.Cd "sht4xtemp* at iic? addr 0x44"
+.Sh DESCRIPTION
+The
+.Nm
+driver provides measurements from the SHT40/SHT41/SHT45 humidity/temperature
+sensors via the
+.Xr envsys 4
+framework.
+The
+.Nm
+.Ar addr
+argument selects the address at the
+.Xr iic 4
+bus.
+The resolution, heater controls and crc validity can be changed through
+.Xr sysctl 8
+nodes.
+.Sh SYSCTL VARIABLES
+The following
+.Xr sysctl 3
+variables are provided:
+.Bl -tag -width indent
+.It hw.sht4xtemp0.resolutions
+Lists the resolutions supported by the driver and chip.
+.It hw.sht4xtemp0.resolution
+Set the resolution, or number of bits, used for %RH and temperature.
+Use one of the strings listed in hw.sht4xtemp.resolutions.
+.It hw.sht4xtemp0.ignorecrc
+If set, the crc calculation for %RH and temperature will be ignored.
+.It hw.sht4xtemp0.heateron
+Turn the heater on and off.  Please note that the heater is turned on right
+before the measurement and runs for a pulse width of time.  Then the measurement
+is taken and the heater is turned off.  There is no way to keep the heater running
+with this chip.
+.It hw.sht4xtemp0.heaterstrength
+From 1 to 3, the amount of energy put into the heater.
+The higher the number, the more power used.
+.It hw.sht4xtemp0.heaterpulses
+Lists the valid heater pulses supported by the driver and chip.
+.It hw.sht4xtemp0.heaterpulse
+Set the heater pulse length.  Use one of the strings listed in
+hw.sht4xtemp.heaterpulses
+.It hw.sht4xtemp0.debug
+If the driver is compiled with
+.Dv SI70XX_DEBUG ,
+this node will appear and can be used to set the debugging level.
+.It hw.sht4xtemp0.readattempts
+To read %RH or temperature the chip requires that the command be sent,
+then a delay must be observed before a read can be done to get the values
+back.  The delays are documented in the datasheet for the chip.
+The driver will attempt to read back the values readattempts number of
+times.
+The default is 10 which should be more than enough for most purposes.
+.El
+.Sh SEE ALSO
+.Xr envsys 4 ,
+.Xr iic 4 ,
+.Xr envstat 8 ,
+.Xr sysctl 8
+.Sh HISTORY
+The
+.Nm
+driver first appeared in
+.Nx 10.0 .
+.Sh AUTHORS
+.An -nosplit
+The
+.Nm
+driver was written by
+.An Brad Spencer Aq Mt b...@anduin.eldar.org .

Index: src/sys/dev/i2c/sht4x.c
diff -u /dev/null src/sys/dev/i2c/sht4x.c:1.1
--- /dev/null	Sun Oct  3 17:27:03 2021
+++ src/sys/dev/i2c/sht4x.c	Sun Oct  3 17:27:02 2021
@@ -0,0 +1,886 @@
+/*	$NetBSD: sht4x.c,v 1.1 2021/10/03 17:27:02 brad Exp $	*/
+
+/*
+ * Copyright (c) 2021 Brad Spencer <b...@anduin.eldar.org>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <sys/cdefs.h>
+__KERNEL_RCSID(0, "$NetBSD: sht4x.c,v 1.1 2021/10/03 17:27:02 brad Exp $");
+
+/*
+  Driver for the Sensirion SHT40/SHT41/SHT45
+*/
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/kernel.h>
+#include <sys/device.h>
+#include <sys/module.h>
+#include <sys/sysctl.h>
+#include <sys/mutex.h>
+
+#include <dev/sysmon/sysmonvar.h>
+#include <dev/i2c/i2cvar.h>
+#include <dev/i2c/sht4xreg.h>
+#include <dev/i2c/sht4xvar.h>
+
+
+static uint8_t 	sht4x_crc(uint8_t *, size_t);
+static int 	sht4x_poke(i2c_tag_t, i2c_addr_t, bool);
+static int 	sht4x_match(device_t, cfdata_t, void *);
+static void 	sht4x_attach(device_t, device_t, void *);
+static int 	sht4x_detach(device_t, int);
+static void 	sht4x_refresh(struct sysmon_envsys *, envsys_data_t *);
+static int 	sht4x_verify_sysctl(SYSCTLFN_ARGS);
+static int 	sht4x_verify_sysctl_resolution(SYSCTLFN_ARGS);
+static int 	sht4x_verify_sysctl_heateron(SYSCTLFN_ARGS);
+static int 	sht4x_verify_sysctl_heatervalue(SYSCTLFN_ARGS);
+static int 	sht4x_verify_sysctl_heaterpulse(SYSCTLFN_ARGS);
+
+#define SHT4X_DEBUG
+#ifdef SHT4X_DEBUG
+#define DPRINTF(s, l, x) \
+    do { \
+	if (l <= s->sc_sht4xdebug) \
+	    printf x; \
+    } while (/*CONSTCOND*/0)
+#else
+#define DPRINTF(s, l, x)
+#endif
+
+CFATTACH_DECL_NEW(sht4xtemp, sizeof(struct sht4x_sc),
+    sht4x_match, sht4x_attach, sht4x_detach, NULL);
+
+static struct sht4x_sensor sht4x_sensors[] = {
+	{
+		.desc = "humidity",
+		.type = ENVSYS_SRELHUMIDITY,
+	},
+	{
+		.desc = "temperature",
+		.type = ENVSYS_STEMP,
+	}
+};
+
+/* The typical delays are documented in the datasheet for the chip.
+   There is no need to be very accurate with these, just rough estimates
+   will work fine.
+*/
+
+static struct sht4x_timing sht4x_timings[] = {
+	{
+		.cmd = SHT4X_READ_SERIAL,
+		.typicaldelay = 5000,
+	},
+	{
+		.cmd = SHT4X_SOFT_RESET,
+		.typicaldelay = 1000,
+	},
+	{
+		.cmd = SHT4X_MEASURE_HIGH_PRECISION,
+		.typicaldelay = 8000,
+	},
+	{
+		.cmd = SHT4X_MEASURE_MEDIUM_PRECISION,
+		.typicaldelay = 4000,
+	},
+	{
+		.cmd = SHT4X_MEASURE_LOW_PRECISION,
+		.typicaldelay = 2000,
+	},
+	{
+		.cmd = SHT4X_MEASURE_HIGH_PRECISION_HIGH_HEAT_1_S,
+		.typicaldelay = 1000000,
+	},
+	{
+		.cmd = SHT4X_MEASURE_HIGH_PRECISION_MEDIUM_HEAT_1_S,
+		.typicaldelay = 1000000,
+	},
+	{
+		.cmd = SHT4X_MEASURE_HIGH_PRECISION_LOW_HEAT_1_S,
+		.typicaldelay = 1000000,
+	},
+	{
+		.cmd = SHT4X_MEASURE_HIGH_PRECISION_HIGH_HEAT_TENTH_S,
+		.typicaldelay = 100000,
+	},
+	{
+		.cmd = SHT4X_MEASURE_HIGH_PRECISION_MEDIUM_HEAT_TENTH_S,
+		.typicaldelay = 100000,
+	},
+	{
+		.cmd = SHT4X_MEASURE_HIGH_PRECISION_LOW_HEAT_TENTH_S,
+		.typicaldelay = 100000,
+	}
+};
+
+/* Used when the heater is not on to find the command to use for the
+ * measurement.
+ */
+
+static struct sht4x_resolution sht4x_resolutions[] = {
+	{
+		.text = "high",
+		.cmd = SHT4X_MEASURE_HIGH_PRECISION,
+	},
+	{
+		.text = "medium",
+		.cmd = SHT4X_MEASURE_MEDIUM_PRECISION,
+	},
+	{
+		.text = "low",
+		.cmd = SHT4X_MEASURE_LOW_PRECISION,
+	}
+};
+
+static const char sht4x_resolution_names[] =
+    "high, medium, low";
+
+static struct sht4x_heaterpulse sht4x_heaterpulses[] = {
+	{
+		.length = "short",
+	},
+	{
+		.length = "long",
+	}
+};
+
+/* This is consulted when the heater is on for which command is to be
+   used for the measurement.
+*/
+
+static struct sht4x_heateron_command sht4x_heateron_commands[] = {
+	{
+		.heatervalue = 1,
+		.pulselength = "short",
+		.cmd = SHT4X_MEASURE_HIGH_PRECISION_LOW_HEAT_TENTH_S,
+	},
+	{
+		.heatervalue = 2,
+		.pulselength = "short",
+		.cmd = SHT4X_MEASURE_HIGH_PRECISION_MEDIUM_HEAT_TENTH_S,
+	},
+	{
+		.heatervalue = 3,
+		.pulselength = "short",
+		.cmd = SHT4X_MEASURE_HIGH_PRECISION_HIGH_HEAT_TENTH_S,
+	},
+	{
+		.heatervalue = 1,
+		.pulselength = "long",
+		.cmd = SHT4X_MEASURE_HIGH_PRECISION_LOW_HEAT_1_S,
+	},
+	{
+		.heatervalue = 2,
+		.pulselength = "long",
+		.cmd = SHT4X_MEASURE_HIGH_PRECISION_MEDIUM_HEAT_1_S,
+	},
+	{
+		.heatervalue = 3,
+		.pulselength = "long",
+		.cmd = SHT4X_MEASURE_HIGH_PRECISION_HIGH_HEAT_1_S,
+	}
+};
+
+static const char sht4x_heaterpulse_names[] =
+    "short, long";
+
+int
+sht4x_verify_sysctl(SYSCTLFN_ARGS)
+{
+	int error, t;
+	struct sysctlnode node;
+
+	node = *rnode;
+	t = *(int *)rnode->sysctl_data;
+	node.sysctl_data = &t;
+	error = sysctl_lookup(SYSCTLFN_CALL(&node));
+	if (error || newp == NULL)
+		return error;
+
+	if (t < 0)
+		return EINVAL;
+
+	*(int *)rnode->sysctl_data = t;
+
+	return 0;
+}
+
+/* None of the heater and resolutions sysctls change anything on the chip in
+   real time.  The values set are used to send different commands depending on
+   how they are set up.
+
+   What this implies is that the chip could be reset and the driver would not care.
+
+*/
+
+int
+sht4x_verify_sysctl_resolution(SYSCTLFN_ARGS)
+{
+	char buf[SHT4X_RES_NAME];
+	struct sht4x_sc *sc;
+	struct sysctlnode node;
+	int error = 0;
+	size_t i;
+
+	node = *rnode;
+	sc = node.sysctl_data;
+	(void) memcpy(buf, sc->sc_resolution, SHT4X_RES_NAME);
+	node.sysctl_data = buf;
+	error = sysctl_lookup(SYSCTLFN_CALL(&node));
+	if (error || newp == NULL)
+		return error;
+
+	for (i = 0; i < __arraycount(sht4x_resolutions); i++) {
+		if (strncmp(node.sysctl_data, sht4x_resolutions[i].text,
+		    SHT4X_RES_NAME) == 0) {
+			break;
+		}
+	}
+
+	if (i == __arraycount(sht4x_resolutions))
+		return EINVAL;
+	(void) memcpy(sc->sc_resolution, node.sysctl_data, SHT4X_RES_NAME);
+
+	return error;
+}
+
+int
+sht4x_verify_sysctl_heateron(SYSCTLFN_ARGS)
+{
+	int 		error;
+	bool 		t;
+	struct sht4x_sc *sc;
+	struct sysctlnode node;
+
+	node = *rnode;
+	sc = node.sysctl_data;
+	t = sc->sc_heateron;
+	node.sysctl_data = &t;
+	error = sysctl_lookup(SYSCTLFN_CALL(&node));
+	if (error || newp == NULL)
+		return error;
+
+	sc->sc_heateron = t;
+
+	return error;
+}
+
+int
+sht4x_verify_sysctl_heatervalue(SYSCTLFN_ARGS)
+{
+	int 		error = 0, t;
+	struct sht4x_sc *sc;
+	struct sysctlnode node;
+
+	node = *rnode;
+	sc = node.sysctl_data;
+	t = sc->sc_heaterval;
+	node.sysctl_data = &t;
+	error = sysctl_lookup(SYSCTLFN_CALL(&node));
+	if (error || newp == NULL)
+		return (error);
+
+	if (t < 1 || t > 3)
+		return (EINVAL);
+
+	sc->sc_heaterval = t;
+
+	return error;
+}
+
+int
+sht4x_verify_sysctl_heaterpulse(SYSCTLFN_ARGS)
+{
+	char buf[SHT4X_PULSE_NAME];
+	struct sht4x_sc *sc;
+	struct sysctlnode node;
+	int error = 0;
+	size_t i;
+
+	node = *rnode;
+	sc = node.sysctl_data;
+	(void) memcpy(buf, sc->sc_heaterpulse, SHT4X_PULSE_NAME);
+	node.sysctl_data = buf;
+	error = sysctl_lookup(SYSCTLFN_CALL(&node));
+	if (error || newp == NULL)
+		return error;
+
+	for (i = 0; i < __arraycount(sht4x_heaterpulses); i++) {
+		if (strncmp(node.sysctl_data, sht4x_heaterpulses[i].length,
+		    SHT4X_RES_NAME) == 0) {
+			break;
+		}
+	}
+
+	if (i == __arraycount(sht4x_heaterpulses))
+		return EINVAL;
+	(void) memcpy(sc->sc_heaterpulse, node.sysctl_data, SHT4X_PULSE_NAME);
+
+	return error;
+}
+
+static int
+sht4x_cmddelay(uint8_t cmd)
+{
+	int r = -1;
+
+	for(int i = 0;i < __arraycount(sht4x_timings);i++) {
+		if (cmd == sht4x_timings[i].cmd) {
+			r = sht4x_timings[i].typicaldelay;
+			break;
+		}
+	}
+
+	if (r == -1) {
+		panic("Bad command look up in cmd delay: cmd: %d\n",cmd);
+	}
+
+	return r;
+}
+
+static int
+sht4x_cmd(i2c_tag_t tag, i2c_addr_t addr, uint8_t *cmd,
+    uint8_t clen, uint8_t *buf, size_t blen, int readattempts)
+{
+	int error;
+	int cmddelay;
+
+	error = iic_exec(tag,I2C_OP_WRITE_WITH_STOP,addr,cmd,clen,NULL,0,0);
+
+	/* Every command returns something except for the soft reset
+	   which returns nothing.  This chip is also nice in that pretty
+	   much every command that returns something does it in the same way.
+	*/
+	if (error == 0 && cmd[0] != SHT4X_SOFT_RESET) {
+		cmddelay = sht4x_cmddelay(cmd[0]);
+		delay(cmddelay);
+
+		for (int aint = 0; aint < readattempts; aint++) {
+			error = iic_exec(tag,I2C_OP_READ_WITH_STOP,addr,NULL,0,buf,blen,0);
+			if (error == 0)
+				break;
+			delay(1000);
+		}
+	}
+
+	return error;
+}
+
+static int
+sht4x_cmdr(struct sht4x_sc *sc, uint8_t cmd, uint8_t *buf, size_t blen)
+{
+	return sht4x_cmd(sc->sc_tag, sc->sc_addr, &cmd, 1, buf, blen, sc->sc_readattempts);
+}
+
+static	uint8_t
+sht4x_crc(uint8_t * data, size_t size)
+{
+	uint8_t crc = 0xFF;
+
+	for (size_t i = 0; i < size; i++) {
+		crc ^= data[i];
+		for (size_t j = 8; j > 0; j--) {
+			if (crc & 0x80)
+				crc = (crc << 1) ^ 0x131;
+			else
+				crc <<= 1;
+		}
+	}
+	return crc;
+}
+
+static int
+sht4x_poke(i2c_tag_t tag, i2c_addr_t addr, bool matchdebug)
+{
+	uint8_t reg = SHT4X_READ_SERIAL;
+	uint8_t buf[6];
+	int error;
+
+	error = sht4x_cmd(tag, addr, &reg, 1, buf, 6, 10);
+	if (matchdebug) {
+		printf("poke X 1: %d\n", error);
+	}
+	return error;
+}
+
+static int
+sht4x_sysctl_init(struct sht4x_sc *sc)
+{
+	int error;
+	const struct sysctlnode *cnode;
+	int sysctlroot_num;
+
+	if ((error = sysctl_createv(&sc->sc_sht4xlog, 0, NULL, &cnode,
+	    0, CTLTYPE_NODE, device_xname(sc->sc_dev),
+	    SYSCTL_DESCR("sht4x controls"), NULL, 0, NULL, 0, CTL_HW,
+	    CTL_CREATE, CTL_EOL)) != 0)
+		return error;
+
+	sysctlroot_num = cnode->sysctl_num;
+
+#ifdef SHT4X_DEBUG
+	if ((error = sysctl_createv(&sc->sc_sht4xlog, 0, NULL, &cnode,
+	    CTLFLAG_READWRITE, CTLTYPE_INT, "debug",
+	    SYSCTL_DESCR("Debug level"), sht4x_verify_sysctl, 0,
+	    &sc->sc_sht4xdebug, 0, CTL_HW, sysctlroot_num, CTL_CREATE,
+	    CTL_EOL)) != 0)
+		return error;
+
+#endif
+
+	if ((error = sysctl_createv(&sc->sc_sht4xlog, 0, NULL, &cnode,
+	    CTLFLAG_READWRITE, CTLTYPE_INT, "readattempts",
+	    SYSCTL_DESCR("The number of times to attempt to read the values"),
+	    sht4x_verify_sysctl, 0, &sc->sc_readattempts, 0, CTL_HW,
+	    sysctlroot_num, CTL_CREATE, CTL_EOL)) != 0)
+		return error;
+
+	if ((error = sysctl_createv(&sc->sc_sht4xlog, 0, NULL, &cnode,
+	    CTLFLAG_READONLY, CTLTYPE_STRING, "resolutions",
+	    SYSCTL_DESCR("Valid resolutions"), 0, 0,
+	    __UNCONST(sht4x_resolution_names),
+	    sizeof(sht4x_resolution_names) + 1,
+	    CTL_HW, sysctlroot_num, CTL_CREATE, CTL_EOL)) != 0)
+		return error;
+
+	if ((error = sysctl_createv(&sc->sc_sht4xlog, 0, NULL, &cnode,
+	    CTLFLAG_READWRITE, CTLTYPE_STRING, "resolution",
+	    SYSCTL_DESCR("Resolution of RH and Temp"),
+	    sht4x_verify_sysctl_resolution, 0, (void *) sc,
+	    SHT4X_RES_NAME, CTL_HW, sysctlroot_num, CTL_CREATE, CTL_EOL)) != 0)
+		return error;
+
+	if ((error = sysctl_createv(&sc->sc_sht4xlog, 0, NULL, &cnode,
+	    CTLFLAG_READWRITE, CTLTYPE_BOOL, "ignorecrc",
+	    SYSCTL_DESCR("Ignore the CRC byte"), NULL, 0, &sc->sc_ignorecrc,
+	    0, CTL_HW, sysctlroot_num, CTL_CREATE, CTL_EOL)) != 0)
+		return error;
+
+	if ((error = sysctl_createv(&sc->sc_sht4xlog, 0, NULL, &cnode,
+	    CTLFLAG_READWRITE, CTLTYPE_BOOL, "heateron",
+	    SYSCTL_DESCR("Heater on"), sht4x_verify_sysctl_heateron, 0,
+	    (void *)sc, 0, CTL_HW, sysctlroot_num, CTL_CREATE, CTL_EOL)) != 0)
+		return error;
+
+	if ((error = sysctl_createv(&sc->sc_sht4xlog, 0, NULL, &cnode,
+	    CTLFLAG_READWRITE, CTLTYPE_INT, "heaterstrength",
+	    SYSCTL_DESCR("Heater strength 1 to 3"),
+	    sht4x_verify_sysctl_heatervalue, 0, (void *)sc, 0, CTL_HW,
+	    sysctlroot_num, CTL_CREATE, CTL_EOL)) != 0)
+		return error;
+
+	if ((error = sysctl_createv(&sc->sc_sht4xlog, 0, NULL, &cnode,
+	    CTLFLAG_READONLY, CTLTYPE_STRING, "heaterpulses",
+	    SYSCTL_DESCR("Valid heater pulse lengths"), 0, 0,
+	    __UNCONST(sht4x_heaterpulse_names),
+	    sizeof(sht4x_heaterpulse_names) + 1,
+	    CTL_HW, sysctlroot_num, CTL_CREATE, CTL_EOL)) != 0)
+		return error;
+
+	if ((error = sysctl_createv(&sc->sc_sht4xlog, 0, NULL, &cnode,
+	    CTLFLAG_READWRITE, CTLTYPE_STRING, "heaterpulse",
+	    SYSCTL_DESCR("Heater pulse length"),
+	    sht4x_verify_sysctl_heaterpulse, 0, (void *) sc,
+	    SHT4X_RES_NAME, CTL_HW, sysctlroot_num, CTL_CREATE, CTL_EOL)) != 0)
+		return error;
+	return 0;
+}
+
+static int
+sht4x_match(device_t parent, cfdata_t match, void *aux)
+{
+	struct i2c_attach_args *ia = aux;
+	int error, match_result;
+	const bool matchdebug = false;
+
+	if (iic_use_direct_match(ia, match, NULL, &match_result))
+		return match_result;
+
+	/* indirect config - check for configured address */
+	if (ia->ia_addr != SHT4X_TYPICAL_ADDR)
+		return 0;
+
+	/*
+	 * Check to see if something is really at this i2c address. This will
+	 * keep phantom devices from appearing
+	 */
+	if (iic_acquire_bus(ia->ia_tag, 0) != 0) {
+		if (matchdebug)
+			printf("in match acquire bus failed\n");
+		return 0;
+	}
+
+	error = sht4x_poke(ia->ia_tag, ia->ia_addr, matchdebug);
+	iic_release_bus(ia->ia_tag, 0);
+
+	return error == 0 ? I2C_MATCH_ADDRESS_AND_PROBE : 0;
+}
+
+static void
+sht4x_attach(device_t parent, device_t self, void *aux)
+{
+	struct sht4x_sc *sc;
+	struct i2c_attach_args *ia;
+	int error, i;
+	int ecount = 0;
+	uint8_t buf[6];
+	uint8_t sncrcpt1, sncrcpt2;
+
+	ia = aux;
+	sc = device_private(self);
+
+	sc->sc_dev = self;
+	sc->sc_tag = ia->ia_tag;
+	sc->sc_addr = ia->ia_addr;
+	sc->sc_sht4xdebug = 0;
+	strlcpy(sc->sc_resolution,"high",SHT4X_RES_NAME);
+	sc->sc_readattempts = 10;
+	sc->sc_ignorecrc = false;
+	sc->sc_heateron = false;
+	sc->sc_heaterval = 1;
+	strlcpy(sc->sc_heaterpulse,"short",SHT4X_PULSE_NAME);
+	sc->sc_sme = NULL;
+
+	aprint_normal("\n");
+
+	mutex_init(&sc->sc_mutex, MUTEX_DEFAULT, IPL_NONE);
+	sc->sc_numsensors = __arraycount(sht4x_sensors);
+
+	if ((sc->sc_sme = sysmon_envsys_create()) == NULL) {
+		aprint_error_dev(self,
+		    "Unable to create sysmon structure\n");
+		sc->sc_sme = NULL;
+		return;
+	}
+	if ((error = sht4x_sysctl_init(sc)) != 0) {
+		aprint_error_dev(self, "Can't setup sysctl tree (%d)\n", error);
+		goto out;
+	}
+
+	error = iic_acquire_bus(sc->sc_tag, 0);
+	if (error) {
+		aprint_error_dev(self, "Could not acquire iic bus: %d\n",
+		    error);
+		goto out;
+	}
+
+	error = sht4x_cmdr(sc, SHT4X_SOFT_RESET, NULL, 0);
+	if (error != 0)
+		aprint_error_dev(self, "Reset failed: %d\n", error);
+
+	delay(1000); /* 1 ms max */
+
+	error = sht4x_cmdr(sc, SHT4X_READ_SERIAL, buf, 6);
+	if (error) {
+		aprint_error_dev(self, "Failed to read serial number: %d\n",
+		    error);
+		ecount++;
+	}
+
+	sncrcpt1 = sht4x_crc(&buf[0],2);
+	sncrcpt2 = sht4x_crc(&buf[3],2);
+
+	DPRINTF(sc, 2, ("%s: read serial number values: %02x%02x - %02x, %02x%02x - %02x ; %02x %02x\n",
+	    device_xname(sc->sc_dev), buf[0], buf[1], buf[2], buf[3], buf[4], buf[5], sncrcpt1, sncrcpt2));
+
+	iic_release_bus(sc->sc_tag, 0);
+	if (error != 0) {
+		aprint_error_dev(self, "Unable to setup device\n");
+		goto out;
+	}
+
+	for (i = 0; i < sc->sc_numsensors; i++) {
+		strlcpy(sc->sc_sensors[i].desc, sht4x_sensors[i].desc,
+		    sizeof(sc->sc_sensors[i].desc));
+
+		sc->sc_sensors[i].units = sht4x_sensors[i].type;
+		sc->sc_sensors[i].state = ENVSYS_SINVALID;
+
+		DPRINTF(sc, 2, ("%s: registering sensor %d (%s)\n", __func__, i,
+		    sc->sc_sensors[i].desc));
+
+		error = sysmon_envsys_sensor_attach(sc->sc_sme,
+		    &sc->sc_sensors[i]);
+		if (error) {
+			aprint_error_dev(self,
+			    "Unable to attach sensor %d: %d\n", i, error);
+			goto out;
+		}
+	}
+
+	sc->sc_sme->sme_name = device_xname(sc->sc_dev);
+	sc->sc_sme->sme_cookie = sc;
+	sc->sc_sme->sme_refresh = sht4x_refresh;
+
+	DPRINTF(sc, 2, ("sht4x_attach: registering with envsys\n"));
+
+	if (sysmon_envsys_register(sc->sc_sme)) {
+		aprint_error_dev(self,
+			"unable to register with sysmon\n");
+		sysmon_envsys_destroy(sc->sc_sme);
+		sc->sc_sme = NULL;
+		return;
+	}
+
+	/* There is no documented way to ask the chip what version it is.  This
+	   is likely fine as the only apparent difference is in how precise the
+	   measurements will be.  The actual conversation with the chip is
+	   identical no matter which one you are talking to.
+	*/
+
+	aprint_normal_dev(self, "Sensirion SHT40/SHT41/SHT45, "
+	    "Serial number: %02x%02x%02x%02x%s",
+	    buf[0], buf[1], buf[3], buf[4],
+	    (sncrcpt1 == buf[2] && sncrcpt2 == buf[5]) ? "\n" : " (bad crc)\n");
+	return;
+out:
+	sysmon_envsys_destroy(sc->sc_sme);
+	sc->sc_sme = NULL;
+}
+
+/* If you use the heater on this chip, there is no documented choice but to use
+   the highest precision.  If the heater is not in use one may select different
+   precisions or repeatability for the measurement.
+
+   Further, if the heater is used, it will only be active during the measurement.
+   The use of the heater will add delay to the measurement as chip will not
+   return anything until the heater pulse time is over.
+*/
+
+static uint8_t
+sht4x_compute_measure_command(char *resolution, bool heateron,
+    int heatervalue, char *heaterpulse)
+{
+	int i;
+	uint8_t r;
+
+	if (heateron == false) {
+		for (i = 0; i < __arraycount(sht4x_resolutions); i++) {
+			if (strncmp(resolution, sht4x_resolutions[i].text,
+			    SHT4X_RES_NAME) == 0) {
+				r = sht4x_resolutions[i].cmd;
+				break;
+			}
+		}
+
+		if (i == __arraycount(sht4x_resolutions))
+			panic("Heater off could not find command for resolution: %s\n",resolution);
+	} else {
+		for (i = 0; i < __arraycount(sht4x_heateron_commands); i++) {
+			if (heatervalue == sht4x_heateron_commands[i].heatervalue &&
+			    strncmp(heaterpulse, sht4x_heateron_commands[i].pulselength,
+			    SHT4X_PULSE_NAME) == 0) {
+				r = sht4x_heateron_commands[i].cmd;
+				break;
+			}
+		}
+
+		if (i == __arraycount(sht4x_heateron_commands))
+			panic("Heater on could not find command for heatervalue, heaterpulse: %d %s\n",
+			    heatervalue,heaterpulse);
+	}
+
+	return r;
+}
+
+static void
+sht4x_refresh(struct sysmon_envsys * sme, envsys_data_t * edata)
+{
+	struct sht4x_sc *sc;
+	sc = sme->sme_cookie;
+	int error;
+	uint8_t rawdata[6];
+	uint8_t measurement_command;
+	edata->state = ENVSYS_SINVALID;
+
+	mutex_enter(&sc->sc_mutex);
+	error = iic_acquire_bus(sc->sc_tag, 0);
+	if (error) {
+		DPRINTF(sc, 2, ("%s: Could not acquire i2c bus: %x\n",
+		    device_xname(sc->sc_dev), error));
+		goto out;
+	}
+
+	/*
+	  The documented conversion calculations for the raw values are as follows:
+
+	  %RH = (-6 + 125 * rawvalue / 65535)
+
+	  T in Celsius = (-45 + 175 * rawvalue / 65535)
+
+	  It follows then:
+
+	  T in Kelvin = (229.15 + 175 * rawvalue / 65535)
+
+	  given the relationship between Celsius and Kelvin.
+
+	  What follows reorders the calculation a bit and scales it up to avoid
+	  the use of any floating point.  All that would really have to happen
+	  is a scale up to 10^6 for the sysenv framework, which wants
+	  temperature in micro-kelvin and percent relative humidity scaled up
+	  10^6, but since this conversion uses 64 bits due to intermediate
+	  values that are bigger than 32 bits the conversion first scales up to
+	  10^9 and the scales back down by 10^3 at the end.  This preserves some
+	  precision in the conversion that would otherwise be lost.
+	 */
+
+	measurement_command = sht4x_compute_measure_command(sc->sc_resolution,
+	    sc->sc_heateron, sc->sc_heaterval, sc->sc_heaterpulse);
+	DPRINTF(sc, 2, ("%s: Measurement command: %02x\n",
+	    device_xname(sc->sc_dev), measurement_command));
+
+	/* This chip is pretty nice in that all commands are the same length and
+	   return the same result.  What is not so nice is that you can not ask
+	   for temperature and humidity independently.
+
+	   The result will be 16 bits of raw temperature and a CRC byte followed
+	   by 16 bits of humidity followed by a CRC byte.
+	*/
+
+	error = sht4x_cmdr(sc,measurement_command,rawdata,6);
+
+	if (error == 0) {
+		DPRINTF(sc, 2, ("%s: Raw data: %02x%02x %02x - %02x%02x %02x\n",
+		    device_xname(sc->sc_dev), rawdata[0], rawdata[1], rawdata[2],
+		    rawdata[3], rawdata[4], rawdata[5]));
+
+
+		uint8_t *svalptr;
+		uint64_t svalue;
+		int64_t v1;
+		uint64_t v2;
+		uint64_t d1 = 65535;
+		uint64_t mul1;
+		uint64_t mul2;
+		uint64_t div1 = 10000;
+		uint64_t q;
+
+		switch (edata->sensor) {
+		case SHT4X_TEMP_SENSOR:
+			svalptr = &rawdata[0];
+			v1 = 22915; /* this is scaled up already from 229.15 */
+			v2 = 175;
+			mul1 = 10000000000;
+			mul2 = 100000000;
+			break;
+		case SHT4X_HUMIDITY_SENSOR:
+			svalptr = &rawdata[3];
+			v1 = -6;
+			v2 = 125;
+			mul1 = 10000000000;
+			mul2 = 10000000000;
+			break;
+		default:
+			error = EINVAL;
+			break;
+		}
+
+		if (error == 0) {
+			uint8_t testcrc;
+
+			/* Fake out the CRC check if being asked to ignore CRC */
+			if (sc->sc_ignorecrc) {
+				testcrc = *(svalptr + 2);
+			} else {
+				testcrc = sht4x_crc(svalptr,2);
+			}
+
+			if (*(svalptr + 2) == testcrc) {
+				svalue = *svalptr << 8 | *(svalptr + 1);
+				DPRINTF(sc, 2, ("%s: Raw sensor 16 bit: %#jx\n",
+				    device_xname(sc->sc_dev), (uintmax_t)svalue));
+
+				/* Scale up */
+				svalue = svalue * mul1;
+				v1 = v1 * mul2;
+				/* Perform the conversion */
+				q = ((v2 * (svalue / d1)) + v1) / div1;
+
+				DPRINTF(sc, 2, ("%s: Computed sensor: %#jx\n",
+				    device_xname(sc->sc_dev), (uintmax_t)q));
+				/* The results will fit in 32 bits, so nothing will be lost */
+				edata->value_cur = (uint32_t) q;
+				edata->state = ENVSYS_SVALID;
+			} else {
+				error = EINVAL;
+			}
+		}
+	}
+
+	if (error) {
+		DPRINTF(sc, 2, ("%s: Failed to get new status in refresh %d\n",
+		    device_xname(sc->sc_dev), error));
+	}
+
+	iic_release_bus(sc->sc_tag, 0);
+out:
+	mutex_exit(&sc->sc_mutex);
+}
+
+static int
+sht4x_detach(device_t self, int flags)
+{
+	struct sht4x_sc *sc;
+
+	sc = device_private(self);
+
+	mutex_enter(&sc->sc_mutex);
+
+	/* Remove the sensors */
+	if (sc->sc_sme != NULL) {
+		sysmon_envsys_unregister(sc->sc_sme);
+		sc->sc_sme = NULL;
+	}
+	mutex_exit(&sc->sc_mutex);
+
+	/* Remove the sysctl tree */
+	sysctl_teardown(&sc->sc_sht4xlog);
+
+	/* Remove the mutex */
+	mutex_destroy(&sc->sc_mutex);
+
+	return 0;
+}
+
+MODULE(MODULE_CLASS_DRIVER, sht4xtemp, "i2cexec,sysmon_envsys");
+
+#ifdef _MODULE
+#include "ioconf.c"
+#endif
+
+static int
+sht4xtemp_modcmd(modcmd_t cmd, void *opaque)
+{
+
+	switch (cmd) {
+	case MODULE_CMD_INIT:
+#ifdef _MODULE
+		return config_init_component(cfdriver_ioconf_sht4xtemp,
+		    cfattach_ioconf_sht4xtemp, cfdata_ioconf_sht4xtemp);
+#else
+		return 0;
+#endif
+	case MODULE_CMD_FINI:
+#ifdef _MODULE
+		return config_fini_component(cfdriver_ioconf_sht4xtemp,
+		      cfattach_ioconf_sht4xtemp, cfdata_ioconf_sht4xtemp);
+#else
+		return 0;
+#endif
+	default:
+		return ENOTTY;
+	}
+}
Index: src/sys/dev/i2c/sht4xreg.h
diff -u /dev/null src/sys/dev/i2c/sht4xreg.h:1.1
--- /dev/null	Sun Oct  3 17:27:03 2021
+++ src/sys/dev/i2c/sht4xreg.h	Sun Oct  3 17:27:02 2021
@@ -0,0 +1,44 @@
+/*	$NetBSD: sht4xreg.h,v 1.1 2021/10/03 17:27:02 brad Exp $	*/
+
+/*
+ * Copyright (c) 2021 Brad Spencer <b...@anduin.eldar.org>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef _DEV_I2C_SHT4XREG_H_
+#define _DEV_I2C_SHT4XREG_H_
+
+#define SHT4X_TYPICAL_ADDR	0x44
+
+#define SHT4X_READ_SERIAL 0x89
+#define SHT4X_SOFT_RESET 0x94
+
+/* If you do not use the heater, you can take measurements at a couple
+   of different percisions */
+#define SHT4X_MEASURE_HIGH_PRECISION 0xFD
+#define SHT4X_MEASURE_MEDIUM_PRECISION 0xF6
+#define SHT4X_MEASURE_LOW_PRECISION 0xE0
+
+/* The SHT4X chip only support the heater when reading with the
+   highest percision and then only when the measurement is happening.
+   You can have the heater on for 1 second or 1 tenth of a second.
+   After the measurement the heater will switch itself off */
+#define SHT4X_MEASURE_HIGH_PRECISION_HIGH_HEAT_1_S 0x39
+#define SHT4X_MEASURE_HIGH_PRECISION_HIGH_HEAT_TENTH_S 0x32
+#define SHT4X_MEASURE_HIGH_PRECISION_MEDIUM_HEAT_1_S 0x2F
+#define SHT4X_MEASURE_HIGH_PRECISION_MEDIUM_HEAT_TENTH_S 0x24
+#define SHT4X_MEASURE_HIGH_PRECISION_LOW_HEAT_1_S 0x1E
+#define SHT4X_MEASURE_HIGH_PRECISION_LOW_HEAT_TENTH_S 0x15
+
+#endif
Index: src/sys/dev/i2c/sht4xvar.h
diff -u /dev/null src/sys/dev/i2c/sht4xvar.h:1.1
--- /dev/null	Sun Oct  3 17:27:03 2021
+++ src/sys/dev/i2c/sht4xvar.h	Sun Oct  3 17:27:02 2021
@@ -0,0 +1,72 @@
+/*	$NetBSD: sht4xvar.h,v 1.1 2021/10/03 17:27:02 brad Exp $	*/
+
+/*
+ * Copyright (c) 2021 Brad Spencer <b...@anduin.eldar.org>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef _DEV_I2C_SHT4XVAR_H_
+#define _DEV_I2C_SHT4XVAR_H_
+
+#define SHT4X_NUM_SENSORS	2
+#define SHT4X_HUMIDITY_SENSOR 0
+#define SHT4X_TEMP_SENSOR 1
+
+#define SHT4X_RES_NAME 7
+#define SHT4X_PULSE_NAME 6
+
+struct sht4x_sc {
+	int 		sc_sht4xdebug;
+	device_t 	sc_dev;
+	i2c_tag_t 	sc_tag;
+	i2c_addr_t 	sc_addr;
+	kmutex_t 	sc_mutex;
+	int 		sc_numsensors;
+	struct sysmon_envsys *sc_sme;
+	struct sysctllog *sc_sht4xlog;
+	envsys_data_t 	sc_sensors[SHT4X_NUM_SENSORS];
+	bool 		sc_ignorecrc;
+	char 		sc_resolution[SHT4X_RES_NAME];
+	int 		sc_readattempts;
+	bool 		sc_heateron;
+	int 		sc_heaterval;
+	char            sc_heaterpulse[SHT4X_PULSE_NAME];
+};
+
+struct sht4x_sensor {
+	const char     *desc;
+	enum envsys_units type;
+};
+
+struct sht4x_timing {
+	uint8_t cmd;
+	int     typicaldelay;
+};
+
+struct sht4x_resolution {
+	const char     *text;
+	uint8_t        cmd;
+};
+
+struct sht4x_heaterpulse {
+	const char     *length;
+};
+
+struct sht4x_heateron_command {
+	int            heatervalue;
+	const char     *pulselength;
+	uint8_t        cmd;
+};
+
+#endif

Index: src/sys/modules/sht4xtemp/Makefile
diff -u /dev/null src/sys/modules/sht4xtemp/Makefile:1.1
--- /dev/null	Sun Oct  3 17:27:03 2021
+++ src/sys/modules/sht4xtemp/Makefile	Sun Oct  3 17:27:02 2021
@@ -0,0 +1,11 @@
+.include "../Makefile.inc"
+
+.PATH:	${S}/dev/i2c
+
+KMOD=	sht4xtemp
+IOCONF=	sht4xtemp.ioconf
+SRCS=	sht4x.c
+
+WARNS=	3
+
+.include <bsd.kmodule.mk>
Index: src/sys/modules/sht4xtemp/sht4xtemp.ioconf
diff -u /dev/null src/sys/modules/sht4xtemp/sht4xtemp.ioconf:1.1
--- /dev/null	Sun Oct  3 17:27:03 2021
+++ src/sys/modules/sht4xtemp/sht4xtemp.ioconf	Sun Oct  3 17:27:02 2021
@@ -0,0 +1,7 @@
+ioconf sht4xtemp
+
+include "conf/files"
+
+pseudo-root iic*
+
+sht4xtemp* at iic? addr 0x44

Reply via email to