[PATCH 4/4] hwmon: (ina2xx) Return 0 on inactive alarm/limit reads

From: Jared Kangas

Date: Wed Jul 29 2026 - 11:46:07 EST


Guard alarm/limit reads with a check that returns zero if the active
alarm is for a different type. This addresses two issues:

1. in0/curr1 alarms may be unintentionally cleared by reading from the
opposite input's alarm.

2. When a limit for either in0 (shunt voltage) or curr1 (current) is
set, both of their alarms are triggered, and both of their limits
read nonzero.

An example of this behavior on an INA231:

# cd /sys/class/hwmon/hwmon0
# head {curr1,in0}_input
==> curr1_input <==
1713

==> in0_input <==
2
# echo 1800 >curr1_lcrit
# head {curr1,in0}_lcrit_alarm
==> curr1_lcrit_alarm <==
1

==> in0_lcrit_alarm <==
0
# head {in0,curr1}_lcrit_alarm
==> in0_lcrit_alarm <==
1

==> curr1_lcrit_alarm <==
0
# head {in0,curr1}_lcrit_alarm
==> in0_lcrit_alarm <==
1

==> curr1_lcrit_alarm <==
1

This is because curr1 uses the same underlying masks
(INA226_SHUNT_*_VOLTAGE_MASK) as in0 on the hardware. As a result,
ina2xx_{curr,in}_read() both read the shunt voltage alarms/limits
without considering whether the voltage or current is currently set.

After this fix, the alarms only read back 1 if their corresponding limit
is set:

# echo 0 >curr1_lcrit
# head {curr1,in0}_lcrit_alarm
==> curr1_lcrit_alarm <==
0

==> in0_lcrit_alarm <==
0
# echo 9999 >curr1_lcrit
# head {curr1,in0}_lcrit_alarm
==> curr1_lcrit_alarm <==
1

==> in0_lcrit_alarm <==
0
# echo 9999 >in0_lcrit
# head {curr1,in0}_lcrit_alarm
==> curr1_lcrit_alarm <==
0

==> in0_lcrit_alarm <==
1

Fixes: 4d5c2d986757 ("hwmon: (ina2xx) Add support for current limits")
Signed-off-by: Jared Kangas <jkangas@xxxxxxxxxx>
---
drivers/hwmon/ina2xx.c | 12 ++++++++++++
1 file changed, 12 insertions(+)

diff --git a/drivers/hwmon/ina2xx.c b/drivers/hwmon/ina2xx.c
index 8ba0dce1f9e31..5521490deba98 100644
--- a/drivers/hwmon/ina2xx.c
+++ b/drivers/hwmon/ina2xx.c
@@ -479,6 +479,12 @@ static int ina226_alert_limit_read(struct ina2xx_data *data, enum ina2xx_alert_t
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;
@@ -558,6 +564,12 @@ static int ina226_alert_read(struct ina2xx_data *data, enum ina2xx_alert_type al
u32 mask;
int ret;

+ /* Avoid reading inactive alerts, which may clear the active alert */
+ if (data->active_alert != alert) {
+ *val = 0;
+ return 0;
+ }
+
ret = regmap_read_bypassed(data->regmap, INA226_MASK_ENABLE, &regval);
if (ret)
return ret;

--
2.55.0