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
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_RASPBERRYPI_HWMON) += raspberrypi-hwmon.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_SCH5627) += sch5627.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)
{
int ret;
reg = reg | INST_READ_BM | INST_16BIT_BM;
ret = spi_w8r16(spi, reg);
return ret;
if (ret < 0)
return ret;
return le16_to_cpu((__force __le16)ret);
}
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);
if (ret < 0) {
dev_err(&hdev->dev, "unable to initialize device (%d)\n", ret);
goto fail_and_stop;
goto fail_and_close;
}
ret = corsairpsu_fwinfo(priv);
if (ret < 0) {
dev_err(&hdev->dev, "unable to query firmware (%d)\n", ret);
goto fail_and_stop;
goto fail_and_close;
}
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 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,
@ -366,12 +372,14 @@ static ssize_t show_pwm1(struct device *dev, struct device_attribute *devattr,
int nr = attr->index;
int pwm;
mutex_lock(&data->update_lock);
if (data->pwm_highres)
pwm = data->pwm1[nr];
else
pwm = data->pwm1[nr] >= 2 * data->pwm1_freq ?
255 : (data->pwm1[nr] * 255 + data->pwm1_freq) /
(2 * data->pwm1_freq);
mutex_unlock(&data->update_lock);
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 temp;
mutex_lock(&data->update_lock);
if (!nr) {
/*
* 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
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,
@ -592,9 +604,14 @@ static ssize_t temp2_crit_hyst_show(struct device *dev,
struct device_attribute *dummy, char *buf)
{
struct lm63_data *data = lm63_update_device(dev);
return sprintf(buf, "%d\n", temp8_from_reg(data, 2)
+ data->temp2_offset
- TEMP8_FROM_REG(data->temp2_crit_hyst));
int temp;
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,
@ -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 lm63_data *data = lm63_update_device(dev);
int temp;
return sprintf(buf, "%d\n", lut_temp_from_reg(data, attr->index)
+ data->temp2_offset
- TEMP8_FROM_REG(data->lut_temp_hyst));
mutex_lock(&data->update_lock);
temp = lut_temp_from_reg(data, attr->index) + data->temp2_offset
- 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,
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;
long val;
int err;

View File

@ -137,7 +137,7 @@ static const struct lm75_params device_params[] = {
},
[as6200] = {
.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_sample_time = 125,
.num_sample_times = 4,
@ -286,8 +286,8 @@ static const struct lm75_params device_params[] = {
},
[tmp112] = {
.config_reg_16bits = true,
.set_mask = 0x60C0, /* 12-bit mode, 8 samples / second */
.clr_mask = 1 << 15, /* no one-shot mode*/
.set_mask = 0xC060, /* 12-bit mode, 8 samples / second */
.clr_mask = 1 << 7, /* no one-shot mode*/
.default_resolution = 12,
.default_sample_time = 125,
.num_sample_times = 4,
@ -353,7 +353,7 @@ static inline int lm75_write_config(struct lm75_data *data, u16 set_mask,
u16 clr_mask)
{
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)
@ -416,7 +416,7 @@ static int lm75_read(struct device *dev, enum hwmon_sensor_types type,
switch (data->kind) {
case as6200:
case tmp112:
*val = (regval >> 13) & 0x1;
*val = !!(regval & BIT(13)) == !!(regval & BIT(2));
break;
default:
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)
{
val = DIV_ROUND_CLOSEST(val * 1000, scale);
val = val << 4;
u32 reg_val;
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)
@ -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)
{
u32 reg_val;
long cmax;
reg_val = DIV_ROUND_CLOSEST(val * st->r_sense_uohm[channel], LTC2992_IADC_NANOV_LSB);
reg_val = reg_val << 4;
cmax = DIV_ROUND_CLOSEST_ULL(0xFFFULL * LTC2992_IADC_NANOV_LSB,
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);
}
@ -625,8 +637,10 @@ static int ltc2992_get_power(struct ltc2992_state *st, u32 reg, u32 channel, lon
if (reg_val < 0)
return reg_val;
*val = mul_u64_u32_div(reg_val, LTC2992_VADC_UV_LSB * LTC2992_IADC_NANOV_LSB,
st->r_sense_uohm[channel] * 1000);
*val = mul_u64_u32_div(reg_val,
LTC2992_VADC_UV_LSB / 1000 *
LTC2992_IADC_NANOV_LSB,
st->r_sense_uohm[channel]);
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)
{
u32 reg_val;
u64 pmax, uval;
reg_val = mul_u64_u32_div(val, st->r_sense_uohm[channel] * 1000,
LTC2992_VADC_UV_LSB * LTC2992_IADC_NANOV_LSB);
uval = max(val, 0L);
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);
}