hwmon fixes for v7.1-rc3

* ads7871: Fix endianness bug in 16-bit register reads
 
 * lm75: Fix configuration register writes and AS6200/TMP112 setup and
   alarm handling
 
 * lm63: Fix TOCTOU problems
 
 * corsair-psu: Close HID device on probe errors
 
 * ltc2992: Fix overflow and threshold range
 
 * Documentation: fix link to ideapad-laptop.c file
 
 * Makefile: Remove stale CONFIG_SENSORS_SBRMI Makefile reference
 -----BEGIN PGP SIGNATURE-----
 
 iQIzBAABCAAdFiEEiHPvMQj9QTOCiqgVyx8mb86fmYEFAmn/RB8ACgkQyx8mb86f
 mYGoYQ//UP395fxUKRA7Z2yqI6qOCm0afBpuinf406qOks8ape7caPzM3lgrwTIv
 vvL+VRmPhCdxrl1u3VP5wM802k7jzJ8JmIGiB767ArquFhEuSoSH1J0JRs2EBbcA
 gRHgtWKbbKZbIMaoAZ6HZCuc9CjdV1jxmVn1XtuD06e6grXmXOLQLt80SsKQBDgG
 Pa7w+dMzT53DaRrAy5XzSbB7LK6ADdacivNlu0/W5qWuHw3oVDqloGdXGCLGcLfd
 h4XKq3LzZetu3Hb352PAoCBGN/vEJaKexb8TzHB/omqijEKi8PiZIueldiZSc+5N
 ndTPP1oHSuh4S/lS+cfl1YqQmQjAyylLk4PHp3fIZmm+YAc4RqhQrAaM2nIYnLGf
 lcdKkeZatwLp6ynO68gJxuK6JTacy9alWGwffzuVqVOCdcZsz8x5F0PNvSoYXKST
 La05RZ/sm0TQQxkSzj8DIg17Qlc/byg3EQ5PIYpBd08zgMr5ohUwDIfgZ9zgmBsh
 ShFggpSu43gW6ltRYjNcpKZnrd5ahglHB1yCbfmBUzx7ZjPiF2p4nyGweFWQceGQ
 64X0NvXmHID4PlR36KkalU4OTB+u73ml0J42qlEjbu82E5qRtl3TUEGbLeShfHcQ
 SWvHqfdP/vaQXrVjR+XY2nzSBhhhE5WP4KC2kUm5AJ2FBCt9tP8=
 =5LR5
 -----END PGP SIGNATURE-----

Merge tag 'hwmon-for-v7.1-rc3' of git://git.kernel.org/pub/scm/linux/kernel/git/groeck/linux-staging

Pull hwmon fixes from Guenter Roeck:

 - ads7871: Fix endianness bug in 16-bit register reads

 - lm75: Fix configuration register writes and AS6200/TMP112 setup and
   alarm handling

 - lm63: Fix TOCTOU problems

 - corsair-psu: Close HID device on probe errors

 - ltc2992: Fix overflow and threshold range

 - Documentation: fix link to ideapad-laptop.c file

 - Remove stale CONFIG_SENSORS_SBRMI Makefile reference

* tag 'hwmon-for-v7.1-rc3' of git://git.kernel.org/pub/scm/linux/kernel/git/groeck/linux-staging:
  hwmon: (ads7871) Fix endianness bug in 16-bit register reads
  hwmon: (lm75) Fix configuration register writes.
  hwmon: (lm75) Fix AS6200 and TMP112 setup and alarm handling
  hwmon: (lm63) Add locking to avoid TOCTOU
  hwmon: (corsair-psu) Close HID device on probe errors
  hwmon: Remove stale CONFIG_SENSORS_SBRMI Makefile reference
  Documentation: hwmon: fix link to ideapad-laptop.c file
  hwmon: (ltc2992) Fix u32 overflow in power read path
  hwmon: (ltc2992) Clamp threshold writes to hardware range
This commit is contained in:
Linus Torvalds 2026-05-09 08:32:50 -07:00
commit ec89572766
7 changed files with 75 additions and 28 deletions

View File

@ -135,4 +135,4 @@ References
4. **Lenovo IdeaPad Laptop Driver:** Reference for DMI-based hardware 4. **Lenovo IdeaPad Laptop Driver:** Reference for DMI-based hardware
feature gating in Lenovo laptops. feature gating in Lenovo laptops.
https://github.com/torvalds/linux/blob/master/drivers/platform/x86/ideapad-laptop.c https://github.com/torvalds/linux/blob/master/drivers/platform/x86/lenovo/ideapad-laptop.c

View File

@ -201,7 +201,6 @@ obj-$(CONFIG_SENSORS_PWM_FAN) += pwm-fan.o
obj-$(CONFIG_SENSORS_QNAP_MCU_HWMON) += qnap-mcu-hwmon.o obj-$(CONFIG_SENSORS_QNAP_MCU_HWMON) += qnap-mcu-hwmon.o
obj-$(CONFIG_SENSORS_RASPBERRYPI_HWMON) += raspberrypi-hwmon.o obj-$(CONFIG_SENSORS_RASPBERRYPI_HWMON) += raspberrypi-hwmon.o
obj-$(CONFIG_SENSORS_SBTSI) += sbtsi_temp.o obj-$(CONFIG_SENSORS_SBTSI) += sbtsi_temp.o
obj-$(CONFIG_SENSORS_SBRMI) += sbrmi.o
obj-$(CONFIG_SENSORS_SCH56XX_COMMON)+= sch56xx-common.o obj-$(CONFIG_SENSORS_SCH56XX_COMMON)+= sch56xx-common.o
obj-$(CONFIG_SENSORS_SCH5627) += sch5627.o obj-$(CONFIG_SENSORS_SCH5627) += sch5627.o
obj-$(CONFIG_SENSORS_SCH5636) += sch5636.o obj-$(CONFIG_SENSORS_SCH5636) += sch5636.o

View File

@ -77,9 +77,13 @@ static int ads7871_read_reg8(struct spi_device *spi, int reg)
static int ads7871_read_reg16(struct spi_device *spi, int reg) static int ads7871_read_reg16(struct spi_device *spi, int reg)
{ {
int ret; int ret;
reg = reg | INST_READ_BM | INST_16BIT_BM; reg = reg | INST_READ_BM | INST_16BIT_BM;
ret = spi_w8r16(spi, reg); ret = spi_w8r16(spi, reg);
if (ret < 0)
return ret; return ret;
return le16_to_cpu((__force __le16)ret);
} }
static int ads7871_write_reg8(struct spi_device *spi, int reg, u8 val) static int ads7871_write_reg8(struct spi_device *spi, int reg, u8 val)

View File

@ -796,13 +796,13 @@ static int corsairpsu_probe(struct hid_device *hdev, const struct hid_device_id
ret = corsairpsu_init(priv); ret = corsairpsu_init(priv);
if (ret < 0) { if (ret < 0) {
dev_err(&hdev->dev, "unable to initialize device (%d)\n", ret); dev_err(&hdev->dev, "unable to initialize device (%d)\n", ret);
goto fail_and_stop; goto fail_and_close;
} }
ret = corsairpsu_fwinfo(priv); ret = corsairpsu_fwinfo(priv);
if (ret < 0) { if (ret < 0) {
dev_err(&hdev->dev, "unable to query firmware (%d)\n", ret); dev_err(&hdev->dev, "unable to query firmware (%d)\n", ret);
goto fail_and_stop; goto fail_and_close;
} }
corsairpsu_get_criticals(priv); corsairpsu_get_criticals(priv);

View File

@ -333,7 +333,13 @@ static ssize_t show_fan(struct device *dev, struct device_attribute *devattr,
{ {
struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
struct lm63_data *data = lm63_update_device(dev); struct lm63_data *data = lm63_update_device(dev);
return sprintf(buf, "%d\n", FAN_FROM_REG(data->fan[attr->index])); int fan;
mutex_lock(&data->update_lock);
fan = FAN_FROM_REG(data->fan[attr->index]);
mutex_unlock(&data->update_lock);
return sprintf(buf, "%d\n", fan);
} }
static ssize_t set_fan(struct device *dev, struct device_attribute *dummy, static ssize_t set_fan(struct device *dev, struct device_attribute *dummy,
@ -366,12 +372,14 @@ static ssize_t show_pwm1(struct device *dev, struct device_attribute *devattr,
int nr = attr->index; int nr = attr->index;
int pwm; int pwm;
mutex_lock(&data->update_lock);
if (data->pwm_highres) if (data->pwm_highres)
pwm = data->pwm1[nr]; pwm = data->pwm1[nr];
else else
pwm = data->pwm1[nr] >= 2 * data->pwm1_freq ? pwm = data->pwm1[nr] >= 2 * data->pwm1_freq ?
255 : (data->pwm1[nr] * 255 + data->pwm1_freq) / 255 : (data->pwm1[nr] * 255 + data->pwm1_freq) /
(2 * data->pwm1_freq); (2 * data->pwm1_freq);
mutex_unlock(&data->update_lock);
return sprintf(buf, "%d\n", pwm); return sprintf(buf, "%d\n", pwm);
} }
@ -529,6 +537,7 @@ static ssize_t show_temp11(struct device *dev, struct device_attribute *devattr,
int nr = attr->index; int nr = attr->index;
int temp; int temp;
mutex_lock(&data->update_lock);
if (!nr) { if (!nr) {
/* /*
* Use unsigned temperature unless its value is zero. * Use unsigned temperature unless its value is zero.
@ -544,7 +553,10 @@ static ssize_t show_temp11(struct device *dev, struct device_attribute *devattr,
else else
temp = TEMP11_FROM_REG(data->temp11[nr]); temp = TEMP11_FROM_REG(data->temp11[nr]);
} }
return sprintf(buf, "%d\n", temp + data->temp2_offset); temp += data->temp2_offset;
mutex_unlock(&data->update_lock);
return sprintf(buf, "%d\n", temp);
} }
static ssize_t set_temp11(struct device *dev, struct device_attribute *devattr, static ssize_t set_temp11(struct device *dev, struct device_attribute *devattr,
@ -592,9 +604,14 @@ static ssize_t temp2_crit_hyst_show(struct device *dev,
struct device_attribute *dummy, char *buf) struct device_attribute *dummy, char *buf)
{ {
struct lm63_data *data = lm63_update_device(dev); struct lm63_data *data = lm63_update_device(dev);
return sprintf(buf, "%d\n", temp8_from_reg(data, 2) int temp;
+ data->temp2_offset
- TEMP8_FROM_REG(data->temp2_crit_hyst)); mutex_lock(&data->update_lock);
temp = temp8_from_reg(data, 2) + data->temp2_offset
- TEMP8_FROM_REG(data->temp2_crit_hyst);
mutex_unlock(&data->update_lock);
return sprintf(buf, "%d\n", temp);
} }
static ssize_t show_lut_temp_hyst(struct device *dev, static ssize_t show_lut_temp_hyst(struct device *dev,
@ -602,10 +619,14 @@ static ssize_t show_lut_temp_hyst(struct device *dev,
{ {
struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr); struct sensor_device_attribute *attr = to_sensor_dev_attr(devattr);
struct lm63_data *data = lm63_update_device(dev); struct lm63_data *data = lm63_update_device(dev);
int temp;
return sprintf(buf, "%d\n", lut_temp_from_reg(data, attr->index) mutex_lock(&data->update_lock);
+ data->temp2_offset temp = lut_temp_from_reg(data, attr->index) + data->temp2_offset
- TEMP8_FROM_REG(data->lut_temp_hyst)); - TEMP8_FROM_REG(data->lut_temp_hyst);
mutex_unlock(&data->update_lock);
return sprintf(buf, "%d\n", temp);
} }
/* /*
@ -616,7 +637,7 @@ static ssize_t temp2_crit_hyst_store(struct device *dev,
struct device_attribute *dummy, struct device_attribute *dummy,
const char *buf, size_t count) const char *buf, size_t count)
{ {
struct lm63_data *data = dev_get_drvdata(dev); struct lm63_data *data = lm63_update_device(dev);
struct i2c_client *client = data->client; struct i2c_client *client = data->client;
long val; long val;
int err; int err;

View File

@ -137,7 +137,7 @@ static const struct lm75_params device_params[] = {
}, },
[as6200] = { [as6200] = {
.config_reg_16bits = true, .config_reg_16bits = true,
.set_mask = 0x94C0, /* 8 sample/s, 4 CF, positive polarity */ .set_mask = 0xC010, /* 8 sample/s, 4 CF */
.default_resolution = 12, .default_resolution = 12,
.default_sample_time = 125, .default_sample_time = 125,
.num_sample_times = 4, .num_sample_times = 4,
@ -286,8 +286,8 @@ static const struct lm75_params device_params[] = {
}, },
[tmp112] = { [tmp112] = {
.config_reg_16bits = true, .config_reg_16bits = true,
.set_mask = 0x60C0, /* 12-bit mode, 8 samples / second */ .set_mask = 0xC060, /* 12-bit mode, 8 samples / second */
.clr_mask = 1 << 15, /* no one-shot mode*/ .clr_mask = 1 << 7, /* no one-shot mode*/
.default_resolution = 12, .default_resolution = 12,
.default_sample_time = 125, .default_sample_time = 125,
.num_sample_times = 4, .num_sample_times = 4,
@ -353,7 +353,7 @@ static inline int lm75_write_config(struct lm75_data *data, u16 set_mask,
u16 clr_mask) u16 clr_mask)
{ {
return regmap_update_bits(data->regmap, LM75_REG_CONF, return regmap_update_bits(data->regmap, LM75_REG_CONF,
clr_mask | LM75_SHUTDOWN, set_mask); clr_mask | set_mask | LM75_SHUTDOWN, set_mask);
} }
static irqreturn_t lm75_alarm_handler(int irq, void *private) static irqreturn_t lm75_alarm_handler(int irq, void *private)
@ -416,7 +416,7 @@ static int lm75_read(struct device *dev, enum hwmon_sensor_types type,
switch (data->kind) { switch (data->kind) {
case as6200: case as6200:
case tmp112: case tmp112:
*val = (regval >> 13) & 0x1; *val = !!(regval & BIT(13)) == !!(regval & BIT(2));
break; break;
default: default:
return -EINVAL; return -EINVAL;

View File

@ -431,10 +431,16 @@ static int ltc2992_get_voltage(struct ltc2992_state *st, u32 reg, u32 scale, lon
static int ltc2992_set_voltage(struct ltc2992_state *st, u32 reg, u32 scale, long val) static int ltc2992_set_voltage(struct ltc2992_state *st, u32 reg, u32 scale, long val)
{ {
val = DIV_ROUND_CLOSEST(val * 1000, scale); u32 reg_val;
val = val << 4; long vmax;
return ltc2992_write_reg(st, reg, 2, val); vmax = DIV_ROUND_CLOSEST_ULL(0xFFFULL * scale, 1000);
val = max(val, 0L);
val = min(val, vmax);
reg_val = min(DIV_ROUND_CLOSEST_ULL((u64)val * 1000, scale),
0xFFFULL) << 4;
return ltc2992_write_reg(st, reg, 2, reg_val);
} }
static int ltc2992_read_gpio_alarm(struct ltc2992_state *st, int nr_gpio, u32 attr, long *val) static int ltc2992_read_gpio_alarm(struct ltc2992_state *st, int nr_gpio, u32 attr, long *val)
@ -559,9 +565,15 @@ static int ltc2992_get_current(struct ltc2992_state *st, u32 reg, u32 channel, l
static int ltc2992_set_current(struct ltc2992_state *st, u32 reg, u32 channel, long val) static int ltc2992_set_current(struct ltc2992_state *st, u32 reg, u32 channel, long val)
{ {
u32 reg_val; u32 reg_val;
long cmax;
reg_val = DIV_ROUND_CLOSEST(val * st->r_sense_uohm[channel], LTC2992_IADC_NANOV_LSB); cmax = DIV_ROUND_CLOSEST_ULL(0xFFFULL * LTC2992_IADC_NANOV_LSB,
reg_val = reg_val << 4; st->r_sense_uohm[channel]);
val = max(val, 0L);
val = min(val, cmax);
reg_val = min(DIV_ROUND_CLOSEST_ULL((u64)val * st->r_sense_uohm[channel],
LTC2992_IADC_NANOV_LSB),
0xFFFULL) << 4;
return ltc2992_write_reg(st, reg, 2, reg_val); return ltc2992_write_reg(st, reg, 2, reg_val);
} }
@ -625,8 +637,10 @@ static int ltc2992_get_power(struct ltc2992_state *st, u32 reg, u32 channel, lon
if (reg_val < 0) if (reg_val < 0)
return reg_val; return reg_val;
*val = mul_u64_u32_div(reg_val, LTC2992_VADC_UV_LSB * LTC2992_IADC_NANOV_LSB, *val = mul_u64_u32_div(reg_val,
st->r_sense_uohm[channel] * 1000); LTC2992_VADC_UV_LSB / 1000 *
LTC2992_IADC_NANOV_LSB,
st->r_sense_uohm[channel]);
return 0; return 0;
} }
@ -634,9 +648,18 @@ static int ltc2992_get_power(struct ltc2992_state *st, u32 reg, u32 channel, lon
static int ltc2992_set_power(struct ltc2992_state *st, u32 reg, u32 channel, long val) static int ltc2992_set_power(struct ltc2992_state *st, u32 reg, u32 channel, long val)
{ {
u32 reg_val; u32 reg_val;
u64 pmax, uval;
reg_val = mul_u64_u32_div(val, st->r_sense_uohm[channel] * 1000, uval = max(val, 0L);
LTC2992_VADC_UV_LSB * LTC2992_IADC_NANOV_LSB); pmax = mul_u64_u32_div(0xFFFFFFULL,
LTC2992_VADC_UV_LSB / 1000 *
LTC2992_IADC_NANOV_LSB,
st->r_sense_uohm[channel]);
uval = min(uval, pmax);
reg_val = min(mul_u64_u32_div(uval, st->r_sense_uohm[channel],
LTC2992_VADC_UV_LSB / 1000 *
LTC2992_IADC_NANOV_LSB),
0xFFFFFFULL);
return ltc2992_write_reg(st, reg, 3, reg_val); return ltc2992_write_reg(st, reg, 3, reg_val);
} }