SQ52210 adds power attribute to report power data, and implements
read/write functions for this purpose.
Signed-off-by: Wenliang Yan <wenliang202407@163.com>
---
drivers/hwmon/ina3221.c | 79 ++++++++++++++++++++++++++++++++++++++---
1 file changed, 75 insertions(+), 4 deletions(-)
diff --git a/drivers/hwmon/ina3221.c b/drivers/hwmon/ina3221.c
index abb6049c8eab..ea01687ad1fa 100644
--- a/drivers/hwmon/ina3221.c
+++ b/drivers/hwmon/ina3221.c
@@ -348,19 +348,16 @@ static const u8 ina3221_in_reg[] = {
INA3221_SHUNT3,
INA3221_SHUNT_SUM,
};
-
static const u8 alert_limit_reg[] = {
SQ52210_ALERT_LIMIT1,
SQ52210_ALERT_LIMIT2,
SQ52210_ALERT_LIMIT3,
};
-
static const u8 alert_flag[] = {
F_AFF1,
F_AFF2,
F_AFF3,
};
-
/*
* Turns alert limit values into register values.
* Opposite of the formula in ina3221_read_value().
@@ -557,6 +554,61 @@ static int ina3221_read_curr(struct device *dev, u32 attr,
}
}
+static const u8 ina3221_power_reg[][INA3221_NUM_CHANNELS] = {
+ [hwmon_power_input] = { SQ52210_POWER1, SQ52210_POWER2, SQ52210_POWER3 },
+ [hwmon_power_crit] = { SQ52210_ALERT_LIMIT1, SQ52210_ALERT_LIMIT2,
+ SQ52210_ALERT_LIMIT3 },
+ [hwmon_power_crit_alarm] = { F_AFF1, F_AFF2, F_AFF3 },
+};
+
+static int ina3221_read_power(struct device *dev, u32 attr, int channel, long *val)
+{
+ struct ina3221_data *ina = dev_get_drvdata(dev);
+ u8 reg = ina3221_power_reg[attr][channel];
+ int regval, ret;
+
+ switch (attr) {
+ case hwmon_power_input:
+ if (!ina3221_is_enabled(ina, channel))
+ return -ENODATA;
+
+ /* Write CONFIG register to trigger a single-shot measurement */
+ if (ina->single_shot) {
+ regmap_write(ina->regmap, INA3221_CONFIG,
+ ina->reg_config);
+
+ ret = ina3221_wait_for_data(ina);
+ if (ret)
+ return ret;
+ }
+
+ ret = ina3221_read_value(ina, reg, ®val);
+ if (ret)
+ return ret;
+ /* Return power in mW */
+ *val = DIV_ROUND_CLOSEST(regval * ina->power_lsb_uW, 1000);
+ return 0;
+ case hwmon_power_crit:
+ reg = ina3221_power_reg[attr][channel];
+ ret = ina3221_read_value(ina, reg, ®val);
+ if (ret)
+ return ret;
+ /* Return power in mW */
+ *val = DIV_ROUND_CLOSEST(regval * ina->power_lsb_uW, 1000);
+ return 0;
+ case hwmon_power_crit_alarm:
+ reg = ina3221_power_reg[attr][channel];
+ ret = regmap_field_read(ina->fields[reg], ®val);
+ if (ret)
+ return ret;
+ *val = regval;
+ return 0;
+
+ default:
+ return -EOPNOTSUPP;
+ }
+}
+
static const u32 sq52210_alert_mask[][INA3221_NUM_CHANNELS] = {
[hwmon_curr_lcrit] = { BIT(15), BIT(14), BIT(13) },
[hwmon_in_crit] = { BIT(12), BIT(11), BIT(10) },
@@ -760,6 +812,19 @@ static int ina3221_write_in(struct device *dev, u32 attr, int channel, long val)
return 0;
}
}
+
+static int ina3221_write_power(struct device *dev, u32 attr, int channel, long val)
+{
+ struct ina3221_data *ina = dev_get_drvdata(dev);
+
+ switch (attr) {
+ case hwmon_power_crit:
+ return sq52210_alert_limit_write(ina, attr, channel, val);
+ default:
+ return 0;
+ }
+}
+
static int ina3221_read(struct device *dev, enum hwmon_sensor_types type,
u32 attr, int channel, long *val)
{
@@ -776,6 +841,9 @@ static int ina3221_read(struct device *dev, enum hwmon_sensor_types type,
case hwmon_curr:
ret = ina3221_read_curr(dev, attr, channel, val);
break;
+ case hwmon_power:
+ ret = ina3221_read_power(dev, attr, channel, val);
+ break;
default:
ret = -EOPNOTSUPP;
break;
@@ -799,6 +867,9 @@ static int ina3221_write(struct device *dev, enum hwmon_sensor_types type,
case hwmon_curr:
ret = ina3221_write_curr(dev, attr, channel, val);
break;
+ case hwmon_power:
+ ret = ina3221_write_power(dev, attr, channel, val);
+ break;
default:
ret = -EOPNOTSUPP;
break;
@@ -977,7 +1048,7 @@ static int ina3221_set_shunt(struct ina3221_data *ina, unsigned long val)
ina->current_lsb_uA = DIV_ROUND_CLOSEST(SQ52210_SHUNT_LSB, val);
ina->power_lsb_uW = ina->config->power_lsb_factor *
- ina->current_lsb_uA;
+ ina->current_lsb_uA;
return 0;
}
--
2.17.1