* [PATCH v5 1/4] hwmon: it87: describe per-chip temperature resources
2026-08-29 17:05 [PATCH v5 0/4] hwmon: it87: add IT8613E support Jerome Tollet
@ 2026-08-29 17:05 ` Jerome Tollet
2026-08-29 17:05 ` [PATCH v5 2/4] hwmon: it87: prepare for extended PWM temp maps Jerome Tollet
` (2 subsequent siblings)
3 siblings, 0 replies; 5+ messages in thread
From: Jerome Tollet @ 2026-08-29 17:05 UTC (permalink / raw)
To: Jean Delvare, Guenter Roeck
Cc: linux-hwmon, Benoit Masson, Jonathan Corbet, Shuah Khan,
Randy Dunlap, linux-doc, linux-kernel, Jerome Tollet
From: "benoit.masson" <yahoo@perenite.com>
Add per-chip temp limit/offset/map counts and wire the driver
to use them.
This keeps existing chips on the previous defaults while allowing newer
chips to advertise larger resources.
Signed-off-by: benoit.masson <yahoo@perenite.com>
Signed-off-by: Jerome Tollet <jerome.tollet@gmail.com>
---
drivers/hwmon/it87.c | 151 ++++++++++++++++++++++++++++++++-----------
1 file changed, 114 insertions(+), 37 deletions(-)
diff --git a/drivers/hwmon/it87.c b/drivers/hwmon/it87.c
index 87edb1b60..1c77f6c97 100644
--- a/drivers/hwmon/it87.c
+++ b/drivers/hwmon/it87.c
@@ -247,7 +247,7 @@ static const u8 IT87_REG_FAN[] = { 0x0d, 0x0e, 0x0f, 0x80, 0x82, 0x4c };
static const u8 IT87_REG_FAN_MIN[] = { 0x10, 0x11, 0x12, 0x84, 0x86, 0x4e };
static const u8 IT87_REG_FANX[] = { 0x18, 0x19, 0x1a, 0x81, 0x83, 0x4d };
static const u8 IT87_REG_FANX_MIN[] = { 0x1b, 0x1c, 0x1d, 0x85, 0x87, 0x4f };
-static const u8 IT87_REG_TEMP_OFFSET[] = { 0x56, 0x57, 0x59 };
+static const u8 IT87_REG_TEMP_OFFSET[] = { 0x56, 0x57, 0x59, 0x5a, 0x90, 0x91 };
#define IT87_REG_FAN_MAIN_CTRL 0x13
#define IT87_REG_FAN_CTL 0x14
@@ -282,7 +282,6 @@ static const u8 IT87_REG_AUTO_BASE[] = { 0x60, 0x68, 0x70, 0x78, 0xa0, 0xa8 };
#define NUM_VIN_LIMIT 8
#define NUM_TEMP 6
#define NUM_TEMP_OFFSET ARRAY_SIZE(IT87_REG_TEMP_OFFSET)
-#define NUM_TEMP_LIMIT 3
#define NUM_FAN ARRAY_SIZE(IT87_REG_FAN)
#define NUM_FAN_DIV 3
#define NUM_PWM ARRAY_SIZE(IT87_REG_PWM)
@@ -292,6 +291,9 @@ struct it87_devices {
const char *name;
const char * const model;
u32 features;
+ u8 num_temp_limit;
+ u8 num_temp_offset;
+ u8 num_temp_map;
u8 peci_mask;
u8 old_peci_mask;
u8 smbus_bitmap; /* SMBus enable bits in extra config register */
@@ -302,7 +304,6 @@ struct it87_devices {
#define FEAT_NEWER_AUTOPWM BIT(1)
#define FEAT_OLD_AUTOPWM BIT(2)
#define FEAT_16BIT_FANS BIT(3)
-#define FEAT_TEMP_OFFSET BIT(4)
#define FEAT_TEMP_PECI BIT(5)
#define FEAT_TEMP_OLD_PECI BIT(6)
#define FEAT_FAN16_CONFIG BIT(7) /* Need to enable 16-bit fans */
@@ -335,43 +336,61 @@ static const struct it87_devices it87_devices[] = {
.model = "IT87F",
.features = FEAT_OLD_AUTOPWM | FEAT_FANCTL_ONOFF,
/* may need to overwrite */
+ .num_temp_limit = 3,
+ .num_temp_offset = 0,
+ .num_temp_map = 3,
},
[it8712] = {
.name = "it8712",
.model = "IT8712F",
.features = FEAT_OLD_AUTOPWM | FEAT_VID | FEAT_FANCTL_ONOFF,
/* may need to overwrite */
+ .num_temp_limit = 3,
+ .num_temp_offset = 0,
+ .num_temp_map = 3,
},
[it8716] = {
.name = "it8716",
.model = "IT8716F",
- .features = FEAT_16BIT_FANS | FEAT_TEMP_OFFSET | FEAT_VID
+ .features = FEAT_16BIT_FANS | FEAT_VID
| FEAT_FAN16_CONFIG | FEAT_FIVE_FANS | FEAT_PWM_FREQ2
| FEAT_FANCTL_ONOFF,
+ .num_temp_limit = 3,
+ .num_temp_offset = 3,
+ .num_temp_map = 3,
},
[it8718] = {
.name = "it8718",
.model = "IT8718F",
- .features = FEAT_16BIT_FANS | FEAT_TEMP_OFFSET | FEAT_VID
+ .features = FEAT_16BIT_FANS | FEAT_VID
| FEAT_TEMP_OLD_PECI | FEAT_FAN16_CONFIG | FEAT_FIVE_FANS
| FEAT_PWM_FREQ2 | FEAT_FANCTL_ONOFF,
+ .num_temp_limit = 3,
+ .num_temp_offset = 3,
+ .num_temp_map = 3,
.old_peci_mask = 0x4,
},
[it8720] = {
.name = "it8720",
.model = "IT8720F",
- .features = FEAT_16BIT_FANS | FEAT_TEMP_OFFSET | FEAT_VID
+ .features = FEAT_16BIT_FANS | FEAT_VID
| FEAT_TEMP_OLD_PECI | FEAT_FAN16_CONFIG | FEAT_FIVE_FANS
| FEAT_PWM_FREQ2 | FEAT_FANCTL_ONOFF,
+ .num_temp_limit = 3,
+ .num_temp_offset = 3,
+ .num_temp_map = 3,
.old_peci_mask = 0x4,
},
[it8721] = {
.name = "it8721",
.model = "IT8721F",
.features = FEAT_NEWER_AUTOPWM | FEAT_12MV_ADC | FEAT_16BIT_FANS
- | FEAT_TEMP_OFFSET | FEAT_TEMP_OLD_PECI | FEAT_TEMP_PECI
+ | FEAT_TEMP_OLD_PECI | FEAT_TEMP_PECI
| FEAT_FAN16_CONFIG | FEAT_FIVE_FANS | FEAT_IN7_INTERNAL
| FEAT_PWM_FREQ2 | FEAT_FANCTL_ONOFF,
+ .num_temp_limit = 3,
+ .num_temp_offset = 3,
+ .num_temp_map = 3,
.peci_mask = 0x05,
.old_peci_mask = 0x02, /* Actually reports PCH */
},
@@ -379,18 +398,24 @@ static const struct it87_devices it87_devices[] = {
.name = "it8728",
.model = "IT8728F",
.features = FEAT_NEWER_AUTOPWM | FEAT_12MV_ADC | FEAT_16BIT_FANS
- | FEAT_TEMP_OFFSET | FEAT_TEMP_PECI | FEAT_FIVE_FANS
+ | FEAT_TEMP_PECI | FEAT_FIVE_FANS
| FEAT_IN7_INTERNAL | FEAT_PWM_FREQ2
| FEAT_FANCTL_ONOFF,
+ .num_temp_limit = 6,
+ .num_temp_offset = 3,
+ .num_temp_map = 3,
.peci_mask = 0x07,
},
[it8732] = {
.name = "it8732",
.model = "IT8732F",
.features = FEAT_NEWER_AUTOPWM | FEAT_16BIT_FANS
- | FEAT_TEMP_OFFSET | FEAT_TEMP_OLD_PECI | FEAT_TEMP_PECI
+ | FEAT_TEMP_OLD_PECI | FEAT_TEMP_PECI
| FEAT_10_9MV_ADC | FEAT_IN7_INTERNAL | FEAT_FOUR_FANS
| FEAT_FOUR_PWM | FEAT_FANCTL_ONOFF,
+ .num_temp_limit = 3,
+ .num_temp_offset = 3,
+ .num_temp_map = 3,
.peci_mask = 0x07,
.old_peci_mask = 0x02, /* Actually reports PCH */
},
@@ -398,73 +423,97 @@ static const struct it87_devices it87_devices[] = {
.name = "it8771",
.model = "IT8771E",
.features = FEAT_NEWER_AUTOPWM | FEAT_12MV_ADC | FEAT_16BIT_FANS
- | FEAT_TEMP_OFFSET | FEAT_TEMP_PECI | FEAT_IN7_INTERNAL
+ | FEAT_TEMP_PECI | FEAT_IN7_INTERNAL
| FEAT_PWM_FREQ2 | FEAT_FANCTL_ONOFF,
/* PECI: guesswork */
/* 12mV ADC (OHM) */
/* 16 bit fans (OHM) */
/* three fans, always 16 bit (guesswork) */
+ .num_temp_limit = 3,
+ .num_temp_offset = 3,
+ .num_temp_map = 3,
.peci_mask = 0x07,
},
[it8772] = {
.name = "it8772",
.model = "IT8772E",
.features = FEAT_NEWER_AUTOPWM | FEAT_12MV_ADC | FEAT_16BIT_FANS
- | FEAT_TEMP_OFFSET | FEAT_TEMP_PECI | FEAT_IN7_INTERNAL
+ | FEAT_TEMP_PECI | FEAT_IN7_INTERNAL
| FEAT_PWM_FREQ2 | FEAT_FANCTL_ONOFF,
/* PECI (coreboot) */
/* 12mV ADC (HWSensors4, OHM) */
/* 16 bit fans (HWSensors4, OHM) */
/* three fans, always 16 bit (datasheet) */
+ .num_temp_limit = 3,
+ .num_temp_offset = 3,
+ .num_temp_map = 3,
.peci_mask = 0x07,
},
[it8781] = {
.name = "it8781",
.model = "IT8781F",
- .features = FEAT_16BIT_FANS | FEAT_TEMP_OFFSET
+ .features = FEAT_16BIT_FANS
| FEAT_TEMP_OLD_PECI | FEAT_FAN16_CONFIG | FEAT_PWM_FREQ2
| FEAT_FANCTL_ONOFF,
+ .num_temp_limit = 3,
+ .num_temp_offset = 3,
+ .num_temp_map = 3,
.old_peci_mask = 0x4,
},
[it8782] = {
.name = "it8782",
.model = "IT8782F",
- .features = FEAT_16BIT_FANS | FEAT_TEMP_OFFSET
+ .features = FEAT_16BIT_FANS
| FEAT_TEMP_OLD_PECI | FEAT_FAN16_CONFIG | FEAT_PWM_FREQ2
| FEAT_FANCTL_ONOFF,
+ .num_temp_limit = 3,
+ .num_temp_offset = 3,
+ .num_temp_map = 3,
.old_peci_mask = 0x4,
},
[it8783] = {
.name = "it8783",
.model = "IT8783E/F",
- .features = FEAT_16BIT_FANS | FEAT_TEMP_OFFSET
+ .features = FEAT_16BIT_FANS
| FEAT_TEMP_OLD_PECI | FEAT_FAN16_CONFIG | FEAT_PWM_FREQ2
| FEAT_FANCTL_ONOFF,
+ .num_temp_limit = 3,
+ .num_temp_offset = 3,
+ .num_temp_map = 3,
.old_peci_mask = 0x4,
},
[it8786] = {
.name = "it8786",
.model = "IT8786E",
.features = FEAT_NEWER_AUTOPWM | FEAT_12MV_ADC | FEAT_16BIT_FANS
- | FEAT_TEMP_OFFSET | FEAT_TEMP_PECI | FEAT_IN7_INTERNAL
+ | FEAT_TEMP_PECI | FEAT_IN7_INTERNAL
| FEAT_PWM_FREQ2 | FEAT_FANCTL_ONOFF,
+ .num_temp_limit = 3,
+ .num_temp_offset = 3,
+ .num_temp_map = 3,
.peci_mask = 0x07,
},
[it8790] = {
.name = "it8790",
.model = "IT8790E",
.features = FEAT_NEWER_AUTOPWM | FEAT_12MV_ADC | FEAT_16BIT_FANS
- | FEAT_TEMP_OFFSET | FEAT_TEMP_PECI | FEAT_IN7_INTERNAL
+ | FEAT_TEMP_PECI | FEAT_IN7_INTERNAL
| FEAT_PWM_FREQ2 | FEAT_FANCTL_ONOFF | FEAT_NOCONF,
+ .num_temp_limit = 3,
+ .num_temp_offset = 3,
+ .num_temp_map = 3,
.peci_mask = 0x07,
},
[it8792] = {
.name = "it8792",
.model = "IT8792E/IT8795E",
.features = FEAT_NEWER_AUTOPWM | FEAT_16BIT_FANS
- | FEAT_TEMP_OFFSET | FEAT_TEMP_OLD_PECI | FEAT_TEMP_PECI
+ | FEAT_TEMP_OLD_PECI | FEAT_TEMP_PECI
| FEAT_10_9MV_ADC | FEAT_IN7_INTERNAL | FEAT_FANCTL_ONOFF
| FEAT_NOCONF,
+ .num_temp_limit = 3,
+ .num_temp_offset = 3,
+ .num_temp_map = 3,
.peci_mask = 0x07,
.old_peci_mask = 0x02, /* Actually reports PCH */
},
@@ -472,54 +521,72 @@ static const struct it87_devices it87_devices[] = {
.name = "it8603",
.model = "IT8603E",
.features = FEAT_NEWER_AUTOPWM | FEAT_12MV_ADC | FEAT_16BIT_FANS
- | FEAT_TEMP_OFFSET | FEAT_TEMP_PECI | FEAT_IN7_INTERNAL
+ | FEAT_TEMP_PECI | FEAT_IN7_INTERNAL
| FEAT_AVCC3 | FEAT_PWM_FREQ2,
+ .num_temp_limit = 3,
+ .num_temp_offset = 3,
+ .num_temp_map = 4,
.peci_mask = 0x07,
},
[it8620] = {
.name = "it8620",
.model = "IT8620E",
.features = FEAT_NEWER_AUTOPWM | FEAT_12MV_ADC | FEAT_16BIT_FANS
- | FEAT_TEMP_OFFSET | FEAT_TEMP_PECI | FEAT_SIX_FANS
+ | FEAT_TEMP_PECI | FEAT_SIX_FANS
| FEAT_IN7_INTERNAL | FEAT_SIX_PWM | FEAT_PWM_FREQ2
| FEAT_SIX_TEMP | FEAT_VIN3_5V | FEAT_FANCTL_ONOFF,
+ .num_temp_limit = 3,
+ .num_temp_offset = 3,
+ .num_temp_map = 3,
.peci_mask = 0x07,
},
[it8622] = {
.name = "it8622",
.model = "IT8622E",
.features = FEAT_NEWER_AUTOPWM | FEAT_12MV_ADC | FEAT_16BIT_FANS
- | FEAT_TEMP_OFFSET | FEAT_TEMP_PECI | FEAT_FIVE_FANS
+ | FEAT_TEMP_PECI | FEAT_FIVE_FANS
| FEAT_FIVE_PWM | FEAT_IN7_INTERNAL | FEAT_PWM_FREQ2
| FEAT_AVCC3 | FEAT_VIN3_5V | FEAT_FOUR_TEMP,
- .peci_mask = 0x07,
+ .num_temp_limit = 3,
+ .num_temp_offset = 3,
+ .num_temp_map = 4,
+ .peci_mask = 0x0f,
.smbus_bitmap = BIT(1) | BIT(2),
},
[it8628] = {
.name = "it8628",
.model = "IT8628E",
.features = FEAT_NEWER_AUTOPWM | FEAT_12MV_ADC | FEAT_16BIT_FANS
- | FEAT_TEMP_OFFSET | FEAT_TEMP_PECI | FEAT_SIX_FANS
+ | FEAT_TEMP_PECI | FEAT_SIX_FANS
| FEAT_IN7_INTERNAL | FEAT_SIX_PWM | FEAT_PWM_FREQ2
| FEAT_SIX_TEMP | FEAT_VIN3_5V | FEAT_FANCTL_ONOFF,
+ .num_temp_limit = 6,
+ .num_temp_offset = 3,
+ .num_temp_map = 3,
.peci_mask = 0x07,
},
[it8689] = {
.name = "it8689",
.model = "IT8689E",
.features = FEAT_NEWER_AUTOPWM | FEAT_12MV_ADC | FEAT_16BIT_FANS
- | FEAT_TEMP_OFFSET | FEAT_SIX_FANS | FEAT_IN7_INTERNAL
+ | FEAT_SIX_FANS | FEAT_IN7_INTERNAL
| FEAT_SIX_PWM | FEAT_PWM_FREQ2 | FEAT_SIX_TEMP | FEAT_AVCC3
| FEAT_FANCTL_ONOFF,
+ .num_temp_limit = 3,
+ .num_temp_offset = 3,
+ .num_temp_map = 3,
.smbus_bitmap = BIT(1) | BIT(2),
},
[it87952] = {
.name = "it87952",
.model = "IT87952E",
.features = FEAT_NEWER_AUTOPWM | FEAT_16BIT_FANS
- | FEAT_TEMP_OFFSET | FEAT_TEMP_OLD_PECI | FEAT_TEMP_PECI
+ | FEAT_TEMP_OLD_PECI | FEAT_TEMP_PECI
| FEAT_10_9MV_ADC | FEAT_IN7_INTERNAL | FEAT_FANCTL_ONOFF
| FEAT_NOCONF,
+ .num_temp_limit = 3,
+ .num_temp_offset = 3,
+ .num_temp_map = 3,
.peci_mask = 0x07,
.old_peci_mask = 0x02, /* Actually reports PCH */
},
@@ -530,7 +597,6 @@ static const struct it87_devices it87_devices[] = {
#define has_10_9mv_adc(data) ((data)->features & FEAT_10_9MV_ADC)
#define has_newer_autopwm(data) ((data)->features & FEAT_NEWER_AUTOPWM)
#define has_old_autopwm(data) ((data)->features & FEAT_OLD_AUTOPWM)
-#define has_temp_offset(data) ((data)->features & FEAT_TEMP_OFFSET)
#define has_temp_peci(data, nr) (((data)->features & FEAT_TEMP_PECI) && \
((data)->peci_mask & BIT(nr)))
#define has_temp_old_peci(data, nr) \
@@ -589,6 +655,9 @@ struct it87_data {
int sioaddr;
enum chips type;
u32 features;
+ u8 num_temp_limit;
+ u8 num_temp_offset;
+ u8 num_temp_map;
u8 peci_mask;
u8 old_peci_mask;
@@ -937,12 +1006,12 @@ static struct it87_data *it87_update_device(struct device *dev)
data->temp[i][0] =
it87_read_value(data, IT87_REG_TEMP(i));
- if (has_temp_offset(data) && i < NUM_TEMP_OFFSET)
+ if (i < data->num_temp_offset)
data->temp[i][3] =
it87_read_value(data,
IT87_REG_TEMP_OFFSET[i]);
- if (i >= NUM_TEMP_LIMIT)
+ if (i >= data->num_temp_limit)
continue;
data->temp[i][1] =
@@ -1693,16 +1762,18 @@ static ssize_t show_pwm_temp_map(struct device *dev,
struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
struct it87_data *data = it87_update_device(dev);
int nr = sensor_attr->index;
+ u8 num_map;
int map;
if (IS_ERR(data))
return PTR_ERR(data);
+ num_map = data->num_temp_map;
map = data->pwm_temp_map[nr];
- if (map >= 3)
+ if (map >= num_map)
map = 0; /* Should never happen */
- if (nr >= 3) /* pwm channels 3..6 map to temp4..6 */
- map += 3;
+ if (nr >= num_map) /* pwm channels 3..6 map to temp4..6 */
+ map += num_map;
return sprintf(buf, "%d\n", (int)BIT(map));
}
@@ -1714,6 +1785,7 @@ static ssize_t set_pwm_temp_map(struct device *dev,
struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
struct it87_data *data = dev_get_drvdata(dev);
int nr = sensor_attr->index;
+ u8 num_map = data->num_temp_map;
long val;
int err;
u8 reg;
@@ -1721,8 +1793,8 @@ static ssize_t set_pwm_temp_map(struct device *dev,
if (kstrtol(buf, 10, &val) < 0)
return -EINVAL;
- if (nr >= 3)
- val -= 3;
+ if (nr >= num_map)
+ val -= num_map;
switch (val) {
case BIT(0):
@@ -2376,7 +2448,7 @@ static umode_t it87_temp_is_visible(struct kobject *kobj,
return attr->mode;
}
- if (a == 5 && !has_temp_offset(data))
+ if (a == 5 && i >= data->num_temp_offset)
return 0;
if (a == 6 && !data->has_beep)
@@ -3268,7 +3340,7 @@ static void it87_check_limit_regs(struct it87_data *data)
if (reg == 0xff)
it87_write_value(data, IT87_REG_VIN_MIN(i), 0);
}
- for (i = 0; i < NUM_TEMP_LIMIT; i++) {
+ for (i = 0; i < data->num_temp_limit; i++) {
reg = it87_read_value(data, IT87_REG_TEMP_HIGH(i));
if (reg == 0xff)
it87_write_value(data, IT87_REG_TEMP_HIGH(i), 127);
@@ -3461,6 +3533,7 @@ static int it87_probe(struct platform_device *pdev)
struct resource *res;
struct device *dev = &pdev->dev;
struct it87_sio_data *sio_data = dev_get_platdata(dev);
+ const struct it87_devices *chip;
int enable_pwm_interface;
struct device *hwmon_dev;
int err;
@@ -3483,9 +3556,13 @@ static int it87_probe(struct platform_device *pdev)
data->type = sio_data->type;
data->smbus_bitmap = sio_data->smbus_bitmap;
data->ec_special_config = sio_data->ec_special_config;
- data->features = it87_devices[sio_data->type].features;
- data->peci_mask = it87_devices[sio_data->type].peci_mask;
- data->old_peci_mask = it87_devices[sio_data->type].old_peci_mask;
+ chip = &it87_devices[sio_data->type];
+ data->features = chip->features;
+ data->peci_mask = chip->peci_mask;
+ data->old_peci_mask = chip->old_peci_mask;
+ data->num_temp_limit = chip->num_temp_limit;
+ data->num_temp_offset = chip->num_temp_offset;
+ data->num_temp_map = chip->num_temp_map;
/*
* IT8705F Datasheet 0.4.1, 3h == Version G.
* IT8712F Datasheet 0.9.1, section 8.3.5 indicates 8h == Version J.
--
2.55.0
^ permalink raw reply [flat|nested] 5+ messages in thread* [PATCH v5 2/4] hwmon: it87: prepare for extended PWM temp maps
2026-08-29 17:05 [PATCH v5 0/4] hwmon: it87: add IT8613E support Jerome Tollet
2026-08-29 17:05 ` [PATCH v5 1/4] hwmon: it87: describe per-chip temperature resources Jerome Tollet
@ 2026-08-29 17:05 ` Jerome Tollet
2026-08-29 17:05 ` [PATCH v5 3/4] hwmon: it87: expose additional temperature limits Jerome Tollet
2026-08-29 17:05 ` [PATCH v5 4/4] hwmon: it87: add IT8613E support Jerome Tollet
3 siblings, 0 replies; 5+ messages in thread
From: Jerome Tollet @ 2026-08-29 17:05 UTC (permalink / raw)
To: Jean Delvare, Guenter Roeck
Cc: linux-hwmon, Benoit Masson, Jonathan Corbet, Shuah Khan,
Randy Dunlap, linux-doc, linux-kernel, Jerome Tollet
From: "benoit.masson" <yahoo@perenite.com>
Introduce helper logic for PWM-to-temperature mappings so newer
register layouts can be supported without affecting legacy chips.
Signed-off-by: benoit.masson <yahoo@perenite.com>
Signed-off-by: Jerome Tollet <jerome.tollet@gmail.com>
---
drivers/hwmon/it87.c | 199 +++++++++++++++++++++++++++++++++----------
1 file changed, 154 insertions(+), 45 deletions(-)
diff --git a/drivers/hwmon/it87.c b/drivers/hwmon/it87.c
index 1c77f6c97..e077adbb3 100644
--- a/drivers/hwmon/it87.c
+++ b/drivers/hwmon/it87.c
@@ -252,6 +252,7 @@ static const u8 IT87_REG_TEMP_OFFSET[] = { 0x56, 0x57, 0x59, 0x5a, 0x90, 0x91 };
#define IT87_REG_FAN_MAIN_CTRL 0x13
#define IT87_REG_FAN_CTL 0x14
static const u8 IT87_REG_PWM[] = { 0x15, 0x16, 0x17, 0x7f, 0xa7, 0xaf };
+static const u8 IT87_REG_PWM_8665[] = { 0x15, 0x16, 0x17, 0x1e, 0x1f, 0x92 };
static const u8 IT87_REG_PWM_DUTY[] = { 0x63, 0x6b, 0x73, 0x7b, 0xa3, 0xab };
static const u8 IT87_REG_VIN[] = { 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26,
@@ -282,6 +283,7 @@ static const u8 IT87_REG_AUTO_BASE[] = { 0x60, 0x68, 0x70, 0x78, 0xa0, 0xa8 };
#define NUM_VIN_LIMIT 8
#define NUM_TEMP 6
#define NUM_TEMP_OFFSET ARRAY_SIZE(IT87_REG_TEMP_OFFSET)
+#define IT87_PWM_OLD_NUM_TEMP 3
#define NUM_FAN ARRAY_SIZE(IT87_REG_FAN)
#define NUM_FAN_DIV 3
#define NUM_PWM ARRAY_SIZE(IT87_REG_PWM)
@@ -291,6 +293,7 @@ struct it87_devices {
const char *name;
const char * const model;
u32 features;
+ const u8 *reg_pwm;
u8 num_temp_limit;
u8 num_temp_offset;
u8 num_temp_map;
@@ -329,6 +332,7 @@ struct it87_devices {
#define FEAT_FOUR_PWM BIT(21) /* Supports four fan controls */
#define FEAT_FOUR_TEMP BIT(22)
#define FEAT_FANCTL_ONOFF BIT(23) /* chip has FAN_CTL ON/OFF */
+#define FEAT_NEW_TEMPMAP BIT(24) /* PWM uses extended temp map */
static const struct it87_devices it87_devices[] = {
[it87] = {
@@ -336,6 +340,7 @@ static const struct it87_devices it87_devices[] = {
.model = "IT87F",
.features = FEAT_OLD_AUTOPWM | FEAT_FANCTL_ONOFF,
/* may need to overwrite */
+ .reg_pwm = IT87_REG_PWM,
.num_temp_limit = 3,
.num_temp_offset = 0,
.num_temp_map = 3,
@@ -345,6 +350,7 @@ static const struct it87_devices it87_devices[] = {
.model = "IT8712F",
.features = FEAT_OLD_AUTOPWM | FEAT_VID | FEAT_FANCTL_ONOFF,
/* may need to overwrite */
+ .reg_pwm = IT87_REG_PWM,
.num_temp_limit = 3,
.num_temp_offset = 0,
.num_temp_map = 3,
@@ -355,6 +361,7 @@ static const struct it87_devices it87_devices[] = {
.features = FEAT_16BIT_FANS | FEAT_VID
| FEAT_FAN16_CONFIG | FEAT_FIVE_FANS | FEAT_PWM_FREQ2
| FEAT_FANCTL_ONOFF,
+ .reg_pwm = IT87_REG_PWM,
.num_temp_limit = 3,
.num_temp_offset = 3,
.num_temp_map = 3,
@@ -365,6 +372,7 @@ static const struct it87_devices it87_devices[] = {
.features = FEAT_16BIT_FANS | FEAT_VID
| FEAT_TEMP_OLD_PECI | FEAT_FAN16_CONFIG | FEAT_FIVE_FANS
| FEAT_PWM_FREQ2 | FEAT_FANCTL_ONOFF,
+ .reg_pwm = IT87_REG_PWM,
.num_temp_limit = 3,
.num_temp_offset = 3,
.num_temp_map = 3,
@@ -376,6 +384,7 @@ static const struct it87_devices it87_devices[] = {
.features = FEAT_16BIT_FANS | FEAT_VID
| FEAT_TEMP_OLD_PECI | FEAT_FAN16_CONFIG | FEAT_FIVE_FANS
| FEAT_PWM_FREQ2 | FEAT_FANCTL_ONOFF,
+ .reg_pwm = IT87_REG_PWM,
.num_temp_limit = 3,
.num_temp_offset = 3,
.num_temp_map = 3,
@@ -388,6 +397,7 @@ static const struct it87_devices it87_devices[] = {
| FEAT_TEMP_OLD_PECI | FEAT_TEMP_PECI
| FEAT_FAN16_CONFIG | FEAT_FIVE_FANS | FEAT_IN7_INTERNAL
| FEAT_PWM_FREQ2 | FEAT_FANCTL_ONOFF,
+ .reg_pwm = IT87_REG_PWM,
.num_temp_limit = 3,
.num_temp_offset = 3,
.num_temp_map = 3,
@@ -401,6 +411,7 @@ static const struct it87_devices it87_devices[] = {
| FEAT_TEMP_PECI | FEAT_FIVE_FANS
| FEAT_IN7_INTERNAL | FEAT_PWM_FREQ2
| FEAT_FANCTL_ONOFF,
+ .reg_pwm = IT87_REG_PWM,
.num_temp_limit = 6,
.num_temp_offset = 3,
.num_temp_map = 3,
@@ -413,6 +424,7 @@ static const struct it87_devices it87_devices[] = {
| FEAT_TEMP_OLD_PECI | FEAT_TEMP_PECI
| FEAT_10_9MV_ADC | FEAT_IN7_INTERNAL | FEAT_FOUR_FANS
| FEAT_FOUR_PWM | FEAT_FANCTL_ONOFF,
+ .reg_pwm = IT87_REG_PWM,
.num_temp_limit = 3,
.num_temp_offset = 3,
.num_temp_map = 3,
@@ -429,6 +441,7 @@ static const struct it87_devices it87_devices[] = {
/* 12mV ADC (OHM) */
/* 16 bit fans (OHM) */
/* three fans, always 16 bit (guesswork) */
+ .reg_pwm = IT87_REG_PWM,
.num_temp_limit = 3,
.num_temp_offset = 3,
.num_temp_map = 3,
@@ -444,6 +457,7 @@ static const struct it87_devices it87_devices[] = {
/* 12mV ADC (HWSensors4, OHM) */
/* 16 bit fans (HWSensors4, OHM) */
/* three fans, always 16 bit (datasheet) */
+ .reg_pwm = IT87_REG_PWM,
.num_temp_limit = 3,
.num_temp_offset = 3,
.num_temp_map = 3,
@@ -455,6 +469,7 @@ static const struct it87_devices it87_devices[] = {
.features = FEAT_16BIT_FANS
| FEAT_TEMP_OLD_PECI | FEAT_FAN16_CONFIG | FEAT_PWM_FREQ2
| FEAT_FANCTL_ONOFF,
+ .reg_pwm = IT87_REG_PWM,
.num_temp_limit = 3,
.num_temp_offset = 3,
.num_temp_map = 3,
@@ -466,6 +481,7 @@ static const struct it87_devices it87_devices[] = {
.features = FEAT_16BIT_FANS
| FEAT_TEMP_OLD_PECI | FEAT_FAN16_CONFIG | FEAT_PWM_FREQ2
| FEAT_FANCTL_ONOFF,
+ .reg_pwm = IT87_REG_PWM,
.num_temp_limit = 3,
.num_temp_offset = 3,
.num_temp_map = 3,
@@ -477,6 +493,7 @@ static const struct it87_devices it87_devices[] = {
.features = FEAT_16BIT_FANS
| FEAT_TEMP_OLD_PECI | FEAT_FAN16_CONFIG | FEAT_PWM_FREQ2
| FEAT_FANCTL_ONOFF,
+ .reg_pwm = IT87_REG_PWM,
.num_temp_limit = 3,
.num_temp_offset = 3,
.num_temp_map = 3,
@@ -488,6 +505,7 @@ static const struct it87_devices it87_devices[] = {
.features = FEAT_NEWER_AUTOPWM | FEAT_12MV_ADC | FEAT_16BIT_FANS
| FEAT_TEMP_PECI | FEAT_IN7_INTERNAL
| FEAT_PWM_FREQ2 | FEAT_FANCTL_ONOFF,
+ .reg_pwm = IT87_REG_PWM,
.num_temp_limit = 3,
.num_temp_offset = 3,
.num_temp_map = 3,
@@ -499,6 +517,7 @@ static const struct it87_devices it87_devices[] = {
.features = FEAT_NEWER_AUTOPWM | FEAT_12MV_ADC | FEAT_16BIT_FANS
| FEAT_TEMP_PECI | FEAT_IN7_INTERNAL
| FEAT_PWM_FREQ2 | FEAT_FANCTL_ONOFF | FEAT_NOCONF,
+ .reg_pwm = IT87_REG_PWM,
.num_temp_limit = 3,
.num_temp_offset = 3,
.num_temp_map = 3,
@@ -511,6 +530,7 @@ static const struct it87_devices it87_devices[] = {
| FEAT_TEMP_OLD_PECI | FEAT_TEMP_PECI
| FEAT_10_9MV_ADC | FEAT_IN7_INTERNAL | FEAT_FANCTL_ONOFF
| FEAT_NOCONF,
+ .reg_pwm = IT87_REG_PWM,
.num_temp_limit = 3,
.num_temp_offset = 3,
.num_temp_map = 3,
@@ -523,6 +543,7 @@ static const struct it87_devices it87_devices[] = {
.features = FEAT_NEWER_AUTOPWM | FEAT_12MV_ADC | FEAT_16BIT_FANS
| FEAT_TEMP_PECI | FEAT_IN7_INTERNAL
| FEAT_AVCC3 | FEAT_PWM_FREQ2,
+ .reg_pwm = IT87_REG_PWM,
.num_temp_limit = 3,
.num_temp_offset = 3,
.num_temp_map = 4,
@@ -535,6 +556,7 @@ static const struct it87_devices it87_devices[] = {
| FEAT_TEMP_PECI | FEAT_SIX_FANS
| FEAT_IN7_INTERNAL | FEAT_SIX_PWM | FEAT_PWM_FREQ2
| FEAT_SIX_TEMP | FEAT_VIN3_5V | FEAT_FANCTL_ONOFF,
+ .reg_pwm = IT87_REG_PWM,
.num_temp_limit = 3,
.num_temp_offset = 3,
.num_temp_map = 3,
@@ -547,6 +569,7 @@ static const struct it87_devices it87_devices[] = {
| FEAT_TEMP_PECI | FEAT_FIVE_FANS
| FEAT_FIVE_PWM | FEAT_IN7_INTERNAL | FEAT_PWM_FREQ2
| FEAT_AVCC3 | FEAT_VIN3_5V | FEAT_FOUR_TEMP,
+ .reg_pwm = IT87_REG_PWM_8665,
.num_temp_limit = 3,
.num_temp_offset = 3,
.num_temp_map = 4,
@@ -560,6 +583,7 @@ static const struct it87_devices it87_devices[] = {
| FEAT_TEMP_PECI | FEAT_SIX_FANS
| FEAT_IN7_INTERNAL | FEAT_SIX_PWM | FEAT_PWM_FREQ2
| FEAT_SIX_TEMP | FEAT_VIN3_5V | FEAT_FANCTL_ONOFF,
+ .reg_pwm = IT87_REG_PWM,
.num_temp_limit = 6,
.num_temp_offset = 3,
.num_temp_map = 3,
@@ -572,6 +596,7 @@ static const struct it87_devices it87_devices[] = {
| FEAT_SIX_FANS | FEAT_IN7_INTERNAL
| FEAT_SIX_PWM | FEAT_PWM_FREQ2 | FEAT_SIX_TEMP | FEAT_AVCC3
| FEAT_FANCTL_ONOFF,
+ .reg_pwm = IT87_REG_PWM,
.num_temp_limit = 3,
.num_temp_offset = 3,
.num_temp_map = 3,
@@ -584,6 +609,7 @@ static const struct it87_devices it87_devices[] = {
| FEAT_TEMP_OLD_PECI | FEAT_TEMP_PECI
| FEAT_10_9MV_ADC | FEAT_IN7_INTERNAL | FEAT_FANCTL_ONOFF
| FEAT_NOCONF,
+ .reg_pwm = IT87_REG_PWM,
.num_temp_limit = 3,
.num_temp_offset = 3,
.num_temp_map = 3,
@@ -626,6 +652,7 @@ static const struct it87_devices it87_devices[] = {
#define has_scaling(data) ((data)->features & (FEAT_12MV_ADC | \
FEAT_10_9MV_ADC))
#define has_fanctl_onoff(data) ((data)->features & FEAT_FANCTL_ONOFF)
+#define has_new_tempmap(data) ((data)->features & FEAT_NEW_TEMPMAP)
struct it87_sio_data {
int sioaddr;
@@ -655,6 +682,7 @@ struct it87_data {
int sioaddr;
enum chips type;
u32 features;
+ const u8 *reg_pwm;
u8 num_temp_limit;
u8 num_temp_offset;
u8 num_temp_map;
@@ -704,7 +732,9 @@ struct it87_data {
u8 has_pwm; /* Bitfield, pwm control enabled */
u8 pwm_ctrl[NUM_PWM]; /* Register value */
u8 pwm_duty[NUM_PWM]; /* Manual PWM value set by user */
- u8 pwm_temp_map[NUM_PWM];/* PWM to temp. chan. mapping (bits 1-0) */
+ u8 pwm_temp_map[NUM_PWM];/* PWM to temp. chan. mapping */
+ u8 pwm_temp_map_mask;
+ u8 pwm_temp_map_shift;
/* Automatic fan speed control registers */
u8 auto_pwm[NUM_AUTO_PWM][4]; /* [nr][3] is hard-coded */
@@ -786,6 +816,71 @@ static int pwm_from_reg(const struct it87_data *data, u8 reg)
return (reg & 0x7f) << 1;
}
+static inline u8 pwm_temp_map_get(const struct it87_data *data, u8 ctrl)
+{
+ return (ctrl >> data->pwm_temp_map_shift) &
+ data->pwm_temp_map_mask;
+}
+
+static inline u8 pwm_temp_map_set(const struct it87_data *data, u8 ctrl,
+ u8 map)
+{
+ ctrl &= ~(data->pwm_temp_map_mask << data->pwm_temp_map_shift);
+ return ctrl | ((map & data->pwm_temp_map_mask)
+ << data->pwm_temp_map_shift);
+}
+
+static inline u8 pwm_num_temp_map(const struct it87_data *data)
+{
+ return data->num_temp_map;
+}
+
+static unsigned int pwm_temp_channel(const struct it87_data *data,
+ int nr, u8 map)
+{
+ if (has_new_tempmap(data)) {
+ u8 num = pwm_num_temp_map(data);
+
+ if (map >= num)
+ map = 0;
+ return map;
+ }
+
+ if (map >= IT87_PWM_OLD_NUM_TEMP)
+ map = 0;
+
+ if (nr >= IT87_PWM_OLD_NUM_TEMP)
+ map += IT87_PWM_OLD_NUM_TEMP;
+
+ return map;
+}
+
+static int pwm_temp_map_from_channel(const struct it87_data *data, int nr,
+ unsigned int channel, u8 *map)
+{
+ if (has_new_tempmap(data)) {
+ u8 num = pwm_num_temp_map(data);
+
+ if (channel >= num)
+ return -EINVAL;
+ *map = channel;
+ return 0;
+ }
+
+ if (nr >= IT87_PWM_OLD_NUM_TEMP) {
+ if (channel < IT87_PWM_OLD_NUM_TEMP ||
+ channel >= 2 * IT87_PWM_OLD_NUM_TEMP)
+ return -EINVAL;
+ channel -= IT87_PWM_OLD_NUM_TEMP;
+ } else {
+ if (channel >= IT87_PWM_OLD_NUM_TEMP)
+ return -EINVAL;
+ }
+
+ *map = channel;
+ return 0;
+}
+
static int DIV_TO_REG(int val)
{
int answer = 0;
@@ -797,6 +892,11 @@ static int DIV_TO_REG(int val)
#define DIV_FROM_REG(val) BIT(val)
+static inline u16 it87_reg_pwm(const struct it87_data *data, int nr)
+{
+ return data->reg_pwm[nr];
+}
+
/*
* PWM base frequencies. The frequency has to be divided by either 128 or 256,
* depending on the chip type, to calculate the actual PWM frequency.
@@ -877,14 +977,22 @@ static void it87_write_value(struct it87_data *data, u8 reg, u8 value)
static void it87_update_pwm_ctrl(struct it87_data *data, int nr)
{
- data->pwm_ctrl[nr] = it87_read_value(data, IT87_REG_PWM[nr]);
+ data->pwm_ctrl[nr] = it87_read_value(data, it87_reg_pwm(data, nr));
if (has_newer_autopwm(data)) {
- data->pwm_temp_map[nr] = data->pwm_ctrl[nr] & 0x03;
+ data->pwm_temp_map[nr] =
+ pwm_temp_map_get(data, data->pwm_ctrl[nr]);
+ if (has_new_tempmap(data) &&
+ data->pwm_temp_map[nr] >= pwm_num_temp_map(data))
+ data->pwm_temp_map[nr] = 0;
data->pwm_duty[nr] = it87_read_value(data,
IT87_REG_PWM_DUTY[nr]);
} else {
if (data->pwm_ctrl[nr] & 0x80) /* Automatic mode */
- data->pwm_temp_map[nr] = data->pwm_ctrl[nr] & 0x03;
+ data->pwm_temp_map[nr] =
+ pwm_temp_map_get(data, data->pwm_ctrl[nr]);
+ if (has_new_tempmap(data) &&
+ data->pwm_temp_map[nr] >= pwm_num_temp_map(data))
+ data->pwm_temp_map[nr] = 0;
else /* Manual mode */
data->pwm_duty[nr] = data->pwm_ctrl[nr] & 0x7f;
}
@@ -1617,6 +1725,8 @@ static ssize_t set_pwm_enable(struct device *dev, struct device_attribute *attr,
if (err)
return err;
+ it87_update_pwm_ctrl(data, nr);
+
if (val == 0) {
if (nr < 3 && has_fanctl_onoff(data)) {
int tmp;
@@ -1636,27 +1746,30 @@ static ssize_t set_pwm_enable(struct device *dev, struct device_attribute *attr,
data->pwm_duty[nr]);
/* and set manual mode */
if (has_newer_autopwm(data)) {
- ctrl = (data->pwm_ctrl[nr] & 0x7c) |
- data->pwm_temp_map[nr];
+ ctrl = pwm_temp_map_set(data,
+ data->pwm_ctrl[nr] &
+ ~0x80,
+ data->pwm_temp_map[nr]);
} else {
ctrl = data->pwm_duty[nr];
}
data->pwm_ctrl[nr] = ctrl;
- it87_write_value(data, IT87_REG_PWM[nr], ctrl);
+ it87_write_value(data, it87_reg_pwm(data, nr), ctrl);
}
} else {
u8 ctrl;
if (has_newer_autopwm(data)) {
- ctrl = (data->pwm_ctrl[nr] & 0x7c) |
- data->pwm_temp_map[nr];
+ ctrl = pwm_temp_map_set(data,
+ data->pwm_ctrl[nr] & ~0x80,
+ data->pwm_temp_map[nr]);
if (val != 1)
ctrl |= 0x80;
} else {
ctrl = (val == 1 ? data->pwm_duty[nr] : 0x80);
}
data->pwm_ctrl[nr] = ctrl;
- it87_write_value(data, IT87_REG_PWM[nr], ctrl);
+ it87_write_value(data, it87_reg_pwm(data, nr), ctrl);
if (has_fanctl_onoff(data) && nr < 3) {
/* set SmartGuardian mode */
@@ -1707,7 +1820,7 @@ static ssize_t set_pwm(struct device *dev, struct device_attribute *attr,
*/
if (!(data->pwm_ctrl[nr] & 0x80)) {
data->pwm_ctrl[nr] = data->pwm_duty[nr];
- it87_write_value(data, IT87_REG_PWM[nr],
+ it87_write_value(data, it87_reg_pwm(data, nr),
data->pwm_ctrl[nr]);
}
}
@@ -1762,20 +1875,14 @@ static ssize_t show_pwm_temp_map(struct device *dev,
struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
struct it87_data *data = it87_update_device(dev);
int nr = sensor_attr->index;
- u8 num_map;
- int map;
+ unsigned int channel;
if (IS_ERR(data))
return PTR_ERR(data);
- num_map = data->num_temp_map;
- map = data->pwm_temp_map[nr];
- if (map >= num_map)
- map = 0; /* Should never happen */
- if (nr >= num_map) /* pwm channels 3..6 map to temp4..6 */
- map += num_map;
+ channel = pwm_temp_channel(data, nr, data->pwm_temp_map[nr]);
- return sprintf(buf, "%d\n", (int)BIT(map));
+ return sprintf(buf, "%d\n", (int)BIT(channel));
}
static ssize_t set_pwm_temp_map(struct device *dev,
@@ -1785,45 +1892,34 @@ static ssize_t set_pwm_temp_map(struct device *dev,
struct sensor_device_attribute *sensor_attr = to_sensor_dev_attr(attr);
struct it87_data *data = dev_get_drvdata(dev);
int nr = sensor_attr->index;
- u8 num_map = data->num_temp_map;
long val;
int err;
- u8 reg;
+ unsigned int channel;
+ u8 map;
- if (kstrtol(buf, 10, &val) < 0)
+ if (kstrtol(buf, 10, &val) < 0 || val <= 0 || !is_power_of_2(val))
return -EINVAL;
- if (nr >= num_map)
- val -= num_map;
-
- switch (val) {
- case BIT(0):
- reg = 0x00;
- break;
- case BIT(1):
- reg = 0x01;
- break;
- case BIT(2):
- reg = 0x02;
- break;
- default:
+ channel = __ffs(val);
+ if (pwm_temp_map_from_channel(data, nr, channel, &map))
return -EINVAL;
- }
err = it87_lock(data);
if (err)
return err;
it87_update_pwm_ctrl(data, nr);
- data->pwm_temp_map[nr] = reg;
+ data->pwm_temp_map[nr] = map;
/*
* If we are in automatic mode, write the temp mapping immediately;
* otherwise, just store it for later use.
*/
if (data->pwm_ctrl[nr] & 0x80) {
- data->pwm_ctrl[nr] = (data->pwm_ctrl[nr] & 0xfc) |
- data->pwm_temp_map[nr];
- it87_write_value(data, IT87_REG_PWM[nr], data->pwm_ctrl[nr]);
+ data->pwm_ctrl[nr] = pwm_temp_map_set(data,
+ data->pwm_ctrl[nr],
+ data->pwm_temp_map[nr]);
+ it87_write_value(data, it87_reg_pwm(data, nr),
+ data->pwm_ctrl[nr]);
}
it87_unlock(data);
return count;
@@ -3422,7 +3518,10 @@ static void it87_init_device(struct platform_device *pdev)
* manual duty cycle.
*/
for (i = 0; i < NUM_AUTO_PWM; i++) {
- data->pwm_temp_map[i] = i;
+ if (has_new_tempmap(data))
+ data->pwm_temp_map[i] = 0;
+ else
+ data->pwm_temp_map[i] = i % IT87_PWM_OLD_NUM_TEMP;
data->pwm_duty[i] = 0x7f; /* Full speed */
data->auto_pwm[i][3] = 0x7f; /* Full speed, hard-coded */
}
@@ -3494,7 +3593,8 @@ static int it87_check_pwm(struct device *dev)
for (i = 0; i < ARRAY_SIZE(pwm); i++)
pwm[i] = it87_read_value(data,
- IT87_REG_PWM[i]);
+ it87_reg_pwm(data,
+ i));
/*
* If any fan is in automatic pwm mode, the polarity
@@ -3509,7 +3609,8 @@ static int it87_check_pwm(struct device *dev)
tmp | 0x87);
for (i = 0; i < 3; i++)
it87_write_value(data,
- IT87_REG_PWM[i],
+ it87_reg_pwm(data,
+ i),
0x7f & ~pwm[i]);
return 1;
}
@@ -3558,11 +3659,19 @@ static int it87_probe(struct platform_device *pdev)
data->ec_special_config = sio_data->ec_special_config;
chip = &it87_devices[sio_data->type];
data->features = chip->features;
+ data->reg_pwm = chip->reg_pwm;
data->peci_mask = chip->peci_mask;
data->old_peci_mask = chip->old_peci_mask;
data->num_temp_limit = chip->num_temp_limit;
data->num_temp_offset = chip->num_temp_offset;
data->num_temp_map = chip->num_temp_map;
+ if (has_new_tempmap(data)) {
+ data->pwm_temp_map_mask = 0x07;
+ data->pwm_temp_map_shift = 3;
+ } else {
+ data->pwm_temp_map_mask = 0x03;
+ data->pwm_temp_map_shift = 0;
+ }
/*
* IT8705F Datasheet 0.4.1, 3h == Version G.
* IT8712F Datasheet 0.9.1, section 8.3.5 indicates 8h == Version J.
--
2.55.0
^ permalink raw reply [flat|nested] 5+ messages in thread* [PATCH v5 3/4] hwmon: it87: expose additional temperature limits
2026-08-29 17:05 [PATCH v5 0/4] hwmon: it87: add IT8613E support Jerome Tollet
2026-08-29 17:05 ` [PATCH v5 1/4] hwmon: it87: describe per-chip temperature resources Jerome Tollet
2026-08-29 17:05 ` [PATCH v5 2/4] hwmon: it87: prepare for extended PWM temp maps Jerome Tollet
@ 2026-08-29 17:05 ` Jerome Tollet
2026-08-29 17:05 ` [PATCH v5 4/4] hwmon: it87: add IT8613E support Jerome Tollet
3 siblings, 0 replies; 5+ messages in thread
From: Jerome Tollet @ 2026-08-29 17:05 UTC (permalink / raw)
To: Jean Delvare, Guenter Roeck
Cc: linux-hwmon, Benoit Masson, Jonathan Corbet, Shuah Khan,
Randy Dunlap, linux-doc, linux-kernel, Jerome Tollet
From: "benoit.masson" <yahoo@perenite.com>
Expose extra temp min/max/offset/type/alarm attributes when a chip
reports more than three temperature resources.
Signed-off-by: benoit.masson <yahoo@perenite.com>
Signed-off-by: Jerome Tollet <jerome.tollet@gmail.com>
---
drivers/hwmon/it87.c | 58 ++++++++++++++++++++++++++++++++++++++++----
1 file changed, 53 insertions(+), 5 deletions(-)
diff --git a/drivers/hwmon/it87.c b/drivers/hwmon/it87.c
index e077adbb3..e44ec65c7 100644
--- a/drivers/hwmon/it87.c
+++ b/drivers/hwmon/it87.c
@@ -1349,8 +1349,26 @@ static SENSOR_DEVICE_ATTR_2(temp3_max, S_IRUGO | S_IWUSR, show_temp, set_temp,
static SENSOR_DEVICE_ATTR_2(temp3_offset, S_IRUGO | S_IWUSR, show_temp,
set_temp, 2, 3);
static SENSOR_DEVICE_ATTR_2(temp4_input, S_IRUGO, show_temp, NULL, 3, 0);
+static SENSOR_DEVICE_ATTR_2(temp4_min, 0644, show_temp, set_temp,
+ 3, 1);
+static SENSOR_DEVICE_ATTR_2(temp4_max, 0644, show_temp, set_temp,
+ 3, 2);
+static SENSOR_DEVICE_ATTR_2(temp4_offset, 0644, show_temp,
+ set_temp, 3, 3);
static SENSOR_DEVICE_ATTR_2(temp5_input, S_IRUGO, show_temp, NULL, 4, 0);
+static SENSOR_DEVICE_ATTR_2(temp5_min, 0644, show_temp, set_temp,
+ 4, 1);
+static SENSOR_DEVICE_ATTR_2(temp5_max, 0644, show_temp, set_temp,
+ 4, 2);
+static SENSOR_DEVICE_ATTR_2(temp5_offset, 0644, show_temp,
+ set_temp, 4, 3);
static SENSOR_DEVICE_ATTR_2(temp6_input, S_IRUGO, show_temp, NULL, 5, 0);
+static SENSOR_DEVICE_ATTR_2(temp6_min, 0644, show_temp, set_temp,
+ 5, 1);
+static SENSOR_DEVICE_ATTR_2(temp6_max, 0644, show_temp, set_temp,
+ 5, 2);
+static SENSOR_DEVICE_ATTR_2(temp6_offset, 0644, show_temp,
+ set_temp, 5, 3);
static int get_temp_type(struct it87_data *data, int index)
{
@@ -1476,6 +1494,12 @@ static SENSOR_DEVICE_ATTR(temp2_type, S_IRUGO | S_IWUSR, show_temp_type,
set_temp_type, 1);
static SENSOR_DEVICE_ATTR(temp3_type, S_IRUGO | S_IWUSR, show_temp_type,
set_temp_type, 2);
+static SENSOR_DEVICE_ATTR(temp4_type, 0644, show_temp_type,
+ set_temp_type, 3);
+static SENSOR_DEVICE_ATTR(temp5_type, 0644, show_temp_type,
+ set_temp_type, 4);
+static SENSOR_DEVICE_ATTR(temp6_type, 0644, show_temp_type,
+ set_temp_type, 5);
/* 6 Fans */
@@ -2308,6 +2332,9 @@ static SENSOR_DEVICE_ATTR(fan6_alarm, S_IRUGO, show_alarm, NULL, 7);
static SENSOR_DEVICE_ATTR(temp1_alarm, S_IRUGO, show_alarm, NULL, 16);
static SENSOR_DEVICE_ATTR(temp2_alarm, S_IRUGO, show_alarm, NULL, 17);
static SENSOR_DEVICE_ATTR(temp3_alarm, S_IRUGO, show_alarm, NULL, 18);
+static SENSOR_DEVICE_ATTR(temp4_alarm, 0444, show_alarm, NULL, 19);
+static SENSOR_DEVICE_ATTR(temp5_alarm, 0444, show_alarm, NULL, 20);
+static SENSOR_DEVICE_ATTR(temp6_alarm, 0444, show_alarm, NULL, 21);
static SENSOR_DEVICE_ATTR(intrusion0_alarm, S_IRUGO | S_IWUSR,
show_alarm, clear_intrusion, 4);
@@ -2368,6 +2395,9 @@ static SENSOR_DEVICE_ATTR(temp1_beep, S_IRUGO | S_IWUSR,
show_beep, set_beep, 2);
static SENSOR_DEVICE_ATTR(temp2_beep, S_IRUGO, show_beep, NULL, 2);
static SENSOR_DEVICE_ATTR(temp3_beep, S_IRUGO, show_beep, NULL, 2);
+static SENSOR_DEVICE_ATTR(temp4_beep, 0444, show_beep, NULL, 2);
+static SENSOR_DEVICE_ATTR(temp5_beep, 0444, show_beep, NULL, 2);
+static SENSOR_DEVICE_ATTR(temp6_beep, 0444, show_beep, NULL, 2);
static ssize_t vrm_show(struct device *dev, struct device_attribute *attr,
char *buf)
@@ -2530,14 +2560,12 @@ static umode_t it87_temp_is_visible(struct kobject *kobj,
int i = index / 7; /* temperature index */
int a = index % 7; /* attribute index */
- if (index >= 21) {
- i = index - 21 + 3;
- a = 0;
- }
-
if (!(data->has_temp & BIT(i)))
return 0;
+ if (a && i >= data->num_temp_limit)
+ return 0;
+
if (a == 3) {
if (get_temp_type(data, i) == 0)
return 0;
@@ -2579,8 +2607,28 @@ static struct attribute *it87_attributes_temp[] = {
&sensor_dev_attr_temp3_beep.dev_attr.attr,
&sensor_dev_attr_temp4_input.dev_attr.attr, /* 21 */
+ &sensor_dev_attr_temp4_max.dev_attr.attr,
+ &sensor_dev_attr_temp4_min.dev_attr.attr,
+ &sensor_dev_attr_temp4_type.dev_attr.attr,
+ &sensor_dev_attr_temp4_alarm.dev_attr.attr,
+ &sensor_dev_attr_temp4_offset.dev_attr.attr,
+ &sensor_dev_attr_temp4_beep.dev_attr.attr,
+
&sensor_dev_attr_temp5_input.dev_attr.attr,
+ &sensor_dev_attr_temp5_max.dev_attr.attr,
+ &sensor_dev_attr_temp5_min.dev_attr.attr,
+ &sensor_dev_attr_temp5_type.dev_attr.attr,
+ &sensor_dev_attr_temp5_alarm.dev_attr.attr,
+ &sensor_dev_attr_temp5_offset.dev_attr.attr,
+ &sensor_dev_attr_temp5_beep.dev_attr.attr,
+
&sensor_dev_attr_temp6_input.dev_attr.attr,
+ &sensor_dev_attr_temp6_max.dev_attr.attr,
+ &sensor_dev_attr_temp6_min.dev_attr.attr,
+ &sensor_dev_attr_temp6_type.dev_attr.attr,
+ &sensor_dev_attr_temp6_alarm.dev_attr.attr,
+ &sensor_dev_attr_temp6_offset.dev_attr.attr,
+ &sensor_dev_attr_temp6_beep.dev_attr.attr,
NULL
};
--
2.55.0
^ permalink raw reply [flat|nested] 5+ messages in thread* [PATCH v5 4/4] hwmon: it87: add IT8613E support
2026-08-29 17:05 [PATCH v5 0/4] hwmon: it87: add IT8613E support Jerome Tollet
` (2 preceding siblings ...)
2026-08-29 17:05 ` [PATCH v5 3/4] hwmon: it87: expose additional temperature limits Jerome Tollet
@ 2026-08-29 17:05 ` Jerome Tollet
3 siblings, 0 replies; 5+ messages in thread
From: Jerome Tollet @ 2026-08-29 17:05 UTC (permalink / raw)
To: Jean Delvare, Guenter Roeck
Cc: linux-hwmon, Benoit Masson, Jonathan Corbet, Shuah Khan,
Randy Dunlap, linux-doc, linux-kernel, Jerome Tollet
From: "benoit.masson" <yahoo@perenite.com>
Teach the Super I/O probe path to recognize IT8613E and add its
complete hardware monitoring configuration.
Add feature flags, temperature resource counts, 11 mV ADC scaling,
the IT8665-style PWM register map, and GPIO pin-mux checks. Document
the chip in the hwmon guide.
Signed-off-by: benoit.masson <yahoo@perenite.com>
Signed-off-by: Jerome Tollet <jerome.tollet@gmail.com>
---
Documentation/hwmon/it87.rst | 8 +++++
drivers/hwmon/it87.c | 64 ++++++++++++++++++++++++++++++++++--
2 files changed, 70 insertions(+), 2 deletions(-)
diff --git a/Documentation/hwmon/it87.rst b/Documentation/hwmon/it87.rst
index fc1c90b02..c33ba8a07 100644
--- a/Documentation/hwmon/it87.rst
+++ b/Documentation/hwmon/it87.rst
@@ -11,6 +11,14 @@ Supported chips:
Datasheet: Not publicly available
+ * IT8613E
+
+ Prefix: 'it8613'
+
+ Addresses scanned: from Super I/O config space (8 I/O ports)
+
+ Datasheet: Not publicly available
+
* IT8620E
Prefix: 'it8620'
diff --git a/drivers/hwmon/it87.c b/drivers/hwmon/it87.c
index e44ec65c7..67a94761d 100644
--- a/drivers/hwmon/it87.c
+++ b/drivers/hwmon/it87.c
@@ -36,6 +36,7 @@
* IT8790E Super I/O chip w/LPC interface
* IT8792E Super I/O chip w/LPC interface
* IT87952E Super I/O chip w/LPC interface
+ * IT8613E Super I/O chip w/LPC interface
* Sis950 A clone of the IT8705F
*
* Copyright (C) 2001 Chris Gauthron
@@ -65,7 +66,7 @@
enum chips { it87, it8712, it8716, it8718, it8720, it8721, it8728, it8732,
it8771, it8772, it8781, it8782, it8783, it8786, it8790,
- it8792, it8603, it8620, it8622, it8628, it8689, it87952 };
+ it8792, it8603, it8613, it8620, it8622, it8628, it8689, it87952 };
static struct platform_device *it87_pdev[2];
@@ -159,6 +160,7 @@ static inline void superio_exit(int ioreg, bool noexit)
#define IT8786E_DEVID 0x8786
#define IT8790E_DEVID 0x8790
#define IT8603E_DEVID 0x8603
+#define IT8613E_DEVID 0x8613
#define IT8620E_DEVID 0x8620
#define IT8622E_DEVID 0x8622
#define IT8623E_DEVID 0x8623
@@ -333,6 +335,7 @@ struct it87_devices {
#define FEAT_FOUR_TEMP BIT(22)
#define FEAT_FANCTL_ONOFF BIT(23) /* chip has FAN_CTL ON/OFF */
#define FEAT_NEW_TEMPMAP BIT(24) /* PWM uses extended temp map */
+#define FEAT_11MV_ADC BIT(25)
static const struct it87_devices it87_devices[] = {
[it87] = {
@@ -549,6 +552,19 @@ static const struct it87_devices it87_devices[] = {
.num_temp_map = 4,
.peci_mask = 0x07,
},
+ [it8613] = {
+ .name = "it8613",
+ .model = "IT8613E",
+ .features = FEAT_NEWER_AUTOPWM | FEAT_11MV_ADC | FEAT_16BIT_FANS
+ | FEAT_TEMP_PECI | FEAT_FIVE_FANS
+ | FEAT_FIVE_PWM | FEAT_IN7_INTERNAL | FEAT_PWM_FREQ2
+ | FEAT_AVCC3 | FEAT_NEW_TEMPMAP,
+ .reg_pwm = IT87_REG_PWM_8665,
+ .num_temp_limit = 6,
+ .num_temp_offset = 6,
+ .num_temp_map = 6,
+ .peci_mask = 0x07,
+ },
[it8620] = {
.name = "it8620",
.model = "IT8620E",
@@ -621,6 +637,7 @@ static const struct it87_devices it87_devices[] = {
#define has_16bit_fans(data) ((data)->features & FEAT_16BIT_FANS)
#define has_12mv_adc(data) ((data)->features & FEAT_12MV_ADC)
#define has_10_9mv_adc(data) ((data)->features & FEAT_10_9MV_ADC)
+#define has_11mv_adc(data) ((data)->features & FEAT_11MV_ADC)
#define has_newer_autopwm(data) ((data)->features & FEAT_NEWER_AUTOPWM)
#define has_old_autopwm(data) ((data)->features & FEAT_OLD_AUTOPWM)
#define has_temp_peci(data, nr) (((data)->features & FEAT_TEMP_PECI) && \
@@ -650,7 +667,8 @@ static const struct it87_devices it87_devices[] = {
#define has_vin3_5v(data) ((data)->features & FEAT_VIN3_5V)
#define has_noconf(data) ((data)->features & FEAT_NOCONF)
#define has_scaling(data) ((data)->features & (FEAT_12MV_ADC | \
- FEAT_10_9MV_ADC))
+ FEAT_10_9MV_ADC | \
+ FEAT_11MV_ADC))
#define has_fanctl_onoff(data) ((data)->features & FEAT_FANCTL_ONOFF)
#define has_new_tempmap(data) ((data)->features & FEAT_NEW_TEMPMAP)
@@ -757,6 +775,8 @@ static int adc_lsb(const struct it87_data *data, int nr)
lsb = 120;
else if (has_10_9mv_adc(data))
lsb = 109;
+ else if (has_11mv_adc(data))
+ lsb = 110;
else
lsb = 160;
if (data->in_scaled & BIT(nr))
@@ -3006,6 +3026,9 @@ static int __init it87_find(int sioaddr, unsigned short *address,
case IT8623E_DEVID:
sio_data->type = it8603;
break;
+ case IT8613E_DEVID:
+ sio_data->type = it8613;
+ break;
case IT8620E_DEVID:
sio_data->type = it8620;
break;
@@ -3183,6 +3206,43 @@ static int __init it87_find(int sioaddr, unsigned short *address,
sio_data->skip_in |= BIT(5); /* No VIN5 */
sio_data->skip_in |= BIT(6); /* No VIN6 */
+ sio_data->beep_pin = superio_inb(sioaddr,
+ IT87_SIO_BEEP_PIN_REG) & 0x3f;
+ } else if (sio_data->type == it8613) {
+ int reg27, reg29, reg2a;
+
+ superio_select(sioaddr, GPIO);
+
+ /* Check for pwm3, fan3, pwm5, fan5 */
+ reg27 = superio_inb(sioaddr, IT87_SIO_GPIO3_REG);
+ if (!(reg27 & BIT(1)))
+ sio_data->skip_fan |= BIT(4);
+ if (reg27 & BIT(3))
+ sio_data->skip_pwm |= BIT(4);
+ if (reg27 & BIT(6))
+ sio_data->skip_pwm |= BIT(2);
+ if (reg27 & BIT(7))
+ sio_data->skip_fan |= BIT(2);
+
+ /* Check for pwm2, fan2 */
+ reg29 = superio_inb(sioaddr, IT87_SIO_GPIO5_REG);
+ if (reg29 & BIT(1))
+ sio_data->skip_pwm |= BIT(1);
+ if (reg29 & BIT(2))
+ sio_data->skip_fan |= BIT(1);
+
+ /* Check for pwm4, fan4 */
+ reg2a = superio_inb(sioaddr, IT87_SIO_PINX1_REG);
+ if (!(reg2a & BIT(0)) || (reg29 & BIT(7))) {
+ sio_data->skip_fan |= BIT(3);
+ sio_data->skip_pwm |= BIT(3);
+ }
+
+ sio_data->skip_pwm |= BIT(0); /* No pwm1 */
+ sio_data->skip_fan |= BIT(0); /* No fan1 */
+ sio_data->skip_in |= BIT(3); /* No VIN3 */
+ sio_data->skip_in |= BIT(6); /* No VIN6 */
+
sio_data->beep_pin = superio_inb(sioaddr,
IT87_SIO_BEEP_PIN_REG) & 0x3f;
} else if (sio_data->type == it8620 || sio_data->type == it8628) {
--
2.55.0
^ permalink raw reply [flat|nested] 5+ messages in thread