Index: src/sys/dev/i2c/dbcool.c
===================================================================
RCS file: /cvsroot/src/sys/dev/i2c/dbcool.c,v
retrieving revision 1.69
diff -u -r1.69 dbcool.c
--- src/sys/dev/i2c/dbcool.c	7 Jul 2026 12:42:58 -0000	1.69
+++ src/sys/dev/i2c/dbcool.c	29 Jul 2026 09:22:30 -0000
@@ -73,7 +73,7 @@
 
 /* Sensor read functions */
 static void dbcool_refresh(struct sysmon_envsys *, envsys_data_t *);
-static int dbcool_read_rpm(struct dbcool_softc *, uint8_t);
+static int dbcool_read_rpm(struct dbcool_softc *, uint8_t, int);
 static int dbcool_read_temp(struct dbcool_softc *, uint8_t, bool);
 static int dbcool_read_volt(struct dbcool_softc *, uint8_t, int, bool);
 
@@ -107,8 +107,9 @@
 static int sysctl_dbcool_thyst(SYSCTLFN_PROTO);
 
 /* Set-up subroutines */
+static int  dbcool_set_fan_divider(struct dbcool_chipset *, int, uint8_t);
 static void dbcool_setup_controllers(struct dbcool_softc *);
-static int  dbcool_setup_sensors(struct dbcool_softc *);
+static int  dbcool_setup_sensors(struct dbcool_softc *, prop_dictionary_t);
 static int  dbcool_attach_sensor(struct dbcool_softc *, int);
 static int  dbcool_attach_temp_control(struct dbcool_softc *, int,
 	struct chip_id *);
@@ -538,6 +539,12 @@
 	{ DBC_EOF,  {0, 0, 0 }, 0, 0, 0 }
 };
 
+struct dbcool_fan_div ADM1030_fan_div_table[] = {
+	{ 0x08, 0x20 },
+	{ 0x09, 0x21 },
+	{ 0, 0 }
+};
+
 struct dbcool_power_control ADM1030_power_table[] = {
 	{ { DBCOOL_ADM1030_CFG1,  DBCOOL_NO_REG, DBCOOL_NO_REG,
 	    DBCOOL_ADM1030_FAN_SPEED_CFG },
@@ -664,60 +671,62 @@
 
 struct chip_id chip_table[] = {
 	{ DBCOOL_COMPANYID, ADT7490_DEVICEID, ADT7490_REV_ID,
-		ADT7490_sensor_table, ADT7475_power_table,
+		ADT7490_sensor_table, ADT7475_power_table, NULL,
 		DBCFLAG_TEMPOFFSET | DBCFLAG_HAS_MAXDUTY | DBCFLAG_HAS_PECI,
 		90000 * 60, "ADT7490" },
 	{ DBCOOL_COMPANYID, ADT7476_DEVICEID, 0xff,
-		ADT7476_sensor_table, ADT7475_power_table,
+		ADT7476_sensor_table, ADT7475_power_table, NULL,
 		DBCFLAG_TEMPOFFSET | DBCFLAG_HAS_MAXDUTY,
 		90000 * 60, "ADT7476" },
 	{ DBCOOL_COMPANYID, ADT7475_DEVICEID, 0xff,
-		ADT7475_sensor_table, ADT7475_power_table,
+		ADT7475_sensor_table, ADT7475_power_table, NULL,
 		DBCFLAG_TEMPOFFSET | DBCFLAG_HAS_MAXDUTY | DBCFLAG_HAS_SHDN,
 		90000 * 60, "ADT7475" },
 	{ DBCOOL_COMPANYID, ADT7473_DEVICEID, ADT7473_REV_ID1,
-		ADT7475_sensor_table, ADT7475_power_table,
+		ADT7475_sensor_table, ADT7475_power_table, NULL,
 		DBCFLAG_TEMPOFFSET | DBCFLAG_HAS_MAXDUTY | DBCFLAG_HAS_SHDN,
 		90000 * 60, "ADT7460/ADT7463" },
 	{ DBCOOL_COMPANYID, ADT7473_DEVICEID, ADT7473_REV_ID2,
-		ADT7475_sensor_table, ADT7475_power_table,
+		ADT7475_sensor_table, ADT7475_power_table, NULL,
 		DBCFLAG_TEMPOFFSET | DBCFLAG_HAS_MAXDUTY | DBCFLAG_HAS_SHDN,
 		90000 * 60, "ADT7463-1" },
 	{ DBCOOL_COMPANYID, ADT7468_DEVICEID, 0xff,
-		ADT7476_sensor_table, ADT7475_power_table,
+		ADT7476_sensor_table, ADT7475_power_table, NULL,
 		DBCFLAG_TEMPOFFSET  | DBCFLAG_MULTI_VCC | DBCFLAG_HAS_MAXDUTY |
 		    DBCFLAG_4BIT_VER | DBCFLAG_HAS_SHDN,
 		90000 * 60, "ADT7467/ADT7468" },
 	{ DBCOOL_COMPANYID, ADT7466_DEVICEID, 0xff,
-		ADT7466_sensor_table, NULL,
+		ADT7466_sensor_table, NULL, NULL,
 		DBCFLAG_ADT7466 | DBCFLAG_TEMPOFFSET | DBCFLAG_HAS_SHDN,
 		82000 * 60, "ADT7466" },
 	{ DBCOOL_COMPANYID, ADT7463_DEVICEID, ADT7463_REV_ID1,
-		ADM1027_sensor_table, ADT7475_power_table,
+		ADM1027_sensor_table, ADT7475_power_table, NULL,
 		DBCFLAG_MULTI_VCC | DBCFLAG_4BIT_VER | DBCFLAG_HAS_SHDN,
 		90000 * 60, "ADT7463" },
 	{ DBCOOL_COMPANYID, ADT7463_DEVICEID, ADT7463_REV_ID2,
-		ADM1027_sensor_table, ADT7475_power_table,
+		ADM1027_sensor_table, ADT7475_power_table, NULL,
 		DBCFLAG_MULTI_VCC | DBCFLAG_4BIT_VER | DBCFLAG_HAS_SHDN |
 		    DBCFLAG_HAS_VID_SEL,
 		90000 * 60, "ADT7463" },
 	{ DBCOOL_COMPANYID, ADM1027_DEVICEID, ADM1027_REV_ID,
-		ADM1027_sensor_table, ADT7475_power_table,
+		ADM1027_sensor_table, ADT7475_power_table, NULL,
 		DBCFLAG_MULTI_VCC | DBCFLAG_4BIT_VER,
 		90000 * 60, "ADM1027" },
 	{ DBCOOL_COMPANYID, ADM1030_DEVICEID, 0xff,
 		ADM1030_sensor_table, ADM1030_power_table,
-		DBCFLAG_ADM1030 | DBCFLAG_NO_READBYTE,
+		ADM1030_fan_div_table,
+		DBCFLAG_ADM1030 | DBCFLAG_NO_READBYTE | DBCFLAG_HAS_FANDIV,
 		11250 * 60, "ADM1030" },
 	{ DBCOOL_COMPANYID, ADM1031_DEVICEID, 0xff,
 		ADM1031_sensor_table, ADM1030_power_table,
-		DBCFLAG_ADM1030 | DBCFLAG_NO_READBYTE,
+		ADM1030_fan_div_table,
+		DBCFLAG_ADM1030 | DBCFLAG_NO_READBYTE | DBCFLAG_HAS_FANDIV,
 		11250 * 60, "ADM1031" },
 	{ SMSC_COMPANYID, EMC6D103S_DEVICEID, EMC6D103S_REV_ID,
-		EMC6D103S_sensor_table, ADT7475_power_table,
+		EMC6D103S_sensor_table, ADT7475_power_table, NULL,
 		DBCFLAG_4BIT_VER,
 		90000 * 60, "EMC6D103S" },
-	{ 0, 0, 0, NULL, NULL, 0, 0, NULL }
+	{ 0, 0, 0, NULL, NULL, NULL, 0, 0, NULL }
 };
 
 static const char *behavior[] = {
@@ -1004,7 +1013,7 @@
 }
 
 static int
-dbcool_read_rpm(struct dbcool_softc *sc, uint8_t reg)
+dbcool_read_rpm(struct dbcool_softc *sc, uint8_t reg, int fan_div)
 {
 	int rpm;
 	uint8_t rpm_lo, rpm_hi;
@@ -1020,7 +1029,8 @@
 		return 0;	/* 0xffff indicates stalled/failed fan */
 
 	/* don't divide by zero */
-	return (rpm == 0)? 0 : (sc->sc_dc.dc_chip->rpm_dividend / rpm);
+	return (rpm == 0)? 0 :
+	    (sc->sc_dc.dc_chip->rpm_dividend / rpm / fan_div);
 }
 
 /* Provide chip's supply voltage, in microvolts */
@@ -1536,7 +1546,7 @@
 
 	/* Create the sensors for this device */
 	sc->sc_sme = sysmon_envsys_create();
-	if (dbcool_setup_sensors(sc))
+	if (dbcool_setup_sensors(sc, device_properties(self)))
 		goto out;
 
 	if (sc->sc_root_sysctl_num != 0) {
@@ -1602,13 +1612,47 @@
 }
 
 static int
-dbcool_setup_sensors(struct dbcool_softc *sc)
+dbcool_set_fan_divider(struct dbcool_chipset *dcp, int flags, uint8_t fanchar_reg)
 {
-	int i;
+	uint8_t val;
+	int div;
+
+	div = 1;
+	val = dcp->dc_readreg(dcp, fanchar_reg);
+
+	if (flags & DBCFLAG_ADM1030) {
+		val &= DBCOOL_ADM1030_FANDIV_MASK;
+		switch (val)
+		{
+			case DBCOOL_ADM1030_FANDIV_8:
+				div = 8;
+				break;
+			case DBCOOL_ADM1030_FANDIV_4:
+				div = 4;
+				break;
+			case DBCOOL_ADM1030_FANDIV_2:
+				div = 2;
+				break;
+			case DBCOOL_ADM1030_FANDIV_1:
+			default:
+				div = 1;
+				break;
+		}
+	}
+	return div;
+}
+
+static int
+dbcool_setup_sensors(struct dbcool_softc *sc, prop_dictionary_t props)
+{
+	int i, j;
 	int error = 0;
-	uint8_t	vid_reg, vid_val;
+	uint8_t	vid_reg, vid_val, fanchar_reg;
+	uint16_t props_fan_div, div_val;
 	struct chip_id *chip = sc->sc_dc.dc_chip;
+	struct dbcool_fan_div *fan_div_table = chip->fan_div;
 
+	sc->sc_fan_num = 0;
 	for (i=0; chip->table[i].type != DBC_EOF; i++) {
 		if (i < DBCOOL_MAXSENSORS)
 			sc->sc_sysctl_num[i] = -1;
@@ -1642,11 +1686,43 @@
 			error = dbcool_attach_sensor(sc, i);
 			break;
 		case DBC_FAN:
+			/* Do we have a fan divider on the chip? */
+			fanchar_reg = 0;
+			if (chip->flags & DBCFLAG_HAS_FANDIV &&
+			    fan_div_table != NULL) {
+				for (j=0; fan_div_table[j].fan_reg != 0; j++)
+					if (chip->table[i].reg.val_reg ==
+					    fan_div_table[j].fan_reg)
+						fanchar_reg =
+						    fan_div_table[j].char_reg;
+			}
+			if (fanchar_reg)
+				sc->sc_fan_div[i] =
+				    dbcool_set_fan_divider(&sc->sc_dc,
+				    sc->sc_dc.dc_chip->flags, fanchar_reg);
+			else
+				sc->sc_fan_div[i] = 1;
+
+			/*
+			 * Do we have a fan divider property?
+			 * Each 4 bits contains a divider for that fan.
+			 * We only accept dividers up to 8x
+			 */
+			if (prop_dictionary_get_uint16(props,
+			    "fan_div", &props_fan_div) != 0) {
+				div_val =
+				    (props_fan_div >> (sc->sc_fan_num * 4))
+				    & 0x0f;
+				if (div_val > 1 && div_val < 9)
+					sc->sc_fan_div[i] *= div_val;
+			}
+
 			sc->sc_sensor[i].units = ENVSYS_SFANRPM;
 			sc->sc_sensor[i].state = ENVSYS_SINVALID;
 			sc->sc_sensor[i].flags |= ENVSYS_FMONLIMITS;
 			sc->sc_sensor[i].flags |= ENVSYS_FHAS_ENTROPY;
 			error = dbcool_attach_sensor(sc, i);
+			sc->sc_fan_num++;
 			break;
 		case DBC_VID:
 			sc->sc_sensor[i].units = ENVSYS_INTEGER;
@@ -1811,7 +1887,7 @@
 dbcool_refresh(struct sysmon_envsys *sme, envsys_data_t *edata)
 {
 	struct dbcool_softc *sc=sme->sme_cookie;
-	int i, nom_volt_idx, cur;
+	int i, nom_volt_idx, fan_div, cur;
 	struct reg_list *reg;
 
 	i = edata->sensor;
@@ -1829,7 +1905,8 @@
 						true);
 			break;
 		case ENVSYS_SFANRPM:
-			cur = dbcool_read_rpm(sc, reg->val_reg);
+			fan_div = sc->sc_fan_div[i];
+			cur = dbcool_read_rpm(sc, reg->val_reg, fan_div);
 			break;
 		case ENVSYS_INTEGER:
 			return;
@@ -2015,9 +2092,10 @@
 		      sysmon_envsys_lim_t *lims, uint32_t *props)
 {
 	struct reg_list *reg = sc->sc_regs[idx];
+	int fan_div = sc->sc_fan_div[idx];
 	int32_t	limit;
 
-	limit = dbcool_read_rpm(sc, reg->lo_lim_reg);
+	limit = dbcool_read_rpm(sc, reg->lo_lim_reg, fan_div);
 	if (limit) {
 		lims->sel_critmin = limit;
 		*props |= PROP_CRITMIN;
Index: src/sys/dev/i2c/dbcool_reg.h
===================================================================
RCS file: /cvsroot/src/sys/dev/i2c/dbcool_reg.h,v
retrieving revision 1.9
diff -u -r1.9 dbcool_reg.h
--- src/sys/dev/i2c/dbcool_reg.h	16 Apr 2020 23:29:53 -0000	1.9
+++ src/sys/dev/i2c/dbcool_reg.h	29 Jul 2026 09:22:30 -0000
@@ -362,6 +362,13 @@
 #define	DBCOOL_ADM1030_COMPANYID	DBCOOL_COMPANYID_REG
 #define	DBCOOL_ADM1030_REVISION		DBCOOL_REVISION_REG
 
+/* ADM1030 fan characteristics registers: fan speed range (divider) */
+#define DBCOOL_ADM1030_FANDIV_MASK	0xc0
+#define DBCOOL_ADM1030_FANDIV_1		0x00
+#define DBCOOL_ADM1030_FANDIV_2		0x40
+#define DBCOOL_ADM1030_FANDIV_4		0x80
+#define DBCOOL_ADM1030_FANDIV_8		0xc0
+
 /*      
  * Macros to locate limit registers for the various sensor types
  */     
Index: src/sys/dev/i2c/dbcool_var.h
===================================================================
RCS file: /cvsroot/src/sys/dev/i2c/dbcool_var.h,v
retrieving revision 1.18
diff -u -r1.18 dbcool_var.h
--- src/sys/dev/i2c/dbcool_var.h	21 Sep 2025 13:54:56 -0000	1.18
+++ src/sys/dev/i2c/dbcool_var.h	29 Jul 2026 09:22:30 -0000
@@ -74,6 +74,7 @@
 #define	DBCFLAG_OBSOLETE	0x0020	/* was DBCFLAG_HAS_VID */
 #define	DBCFLAG_HAS_VID_SEL	0x0040
 #define	DBCFLAG_HAS_PECI	0x0080
+#define	DBCFLAG_HAS_FANDIV	0x0100
 #define	DBCFLAG_NO_READBYTE	0x1000
 #define	DBCFLAG_ADM1030		0x2000
 #define	DBCFLAG_ADT7466		0x4000
@@ -95,6 +96,11 @@
 	int nom_volt_index;
 };
 
+struct dbcool_fan_div {
+	uint8_t fan_reg;
+	uint8_t char_reg;
+};
+
 /*
  * The members of dbcool_power_control need to stay in the same order
  * as the enum dbc_pwm_params above
@@ -125,6 +131,8 @@
 	int sc_sysctl_num[DBCOOL_MAXSENSORS];
 	struct reg_list *sc_regs[DBCOOL_MAXSENSORS];
 	int sc_nom_volt[DBCOOL_MAXSENSORS];
+	int sc_fan_num;
+	int sc_fan_div[DBCOOL_MAXSENSORS];
 	int sc_temp_offset;
 	int64_t sc_supply_voltage;
 	bool sc_suspend;
@@ -140,6 +148,7 @@
 	uint8_t rev;
 	struct dbcool_sensor *table;
 	struct dbcool_power_control *power;
+	struct dbcool_fan_div *fan_div;
 	int flags;
 	int rpm_dividend;
 	const char *name;
