summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Documentation/hwmon/gpd-fan.rst2
-rw-r--r--Documentation/hwmon/hwmon-kernel-api.rst15
-rw-r--r--drivers/hwmon/applesmc.c7
-rw-r--r--drivers/hwmon/aspeed-pwm-tacho.c4
-rw-r--r--drivers/hwmon/chipcap2.c9
-rw-r--r--drivers/hwmon/corsair-cpro.c24
-rw-r--r--drivers/hwmon/gpio-fan.c13
-rw-r--r--drivers/hwmon/hwmon.c31
-rw-r--r--drivers/hwmon/ina2xx.c163
-rw-r--r--drivers/hwmon/ltc4282.c2
-rw-r--r--drivers/hwmon/mcp9982.c2
-rw-r--r--drivers/hwmon/pmbus/pmbus_core.c4
-rw-r--r--drivers/hwmon/sht4x.c8
-rw-r--r--drivers/hwmon/yogafan.c2
14 files changed, 223 insertions, 63 deletions
diff --git a/Documentation/hwmon/gpd-fan.rst b/Documentation/hwmon/gpd-fan.rst
index 29527a77fe88..b27657d33056 100644
--- a/Documentation/hwmon/gpd-fan.rst
+++ b/Documentation/hwmon/gpd-fan.rst
@@ -67,7 +67,7 @@ pwm1_enable
at full speed. Write "1" to set to manual, write "2" to let the EC control
decide fan speed. Read this attribute to see current status.
- NB:In consideration of the safety of the device, when setting to manual mode,
+ NB: In consideration of the safety of the device, when setting to manual mode,
the pwm speed will be set to the maximum value (255) by default. You can set
a different value by writing pwm1 later.
diff --git a/Documentation/hwmon/hwmon-kernel-api.rst b/Documentation/hwmon/hwmon-kernel-api.rst
index 9fcde32a140d..c3eb433a78f6 100644
--- a/Documentation/hwmon/hwmon-kernel-api.rst
+++ b/Documentation/hwmon/hwmon-kernel-api.rst
@@ -42,6 +42,9 @@ register/unregister functions::
char *devm_hwmon_sanitize_name(struct device *dev, const char *name);
+ int hwmon_notify_event(struct device *dev, enum hwmon_sensor_types type,
+ u32 attr, int channel);
+
void hwmon_lock(struct device *dev);
void hwmon_unlock(struct device *dev);
@@ -90,6 +93,18 @@ implemented in the driver, or debugfs functions, hwmon_lock() and hwmon_unlock()
can be used to ensure that calls to those functions are serialized. Those
functions also support guard() and scoped_guard() variants.
+Drivers can call hwmon_notify_event() to notify userspace and the thermal
+subsystem when a hardware monitoring event (such as an alarm or a fault
+condition) occurs or clears. The parameters are the hwmon device, the sensor
+type, the attribute identifier associated with the event (such as
+hwmon_temp_max_alarm or hwmon_fan_fault), and the sensor channel number.
+hwmon_notify_event() generates a sysfs event (calling sysfs_notify()) and a
+udev event with the attribute name passed in the NAME environment property
+(e.g., "NAME=temp1_max_alarm"). If the event is for a temperature sensor and
+the sensor is attached to a thermal zone, it also notifies the thermal
+subsystem to update the thermal zone. hwmon_notify_event() returns 0 on
+success or a negative error code on failure.
+
Using devm_hwmon_device_register_with_info()
--------------------------------------------
diff --git a/drivers/hwmon/applesmc.c b/drivers/hwmon/applesmc.c
index 00e603b5e401..d0baa10502f7 100644
--- a/drivers/hwmon/applesmc.c
+++ b/drivers/hwmon/applesmc.c
@@ -1128,12 +1128,17 @@ static void applesmc_release_light_sensor(void)
static int applesmc_create_key_backlight(void)
{
+ int ret;
+
if (!smcreg.has_key_backlight)
return 0;
applesmc_led_wq = create_singlethread_workqueue("applesmc-led");
if (!applesmc_led_wq)
return -ENOMEM;
- return led_classdev_register(&pdev->dev, &applesmc_backlight);
+ ret = led_classdev_register(&pdev->dev, &applesmc_backlight);
+ if (ret)
+ destroy_workqueue(applesmc_led_wq);
+ return ret;
}
static void applesmc_release_key_backlight(void)
diff --git a/drivers/hwmon/aspeed-pwm-tacho.c b/drivers/hwmon/aspeed-pwm-tacho.c
index 1c5945d4ba37..bfce589c3fb1 100644
--- a/drivers/hwmon/aspeed-pwm-tacho.c
+++ b/drivers/hwmon/aspeed-pwm-tacho.c
@@ -934,7 +934,9 @@ static int aspeed_pwm_tacho_probe(struct platform_device *pdev)
"missing or invalid reset controller device tree entry");
return PTR_ERR(priv->rst);
}
- reset_control_deassert(priv->rst);
+ ret = reset_control_deassert(priv->rst);
+ if (ret)
+ return ret;
ret = devm_add_action_or_reset(dev, aspeed_pwm_tacho_remove, priv);
if (ret)
diff --git a/drivers/hwmon/chipcap2.c b/drivers/hwmon/chipcap2.c
index 086571d556b7..9bef767b589e 100644
--- a/drivers/hwmon/chipcap2.c
+++ b/drivers/hwmon/chipcap2.c
@@ -92,11 +92,6 @@ struct cc2_data {
bool process_irqs;
};
-enum cc2_chan_addr {
- CC2_CHAN_TEMP = 0,
- CC2_CHAN_HUMIDITY,
-};
-
/* %RH as a per cent mille from a register value */
static long cc2_rh_convert(u16 data)
{
@@ -499,7 +494,7 @@ static irqreturn_t cc2_low_interrupt(int irq, void *data)
if (cc2->process_irqs) {
hwmon_notify_event(cc2->hwmon, hwmon_humidity,
- hwmon_humidity_min_alarm, CC2_CHAN_HUMIDITY);
+ hwmon_humidity_min_alarm, 0);
cc2->rh_alarm.low_alarm = true;
}
@@ -512,7 +507,7 @@ static irqreturn_t cc2_high_interrupt(int irq, void *data)
if (cc2->process_irqs) {
hwmon_notify_event(cc2->hwmon, hwmon_humidity,
- hwmon_humidity_max_alarm, CC2_CHAN_HUMIDITY);
+ hwmon_humidity_max_alarm, 0);
cc2->rh_alarm.high_alarm = true;
}
diff --git a/drivers/hwmon/corsair-cpro.c b/drivers/hwmon/corsair-cpro.c
index 8354a002f4c5..c09645152613 100644
--- a/drivers/hwmon/corsair-cpro.c
+++ b/drivers/hwmon/corsair-cpro.c
@@ -566,21 +566,18 @@ static int bootloader_show(struct seq_file *seqf, void *unused)
}
DEFINE_SHOW_ATTRIBUTE(bootloader);
-static void ccp_debugfs_init(struct ccp_device *ccp)
+static void ccp_debugfs_init(struct ccp_device *ccp, bool fw_valid, bool bl_valid)
{
char name[32];
- int ret;
scnprintf(name, sizeof(name), "corsaircpro-%s", dev_name(&ccp->hdev->dev));
ccp->debugfs = debugfs_create_dir(name, NULL);
- ret = get_fw_version(ccp);
- if (!ret)
+ if (fw_valid)
debugfs_create_file("firmware_version", 0444,
ccp->debugfs, ccp, &firmware_fops);
- ret = get_bl_version(ccp);
- if (!ret)
+ if (bl_valid)
debugfs_create_file("bootloader_version", 0444,
ccp->debugfs, ccp, &bootloader_fops);
}
@@ -588,6 +585,7 @@ static void ccp_debugfs_init(struct ccp_device *ccp)
static int ccp_probe(struct hid_device *hdev, const struct hid_device_id *id)
{
struct ccp_device *ccp;
+ bool fw_valid, bl_valid;
int ret;
ccp = devm_kzalloc(&hdev->dev, sizeof(*ccp), GFP_KERNEL);
@@ -632,17 +630,27 @@ static int ccp_probe(struct hid_device *hdev, const struct hid_device_id *id)
if (ret)
goto out_hw_close;
- ccp_debugfs_init(ccp);
+ /*
+ * Query the versions before registering the hwmon device: they send
+ * USB commands without holding ccp->mutex, which is only safe while
+ * nothing else can call send_usb_cmd().
+ */
+ fw_valid = !get_fw_version(ccp);
+ bl_valid = !get_bl_version(ccp);
ccp->hwmon_dev = hwmon_device_register_with_info(&hdev->dev, "corsaircpro",
ccp, &ccp_chip_info, NULL);
if (IS_ERR(ccp->hwmon_dev)) {
ret = PTR_ERR(ccp->hwmon_dev);
- goto out_hw_close;
+ goto out_debugfs_remove;
}
+ ccp_debugfs_init(ccp, fw_valid, bl_valid);
+
return 0;
+out_debugfs_remove:
+ debugfs_remove_recursive(ccp->debugfs);
out_hw_close:
hid_hw_close(hdev);
hid_device_io_stop(hdev);
diff --git a/drivers/hwmon/gpio-fan.c b/drivers/hwmon/gpio-fan.c
index 084828e1e281..df8bd9707605 100644
--- a/drivers/hwmon/gpio-fan.c
+++ b/drivers/hwmon/gpio-fan.c
@@ -12,6 +12,7 @@
#include <linux/slab.h>
#include <linux/interrupt.h>
#include <linux/irq.h>
+#include <linux/devm-helpers.h>
#include <linux/platform_device.h>
#include <linux/err.h>
#include <linux/kstrtox.h>
@@ -84,6 +85,7 @@ static DEVICE_ATTR_RO(fan1_alarm);
static int fan_alarm_init(struct gpio_fan_data *fan_data)
{
int alarm_irq;
+ int err;
struct device *dev = fan_data->dev;
/*
@@ -94,7 +96,11 @@ static int fan_alarm_init(struct gpio_fan_data *fan_data)
if (alarm_irq <= 0)
return 0;
- INIT_WORK(&fan_data->alarm_work, fan_alarm_notify);
+ err = devm_work_autocancel(dev, &fan_data->alarm_work,
+ fan_alarm_notify);
+ if (err)
+ return err;
+
irq_set_irq_type(alarm_irq, IRQ_TYPE_EDGE_BOTH);
return devm_request_irq(dev, alarm_irq, fan_alarm_irq_handler,
IRQF_SHARED, "GPIO fan alarm", fan_data);
@@ -606,8 +612,11 @@ static void gpio_fan_shutdown(struct platform_device *pdev)
{
struct gpio_fan_data *fan_data = platform_get_drvdata(pdev);
- if (fan_data->gpios)
+ if (fan_data->gpios) {
+ mutex_lock(&fan_data->lock);
set_fan_speed(fan_data, 0);
+ mutex_unlock(&fan_data->lock);
+ }
}
static int gpio_fan_runtime_suspend(struct device *dev)
diff --git a/drivers/hwmon/hwmon.c b/drivers/hwmon/hwmon.c
index 41755910a25a..10d2df3efdfa 100644
--- a/drivers/hwmon/hwmon.c
+++ b/drivers/hwmon/hwmon.c
@@ -318,6 +318,11 @@ static int hwmon_attr_base(enum hwmon_sensor_types type)
return 1;
}
+static bool is_hwmon_device(struct device *dev)
+{
+ return dev->class == &hwmon_class;
+}
+
#if IS_REACHABLE(CONFIG_I2C)
/*
@@ -338,7 +343,7 @@ static int hwmon_attr_base(enum hwmon_sensor_types type)
static int hwmon_match_device(struct device *dev, const void *data)
{
- return dev->class == &hwmon_class;
+ return is_hwmon_device(dev);
}
static ssize_t pec_show(struct device *dev, const struct device_attribute *dummy,
@@ -371,18 +376,17 @@ static ssize_t pec_store(struct device *dev, const struct device_attribute *deva
* handling is not required.
*/
hwdev = to_hwmon_device(hdev);
- guard(mutex)(&hwdev->lock);
- if (hwdev->chip->ops->write) {
- err = hwdev->chip->ops->write(hdev, hwmon_chip, hwmon_chip_pec, 0, val);
- if (err && err != -EOPNOTSUPP)
- goto put;
+ scoped_guard(mutex, &hwdev->lock) {
+ if (hwdev->chip->ops->write) {
+ err = hwdev->chip->ops->write(hdev, hwmon_chip, hwmon_chip_pec, 0, val);
+ if (err && err != -EOPNOTSUPP)
+ goto put;
+ }
+ if (!val)
+ client->flags &= ~I2C_CLIENT_PEC;
+ else
+ client->flags |= I2C_CLIENT_PEC;
}
-
- if (!val)
- client->flags &= ~I2C_CLIENT_PEC;
- else
- client->flags |= I2C_CLIENT_PEC;
-
err = count;
put:
put_device(hdev);
@@ -782,6 +786,9 @@ int hwmon_notify_event(struct device *dev, enum hwmon_sensor_types type,
const char *template;
int base;
+ if (WARN(!is_hwmon_device(dev), "%s is not a hardware monitoring device\n",
+ dev_name(dev)))
+ return -EINVAL;
if (type >= ARRAY_SIZE(__templates))
return -EINVAL;
if (attr >= __templates_size[type])
diff --git a/drivers/hwmon/ina2xx.c b/drivers/hwmon/ina2xx.c
index 5c6dc2c370d8..19b35f3bf3a3 100644
--- a/drivers/hwmon/ina2xx.c
+++ b/drivers/hwmon/ina2xx.c
@@ -8,6 +8,7 @@
*/
#include <linux/bitfield.h>
+#include <linux/bitops.h>
#include <linux/bits.h>
#include <linux/delay.h>
#include <linux/device.h>
@@ -129,6 +130,17 @@ enum ina2xx_ids {
sy24655
};
+enum ina2xx_alert_type {
+ INA2XX_ALERT_NONE,
+ INA2XX_ALERT_CURRENT_LOW,
+ INA2XX_ALERT_CURRENT_HIGH,
+ INA2XX_ALERT_POWER_HIGH,
+ INA2XX_ALERT_BUS_VOLTAGE_LOW,
+ INA2XX_ALERT_BUS_VOLTAGE_HIGH,
+ INA2XX_ALERT_SHUNT_VOLTAGE_LOW,
+ INA2XX_ALERT_SHUNT_VOLTAGE_HIGH,
+};
+
struct ina2xx_config {
u16 config_default;
bool has_alerts; /* chip supports alerts and limits */
@@ -148,6 +160,7 @@ struct ina2xx_data {
const struct ina2xx_config *config;
enum ina2xx_ids chip;
+ enum ina2xx_alert_type active_alert;
long rshunt;
long current_lsb_uA;
long power_lsb_uW;
@@ -428,16 +441,78 @@ static u16 ina226_alert_to_reg(struct ina2xx_data *data, int reg, long val)
}
}
-static int ina226_alert_limit_read(struct ina2xx_data *data, u32 mask, int reg, long *val)
+static u32 ina2xx_alert_type_to_mask(enum ina2xx_alert_type alert)
+{
+ switch (alert) {
+ case INA2XX_ALERT_CURRENT_LOW:
+ case INA2XX_ALERT_SHUNT_VOLTAGE_LOW:
+ return INA226_SHUNT_UNDER_VOLTAGE_MASK;
+ case INA2XX_ALERT_CURRENT_HIGH:
+ case INA2XX_ALERT_SHUNT_VOLTAGE_HIGH:
+ return INA226_SHUNT_OVER_VOLTAGE_MASK;
+ case INA2XX_ALERT_BUS_VOLTAGE_LOW:
+ return INA226_BUS_UNDER_VOLTAGE_MASK;
+ case INA2XX_ALERT_BUS_VOLTAGE_HIGH:
+ return INA226_BUS_OVER_VOLTAGE_MASK;
+ case INA2XX_ALERT_POWER_HIGH:
+ return INA226_POWER_OVER_LIMIT_MASK;
+ case INA2XX_ALERT_NONE:
+ return 0;
+ default:
+ /* programmer error */
+ WARN_ON_ONCE(1);
+ return 0;
+ }
+}
+
+static enum ina2xx_alert_type ina2xx_mask_to_alert_type(u32 mask)
+{
+ int top_bit = fls(mask & INA226_ALERT_CONFIG_MASK);
+
+ if (!top_bit)
+ return INA2XX_ALERT_NONE;
+
+ /*
+ * Multiple bits may be set, with the highest-set function taking
+ * precedence according to the datasheet. Shunt voltage masks are
+ * assumed to map to voltage monitoring rather than current monitoring,
+ * since the latter isn't directly implemented in the hardware.
+ */
+ switch (BIT(top_bit - 1)) {
+ case INA226_SHUNT_OVER_VOLTAGE_MASK:
+ return INA2XX_ALERT_SHUNT_VOLTAGE_HIGH;
+ case INA226_SHUNT_UNDER_VOLTAGE_MASK:
+ return INA2XX_ALERT_SHUNT_VOLTAGE_LOW;
+ case INA226_BUS_OVER_VOLTAGE_MASK:
+ return INA2XX_ALERT_BUS_VOLTAGE_HIGH;
+ case INA226_BUS_UNDER_VOLTAGE_MASK:
+ return INA2XX_ALERT_BUS_VOLTAGE_LOW;
+ case INA226_POWER_OVER_LIMIT_MASK:
+ return INA2XX_ALERT_POWER_HIGH;
+ default:
+ return INA2XX_ALERT_NONE;
+ }
+}
+
+static int ina226_alert_limit_read(struct ina2xx_data *data, enum ina2xx_alert_type alert,
+ int reg, long *val)
{
struct regmap *regmap = data->regmap;
int regval;
+ u32 mask;
int ret;
+ /* Avoid nonzero reads from inactive alerts caused by shared limit register */
+ if (data->active_alert != alert) {
+ *val = 0;
+ return 0;
+ }
+
ret = regmap_read(regmap, INA226_MASK_ENABLE, &regval);
if (ret)
return ret;
+ mask = ina2xx_alert_type_to_mask(alert);
if (regval & mask) {
ret = regmap_read(regmap, INA226_ALERT_LIMIT, &regval);
if (ret)
@@ -449,9 +524,11 @@ static int ina226_alert_limit_read(struct ina2xx_data *data, u32 mask, int reg,
return 0;
}
-static int ina226_alert_limit_write(struct ina2xx_data *data, u32 mask, int reg, long val)
+static int ina226_alert_limit_write(struct ina2xx_data *data, enum ina2xx_alert_type alert,
+ int reg, long val)
{
struct regmap *regmap = data->regmap;
+ u32 mask;
int ret;
if (val < 0)
@@ -466,15 +543,22 @@ static int ina226_alert_limit_write(struct ina2xx_data *data, u32 mask, int reg,
INA226_ALERT_CONFIG_MASK, 0);
if (ret < 0)
return ret;
+ data->active_alert = INA2XX_ALERT_NONE;
ret = regmap_write(regmap, INA226_ALERT_LIMIT,
ina226_alert_to_reg(data, reg, val));
if (ret < 0)
return ret;
- if (val)
- return regmap_update_bits(regmap, INA226_MASK_ENABLE,
- INA226_ALERT_CONFIG_MASK, mask);
+ if (val) {
+ mask = ina2xx_alert_type_to_mask(alert);
+ ret = regmap_update_bits(regmap, INA226_MASK_ENABLE,
+ INA226_ALERT_CONFIG_MASK, mask);
+ if (ret < 0)
+ return ret;
+ data->active_alert = alert;
+ }
+
return 0;
}
@@ -498,15 +582,26 @@ static int ina2xx_chip_read(struct device *dev, u32 attr, long *val)
return 0;
}
-static int ina226_alert_read(struct regmap *regmap, u32 mask, long *val)
+static int ina226_alert_read(struct ina2xx_data *data, enum ina2xx_alert_type alert, long *val)
{
unsigned int regval;
+ u32 mask;
int ret;
- ret = regmap_read_bypassed(regmap, INA226_MASK_ENABLE, &regval);
+ /*
+ * With alert latching, reading alerts from hardware also clears the
+ * alert, so return early if the alert is inactive.
+ */
+ if (data->active_alert != alert) {
+ *val = 0;
+ return 0;
+ }
+
+ ret = regmap_read_bypassed(data->regmap, INA226_MASK_ENABLE, &regval);
if (ret)
return ret;
+ mask = ina2xx_alert_type_to_mask(alert);
*val = (regval & mask) && (regval & INA226_ALERT_FUNCTION_FLAG);
return 0;
@@ -515,10 +610,10 @@ static int ina226_alert_read(struct regmap *regmap, u32 mask, long *val)
static int ina2xx_in_read(struct device *dev, u32 attr, int channel, long *val)
{
int voltage_reg = channel ? INA2XX_BUS_VOLTAGE : INA2XX_SHUNT_VOLTAGE;
- u32 under_voltage_mask = channel ? INA226_BUS_UNDER_VOLTAGE_MASK
- : INA226_SHUNT_UNDER_VOLTAGE_MASK;
- u32 over_voltage_mask = channel ? INA226_BUS_OVER_VOLTAGE_MASK
- : INA226_SHUNT_OVER_VOLTAGE_MASK;
+ enum ina2xx_alert_type under_voltage_alert = channel ? INA2XX_ALERT_BUS_VOLTAGE_LOW
+ : INA2XX_ALERT_SHUNT_VOLTAGE_LOW;
+ enum ina2xx_alert_type over_voltage_alert = channel ? INA2XX_ALERT_BUS_VOLTAGE_HIGH
+ : INA2XX_ALERT_SHUNT_VOLTAGE_HIGH;
struct ina2xx_data *data = dev_get_drvdata(dev);
struct regmap *regmap = data->regmap;
unsigned int regval;
@@ -532,15 +627,15 @@ static int ina2xx_in_read(struct device *dev, u32 attr, int channel, long *val)
*val = ina2xx_get_value(data, voltage_reg, regval);
break;
case hwmon_in_lcrit:
- return ina226_alert_limit_read(data, under_voltage_mask,
+ return ina226_alert_limit_read(data, under_voltage_alert,
voltage_reg, val);
case hwmon_in_crit:
- return ina226_alert_limit_read(data, over_voltage_mask,
+ return ina226_alert_limit_read(data, over_voltage_alert,
voltage_reg, val);
case hwmon_in_lcrit_alarm:
- return ina226_alert_read(regmap, under_voltage_mask, val);
+ return ina226_alert_read(data, under_voltage_alert, val);
case hwmon_in_crit_alarm:
- return ina226_alert_read(regmap, over_voltage_mask, val);
+ return ina226_alert_read(data, over_voltage_alert, val);
default:
return -EOPNOTSUPP;
}
@@ -594,10 +689,10 @@ static int ina2xx_power_read(struct device *dev, u32 attr, long *val)
case hwmon_power_average:
return sy24655_average_power_read(data, SY24655_EIN, val);
case hwmon_power_crit:
- return ina226_alert_limit_read(data, INA226_POWER_OVER_LIMIT_MASK,
+ return ina226_alert_limit_read(data, INA2XX_ALERT_POWER_HIGH,
INA2XX_POWER, val);
case hwmon_power_crit_alarm:
- return ina226_alert_read(data->regmap, INA226_POWER_OVER_LIMIT_MASK, val);
+ return ina226_alert_read(data, INA2XX_ALERT_POWER_HIGH, val);
default:
return -EOPNOTSUPP;
}
@@ -633,15 +728,15 @@ static int ina2xx_curr_read(struct device *dev, u32 attr, long *val)
*val = ina2xx_get_value(data, INA2XX_CURRENT, regval);
return 0;
case hwmon_curr_lcrit:
- return ina226_alert_limit_read(data, INA226_SHUNT_UNDER_VOLTAGE_MASK,
+ return ina226_alert_limit_read(data, INA2XX_ALERT_CURRENT_LOW,
INA2XX_CURRENT, val);
case hwmon_curr_crit:
- return ina226_alert_limit_read(data, INA226_SHUNT_OVER_VOLTAGE_MASK,
+ return ina226_alert_limit_read(data, INA2XX_ALERT_CURRENT_HIGH,
INA2XX_CURRENT, val);
case hwmon_curr_lcrit_alarm:
- return ina226_alert_read(regmap, INA226_SHUNT_UNDER_VOLTAGE_MASK, val);
+ return ina226_alert_read(data, INA2XX_ALERT_CURRENT_LOW, val);
case hwmon_curr_crit_alarm:
- return ina226_alert_read(regmap, INA226_SHUNT_OVER_VOLTAGE_MASK, val);
+ return ina226_alert_read(data, INA2XX_ALERT_CURRENT_HIGH, val);
default:
return -EOPNOTSUPP;
}
@@ -685,12 +780,12 @@ static int ina2xx_in_write(struct device *dev, u32 attr, int channel, long val)
switch (attr) {
case hwmon_in_lcrit:
return ina226_alert_limit_write(data,
- channel ? INA226_BUS_UNDER_VOLTAGE_MASK : INA226_SHUNT_UNDER_VOLTAGE_MASK,
+ channel ? INA2XX_ALERT_BUS_VOLTAGE_LOW : INA2XX_ALERT_SHUNT_VOLTAGE_LOW,
channel ? INA2XX_BUS_VOLTAGE : INA2XX_SHUNT_VOLTAGE,
val);
case hwmon_in_crit:
return ina226_alert_limit_write(data,
- channel ? INA226_BUS_OVER_VOLTAGE_MASK : INA226_SHUNT_OVER_VOLTAGE_MASK,
+ channel ? INA2XX_ALERT_BUS_VOLTAGE_HIGH : INA2XX_ALERT_SHUNT_VOLTAGE_HIGH,
channel ? INA2XX_BUS_VOLTAGE : INA2XX_SHUNT_VOLTAGE,
val);
default:
@@ -705,7 +800,7 @@ static int ina2xx_power_write(struct device *dev, u32 attr, long val)
switch (attr) {
case hwmon_power_crit:
- return ina226_alert_limit_write(data, INA226_POWER_OVER_LIMIT_MASK,
+ return ina226_alert_limit_write(data, INA2XX_ALERT_POWER_HIGH,
INA2XX_POWER, val);
default:
return -EOPNOTSUPP;
@@ -719,10 +814,10 @@ static int ina2xx_curr_write(struct device *dev, u32 attr, long val)
switch (attr) {
case hwmon_curr_lcrit:
- return ina226_alert_limit_write(data, INA226_SHUNT_UNDER_VOLTAGE_MASK,
+ return ina226_alert_limit_write(data, INA2XX_ALERT_CURRENT_LOW,
INA2XX_CURRENT, val);
case hwmon_curr_crit:
- return ina226_alert_limit_write(data, INA226_SHUNT_OVER_VOLTAGE_MASK,
+ return ina226_alert_limit_write(data, INA2XX_ALERT_CURRENT_HIGH,
INA2XX_CURRENT, val);
default:
return -EOPNOTSUPP;
@@ -883,8 +978,12 @@ static ssize_t shunt_resistor_show(struct device *dev,
struct device_attribute *da, char *buf)
{
struct ina2xx_data *data = dev_get_drvdata(dev);
+ long rshunt;
- return sysfs_emit(buf, "%li\n", data->rshunt);
+ scoped_guard(hwmon_lock, dev) {
+ rshunt = data->rshunt;
+ }
+ return sysfs_emit(buf, "%li\n", rshunt);
}
static ssize_t shunt_resistor_store(struct device *dev,
@@ -940,6 +1039,16 @@ static int ina2xx_init(struct device *dev, struct ina2xx_data *data)
if (data->config->has_alerts) {
bool active_high = device_property_read_bool(dev, "ti,alert-polarity-active-high");
+ unsigned int mask_enable;
+
+ /*
+ * Infer active alert from MASK_ENABLE in case it's already
+ * configured (e.g., by a past probe or firmware)
+ */
+ ret = regmap_read(regmap, INA226_MASK_ENABLE, &mask_enable);
+ if (ret < 0)
+ return ret;
+ data->active_alert = ina2xx_mask_to_alert_type(mask_enable);
regmap_update_bits(regmap, INA226_MASK_ENABLE,
INA226_ALERT_LATCH_ENABLE | INA226_ALERT_POLARITY,
diff --git a/drivers/hwmon/ltc4282.c b/drivers/hwmon/ltc4282.c
index b1675dc5b3c7..54ba4b8542e9 100644
--- a/drivers/hwmon/ltc4282.c
+++ b/drivers/hwmon/ltc4282.c
@@ -1106,7 +1106,7 @@ static const struct clk_ops ltc4282_ops = {
static int ltc428_clk_provider_setup(struct ltc4282_state *st,
struct device *dev)
{
- struct clk_init_data init;
+ struct clk_init_data init = {};
int ret;
if (!IS_ENABLED(CONFIG_COMMON_CLK))
diff --git a/drivers/hwmon/mcp9982.c b/drivers/hwmon/mcp9982.c
index 9e19e2697e25..3918dc36c946 100644
--- a/drivers/hwmon/mcp9982.c
+++ b/drivers/hwmon/mcp9982.c
@@ -395,6 +395,8 @@ static int mcp9982_read(struct device *dev, enum hwmon_sensor_types type, u32 at
reg_status, !(reg_status & MCP9982_STATUS_BUSY),
MCP9982_WAKE_UP_TIME_US,
MCP9982_WAKE_UP_TIME_US * 10);
+ if (ret)
+ return ret;
break;
}
break;
diff --git a/drivers/hwmon/pmbus/pmbus_core.c b/drivers/hwmon/pmbus/pmbus_core.c
index 806c9a4913bb..5f69c1420b4e 100644
--- a/drivers/hwmon/pmbus/pmbus_core.c
+++ b/drivers/hwmon/pmbus/pmbus_core.c
@@ -1275,7 +1275,9 @@ static int pmbus_get_boolean(struct i2c_client *client, struct pmbus_boolean *b,
regval = status & mask;
if (regval) {
- if (data->revision >= PMBUS_REV_12) {
+ /* Generic STATUS_WORD alarms are not individually clearable. */
+ if (data->revision >= PMBUS_REV_12 &&
+ reg != PMBUS_STATUS_WORD) {
ret = _pmbus_write_byte_data(client, page, reg, regval);
if (ret)
return ret;
diff --git a/drivers/hwmon/sht4x.c b/drivers/hwmon/sht4x.c
index 9cace0e8acda..a97dda9e92dc 100644
--- a/drivers/hwmon/sht4x.c
+++ b/drivers/hwmon/sht4x.c
@@ -277,6 +277,8 @@ static ssize_t heater_enable_store(struct device *dev,
heating_time_bound = 1100;
}
+ guard(hwmon_lock)(dev);
+
if (time_before(jiffies, data->heating_complete))
return -EBUSY;
@@ -286,7 +288,7 @@ static ssize_t heater_enable_store(struct device *dev,
data->heating_complete = jiffies + msecs_to_jiffies(heating_time_bound);
data->data_pending = true;
- return 0;
+ return count;
}
static ssize_t heater_power_show(struct device *dev,
@@ -314,6 +316,8 @@ static ssize_t heater_power_store(struct device *dev,
if (power != 20 && power != 110 && power != 200)
return -EINVAL;
+ guard(hwmon_lock)(dev);
+
data->heater_power = power;
return count;
@@ -344,6 +348,8 @@ static ssize_t heater_time_store(struct device *dev,
if (time != 100 && time != 1000)
return -EINVAL;
+ guard(hwmon_lock)(dev);
+
data->heater_time = time;
return count;
diff --git a/drivers/hwmon/yogafan.c b/drivers/hwmon/yogafan.c
index 48fa5148d9e2..278cb089b0fd 100644
--- a/drivers/hwmon/yogafan.c
+++ b/drivers/hwmon/yogafan.c
@@ -1,5 +1,5 @@
// SPDX-License-Identifier: GPL-2.0-only
-/**
+/*
* yoga_fan.c - Lenovo Yoga/Legion Fan Hardware Monitoring Driver
*
* Provides fan speed monitoring for Lenovo Yoga, Legion, and IdeaPad