Module Name:    src
Committed By:   brad
Date:           Sat Dec  3 01:04:43 UTC 2022

Modified Files:
        src/distrib/sets/lists/debug: module.mi
        src/distrib/sets/lists/modules: mi
        src/share/man/man4: bmx280thp.4 spi.4
        src/sys/conf: files
        src/sys/dev/i2c: files.i2c
        src/sys/dev/spi: files.spi
        src/sys/modules: Makefile
        src/sys/modules/bmx280thp: Makefile bmx280thp.ioconf
Added Files:
        src/sys/dev/i2c: bmx280thpi2c.c
        src/sys/dev/ic: bmx280.c bmx280reg.h bmx280var.h
        src/sys/dev/spi: bmx280thpspi.c
        src/sys/modules/bmx280thpi2c: Makefile bmx280thpi2c.ioconf
Removed Files:
        src/sys/dev/i2c: bmx280.c bmx280reg.h bmx280var.h

Log Message:
Split the BMP280 / BME280 driver into common code and create I2C and
SPI attachments.


To generate a diff of this commit:
cvs rdiff -u -r1.22 -r1.23 src/distrib/sets/lists/debug/module.mi
cvs rdiff -u -r1.156 -r1.157 src/distrib/sets/lists/modules/mi
cvs rdiff -u -r1.4 -r1.5 src/share/man/man4/bmx280thp.4
cvs rdiff -u -r1.12 -r1.13 src/share/man/man4/spi.4
cvs rdiff -u -r1.1303 -r1.1304 src/sys/conf/files
cvs rdiff -u -r1.6 -r0 src/sys/dev/i2c/bmx280.c
cvs rdiff -u -r1.1 -r0 src/sys/dev/i2c/bmx280reg.h
cvs rdiff -u -r0 -r1.1 src/sys/dev/i2c/bmx280thpi2c.c
cvs rdiff -u -r1.2 -r0 src/sys/dev/i2c/bmx280var.h
cvs rdiff -u -r1.125 -r1.126 src/sys/dev/i2c/files.i2c
cvs rdiff -u -r0 -r1.1 src/sys/dev/ic/bmx280.c src/sys/dev/ic/bmx280reg.h \
    src/sys/dev/ic/bmx280var.h
cvs rdiff -u -r0 -r1.1 src/sys/dev/spi/bmx280thpspi.c
cvs rdiff -u -r1.9 -r1.10 src/sys/dev/spi/files.spi
cvs rdiff -u -r1.273 -r1.274 src/sys/modules/Makefile
cvs rdiff -u -r1.1 -r1.2 src/sys/modules/bmx280thp/Makefile \
    src/sys/modules/bmx280thp/bmx280thp.ioconf
cvs rdiff -u -r0 -r1.1 src/sys/modules/bmx280thpi2c/Makefile \
    src/sys/modules/bmx280thpi2c/bmx280thpi2c.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/debug/module.mi
diff -u src/distrib/sets/lists/debug/module.mi:1.22 src/distrib/sets/lists/debug/module.mi:1.23
--- src/distrib/sets/lists/debug/module.mi:1.22	Mon Nov 21 21:24:01 2022
+++ src/distrib/sets/lists/debug/module.mi	Sat Dec  3 01:04:43 2022
@@ -1,4 +1,4 @@
-# $NetBSD: module.mi,v 1.22 2022/11/21 21:24:01 brad Exp $
+# $NetBSD: module.mi,v 1.23 2022/12/03 01:04:43 brad Exp $
 ./usr/libdata/debug/@MODULEDIR@					modules-base-kernel	kmod,debug
 ./usr/libdata/debug/@MODULEDIR@/accf_dataready			modules-base-kernel	kmod,debug
 ./usr/libdata/debug/@MODULEDIR@/accf_dataready/accf_dataready.kmod.debug	modules-base-kernel	kmod,debug
@@ -24,6 +24,8 @@
 ./usr/libdata/debug/@MODULEDIR@/blowfish/blowfish.kmod.debug		modules-base-kernel	kmod,debug
 ./usr/libdata/debug/@MODULEDIR@/bmx280thp				modules-base-kernel	kmod,debug
 ./usr/libdata/debug/@MODULEDIR@/bmx280thp/bmx280thp.kmod.debug		modules-base-kernel	kmod,debug
+./usr/libdata/debug/@MODULEDIR@/bmx280thpi2c				modules-base-kernel	kmod,debug
+./usr/libdata/debug/@MODULEDIR@/bmx280thpi2c/bmx280thpi2c.kmod.debug	modules-base-kernel	kmod,debug
 ./usr/libdata/debug/@MODULEDIR@/bpf				modules-base-kernel	kmod,debug
 ./usr/libdata/debug/@MODULEDIR@/bpf/bpf.kmod.debug			modules-base-kernel	kmod,debug
 ./usr/libdata/debug/@MODULEDIR@/bpf_filter			modules-base-kernel	kmod,debug

Index: src/distrib/sets/lists/modules/mi
diff -u src/distrib/sets/lists/modules/mi:1.156 src/distrib/sets/lists/modules/mi:1.157
--- src/distrib/sets/lists/modules/mi:1.156	Mon Nov 21 21:24:01 2022
+++ src/distrib/sets/lists/modules/mi	Sat Dec  3 01:04:43 2022
@@ -1,4 +1,4 @@
-# $NetBSD: mi,v 1.156 2022/11/21 21:24:01 brad Exp $
+# $NetBSD: mi,v 1.157 2022/12/03 01:04:43 brad Exp $
 #
 # Note: don't delete entries from here - mark them as "obsolete" instead.
 #
@@ -33,6 +33,8 @@
 ./@MODULEDIR@/blowfish/blowfish.kmod		modules-base-kernel	kmod
 ./@MODULEDIR@/bmx280thp				modules-base-kernel	kmod
 ./@MODULEDIR@/bmx280thp/bmx280thp.kmod		modules-base-kernel	kmod
+./@MODULEDIR@/bmx280thpi2c			modules-base-kernel	kmod
+./@MODULEDIR@/bmx280thpi2c/bmx280thpi2c.kmod	modules-base-kernel	kmod
 ./@MODULEDIR@/bpf				modules-base-kernel	kmod
 ./@MODULEDIR@/bpf/bpf.kmod			modules-base-kernel	kmod
 ./@MODULEDIR@/bpf_filter			modules-base-kernel	kmod

Index: src/share/man/man4/bmx280thp.4
diff -u src/share/man/man4/bmx280thp.4:1.4 src/share/man/man4/bmx280thp.4:1.5
--- src/share/man/man4/bmx280thp.4:1.4	Wed Nov 23 23:49:23 2022
+++ src/share/man/man4/bmx280thp.4	Sat Dec  3 01:04:42 2022
@@ -1,4 +1,4 @@
-.\" $NetBSD: bmx280thp.4,v 1.4 2022/11/23 23:49:23 wiz Exp $
+.\" $NetBSD: bmx280thp.4,v 1.5 2022/12/03 01:04:42 brad Exp $
 .\"
 .\" Copyright (c) 2022 Brad Spencer <b...@anduin.eldar.org>
 .\"
@@ -23,6 +23,9 @@
 .Sh SYNOPSIS
 .Cd "bmx280thp* at iic? addr 0x76"
 .Cd "bmx280thp* at iic? addr 0x77"
+
+.Cd "bmx280thp* at spi? slave 0"
+.Cd "bmx280thp* at spi? slave 1"
 .Sh DESCRIPTION
 The
 .Nm
@@ -35,8 +38,14 @@ The
 .Ar addr
 argument selects the address at the
 .Xr iic 4
+bus and the
+.Nm
+.Ar slave
+argument selects which chip select will be used on the
+.Xr spi 4
 bus.
-The precision of the measurement can be changed through
+The precision of the measurement which is related to the over
+sampling performed on the measurement can be changed through
 .Xr sysctl 8
 nodes.
 .Sh SYSCTL VARIABLES
@@ -82,6 +91,7 @@ The default is 25 which should be more t
 .Sh SEE ALSO
 .Xr envsys 4 ,
 .Xr iic 4 ,
+.Xr spi 4 ,
 .Xr envstat 8 ,
 .Xr sysctl 8
 .Sh HISTORY
@@ -98,4 +108,3 @@ driver was written by
 .Sh BUGS
 The driver does not support the continuous read mode that the BMP280
 and BME280 has.
-This driver does not support the SPI interface.

Index: src/share/man/man4/spi.4
diff -u src/share/man/man4/spi.4:1.12 src/share/man/man4/spi.4:1.13
--- src/share/man/man4/spi.4:1.12	Tue Dec  7 17:50:27 2021
+++ src/share/man/man4/spi.4	Sat Dec  3 01:04:42 2022
@@ -1,4 +1,4 @@
-.\"	$NetBSD: spi.4,v 1.12 2021/12/07 17:50:27 brad Exp $
+.\"	$NetBSD: spi.4,v 1.13 2022/12/03 01:04:42 brad Exp $
 .\"
 .\" Copyright (c) 2006 Urbana-Champaign Independent Media Center.
 .\" Copyright (c) 2006 Garrett D'Amore.
@@ -131,6 +131,8 @@ includes the following machine-independe
 .Tn SPI
 drivers:
 .Bl -tag -width mcp23s17gpio(4) -offset indent
+.It Xr bmx280thp 4
+Bosch BMP280 / BME280 sensor.
 .It Xr m25p 4
 STMicroelectronics M25P family of NOR flash devices.
 .It Xr mcp23s17gpio 4

Index: src/sys/conf/files
diff -u src/sys/conf/files:1.1303 src/sys/conf/files:1.1304
--- src/sys/conf/files:1.1303	Sat Nov  5 17:31:38 2022
+++ src/sys/conf/files	Sat Dec  3 01:04:42 2022
@@ -1,4 +1,4 @@
-#	$NetBSD: files,v 1.1303 2022/11/05 17:31:38 jmcneill Exp $
+#	$NetBSD: files,v 1.1304 2022/12/03 01:04:42 brad Exp $
 #	@(#)files.newconf	7.5 (Berkeley) 5/10/93
 
 version 	20171118
@@ -437,6 +437,10 @@ file	dev/ic/ssdfb.c	ssdfb
 device  scmd
 file	dev/ic/scmd.c	scmd
 
+# Bosch BMP280 / BME280 sensor (attaches via I2C or SPI)
+device  bmx280thp
+file	dev/ic/bmx280.c	bmx280thp
+
 # Generic HID support (used by USB, bluetooth and i2c)
 include "dev/hid/files.hid"
 

Index: src/sys/dev/i2c/files.i2c
diff -u src/sys/dev/i2c/files.i2c:1.125 src/sys/dev/i2c/files.i2c:1.126
--- src/sys/dev/i2c/files.i2c:1.125	Mon Nov 21 21:24:01 2022
+++ src/sys/dev/i2c/files.i2c	Sat Dec  3 01:04:43 2022
@@ -1,4 +1,4 @@
-#	$NetBSD: files.i2c,v 1.125 2022/11/21 21:24:01 brad Exp $
+#	$NetBSD: files.i2c,v 1.126 2022/12/03 01:04:43 brad Exp $
 
 obsolete defflag	opt_i2cbus.h		I2C_SCAN
 define	i2cbus { }
@@ -437,6 +437,5 @@ attach aht20temp at iic
 file dev/i2c/aht20.c				aht20temp
 
 # Bosch Sensortec BMP280/BME280 Temperature, Humidity and Pressure sensor
-device bmx280thp
-attach bmx280thp at iic
-file dev/i2c/bmx280.c				bmx280thp
+attach	bmx280thp at iic with bmx280thpi2c
+file dev/i2c/bmx280thpi2c.c			bmx280thpi2c

Index: src/sys/dev/spi/files.spi
diff -u src/sys/dev/spi/files.spi:1.9 src/sys/dev/spi/files.spi:1.10
--- src/sys/dev/spi/files.spi:1.9	Mon Jan 17 16:31:23 2022
+++ src/sys/dev/spi/files.spi	Sat Dec  3 01:04:43 2022
@@ -1,4 +1,4 @@
-#	$NetBSD: files.spi,v 1.9 2022/01/17 16:31:23 thorpej Exp $
+#	$NetBSD: files.spi,v 1.10 2022/12/03 01:04:43 brad Exp $
 
 define	spibus { }
 
@@ -47,3 +47,7 @@ file	dev/spi/mcp3k.c			mcp3kadc
 # Sparkfun Serial motor controller
 attach  scmd at spi with scmdspi
 file	dev/spi/scmdspi.c		scmdspi
+
+# Bosch BMP280 / BME280 sensor
+attach  bmx280thp at spi with bmx280thpspi
+file	dev/spi/bmx280thpspi.c		bmx280thpspi

Index: src/sys/modules/Makefile
diff -u src/sys/modules/Makefile:1.273 src/sys/modules/Makefile:1.274
--- src/sys/modules/Makefile:1.273	Mon Nov 21 21:24:01 2022
+++ src/sys/modules/Makefile	Sat Dec  3 01:04:42 2022
@@ -1,4 +1,4 @@
-#	$NetBSD: Makefile,v 1.273 2022/11/21 21:24:01 brad Exp $
+#	$NetBSD: Makefile,v 1.274 2022/12/03 01:04:42 brad Exp $
 
 .include <bsd.own.mk>
 
@@ -34,6 +34,7 @@ SUBDIR+=	blowfish
 SUBDIR+=	bpf
 SUBDIR+=	bpf_filter
 SUBDIR+=	bmx280thp
+SUBDIR+=	bmx280thpi2c
 SUBDIR+=	bufq_disksort
 SUBDIR+=	bufq_fcfs
 SUBDIR+=	bufq_priocscan

Index: src/sys/modules/bmx280thp/Makefile
diff -u src/sys/modules/bmx280thp/Makefile:1.1 src/sys/modules/bmx280thp/Makefile:1.2
--- src/sys/modules/bmx280thp/Makefile:1.1	Mon Nov 21 21:24:01 2022
+++ src/sys/modules/bmx280thp/Makefile	Sat Dec  3 01:04:42 2022
@@ -1,6 +1,6 @@
 .include "../Makefile.inc"
 
-.PATH:	${S}/dev/i2c
+.PATH:	${S}/dev/ic
 
 KMOD=	bmx280thp
 IOCONF=	bmx280thp.ioconf
Index: src/sys/modules/bmx280thp/bmx280thp.ioconf
diff -u src/sys/modules/bmx280thp/bmx280thp.ioconf:1.1 src/sys/modules/bmx280thp/bmx280thp.ioconf:1.2
--- src/sys/modules/bmx280thp/bmx280thp.ioconf:1.1	Mon Nov 21 21:24:01 2022
+++ src/sys/modules/bmx280thp/bmx280thp.ioconf	Sat Dec  3 01:04:42 2022
@@ -1,8 +1,3 @@
 ioconf bmx280thp
 
 include "conf/files"
-
-pseudo-root iic*
-
-bmx280thp* at iic? addr 0x76
-bmx280thp* at iic? addr 0x77

Added files:

Index: src/sys/dev/i2c/bmx280thpi2c.c
diff -u /dev/null src/sys/dev/i2c/bmx280thpi2c.c:1.1
--- /dev/null	Sat Dec  3 01:04:43 2022
+++ src/sys/dev/i2c/bmx280thpi2c.c	Sat Dec  3 01:04:43 2022
@@ -0,0 +1,264 @@
+/*	$NetBSD: bmx280thpi2c.c,v 1.1 2022/12/03 01:04:43 brad Exp $	*/
+
+/*
+ * Copyright (c) 2022 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: bmx280thpi2c.c,v 1.1 2022/12/03 01:04:43 brad Exp $");
+
+/*
+ * I2C driver for the Bosch BMP280 / BME280 sensor.
+ * Uses the common bmx280thp driver to do the real work.
+*/
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/kernel.h>
+#include <sys/device.h>
+#include <sys/module.h>
+#include <sys/conf.h>
+#include <sys/sysctl.h>
+#include <sys/mutex.h>
+#include <sys/condvar.h>
+#include <sys/pool.h>
+#include <sys/kmem.h>
+
+#include <dev/sysmon/sysmonvar.h>
+#include <dev/i2c/i2cvar.h>
+#include <dev/spi/spivar.h>
+#include <dev/ic/bmx280reg.h>
+#include <dev/ic/bmx280var.h>
+
+extern void	bmx280_attach(struct bmx280_sc *);
+
+static int 	bmx280thpi2c_poke(i2c_tag_t, i2c_addr_t, bool);
+static int 	bmx280thpi2c_match(device_t, cfdata_t, void *);
+static void 	bmx280thpi2c_attach(device_t, device_t, void *);
+static int 	bmx280thpi2c_detach(device_t, int);
+
+#define BMX280_DEBUG
+#ifdef BMX280_DEBUG
+#define DPRINTF(s, l, x) \
+    do { \
+	if (l <= s->sc_bmx280debug) \
+	    printf x; \
+    } while (/*CONSTCOND*/0)
+#else
+#define DPRINTF(s, l, x)
+#endif
+
+CFATTACH_DECL_NEW(bmx280thpi2c, sizeof(struct bmx280_sc),
+    bmx280thpi2c_match, bmx280thpi2c_attach, bmx280thpi2c_detach, NULL);
+
+/* For the BMX280, a read consists of writing on the I2C bus
+ * a I2C START, I2C SLAVE address, then the starting register.
+ * If that works, then following will be another I2C START,
+ * I2C SLAVE address, followed by as many I2C reads that is
+ * desired and then a I2C STOP
+ */
+
+static int
+bmx280thpi2c_read_register_direct(i2c_tag_t tag, i2c_addr_t addr, uint8_t reg,
+    uint8_t *buf, size_t blen)
+{
+	int error;
+
+	error = iic_exec(tag,I2C_OP_WRITE,addr,&reg,1,NULL,0,0);
+
+	if (error == 0) {
+		error = iic_exec(tag,I2C_OP_READ_WITH_STOP,addr,NULL,0,
+		    buf,blen,0);
+	}
+
+	return error;
+}
+
+static int
+bmx280thpi2c_read_register(struct bmx280_sc *sc, uint8_t reg,
+    uint8_t *buf, size_t blen)
+{
+	int error;
+
+	KASSERT(blen > 0);
+
+	error = bmx280thpi2c_read_register_direct(sc->sc_tag, sc->sc_addr, reg,
+	    buf, blen);
+
+	return error;
+}
+
+/* For the BMX280, a write consists of sending a I2C START, I2C SLAVE
+ * address and then pairs of registers and data until a I2C STOP is
+ * sent.
+ */
+
+static int
+bmx280thpi2c_write_register(struct bmx280_sc *sc,
+    uint8_t *buf, size_t blen)
+{
+	int error;
+
+	KASSERT(blen > 0);
+	/* XXX - there should be a KASSERT for blen at least
+	   being an even number */
+
+	error = iic_exec(sc->sc_tag,I2C_OP_WRITE_WITH_STOP,sc->sc_addr,NULL,0,
+	    buf,blen,0);
+
+	return error;
+}
+
+static int
+bmx280thpi2c_acquire_bus(struct bmx280_sc *sc)
+{
+	return(iic_acquire_bus(sc->sc_tag, 0));
+}
+
+static void
+bmx280thpi2c_release_bus(struct bmx280_sc *sc)
+{
+	iic_release_bus(sc->sc_tag, 0);
+}
+
+static int
+bmx280thpi2c_poke(i2c_tag_t tag, i2c_addr_t addr, bool matchdebug)
+{
+	uint8_t reg = BMX280_REGISTER_ID;
+	uint8_t buf[1];
+	int error;
+
+	error = bmx280thpi2c_read_register_direct(tag, addr, reg, buf, 1);
+	if (matchdebug) {
+		printf("poke X 1: %d\n", error);
+	}
+	return error;
+}
+
+static int
+bmx280thpi2c_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 != BMX280_TYPICAL_ADDR_1 &&
+	    ia->ia_addr != BMX280_TYPICAL_ADDR_2)
+		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 = bmx280thpi2c_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
+bmx280thpi2c_attach(device_t parent, device_t self, void *aux)
+{
+	struct bmx280_sc *sc;
+	struct i2c_attach_args *ia;
+
+	ia = aux;
+	sc = device_private(self);
+
+	sc->sc_dev = self;
+	sc->sc_tag = ia->ia_tag;
+	sc->sc_addr = ia->ia_addr;
+	sc->sc_bmx280debug = 0;
+	sc->sc_func_acquire_bus = &bmx280thpi2c_acquire_bus;
+	sc->sc_func_release_bus = &bmx280thpi2c_release_bus;
+	sc->sc_func_read_register = &bmx280thpi2c_read_register;
+	sc->sc_func_write_register = &bmx280thpi2c_write_register;
+
+	mutex_init(&sc->sc_mutex, MUTEX_DEFAULT, IPL_NONE);
+
+	bmx280_attach(sc);
+
+	return;
+}
+
+static int
+bmx280thpi2c_detach(device_t self, int flags)
+{
+	struct bmx280_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_bmx280log);
+
+	/* Remove the mutex */
+	mutex_destroy(&sc->sc_mutex);
+
+	return 0;
+}
+
+MODULE(MODULE_CLASS_DRIVER, bmx280thpi2c, "iic,bmx280thp");
+
+#ifdef _MODULE
+/* Like other drivers, we do this because the bmx280 common
+ * driver has the definitions already.
+ */
+#undef  CFDRIVER_DECL
+#define CFDRIVER_DECL(name, class, attr)
+#include "ioconf.c"
+#endif
+
+static int
+bmx280thpi2c_modcmd(modcmd_t cmd, void *opaque)
+{
+
+	switch (cmd) {
+	case MODULE_CMD_INIT:
+#ifdef _MODULE
+		return config_init_component(cfdriver_ioconf_bmx280thpi2c,
+		    cfattach_ioconf_bmx280thpi2c, cfdata_ioconf_bmx280thpi2c);
+#else
+		return 0;
+#endif
+	case MODULE_CMD_FINI:
+#ifdef _MODULE
+		return config_fini_component(cfdriver_ioconf_bmx280thpi2c,
+		      cfattach_ioconf_bmx280thpi2c, cfdata_ioconf_bmx280thpi2c);
+#else
+		return 0;
+#endif
+	default:
+		return ENOTTY;
+	}
+}

Index: src/sys/dev/ic/bmx280.c
diff -u /dev/null src/sys/dev/ic/bmx280.c:1.1
--- /dev/null	Sat Dec  3 01:04:43 2022
+++ src/sys/dev/ic/bmx280.c	Sat Dec  3 01:04:43 2022
@@ -0,0 +1,1013 @@
+/*	$NetBSD: bmx280.c,v 1.1 2022/12/03 01:04:43 brad Exp $	*/
+
+/*
+ * Copyright (c) 2022 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: bmx280.c,v 1.1 2022/12/03 01:04:43 brad Exp $");
+
+/*
+ * Common driver for the Bosch BMP280/BME280 temperature, humidity (sometimes) and
+ * (usually barometric) pressure sensor.  Calls out to specific frontends to
+ * the move bits around.
+*/
+
+#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 <sys/proc.h>
+
+#include <dev/sysmon/sysmonvar.h>
+#include <dev/spi/spivar.h>
+#include <dev/i2c/i2cvar.h>
+#include <dev/ic/bmx280reg.h>
+#include <dev/ic/bmx280var.h>
+
+
+static void	bmx280_store_raw_blob_tp(struct bmx280_sc *, uint8_t *);
+static void	bmx280_store_raw_blob_h(struct bmx280_sc *, uint8_t *);
+void 		bmx280_attach(struct bmx280_sc *);
+static void 	bmx280_refresh(struct sysmon_envsys *, envsys_data_t *);
+static int 	bmx280_verify_sysctl(SYSCTLFN_ARGS);
+static int 	bmx280_verify_sysctl_osrs(SYSCTLFN_ARGS);
+static int 	bmx280_verify_sysctl_irr(SYSCTLFN_ARGS);
+
+#define BMX280_DEBUG
+#ifdef BMX280_DEBUG
+#define DPRINTF(s, l, x) \
+    do { \
+	if (l <= s->sc_bmx280debug) \
+	    printf x; \
+    } while (/*CONSTCOND*/0)
+#else
+#define DPRINTF(s, l, x)
+#endif
+
+static struct bmx280_sensor bmx280_sensors[] = {
+	{
+		.desc = "temperature",
+		.type = ENVSYS_STEMP,
+	},
+	{
+		.desc = "pressure",
+		.type = ENVSYS_PRESSURE,
+	},
+	{
+		.desc = "humidity",
+		.type = ENVSYS_SRELHUMIDITY,
+	}
+};
+
+static struct bmx280_osrs_list bmx280_osrs[] = {
+	{
+		.text = 1,
+		.mask = BMX280_OSRS_TP_VALUE_X1,
+	},
+	{
+		.text = 2,
+		.mask = BMX280_OSRS_TP_VALUE_X2,
+	},
+	{
+		.text = 4,
+		.mask = BMX280_OSRS_TP_VALUE_X4,
+	},
+	{
+		.text = 8,
+		.mask = BMX280_OSRS_TP_VALUE_X8,
+	},
+	{
+		.text = 16,
+		.mask = BMX280_OSRS_TP_VALUE_X16,
+	}
+};
+
+static struct bmx280_irr_list bmx280_irr[] = {
+	{
+		.text = 1,
+		.mask = BMX280_FILTER_VALUE_OFF,
+	},
+	{
+		.text = 2,
+		.mask = BMX280_FILTER_VALUE_2,
+	},
+	{
+		.text = 5,
+		.mask = BMX280_FILTER_VALUE_5,
+	},
+	{
+		.text = 11,
+		.mask = BMX280_FILTER_VALUE_11,
+	},
+	{
+		.text = 22,
+		.mask = BMX280_FILTER_VALUE_22,
+	}
+};
+
+static uint8_t
+bmx280_osrs_text_to_mask(int t)
+{
+	int i;
+	uint8_t m = 0;
+
+	for (i = 0; i < __arraycount(bmx280_osrs); i++) {
+		if (t == bmx280_osrs[i].text) {
+			m = bmx280_osrs[i].mask;
+			break;
+		}
+	}
+
+	return m;
+}
+
+static uint8_t
+bmx280_irr_text_to_mask(int t)
+{
+	int i;
+	uint8_t m = 0;
+
+	for (i = 0; i < __arraycount(bmx280_irr); i++) {
+		if (t == bmx280_irr[i].text) {
+			m = bmx280_irr[i].mask;
+			break;
+		}
+	}
+
+	return m;
+}
+
+int
+bmx280_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;
+}
+
+int
+bmx280_verify_sysctl_osrs(SYSCTLFN_ARGS)
+{
+	struct sysctlnode node;
+	int error = 0, t;
+	size_t i;
+
+	node = *rnode;
+	t = *(int *)rnode->sysctl_data;
+	node.sysctl_data = &t;
+	error = sysctl_lookup(SYSCTLFN_CALL(&node));
+	if (error || newp == NULL)
+		return error;
+
+	for (i = 0; i < __arraycount(bmx280_osrs); i++) {
+		if (t == bmx280_osrs[i].text) {
+			break;
+		}
+	}
+
+	if (i == __arraycount(bmx280_osrs))
+		return EINVAL;
+
+	*(int *)rnode->sysctl_data = t;
+
+	return error;
+}
+
+int
+bmx280_verify_sysctl_irr(SYSCTLFN_ARGS)
+{
+	struct sysctlnode node;
+	int error = 0, t;
+	size_t i;
+
+	node = *rnode;
+	t = *(int *)rnode->sysctl_data;
+	node.sysctl_data = &t;
+	error = sysctl_lookup(SYSCTLFN_CALL(&node));
+	if (error || newp == NULL)
+		return error;
+
+	for (i = 0; i < __arraycount(bmx280_irr); i++) {
+		if (t == bmx280_irr[i].text) {
+			break;
+		}
+	}
+
+	if (i == __arraycount(bmx280_irr))
+		return EINVAL;
+
+	*(int *)rnode->sysctl_data = t;
+
+	return error;
+}
+
+/* The datasheet was pretty vague as to the byte order...
+ * in fact, down right deceptive...
+ */
+
+static void
+bmx280_store_raw_blob_tp(struct bmx280_sc *sc, uint8_t *b) {
+	sc->sc_cal_blob.dig_T1 = (uint16_t)b[1] << 8;
+	sc->sc_cal_blob.dig_T1 = sc->sc_cal_blob.dig_T1 | (uint16_t)b[0];
+	sc->sc_cal_blob.dig_T2 = (int16_t)b[3] << 8;
+	sc->sc_cal_blob.dig_T2 = sc->sc_cal_blob.dig_T2 | (int16_t)b[2];
+	sc->sc_cal_blob.dig_T3 = (int16_t)b[5] << 8;
+	sc->sc_cal_blob.dig_T3 = sc->sc_cal_blob.dig_T3 | (int16_t)b[4];
+
+	sc->sc_cal_blob.dig_P1 = (uint16_t)b[7] << 8;
+	sc->sc_cal_blob.dig_P1 = sc->sc_cal_blob.dig_P1 | (uint16_t)b[6];
+	sc->sc_cal_blob.dig_P2 = (int16_t)b[9] << 8;
+	sc->sc_cal_blob.dig_P2 = sc->sc_cal_blob.dig_P2 | (int16_t)b[8];
+	sc->sc_cal_blob.dig_P3 = (int16_t)b[11] << 8;
+	sc->sc_cal_blob.dig_P3 = sc->sc_cal_blob.dig_P3 | (int16_t)b[10];
+	sc->sc_cal_blob.dig_P4 = (int16_t)b[13] << 8;
+	sc->sc_cal_blob.dig_P4 = sc->sc_cal_blob.dig_P4 | (int16_t)b[12];
+	sc->sc_cal_blob.dig_P5 = (int16_t)b[15] << 8;
+	sc->sc_cal_blob.dig_P5 = sc->sc_cal_blob.dig_P5 | (int16_t)b[14];
+	sc->sc_cal_blob.dig_P6 = (int16_t)b[17] << 8;
+	sc->sc_cal_blob.dig_P6 = sc->sc_cal_blob.dig_P6 | (int16_t)b[16];
+	sc->sc_cal_blob.dig_P7 = (int16_t)b[19] << 8;
+	sc->sc_cal_blob.dig_P7 = sc->sc_cal_blob.dig_P7 | (int16_t)b[18];
+	sc->sc_cal_blob.dig_P8 = (int16_t)b[21] << 8;
+	sc->sc_cal_blob.dig_P8 = sc->sc_cal_blob.dig_P8 | (int16_t)b[20];
+	sc->sc_cal_blob.dig_P9 = (int16_t)b[23] << 8;
+	sc->sc_cal_blob.dig_P9 = sc->sc_cal_blob.dig_P9 | (int16_t)b[22];
+}
+
+static void
+bmx280_store_raw_blob_h(struct bmx280_sc *sc, uint8_t *b) {
+	sc->sc_cal_blob.dig_H1 = (uint8_t)b[0];
+	sc->sc_cal_blob.dig_H2 = (int16_t)b[2] << 8;
+	sc->sc_cal_blob.dig_H2 = sc->sc_cal_blob.dig_H2 | (int16_t)b[1];
+	sc->sc_cal_blob.dig_H3 = (uint8_t)b[3];
+	sc->sc_cal_blob.dig_H4 = ((int16_t)((b[4] << 4) | (b[5] & 0x0F)));
+	sc->sc_cal_blob.dig_H5 = (int16_t)b[6] << 4;
+	sc->sc_cal_blob.dig_H5 = sc->sc_cal_blob.dig_H5 | (((int16_t)b[5] & 0x00f0) >> 4);
+	sc->sc_cal_blob.dig_H6 = (int8_t)b[7];
+}
+
+static int
+bmx280_sysctl_init(struct bmx280_sc *sc)
+{
+	int error;
+	const struct sysctlnode *cnode;
+	int sysctlroot_num, sysctlwait_num;
+
+	sc->sc_func_attach = &bmx280_attach;
+
+	if ((error = sysctl_createv(&sc->sc_bmx280log, 0, NULL, &cnode,
+	    0, CTLTYPE_NODE, device_xname(sc->sc_dev),
+	    SYSCTL_DESCR("bmx280 controls"), NULL, 0, NULL, 0, CTL_HW,
+	    CTL_CREATE, CTL_EOL)) != 0)
+		return error;
+
+	sysctlroot_num = cnode->sysctl_num;
+
+#ifdef BMX280_DEBUG
+	if ((error = sysctl_createv(&sc->sc_bmx280log, 0, NULL, &cnode,
+	    CTLFLAG_READWRITE, CTLTYPE_INT, "debug",
+	    SYSCTL_DESCR("Debug level"), bmx280_verify_sysctl, 0,
+	    &sc->sc_bmx280debug, 0, CTL_HW, sysctlroot_num, CTL_CREATE,
+	    CTL_EOL)) != 0)
+		return error;
+
+	/* It would be nice to have a CTLTYPE_SHORT */
+
+	if ((error = sysctl_createv(&sc->sc_bmx280log, 0, NULL, &cnode,
+	    CTLFLAG_READWRITE, CTLTYPE_BOOL, "dump_calibration",
+	    SYSCTL_DESCR("Dumps the calibration values to the console"),
+	    bmx280_verify_sysctl, 0,
+	    &sc->sc_bmx280dump, 0, CTL_HW, sysctlroot_num, CTL_CREATE,
+	    CTL_EOL)) != 0)
+		return error;
+#endif
+	if ((error = sysctl_createv(&sc->sc_bmx280log, 0, NULL, &cnode,
+	    CTLFLAG_READWRITE, CTLTYPE_INT, "readattempts",
+	    SYSCTL_DESCR("Read attempts"), bmx280_verify_sysctl, 0,
+	    &sc->sc_readattempts, 0, CTL_HW, sysctlroot_num, CTL_CREATE,
+	    CTL_EOL)) != 0)
+		return error;
+
+	if ((error = sysctl_createv(&sc->sc_bmx280log, 0, NULL, &cnode,
+	    CTLFLAG_READWRITE, CTLTYPE_INT, "osrs_t",
+	    SYSCTL_DESCR("Temperature oversample"),
+	    bmx280_verify_sysctl_osrs, 0, &sc->sc_osrs_t,
+	    0, CTL_HW, sysctlroot_num, CTL_CREATE, CTL_EOL)) != 0)
+		return error;
+
+	if ((error = sysctl_createv(&sc->sc_bmx280log, 0, NULL, &cnode,
+	    CTLFLAG_READWRITE, CTLTYPE_INT, "osrs_p",
+	    SYSCTL_DESCR("Pressure oversample"),
+	    bmx280_verify_sysctl_osrs, 0, &sc->sc_osrs_p,
+	    0, CTL_HW, sysctlroot_num, CTL_CREATE, CTL_EOL)) != 0)
+		return error;
+
+	if (sc->sc_has_humidity) {
+		if ((error = sysctl_createv(&sc->sc_bmx280log, 0, NULL, &cnode,
+		    CTLFLAG_READWRITE, CTLTYPE_INT, "osrs_h",
+		    SYSCTL_DESCR("Humidity oversample"),
+		    bmx280_verify_sysctl_osrs, 0, &sc->sc_osrs_h,
+		    0, CTL_HW, sysctlroot_num, CTL_CREATE, CTL_EOL)) != 0)
+			return error;
+	}
+
+	if ((error = sysctl_createv(&sc->sc_bmx280log, 0, NULL, &cnode,
+	    CTLFLAG_READWRITE, CTLTYPE_INT, "irr_samples",
+	    SYSCTL_DESCR("IRR samples"),
+	    bmx280_verify_sysctl_irr, 0, &sc->sc_irr_samples,
+	    0, CTL_HW, sysctlroot_num, CTL_CREATE, CTL_EOL)) != 0)
+		return error;
+
+	if ((error = sysctl_createv(&sc->sc_bmx280log, 0, NULL, &cnode,
+	    0, CTLTYPE_NODE, "waitfactor",
+	    SYSCTL_DESCR("bmx280 wait factors"), NULL, 0, NULL, 0, CTL_HW,
+	    sysctlroot_num, CTL_CREATE, CTL_EOL)) != 0)
+		return error;
+	sysctlwait_num = cnode->sysctl_num;
+
+	if ((error = sysctl_createv(&sc->sc_bmx280log, 0, NULL, &cnode,
+	    CTLFLAG_READWRITE, CTLTYPE_INT, "t",
+	    SYSCTL_DESCR("Temperature wait multiplier"),
+	    bmx280_verify_sysctl, 0, &sc->sc_waitfactor_t,
+	    0, CTL_HW, sysctlroot_num, sysctlwait_num, CTL_CREATE, CTL_EOL)) != 0)
+		return error;
+
+	if ((error = sysctl_createv(&sc->sc_bmx280log, 0, NULL, &cnode,
+	    CTLFLAG_READWRITE, CTLTYPE_INT, "p",
+	    SYSCTL_DESCR("Pressure wait multiplier"),
+	    bmx280_verify_sysctl, 0, &sc->sc_waitfactor_p,
+	    0, CTL_HW, sysctlroot_num, sysctlwait_num, CTL_CREATE, CTL_EOL)) != 0)
+		return error;
+
+	if (sc->sc_has_humidity) {
+		if ((error = sysctl_createv(&sc->sc_bmx280log, 0, NULL, &cnode,
+		    CTLFLAG_READWRITE, CTLTYPE_INT, "h",
+		    SYSCTL_DESCR("Humidity wait multiplier"),
+		    bmx280_verify_sysctl, 0, &sc->sc_waitfactor_h,
+		    0, CTL_HW, sysctlroot_num, sysctlwait_num, CTL_CREATE, CTL_EOL)) != 0)
+			return error;
+	}
+
+	return 0;
+}
+void
+bmx280_attach(struct bmx280_sc *sc)
+{
+	int error, i;
+	uint8_t reg, chip_id;
+	uint8_t buf[2];
+
+	sc->sc_bmx280dump = false;
+	sc->sc_has_humidity = false;
+	sc->sc_readattempts = 25;
+	sc->sc_osrs_t = 1;
+	sc->sc_osrs_p = 4;
+	sc->sc_osrs_h = 1;
+	sc->sc_irr_samples = 1;
+	sc->sc_previous_irr = 0xff;
+	sc->sc_waitfactor_t = 6;
+	sc->sc_waitfactor_p = 2;
+	sc->sc_waitfactor_h = 2;
+	sc->sc_sme = NULL;
+
+	aprint_normal("\n");
+
+	mutex_init(&sc->sc_mutex, MUTEX_DEFAULT, IPL_NONE);
+	sc->sc_numsensors = __arraycount(bmx280_sensors);
+
+	if ((sc->sc_sme = sysmon_envsys_create()) == NULL) {
+		aprint_error_dev(sc->sc_dev,
+		    "Unable to create sysmon structure\n");
+		sc->sc_sme = NULL;
+		return;
+	}
+
+	error = (*(sc->sc_func_acquire_bus))(sc);
+	if (error) {
+		aprint_error_dev(sc->sc_dev, "Could not acquire the bus: %d\n",
+		    error);
+		goto out;
+	}
+
+	buf[0] = BMX280_REGISTER_RESET;
+	buf[1] = BMX280_TRIGGER_RESET;
+	error = (*(sc->sc_func_write_register))(sc, buf, 2);
+	if (error) {
+		aprint_error_dev(sc->sc_dev, "Failed to reset chip: %d\n",
+		    error);
+	}
+
+	delay(30000);
+
+	reg = BMX280_REGISTER_ID;
+	error = (*(sc->sc_func_read_register))(sc, reg, &chip_id, 1);
+	if (error) {
+		aprint_error_dev(sc->sc_dev, "Failed to read ID: %d\n",
+		    error);
+	}
+
+	delay(1000);
+
+	DPRINTF(sc, 2, ("%s: read ID value: %02x\n",
+	    device_xname(sc->sc_dev), chip_id));
+
+	if (chip_id == BMX280_ID_BME280) {
+		sc->sc_has_humidity = true;
+	}
+
+	if ((error = bmx280_sysctl_init(sc)) != 0) {
+		aprint_error_dev(sc->sc_dev, "Can't setup sysctl tree (%d)\n", error);
+		goto out;
+	}
+
+	uint8_t raw_blob_tp[24];
+	reg = BMX280_REGISTER_DIG_T1;
+	error = (*(sc->sc_func_read_register))(sc, reg, raw_blob_tp, 24);
+	if (error) {
+		aprint_error_dev(sc->sc_dev, "Failed to read the calibration registers for tp: %d\n",
+		    error);
+	}
+
+	if (sc->sc_bmx280debug > 0) {
+		for(int _d = 0;_d < 24;_d++) {
+			DPRINTF(sc, 0, ("%s: %d %02x\n",
+			    device_xname(sc->sc_dev), _d, raw_blob_tp[_d]));
+		}
+	}
+
+	bmx280_store_raw_blob_tp(sc,raw_blob_tp);
+
+	if (sc->sc_has_humidity) {
+		uint8_t raw_blob_h[8];
+
+		reg = BMX280_REGISTER_DIG_H1;
+		error = (*(sc->sc_func_read_register))(sc, reg, raw_blob_h, 1);
+		if (error) {
+			aprint_error_dev(sc->sc_dev, "Failed to read the calibration registers for h1: %d\n",
+			    error);
+		}
+
+		reg = BMX280_REGISTER_DIG_H2;
+		error = (*(sc->sc_func_read_register))(sc, reg, &raw_blob_h[1], 7);
+		if (error) {
+			aprint_error_dev(sc->sc_dev, "Failed to read the calibration registers for h2 - h6: %d\n",
+			    error);
+		}
+
+		if (sc->sc_bmx280debug > 0) {
+			for(int _d = 0;_d < 8;_d++) {
+				DPRINTF(sc, 0, ("%s: %d %02x\n",
+				    device_xname(sc->sc_dev), _d, raw_blob_h[_d]));
+			}
+		}
+
+		bmx280_store_raw_blob_h(sc,raw_blob_h);
+	}
+
+	(*(sc->sc_func_release_bus))(sc);
+
+	if (error != 0) {
+		aprint_error_dev(sc->sc_dev, "Unable to setup device\n");
+		goto out;
+	}
+
+	for (i = 0; i < sc->sc_numsensors; i++) {
+		if (sc->sc_has_humidity == false &&
+		    bmx280_sensors[i].type == ENVSYS_SRELHUMIDITY) {
+			break;
+		}
+
+		strlcpy(sc->sc_sensors[i].desc, bmx280_sensors[i].desc,
+		    sizeof(sc->sc_sensors[i].desc));
+
+		sc->sc_sensors[i].units = bmx280_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(sc->sc_dev,
+			    "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 = bmx280_refresh;
+
+	DPRINTF(sc, 2, ("bmx280_attach: registering with envsys\n"));
+
+	if (sysmon_envsys_register(sc->sc_sme)) {
+		aprint_error_dev(sc->sc_dev,
+			"unable to register with sysmon\n");
+		sysmon_envsys_destroy(sc->sc_sme);
+		sc->sc_sme = NULL;
+		return;
+	}
+
+	aprint_normal_dev(sc->sc_dev, "Bosch Sensortec %s, Chip ID: 0x%02x\n",
+	    (chip_id == BMX280_ID_BMP280) ? "BMP280" : (chip_id == BMX280_ID_BME280) ? "BME280" : "Unknown chip",
+	    chip_id);
+
+	return;
+out:
+	sysmon_envsys_destroy(sc->sc_sme);
+	sc->sc_sme = NULL;
+}
+
+/* The conversion algorithms are taken from the BMP280 datasheet.  The
+ * same algorithms are used with the BME280.
+ *
+ * https://www.bosch-sensortec.com/media/boschsensortec/downloads/datasheets/bst-bmp280-ds001.pdf
+ *
+ * Section 3.11.3, page 21
+ *
+ */
+
+static int32_t
+bmx280_compensate_T_int32(struct bmx280_calibration_blob *b,
+    int32_t adc_T,
+    int32_t *t_fine)
+{
+	int32_t var1, var2, T;
+	var1 = ((((adc_T>>3) - ((int32_t)b->dig_T1<<1))) * ((int32_t)b->dig_T2)) >> 11;
+	var2 = (((((adc_T>>4) - ((int32_t)b->dig_T1)) * ((adc_T>>4) - ((int32_t)b->dig_T1))) >> 12) *
+	    ((int32_t)b->dig_T3)) >> 14;
+	*t_fine = var1 + var2;
+	T = (*t_fine * 5 + 128) >> 8;
+	return T;
+}
+
+/* Returns pressure in Pa as unsigned 32 bit integer in Q24.8 format (24 integer bits and 8 fractional bits).
+ * Output value of 24674867 represents 24674867/256 = 96386.2 Pa = 963.862 hPa
+ */
+static uint32_t
+bmx280_compensate_P_int64(struct bmx280_calibration_blob *b,
+    int32_t adc_P,
+    int32_t t_fine)
+{
+	int64_t var1, var2, p;
+	var1 = ((int64_t)t_fine) - 128000;
+	var2 = var1 * var1 * (int64_t)b->dig_P6;
+	var2 = var2 + ((var1*(int64_t)b->dig_P5)<<17);
+	var2 = var2 + (((int64_t)b->dig_P4)<<35);
+	var1 = ((var1 * var1 * (int64_t)b->dig_P3)>>8) + ((var1 * (int64_t)b->dig_P2)<<12);
+	var1 = (((((int64_t)1)<<47)+var1))*((int64_t)b->dig_P1)>>33;
+	if (var1 == 0) {
+		return 0; /* avoid exception caused by division by zero */
+	}
+	p = 1048576-adc_P;
+	p = (((p<<31)-var2)*3125)/var1;
+	var1 = (((int64_t)b->dig_P9) * (p>>13) * (p>>13)) >> 25;
+	var2 = (((int64_t)b->dig_P8) * p) >> 19;
+	p = ((p + var1 + var2) >> 8) + (((int64_t)b->dig_P7)<<4);
+	return (uint32_t)p;
+}
+
+/* Returns humidity in %RH as unsigned 32 bit integer in Q22.10 format (22 integer and 10 fractional bits).
+ *
+ * Output value of 47445 represents 47445/1024 = 46.333 %RH
+ */
+static uint32_t
+bmx280_compensate_H_int32(struct bmx280_calibration_blob *b,
+    int32_t adc_H,
+    int32_t t_fine)
+{
+	int32_t v_x1_u32r;
+	v_x1_u32r = (t_fine - ((int32_t)76800));
+	v_x1_u32r = (((((adc_H << 14) - (((int32_t)b->dig_H4) << 20) - (((int32_t)b->dig_H5) *
+	    v_x1_u32r)) + ((int32_t)16384)) >> 15) * (((((((v_x1_u32r *
+	    ((int32_t)b->dig_H6)) >> 10) * (((v_x1_u32r * ((int32_t)b->dig_H3)) >> 11) +
+	    ((int32_t)32768))) >> 10) + ((int32_t)2097152)) * ((int32_t)b->dig_H2) +
+	    8192) >> 14));
+	v_x1_u32r = (v_x1_u32r - (((((v_x1_u32r >> 15) * (v_x1_u32r >> 15)) >> 7) *
+	    ((int32_t)b->dig_H1)) >> 4));
+	v_x1_u32r = (v_x1_u32r < 0 ? 0 : v_x1_u32r);
+	v_x1_u32r = (v_x1_u32r > 419430400 ? 419430400 : v_x1_u32r);
+	return (uint32_t)(v_x1_u32r>>12);
+}
+
+
+static int
+bmx280_set_control_and_trigger(struct bmx280_sc *sc,
+    uint8_t osrs_t_mask,
+    uint8_t osrs_p_mask,
+    uint8_t osrs_h_mask,
+    uint8_t filter_mask)
+{
+	uint8_t cr[6];
+	int error;
+	int s = 0;
+
+	cr[0] = cr[1] = cr[2] = cr[3] = cr[4] = cr[5] = 0;
+
+	if (filter_mask != sc->sc_previous_irr) {
+		cr[s] = BMX280_REGISTER_CONFIG;
+		s++;
+		cr[s] = filter_mask << BMX280_CONFIG_FILTER_SHIFT;
+		s++;
+		sc->sc_previous_irr = filter_mask;
+	}
+	if (sc->sc_has_humidity) {
+		cr[s] = BMX280_REGISTER_CTRL_HUM;
+		s++;
+		cr[s] = osrs_h_mask;
+		s++;
+	}
+	cr[s] = BMX280_REGISTER_CTRL_MEAS;
+	s++;
+	cr[s] = osrs_t_mask << BMX280_CTRL_OSRS_T_SHIFT;
+	cr[s] = cr[s] | osrs_p_mask << BMX280_CTRL_OSRS_P_SHIFT;
+	cr[s] = cr[s] | BMX280_MODE_FORCED;
+	s++;
+	DPRINTF(sc, 2, ("%s: control register set up: num: %d ; %02x %02x ; %02x %02x ; %02x %02x\n",
+	    device_xname(sc->sc_dev), s, cr[0], cr[1], cr[2], cr[3], cr[4], cr[5]));
+	error = (*(sc->sc_func_write_register))(sc, cr, s);
+	if (error) {
+		DPRINTF(sc, 2, ("%s: write control registers: %d\n",
+		    device_xname(sc->sc_dev), error));
+		error = EINVAL;
+	}
+
+	/* The wait needed is not well documented, so this is somewhat of a guess.
+	 * There is an attempt with this to only wait as long as needed.
+	 */
+
+	int p1, p2;
+
+	p1 = (osrs_t_mask * sc->sc_waitfactor_t) + (osrs_p_mask * sc->sc_waitfactor_p);
+	if (sc->sc_has_humidity) {
+		p1 = p1 + (osrs_h_mask * sc->sc_waitfactor_h);
+	}
+	p2 = mstohz(p1);
+	if (p2 == 0) {
+		p2 = 1;
+	}
+	/* Be careful with this...  the print itself will cause extra delay */
+	DPRINTF(sc, 2, ("%s: p1: %d ; %d\n",
+	    device_xname(sc->sc_dev), p1, p2));
+	kpause("b280mea",false,p2,NULL);
+
+	return error;
+}
+
+static int
+bmx280_wait_for_data(struct bmx280_sc *sc)
+{
+	uint8_t reg;
+	uint8_t running = 99;
+	int c = sc->sc_readattempts;
+	int error = 0, ierror;
+
+	reg = BMX280_REGISTER_STATUS;
+	do {
+		delay(1000);
+		ierror = (*(sc->sc_func_read_register))(sc, reg, &running, 1);
+		if (ierror) {
+			DPRINTF(sc, 2, ("%s: Refresh failed to read back status: %d\n",
+			    device_xname(sc->sc_dev), ierror));
+			error = EINVAL;
+			break;
+		}
+
+		DPRINTF(sc, 2, ("%s: Refresh status read back: %02x\n",
+		    device_xname(sc->sc_dev), running));
+
+		c--;
+	} while (c > 0 && (running & BMX280_STATUS_MEASURING_MASK));
+
+	return error;
+}
+
+static int
+bmx280_read_data(struct bmx280_sc *sc,
+    int32_t *temp,
+    int32_t *press,
+    int32_t *hum,
+    bool justtemp)
+{
+	int error = 0, ierror;
+	int rlen, rtstart, rpstart, rhstart;
+	int x_temp, x_press, x_hum;
+	uint8_t raw_press_temp_hum[8], reg;
+
+	raw_press_temp_hum[0] = raw_press_temp_hum[1] =
+	    raw_press_temp_hum[2] = raw_press_temp_hum[3] =
+	    raw_press_temp_hum[4] = raw_press_temp_hum[5] =
+	    raw_press_temp_hum[6] = raw_press_temp_hum[7] = 0;
+
+	if (justtemp) {
+		reg = BMX280_REGISTER_TEMP_MSB;
+		rlen = 3;
+		rtstart = 0;
+		rpstart = 0;
+		rhstart = 0;
+	} else {
+		reg = BMX280_REGISTER_PRESS_MSB;
+		if (sc->sc_has_humidity == false) {
+			rlen = 6;
+		} else {
+			rlen = 8;
+		}
+		rtstart = 3;
+		rpstart = 0;
+		rhstart = 6;
+	}
+
+	DPRINTF(sc, 2, ("%s: read data: reg: %02x ; len: %d ; tstart: %d ; pstart: %d\n",
+	    device_xname(sc->sc_dev), reg, rlen, rtstart, rpstart));
+
+	ierror = (*(sc->sc_func_read_register))(sc, reg, raw_press_temp_hum, rlen);
+	if (ierror) {
+		DPRINTF(sc, 2, ("%s: failed to read pressure and temp registers: %d\n",
+		    device_xname(sc->sc_dev), ierror));
+		error = EINVAL;
+		goto out;
+	}
+
+	DPRINTF(sc, 2, ("%s: raw pressure, temp and hum: %02x %02x %02x - %02x %02x %02x - %02x %02x\n",
+	    device_xname(sc->sc_dev),
+	    raw_press_temp_hum[0], raw_press_temp_hum[1], raw_press_temp_hum[2],
+	    raw_press_temp_hum[3], raw_press_temp_hum[4], raw_press_temp_hum[5],
+	    raw_press_temp_hum[6],raw_press_temp_hum[7]));
+
+	x_temp = raw_press_temp_hum[rtstart] << 12;
+	x_temp = x_temp | (raw_press_temp_hum[rtstart + 1] << 4);
+	x_temp = x_temp | (raw_press_temp_hum[rtstart + 2] >> 4);
+
+	DPRINTF(sc, 1, ("%s: intermediate temp: %d (%04x)\n",
+	    device_xname(sc->sc_dev), x_temp, x_temp));
+
+	*temp = x_temp;
+
+	*hum = 0;
+	*press = 0;
+
+	if (justtemp == false) {
+		x_press = raw_press_temp_hum[rpstart] << 12;
+		x_press = x_press | (raw_press_temp_hum[rpstart + 1] << 4);
+		x_press = x_press | (raw_press_temp_hum[rpstart + 2] >> 4);
+
+		DPRINTF(sc, 1, ("%s: intermediate pressure: %d (%04x)\n",
+		    device_xname(sc->sc_dev), x_press, x_press));
+		*press = x_press;
+	}
+	if (sc->sc_has_humidity) {
+		x_hum = raw_press_temp_hum[rhstart] << 8;
+		x_hum = x_hum | raw_press_temp_hum[rhstart + 1];
+
+		DPRINTF(sc, 1, ("%s: intermediate humidity: %d (%02x)\n",
+		    device_xname(sc->sc_dev), x_hum, x_hum));
+		*hum = x_hum;
+	}
+
+ out:
+	return error;
+}
+
+static void
+bmx280_refresh(struct sysmon_envsys * sme, envsys_data_t * edata)
+{
+	struct bmx280_sc *sc;
+	sc = sme->sme_cookie;
+	int error = 0;
+	int32_t t_fine;
+	int32_t m_temp, m_press, m_hum;
+	int32_t comp_temp;
+	uint32_t comp_press;
+	uint32_t comp_hum;
+	edata->state = ENVSYS_SINVALID;
+
+	/* Ya... just do this on a refresh... */
+
+	if (sc->sc_bmx280dump) {
+		DPRINTF(sc, 1, ("%s: dig_T1: %d %04x\n",__func__,sc->sc_cal_blob.dig_T1,sc->sc_cal_blob.dig_T1));
+		DPRINTF(sc, 1, ("%s: dig_T2: %d %04x\n",__func__,sc->sc_cal_blob.dig_T2,sc->sc_cal_blob.dig_T2));
+		DPRINTF(sc, 1, ("%s: dig_T3: %d %04x\n",__func__,sc->sc_cal_blob.dig_T3,sc->sc_cal_blob.dig_T3));
+		DPRINTF(sc, 1, ("%s: dig_P1: %d %04x\n",__func__,sc->sc_cal_blob.dig_P1,sc->sc_cal_blob.dig_P1));
+		DPRINTF(sc, 1, ("%s: dig_P2: %d %04x\n",__func__,sc->sc_cal_blob.dig_P2,sc->sc_cal_blob.dig_P2));
+		DPRINTF(sc, 1, ("%s: dig_P3: %d %04x\n",__func__,sc->sc_cal_blob.dig_P3,sc->sc_cal_blob.dig_P3));
+		DPRINTF(sc, 1, ("%s: dig_P4: %d %04x\n",__func__,sc->sc_cal_blob.dig_P4,sc->sc_cal_blob.dig_P4));
+		DPRINTF(sc, 1, ("%s: dig_P5: %d %04x\n",__func__,sc->sc_cal_blob.dig_P5,sc->sc_cal_blob.dig_P5));
+		DPRINTF(sc, 1, ("%s: dig_P6: %d %04x\n",__func__,sc->sc_cal_blob.dig_P6,sc->sc_cal_blob.dig_P6));
+		DPRINTF(sc, 1, ("%s: dig_P7: %d %04x\n",__func__,sc->sc_cal_blob.dig_P7,sc->sc_cal_blob.dig_P7));
+		DPRINTF(sc, 1, ("%s: dig_P8: %d %04x\n",__func__,sc->sc_cal_blob.dig_P8,sc->sc_cal_blob.dig_P8));
+		DPRINTF(sc, 1, ("%s: dig_P9: %d %04x\n",__func__,sc->sc_cal_blob.dig_P9,sc->sc_cal_blob.dig_P9));
+
+		if (sc->sc_has_humidity) {
+			DPRINTF(sc, 1, ("%s: dig_H1: %d %02x\n",__func__,sc->sc_cal_blob.dig_H1,sc->sc_cal_blob.dig_H1));
+			DPRINTF(sc, 1, ("%s: dig_H2: %d %04x\n",__func__,sc->sc_cal_blob.dig_H2,sc->sc_cal_blob.dig_H2));
+			DPRINTF(sc, 1, ("%s: dig_H3: %d %02x\n",__func__,sc->sc_cal_blob.dig_H3,sc->sc_cal_blob.dig_H3));
+			DPRINTF(sc, 1, ("%s: dig_H4: %d %04x\n",__func__,sc->sc_cal_blob.dig_H4,sc->sc_cal_blob.dig_H4));
+			DPRINTF(sc, 1, ("%s: dig_H5: %d %04x\n",__func__,sc->sc_cal_blob.dig_H5,sc->sc_cal_blob.dig_H5));
+			DPRINTF(sc, 1, ("%s: dig_H6: %d %02x\n",__func__,sc->sc_cal_blob.dig_H6,sc->sc_cal_blob.dig_H6));
+		}
+
+		sc->sc_bmx280dump = false;
+	}
+
+	mutex_enter(&sc->sc_mutex);
+	error = (*(sc->sc_func_acquire_bus))(sc);
+	if (error) {
+		DPRINTF(sc, 2, ("%s: Could not acquire i2c bus: %x\n",
+		    device_xname(sc->sc_dev), error));
+		goto out;
+	}
+
+	if (error == 0) {
+		switch (edata->sensor) {
+		case BMX280_TEMP_SENSOR:
+			/* A temperature reading does not need pressure */
+
+			error = bmx280_set_control_and_trigger(sc,
+			    bmx280_osrs_text_to_mask(sc->sc_osrs_t),
+			    0,
+			    0,
+			    bmx280_irr_text_to_mask(sc->sc_irr_samples));
+
+			if (error == 0) {
+				error = bmx280_wait_for_data(sc);
+
+				if (error == 0) {
+					error = bmx280_read_data(sc, &m_temp, &m_press, &m_hum, true);
+
+					if (error == 0) {
+						comp_temp = bmx280_compensate_T_int32(&sc->sc_cal_blob, m_temp, &t_fine);
+
+						DPRINTF(sc, 1, ("%s: Refresh compensated temp: %d - t_fine: %d\n",
+						    device_xname(sc->sc_dev), comp_temp, t_fine));
+
+						/* comp_temp is in Celcius * 100.  This converts it to microkelvin */
+
+						uint32_t q;
+
+						q = (uint32_t)comp_temp;
+						q = q + 27315;
+						q = q * 10000;
+
+						DPRINTF(sc, 1, ("%s: Refresh Q: %d\n", __func__, q));
+
+						edata->value_cur = q;
+						edata->state = ENVSYS_SVALID;
+					}
+				}
+			}
+			break;
+		case BMX280_PRESSURE_SENSOR:
+
+			/* Pressure needs the temp too */
+			error = bmx280_set_control_and_trigger(sc,
+			    bmx280_osrs_text_to_mask(sc->sc_osrs_t),
+			    bmx280_osrs_text_to_mask(sc->sc_osrs_p),
+			    0,
+			    bmx280_irr_text_to_mask(sc->sc_irr_samples));
+
+			if (error == 0) {
+				error = bmx280_wait_for_data(sc);
+
+				if (error == 0) {
+					error = bmx280_read_data(sc, &m_temp, &m_press, &m_hum, false);
+
+					if (error == 0) {
+						comp_temp = bmx280_compensate_T_int32(&sc->sc_cal_blob, m_temp, &t_fine);
+
+						DPRINTF(sc, 1, ("%s: Refresh compensated temp for pressure: %d - t_fine: %d\n",
+						    device_xname(sc->sc_dev), comp_temp, t_fine));
+
+						comp_press = bmx280_compensate_P_int64(&sc->sc_cal_blob, m_press, t_fine);
+
+						DPRINTF(sc, 1, ("%s: Refresh compensated pressure: %d\n",
+						    device_xname(sc->sc_dev), comp_press));
+
+						uint32_t q;
+
+						q = comp_press;
+						q = q / 256;
+						q = q * 100;
+
+						DPRINTF(sc, 1, ("%s: Refresh pressure Q: %d\n", __func__, q));
+
+						edata->value_cur = q;
+						edata->state = ENVSYS_SVALID;
+					}
+				}
+			}
+			break;
+
+		case BMX280_HUMIDITY_SENSOR:
+
+			/* Humidity wants temperature */
+
+			error = bmx280_set_control_and_trigger(sc,
+			    bmx280_osrs_text_to_mask(sc->sc_osrs_t),
+			    0,
+			    bmx280_osrs_text_to_mask(sc->sc_osrs_h),
+			    bmx280_irr_text_to_mask(sc->sc_irr_samples));
+
+			if (error == 0) {
+				error = bmx280_wait_for_data(sc);
+
+				if (error == 0) {
+					error = bmx280_read_data(sc, &m_temp, &m_press, &m_hum, false);
+
+					if (error == 0) {
+						comp_temp = bmx280_compensate_T_int32(&sc->sc_cal_blob, m_temp, &t_fine);
+
+						DPRINTF(sc, 1, ("%s: Refresh compensated temp for humidity: %d - t_fine: %d\n",
+						    device_xname(sc->sc_dev), comp_temp, t_fine));
+
+						comp_hum = bmx280_compensate_H_int32(&sc->sc_cal_blob, m_hum, t_fine);
+
+						DPRINTF(sc, 2, ("%s: Refresh compensated humidity: %d\n",
+						    device_xname(sc->sc_dev), comp_hum));
+
+						uint64_t q;
+
+						q = (uint64_t)comp_hum * 1000000;
+						DPRINTF(sc, 1, ("%s: Refresh humidity Q 1: %jd\n", __func__, (uintmax_t)q));
+						q = q / 1024;
+
+						DPRINTF(sc, 1, ("%s: Refresh humidity Q 2: %jd\n", __func__, (uintmax_t)q));
+
+						edata->value_cur = (uint32_t) q;
+						edata->state = ENVSYS_SVALID;
+					}
+				}
+			}
+			break;
+		}
+	}
+
+	if (error) {
+		DPRINTF(sc, 2, ("%s: Failed to get new status in refresh %d\n",
+		    device_xname(sc->sc_dev), error));
+	}
+
+	(*(sc->sc_func_release_bus))(sc);
+out:
+	mutex_exit(&sc->sc_mutex);
+}
+
+MODULE(MODULE_CLASS_DRIVER, bmx280thp, NULL);
+
+#ifdef _MODULE
+CFDRIVER_DECL(bmx280thp, DV_DULL, NULL);
+#include "ioconf.c"
+#endif
+
+static int
+bmx280thp_modcmd(modcmd_t cmd, void *opaque)
+{
+
+	switch (cmd) {
+	case MODULE_CMD_INIT:
+#ifdef _MODULE
+		return config_init_component(cfdriver_ioconf_bmx280thp,
+		    cfattach_ioconf_bmx280thp, cfdata_ioconf_bmx280thp);
+#else
+		return 0;
+#endif
+	case MODULE_CMD_FINI:
+#ifdef _MODULE
+		return config_fini_component(cfdriver_ioconf_bmx280thp,
+		      cfattach_ioconf_bmx280thp, cfdata_ioconf_bmx280thp);
+#else
+		return 0;
+#endif
+	default:
+		return ENOTTY;
+	}
+}
Index: src/sys/dev/ic/bmx280reg.h
diff -u /dev/null src/sys/dev/ic/bmx280reg.h:1.1
--- /dev/null	Sat Dec  3 01:04:43 2022
+++ src/sys/dev/ic/bmx280reg.h	Sat Dec  3 01:04:43 2022
@@ -0,0 +1,96 @@
+/*	$NetBSD: bmx280reg.h,v 1.1 2022/12/03 01:04:43 brad Exp $	*/
+
+/*
+ * Copyright (c) 2022 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_IC_BMX280REG_H_
+#define _DEV_IC_BMX280REG_H_
+
+#define BMX280_TYPICAL_ADDR_1	0x76
+#define BMX280_TYPICAL_ADDR_2	0x77
+
+#define BMX280_REGISTER_DIG_T1		0x88
+#define BMX280_REGISTER_DIG_T2		0x8A
+#define BMX280_REGISTER_DIG_T3		0x8C
+#define BMX280_REGISTER_DIG_P1		0x8E
+#define BMX280_REGISTER_DIG_P2		0x90
+#define BMX280_REGISTER_DIG_P3		0x92
+#define BMX280_REGISTER_DIG_P4		0x94
+#define BMX280_REGISTER_DIG_P5		0x96
+#define BMX280_REGISTER_DIG_P6		0x98
+#define BMX280_REGISTER_DIG_P7		0x9A
+#define BMX280_REGISTER_DIG_P8		0x9C
+#define BMX280_REGISTER_DIG_P9		0x9E
+#define BMX280_REGISTER_DIG_H1		0xA1
+#define BMX280_REGISTER_DIG_H2		0xE1
+#define BMX280_REGISTER_DIG_H3		0xE3
+#define BMX280_REGISTER_DIG_H4		0xE4
+#define BMX280_REGISTER_DIG_H5		0xE5
+
+#define BMX280_REGISTER_ID		0xD0
+#define BMX280_ID_BMP280		0x58
+#define BMX280_ID_BME280		0x60
+
+#define BMX280_REGISTER_RESET		0xE0
+#define BMX280_TRIGGER_RESET		0xB6
+
+#define BMX280_REGISTER_CTRL_HUM	0xF2
+
+#define BMX280_REGISTER_STATUS		0xF3
+#define BMX280_STATUS_MEASURING_MASK	0x08
+#define BMX280_STATUS_IM_UPDATE_MASK	0x01
+
+#define BMX280_REGISTER_CTRL_MEAS	0xF4
+#define BMX280_CTRL_OSRS_T_MASK		0xE0
+#define BMX280_CTRL_OSRS_P_MASK		0x1C
+#define BMX280_CTRL_OSRS_T_SHIFT	5
+#define BMX280_CTRL_OSRS_P_SHIFT	2
+#define BMX280_OSRS_TP_VALUE_SKIPPED	0x00
+#define BMX280_OSRS_TP_VALUE_X1		0x01
+#define BMX280_OSRS_TP_VALUE_X2		0x02
+#define BMX280_OSRS_TP_VALUE_X4		0x03
+#define BMX280_OSRS_TP_VALUE_X8		0x04
+#define BMX280_OSRS_TP_VALUE_X16	0x05
+#define BMX280_CTRL_MODE_MASK		0x03
+#define BMX280_MODE_SLEEP		0x00
+#define BMX280_MODE_FORCED		0x01
+#define BMX280_MODE_NORMAL		0x03
+
+#define BMX280_REGISTER_CONFIG		0xF5
+#define BMX280_CONFIG_T_SB_MASK		0xE0
+#define BMX280_CONFIG_FILTER_MASK	0x1C
+#define BMX280_CONFIG_FILTER_SHIFT	2
+#define BMX280_FILTER_VALUE_OFF		0x00
+#define BMX280_FILTER_VALUE_2		0x01
+#define BMX280_FILTER_VALUE_5		0x02
+#define BMX280_FILTER_VALUE_11		0x04
+#define BMX280_FILTER_VALUE_22		0x05
+#define BMX280_CONFIG_SPI3W_EN_MASK	0x01
+
+#define BMX280_REGISTER_PRESS_MSB	0xF7
+#define BMX280_REGISTER_PRESS_LSB	0xF8
+#define BMX280_REGISTER_PRESS_XLSB	0xF9
+
+#define BMX280_REGISTER_TEMP_MSB	0xFA
+#define BMX280_REGISTER_TEMP_LSB	0xFB
+#define BMX280_REGISTER_TEMP_XLSB	0xFC
+
+#define BMX280_TEMPPRES_XLSB_MASK	0xF0
+
+#define BMX280_REGISTER_HUM_MSB		0xFD
+#define BMX280_REGISTER_HUM_LSB		0xFE
+
+#endif
Index: src/sys/dev/ic/bmx280var.h
diff -u /dev/null src/sys/dev/ic/bmx280var.h:1.1
--- /dev/null	Sat Dec  3 01:04:43 2022
+++ src/sys/dev/ic/bmx280var.h	Sat Dec  3 01:04:43 2022
@@ -0,0 +1,94 @@
+/*	$NetBSD: bmx280var.h,v 1.1 2022/12/03 01:04:43 brad Exp $	*/
+
+/*
+ * Copyright (c) 2022 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_IC_BMX280VAR_H_
+#define _DEV_IC_BMX280VAR_H_
+
+#define BMX280_NUM_SENSORS	3
+#define BMX280_TEMP_SENSOR 0
+#define BMX280_PRESSURE_SENSOR 1
+#define BMX280_HUMIDITY_SENSOR 2
+
+struct bmx280_calibration_blob {
+	uint16_t dig_T1;
+	int16_t dig_T2;
+	int16_t dig_T3;
+
+	uint16_t dig_P1;
+	int16_t dig_P2;
+	int16_t dig_P3;
+	int16_t dig_P4;
+	int16_t dig_P5;
+	int16_t dig_P6;
+	int16_t dig_P7;
+	int16_t dig_P8;
+	int16_t dig_P9;
+	uint8_t dig_H1;
+	int16_t dig_H2;
+	uint8_t dig_H3;
+	int16_t dig_H4;
+	int16_t dig_H5;
+	int8_t dig_H6;
+};
+
+struct bmx280_sc {
+	int 		sc_bmx280debug;
+	device_t 	sc_dev;
+	i2c_tag_t 	sc_tag;
+	i2c_addr_t 	sc_addr;
+	struct spi_handle *sc_sh;
+	kmutex_t 	sc_mutex;
+	int 		sc_numsensors;
+	struct sysmon_envsys *sc_sme;
+	struct sysctllog *sc_bmx280log;
+	envsys_data_t 	sc_sensors[BMX280_NUM_SENSORS];
+	struct bmx280_calibration_blob	sc_cal_blob;
+	bool		sc_has_humidity;
+	int		sc_readattempts;
+	int		sc_osrs_t;
+	int		sc_osrs_p;
+	int		sc_osrs_h;
+	int		sc_irr_samples;
+	uint8_t		sc_previous_irr;
+	bool		sc_bmx280dump;
+	int		sc_waitfactor_t;
+	int		sc_waitfactor_p;
+	int		sc_waitfactor_h;
+	void		(*sc_func_attach)(struct bmx280_sc *);
+	int		(*sc_func_acquire_bus)(struct bmx280_sc *);
+	void		(*sc_func_release_bus)(struct bmx280_sc *);
+	int		(*sc_func_read_register)(struct bmx280_sc *, uint8_t, uint8_t *, size_t);
+	int		(*sc_func_write_register)(struct bmx280_sc *, uint8_t *, size_t);
+};
+
+struct bmx280_sensor {
+	const char     *desc;
+	enum envsys_units type;
+};
+
+struct bmx280_osrs_list {
+	const int	text;
+	uint8_t		mask;
+};
+
+struct bmx280_irr_list {
+	const int	text;
+	uint8_t		mask;
+};
+
+#endif

Index: src/sys/dev/spi/bmx280thpspi.c
diff -u /dev/null src/sys/dev/spi/bmx280thpspi.c:1.1
--- /dev/null	Sat Dec  3 01:04:43 2022
+++ src/sys/dev/spi/bmx280thpspi.c	Sat Dec  3 01:04:43 2022
@@ -0,0 +1,205 @@
+/*	$NetBSD: bmx280thpspi.c,v 1.1 2022/12/03 01:04:43 brad Exp $	*/
+
+/*
+ * Copyright (c) 2022 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: bmx280thpspi.c,v 1.1 2022/12/03 01:04:43 brad Exp $");
+
+/*
+ * SPI driver for the Bosch BMP280 / BME280 sensor.
+ * Uses the common bmx280thp driver to do the real work.
+*/
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/kernel.h>
+#include <sys/device.h>
+#include <sys/module.h>
+#include <sys/conf.h>
+#include <sys/sysctl.h>
+#include <sys/mutex.h>
+#include <sys/condvar.h>
+#include <sys/pool.h>
+#include <sys/kmem.h>
+
+#include <dev/sysmon/sysmonvar.h>
+#include <dev/i2c/i2cvar.h>
+#include <dev/spi/spivar.h>
+#include <dev/ic/bmx280reg.h>
+#include <dev/ic/bmx280var.h>
+
+extern void	bmx280_attach(struct bmx280_sc *);
+
+static int 	bmx280thpspi_match(device_t, cfdata_t, void *);
+static void 	bmx280thpspi_attach(device_t, device_t, void *);
+static int 	bmx280thpspi_detach(device_t, int);
+
+#define BMX280_DEBUG
+#ifdef BMX280_DEBUG
+#define DPRINTF(s, l, x) \
+    do { \
+	if (l <= s->sc_bmx280debug) \
+	    printf x; \
+    } while (/*CONSTCOND*/0)
+#else
+#define DPRINTF(s, l, x)
+#endif
+
+CFATTACH_DECL_NEW(bmx280thpspi, sizeof(struct bmx280_sc),
+    bmx280thpspi_match, bmx280thpspi_attach, bmx280thpspi_detach, NULL);
+
+/* The SPI interface of the chip, assuming that it has managed to get into that
+ * mode to start with, is pretty simple.  Simply send the register MINUS the 7th
+ * bit which will be 1 and then do as many reads as you want.  The chip will
+ * auto increment for you.
+ *
+ * The delays are only hinted at in the data sheet.
+ */
+
+static int
+bmx280thpspi_read_reg_direct(struct spi_handle *sh, uint8_t reg,
+    uint8_t *buf, size_t rlen)
+{
+	int err = 0;
+	uint8_t rreg = reg | 0x80;
+
+	if (buf != NULL) {
+		err = spi_send_recv(sh, 1, &rreg,
+		    rlen, buf);
+	} else {
+		err = spi_send(sh, 1, &rreg);
+	}
+
+	return err;
+}
+
+static int
+bmx280thpspi_read_reg(struct bmx280_sc *sc, uint8_t reg, uint8_t *buf, size_t rlen)
+{
+	return bmx280thpspi_read_reg_direct(sc->sc_sh, reg, buf, rlen);
+}
+
+/* SPI writes to this device are normal enough.  You send the register
+ * you want making sure that the high bit, 0x80, is clear and then the
+ * data.  These pairs can be repeated as many times as you like.
+ */
+static int
+bmx280thpspi_write_reg_direct(struct spi_handle *sh, uint8_t *buf, size_t slen)
+{
+	int err = 0;
+	int i;
+
+	/* XXX -
+	   this is probably  BAD thing to do... but we must insure that the
+	   registers have a cleared bit.. otherwise it is a read ....
+	*/
+
+	for(i = 0; i < slen;i+=2) {
+		buf[i] = buf[i] & 0x7F;
+	}
+
+	err = spi_send(sh, slen, buf);
+
+	return err;
+}
+
+static int
+bmx280thpspi_write_reg(struct bmx280_sc *sc, uint8_t *buf, size_t slen)
+{
+	return bmx280thpspi_write_reg_direct(sc->sc_sh, buf, slen);
+}
+
+/* These are to satisfy the common code */
+static int
+bmx280thpspi_acquire_bus(struct bmx280_sc *sc)
+{
+	return 0;
+}
+
+static void
+bmx280thpspi_release_bus(struct bmx280_sc *sc)
+{
+	return;
+}
+
+/* Nothing more is done here.  Assumptions on whether or not
+ * the SPI interface is set up may not be proper.... for better
+ * or worse... and there is setting that are needed such as the
+ * SPI mode and bus speed that really should not be done here, so
+ * any active match might not work anyway.
+ */
+static int
+bmx280thpspi_match(device_t parent, cfdata_t match, void *aux)
+{
+	const bool matchdebug = false;
+
+	if (matchdebug) {
+		printf("Trying to match\n");
+	}
+
+	return 1;
+}
+
+static void
+bmx280thpspi_attach(device_t parent, device_t self, void *aux)
+{
+	struct bmx280_sc *sc;
+	struct spi_attach_args *sa;
+	int error;
+
+	sa = aux;
+	sc = device_private(self);
+
+	sc->sc_dev = self;
+	sc->sc_sh = sa->sa_handle;
+	sc->sc_bmx280debug = 0;
+	sc->sc_func_acquire_bus = &bmx280thpspi_acquire_bus;
+	sc->sc_func_release_bus = &bmx280thpspi_release_bus;
+	sc->sc_func_read_register = &bmx280thpspi_read_reg;
+	sc->sc_func_write_register = &bmx280thpspi_write_reg;
+
+	/* Configure for 1MHz and SPI mode 0 according to the data sheet.
+	 * The chip will actually handle a number of different modes and
+	 * can go a lot faster, just use this for now...
+	 */
+	error = spi_configure(self, sa->sa_handle, SPI_MODE_0, 1000000);
+	if (error) {
+		return;
+	}
+
+	/* Please note that if the pins are not set up for SPI, the attachment
+	 * will probably not work out.
+	 */
+	bmx280_attach(sc);
+
+	return;
+}
+
+/* These really do not do a whole lot, as SPI devices do not seem to work
+ * as modules.
+ */
+static int
+bmx280thpspi_detach(device_t self, int flags)
+{
+	struct bmx280_sc *sc;
+
+	sc = device_private(self);
+
+	mutex_destroy(&sc->sc_mutex);
+
+	return 0;
+}

Index: src/sys/modules/bmx280thpi2c/Makefile
diff -u /dev/null src/sys/modules/bmx280thpi2c/Makefile:1.1
--- /dev/null	Sat Dec  3 01:04:43 2022
+++ src/sys/modules/bmx280thpi2c/Makefile	Sat Dec  3 01:04:42 2022
@@ -0,0 +1,11 @@
+.include "../Makefile.inc"
+
+.PATH:	${S}/dev/i2c
+
+KMOD=	bmx280thpi2c
+IOCONF=	bmx280thpi2c.ioconf
+SRCS=	bmx280thpi2c.c
+
+WARNS=	3
+
+.include <bsd.kmodule.mk>
Index: src/sys/modules/bmx280thpi2c/bmx280thpi2c.ioconf
diff -u /dev/null src/sys/modules/bmx280thpi2c/bmx280thpi2c.ioconf:1.1
--- /dev/null	Sat Dec  3 01:04:43 2022
+++ src/sys/modules/bmx280thpi2c/bmx280thpi2c.ioconf	Sat Dec  3 01:04:42 2022
@@ -0,0 +1,8 @@
+ioconf bmx280thpi2c
+
+include "conf/files"
+
+pseudo-root iic*
+
+bmx280thp* at iic? addr 0x76
+bmx280thp* at iic? addr 0x77

Reply via email to