hwmon fixes for v7.0-rc3

- aht10: Fix initialization commands for AHT20
 
 - emc1403: correct a malformed email address
 
 - it87: Check the it87_lock() return value
 
 - max6639: fix inverted polarity
 
 - macsmc: Fix overflows, underflows, sign extension, and other problems
 
 - pmbus/q54sj108a2: fix stack overflow in debugfs read
 
 - Drop support for SMARC-sAM67 (discontinued and never released to market)
 -----BEGIN PGP SIGNATURE-----
 
 iQIzBAABCAAdFiEEiHPvMQj9QTOCiqgVyx8mb86fmYEFAmmsDycACgkQyx8mb86f
 mYE5PhAAjn5II2E0aAJhuulPIEtMQekjZd33q//XUGL5tcz5PVakVtK6MBkGQA7P
 a3ryouTH4TUlmfjlwEWHu3Dde3bElStfUoFWAvvQc74rkiZdmSbo3fyU4LWNGnIu
 2lxcOsjpMbIUC2xV0WUUmg/2r/v+Z8mFrLXbF0YEzhZfzpMin3kNxdCTjBqAa6p7
 E6/Wayxh13W1o0UNJNnCJ6jdxKQPQ8GkVgB9EyivJqmyiJjrPhbFN4KWVhUCHhGF
 mvoMzuC6inVbMwDa2cjU8Ykx9NqVMte4xqZ92f8F8ObH6+dxoRJeszrAvY5PDwy0
 p8OJcB9bZXzv7VYLBxIEsQg3Dm/VVk7YqRpPtChjrL7Z6VUtV170mq4r54YeLWfA
 6xNwoNZpxylOjbG57F+Tv9S2ogQtxyGmg+J5r14tB2IQKJEZQfmsYAIXLeJwgcwu
 gPJWvQsUiB0sMe5Uoxck9EQou5QCKfdjX/XrlRfJm94aZHicajgM/wEXBFtn4a0E
 U3k1WSWq9aVTZrto6mMaVrXnAu2dWrXY2TkfxI/3/6Q8NDdg2ckDaTKFaPC3w9Xy
 S31SMjI98EviNKpZ9K9aP4RpYQTQk/K50fisZ4cZtT+trDvnEcc161+USB7tYE6j
 YdOjYM+Eqh3cEIDGjiP4lLS8Tnc8+IzpqljGru99TbgK9Ma4hXI=
 =+l89
 -----END PGP SIGNATURE-----

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

Pull hwmon fixes from Guenter Roeck:

 - Fix initialization commands for AHT20

 - Correct a malformed email address (emc1403)

 - Check the it87_lock() return value

 - Fix inverted polarity (max6639)

 - Fix overflows, underflows, sign extension, and other problems in
   macsmc

 - Fix stack overflow in debugfs read (pmbus/q54sj108a2)

 - Drop support for SMARC-sAM67 (discontinued and never released to
   market)

* tag 'hwmon-for-v7.0-rc3' of git://git.kernel.org/pub/scm/linux/kernel/git/groeck/linux-staging:
  hwmon: (pmbus/q54sj108a2) fix stack overflow in debugfs read
  hwmon: (max6639) fix inverted polarity
  dt-bindings: hwmon: sl28cpld: Drop sa67mcu compatible
  hwmon: (it87) Check the it87_lock() return value
  Revert "hwmon: add SMARC-sAM67 support"
  hwmon: (aht10) Fix initialization commands for AHT20
  hwmon: (emc1403) correct a malformed email address
  hwmon: (macsmc) Fix overflows, underflows, and sign extension
  hwmon: (macsmc) Fix regressions in Apple Silicon SMC hwmon driver
This commit is contained in:
Linus Torvalds 2026-03-07 08:39:59 -08:00
commit 7b6e48df88
13 changed files with 46 additions and 255 deletions

View file

@ -16,7 +16,6 @@ description: |
properties:
compatible:
enum:
- kontron,sa67mcu-hwmon
- kontron,sl28cpld-fan
reg:

View file

@ -57,7 +57,7 @@ Supported chips:
- https://ww1.microchip.com/downloads/en/DeviceDoc/EMC1438%20DS%20Rev.%201.0%20(04-29-10).pdf
Author:
Kalhan Trisal <kalhan.trisal@intel.com
Kalhan Trisal <kalhan.trisal@intel.com>
Description

View file

@ -220,7 +220,6 @@ Hardware Monitoring Kernel Drivers
q54sj108a2
qnap-mcu-hwmon
raspberrypi-hwmon
sa67
sbrmi
sbtsi_temp
sch5627

View file

@ -1,41 +0,0 @@
.. SPDX-License-Identifier: GPL-2.0-only
Kernel driver sa67mcu
=====================
Supported chips:
* Kontron sa67mcu
Prefix: 'sa67mcu'
Datasheet: not available
Authors: Michael Walle <mwalle@kernel.org>
Description
-----------
The sa67mcu is a board management controller which also exposes a hardware
monitoring controller.
The controller has two voltage and one temperature sensor. The values are
hold in two 8 bit registers to form one 16 bit value. Reading the lower byte
will also capture the high byte to make the access atomic. The unit of the
volatge sensors are 1mV and the unit of the temperature sensor is 0.1degC.
Sysfs entries
-------------
The following attributes are supported.
======================= ========================================================
in0_label "VDDIN"
in0_input Measured VDDIN voltage.
in1_label "VDD_RTC"
in1_input Measured VDD_RTC voltage.
temp1_input MCU temperature. Roughly the board temperature.
======================= ========================================================

View file

@ -24320,7 +24320,6 @@ F: Documentation/devicetree/bindings/interrupt-controller/kontron,sl28cpld-intc.
F: Documentation/devicetree/bindings/pwm/kontron,sl28cpld-pwm.yaml
F: Documentation/devicetree/bindings/watchdog/kontron,sl28cpld-wdt.yaml
F: drivers/gpio/gpio-sl28cpld.c
F: drivers/hwmon/sa67mcu-hwmon.c
F: drivers/hwmon/sl28cpld-hwmon.c
F: drivers/irqchip/irq-sl28cpld.c
F: drivers/pwm/pwm-sl28cpld.c

View file

@ -1927,16 +1927,6 @@ config SENSORS_RASPBERRYPI_HWMON
This driver can also be built as a module. If so, the module
will be called raspberrypi-hwmon.
config SENSORS_SA67MCU
tristate "Kontron sa67mcu hardware monitoring driver"
depends on MFD_SL28CPLD || COMPILE_TEST
help
If you say yes here you get support for the voltage and temperature
monitor of the sa67 board management controller.
This driver can also be built as a module. If so, the module
will be called sa67mcu-hwmon.
config SENSORS_SL28CPLD
tristate "Kontron sl28cpld hardware monitoring driver"
depends on MFD_SL28CPLD || COMPILE_TEST

View file

@ -199,7 +199,6 @@ obj-$(CONFIG_SENSORS_PT5161L) += pt5161l.o
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_SA67MCU) += sa67mcu-hwmon.o
obj-$(CONFIG_SENSORS_SBTSI) += sbtsi_temp.o
obj-$(CONFIG_SENSORS_SBRMI) += sbrmi.o
obj-$(CONFIG_SENSORS_SCH56XX_COMMON)+= sch56xx-common.o

View file

@ -37,7 +37,9 @@
#define AHT10_CMD_MEAS 0b10101100
#define AHT10_CMD_RST 0b10111010
#define DHT20_CMD_INIT 0x71
#define AHT20_CMD_INIT 0b10111110
#define DHT20_CMD_INIT 0b01110001
/*
* Flags in the answer byte/command
@ -341,7 +343,7 @@ static int aht10_probe(struct i2c_client *client)
data->meas_size = AHT20_MEAS_SIZE;
data->crc8 = true;
crc8_populate_msb(crc8_table, AHT20_CRC8_POLY);
data->init_cmd = AHT10_CMD_INIT;
data->init_cmd = AHT20_CMD_INIT;
break;
case dht20:
data->meas_size = AHT20_MEAS_SIZE;

View file

@ -3590,10 +3590,13 @@ static int it87_resume(struct device *dev)
{
struct platform_device *pdev = to_platform_device(dev);
struct it87_data *data = dev_get_drvdata(dev);
int err;
it87_resume_sio(pdev);
it87_lock(data);
err = it87_lock(data);
if (err)
return err;
it87_check_pwm(dev);
it87_check_limit_regs(data);

View file

@ -22,6 +22,7 @@
#include <linux/bitfield.h>
#include <linux/hwmon.h>
#include <linux/math64.h>
#include <linux/mfd/macsmc.h>
#include <linux/module.h>
#include <linux/of.h>
@ -130,7 +131,7 @@ static int macsmc_hwmon_read_ioft_scaled(struct apple_smc *smc, smc_key key,
if (ret < 0)
return ret;
*p = mult_frac(val, scale, 65536);
*p = mul_u64_u32_div(val, scale, 65536);
return 0;
}
@ -140,7 +141,7 @@ static int macsmc_hwmon_read_ioft_scaled(struct apple_smc *smc, smc_key key,
* them.
*/
static int macsmc_hwmon_read_f32_scaled(struct apple_smc *smc, smc_key key,
int *p, int scale)
long *p, int scale)
{
u32 fval;
u64 val;
@ -162,21 +163,21 @@ static int macsmc_hwmon_read_f32_scaled(struct apple_smc *smc, smc_key key,
val = 0;
else if (exp < 0)
val >>= -exp;
else if (exp != 0 && (val & ~((1UL << (64 - exp)) - 1))) /* overflow */
else if (exp != 0 && (val & ~((1ULL << (64 - exp)) - 1))) /* overflow */
val = U64_MAX;
else
val <<= exp;
if (fval & FLT_SIGN_MASK) {
if (val > (-(s64)INT_MIN))
*p = INT_MIN;
if (val > (u64)LONG_MAX + 1)
*p = LONG_MIN;
else
*p = -val;
*p = -(long)val;
} else {
if (val > INT_MAX)
*p = INT_MAX;
if (val > (u64)LONG_MAX)
*p = LONG_MAX;
else
*p = val;
*p = (long)val;
}
return 0;
@ -195,7 +196,7 @@ static int macsmc_hwmon_read_key(struct apple_smc *smc,
switch (sensor->info.type_code) {
/* 32-bit IEEE 754 float */
case __SMC_KEY('f', 'l', 't', ' '): {
u32 flt_ = 0;
long flt_ = 0;
ret = macsmc_hwmon_read_f32_scaled(smc, sensor->macsmc_key,
&flt_, scale);
@ -214,7 +215,10 @@ static int macsmc_hwmon_read_key(struct apple_smc *smc,
if (ret)
return ret;
*val = (long)ioft;
if (ioft > LONG_MAX)
*val = LONG_MAX;
else
*val = (long)ioft;
break;
}
default:
@ -224,29 +228,26 @@ static int macsmc_hwmon_read_key(struct apple_smc *smc,
return 0;
}
static int macsmc_hwmon_write_f32(struct apple_smc *smc, smc_key key, int value)
static int macsmc_hwmon_write_f32(struct apple_smc *smc, smc_key key, long value)
{
u64 val;
u32 fval = 0;
int exp = 0, neg;
int exp, neg;
neg = value < 0;
val = abs(value);
neg = val != value;
if (val) {
int msb = __fls(val) - exp;
exp = __fls(val);
if (msb > 23) {
val >>= msb - FLT_MANT_BIAS;
exp -= msb - FLT_MANT_BIAS;
} else if (msb < 23) {
val <<= FLT_MANT_BIAS - msb;
exp += msb;
}
if (exp > 23)
val >>= exp - 23;
else
val <<= 23 - exp;
fval = FIELD_PREP(FLT_SIGN_MASK, neg) |
FIELD_PREP(FLT_EXP_MASK, exp + FLT_EXP_BIAS) |
FIELD_PREP(FLT_MANT_MASK, val);
FIELD_PREP(FLT_MANT_MASK, val & FLT_MANT_MASK);
}
return apple_smc_write_u32(smc, key, fval);
@ -663,8 +664,8 @@ static int macsmc_hwmon_populate_sensors(struct macsmc_hwmon *hwmon,
if (!hwmon->volt.sensors)
return -ENOMEM;
for_each_child_of_node_with_prefix(hwmon_node, key_node, "volt-") {
sensor = &hwmon->temp.sensors[hwmon->temp.count];
for_each_child_of_node_with_prefix(hwmon_node, key_node, "voltage-") {
sensor = &hwmon->volt.sensors[hwmon->volt.count];
if (!macsmc_hwmon_create_sensor(hwmon->dev, hwmon->smc, key_node, sensor)) {
sensor->attrs = HWMON_I_INPUT;

View file

@ -607,7 +607,7 @@ static int max6639_init_client(struct i2c_client *client,
return err;
/* Fans PWM polarity high by default */
err = regmap_write(data->regmap, MAX6639_REG_FAN_CONFIG2a(i), 0x00);
err = regmap_write(data->regmap, MAX6639_REG_FAN_CONFIG2a(i), 0x02);
if (err)
return err;

View file

@ -79,7 +79,8 @@ static ssize_t q54sj108a2_debugfs_read(struct file *file, char __user *buf,
int idx = *idxp;
struct q54sj108a2_data *psu = to_psu(idxp, idx);
char data[I2C_SMBUS_BLOCK_MAX + 2] = { 0 };
char data_char[I2C_SMBUS_BLOCK_MAX + 2] = { 0 };
char data_char[I2C_SMBUS_BLOCK_MAX * 2 + 2] = { 0 };
char *out = data;
char *res;
switch (idx) {
@ -150,27 +151,27 @@ static ssize_t q54sj108a2_debugfs_read(struct file *file, char __user *buf,
if (rc < 0)
return rc;
res = bin2hex(data, data_char, 32);
rc = res - data;
res = bin2hex(data_char, data, rc);
rc = res - data_char;
out = data_char;
break;
case Q54SJ108A2_DEBUGFS_FLASH_KEY:
rc = i2c_smbus_read_block_data(psu->client, PMBUS_FLASH_KEY_WRITE, data);
if (rc < 0)
return rc;
res = bin2hex(data, data_char, 4);
rc = res - data;
res = bin2hex(data_char, data, rc);
rc = res - data_char;
out = data_char;
break;
default:
return -EINVAL;
}
data[rc] = '\n';
out[rc] = '\n';
rc += 2;
return simple_read_from_buffer(buf, count, ppos, data, rc);
return simple_read_from_buffer(buf, count, ppos, out, rc);
}
static ssize_t q54sj108a2_debugfs_write(struct file *file, const char __user *buf,

View file

@ -1,161 +0,0 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
* sl67mcu hardware monitoring driver
*
* Copyright 2025 Kontron Europe GmbH
*/
#include <linux/bitfield.h>
#include <linux/hwmon.h>
#include <linux/kernel.h>
#include <linux/mod_devicetable.h>
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/property.h>
#include <linux/regmap.h>
#define SA67MCU_VOLTAGE(n) (0x00 + ((n) * 2))
#define SA67MCU_TEMP(n) (0x04 + ((n) * 2))
struct sa67mcu_hwmon {
struct regmap *regmap;
u32 offset;
};
static int sa67mcu_hwmon_read(struct device *dev,
enum hwmon_sensor_types type, u32 attr,
int channel, long *input)
{
struct sa67mcu_hwmon *hwmon = dev_get_drvdata(dev);
unsigned int offset;
u8 reg[2];
int ret;
switch (type) {
case hwmon_in:
switch (attr) {
case hwmon_in_input:
offset = hwmon->offset + SA67MCU_VOLTAGE(channel);
break;
default:
return -EOPNOTSUPP;
}
break;
case hwmon_temp:
switch (attr) {
case hwmon_temp_input:
offset = hwmon->offset + SA67MCU_TEMP(channel);
break;
default:
return -EOPNOTSUPP;
}
break;
default:
return -EOPNOTSUPP;
}
/* Reading the low byte will capture the value */
ret = regmap_bulk_read(hwmon->regmap, offset, reg, ARRAY_SIZE(reg));
if (ret)
return ret;
*input = reg[1] << 8 | reg[0];
/* Temperatures are s16 and in 0.1degC steps. */
if (type == hwmon_temp)
*input = sign_extend32(*input, 15) * 100;
return 0;
}
static const struct hwmon_channel_info * const sa67mcu_hwmon_info[] = {
HWMON_CHANNEL_INFO(in,
HWMON_I_INPUT | HWMON_I_LABEL,
HWMON_I_INPUT | HWMON_I_LABEL),
HWMON_CHANNEL_INFO(temp, HWMON_T_INPUT),
NULL
};
static const char *const sa67mcu_hwmon_in_labels[] = {
"VDDIN",
"VDD_RTC",
};
static int sa67mcu_hwmon_read_string(struct device *dev,
enum hwmon_sensor_types type, u32 attr,
int channel, const char **str)
{
switch (type) {
case hwmon_in:
switch (attr) {
case hwmon_in_label:
*str = sa67mcu_hwmon_in_labels[channel];
return 0;
default:
return -EOPNOTSUPP;
}
default:
return -EOPNOTSUPP;
}
}
static const struct hwmon_ops sa67mcu_hwmon_ops = {
.visible = 0444,
.read = sa67mcu_hwmon_read,
.read_string = sa67mcu_hwmon_read_string,
};
static const struct hwmon_chip_info sa67mcu_hwmon_chip_info = {
.ops = &sa67mcu_hwmon_ops,
.info = sa67mcu_hwmon_info,
};
static int sa67mcu_hwmon_probe(struct platform_device *pdev)
{
struct sa67mcu_hwmon *hwmon;
struct device *hwmon_dev;
int ret;
if (!pdev->dev.parent)
return -ENODEV;
hwmon = devm_kzalloc(&pdev->dev, sizeof(*hwmon), GFP_KERNEL);
if (!hwmon)
return -ENOMEM;
hwmon->regmap = dev_get_regmap(pdev->dev.parent, NULL);
if (!hwmon->regmap)
return -ENODEV;
ret = device_property_read_u32(&pdev->dev, "reg", &hwmon->offset);
if (ret)
return -EINVAL;
hwmon_dev = devm_hwmon_device_register_with_info(&pdev->dev,
"sa67mcu_hwmon", hwmon,
&sa67mcu_hwmon_chip_info,
NULL);
if (IS_ERR(hwmon_dev))
dev_err(&pdev->dev, "failed to register as hwmon device");
return PTR_ERR_OR_ZERO(hwmon_dev);
}
static const struct of_device_id sa67mcu_hwmon_of_match[] = {
{ .compatible = "kontron,sa67mcu-hwmon", },
{}
};
MODULE_DEVICE_TABLE(of, sa67mcu_hwmon_of_match);
static struct platform_driver sa67mcu_hwmon_driver = {
.probe = sa67mcu_hwmon_probe,
.driver = {
.name = "sa67mcu-hwmon",
.of_match_table = sa67mcu_hwmon_of_match,
},
};
module_platform_driver(sa67mcu_hwmon_driver);
MODULE_DESCRIPTION("sa67mcu Hardware Monitoring Driver");
MODULE_AUTHOR("Michael Walle <mwalle@kernel.org>");
MODULE_LICENSE("GPL");