--- src/sys/kern/kern_todr.c.dist	2026-01-23 16:30:48.189998898 +0100
+++ src/sys/kern/kern_todr.c	2026-02-11 14:58:11.409976461 +0100
@@ -78,6 +78,7 @@
 #include <sys/device_calls.h>
 #include <sys/intr.h>
 #include <sys/kernel.h>
+#include <sys/kmem.h>
 #include <sys/mutex.h>
 #include <sys/rndsource.h>
 #include <sys/sdt.h>
@@ -86,11 +87,17 @@
 
 #include <dev/clock_subr.h>	/* hmm.. this should probably move to sys */
 
+struct todr_list {
+	todr_chip_handle_t todr_handle;
+	struct todr_list *todr_next;
+};
+
 static int todr_gettime(todr_chip_handle_t, struct timeval *);
 static int todr_settime(todr_chip_handle_t, struct timeval *);
 
 static kmutex_t todr_mutex;
-static todr_chip_handle_t todr_handle;
+static struct todr_list todr_head =
+	{ .todr_handle = NULL, .todr_next = NULL };
 static bool todr_initialized;
 
 /* The minimum reasonable RTC date before preposterousness */
@@ -179,6 +186,7 @@
 void
 todr_attach(todr_chip_handle_t todr)
 {
+	struct todr_list *todr_newp, *todr_iterp;
 
 	/*
 	 * todr_init() is called very early in main(), but this is
@@ -191,13 +199,22 @@
 		return;
 	}
 
-	todr_lock();
-	if (todr_handle) {
-		todr_unlock();
-		printf("todr_attach: TOD already configured\n");
-		return;
+	/* Initial entry is static, others allocated. */
+	if (todr_head.todr_handle != NULL) {
+		todr_newp = kmem_alloc(sizeof(struct todr_list),
+		    KM_SLEEP);
+		todr_newp->todr_next = NULL;
+		todr_lock();
+		todr_newp->todr_handle = todr;
+		todr_iterp = &todr_head;
+		while (todr_iterp->todr_next != NULL)
+			todr_iterp = todr_iterp->todr_next;
+		todr_iterp->todr_next = todr_newp;
+		printf("(secondary clock)\n");
+	} else {
+		todr_lock();
+		todr_head.todr_handle = todr;
 	}
-	todr_handle = todr;
 	todr_unlock();
 }
 
@@ -246,16 +263,17 @@
 	/*
 	 * Some ports need to be supplied base in order to fabricate a time_t.
 	 */
-	if (todr_handle)
-		todr_handle->todr_base_time = base;
+	if (todr_head.todr_handle != NULL)
+		todr_head.todr_handle->todr_base_time = base;
 
 	memset(&tv, 0, sizeof(tv));
 
-	if ((todr_handle == NULL) ||
-	    (todr_gettime(todr_handle, &tv) != 0) ||
+	/* Note, that we only read time from the first RTC. */
+	if ((todr_head.todr_handle == NULL) ||
+	    (todr_gettime(todr_head.todr_handle, &tv) != 0) ||
 	    (tv.tv_sec < (PREPOSTEROUS_YEARS * SECS_PER_COMMON_YEAR))) {
 
-		if (todr_handle != NULL)
+		if (todr_head.todr_handle != NULL)
 			printf("WARNING: preposterous TOD clock time\n");
 		else
 			printf("WARNING: no TOD clock present\n");
@@ -322,6 +340,7 @@
 todr_save_systime(void)
 {
 	struct timeval tv;
+	struct todr_list *todr_iterp;
 
 	KASSERT(todr_lock_owned());
 
@@ -338,9 +357,13 @@
 	if (tv.tv_sec == 0)
 		return;
 
-	if (todr_handle)
-		if (todr_settime(todr_handle, &tv) != 0)
-			printf("Cannot set TOD clock time\n");
+	todr_iterp = &todr_head;
+	do {
+		if (todr_iterp->todr_handle != NULL)
+			if (todr_settime(todr_iterp->todr_handle, &tv) != 0)
+				printf("Cannot set TOD clock time\n");
+		todr_iterp = todr_iterp->todr_next;
+	} while (todr_iterp != NULL);
 }
 
 /*
--- src/sys/arch/sparc64/conf/GENERIC.dist	2026-02-10 22:21:13.119986367 +0100
+++ src/sys/arch/sparc64/conf/GENERIC	2026-02-16 16:20:33.489999265 +0100
@@ -830,9 +830,13 @@
 lmtemp* 	at iic? addr?
 tda*		at iic? addr?	# fan control on SB1000/2000
 dbcool* 	at iic? addr?	# SB25000
+nxp75a* 	at iic? addr?	# U45
+lm95221ts* 	at iic? addr?	# U45
+adt7462sm* 	at iic? addr?	# U45
 seeprom*	at iic? addr?	# i2c-at24c64 fru's
 pcagpio* 	at iic? addr?	# V210/V240 GPIO's
 pcf8574io* 	at iic? addr?	# E250 GPIO's
+dsrtc* 		at iic? addr?	# RSC clock found on V210 and V240.
 
 ### Other pseudo-devices
 
--- src/sys/arch/sparc64/sparc64/autoconf.c.dist	2026-02-06 17:35:30.000000000 +0100
+++ src/sys/arch/sparc64/sparc64/autoconf.c	2026-02-04 20:14:36.879990895 +0100
@@ -1,4 +1,4 @@
-/*	$NetBSD: autoconf.c,v 1.247 2026/02/06 16:35:30 jdc Exp $ */
+/*	$NetBSD: autoconf.c,v 1.246 2025/10/13 04:06:13 thorpej Exp $ */
 
 /*
  * Copyright (c) 1996
@@ -48,7 +48,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: autoconf.c,v 1.247 2026/02/06 16:35:30 jdc Exp $");
+__KERNEL_RCSID(0, "$NetBSD: autoconf.c,v 1.246 2025/10/13 04:06:13 thorpej Exp $");
 
 #include "opt_ddb.h"
 #include "opt_kgdb.h"
@@ -775,8 +775,42 @@
 			portid = -1;
 		ma.ma_upaid = portid;
 
-		if (prom_getprop(node, "reg", sizeof(*ma.ma_reg), 
-				 &ma.ma_nreg, &ma.ma_reg) != 0)
+#define NREG32	3
+		if (prom_getproplen(node, "reg") == NREG32 * 4) {
+			/*
+			 * Fix up PROM's where reg is encoded as a 64-bit and
+			 * a 32-bit value (e.g. 00000400 0fc62020 00000010),
+			 * but we want 2 x 64-bit values.
+			 */
+			int n;
+			int32_t *reg32p = NULL;
+
+			if (prom_getprop(node, "reg", sizeof(int32_t),
+			    &n, &reg32p) != 0)
+				continue;
+			if (n != NREG32) {
+				free(reg32p, M_DEVBUF);
+				continue;
+			}
+			ma.ma_reg = malloc(sizeof(*ma.ma_reg), M_DEVBUF,
+			    M_NOWAIT);
+			if (ma.ma_reg == NULL)
+				continue;
+			ma.ma_reg->ur_paddr = reg32p[0];
+			ma.ma_reg->ur_paddr = ma.ma_reg->ur_paddr << 32;
+			ma.ma_reg->ur_paddr |= reg32p[1];
+			ma.ma_reg->ur_len = reg32p[2];
+			ma.ma_nreg = 1;
+			free(reg32p, M_DEVBUF);
+#ifdef DEBUG
+			if (autoconf_debug & ACDB_PROBE) {
+				printf(" fixed up 64/32 reg property\n");
+			}
+#endif
+		} else
+			/* reg is encoded as we expect */
+			if (prom_getprop(node, "reg", sizeof(*ma.ma_reg),
+			    &ma.ma_nreg, &ma.ma_reg) != 0)
 			continue;
 #ifdef DEBUG
 		if (autoconf_debug & ACDB_PROBE) {
--- src/sys/arch/sparc64/sparc64/ofw_patch.c.dist	2026-02-06 17:35:30.000000000 +0100
+++ src/sys/arch/sparc64/sparc64/ofw_patch.c	2026-02-16 13:23:31.919979846 +0100
@@ -1,4 +1,4 @@
-/*	$NetBSD: ofw_patch.c,v 1.10 2026/02/06 16:35:30 jdc Exp $ */
+/*	$NetBSD: ofw_patch.c,v 1.9 2025/09/19 13:19:25 thorpej Exp $ */
 
 /*-
  * Copyright (c) 2020 The NetBSD Foundation, Inc.
@@ -29,7 +29,7 @@
  * POSSIBILITY OF SUCH DAMAGE.
  */
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: ofw_patch.c,v 1.10 2026/02/06 16:35:30 jdc Exp $");
+__KERNEL_RCSID(0, "$NetBSD: ofw_patch.c,v 1.9 2025/09/19 13:19:25 thorpej Exp $");
 
 #include <sys/param.h>
 
@@ -290,6 +290,24 @@
 	add_i2c_device(cfg, "temperature-sensor", "i2c-lm75", 0x4e, 0);
 }
 
+/*
+ * Add U45 environmental sensors that are not in the OFW tree.
+ */
+static void
+add_env_sensors_u45(device_t busdev)
+{
+	prop_array_t cfg;
+
+	DPRINTF(ACDB_PROBE, ("\nAdding sensors for %s ", machine_model));
+	cfg = create_i2c_dict(busdev);
+
+	/* LM95221 at 0x2b */
+	add_i2c_device(cfg, "temperature-sensor", "i2c-lm95221", 0x2b, 0);
+
+	/* NXP LM75A at 0x4f */
+	add_i2c_device(cfg, "temperature-sensor", "i2c-lm75a", 0x4f, 0);
+}
+
 /* Sensors and GPIO's for E450 and E250 */
 static void
 add_i2c_props_e450(device_t busdev, uint64_t node)
@@ -347,6 +365,37 @@
 	prop_object_release(cfg);
 }
 
+/*
+ * Fix-up U45 incorrect properties in the OFW tree.
+ */
+static void
+fix_properties_u45(device_t busdev)
+{
+	prop_dictionary_t props = device_properties(busdev);
+	prop_array_t cfg;
+	prop_object_iterator_t iter;
+	prop_object_t dev;
+	uint8_t addr;
+
+	cfg = prop_dictionary_get(props, "i2c-child-devices");
+	if (!cfg)
+		return;
+
+	iter = prop_array_iterator(cfg);
+	while ((dev = prop_object_iterator_next(iter)) != NULL) {
+		if (prop_object_type(dev) != PROP_TYPE_DICTIONARY)
+			continue;
+		if (prop_dictionary_get_uint8(dev, "addr", &addr) == 0)
+			continue;
+		if (addr != 0x57)
+			continue;
+		/* Change psu-fru-prom to standard 8k seeprom */
+		prop_dictionary_set_data(dev, "compatible", "i2c-at24c64",
+			strlen("i2c-at24c64") + 1);
+	}
+	prop_object_iterator_release(iter);
+}
+
 /* Hardware specific i2c bus properties */
 void
 set_i2c_bus_props(device_t busdev, uint64_t busnode)
@@ -360,6 +409,11 @@
 		    !strcmp(machine_model, "SUNW,Sun-Fire-V210"))
 			add_env_sensors_v210(busdev);
 
+		if (!strcmp(machine_model, "SUNW,A70")) {
+			add_env_sensors_u45(busdev);
+			fix_properties_u45(busdev);
+		}
+
 		/* E450 SUNW,envctrl */
 		if (!strcmp(machine_model, "SUNW,Ultra-4"))
 			add_i2c_props_e450(busdev, busnode);
@@ -389,12 +443,25 @@
 				prop_dictionary_set_uint8(props,
 				    "fan_mask", 0x08);
 		}
+
+		/* Sun use offsets from 2000 but range 1970 to 2069 */
+		if (device_is_a(dev, "dsrtc")) {
+			prop_dictionary_t props = device_properties(dev);
+			prop_dictionary_set_uint(props, "start-year", 2000);
+		}
+	}
+
+	if (!strcmp(machine_model, "SUNW,A70")) {
+		if (device_is_a(dev, "adt7462sm")){
+			/* U45 has 5 measured fans */
+			prop_dictionary_t props = device_properties(dev);
+			prop_dictionary_set_uint8(props, "fan_conf", 0x1f);
+		}
 	}
 
 	if (!strcmp(machine_model, "SUNW,Ultra-250"))
 		if (device_is_a(dev, "pcf8574io"))
 			add_gpio_props_e250(dev, aux);
-
 }
 
 /* Static EDID definitions */
--- src/sys/dev/i2c/adt7462.c.dist	2026-02-10 22:19:38.439986424 +0100
+++ src/sys/dev/i2c/adt7462.c	2026-02-16 16:03:48.469999864 +0100
@@ -0,0 +1,1083 @@
+/* $NetBSD$ */
+
+/*-
+ * Copyright (c) 2026 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Julian Coleman.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__KERNEL_RCSID(0, "$NetBSD$");
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/device.h>
+#include <sys/kernel.h>
+#include <sys/sysctl.h>
+
+#include <dev/sysmon/sysmonvar.h>
+
+#include <dev/i2c/i2cvar.h>
+#include <dev/i2c/adt7462reg.h>
+
+/* Temperature sensors descriptions */
+static const char* temp_names[] =
+    { "local", "remote 1", "remote 2", "remote 3" };
+
+#define ADT7462_DESC_LEN	16
+/* Voltage/analog sensors registers */
+struct adt7462_volts_regs {
+	uint8_t v_reg, h_reg, l_reg;
+};
+static struct adt7462_volts_regs adt7462_volts_table[] = {
+	{ ADT7462_PIN23V_VAL, ADT7462_PIN23V_HIGH, ADT7462_PIN23V_LOW },
+	{ ADT7462_PIN24V_VAL, ADT7462_PIN24V_HIGH, ADT7462_PIN24V_LOW },
+	{ ADT7462_PIN25V_VAL, ADT7462_PIN25V_HIGH, ADT7462_PIN25V_LOW },
+	{ ADT7462_PIN26V_VAL, ADT7462_PIN26V_HIGH, ADT7462_PIN26V_LOW },
+	{ ADT7462_15V1_VAL, ADT7462_15V1_HIGH, ADT7462_15V1_LOW }, /* Pin 28 */
+	{ ADT7462_15V2_VAL, ADT7462_15V2_HIGH, ADT7462_15V2_LOW }, /* Pin 29 */
+	{ ADT7462_33V_VAL, ADT7462_33V_HIGH, ADT7462_33V_LOW }, /* Pin 13 */
+	{ ADT7462_12V1_VAL, ADT7462_12V1_HIGH, ADT7462_12V1_LOW }, /* Pin 7 */
+	{ ADT7462_12V2_VAL, ADT7462_12V2_HIGH, ADT7462_12V2_LOW }, /* Pin 8 */
+	{ ADT7462_12V3_VAL, ADT7462_12V3_HIGH, ADT7462_12V3_LOW }, /* Pin 22 */
+	{ ADT7462_PIN19V_VAL, ADT7462_PIN19V_HIGH, ADT7462_PIN19V_LOW },
+	{ ADT7462_PIN15V_VAL, ADT7462_PIN15V_HIGH, ADT7462_PIN15V_LOW },
+	{ ADT7462_5V_VAL, ADT7462_5V_HIGH, ADT7462_5V_LOW }, /* Pin 21 */
+};
+
+/* 1 LSB values for voltages (datasheet table 16) in mV */
+#define ADT7462_SCALE_12V	62500
+#define ADT7462_SCALE_5V	26000
+#define ADT7462_SCALE_VCCP	6250
+#define ADT7462_SCALE_VVID	12500	/* Vccp when VID's enabled */
+#define ADT7462_SCALE_3_3V	17200
+#define ADT7462_SCALE_VBAT	15600
+#define ADT7462_SCALE_2_5V	13000
+#define ADT7462_SCALE_1_8V	9400
+#define ADT7462_SCALE_1_5V	7800
+#define ADT7462_SCALE_1_25V	6500
+#define ADT7462_SCALE_1_2V	6250
+#define ADT7462_SCALE_0_9V	4690
+
+/* Maximum number of each type of sensor */
+#define ADT7462_MAX_FANS	8
+#define ADT7462_MAX_TEMPS	4
+#define ADT7462_MAX_VOLTS	13
+#define ADT7462_MAX_FAULTS	1
+#define ADT7462_MAX_SENSORS	\
+    (ADT7462_MAX_FANS + ADT7462_MAX_TEMPS + \
+    ADT7462_MAX_VOLTS + ADT7462_MAX_FAULTS)
+
+/* Fan/temp/volt/fault sensor offsets */
+#define ADT7462_FAN_NUM(x)	(x)
+#define ADT7462_TEMP_NUM(x)	(x + ADT7462_MAX_FANS)
+#define ADT7462_VOLT_NUM(x)	(x + ADT7462_MAX_FANS + ADT7462_MAX_TEMPS)
+#define ADT7462_FAULT_NUM(x)	\
+    (x + ADT7462_MAX_FANS + ADT7462_MAX_TEMPS + ADT7462_MAX_VOLTS)
+
+/* Fan conversions */
+#define VAL_TO_SPEED(msb, lsb)  \
+    (ADT7462_TACH_PERIOD / ((msb << 8) + lsb))
+#define SPEED_TO_MSB(spd)       \
+    (((ADT7462_TACH_PERIOD / spd) >> 8) & 0xff)
+
+/* Temperature conversions */
+#define VAL_TO_TEMP(msb, lsb)	\
+    (ADT7462_TEMP_BASE + msb * 1000000 + (lsb >> 6) * 250000)
+#define TEMP_TO_MSB(temp)	\
+    (((temp - ADT7462_TEMP_BASE) / 1000000) & 0xff)
+
+/* Voltage conversions */
+#define VAL_TO_VOLT(val, scale)	\
+    (val * scale)
+#define VOLT_TO_MSB(volt, scale)	\
+    ((volt / scale) & 0xff)
+
+struct adt7462_softc {
+	device_t sc_dev;
+	i2c_tag_t sc_tag;
+	int sc_address;
+	bool sc_monitor;
+
+	int sc_nfans, sc_ntemps, sc_nvolts;
+	int sc_crit_therm[ADT7462_MAX_TEMPS];
+	int sc_map[ADT7462_MAX_SENSORS];  /* Map sysmon numbers to sensors */
+	int sc_vscale[ADT7462_MAX_VOLTS];  /* Scale for voltages */
+	struct sysmon_envsys *sc_sme;
+	envsys_data_t sc_sensor[ADT7462_MAX_SENSORS];
+	uint8_t sc_therm1[ADT7462_MAX_TEMPS], sc_therm2[ADT7462_MAX_TEMPS];
+	uint8_t sc_highlim[ADT7462_MAX_SENSORS];
+	uint8_t sc_lowlim[ADT7462_MAX_SENSORS];
+};
+
+static int adt7462_match(device_t, cfdata_t, void *);
+static int adt7462_ident(i2c_tag_t, i2c_addr_t, int, uint8_t*);
+static void adt7462_attach(device_t, device_t, void *);
+static int adt7462_detach(device_t, int);
+bool adt7462_pmf_suspend(device_t, const pmf_qual_t *);
+bool adt7462_pmf_resume(device_t, const pmf_qual_t *);
+
+static int adt7462_start_monitor(struct adt7462_softc *, int);
+static int adt7462_stop_monitor(struct adt7462_softc *);
+static int adt7462_setup_fans(struct adt7462_softc *, uint8_t *, uint8_t);
+static int adt7462_setup_temps(struct adt7462_softc *, uint8_t *);
+static int adt7462_setup_volts(struct adt7462_softc *, uint8_t *);
+static int adt7462_setup_faults(struct adt7462_softc *);
+
+void adt7462_refresh(struct sysmon_envsys *, envsys_data_t *);
+static void adt7462_read_fan_val(struct adt7462_softc *, envsys_data_t *);
+static void adt7462_read_temp_val(struct adt7462_softc *, envsys_data_t *);
+static void adt7462_read_volt_val(struct adt7462_softc *, envsys_data_t *);
+static void adt7462_read_fault_val(struct adt7462_softc *, envsys_data_t *);
+
+void adt7462_get_limits(struct sysmon_envsys *, envsys_data_t *,
+    sysmon_envsys_lim_t *, uint32_t *);
+void adt7462_set_limits(struct sysmon_envsys *, envsys_data_t *,
+    sysmon_envsys_lim_t *, uint32_t *);
+static void adt7462_get_fan_limits(struct adt7462_softc *,
+    envsys_data_t *, sysmon_envsys_lim_t *, uint32_t *);
+static void adt7462_get_temp_limits(struct adt7462_softc *,
+    envsys_data_t *, sysmon_envsys_lim_t *, uint32_t *);
+static void adt7462_get_volt_limits(struct adt7462_softc *,
+    envsys_data_t *, sysmon_envsys_lim_t *, uint32_t *);
+static void adt7462_set_fan_limits(struct adt7462_softc *,
+    envsys_data_t *, sysmon_envsys_lim_t *, uint32_t *);
+static void adt7462_set_temp_limits(struct adt7462_softc *,
+    envsys_data_t *, sysmon_envsys_lim_t *, uint32_t *);
+static void adt7462_set_volt_limits(struct adt7462_softc *,
+    envsys_data_t *, sysmon_envsys_lim_t *, uint32_t *);
+
+static int adt7462_read_reg_int(i2c_tag_t, i2c_addr_t, uint8_t, uint8_t *);
+static int adt7462_write_reg(struct adt7462_softc *, uint8_t, uint8_t);
+
+static inline int
+adt7462_read_reg(struct adt7462_softc *sc, uint8_t reg, uint8_t *val)
+{
+	return adt7462_read_reg_int(sc->sc_tag, sc->sc_address, reg, val);
+}
+
+CFATTACH_DECL_NEW(adt7462sm, sizeof(struct adt7462_softc),
+	adt7462_match, adt7462_attach, adt7462_detach, NULL);
+
+static const struct device_compatible_entry compat_data[] = {
+	{ .compat = "i2c-adt7462" },
+	DEVICE_COMPAT_EOL
+};
+
+static int
+adt7462_match(device_t parent, cfdata_t cf, void *aux)
+{
+	struct i2c_attach_args *ia = aux;
+	int match_result;
+	uint8_t rev;
+
+	if (iic_use_direct_match(ia, cf, compat_data, &match_result))
+		return match_result;
+
+	if ((ia->ia_addr == ADT7462_ADDR1 || ia->ia_addr == ADT7462_ADDR2)
+	    && adt7462_ident(ia->ia_tag, ia->ia_addr, 1, &rev))
+		return I2C_MATCH_ADDRESS_AND_PROBE;
+
+	return 0;
+}
+
+static int
+adt7462_ident(i2c_tag_t tag, i2c_addr_t addr, int probe_only, uint8_t *rev)
+{
+	uint8_t reg, val;
+	int err;
+
+	/* Device, company and revision ID */
+	reg = ADT7462_DEV_ID;
+	err = adt7462_read_reg_int(tag, addr, reg, &val);
+	if (err || val != ADT7462_DEV_ID_VAL) {
+		if (!probe_only)
+			aprint_verbose("adt7462_ident: "
+			    "device ID invalid or missing\n");
+		return 0;
+	}
+	reg = ADT7462_COMP_ID;
+	err = adt7462_read_reg_int(tag, addr, reg, &val);
+	if (err || val != ADT7462_COMP_ID_VAL) {
+		if (!probe_only)
+			aprint_verbose("adt7462_ident: "
+			    "company ID invalid or missing\n");
+		return 0;
+	}
+	reg = ADT7462_REV_ID;
+	err = adt7462_read_reg_int(tag, addr, reg, rev);
+	if (err || *rev != ADT7462_REV_ID_VAL) {
+		if (!probe_only)
+			aprint_verbose("adt7462_ident: "
+			    "revision invalid or missing\n");
+		return 0;
+	}
+	return 1;
+}
+
+static void
+adt7462_attach(device_t parent, device_t self, void *aux)
+{
+	struct adt7462_softc *sc = device_private(self);
+	struct i2c_attach_args *ia = aux;
+	prop_dictionary_t props = device_properties(self);
+	uint8_t reg, rev, val, fan_conf, pin_cfg[4];
+
+	sc->sc_tag = ia->ia_tag;
+	sc->sc_address = ia->ia_addr;
+	sc->sc_dev = self;
+
+	/* Property override for the number of fans */
+	if (prop_dictionary_get_uint8(props, "fan_conf", &fan_conf) == 0)
+		fan_conf = 0xff;	/* 4 + 4 fans */
+
+	(void) adt7462_ident(sc->sc_tag, sc->sc_address, 0, &rev);
+	aprint_normal(": ADT7462 system monitor: rev. 0x%x\n", rev);
+
+	if (adt7462_start_monitor(sc, 1))
+		return;
+
+	/* Read the pin config registers for fan/temp/volt setup. */
+	reg = ADT7462_PIN_CONF1;
+	if (adt7462_read_reg(sc, reg, &val) != 0) {
+		aprint_error_dev(sc->sc_dev, ": unable to read pin conf1\n");
+		return;
+	}
+	pin_cfg[0] = val;
+	reg = ADT7462_PIN_CONF2;
+	if (adt7462_read_reg(sc, reg, &val) != 0) {
+		aprint_error_dev(sc->sc_dev, ": unable to read pin conf2\n");
+		return;
+	}
+	pin_cfg[1] = val;
+	reg = ADT7462_PIN_CONF3;
+	if (adt7462_read_reg(sc, reg, &val) != 0) {
+		aprint_error_dev(sc->sc_dev, ": unable to read pin conf3\n");
+		return;
+	}
+	pin_cfg[2] = val;
+	reg = ADT7462_PIN_CONF4;
+	if (adt7462_read_reg(sc, reg, &val) != 0) {
+		aprint_error_dev(sc->sc_dev, ": unable to read pin conf4\n");
+		return;
+	}
+	pin_cfg[3] = val;
+
+	sc->sc_sme = sysmon_envsys_create();
+
+	sc->sc_nfans = 0;
+	sc->sc_ntemps = 0;
+	sc->sc_nvolts = 0;
+	if (adt7462_setup_fans(sc, pin_cfg, fan_conf))
+		goto bad;
+	if (adt7462_setup_temps(sc, pin_cfg))
+		goto bad;
+	if (adt7462_setup_volts(sc, pin_cfg))
+		goto bad;
+	if (adt7462_setup_faults(sc))
+		goto bad;
+	aprint_normal_dev(self, "%d fans, %d temperatures, %d voltages\n",
+	    sc->sc_nfans, sc->sc_ntemps, sc->sc_nvolts);
+
+        sc->sc_sme->sme_name = device_xname(self);
+        sc->sc_sme->sme_cookie = sc;
+        sc->sc_sme->sme_refresh = adt7462_refresh;
+	sc->sc_sme->sme_get_limits = adt7462_get_limits;
+	sc->sc_sme->sme_set_limits = adt7462_set_limits;
+	if (sysmon_envsys_register(sc->sc_sme)) {
+		aprint_error_dev(self,
+		    "unable to register with sysmon\n");
+		goto bad;
+	}
+
+	if (!pmf_device_register(self, adt7462_pmf_suspend, adt7462_pmf_resume))
+		aprint_error_dev(self, "couldn't establish power handler\n");
+
+	return;
+
+bad:
+	sysmon_envsys_destroy(sc->sc_sme);
+	sc->sc_sme = NULL;
+	return;
+}
+
+/* Stop (suspend/detach) and restart (resume) monitoring, if we started it. */
+bool
+adt7462_pmf_suspend(device_t dev, const pmf_qual_t *qual)
+{
+	struct adt7462_softc *sc = device_private(dev);
+
+	if (sc->sc_monitor == 1) {
+ 		if (adt7462_stop_monitor(sc))
+ 			return false;
+ 	}
+ 	return true;
+}
+
+bool
+adt7462_pmf_resume(device_t dev, const pmf_qual_t *qual)
+{
+	struct adt7462_softc *sc = device_private(dev);
+
+	if (sc->sc_monitor == 1) {
+ 		if (adt7462_start_monitor(sc, 0))
+ 			return false;
+ 	}
+ 	return true;
+}
+
+static int
+adt7462_detach(device_t self, int flags)
+{
+	struct adt7462_softc *sc = device_private(self);
+
+	pmf_device_deregister(self);
+
+	if (sc->sc_sme != NULL)
+		sysmon_envsys_unregister(sc->sc_sme);
+
+	if (sc->sc_monitor == 1) {
+ 		if (adt7462_stop_monitor(sc))
+ 			return 1;
+ 	}
+	return 0;
+}
+
+static int
+adt7462_start_monitor(struct adt7462_softc *sc, int print)
+{
+	uint8_t reg, val;
+
+	/*
+	 * Start monitoring if not already monitoring.
+	 * Wait 1.0s for the fan readings to stabilise.
+	 */
+	reg = ADT7462_CONF1;
+	if (adt7462_read_reg(sc, reg, &val) != 0) {
+		aprint_error_dev(sc->sc_dev, ": unable to read conf1\n");
+		return 1;
+	}
+	if (!(val & ADT7462_CONF1_MONITOR)) {
+		sc->sc_monitor = 1;
+		val |= ADT7462_CONF1_MONITOR;
+		if (adt7462_write_reg(sc, reg, val) != 0) {
+			aprint_error_dev(sc->sc_dev,
+			    ": unable to write conf1\n");
+			return 1;
+		}
+		if (print)
+			aprint_normal_dev(sc->sc_dev,
+			    ": starting monitoring, "
+			    "waiting 1.0s for readings\n");
+		delay(1000000);
+	} else
+		sc->sc_monitor = 0;
+	return 0;
+}
+
+static int
+adt7462_stop_monitor(struct adt7462_softc *sc)
+{
+	uint8_t reg, val;
+
+	reg = ADT7462_CONF1;
+	if (adt7462_read_reg(sc, reg, &val) != 0) {
+		aprint_error_dev(sc->sc_dev, ": unable to read conf1\n");
+		return 1;
+	}
+
+	val &= ~ADT7462_CONF1_MONITOR;
+	if (adt7462_write_reg(sc, reg, val) != 0) {
+		aprint_error_dev(sc->sc_dev, ": unable to write conf1\n");
+		return 1;
+	}
+	return 0;
+}
+
+static int
+adt7462_setup_fans(struct adt7462_softc *sc, uint8_t *pin_cfg,
+    uint8_t fan_conf)
+{
+	int i, map, snum;
+	uint8_t reg, val, fans;
+
+	/* Check tach enable register to see which tachs are enabled. */
+	reg = ADT7462_TACH_EN;
+	if (adt7462_read_reg(sc, reg, &val) != 0) {
+		aprint_error_dev(sc->sc_dev, "unable to read tach enable\n");
+		return 1;
+	}
+	fans = val & fan_conf;
+
+	/* Don't check the fan present register - it might not be set up. */
+
+	for (i = 0; i < ADT7462_MAX_FANS; i++) {
+		/* Check tach mask and pin1/pin2 configurations. */
+		if (!ADT7462_FAN_TACH_EN(fans, i) ||
+		    !ADT7462_PCR1_TACH(pin_cfg[0], i) ||
+		    !ADT7462_PCR2_TACH(pin_cfg[1], i))
+			continue;
+
+		snum = ADT7462_FAN_NUM(i);
+
+		/* Store initial limit */
+ 		reg = ADT7462_TACH_LIMIT(i);
+		if (adt7462_read_reg(sc, reg, &val) != 0) {
+			aprint_error_dev(sc->sc_dev,
+			    "unable to read fan %d limit\n", i);
+			return 1;
+		}
+		sc->sc_highlim[snum] = val;
+
+		/* Set up sysmon sensor */
+		sc->sc_sensor[snum].units = ENVSYS_SFANRPM;
+		sc->sc_sensor[snum].state = ENVSYS_SINVALID;
+		sc->sc_sensor[snum].flags = ENVSYS_FMONLIMITS;
+		snprintf(sc->sc_sensor[snum].desc,
+		    sizeof(sc->sc_sensor[snum].desc), "fan %d", snum);
+		if (sysmon_envsys_sensor_attach(
+		    sc->sc_sme, &sc->sc_sensor[snum])) {
+			aprint_error_dev(sc->sc_dev,
+			    "unable to attach fan %d at sysmon\n", i);
+			return 1;
+		}
+		map = sc->sc_sensor[snum].sensor;
+		sc->sc_map[map] = i;
+		sc->sc_nfans++;
+	}
+	return 0;
+}
+
+static int
+adt7462_setup_temps(struct adt7462_softc *sc, uint8_t *pin_cfg)
+{
+	int i, map, snum;
+	uint8_t reg, val, val2;
+
+	for (i = 0; i < ADT7462_MAX_TEMPS; i++) {
+		/* Check pin1 configurations. */
+		if (!ADT7462_PCR1_TEMP(pin_cfg[0], i))
+			continue;
+
+		snum = ADT7462_TEMP_NUM(i);
+
+		/* Store initial limits */
+ 		reg = ADT7462_TEMP_THERM1(i);
+		if (adt7462_read_reg(sc, reg, &val) != 0) {
+			aprint_error_dev(sc->sc_dev,
+			    "unable to read temp %d therm1 limit\n", i);
+			return 1;
+		}
+		sc->sc_therm1[i] = val;
+ 		reg = ADT7462_TEMP_THERM2(i);
+		if (adt7462_read_reg(sc, reg, &val2) != 0) {
+			aprint_error_dev(sc->sc_dev,
+			    "unable to read temp %d therm2 limit\n", i);
+			return 1;
+		}
+		sc->sc_therm2[i] = val2;
+		/* Store lowest therm value as critmax. */
+		if (val < val2)
+
+			sc->sc_crit_therm[i] = 1;
+		else
+
+			sc->sc_crit_therm[i] = 2;
+
+ 		reg = ADT7462_TEMP_HIGH(i);
+		if (adt7462_read_reg(sc, reg, &val) != 0) {
+			aprint_error_dev(sc->sc_dev,
+			    "unable to read temp %d high limit\n", i);
+			return 1;
+		}
+		sc->sc_highlim[snum] = val;
+
+ 		reg = ADT7462_TEMP_LOW(i);
+		if (adt7462_read_reg(sc, reg, &val) != 0) {
+			aprint_error_dev(sc->sc_dev,
+			    "unable to read temp %d low limit\n", i);
+			return 1;
+		}
+		sc->sc_lowlim[snum] = val;
+
+		/* Set up sysmon sensor */
+		strlcpy(sc->sc_sensor[snum].desc, temp_names[i],
+			sizeof(sc->sc_sensor[snum].desc));
+
+		sc->sc_sensor[snum].units = ENVSYS_STEMP;
+		sc->sc_sensor[snum].state = ENVSYS_SINVALID;
+		sc->sc_sensor[snum].flags =
+ 		    ENVSYS_FMONLIMITS | ENVSYS_FHAS_ENTROPY;
+		if (sysmon_envsys_sensor_attach(
+		    sc->sc_sme, &sc->sc_sensor[snum])) {
+			aprint_error_dev(sc->sc_dev,
+			    "unable to attach temp %d at sysmon\n", i);
+			return 1;
+		}
+		map = sc->sc_sensor[snum].sensor;
+		sc->sc_map[map] = i;
+		sc->sc_ntemps++;
+	}
+	return 0;
+}
+
+static int
+adt7462_setup_volts(struct adt7462_softc *sc, uint8_t *pin_cfg)
+{
+	int i, map, snum;
+	uint8_t reg, val;
+	char desc[ADT7462_DESC_LEN];
+
+	for (i = 0; i < ADT7462_MAX_VOLTS; i++) {
+		snum = ADT7462_VOLT_NUM(i);
+
+		/* Invidual configuration for each sensor */
+		switch (i) {
+		case 0:		/* Pin 23 (always measures volts) */
+			if (ADT7462_PCR2_P23_25V(pin_cfg[1])) {
+				strcpy(desc, "V2.5 1");
+				sc->sc_vscale[i] = ADT7462_SCALE_2_5V;
+			} else if (ADT7462_PCR2_P23_18V(pin_cfg[1])) {
+				strcpy(desc, "V1.8 1");
+				sc->sc_vscale[i] = ADT7462_SCALE_1_8V;
+			} else if (ADT7462_PCR2_P23_15V(pin_cfg[1])) {
+				strcpy(desc, "V1.5 1");
+				sc->sc_vscale[i] = ADT7462_SCALE_1_5V;
+			} else {
+				strcpy(desc, "Vccp 1");
+				if (ADT7462_PCR1_VIDS(pin_cfg[0]))
+					sc->sc_vscale[i] = ADT7462_SCALE_VVID;
+				else
+					sc->sc_vscale[i] = ADT7462_SCALE_VCCP;
+			}
+			break;
+		case 1:		/* Pin 24 (always measures volts) */
+			if (ADT7462_PCR3_P24_25V(pin_cfg[2])) {
+				strcpy(desc, "V2.5 2");
+				sc->sc_vscale[i] = ADT7462_SCALE_2_5V;
+			} else if (ADT7462_PCR3_P24_18V(pin_cfg[2])) {
+				strcpy(desc, "V1.8 2");
+				sc->sc_vscale[i] = ADT7462_SCALE_1_8V;
+			} else if (ADT7462_PCR3_P24_15V(pin_cfg[2])) {
+				strcpy(desc, "V1.5 2");
+				sc->sc_vscale[i] = ADT7462_SCALE_1_5V;
+			} else {
+				strcpy(desc, "Vccp 2");
+				if (ADT7462_PCR1_VIDS(pin_cfg[0]))
+					sc->sc_vscale[i] = ADT7462_SCALE_VVID;
+				else
+					sc->sc_vscale[i] = ADT7462_SCALE_VCCP;
+			}
+			break;
+		case 2:		/* Pin 25 (check pin config 3) */
+			if (ADT7462_PCR3_P25_33V(pin_cfg[2])) {
+				strcpy(desc, "V3.3 1");
+				sc->sc_vscale[i] = ADT7462_SCALE_3_3V;
+			} else if (ADT7462_PCR3_P25_12V(pin_cfg[2])) {
+				strcpy(desc, "V1.2 1");
+				sc->sc_vscale[i] = ADT7462_SCALE_1_2V;
+			} else
+				continue;	/* Not voltage */
+			break;
+		case 3:		/* Pin 26 (check pin config 3) */
+			if (ADT7462_PCR3_P26_VBAT(pin_cfg[2])) {
+				strcpy(desc, "Vbatt");
+				sc->sc_vscale[i] = ADT7462_SCALE_VBAT;
+			} else if (ADT7462_PCR3_P26_12V(pin_cfg[2])) {
+				strcpy(desc, "V1.2 2");
+				sc->sc_vscale[i] = ADT7462_SCALE_1_2V;
+			} else
+				continue;	/* Not voltage */
+			break;
+		case 4:		/* Pin 28 (check pin config 1 and 4) */
+			if (ADT7462_PCR1_VIDS(pin_cfg[0]))
+				continue;
+			if (!ADT7462_PCR4_P28_15V(pin_cfg[3]))
+				continue;
+			strcpy(desc, "V1.5 1");
+			sc->sc_vscale[i] = ADT7462_SCALE_1_5V;
+			break;
+		case 5:		/* Pin 29 (check pin config 1 and 4) */
+			if (ADT7462_PCR1_VIDS(pin_cfg[0]))
+				continue;
+			if (!ADT7462_PCR4_P29_15V(pin_cfg[3]))
+				continue;
+			strcpy(desc, "V1.5 2");
+			sc->sc_vscale[i] = ADT7462_SCALE_1_5V;
+			break;
+		case 6:		/* Pin 13 (check pin config 2) */
+			if (ADT7462_PCR2_P13_PWM4(pin_cfg[1]))
+				continue;
+			strcpy(desc, "V3.3 2");
+			sc->sc_vscale[i] = ADT7462_SCALE_3_3V;
+			break;
+		case 7:		/* Pin 7 (check pin config 1) */
+			if (!ADT7462_PCR1_PIN7_V(pin_cfg[0]))
+				continue;
+			strcpy(desc, "V12 1");
+			sc->sc_vscale[i] = ADT7462_SCALE_12V;
+			break;
+		case 8:		/* Pin 8 (check pin config 2) */
+			if (ADT7462_PCR2_P8_TACH6(pin_cfg[1]))
+				continue;
+			strcpy(desc, "V12 2");
+			sc->sc_vscale[i] = ADT7462_SCALE_12V;
+			break;
+		case 9:		/* Pin 22 (check pin config 2) */
+			if (ADT7462_PCR2_P22_TACH8(pin_cfg[1]))
+				continue;
+			strcpy(desc, "V12 3");
+			sc->sc_vscale[i] = ADT7462_SCALE_12V;
+			break;
+		case 10:	/* Pin 19 (check pin config 1 and 2) */
+			if (!ADT7462_PCR1_PIN19_V(pin_cfg[0]))
+				continue;
+			if (ADT7462_PCR2_P19_09V(pin_cfg[1])) {
+				strcpy(desc, "V0.9 1");
+				sc->sc_vscale[i] = ADT7462_SCALE_0_9V;
+			} else {
+				strcpy(desc, "V1.25 1");
+				sc->sc_vscale[i] = ADT7462_SCALE_1_25V;
+			}
+			break;
+		case 11:	/* Pin 15 (check pin config 1 and 2) */
+			if (!ADT7462_PCR1_PIN15_V(pin_cfg[0]))
+				continue;
+			if (ADT7462_PCR2_P15_18V(pin_cfg[1])) {
+				strcpy(desc, "V1.8 1");
+				sc->sc_vscale[i] = ADT7462_SCALE_1_8V;
+			} else {
+				strcpy(desc, "V2.5 3");
+				sc->sc_vscale[i] = ADT7462_SCALE_2_5V;
+			}
+			break;
+		case 12:	/* Pin 21 (check pin config 2) */
+			if (ADT7462_PCR2_P21_TACH7(pin_cfg[1]))
+				continue;
+			strcpy(desc, "V5 3");
+			sc->sc_vscale[i] = ADT7462_SCALE_5V;
+			break;
+		}
+
+		/* Store initial limits */
+ 		reg = adt7462_volts_table[i].h_reg;
+		if (adt7462_read_reg(sc, reg, &val) != 0) {
+			aprint_error_dev(sc->sc_dev,
+			    "unable to read temp %d high limit\n", i);
+			return 1;
+		}
+		sc->sc_highlim[snum] = val;
+
+ 		reg = adt7462_volts_table[i].l_reg;
+		if (adt7462_read_reg(sc, reg, &val) != 0) {
+			aprint_error_dev(sc->sc_dev,
+			    "unable to read temp %d low limit\n", i);
+			return 1;
+		}
+		sc->sc_lowlim[snum] = val;
+
+		/* Set up sysmon sensor */
+		sc->sc_sensor[snum].units = ENVSYS_SVOLTS_DC;
+		sc->sc_sensor[snum].state = ENVSYS_SINVALID;
+		sc->sc_sensor[snum].flags = ENVSYS_FMONLIMITS;
+		strlcpy(sc->sc_sensor[snum].desc, desc,
+		    sizeof(sc->sc_sensor[snum].desc));
+		if (sysmon_envsys_sensor_attach(
+		    sc->sc_sme, &sc->sc_sensor[snum])) {
+			aprint_error_dev(sc->sc_dev,
+			    "unable to attach volts %d at sysmon\n", i);
+			return 1;
+		}
+		map = sc->sc_sensor[snum].sensor;
+		sc->sc_map[map] = i;
+		sc->sc_nvolts++;
+	}
+	return 0;
+}
+
+static int
+adt7462_setup_faults(struct adt7462_softc *sc)
+{
+	int map, snum;
+
+	snum = ADT7462_FAULT_NUM(0);
+
+	/* Set up sysmon sensor */
+	strlcpy(sc->sc_sensor[snum].desc, "fan fault",
+	    sizeof(sc->sc_sensor[snum].desc));
+	sc->sc_sensor[snum].units = ENVSYS_INTEGER;
+	sc->sc_sensor[snum].state = ENVSYS_SINVALID;
+	sc->sc_sensor[snum].flags = ENVSYS_FMONCRITICAL;
+	if (sysmon_envsys_sensor_attach(
+	    sc->sc_sme, &sc->sc_sensor[snum])) {
+		aprint_error_dev(sc->sc_dev,
+		    "unable to attach fan fault at sysmon\n");
+		return 1;
+	}
+	map = sc->sc_sensor[snum].sensor;
+	sc->sc_map[map] = 0;
+	return 0;
+}
+
+void
+adt7462_refresh(struct sysmon_envsys *sme, envsys_data_t *edata)
+{
+	struct adt7462_softc *sc = sme->sme_cookie;
+
+	if (edata->sensor < sc->sc_nfans)
+		adt7462_read_fan_val(sc, edata);
+	else if (edata->sensor < sc->sc_nfans + sc->sc_ntemps)
+		adt7462_read_temp_val(sc, edata);
+	else if (edata->sensor < sc->sc_nfans + sc->sc_ntemps + sc->sc_nvolts)
+		adt7462_read_volt_val(sc, edata);
+	else
+		adt7462_read_fault_val(sc, edata);
+}
+
+static void
+adt7462_read_fan_val(struct adt7462_softc *sc, envsys_data_t *edata)
+{
+	int fan = sc->sc_map[edata->sensor];
+	uint8_t	reg, lsb, msb;
+
+	/* Read LSB then MSB to ensure correct reading */
+	reg = ADT7462_TACH_VAL_LSB(fan);
+	if (adt7462_read_reg(sc, reg, &lsb) != 0) {
+		edata->state = ENVSYS_SINVALID;
+		return;
+	}
+	reg += 1;	/* MSB register is always LSB register + 1 */
+	if (adt7462_read_reg(sc, reg, &msb) != 0) {
+		edata->state = ENVSYS_SINVALID;
+		return;
+	}
+	if ((msb == 0xff && lsb == 0xff) || (msb == 0x00 && lsb == 0x00))
+		/* Fan missing or stopped */
+		edata->value_cur = 0;
+	else
+		edata->value_cur = VAL_TO_SPEED(msb, lsb);
+	edata->state = ENVSYS_SVALID;
+}
+
+static void
+adt7462_read_temp_val(struct adt7462_softc *sc, envsys_data_t *edata)
+{
+	int temp = sc->sc_map[edata->sensor];
+	uint8_t	reg, lsb, msb;
+
+	/* Read LSB then MSB to ensure correct reading */
+	reg = ADT7462_TEMP_LSB(temp);
+	if (adt7462_read_reg(sc, reg, &lsb) != 0) {
+		edata->state = ENVSYS_SINVALID;
+		return;
+	}
+	reg += 1;	/* MSB register is always LSB register + 1 */
+	if (adt7462_read_reg(sc, reg, &msb) != 0) {
+		edata->state = ENVSYS_SINVALID;
+		return;
+	}
+
+	edata->value_cur = VAL_TO_TEMP(msb, lsb);
+	edata->state = ENVSYS_SVALID;
+}
+
+static void
+adt7462_read_volt_val(struct adt7462_softc *sc, envsys_data_t *edata)
+{
+	int volt = sc->sc_map[edata->sensor];
+	uint8_t	reg, val;
+
+	reg = adt7462_volts_table[volt].v_reg;
+	if (adt7462_read_reg(sc, reg, &val) != 0) {
+		edata->state = ENVSYS_SINVALID;
+		return;
+	}
+	edata->value_cur = VAL_TO_VOLT(val, sc->sc_vscale[volt]);
+	edata->state = ENVSYS_SVALID;
+}
+
+static void
+adt7462_read_fault_val(struct adt7462_softc *sc, envsys_data_t *edata)
+{
+	uint8_t	reg, val;
+	int32_t which, total;
+	int i, j;
+
+	reg = ADT7462_FAN_STAT_H;
+	if (adt7462_read_reg(sc, reg, &val) != 0) {
+		edata->state = ENVSYS_SINVALID;
+		return;
+	}
+	/* Change our status based on zero or non-zero value */
+	if (val != 0)
+		edata->state = ENVSYS_SCRITICAL;
+	else
+		edata->state = ENVSYS_SVALID;
+	/* Create an 8-digit integer for fan positions (0 OK, 1 fault) */
+	total = 0;
+	for (i = 0; i < 8; i++)
+		if (val & (1 << i)) {
+			which = 1;
+			for (j = 0; j < i; j++)
+				which *= 10;
+			total += which;
+		}
+	if (total != edata->value_cur)
+		aprint_normal_dev(sc->sc_dev,
+		    "fan fault status change: %08d -> %08d\n",
+		    edata->value_cur, total);
+	edata->value_cur = total;
+}
+
+void
+adt7462_get_limits(struct sysmon_envsys *sme, envsys_data_t *edata,
+	sysmon_envsys_lim_t *limits, uint32_t *props)
+{
+	struct adt7462_softc *sc = sme->sme_cookie;
+
+	if (edata->sensor < sc->sc_nfans)
+		adt7462_get_fan_limits(sc, edata, limits, props);
+	else if (edata->sensor < sc->sc_nfans + sc->sc_ntemps)
+		adt7462_get_temp_limits(sc, edata, limits, props);
+	else if (edata->sensor < sc->sc_nfans + sc->sc_ntemps + sc->sc_nvolts)
+		adt7462_get_volt_limits(sc, edata, limits, props);
+	else
+printf("tried to get fault limit!\n");
+}
+
+static void
+adt7462_get_fan_limits(struct adt7462_softc *sc, envsys_data_t *edata,
+	sysmon_envsys_lim_t *limits, uint32_t *props)
+{
+	int fan = sc->sc_map[edata->sensor];
+	uint8_t	reg, val;
+
+	/* The chip measures intervals, so the limit is for low speed. */
+	*props &= ~PROP_WARNMIN;
+
+	reg = ADT7462_TACH_LIMIT(fan);
+	if (adt7462_read_reg(sc, reg, &val) != 0)
+		return;
+	if (val == 0x00)	/* No limit */
+		return;
+	limits->sel_warnmin = VAL_TO_SPEED(val, 0);
+	*props |= PROP_WARNMIN;
+}
+
+static void
+adt7462_get_temp_limits(struct adt7462_softc *sc, envsys_data_t *edata,
+	sysmon_envsys_lim_t *limits, uint32_t *props)
+{
+	int temp = sc->sc_map[edata->sensor];
+	uint8_t	reg, val;
+
+	*props &= ~(PROP_CRITMAX | PROP_WARNMAX | PROP_WARNMIN);
+
+	if (sc->sc_crit_therm[temp] == 1)
+		reg = ADT7462_TEMP_THERM1(temp);
+	else
+		reg = ADT7462_TEMP_THERM2(temp);
+	if (adt7462_read_reg(sc, reg, &val) != 0)
+		return;
+	limits->sel_critmax = VAL_TO_TEMP(val, 0);
+	*props |= PROP_CRITMAX;
+
+	reg = ADT7462_TEMP_HIGH(temp);
+	if (adt7462_read_reg(sc, reg, &val) != 0)
+		return;
+	limits->sel_warnmax = VAL_TO_TEMP(val, 0);
+	*props |= PROP_WARNMAX;
+
+	reg = ADT7462_TEMP_LOW(temp);
+	if (adt7462_read_reg(sc, reg, &val) != 0)
+		return;
+	limits->sel_warnmin = VAL_TO_TEMP(val, 0);
+	*props |= PROP_WARNMIN;
+}
+
+static void
+adt7462_get_volt_limits(struct adt7462_softc *sc, envsys_data_t *edata,
+	sysmon_envsys_lim_t *limits, uint32_t *props)
+{
+	int volt = sc->sc_map[edata->sensor];
+	uint8_t	reg, val;
+
+	*props &= ~(PROP_WARNMAX | PROP_WARNMIN);
+
+	reg = adt7462_volts_table[volt].h_reg;
+	if (adt7462_read_reg(sc, reg, &val) != 0)
+		return;
+	limits->sel_warnmax = VAL_TO_VOLT(val, sc->sc_vscale[volt]);
+	*props |= PROP_WARNMAX;
+
+	reg = adt7462_volts_table[volt].l_reg;
+	if (adt7462_read_reg(sc, reg, &val) != 0)
+		return;
+	limits->sel_warnmin = VAL_TO_VOLT(val, sc->sc_vscale[volt]);
+	*props |= PROP_WARNMIN;
+}
+
+void
+adt7462_set_limits(struct sysmon_envsys *sme, envsys_data_t *edata,
+	sysmon_envsys_lim_t *limits, uint32_t *props)
+{
+	struct adt7462_softc *sc = sme->sme_cookie;
+
+	if (edata->sensor < sc->sc_nfans)
+		adt7462_set_fan_limits(sc, edata, limits, props);
+	else if (edata->sensor < sc->sc_nfans + sc->sc_ntemps)
+		adt7462_set_temp_limits(sc, edata, limits, props);
+	else if (edata->sensor < sc->sc_nfans + sc->sc_ntemps + sc->sc_nvolts)
+		adt7462_set_volt_limits(sc, edata, limits, props);
+	else
+printf("tried to set fault limit!\n");
+}
+
+static void
+adt7462_set_fan_limits(struct adt7462_softc *sc, envsys_data_t *edata,
+	sysmon_envsys_lim_t *limits, uint32_t *props)
+{
+	int fan = sc->sc_map[edata->sensor];
+	uint8_t	reg, val;
+
+	if (*props & PROP_WARNMIN) {
+		if (limits == NULL)	/* Restore defaults */
+			val = sc->sc_highlim[fan];
+		else {
+			if (limits->sel_warnmin == 0)
+				val = 0xff;
+			else
+				val = SPEED_TO_MSB(limits->sel_warnmin);
+		}
+		reg = ADT7462_TACH_LIMIT(fan);
+		adt7462_write_reg(sc, reg, val);
+	}
+}
+
+static void
+adt7462_set_temp_limits(struct adt7462_softc *sc, envsys_data_t *edata,
+	sysmon_envsys_lim_t *limits, uint32_t *props)
+{
+	int temp = sc->sc_map[edata->sensor];
+	uint8_t	reg, val;
+
+	if (*props & PROP_CRITMAX) {
+		if (limits == NULL) {	/* Restore defaults */
+			if (sc->sc_crit_therm[temp] == 1)
+				val = sc->sc_therm1[temp];
+			else
+				val = sc->sc_therm2[temp];
+		} else {
+			val = TEMP_TO_MSB(limits->sel_critmax);
+		}
+		/* Don't change order of therm limits */
+		if (sc->sc_crit_therm[temp] == 1) {
+			reg = ADT7462_TEMP_THERM1(temp);
+			if (val > sc->sc_therm2[temp] - 1)
+				val = sc->sc_therm2[temp];
+		} else {
+			reg = ADT7462_TEMP_THERM2(temp);
+			if (val > sc->sc_therm1[temp] - 1)
+				val = sc->sc_therm1[temp];
+		}
+		adt7462_write_reg(sc, reg, val);
+	}
+
+	if (*props & PROP_WARNMAX) {
+		if (limits == NULL)	/* Restore defaults */
+			val = sc->sc_highlim[edata->sensor];
+		else {
+			val = TEMP_TO_MSB(limits->sel_warnmax);
+		}
+		reg = ADT7462_TEMP_HIGH(temp);
+		adt7462_write_reg(sc, reg, val);
+	}
+
+	if (*props & PROP_WARNMIN) {
+		if (limits == NULL)	/* Restore defaults */
+			val = sc->sc_lowlim[edata->sensor];
+		else {
+			val = TEMP_TO_MSB(limits->sel_warnmin);
+		}
+		reg = ADT7462_TEMP_LOW(temp);
+		adt7462_write_reg(sc, reg, val);
+	}
+}
+
+static void
+adt7462_set_volt_limits(struct adt7462_softc *sc, envsys_data_t *edata,
+	sysmon_envsys_lim_t *limits, uint32_t *props)
+{
+	int volt = sc->sc_map[edata->sensor];
+	uint8_t	reg, val;
+
+	if (*props & PROP_WARNMAX) {
+		if (limits == NULL)	/* Restore defaults */
+			val = sc->sc_highlim[edata->sensor];
+		else {
+			val = VOLT_TO_MSB(limits->sel_warnmax,
+			    sc->sc_vscale[volt]);
+		}
+		reg = adt7462_volts_table[volt].h_reg;
+		adt7462_write_reg(sc, reg, val);
+	}
+
+	if (*props & PROP_WARNMIN) {
+		if (limits == NULL)	/* Restore defaults */
+			val = sc->sc_lowlim[edata->sensor];
+		else {
+			val = VOLT_TO_MSB(limits->sel_warnmin,
+			    sc->sc_vscale[volt]);
+		}
+		reg = adt7462_volts_table[volt].l_reg;
+		adt7462_write_reg(sc, reg, val);
+	}
+}
+
+static int
+adt7462_read_reg_int(i2c_tag_t tag, i2c_addr_t addr, uint8_t reg, uint8_t *val)
+{
+	int err = 0;
+
+	if ((err = iic_acquire_bus(tag, 0)) != 0)
+		return err;
+	err = iic_exec(tag, I2C_OP_READ_WITH_STOP, addr, &reg, 1, val, 1, 0);
+	iic_release_bus(tag, 0);
+	return err;
+}
+
+static int
+adt7462_write_reg(struct adt7462_softc *sc, uint8_t reg, uint8_t val)
+{
+	int err = 0;
+
+	if ((err = iic_acquire_bus(sc->sc_tag, 0)) != 0)
+		return err;
+	err = iic_exec(sc->sc_tag, I2C_OP_WRITE_WITH_STOP, sc->sc_address,
+	    &reg, 1, &val, 1, 0);
+	iic_release_bus(sc->sc_tag, 0);
+	return err;
+}
--- src/sys/dev/i2c/adt7462reg.h.dist	2026-02-10 22:19:43.319986421 +0100
+++ src/sys/dev/i2c/adt7462reg.h	2026-02-16 13:12:05.549980255 +0100
@@ -0,0 +1,716 @@
+/* $NetBSD$ */
+
+/*-
+ * Copyright (c) 2026 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Julian Coleman.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _DEV_I2C_ADT7462REG_H_
+#define _DEV_I2C_ADT7462REG_H_
+
+/*
+ * Register definitions for "ADT7462 Flexible Temperature, Voltage Monitor,
+ * and System Fan Controller".
+ */
+
+#include <sys/cdefs.h>
+__KERNEL_RCSID(0, "$NetBSD$");
+
+#define ADT7462_ADDR1		0x58
+#define ADT7462_ADDR2		0x5c
+
+#define ADT7462_CONF0		0x00
+#define ADT7462_CONF1		0x01
+#define ADT7462_CONF2		0x02
+#define ADT7462_CONF3		0x03
+#define ADT7462_TACH_EN		0x07
+#define ADT7462_TACH_CFG	0x08
+#define ADT7462_GPIO1_CFG	0x09
+#define ADT7462_GPIO2_CFG	0x0a
+#define ADT7462_TMIN_CAL1	0x0b
+#define ADT7462_TMIN_CAL2	0x0c
+#define ADT7462_THERM_CONF	0x0d
+#define ADT7462_CONF_THERM1	0x0e
+#define ADT7462_CONF_THERM2	0x0f
+#define ADT7462_PIN_CONF1	0x10
+#define ADT7462_PIN_CONF2	0x11
+#define ADT7462_PIN_CONF3	0x12
+#define ADT7462_PIN_CONF4	0x13
+#define ADT7462_EASY_CONF	0x14
+#define ADT7462_EDO_ENABLE	0x16
+#define ADT7462_ATTEN1_EN	0x18
+#define ADT7462_ATTEN2_EN	0x19
+#define ADT7462_ACCOUSTICS1	0x1a
+#define ADT7462_ACCOUSTICS2	0x1b
+#define ADT7462_FAN_TEST	0x1c
+#define ADT7462_FANS_PRESENT	0x1d
+#define ADT7462_FAN_TEST_EN	0x1e
+#define ADT7462_PWM1_CFG	0x21
+#define ADT7462_PWM2_CFG	0x22
+#define ADT7462_PWM3_CFG	0x23
+#define ADT7462_PWM4_CFG	0x24
+#define ADT7462_PWM12_FREQ	0x25
+#define ADT7462_PWM34_FREQ	0x26
+#define ADT7462_PWM1_MIN	0x28	/* Minimum PWM1 duty cycle */
+#define ADT7462_PWM2_MIN	0x29	/* Minimum PWM2 duty cycle */
+#define ADT7462_PWM3_MIN	0x2a	/* Minimum PWM3 duty cycle */
+#define ADT7462_PWM4_MIN	0x2b	/* Minimum PWM4 duty cycle */
+#define ADT7462_PWM1234_MAX	0x2c	/* Maximum all PWM duty cycle */
+#define ADT7462_THERM_MASK1	0x30
+#define ADT7462_THERM_MASK2	0x31
+#define ADT7462_VOLT_MASK1	0x32
+#define ADT7462_VOLT_MASK2	0x33
+#define ADT7462_FAN_MASK	0x34
+#define ADT7462_DIG_MASK	0x35
+#define ADT7462_GPIO_MASK	0x36
+#define ADT7462_EDO_MASK1	0x37
+#define ADT7462_EDO_MASK2	0x38
+#define ADT7462_DEV_ID		0x3d
+#define ADT7462_COMP_ID		0x3e
+#define ADT7462_REV_ID		0x3f
+#define ADT7462_LOCAL_LOW	0x44
+#define ADT7462_REM1_LOW	0x45	/* Register contents depend on */
+#define ADT7462_PIN15V_LOW	0x45	/* pin configuration. */
+#define ADT7462_REM2_LOW	0x46
+#define ADT7462_REM3_LOW	0x47
+#define ADT7462_PIN19V_LOW	0x47
+#define ADT7462_LOCAL_HIGH	0x48
+#define ADT7462_REM1_HIGH	0x49
+#define ADT7462_PIN15V_HIGH	0x49
+#define ADT7462_REM2_HIGH	0x4a
+#define ADT7462_REM3_HIGH	0x4b
+#define ADT7462_PIN19V_HIGH	0x4b
+#define ADT7462_LOCAL_THERM1	0x4c
+#define ADT7462_15V2_HIGH	0x4c
+#define ADT7462_REM1_THERM1	0x4d
+#define ADT7462_REM2_THERM1	0x4e
+#define ADT7462_REM3_THERM1	0x4f
+#define ADT7462_LOCAL_THERM2	0x50
+#define ADT7462_15V1_HIGH	0x50
+#define ADT7462_REM1_THERM2	0x51
+#define ADT7462_REM2_THERM2	0x52
+#define ADT7462_REM3_THERM2	0x53
+#define ADT7462_LOCREM1_HYST	0x54
+#define ADT7462_REM23_HYST	0x55
+#define ADT7462_LOCAL_OFF	0x56
+#define ADT7462_REM1_OFF	0x57
+#define ADT7462_REM2_OFF	0x58
+#define ADT7462_REM3_OFF	0x59
+#define ADT7462_REM1_OPP	0x5a
+#define ADT7462_REM2_OPP	0x5b
+#define ADT7462_LOCAL_MIN	0x5c
+#define ADT7462_REM1_MIN	0x5d
+#define ADT7462_REM2_MIN	0x5e
+#define ADT7462_REM3_MIN	0x5f
+#define ADT7462_LOCAL_RANGE	0x60
+#define ADT7462_REM1_RANGE	0x61
+#define ADT7462_REM2_RANGE	0x62
+#define ADT7462_REM3_RANGE	0x63
+#define ADT7462_OPP_HYST	0x64
+#define ADT7462_33V_HIGH	0x68
+#define ADT7462_PIN23V_HIGH	0x69
+#define ADT7462_PIN24V_HIGH	0x6a
+#define ADT7462_PIN25V_HIGH	0x6b
+#define ADT7462_PIN26V_HIGH	0x6c
+#define ADT7462_12V1_LOW	0x6d
+#define ADT7462_12V2_LOW	0x6e
+#define ADT7462_12V3_LOW	0x6f
+#define ADT7462_33V_LOW		0x70
+#define ADT7462_5V_LOW		0x71
+#define ADT7462_PIN23V_LOW	0x72
+#define ADT7462_PIN24V_LOW	0x73
+#define ADT7462_PIN25V_LOW	0x74
+#define ADT7462_PIN26V_LOW	0x75
+#define ADT7462_15V1_LOW	0x76
+#define ADT7462_15V2_LOW	0x77
+#define ADT7462_TACH1_LIMIT	0x78
+#define ADT7462_VID_LIMIT	0x78
+#define ADT7462_TACH2_LIMIT	0x79
+#define ADT7462_TACH3_LIMIT	0x7a
+#define ADT7462_TACH4_LIMIT	0x7b
+#define ADT7462_TACH5_LIMIT	0x7c
+#define ADT7462_12V1_HIGH	0x7c
+#define ADT7462_TACH6_LIMIT	0x7d
+#define ADT7462_12V2_HIGH	0x7d
+#define ADT7462_TACH7_LIMIT	0x7e
+#define ADT7462_5V_HIGH		0x7e
+#define ADT7462_TACH8_LIMIT	0x7f
+#define ADT7462_12V3_HIGH	0x7f
+#define ADT7462_THERM1_TIMELIM	0x80
+#define ADT7462_THERM2_TIMELIM	0x81
+#define ADT7462_LOCAL_VAL_LSB	0x88
+#define ADT7462_LOCAL_VAL_MSB	0x89
+#define ADT7462_REM1_VAL_LSB	0x8a
+#define ADT7462_REM1_VAL_MSB	0x8b
+#define ADT7462_PIN15V_VAL	0x8b
+#define ADT7462_REM2_VAL_LSB	0x8c
+#define ADT7462_REM2_VAL_MSB	0x8d
+#define ADT7462_REM3_VAL_LSB	0x8e
+#define ADT7462_REM3_VAL_MSB	0x8f
+#define ADT7462_PIN19V_VAL	0x8f
+#define ADT7462_PIN23V_VAL	0x90
+#define ADT7462_PIN24V_VAL	0x91
+#define ADT7462_PIN25V_VAL	0x92
+#define ADT7462_PIN26V_VAL	0x93
+#define ADT7462_15V1_VAL	0x94
+#define ADT7462_15V2_VAL	0x95
+#define ADT7462_33V_VAL		0x96
+#define ADT7462_VID_VAL		0x97
+#define ADT7462_TACH1_VAL_LSB	0x98
+#define ADT7462_TACH1_VAL_MSB	0x99
+#define ADT7462_TACH2_VAL_LSB	0x9a
+#define ADT7462_TACH2_VAL_MSB	0x9b
+#define ADT7462_TACH3_VAL_LSB	0x9c
+#define ADT7462_TACH3_VAL_MSB	0x9d
+#define ADT7462_TACH4_VAL_LSB	0x9e
+#define ADT7462_TACH4_VAL_MSB	0x9f
+#define ADT7462_TACH5_VAL_LSB	0xa2
+#define ADT7462_TACH5_VAL_MSB	0xa3
+#define ADT7462_12V1_VAL	0xa3
+#define ADT7462_TACH6_VAL_LSB	0xa4
+#define ADT7462_TACH6_VAL_MSB	0xa5
+#define ADT7462_12V2_VAL	0xa5
+#define ADT7462_TACH7_VAL_LSB	0xa6
+#define ADT7462_TACH7_VAL_MSB	0xa7
+#define ADT7462_5V_VAL		0xa7
+#define ADT7462_TACH8_VAL_LSB	0xa8
+#define ADT7462_TACH8_VAL_MSB	0xa9
+#define ADT7462_12V3_VAL	0xa9
+#define ADT7462_PWM1_CYCLE	0xaa
+#define ADT7462_PWM2_CYCLE	0xab
+#define ADT7462_PWM3_CYCLE	0xac
+#define ADT7462_PWM4_CYCLE	0xad
+#define ADT7462_THERM1_ON_TIM	0xae
+#define ADT7462_THERM2_ON_TIM	0xaf
+#define ADT7462_TEMP1_STAT_H	0xb8
+#define ADT7462_TEMP2_STAT_H	0xb9
+#define ADT7462_TEMP3_STAT_H	0xba
+#define ADT7462_VOLT1_STAT_H	0xbb
+#define ADT7462_VOLT2_STAT_H	0xbc
+#define ADT7462_FAN_STAT_H	0xbd
+#define ADT7462_DIG_STAT_H	0xbe
+#define ADT7462_GPIO_STAT_H	0xbf
+#define ADT7462_TEMP1_STAT_B	0xc0
+#define ADT7462_TEMP2_STAT_B	0xc1
+#define ADT7462_VOLT1_STAT_B	0xc3
+#define ADT7462_VOLT2_STAT_B	0xc4
+#define ADT7462_FAN_STAT_B	0xc5
+#define ADT7462_DIG_STAT_B	0xc6
+
+/* 0x00: Configuration register 0 */
+#define ADT7462_CONF0_BLK_MASK	0x3f	/* # registers for block read */
+#define ADT7462_CONF0_VID_SPEC	0x40	/* 0 = VR10, 1 = VR11 */
+#define ADT7462_CONF0_RESET	0x80	/* Reset all unlocked registers */
+
+/* 0x01: Configuration register 1 */
+#define ADT7462_CONF1_MONITOR	0x01	/* Start monitoring temps and volts */
+#define ADT7462_CONF1_ALERT	0x08	/* 0 = SMB, 1 = comparator */
+#define ADT7462_CONF1_FAST_SPIN	0x10	/* 1 = no fast spin-up */
+#define ADT7462_CONF1_COMPLETE	0x20	/* Setup complete, start monitoring */
+#define ADT7462_CONF1_LOCK	0x40	/* Lock limit registers */
+#define ADT7462_CONF1_READY	0x80	/* Ready to start monitoring */
+
+/* 0x02: Configuration register 2 */
+#define ADT7462_CONF2_FAN_HF	0x01	/* Fast fan measurements */
+#define ADT7462_CONF2_PWM_HF	0x04	/* High frequency PWM measurements */
+#define ADT7462_CONF2_VRD1	0x08	/* Full speed fans on VRD1 */
+#define ADT7462_CONF2_VRD2	0x10	/* Full speed fans on VRD2 */
+#define ADT7462_CONF2_FFULL	0x20	/* Full speed fans */
+#define ADT7462_CONF2_TACH	0xc0	/* Tach pulse to measure */
+
+/* 0x03: Configuration register 3 */
+#define ADT7462_CONF3_GPIO_EN	0x01	/* Enable GPIO's */
+#define ADT7462_CONF3_SCL_TO	0x02	/* Enable SCL timeout */
+#define ADT7462_CONF3_SDA_TO	0x04	/* Enable SDA timeout */
+#define ADT7462_CONF3_VID_LVL	0x08	/* Set low VID threshold */
+#define ADT7462_CONF3_THERM_LVL	0x10	/* Set low therm threshold */
+#define ADT7462_CONF3_CI_RESET	0x20	/* Reset chassis intrusion circuit */
+#define ADT7462_CONF3_XOR_TEST	0x40	/* Enable XOR tree test */
+#define ADT7462_CONF3_VCORE_LOW	0x80	/* Set V_core_low */
+
+/* 0x07: Tach enable register */
+#define ADT7462_TACH1_ENABLE	0x01	/* Enable tach1 measurement */
+#define ADT7462_TACH2_ENABLE	0x02	/* Enable tach2 measurement */
+#define ADT7462_TACH3_ENABLE	0x04	/* Enable tach3 measurement */
+#define ADT7462_TACH4_ENABLE	0x08	/* Enable tach4 measurement */
+#define ADT7462_TACH5_ENABLE	0x10	/* Enable tach5 measurement */
+#define ADT7462_TACH6_ENABLE	0x20	/* Enable tach6 measurement */
+#define ADT7462_TACH7_ENABLE	0x40	/* Enable tach7 measurement */
+#define ADT7462_TACH8_ENABLE	0x80	/* Enable tach8 measurement */
+
+#define ADT7462_FAN_TACH_EN(val, x)	((val & (1 << x)) != 0)
+
+/* 0x08: Tach configuration register */
+#define ADT7462_TACH15_CONT	0x01	/* Continuous tach1+5 measurement */
+#define ADT7462_TACH26_CONT	0x02	/* Continuous tach2+6 measurement */
+#define ADT7462_TACH37_CONT	0x04	/* Continuous tach3+7 measurement */
+#define ADT7462_TACH48_CONT	0x08	/* Continuous tach4+8 measurement */
+
+/* 0x09: GPIO configuration register 1 */
+#define ADT7462_GPIO1_POL	0x01	/* GPIO1 polarity (0 low, 1 high) */
+#define ADT7462_GPIO1_DIR	0x02	/* GPIO1 direction (0 in, 1 out) */
+#define ADT7462_GPIO2_POL	0x04	/* GPIO2 polarity (0 low, 1 high) */
+#define ADT7462_GPIO2_DIR	0x08	/* GPIO2 direction (0 in, 1 out) */
+#define ADT7462_GPIO3_POL	0x10	/* GPIO3 polarity (0 low, 1 high) */
+#define ADT7462_GPIO3_DIR	0x20	/* GPIO3 direction (0 in, 1 out) */
+#define ADT7462_GPIO4_POL	0x40	/* GPIO4 polarity (0 low, 1 high) */
+#define ADT7462_GPIO4_DIR	0x80	/* GPIO4 direction (0 in, 1 out) */
+
+/* 0x0a: GPIO configuration register 2 */
+#define ADT7462_GPIO5_POL	0x01	/* GPIO5 polarity (0 low, 1 high) */
+#define ADT7462_GPIO5_DIR	0x02	/* GPIO5 direction (0 in, 1 out) */
+#define ADT7462_GPIO6_POL	0x04	/* GPIO6 polarity (0 low, 1 high) */
+#define ADT7462_GPIO6_DIR	0x08	/* GPIO6 direction (0 in, 1 out) */
+#define ADT7462_GPIO7_POL	0x10	/* GPIO7 polarity (0 low, 1 high) */
+#define ADT7462_GPIO7_DIR	0x20	/* GPIO7 direction (0 in, 1 out) */
+#define ADT7462_GPIO8_POL	0x40	/* GPIO8 polarity (0 low, 1 high) */
+#define ADT7462_GPIO8_DIR	0x80	/* GPIO8 direction (0 in, 1 out) */
+
+/* 0x0b: Dynamix Tmin control register 1 */
+#define ADT7462_REM1_EN		0x01	/* Enable dynamic rem 1 Tmin control */
+#define ADT7462_REM2_EN		0x02	/* Enable dynamic rem 2 Tmin control */
+#define ADT7462_P1_R1		0x04	/* Copy rem 1 val to op if therm1 */
+#define ADT7462_P1_R2		0x08	/* Copy rem 2 val to op if therm1 */
+#define ADT7462_P2_R1		0x10	/* Copy rem 1 val to op if therm2 */
+#define ADT7462_P2_R2		0x20	/* Copy rem 2 val to op if therm2 */
+
+/* 0x0c: Dynamix Tmin control register 2 */
+#define ADT7462_REM1_CYCLE	0x07	/* Rem 1 cycle mask */
+#define ADT7462_REM2_CYCLE	0x38	/* Rem 2 cycle mask */
+#define ADT7462_CTRL_LOOP	0x40	/* Control loop select */
+
+/* 0x0d: Therm configuration register */
+#define ADT7462_BOOST1		0x01	/* Max fan PWM if therm1 */
+#define ADT7462_BOOST2		0x02	/* Max fan PWM if therm2 */
+#define ADT7462_THERM1_TIMER	0x1c	/* Therm1 timer window mask */
+#define ADT7462_THERM2_TIMER	0xe0	/* Therm2 timer window mask */
+
+/* 0x0e: Therm1 configuration register */
+#define ADT7462_THERM1_TIM_EN	0x01	/* Enable therm1 timer circuit */
+#define ADT7462_THERM1_LOCAL	0x02	/* Therm1 assert on local */
+#define ADT7462_THERM1_REM1	0x04	/* Therm1 assert on remote1 */
+#define ADT7462_THERM1_REM2	0x08	/* Therm1 assert on remote2 */
+#define ADT7462_THERM1_REM3	0x10	/* Therm1 assert on remote3 */
+
+/* 0x0f: Therm2 configuration register */
+#define ADT7462_THERM2_TIM_EN	0x01	/* Enable therm2 timer circuit */
+#define ADT7462_THERM2_LOCAL	0x02	/* Therm2 assert on local */
+#define ADT7462_THERM2_REM1	0x04	/* Therm2 assert on remote1 */
+#define ADT7462_THERM2_REM2	0x08	/* Therm2 assert on remote2 */
+#define ADT7462_THERM2_REM3	0x10	/* Therm2 assert on remote3 */
+
+/* 0x10: Pin configuration register 1 */
+#define ADT7462_PIN7_CONF	0x01	/* 0 = +12v1, 1 = Tach5 */
+#define ADT7462_PIN4_CONF	0x02	/* 0 = GPIO4, 1 = Tach4 */
+#define ADT7462_PIN3_CONF	0x04	/* 0 = GPIO3, 1 = Tach3 */
+#define ADT7462_PIN2_CONF	0x08	/* 0 = GPIO2, 1 = Tach2 */
+#define ADT7462_PIN1_CONF	0x10	/* 0 = GPIO1, 1 = Tach1 */
+#define ADT7462_DIODE3_CONF	0x20	/* 0 = volt/SCSI, 1 = D3+/D3- */
+#define ADT7462_DIODE1_CONF	0x40	/* 0 = volt/SCSI, 1 = D1+/D1- */
+#define ADT7462_VID_EN		0x80	/* 1 = En. VID's pins 1-4 28 31 32 */
+
+#define ADT7462_PCR1_TACH(val, x)	(x > 3 || \
+    (!(val & ADT7462_VID_EN) && (val & (1 << x)) != 0))
+#define ADT7462_PCR1_TEMP(val, x)	(x== 0 || x == 2 || \
+    (x == 3 && (val & ADT7462_DIODE3_CONF)) || \
+    (x == 1 && (val & ADT7462_DIODE1_CONF)))
+#define ADT7462_PCR1_PIN7_V(val)	(!(val & ADT7462_PIN7_CONF))
+#define ADT7462_PCR1_PIN19_V(val)	(!(val & ADT7462_DIODE3_CONF))
+#define ADT7462_PCR1_PIN15_V(val)	(!(val & ADT7462_DIODE1_CONF))
+#define ADT7462_PCR1_VIDS(val)		((val & ADT7462_VID_EN) != 0)
+
+/* 0x11: Pin configuration register 2 */
+#define ADT7462_PIN23_CONF	0x03	/* 00 = Vcc, 2.5v, 1.8v, 11 = 1.5v */
+#define ADT7462_PIN22_CONF	0x04	/* 0 = 12v3, 1 = Tach8 */
+#define ADT7462_PIN21_CONF	0x08	/* 0 = 5v, 1 = Tach7 */
+#define ADT7462_PIN19_CONF	0x10	/* 0 = 1.25v, 1 = 0.9v */
+#define ADT7462_PIN15_CONF	0x20	/* 0 = 2.5v, 1 = 1.8v */
+#define ADT7462_PIN13_CONF	0x40	/* 0 = 3.3v, 1 = PWM4 */
+#define ADT7462_PIN8_CONF	0x80	/* 0 = 12v2, 1 = Tach6 */
+
+#define ADT7462_PCR2_P23_25V(val)	((val & ADT7462_PIN23_CONF) == 0x01)
+#define ADT7462_PCR2_P23_18V(val)	((val & ADT7462_PIN23_CONF) == 0x02)
+#define ADT7462_PCR2_P23_15V(val)	((val & ADT7462_PIN23_CONF) == 0x03)
+#define ADT7462_PCR2_P22_TACH8(val)	((val & ADT7462_PIN22_CONF) == 0x04)
+#define ADT7462_PCR2_P21_TACH7(val)	((val & ADT7462_PIN21_CONF) == 0x08)
+#define ADT7462_PCR2_P19_09V(val)	((val & ADT7462_PIN19_CONF) == 0x10)
+#define ADT7462_PCR2_P15_18V(val)	((val & ADT7462_PIN15_CONF) == 0x20)
+#define ADT7462_PCR2_P13_PWM4(val)	((val & ADT7462_PIN13_CONF) == 0x40)
+#define ADT7462_PCR2_P8_TACH6(val)	((val & ADT7462_PIN8_CONF) == 0x80)
+#define ADT7462_PCR2_TACH(val, x)	(x < 5 || \
+    (x == 5 && ADT7462_PCR2_P8_TACH6(val)) || \
+    (x == 6 && ADT7462_PCR2_P21_TACH7(val)) || \
+    (x == 7 && ADT7462_PCR2_P22_TACH8(val)))
+
+/* 0x12: Pin configuration register 3 */
+#define ADT7462_PIN27_CONF	0x02	/* 0 = fan2max, 1 = chassis intrus */
+#define ADT7462_PIN26_CONF	0x0c	/* 00 = Vbatt, 1.2v2, 10/11=vr_hot2 */
+#define ADT7462_PIN25_CONF	0x30	/* 00 = 3.3v, 1.2v1, 10/11=vr_hot1 */
+#define ADT7462_PIN24_CONF	0xc0	/* 00 = Vccp, 2.5v, 1.8v, 11 = 1.5v */
+
+#define ADT7462_PCR3_P24_25V(val)	((val & ADT7462_PIN24_CONF) == 0x40)
+#define ADT7462_PCR3_P24_18V(val)	((val & ADT7462_PIN24_CONF) == 0x80)
+#define ADT7462_PCR3_P24_15V(val)	((val & ADT7462_PIN24_CONF) == 0xc0)
+#define ADT7462_PCR3_P25_33V(val)	((val & ADT7462_PIN25_CONF) == 0x00)
+#define ADT7462_PCR3_P25_12V(val)	((val & ADT7462_PIN25_CONF) == 0x10)
+#define ADT7462_PCR3_P26_VBAT(val)	((val & ADT7462_PIN26_CONF) == 0x00)
+#define ADT7462_PCR3_P26_12V(val)	((val & ADT7462_PIN26_CONF) == 0x04)
+
+/* 0x13: Pin configuration register 4 */
+#define ADT7462_PIN32_CONF	0x04	/* 0 = GPIO6, 1 = PWM2 */
+#define ADT7462_PIN31_CONF	0x08	/* 0 = GPIO5, 1 = PWM1 */
+#define ADT7462_PIN29_CONF	0x30	/* 00 = GPIO8, 1.5v, 10/11 = therm2 */
+#define ADT7462_PIN28_CONF	0xc0	/* 00 = GPIO7, 1.5v, 10/11 = therm1 */
+
+#define ADT7462_PCR4_P29_15V(val)	((val & ADT7462_PIN29_CONF) == 0x10)
+#define ADT7462_PCR4_P28_15V(val)	((val & ADT7462_PIN28_CONF) == 0x10)
+
+/* 0x14: Easy configuration options */
+#define ADT7462_EASY1		0x01	/* Enable easy option 1 */
+#define ADT7462_EASY2		0x02	/* Enable easy option 2 */
+#define ADT7462_EASY3		0x04	/* Enable easy option 3 */
+#define ADT7462_EASY4		0x08	/* Enable easy option 4 */
+
+/* 0x16: EDO/Single channel enable */
+#define ADT7462_EDO_EN1		0x01	/* Enable EDO on GPIO5 */
+#define ADT7462_EDO_EN2		0x02	/* Enable EDO on GPIO6 */
+#define ADT7462_1CHAN_MODE	0x04	/* Select single-channel mode */
+#define ADT7462_CHAN_SEL	0xf8	/* Select channel mask */
+
+/* 0x18: Voltage attenuator configuration 1 */
+#define ADT7462_ATT_PIN7	0x02	/* Enable attenuator on pin7 */
+#define ADT7462_ATT_PIN8	0x04	/* Enable attenuator on pin8 */
+#define ADT7462_ATT_PIN13	0x08	/* Enable attenuator on pin13 */
+#define ADT7462_ATT_PIN15	0x10	/* Enable attenuator on pin15 */
+#define ADT7462_ATT_PIN19	0x20	/* Enable attenuator on pin19 */
+#define ADT7462_ATT_PIN21	0x40	/* Enable attenuator on pin21 */
+#define ADT7462_ATT_PIN22	0x80	/* Enable attenuator on pin22 */
+
+/* 0x19: Voltage attenuator configuration 2 */
+#define ADT7462_ATT_PIN23	0x01	/* Enable attenuator on pin23 */
+#define ADT7462_ATT_PIN24	0x02	/* Enable attenuator on pin24 */
+#define ADT7462_ATT_PIN25	0x04	/* Enable attenuator on pin25 */
+#define ADT7462_ATT_PIN28	0x10	/* Enable attenuator on pin28 */
+#define ADT7462_ATT_PIN29	0x20	/* Enable attenuator on pin29 */
+
+/* 0x1a: Enhanced acoustics register 1 */
+#define ADT7462_AC_EN1		0x01	/* En. enhanced acoustics for PWM1 */
+#define ADT7462_AC_EN2		0x02	/* En. enhanced acoustics for PWM2 */
+#define ADT7462_AC_RATE1	0x1c	/* Ramp rate for PWM1 */
+
+/* 0x1b: Enhanced acoustics register 2 */
+#define ADT7462_AC_EN3		0x01	/* En. enhanced acoustics for PWM3 */
+#define ADT7462_AC_EN4		0x02	/* En. enhanced acoustics for PWM4 */
+#define ADT7462_AC_RATE3	0x1c	/* Ramp rate for PWM3 */
+#define ADT7462_AC_RATE4	0xe0	/* Ramp rate for PWM4 */
+
+/* 0x1c: Fan freewheeling test */
+#define ADT7462_FAN_FREE1_END	0x01	/* Freewheeling for fan1 complete */
+#define ADT7462_FAN_FREE2_END	0x02	/* Freewheeling for fan2 complete */
+#define ADT7462_FAN_FREE3_END	0x04	/* Freewheeling for fan3 complete */
+#define ADT7462_FAN_FREE4_END	0x08	/* Freewheeling for fan4 complete */
+#define ADT7462_FAN_FREE5_END	0x10	/* Freewheeling for fan5 complete */
+#define ADT7462_FAN_FREE6_END	0x20	/* Freewheeling for fan6 complete */
+#define ADT7462_FAN_FREE7_END	0x40	/* Freewheeling for fan7 complete */
+#define ADT7462_FAN_FREE8_END	0x80	/* Freewheeling for fan8 complete */
+
+/* 0x1d: Fans present */
+#define ADT7462_FAN1_PRESENT	0x01	/* Fan1 present */
+#define ADT7462_FAN2_PRESENT	0x02	/* Fan2 present */
+#define ADT7462_FAN3_PRESENT	0x04	/* Fan3 present */
+#define ADT7462_FAN4_PRESENT	0x08	/* Fan4 present */
+#define ADT7462_FAN5_PRESENT	0x10	/* Fan5 present */
+#define ADT7462_FAN6_PRESENT	0x20	/* Fan6 present */
+#define ADT7462_FAN7_PRESENT	0x40	/* Fan7 present */
+#define ADT7462_FAN8_PRESENT	0x80	/* Fan8 present */
+
+/* 0x1e: Fan freewheeling test */
+#define ADT7462_FAN_FREE1	0x01	/* Start freewheeling test for fan1 */
+#define ADT7462_FAN_FREE2	0x02	/* Start freewheeling test for fan2 */
+#define ADT7462_FAN_FREE3	0x04	/* Start freewheeling test for fan3 */
+#define ADT7462_FAN_FREE4	0x08	/* Start freewheeling test for fan4 */
+#define ADT7462_FAN_FREE5	0x10	/* Start freewheeling test for fan5 */
+#define ADT7462_FAN_FREE6	0x20	/* Start freewheeling test for fan6 */
+#define ADT7462_FAN_FREE7	0x40	/* Start freewheeling test for fan7 */
+#define ADT7462_FAN_FREE8	0x80	/* Start freewheeling test for fan8 */
+
+/* 0x21: PWM1 configuration register */
+#define ADT7462_PWM1_SPIN_TIMEO	0x07	/* Fan startup and test timeout */
+#define ADT7462_PWM1_SLOW	0x08	/* Slow en. acoustics mode start*/
+#define ADT7462_PWM1_INV	0x10	/* PWM output 0 = low, 1 = high */
+#define ADT7462_PWM1_BHVR	0xe0	/* PWM control temp. mask */
+
+/* 0x22: PWM2 configuration register */
+#define ADT7462_PWM2_SPIN_TIMEO	0x07	/* Fan startup and test timeout */
+#define ADT7462_PWM2_SLOW	0x08	/* Slow en. acoustics mode start*/
+#define ADT7462_PWM2_INV	0x10	/* PWM output 0 = low, 1 = high */
+#define ADT7462_PWM2_BHVR	0xe0	/* PWM control temp. mask */
+
+/* 0x23: PWM3 configuration register */
+#define ADT7462_PWM3_SPIN_TIMEO	0x07	/* Fan startup and test timeout */
+#define ADT7462_PWM3_SLOW	0x08	/* Slow en. acoustics mode start*/
+#define ADT7462_PWM3_INV	0x10	/* PWM output 0 = low, 1 = high */
+#define ADT7462_PWM3_BHVR	0xe0	/* PWM control temp. mask */
+
+/* 0x24: PWM1 configuration register */
+#define ADT7462_PWM4_SPIN_TIMEO	0x07	/* Fan startup and test timeout */
+#define ADT7462_PWM4_SLOW	0x08	/* Slow en. acoustics mode start*/
+#define ADT7462_PWM4_INV	0x10	/* PWM output 0 = low, 1 = high */
+#define ADT7462_PWM4_BHVR	0xe0	/* PWM control temp. mask */
+
+/* 0x25: PWM1, PWM2 frequency */
+#define ADT7462_PWM1_TMIN	0x01	/* PWM1 is off or min at Tmin */
+#define ADT7462_PWM2_TMIN	0x02	/* PWM2 is off or min at Tmin */
+#define ADT7462_PWM1_LFREQ	0x1c	/* PWM1 low frequency mask */
+#define ADT7462_PWM2_LFREQ	0xe0	/* PWM2 low frequency mask */
+
+/* 0x26: PWM3, PWM4 frequency */
+#define ADT7462_PWM3_TMIN	0x01	/* PWM3 is off or min at Tmin */
+#define ADT7462_PWM4_TMIN	0x02	/* PWM4 is off or min at Tmin */
+#define ADT7462_PWM3_LFREQ	0x1c	/* PWM3 low frequency mask */
+#define ADT7462_PWM4_LFREQ	0xe0	/* PWM4 low frequency mask */
+
+/* 0x30: Thermal mask register 1 */
+#define ADT7462_MASK_LOCAL	0x02	/* Mask local temp. out of limit */
+#define ADT7462_MASK_REMOTE1	0x04	/* Mask remote1 temp. out of limit */
+#define ADT7462_MASK_REMOTE2	0x08	/* Mask remote2 temp. out of limit */
+#define ADT7462_MASK_REMOTE3	0x10	/* Mask remote3 temp. out of limit */
+#define ADT7462_MASK_DIODE1	0x20	/* Mask remote1 temp. error */
+#define ADT7462_MASK_DIODE2	0x40	/* Mask remote2 temp. error */
+#define ADT7462_MASK_DIODE3	0x80	/* Mask remote3 temp. error */
+
+/* 0x31: Thermal mask register 2 */
+#define ADT7462_MASK_TH1_PCT	0x01	/* Mask therm1 percent alert */
+#define ADT7462_MASK_TH1_ASRT	0x02	/* Mask therm1 assert */
+#define ADT7462_MASK_TH1_STAT	0x04	/* Mask therm1 state alert */
+#define ADT7462_MASK_TH2_PCT	0x08	/* Mask therm2 percent alert */
+#define ADT7462_MASK_TH2_ASRT	0x10	/* Mask therm2 assert */
+#define ADT7462_MASK_TH2_STAT	0x20	/* Mask therm2 state alert */
+#define ADT7462_MASK_VRD1	0x40	/* Mask VRD1 assert */
+#define ADT7462_MASK_VRD2	0x80	/* Mask VRD2 assert */
+
+/* 0x32: Voltage mask register 1 */
+#define ADT7462_MASK_12V1	0x01	/* Mask 12V1 alert */
+#define ADT7462_MASK_12V2	0x02	/* Mask 12V2 alert */
+#define ADT7462_MASK_12V3	0x04	/* Mask 12V3 alert */
+#define ADT7462_MASK_33V	0x08	/* Mask 3.3V alert */
+#define ADT7462_MASK_PIN15V	0x10	/* Mask pin15v alert */
+#define ADT7462_MASK_PIN19V	0x20	/* Mask pin19v alert */
+#define ADT7462_MASK_5V		0x40	/* Mask 5V alert */
+#define ADT7462_MASK_PIN23V	0x80	/* Mask pin23v alert */
+
+/* 0x33: Voltage mask register 2 */
+#define ADT7462_MASK_PIN24V	0x08	/* Mask pin24v alert */
+#define ADT7462_MASK_PIN25V	0x10	/* Mask pin25v alert */
+#define ADT7462_MASK_PIN26V	0x20	/* Mask pin26v alert */
+#define ADT7462_MASK_15V2	0x40	/* Mask 1.5V2 alert */
+#define ADT7462_MASK_15V1	0x80	/* Mask 1.5V1 alert */
+
+/* 0x34: Fan mask register */
+#define ADT7462_MASK_FAN1_FAULT	0x01	/* Mask fan1 fault */
+#define ADT7462_MASK_FAN2_FAULT	0x02	/* Mask fan2 fault */
+#define ADT7462_MASK_FAN3_FAULT	0x04	/* Mask fan3 fault */
+#define ADT7462_MASK_FAN4_FAULT	0x08	/* Mask fan4 fault */
+#define ADT7462_MASK_FAN5_FAULT	0x10	/* Mask fan5 fault */
+#define ADT7462_MASK_FAN6_FAULT	0x20	/* Mask fan6 fault */
+#define ADT7462_MASK_FAN7_FAULT	0x40	/* Mask fan7 fault */
+#define ADT7462_MASK_FAN8_FAULT	0x80	/* Mask fan8 fault */
+
+/* 0x35: Digital mask register */
+#define ADT7462_MASK_FAN2MAX	0x08	/* Mask fan2max alert */
+#define ADT7462_MASK_SCSI1	0x10	/* Mask SCSI1 alert */
+#define ADT7462_MASK_SCSI2	0x20	/* Mask SCSI2 alert */
+#define ADT7462_MASK_VID	0x40	/* Mask VID comparison alert */
+#define ADT7462_MASK_CHASSIS	0x80	/* Mask chassis intrusion alert */
+
+/* 0x36: GPIO mask register */
+#define ADT7462_MASK_GPIO1_FLT	0x01	/* Mask GPIO1 fault */
+#define ADT7462_MASK_GPIO2_FLT	0x02	/* Mask GPIO2 fault */
+#define ADT7462_MASK_GPIO3_FLT	0x04	/* Mask GPIO3 fault */
+#define ADT7462_MASK_GPIO4_FLT	0x08	/* Mask GPIO4 fault */
+#define ADT7462_MASK_GPIO5_FLT	0x10	/* Mask GPIO5 fault */
+#define ADT7462_MASK_GPIO6_FLT	0x20	/* Mask GPIO6 fault */
+#define ADT7462_MASK_GPIO7_FLT	0x40	/* Mask GPIO7 fault */
+#define ADT7462_MASK_GPIO8_FLT	0x80	/* Mask GPIO8 fault */
+
+/* 0x36: EDO mask register 1 */
+#define ADT7462_EDO1_GPIO1	0x01	/* Mask GPIO1 for EDO1 */
+#define ADT7462_EDO1_GPIO2	0x02	/* Mask GPIO2 for EDO1 */
+#define ADT7462_EDO1_GPIO3	0x04	/* Mask GPIO3 for EDO1 */
+#define ADT7462_EDO1_GPIO4	0x08	/* Mask GPIO4 for EDO1 */
+#define ADT7462_EDO1_FAN	0x20	/* Mask fan fault for EDO1 */
+#define ADT7462_EDO1_TEMP	0x40	/* Mask therm for EDO1 */
+#define ADT7462_EDO2_VOLT	0x80	/* Mask volt limit for EDO1 */
+
+/* 0x36: EDO mask register 2 */
+#define ADT7462_EDO2_GPIO1	0x01	/* Mask GPIO1 for EDO2 */
+#define ADT7462_EDO2_GPIO2	0x02	/* Mask GPIO2 for EDO2 */
+#define ADT7462_EDO2_GPIO3	0x04	/* Mask GPIO3 for EDO2 */
+#define ADT7462_EDO2_GPIO4	0x08	/* Mask GPIO4 for EDO2 */
+#define ADT7462_EDO2_FAN	0x20	/* Mask fan fault for EDO2 */
+#define ADT7462_EDO2_TEMP	0x40	/* Mask therm for EDO2 */
+#define ADT7462_EDO2_VOLT	0x80	/* Mask volt limit for EDO2 */
+
+/* 0x3d: Device ID register */
+#define ADT7462_DEV_ID_VAL	0x62	/* ADT7462 device ID */
+
+/* 0x3e: Company ID register */
+#define ADT7462_COMP_ID_VAL	0x41	/* ADT7462 company ID */
+
+/* 0x3f: Revision ID register */
+#define ADT7462_REV_ID_VAL	0x04	/* ADT7462 revision ID */
+
+/* 0x44 - 0x53: Temperature limit registers: -64'C + value */
+#define ADT7462_TEMP_BASE	209150000
+#define ADT7462_TEMP_LOW(x)	(0x44 + x)
+#define ADT7462_TEMP_HIGH(x)	(0x48 + x)
+#define ADT7462_TEMP_THERM1(x)	(0x4c + x)
+#define ADT7462_TEMP_THERM2(x)	(0x50 + x)
+
+/* 0x54 - Local/remote 1 temperature hysteresis */
+#define ADT7462_REMOTE1_TH_HYST	0x0f	/* Remote 1 therm hyst. (0 - 15) */
+#define ADT7462_LOCAL_TH_HYST	0xf0	/* Local therm hyst. (0 - 15) */
+
+/* 0x55 - Remote 2/remote 3 temperature hysteresis */
+#define ADT7462_REMOTE3_TH_HYST	0x0f	/* Remote 3 therm hyst. (0 - 15) */
+#define ADT7462_REMOTE2_TH_HYST	0xf0	/* Remote 2 therm hyst. (0 - 15) */
+
+/* 0x56 - 0x59: Offset registers: resolution = 0.5'C */
+
+/* 0x5a - 0x5b: Operation point registers */
+
+/* 0x5c - 0x5f: Timing registers */
+
+/* 0x60 - 0x63: Trange/Hysteresis registers */
+#define ADT7462_LOCAL_FN_HYST	0x0f	/* Local auto fan loop hyst. (0-15) */
+#define ADT7462_LOCAL_FN_RNGE	0xf0	/* Local Trange value (2 - 80) */
+#define ADT7462_REMOTE1_FN_HYST	ADT7462_LOCAL_FN_HYST
+#define ADT7462_REMOTE1_FN_RNGE	ADT7462_LOCAL_FN_RNGE
+#define ADT7462_REMOTE2_FN_HYST	ADT7462_LOCAL_FN_HYST
+#define ADT7462_REMOTE2_FN_RNGE	ADT7462_LOCAL_FN_RNGE
+#define ADT7462_REMOTE3_FN_HYST	ADT7462_LOCAL_FN_HYST
+#define ADT7462_REMOTE3_FN_RNGE	ADT7462_LOCAL_FN_RNGE
+
+/* 0x64: Operating point hysteresis */
+#define ADT7462_OPT_HYST	0xf0	/* Tmin loop hyst. (0 - 15) */
+
+/* 0x68 - 0x77: Voltage limit registers */
+
+/* 0x78 - 0x7f: Tach limit registers */
+#define ADT7462_TACH_LIMIT(x)	(0x78 + x)
+
+/* 0x80 - 0x81: Therm timer limit registers */
+
+/* 0x88 - 0x8f: Temperature value registers */
+#define ADT7462_TEMP_LSB(x)	(0x88 + 2 * x)
+
+/* 0x90 - 0x96: Voltage value registers */
+
+/* 0x97: VID value register */
+
+/* 0x98 - 0x9f, 0xa2 - 0xa9: Tach value registers */
+#define ADT7462_TACH_VAL_LSB(x)	(x < 4 ? 0x98 + 2 * x : 0x9a + 2 * x)
+#define ADT7462_TACH_PERIOD	(90000 * 60)
+
+/* 0xaa - 0xad: PWM current duty cycle registers */
+
+/* 0xae - 0xaf: Therm time value registers */
+
+/* 0xb8, 0xc0: Host/BMC thermal status register 1 */
+#define ADT7462_LOCAL_TRIP	0x02
+#define ADT7462_REMOTE1_TRIP	0x04
+#define ADT7462_REMOTE2_TRIP	0x08
+#define ADT7462_REMOTE3_TRIP	0x10
+#define ADT7462_DIODE1_ERR	0x20
+#define ADT7462_DIODE2_ERR	0x40
+#define ADT7462_DIODE3_ERR	0x80
+
+/* 0xb9, 0xc1: Host/BMC thermal status register 2 */
+#define ADT7462_THERM1_PCT	0x01
+#define ADT7462_THERM1_ASSERT	0x02
+#define ADT7462_THERM1_STATE	0x04
+#define ADT7462_THERM2_PCT	0x08
+#define ADT7462_THERM2_ASSERT	0x10
+#define ADT7462_THERM2_STATE	0x20
+#define ADT7462_VRD1_ASSERT	0x40
+#define ADT7462_VRD2_ASSERT	0x80
+
+/* 0xba: Host thermal status register 3 */
+#define ADT7462_THERM1_L_EXCD	0x01
+#define ADT7462_THERM1_R1_EXCD	0x02
+#define ADT7462_THERM1_R2_EXCD	0x04
+#define ADT7462_THERM1_R3_EXCD	0x08
+#define ADT7462_THERM2_L_EXCD	0x10
+#define ADT7462_THERM2_R1_EXCD	0x20
+#define ADT7462_THERM2_R2_EXCD	0x40
+#define ADT7462_THERM2_R3_EXCD	0x80
+
+/* 0xbb, 0xc3: Host/BMC voltage status register 1 */
+#define ADT7462_12V1_TRIP	0x01
+#define ADT7462_12V2_TRIP	0x02
+#define ADT7462_12V3_TRIP	0x04
+#define ADT7462_33V_TRIP	0x08
+#define ADT7462_PIN15V_TRIP	0x10
+#define ADT7462_PIN19V_TRIP	0x20
+#define ADT7462_5V_TRIP		0x40
+#define ADT7462_PIN23V_TRIP	0x80
+
+/* 0xbc, 0xc4: Host/BMC voltage status register 2 */
+#define ADT7462_PIN24V_TRIP	0x04
+#define ADT7462_PIN25V_TRIP	0x10
+#define ADT7462_PIN26V_TRIP	0x20
+#define ADT7462_15V2_TRIP	0x40
+#define ADT7462_15V1_TRIP	0x80
+
+/* 0xbd, 0xc5: Host/BMC fan status register */
+#define ADT7462_FAN1_FAULT	0x01
+#define ADT7462_FAN2_FAULT	0x02
+#define ADT7462_FAN3_FAULT	0x04
+#define ADT7462_FAN4_FAULT	0x08
+#define ADT7462_FAN5_FAULT	0x10
+#define ADT7462_FAN6_FAULT	0x20
+#define ADT7462_FAN7_FAULT	0x40
+#define ADT7462_FAN8_FAULT	0x80
+
+/* 0xbe, 0xc6: Host/BMC digital status register */
+#define ADT7462_FAN2MAX_ASSERT	0x08
+#define ADT7462_SCSI1_ASSERT	0x10
+#define ADT7462_SCSI2_ASSERT	0x20
+#define ADT7462_VID_COMP_FLT	0x40
+#define ADT7462_CHASSIS_ASSERT	0x80
+
+/* 0xbe, 0xc6: Host/BMC GPIO status register */
+#define ADT7462_GPIO1_ASSERT	0x01
+#define ADT7462_GPIO2_ASSERT	0x02
+#define ADT7462_GPIO3_ASSERT	0x04
+#define ADT7462_GPIO4_ASSERT	0x08
+#define ADT7462_GPIO5_ASSERT	0x10
+#define ADT7462_GPIO6_ASSERT	0x20
+#define ADT7462_GPIO7_ASSERT	0x40
+#define ADT7462_GPIO8_ASSERT	0x80
+
+#endif /* _DEV_I2C_ADT7462REG_H_ */
--- src/sys/dev/i2c/files.i2c.dist	2026-02-10 22:19:26.249986431 +0100
+++ src/sys/dev/i2c/files.i2c	2026-02-16 16:16:21.629999416 +0100
@@ -464,3 +464,18 @@
 # NXP SC16IS7xx UART bridge
 attach sc16is7xx at iic with sc16is7xxi2c
 file dev/i2c/sc16is7xxi2c.c			sc16is7xxi2c
+
+# Texas Instruments LM95221 temperature sensor
+device	lm95221ts: sysmon_envsys
+attach	lm95221ts at iic
+file	dev/i2c/lm95221.c			lm95221ts
+
+# NXP LM75A temperature sensor
+device	nxp75a: sysmon_envsys
+attach	nxp75a at iic
+file	dev/i2c/nxp75a.c			nxp75a
+
+# ADM1026 system monitor
+device	adt7462sm: sysmon_envsys
+attach	adt7462sm at iic
+file	dev/i2c/adt7462.c			adt7462sm
--- src/sys/dev/i2c/lm95221.c.dist	2026-02-10 22:20:01.329986410 +0100
+++ src/sys/dev/i2c/lm95221.c	2026-02-03 09:37:15.579987938 +0100
@@ -0,0 +1,280 @@
+/* $NetBSD$ */
+
+/*-
+ * Copyright (c) 2020 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Julian Coleman.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__KERNEL_RCSID(0, "$NetBSD$");
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/device.h>
+#include <sys/kernel.h>
+#include <sys/sysctl.h>
+
+#include <dev/sysmon/sysmonvar.h>
+
+#include <dev/i2c/i2cvar.h>
+#include <dev/i2c/lm95221reg.h>
+
+#define LM95221_LOCAL	0
+#define LM95221_REMOTE1	1
+#define LM95221_REMOTE2	2
+#define LM95221_MISSING 0x01
+#define LM95221_SIGNED	0x02
+
+struct lm95221ts_softc {
+	device_t sc_dev;
+	i2c_tag_t sc_tag;
+	int sc_address;
+
+	struct sysmon_envsys *sc_sme;
+	envsys_data_t sc_sensor[LM95221_NSENSORS];
+	int sc_map[LM95221_NSENSORS];		/* Sysmon numbers to sensors */
+	uint8_t	sc_reg_m[LM95221_NSENSORS];	/* MSB register */
+	uint8_t	sc_reg_l[LM95221_NSENSORS];	/* LSB register */
+	uint8_t sc_flags[LM95221_NSENSORS];	/* Flags for remotes */
+};
+
+static int lm95221ts_match(device_t, cfdata_t, void *);
+static void lm95221ts_attach(device_t, device_t, void *);
+static int lm95221ts_detach(device_t, int);
+void lm95221ts_refresh(struct sysmon_envsys *, envsys_data_t *);
+static int lm95221ts_read_temp(struct lm95221ts_softc *, uint8_t, uint8_t,
+    uint8_t, uint32_t *);
+
+CFATTACH_DECL_NEW(lm95221ts, sizeof(struct lm95221ts_softc),
+	lm95221ts_match, lm95221ts_attach, lm95221ts_detach, NULL);
+
+
+static const struct device_compatible_entry compat_data[] = {
+	{ .compat = "i2c-lm95221" },
+	DEVICE_COMPAT_EOL
+};
+
+static int
+lm95221ts_match(device_t parent, cfdata_t cf, void *aux)
+{
+	struct i2c_attach_args *ia = aux;
+	int match_result;
+
+	if (iic_use_direct_match(ia, cf, compat_data, &match_result))
+		return match_result;
+
+	/*
+	 * Indirect config - assume config is correct!
+	 */
+	if (ia->ia_addr == LM95221_ADDR)
+		return I2C_MATCH_ADDRESS_ONLY;
+
+	return 0;
+}
+
+static void
+lm95221ts_attach(device_t parent, device_t self, void *aux)
+{
+	struct lm95221ts_softc *sc = device_private(self);
+	struct i2c_attach_args *ia = aux;
+	uint8_t reg, val;
+	int i, map;
+
+	sc->sc_tag = ia->ia_tag;
+	sc->sc_address = ia->ia_addr;
+	sc->sc_dev = self;
+
+	aprint_normal(": LM95221 temperature sensor\n");
+
+	/* Read status, start conversion */
+	for (i = 0; i < LM95221_NSENSORS; i++)
+		sc->sc_flags[i] = 0;
+
+	if (iic_acquire_bus(sc->sc_tag, 0)) {
+		aprint_error_dev(sc->sc_dev,
+		    "unable to acquire i2c bus\n");
+		return;
+	}
+
+	reg = LM95221_STATUS;
+	if (iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP,
+	    sc->sc_address, &reg, 1, &val, 1, 0)) {
+		aprint_error_dev(sc->sc_dev,
+		    "unable to read status register\n");
+		return;
+	}
+	if (val & LM95221_STAT_NO_REMOTE1)
+		sc->sc_flags[LM95221_REMOTE1] |= LM95221_MISSING;
+	if (val & LM95221_STAT_NO_REMOTE2)
+		sc->sc_flags[LM95221_REMOTE2] |= LM95221_MISSING;
+
+	reg = LM95221_CONFIG;
+	if (iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP,
+	    sc->sc_address, &reg, 1, &val, 1, 0)) {
+		iic_release_bus(sc->sc_tag, 0);
+		aprint_error_dev(sc->sc_dev,
+		    "unable to read config register\n");
+		return;
+	}
+	if (val & LM95221_CONF_REMOTE1)
+		sc->sc_flags[LM95221_REMOTE1] |= LM95221_SIGNED;
+	if (val & LM95221_CONF_REMOTE2)
+		sc->sc_flags[LM95221_REMOTE2] |= LM95221_SIGNED;
+
+	if (val & LM95221_CONF_STANDBY) {
+		val &= ~(LM95221_CONF_STANDBY);
+		if (iic_exec(sc->sc_tag, I2C_OP_WRITE_WITH_STOP,
+		    sc->sc_address, &reg, 1, &val, 1, 0)) {
+			aprint_error_dev(sc->sc_dev,
+			    "unable to write config register\n");
+			iic_release_bus(sc->sc_tag, 0);
+			return;
+		}
+	}
+
+	iic_release_bus(sc->sc_tag, 0);
+
+	sc->sc_sme = sysmon_envsys_create();
+	sc->sc_sme->sme_name = device_xname(self);
+	sc->sc_sme->sme_cookie = sc;
+	sc->sc_sme->sme_refresh = lm95221ts_refresh;
+
+	strlcpy(sc->sc_sensor[LM95221_LOCAL].desc, "local",
+	    sizeof(sc->sc_sensor[LM95221_LOCAL].desc));
+	sc->sc_reg_m[LM95221_LOCAL] = LM95221_LOCAL_MSB;
+	sc->sc_reg_l[LM95221_LOCAL] = LM95221_LOCAL_LSB;
+
+	strlcpy(sc->sc_sensor[LM95221_REMOTE1].desc, "remote 1",
+	    sizeof(sc->sc_sensor[LM95221_REMOTE1].desc));
+	sc->sc_reg_m[LM95221_REMOTE1] = LM95221_REMOTE1_MSB;
+	sc->sc_reg_l[LM95221_REMOTE1] = LM95221_REMOTE1_LSB;
+
+	strlcpy(sc->sc_sensor[LM95221_REMOTE2].desc, "remote 2",
+	    sizeof(sc->sc_sensor[LM95221_REMOTE2].desc));
+	sc->sc_reg_m[LM95221_REMOTE2] = LM95221_REMOTE2_MSB;
+	sc->sc_reg_l[LM95221_REMOTE2] = LM95221_REMOTE2_LSB;
+
+	for (i = 0; i < LM95221_NSENSORS; i++) {
+		if (i == LM95221_REMOTE1 &&
+		    (sc->sc_flags[LM95221_REMOTE1] & LM95221_MISSING))
+			continue;
+		if (i == LM95221_REMOTE2 &&
+		    (sc->sc_flags[LM95221_REMOTE2] & LM95221_MISSING))
+			continue;
+
+		sc->sc_sensor[i].units = ENVSYS_STEMP;
+		sc->sc_sensor[i].state = ENVSYS_SINVALID;
+		sc->sc_sensor[i].flags = ENVSYS_FHAS_ENTROPY;
+
+		if (sysmon_envsys_sensor_attach(sc->sc_sme,
+		    &sc->sc_sensor[i])) {
+			sysmon_envsys_destroy(sc->sc_sme);
+			sc->sc_sme = NULL;
+			aprint_error_dev(sc->sc_dev,
+			    "unable to attach sensor %d to sysmon\n", i);
+			return;
+		}
+		map = sc->sc_sensor[i].sensor;
+		sc->sc_map[map] = i;
+	}
+
+	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;
+	}
+}
+
+static int
+lm95221ts_detach(device_t self, int flags)
+{
+	struct lm95221ts_softc *sc = device_private(self);
+
+	if (sc->sc_sme != NULL) {
+		sysmon_envsys_unregister(sc->sc_sme);
+		sc->sc_sme = NULL;
+	}
+
+	return 0;
+}
+
+void
+lm95221ts_refresh(struct sysmon_envsys *sme, envsys_data_t *edata)
+{
+	struct lm95221ts_softc *sc = sme->sme_cookie;
+	uint32_t val;
+	uint8_t reg_m, reg_l, flags;
+	int map;
+
+	map = sc->sc_map[edata->sensor];
+	reg_m = sc->sc_reg_m[map];
+	reg_l = sc->sc_reg_l[map];
+	flags = sc->sc_flags[map];
+
+	if (iic_acquire_bus(sc->sc_tag, 0))
+		return;
+
+	if (lm95221ts_read_temp(sc, reg_m, reg_l, flags, &val) == 0) {
+		edata->value_cur = val;
+		edata->state = ENVSYS_SVALID;
+	} else {
+		edata->state = ENVSYS_SINVALID;
+	}
+
+	iic_release_bus(sc->sc_tag, 0);
+}
+
+static int
+lm95221ts_read_temp(struct lm95221ts_softc *sc, uint8_t reg_m, uint8_t reg_l,
+    uint8_t flags, uint32_t *valp)
+{
+	uint8_t buf_m, buf_l;
+	int err;
+
+	err = iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP,
+	    sc->sc_address, &reg_m, 1, &buf_m, 1, 0);
+	if (err)
+		return err;
+	err = iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP,
+	    sc->sc_address, &reg_l, 1, &buf_l, 1, 0);
+	if (err)
+		return err;
+
+	/*
+	 * Convert the 11 high bits from the 2 bytes to a temperature in uK.
+	 * Maybe sign-extend the MSB, and add in the LSB
+	 */
+	if (flags & LM95221_SIGNED)
+		*valp = buf_m;
+	else
+		*valp = (int8_t) buf_m;
+	*valp = (*valp << 3) + ((buf_l >> 5) & 0x07);
+	*valp = *valp * 125000 + 273150000;
+
+	return 0;
+}
--- src/sys/dev/i2c/lm95221reg.h.dist	2026-02-10 22:20:01.329986410 +0100
+++ src/sys/dev/i2c/lm95221reg.h	2026-02-03 07:36:19.779992263 +0100
@@ -0,0 +1,102 @@
+/* $NetBSD$ */
+
+/*-
+ * Copyright (c) 2026 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Julian Coleman.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _DEV_I2C_LM95221REG_H_
+#define _DEV_I2C_LM95221REG_H_
+
+/* LM95221 temperature sensor register definitions */
+
+#define	LM95221_ADDR		0x2b
+
+/*
+ * Temperature on the LM95221 is represented by a 10-bit (local) and 11-bit
+ * (remote) 2's complement word or 11-bit (remote) unsigned binary word
+ * with an LSB of 0.125C.  The data is left-justified in 2 * 8-bit registers.
+ *
+ * 11-bit 2's complement:
+ *
+ *	+125C	0111 1101 0000 0000	0x7d00
+ *	+25C	0001 1001 0000 0000	0x1900
+ *	+1C	0000 0001 0000 0000	0x0100
+ *      +0.125C	0000 0000 0010 0000	0x0020
+ *	 0C	0000 0000 0000 0000	0x0000
+ *      -0.125C	1111 1111 1110 0000	0xffe0
+ *	-1C	1111 1111 0000 0000	0xff00
+ *	-25C	1110 0111 0000 0000	0xe700
+ *	-55C	1100 1001 0000 0000	0xc900
+ *
+ * 11-bit unsigned binary:
+ *
+ *    +255.875C	1111 1111 1110 0000	0xffe0
+ *	+255C	1111 1111 0000 0000	0xff90
+ *	+201C	1100 1001 0000 0000	0xc900
+ *	+125C	0111 1101 0000 0000	0x7d00
+ *	+25C	0001 1001 0000 0000	0x1900
+ *	+1C	0000 0001 0000 0000	0x0100
+ *      +0.125C	0000 0000 0010 0000	0x0020
+ *	 0C	0000 0000 0000 0000	0x0000
+ *
+ * 10-bit 2's complement is similar to 11-bit 2's complement
+ * (but with 0.25C resolution)
+ */
+
+/* Command bits 0-2 select the register */
+#define	LM95221_STATUS		0x02	/* Status */
+#define	LM95221_CONFIG		0x03	/* Configuration */
+#define	LM95221_1SHOT		0x0f	/* One conversion when in standby */
+#define	LM95221_LOCAL_MSB	0x10	/* Reading MSB locks LSB 0x20 */
+#define	LM95221_REMOTE1_MSB	0x11	/* Reading MSB locks LSB 0x21 */
+#define	LM95221_REMOTE2_MSB	0x12	/* Reading MSB locks LSB 0x22 */
+#define	LM95221_LOCAL_LSB	0x20	/* Reading LSB unlocks it */
+#define	LM95221_REMOTE1_LSB	0x21	/* Reading LSB unlocks it */
+#define	LM95221_REMOTE2_LSB	0x22	/* Reading LSB unlocks it */
+#define	LM95221_MANUF		0xfe	/* Manufacturer ID (0x01) */
+#define	LM95221_REVISION	0xff	/* Manufacturer ID (0x61) */
+
+/* Status register */
+#define LM95221_STAT_NO_REMOTE1	0x01	/* Remote 1 diode missing */
+#define LM95221_STAT_NO_REMOTE2	0x02	/* Remote 1 diode missing */
+#define LM95221_STAT_BUSY	0x80	/* Currently converting */
+
+/* Configuration register */
+#define LM95221_CONF_REMOTE1	0x02	/* Remote 1 signed format */
+#define LM95221_CONF_REMOTE2	0x04	/* Remote 2 signed format */
+#define LM95221_CONF_CONVRATE	0x30	/* Conversion rate */
+#define LM95221_CONF_STANDBY	0x40	/* Disable conversions */
+#define LM95221_CONVRATE_CONT	0x00	/* Continuous every 66ms */
+#define LM95221_CONVRATE_200	0x10	/* Every 200ms */
+#define LM95221_CONVRATE_1000	0x20	/* Every 1s */
+#define LM95221_CONVRATE_3000	0x30	/* Every 3s */
+
+/* Temperature registers */
+#define LM95221_NSENSORS	3
+
+#endif /* _DEV_I2C_LM95221REG_H_ */
--- src/sys/dev/i2c/nxp75a.c.dist	2026-02-10 22:20:01.319986410 +0100
+++ src/sys/dev/i2c/nxp75a.c	2026-02-16 16:23:02.039999177 +0100
@@ -0,0 +1,305 @@
+/* $NetBSD$ */
+
+/*-
+ * Copyright (c) 2026 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Julian Coleman.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__KERNEL_RCSID(0, "$NetBSD$");
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/device.h>
+#include <sys/kernel.h>
+#include <sys/sysctl.h>
+
+#include <dev/sysmon/sysmonvar.h>
+
+#include <dev/i2c/i2cvar.h>
+#include <dev/i2c/nxp75areg.h>
+
+struct nxp75a_softc {
+	device_t sc_dev;
+	i2c_tag_t sc_tag;
+	int sc_address;
+
+	struct sysmon_envsys *sc_sme;
+	envsys_data_t sc_sensor;
+	uint32_t sc_otemp, sc_hyst;
+};
+
+static int  nxp75a_match(device_t, cfdata_t, void *);
+static void nxp75a_attach(device_t, device_t, void *);
+static int nxp75a_detach(device_t, int);
+void	nxp75a_refresh(struct sysmon_envsys *, envsys_data_t *);
+void    nxp75a_get_limits(struct sysmon_envsys *, envsys_data_t *,
+		    sysmon_envsys_lim_t *, uint32_t *);
+void    nxp75a_set_limits(struct sysmon_envsys *, envsys_data_t *,
+		    sysmon_envsys_lim_t *, uint32_t *);
+static int nxp75a_read_temp(struct nxp75a_softc *, uint8_t, uint32_t *);
+static int nxp75a_write_temp(struct nxp75a_softc *, uint8_t, uint32_t);
+
+CFATTACH_DECL_NEW(nxp75a, sizeof(struct nxp75a_softc),
+	nxp75a_match, nxp75a_attach, nxp75a_detach, NULL);
+
+
+static const struct device_compatible_entry compat_data[] = {
+	{ .compat = "i2c-lm75a" },
+	DEVICE_COMPAT_EOL
+};
+
+static int
+nxp75a_match(device_t parent, cfdata_t cf, void *aux)
+{
+	struct i2c_attach_args *ia = aux;
+	int match_result;
+
+	if (iic_use_direct_match(ia, cf, compat_data, &match_result))
+		return match_result;
+
+	/*
+	 * Indirect config - assume config is correct!
+	 */
+	if ((ia->ia_addr & NXP75A_ADDRMASK) == NXP75A_ADDR)
+		return I2C_MATCH_ADDRESS_ONLY;
+
+	return 0;
+}
+
+static void
+nxp75a_attach(device_t parent, device_t self, void *aux)
+{
+	struct nxp75a_softc *sc = device_private(self);
+	struct i2c_attach_args *ia = aux;
+	uint8_t reg, val;
+	uint32_t tval;
+
+	sc->sc_tag = ia->ia_tag;
+	sc->sc_address = ia->ia_addr;
+	sc->sc_dev = self;
+
+	aprint_normal(": NXP LM75A temperature sensor\n");
+
+	if (iic_acquire_bus(sc->sc_tag, 0)) {
+		aprint_error_dev(self,
+		    "unable to acquire I2C bus\n");
+		return;
+	}
+
+	/* Read and save overtemp (critical limit) and hysteresis */
+	reg = NXP75A_OVERTEMP;
+	if (nxp75a_read_temp(sc, reg, &tval)) {
+		iic_release_bus(sc->sc_tag, 0);
+		aprint_error_dev(sc->sc_dev,
+		    "unable to read overtemp register\n");
+		return;
+	}
+	sc->sc_otemp = tval;
+	reg = NXP75A_THYST;
+	if (nxp75a_read_temp(sc, reg, &tval)) {
+		iic_release_bus(sc->sc_tag, 0);
+		aprint_error_dev(sc->sc_dev,
+		    "unable to read hysteresis register\n");
+		return;
+	}
+	sc->sc_hyst = tval;
+
+	/* Read config, start conversion */
+	reg = NXP75A_CONFIG;
+	if (iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP,
+	    sc->sc_address, &reg, 1, &val, 1, 0)) {
+		iic_release_bus(sc->sc_tag, 0);
+		aprint_error_dev(sc->sc_dev,
+		    "unable to read config register\n");
+		return;
+	}
+
+	if (val & NXP75A_CONF_SHUTDOWN) {
+		val &= ~(NXP75A_CONF_SHUTDOWN);
+		if (iic_exec(sc->sc_tag, I2C_OP_WRITE_WITH_STOP,
+		    sc->sc_address, &reg, 1, &val, 1, 0)) {
+			iic_release_bus(sc->sc_tag, 0);
+			aprint_error_dev(sc->sc_dev,
+			    "unable to write config register\n");
+			return;
+		}
+	}
+
+	iic_release_bus(sc->sc_tag, 0);
+
+	sc->sc_sme = sysmon_envsys_create();
+	sc->sc_sme->sme_name = device_xname(self);
+	sc->sc_sme->sme_cookie = sc;
+	sc->sc_sme->sme_refresh = nxp75a_refresh;
+	sc->sc_sme->sme_get_limits = nxp75a_get_limits;
+	sc->sc_sme->sme_set_limits = nxp75a_set_limits;
+
+	strlcpy(sc->sc_sensor.desc, "temperature", sizeof(sc->sc_sensor.desc));
+	sc->sc_sensor.units = ENVSYS_STEMP;
+	sc->sc_sensor.state = ENVSYS_SINVALID;
+	sc->sc_sensor.flags = ENVSYS_FMONLIMITS | ENVSYS_FHAS_ENTROPY;
+
+	if (sysmon_envsys_sensor_attach(sc->sc_sme, &sc->sc_sensor)) {
+		sysmon_envsys_destroy(sc->sc_sme);
+		sc->sc_sme = NULL;
+		aprint_error_dev(sc->sc_dev,
+		    "unable to attach sensor to sysmon\n");
+		return;
+	}
+
+	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;
+	}
+}
+
+static int
+nxp75a_detach(device_t self, int flags)
+{
+	struct nxp75a_softc *sc = device_private(self);
+
+	if (sc->sc_sme != NULL) {
+		sysmon_envsys_unregister(sc->sc_sme);
+		sc->sc_sme = NULL;
+	}
+
+	return 0;
+}
+
+void
+nxp75a_refresh(struct sysmon_envsys *sme, envsys_data_t *edata)
+{
+	struct nxp75a_softc *sc = sme->sme_cookie;
+	uint8_t reg;
+	uint32_t val;
+
+	if (iic_acquire_bus(sc->sc_tag, 0))
+		return;
+
+	reg = NXP75A_TEMP;
+	if (nxp75a_read_temp(sc, reg, &val) == 0) {
+		edata->value_cur = val;
+		edata->state = ENVSYS_SVALID;
+	} else {
+		edata->state = ENVSYS_SINVALID;
+	}
+
+	iic_release_bus(sc->sc_tag, 0);
+}
+
+void
+nxp75a_get_limits(struct sysmon_envsys *sme, envsys_data_t *edata,
+    sysmon_envsys_lim_t *limits, uint32_t *props)
+{
+	struct nxp75a_softc *sc = sme->sme_cookie;
+	uint8_t reg;
+	uint32_t val;
+
+	*props &= ~(PROP_CRITMAX | PROP_WARNMAX | PROP_WARNMIN);
+
+	if (iic_acquire_bus(sc->sc_tag, 0))
+		return;
+
+	reg = NXP75A_OVERTEMP;
+	if (nxp75a_read_temp(sc, reg, &val) == 0) {
+		limits->sel_critmax = val;
+		*props |= PROP_CRITMAX;
+	}
+
+	iic_release_bus(sc->sc_tag, 0);
+}
+
+void
+nxp75a_set_limits(struct sysmon_envsys *sme, envsys_data_t *edata,
+    sysmon_envsys_lim_t *limits, uint32_t *props)
+{
+	struct nxp75a_softc *sc = sme->sme_cookie;
+	uint8_t reg;
+	uint32_t otemp, hyst;
+
+	if (iic_acquire_bus(sc->sc_tag, 0))
+		return;
+
+	if (*props & PROP_CRITMAX) {
+		if (limits == NULL) {	/* Restore defaults */
+			otemp = sc->sc_otemp;
+			hyst = sc->sc_hyst;
+		} else {
+			otemp = limits->sel_critmax;
+			/* Make sure that hyst is less than overtemp */
+			hyst = otemp - (sc->sc_otemp - sc->sc_hyst);
+		}
+		reg = NXP75A_OVERTEMP;
+		if (nxp75a_write_temp(sc, reg, otemp) == 0) {
+			reg = NXP75A_THYST;
+			nxp75a_write_temp(sc, reg, hyst);
+		}
+	}
+			
+	iic_release_bus(sc->sc_tag, 0);
+}
+
+static int
+nxp75a_read_temp(struct nxp75a_softc *sc, uint8_t reg, uint32_t *valp)
+{
+	uint8_t buf[NXP75A_TEMP_LEN];
+	int err;
+
+	err = iic_exec(sc->sc_tag, I2C_OP_READ_WITH_STOP,
+	    sc->sc_address, &reg, 1, buf, NXP75A_TEMP_LEN, 0);
+	if (err)
+		return err;
+
+	/*
+	 * Convert the 11 high bits from the 2 bytes to a temperature in uK.
+	 * Sign-extend the MSB and add in the LSB
+	 */
+	*valp = (int8_t) buf[0];
+	*valp = (*valp << 3) + ((buf[1] >> 5) & 0x07);
+	*valp = *valp * 125000 + 273150000;
+
+	return 0;
+}
+
+static int
+nxp75a_write_temp(struct nxp75a_softc *sc, uint8_t reg, uint32_t val)
+{
+	uint8_t buf[NXP75A_TEMP_LEN];
+	uint32_t temp;
+
+	/* Convert the temperature in uK to 11 high bits in 2 bytes.*/
+	temp = (int) (val - 273150000) / 125000 ;
+	buf[0] = (temp >> 3) & 0xff;
+	buf[1] = (temp << 5) & 0xe0;
+
+	return iic_exec(sc->sc_tag, I2C_OP_WRITE_WITH_STOP,
+	    sc->sc_address, &reg, 1, buf, NXP75A_TEMP_LEN, 0);
+}
+
--- src/sys/dev/i2c/nxp75areg.h.dist	2026-02-10 22:20:01.329986410 +0100
+++ src/sys/dev/i2c/nxp75areg.h	2026-02-16 16:18:22.169999344 +0100
@@ -0,0 +1,82 @@
+/* $NetBSD$ */
+
+/*-
+ * Copyright (c) 2026 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Julian Coleman.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _DEV_I2C_NXP75AREG_H_
+#define _DEV_I2C_NXP75AREG_H_
+
+/*
+ * *NXP* LM75A temperature sensor register definitions.
+ * Pin compatible but not the same as the *TI* LM75A.
+ */
+
+#define	NXP75A_ADDRMASK		0x3f8
+#define	NXP75A_ADDR		0x48
+
+/*
+ * Temperature on the NXP LM75A is represented by a 11-bit two's complement
+ * word with the LSB equal to 0.125C.  From the data sheet:
+ *
+ *	+127C	011 1111 1000	0x3f8
+ *    +126.875C	011 1111 0111	0x3f7
+ *    +126.125C	011 1111 0001	0x3f1
+ *	+125C	011 1110 1000	0x3e8
+ *	+25C	000 1100 1000	0x9c8
+ *      +0.125C	000 0000 0001	0x001
+ *	 0C	000 0000 0000	0x000
+ *      -0.125C	111 1111 1111	0x7ff
+ *	-25C	111 0011 1000	0x738
+ *     -54.875C	110 0100 1001	0x649
+ *	-55C	110 0100 1000	0x648
+ *
+ * The bits are left-shifted to take the high 11 bits of the 2 registers.
+ */
+
+/* Command bits 0-2 select the register */
+#define	NXP75A_TEMP		0x00
+#define	NXP75A_CONFIG		0x01
+#define	NXP75A_THYST		0x02
+#define	NXP75A_OVERTEMP		0x03
+
+/* Configuration register */
+#define NXP75A_CONF_SHUTDOWN	(1 << 0)	/* Shutdown mode */
+#define NXP75A_CONF_OS_MODE_INT	(1 << 1)	/* OS interrupt mode*/
+#define NXP75A_CONF_OS_MODE_CMP	(1 << 0)	/* OS comparator mode*/
+#define NXP75A_CONF_OS_POL_HIGH	(2 << 1)	/* OS polarity high */
+#define NXP75A_CONF_OS_POL_LOW	(2 << 0)	/* OS polarity low */
+#define NXP75A_CONF_OS_FLTQ_1	(0 << 3)	/* OS fault queue len 1 */
+#define NXP75A_CONF_OS_FLTQ_2	(1 << 3)	/* OS fault queue len 2 */
+#define NXP75A_CONF_OS_FLTQ_4	(2 << 3)	/* OS fault queue len 4 */
+#define NXP75A_CONF_OS_FLTQ_6	(3 << 3)	/* OS fault queue len 6 */
+
+#define NXP75A_TEMP_LEN		2	/* 2 bytes for temperatures */
+#define NXP75A_CONF_LEN		1	/* 1 byte for configuration */
+
+#endif /* _DEV_I2C_NXP75AREG_H_ */
--- src/share/man/man4/lm95221ts.4.dist	2026-02-13 21:47:41.837831341 +0100
+++ src/share/man/man4/lm95221ts.4	2026-02-13 21:57:34.017830988 +0100
@@ -0,0 +1,63 @@
+.\"	$NetBSD$
+.\"
+.\" Copyright (c) 2026 The NetBSD Foundation, Inc.
+.\" All rights reserved.
+.\"
+.\" This code is derived from software contributed to The NetBSD Foundation
+.\" by Julian Coleman.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\"    notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\"    notice, this list of conditions and the following disclaimer in the
+.\"    documentation and/or other materials provided with the distribution.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+.\" ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+.\" TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+.\" PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+.\" BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+.\" CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+.\" SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+.\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+.\" CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+.\" ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+.\" POSSIBILITY OF SUCH DAMAGE.
+.\"
+.Dd February 13, 2026
+.Dt LM95221TS 4
+.Os
+.Sh NAME
+.Nm lm95221ts
+.Nd LM95221 Dual Remote Diode Digital Temperature Sensor
+.Sh SYNOPSIS
+.Cd "lm95221ts* at iic? addr?"
+.Sh DESCRIPTION
+The
+.Nm
+driver provides support for the Texas Instruments LM95221
+temperature sensor, which supports a local and two remote temperature
+sensors.
+The local sensor has a resolution of 0.25 degC whilst the remote
+sensors have a resolution of 0.125 degC.
+The temperature values are available through the 
+.Xr envstat 8
+interface.
+.Sh SEE ALSO
+.Xr envsys 4 ,
+.Xr iic 4 ,
+.Xr intro 4 ,
+.Xr envstat 8
+.Sh HISTORY
+The
+.Nm
+driver first appeared in
+.Nx 11.0 .
+.Sh AUTHORS
+The
+.Nm
+driver was written by
+.An Julian Coleman Aq Mt jcoleman@netbsd.org .
--- src/share/man/man4/nxp75a.4.dist	2026-02-13 21:47:02.827831364 +0100
+++ src/share/man/man4/nxp75a.4	2026-02-16 16:26:20.019999059 +0100
@@ -0,0 +1,69 @@
+.\"	$NetBSD$
+.\"
+.\" Copyright (c) 2026 The NetBSD Foundation, Inc.
+.\" All rights reserved.
+.\"
+.\" This code is derived from software contributed to The NetBSD Foundation
+.\" by Julian Coleman.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\"    notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\"    notice, this list of conditions and the following disclaimer in the
+.\"    documentation and/or other materials provided with the distribution.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+.\" ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+.\" TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+.\" PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+.\" BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+.\" CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+.\" SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+.\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+.\" CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+.\" ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+.\" POSSIBILITY OF SUCH DAMAGE.
+.\"
+.Dd February 13, 2026
+.Dt NXP75A 4
+.Os
+.Sh NAME
+.Nm nxp75a
+.Nd NXP LM75A Digital temperature sensor and thermal watchdog
+.Sh SYNOPSIS
+.Cd "nxp75a* at iic? addr?"
+.Sh DESCRIPTION
+The
+.Nm
+driver provides support for the NXP LM75A temperature sensor,
+with a temperature resolution of 0.125 degC and a single
+programable high limit.
+Both the temperature value and the limit are available through the
+.Xr envstat 8
+interface.
+.Pp
+Note, that although this chip is described as a
+.Qq pin-for-pin replacement for industry standard LM75
+it is not software compatible with it.
+The LM75 and similar chips are supported via the
+.Xr lmtemp 4
+driver.
+.Sh SEE ALSO
+.Xr envsys 4 ,
+.Xr iic 4 ,
+.Xr intro 4 ,
+.Xr lmtemp 4 ,
+.Xr envstat 8
+.Sh HISTORY
+The
+.Nm
+driver first appeared in
+.Nx 11.0 .
+.Sh AUTHORS
+The
+.Nm
+driver was written by
+.An Julian Coleman Aq Mt jcoleman@netbsd.org .
--- src/share/man/man4/pcagpio.4.dist	2026-02-13 21:10:09.207832683 +0100
+++ src/share/man/man4/pcagpio.4	2026-02-13 21:44:37.017831451 +0100
@@ -0,0 +1,64 @@
+.\"	$NetBSD$
+.\"
+.\" Copyright (c) 2020 The NetBSD Foundation, Inc.
+.\" All rights reserved.
+.\"
+.\" This code is derived from software contributed to The NetBSD Foundation
+.\" by Julian Coleman.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\"    notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\"    notice, this list of conditions and the following disclaimer in the
+.\"    documentation and/or other materials provided with the distribution.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+.\" ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+.\" TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+.\" PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+.\" BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+.\" CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+.\" SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+.\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+.\" CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+.\" ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+.\" POSSIBILITY OF SUCH DAMAGE.
+.\"
+.Dd November 15, 2020
+.Dt PCAGPIO 4
+.Os
+.Sh NAME
+.Nm pcagpio
+.Nd Philips Semiconductors PCA9555 and PCA9556 GPIO controller
+.Sh SYNOPSIS
+.Cd "pcagpio* at iic? addr?"
+.Sh DESCRIPTION
+The
+.Nm
+driver provides support for the 8-pin PCA9555 and 16-pin PCA9556
+GPIO controllers.
+System properties are used to configure the pins as LED's or sensors
+which are then exposed via the
+.Xr led
+or
+.Xr envsys
+frameworks.
+.Sh SEE ALSO
+.Xr envsys 4 ,
+.Xr iic 4 ,
+.Xr intro 4 ,
+.Xr led 4 ,
+.Xr envstat 8
+.Sh HISTORY
+The
+.Nm
+driver first appeared in
+.Nx 10.0 .
+.Sh AUTHORS
+The
+.Nm
+driver was written by
+.An Michael Lorenz Aq Mt macallan@netbsd.org .
--- src/share/man/man4/pcf8574io.4.dist	2026-02-13 21:10:25.747832674 +0100
+++ src/share/man/man4/pcf8574io.4	2026-02-13 21:45:27.037831421 +0100
@@ -0,0 +1,67 @@
+.\"	$NetBSD$
+.\"
+.\" Copyright (c) 2020 The NetBSD Foundation, Inc.
+.\" All rights reserved.
+.\"
+.\" This code is derived from software contributed to The NetBSD Foundation
+.\" by Julian Coleman.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\"    notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\"    notice, this list of conditions and the following disclaimer in the
+.\"    documentation and/or other materials provided with the distribution.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+.\" ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+.\" TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+.\" PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+.\" BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+.\" CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+.\" SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+.\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+.\" CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+.\" ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+.\" POSSIBILITY OF SUCH DAMAGE.
+.\"
+.Dd February 13, 2026
+.Dt PCF8754IO 4
+.Os
+.Sh NAME
+.Nm pcf8574io
+.Nd Philips Semiconductors PCF8574 and PCF857A GPIO Controllers
+.Sh SYNOPSIS
+.Cd "pcf8574io* at iic? addr?"
+.Sh DESCRIPTION
+The
+.Nm
+driver provides support for the PCF8574 and PCF857A
+GPIO controllers.
+These differ only in their address on the i2c bus.
+System properties are used to configure the pins as LED's or sensors
+which are then exposed via the
+.Xr led
+or
+.Xr envsys
+frameworks.
+If any pins are configured as alert sensors, then a console message
+will be printed if the pin status changes.
+.Sh SEE ALSO
+.Xr envsys 4 ,
+.Xr iic 4 ,
+.Xr intro 4 ,
+.Xr led 4 ,
+.Xr envstat 8
+.Sh HISTORY
+The
+.Nm
+driver first appeared in
+.Nx 10.0 .
+.Sh AUTHORS
+The
+.Nm
+driver was written by
+.An Julian Coleman Aq Mt jcoleman@netbsd.org .
