Skip to content

Commit 4d5c2d9

Browse files
committed
hwmon: (ina2xx) Add support for current limits
While the chips supported by this driver do not directly support current limits, they do support setting shunt voltage limits. The shunt voltage divided by the shunt resistor value is the current. On top of that, calibration values are set such that in the shunt voltage register and the current register report the same values. That means we can report and configure current limits based on shunt voltage limits, and we can do so with much better accuracy than by setting shunt voltage limits. Reviewed-by: Tzung-Bi Shih <[email protected]> Signed-off-by: Guenter Roeck <[email protected]>
1 parent 9965ebd commit 4d5c2d9

File tree

2 files changed

+63
-2
lines changed

2 files changed

+63
-2
lines changed

Documentation/hwmon/ina2xx.rst

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,10 @@ Sysfs entries for ina226, ina230 and ina231 only
9999
------------------------------------------------
100100

101101
======================= ====================================================
102+
curr1_lcrit Critical low current
103+
curr1_crit Critical high current
104+
curr1_lcrit_alarm Current critical low alarm
105+
curr1_crit_alarm Current critical high alarm
102106
in0_lcrit Critical low shunt voltage
103107
in0_crit Critical high shunt voltage
104108
in0_lcrit_alarm Shunt voltage critical low alarm

drivers/hwmon/ina2xx.c

Lines changed: 59 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -306,7 +306,7 @@ static int ina2xx_read_init(struct device *dev, int reg, long *val)
306306
* Turns alert limit values into register values.
307307
* Opposite of the formula in ina2xx_get_value().
308308
*/
309-
static u16 ina226_alert_to_reg(struct ina2xx_data *data, int reg, unsigned long val)
309+
static u16 ina226_alert_to_reg(struct ina2xx_data *data, int reg, long val)
310310
{
311311
switch (reg) {
312312
case INA2XX_SHUNT_VOLTAGE:
@@ -322,6 +322,11 @@ static u16 ina226_alert_to_reg(struct ina2xx_data *data, int reg, unsigned long
322322
val = clamp_val(val, 0, UINT_MAX - data->power_lsb_uW);
323323
val = DIV_ROUND_CLOSEST(val, data->power_lsb_uW);
324324
return clamp_val(val, 0, USHRT_MAX);
325+
case INA2XX_CURRENT:
326+
val = clamp_val(val, INT_MIN / 1000, INT_MAX / 1000);
327+
/* signed register, result in mA */
328+
val = DIV_ROUND_CLOSEST(val * 1000, data->current_lsb_uA);
329+
return clamp_val(val, SHRT_MIN, SHRT_MAX);
325330
default:
326331
/* programmer goofed */
327332
WARN_ON_ONCE(1);
@@ -473,9 +478,31 @@ static int ina2xx_power_read(struct device *dev, u32 attr, long *val)
473478

474479
static int ina2xx_curr_read(struct device *dev, u32 attr, long *val)
475480
{
481+
struct ina2xx_data *data = dev_get_drvdata(dev);
482+
struct regmap *regmap = data->regmap;
483+
484+
/*
485+
* While the chips supported by this driver do not directly support
486+
* current limits, they do support setting shunt voltage limits.
487+
* The shunt voltage divided by the shunt resistor value is the current.
488+
* On top of that, calibration values are set such that in the shunt
489+
* voltage register and the current register report the same values.
490+
* That means we can report and configure current limits based on shunt
491+
* voltage limits.
492+
*/
476493
switch (attr) {
477494
case hwmon_curr_input:
478495
return ina2xx_read_init(dev, INA2XX_CURRENT, val);
496+
case hwmon_curr_lcrit:
497+
return ina226_alert_limit_read(data, INA226_SHUNT_UNDER_VOLTAGE_MASK,
498+
INA2XX_CURRENT, val);
499+
case hwmon_curr_crit:
500+
return ina226_alert_limit_read(data, INA226_SHUNT_OVER_VOLTAGE_MASK,
501+
INA2XX_CURRENT, val);
502+
case hwmon_curr_lcrit_alarm:
503+
return ina226_alert_read(regmap, INA226_SHUNT_UNDER_VOLTAGE_MASK, val);
504+
case hwmon_curr_crit_alarm:
505+
return ina226_alert_read(regmap, INA226_SHUNT_OVER_VOLTAGE_MASK, val);
479506
default:
480507
return -EOPNOTSUPP;
481508
}
@@ -547,6 +574,23 @@ static int ina2xx_power_write(struct device *dev, u32 attr, long val)
547574
return 0;
548575
}
549576

577+
static int ina2xx_curr_write(struct device *dev, u32 attr, long val)
578+
{
579+
struct ina2xx_data *data = dev_get_drvdata(dev);
580+
581+
switch (attr) {
582+
case hwmon_curr_lcrit:
583+
return ina226_alert_limit_write(data, INA226_SHUNT_UNDER_VOLTAGE_MASK,
584+
INA2XX_CURRENT, val);
585+
case hwmon_curr_crit:
586+
return ina226_alert_limit_write(data, INA226_SHUNT_OVER_VOLTAGE_MASK,
587+
INA2XX_CURRENT, val);
588+
default:
589+
return -EOPNOTSUPP;
590+
}
591+
return 0;
592+
}
593+
550594
static int ina2xx_write(struct device *dev, enum hwmon_sensor_types type,
551595
u32 attr, int channel, long val)
552596
{
@@ -557,6 +601,8 @@ static int ina2xx_write(struct device *dev, enum hwmon_sensor_types type,
557601
return ina2xx_in_write(dev, attr, channel, val);
558602
case hwmon_power:
559603
return ina2xx_power_write(dev, attr, val);
604+
case hwmon_curr:
605+
return ina2xx_curr_write(dev, attr, val);
560606
default:
561607
return -EOPNOTSUPP;
562608
}
@@ -591,6 +637,16 @@ static umode_t ina2xx_is_visible(const void *_data, enum hwmon_sensor_types type
591637
switch (attr) {
592638
case hwmon_curr_input:
593639
return 0444;
640+
case hwmon_curr_lcrit:
641+
case hwmon_curr_crit:
642+
if (chip == ina226)
643+
return 0644;
644+
break;
645+
case hwmon_curr_lcrit_alarm:
646+
case hwmon_curr_crit_alarm:
647+
if (chip == ina226)
648+
return 0444;
649+
break;
594650
default:
595651
break;
596652
}
@@ -636,7 +692,8 @@ static const struct hwmon_channel_info * const ina2xx_info[] = {
636692
HWMON_I_INPUT | HWMON_I_CRIT | HWMON_I_CRIT_ALARM |
637693
HWMON_I_LCRIT | HWMON_I_LCRIT_ALARM
638694
),
639-
HWMON_CHANNEL_INFO(curr, HWMON_C_INPUT),
695+
HWMON_CHANNEL_INFO(curr, HWMON_C_INPUT | HWMON_C_CRIT | HWMON_C_CRIT_ALARM |
696+
HWMON_C_LCRIT | HWMON_C_LCRIT_ALARM),
640697
HWMON_CHANNEL_INFO(power,
641698
HWMON_P_INPUT | HWMON_P_CRIT | HWMON_P_CRIT_ALARM),
642699
NULL

0 commit comments

Comments
 (0)