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 11:11:01 -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,10 @@ static int sysctl_dbcool_thyst(SYSCTLFN_PROTO); /* Set-up subroutines */ +static int dbcool_set_fan_divider(struct dbcool_softc *, prop_dictionary_t, + int); 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 +540,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 }, @@ -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 */ @@ -1536,7 +1545,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 +1611,67 @@ } static int -dbcool_setup_sensors(struct dbcool_softc *sc) +dbcool_set_fan_divider(struct dbcool_softc *sc, prop_dictionary_t props, + int sensor) +{ + uint8_t fanchar_reg, val; + uint16_t props_fan_div, div_val; + int i, div; + + div = 1; + + /* ADM1030/1031 have a fan characteristics register with a divider */ + if (sc->sc_dc.dc_chip->flags & DBCFLAG_ADM1030) { + fanchar_reg = 0; + for (i = 0; ADM1030_fan_div_table[i].fan_reg != 0; i++) { + if (sc->sc_dc.dc_chip->table[sensor].reg.val_reg == + ADM1030_fan_div_table[i].fan_reg) + fanchar_reg = ADM1030_fan_div_table[i].char_reg; + } + if (fanchar_reg) { + val = sc->sc_dc.dc_readreg(&sc->sc_dc, fanchar_reg); + 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; + } + } + } + /* + * 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) + div *= div_val; + } + return div; +} + +static int +dbcool_setup_sensors(struct dbcool_softc *sc, prop_dictionary_t props) { int i; int error = 0; uint8_t vid_reg, vid_val; struct chip_id *chip = sc->sc_dc.dc_chip; + 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 +1705,15 @@ error = dbcool_attach_sensor(sc, i); break; case DBC_FAN: + sc->sc_fan_div[i] = dbcool_set_fan_divider(sc, + props, i); + 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 +1878,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 +1896,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 +2083,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 11:11:01 -0000 @@ -362,6 +362,13 @@ #define DBCOOL_ADM1030_COMPANYID DBCOOL_COMPANYID_REG #define DBCOOL_ADM1030_REVISION DBCOOL_REVISION_REG +/* ADM1030 fan characteristics registers 0x20/0x21: 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 11:11:01 -0000 @@ -95,6 +95,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 +130,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;