[PATCH 3/4] hwmon: (ina2xx) Track active alarm in ina2xx_data
From: Jared Kangas
Date: Wed Jul 29 2026 - 12:51:24 EST
INA2XX current limits are converted into shunt voltage limits internally
using the shunt resistor value. Once a current limit's corresponding
voltage limit is written to the hardware, shunt voltage and current
alarms are indistinguishable from each other.
To allow distinguishing current and shunt voltage alarms, track the
active alarm type in ina2xx_data. The new field is initialized based on
the MASK_ENABLE register's set function.
Signed-off-by: Jared Kangas <jkangas@xxxxxxxxxx>
---
drivers/hwmon/ina2xx.c | 44 ++++++++++++++++++++++++++++++++++++++++++--
1 file changed, 42 insertions(+), 2 deletions(-)
diff --git a/drivers/hwmon/ina2xx.c b/drivers/hwmon/ina2xx.c
index beb851d87f787..8ba0dce1f9e31 100644
--- a/drivers/hwmon/ina2xx.c
+++ b/drivers/hwmon/ina2xx.c
@@ -157,6 +157,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;
@@ -441,6 +442,35 @@ static u32 ina2xx_alert_type_to_mask(enum ina2xx_alert_type alert)
}
}
+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)
{
@@ -492,9 +522,13 @@ static int ina226_alert_limit_write(struct ina2xx_data *data, enum ina2xx_alert_
if (val) {
mask = ina2xx_alert_type_to_mask(alert);
- return regmap_update_bits(regmap, INA226_MASK_ENABLE,
- INA226_ALERT_CONFIG_MASK, mask);
+ ret = regmap_update_bits(regmap, INA226_MASK_ENABLE,
+ INA226_ALERT_CONFIG_MASK, mask);
+ if (ret < 0)
+ return ret;
}
+
+ data->active_alert = val ? alert : INA2XX_ALERT_NONE;
return 0;
}
@@ -960,6 +994,12 @@ 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;
+
+ 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,
--
2.55.0