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 20 Jul 2026 07:43:17 -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); @@ -538,6 +538,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 +670,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 +1012,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 +1028,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 */ @@ -1604,10 +1613,11 @@ static int dbcool_setup_sensors(struct dbcool_softc *sc) { - int i; + int i, j; int error = 0; - uint8_t vid_reg, vid_val; + uint8_t vid_reg, vid_val, fanchar_reg, fanchar_val; struct chip_id *chip = sc->sc_dc.dc_chip; + struct dbcool_fan_div *fan_div_table = chip->fan_div; for (i=0; chip->table[i].type != DBC_EOF; i++) { if (i < DBCOOL_MAXSENSORS) @@ -1642,6 +1652,38 @@ error = dbcool_attach_sensor(sc, i); break; case DBC_FAN: + 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) { + fanchar_val = sc->sc_dc.dc_readreg(&sc->sc_dc, + fanchar_reg); + /* We only handle ADM1030 fan div here. */ + fanchar_val &= DBCOOL_ADM1030_FANDIV_MASK; + switch (fanchar_val) + { + case DBCOOL_ADM1030_FANDIV_8: + sc->sc_fan_div[i] = 8; + break; + case DBCOOL_ADM1030_FANDIV_4: + sc->sc_fan_div[i] = 4; + break; + case DBCOOL_ADM1030_FANDIV_2: + sc->sc_fan_div[i] = 2; + break; + case DBCOOL_ADM1030_FANDIV_1: + default: + sc->sc_fan_div[i] = 1; + break; + } + } else + sc->sc_fan_div[i] = 1; sc->sc_sensor[i].units = ENVSYS_SFANRPM; sc->sc_sensor[i].state = ENVSYS_SINVALID; sc->sc_sensor[i].flags |= ENVSYS_FMONLIMITS; @@ -1811,7 +1853,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 +1871,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 +2058,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 20 Jul 2026 07:43:17 -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 20 Jul 2026 07:43:18 -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,7 @@ int sc_sysctl_num[DBCOOL_MAXSENSORS]; struct reg_list *sc_regs[DBCOOL_MAXSENSORS]; int sc_nom_volt[DBCOOL_MAXSENSORS]; + int sc_fan_div[DBCOOL_MAXSENSORS]; int sc_temp_offset; int64_t sc_supply_voltage; bool sc_suspend; @@ -140,6 +147,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;