Skip to content

Commit bf08749

Browse files
Sanman Pradhangroeck
authored andcommitted
hwmon: (adm1177) fix sysfs ABI violation and current unit conversion
The adm1177 driver exposes the current alert threshold through hwmon_curr_max_alarm. This violates the hwmon sysfs ABI, where *_alarm attributes are read-only status flags and writable thresholds must use currN_max. The driver also stores the threshold internally in microamps, while currN_max is defined in milliamps. Convert the threshold accordingly on both the read and write paths. Widen the cached threshold and related calculations to 64 bits so that small shunt resistor values do not cause truncation or overflow. Also use 64-bit arithmetic for the mA/uA conversions, clamp writes to the range the hardware can represent, and propagate failures from adm1177_write_alert_thr() instead of silently ignoring them. Update the hwmon documentation to reflect the attribute rename and the correct units returned by the driver. Fixes: 09b08ac ("hwmon: (adm1177) Add ADM1177 Hot Swap Controller and Digital Power Monitor driver") Signed-off-by: Sanman Pradhan <[email protected]> Acked-by: Nuno Sá <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Guenter Roeck <[email protected]>
1 parent b0c9d8a commit bf08749

2 files changed

Lines changed: 35 additions & 27 deletions

File tree

Documentation/hwmon/adm1177.rst

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -27,10 +27,10 @@ for details.
2727
Sysfs entries
2828
-------------
2929

30-
The following attributes are supported. Current maxim attribute
30+
The following attributes are supported. Current maximum attribute
3131
is read-write, all other attributes are read-only.
3232

33-
in0_input Measured voltage in microvolts.
33+
in0_input Measured voltage in millivolts.
3434

35-
curr1_input Measured current in microamperes.
36-
curr1_max_alarm Overcurrent alarm in microamperes.
35+
curr1_input Measured current in milliamperes.
36+
curr1_max Overcurrent shutdown threshold in milliamperes.

drivers/hwmon/adm1177.c

Lines changed: 31 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@
1010
#include <linux/hwmon.h>
1111
#include <linux/i2c.h>
1212
#include <linux/init.h>
13+
#include <linux/math64.h>
14+
#include <linux/minmax.h>
1315
#include <linux/module.h>
1416
#include <linux/regulator/consumer.h>
1517

@@ -33,7 +35,7 @@
3335
struct adm1177_state {
3436
struct i2c_client *client;
3537
u32 r_sense_uohm;
36-
u32 alert_threshold_ua;
38+
u64 alert_threshold_ua;
3739
bool vrange_high;
3840
};
3941

@@ -48,7 +50,7 @@ static int adm1177_write_cmd(struct adm1177_state *st, u8 cmd)
4850
}
4951

5052
static int adm1177_write_alert_thr(struct adm1177_state *st,
51-
u32 alert_threshold_ua)
53+
u64 alert_threshold_ua)
5254
{
5355
u64 val;
5456
int ret;
@@ -91,8 +93,8 @@ static int adm1177_read(struct device *dev, enum hwmon_sensor_types type,
9193
*val = div_u64((105840000ull * dummy),
9294
4096 * st->r_sense_uohm);
9395
return 0;
94-
case hwmon_curr_max_alarm:
95-
*val = st->alert_threshold_ua;
96+
case hwmon_curr_max:
97+
*val = div_u64(st->alert_threshold_ua, 1000);
9698
return 0;
9799
default:
98100
return -EOPNOTSUPP;
@@ -126,9 +128,10 @@ static int adm1177_write(struct device *dev, enum hwmon_sensor_types type,
126128
switch (type) {
127129
case hwmon_curr:
128130
switch (attr) {
129-
case hwmon_curr_max_alarm:
130-
adm1177_write_alert_thr(st, val);
131-
return 0;
131+
case hwmon_curr_max:
132+
val = clamp_val(val, 0,
133+
div_u64(105840000ULL, st->r_sense_uohm));
134+
return adm1177_write_alert_thr(st, (u64)val * 1000);
132135
default:
133136
return -EOPNOTSUPP;
134137
}
@@ -156,7 +159,7 @@ static umode_t adm1177_is_visible(const void *data,
156159
if (st->r_sense_uohm)
157160
return 0444;
158161
return 0;
159-
case hwmon_curr_max_alarm:
162+
case hwmon_curr_max:
160163
if (st->r_sense_uohm)
161164
return 0644;
162165
return 0;
@@ -170,7 +173,7 @@ static umode_t adm1177_is_visible(const void *data,
170173

171174
static const struct hwmon_channel_info * const adm1177_info[] = {
172175
HWMON_CHANNEL_INFO(curr,
173-
HWMON_C_INPUT | HWMON_C_MAX_ALARM),
176+
HWMON_C_INPUT | HWMON_C_MAX),
174177
HWMON_CHANNEL_INFO(in,
175178
HWMON_I_INPUT),
176179
NULL
@@ -192,7 +195,8 @@ static int adm1177_probe(struct i2c_client *client)
192195
struct device *dev = &client->dev;
193196
struct device *hwmon_dev;
194197
struct adm1177_state *st;
195-
u32 alert_threshold_ua;
198+
u64 alert_threshold_ua;
199+
u32 prop;
196200
int ret;
197201

198202
st = devm_kzalloc(dev, sizeof(*st), GFP_KERNEL);
@@ -208,22 +212,26 @@ static int adm1177_probe(struct i2c_client *client)
208212
if (device_property_read_u32(dev, "shunt-resistor-micro-ohms",
209213
&st->r_sense_uohm))
210214
st->r_sense_uohm = 0;
211-
if (device_property_read_u32(dev, "adi,shutdown-threshold-microamp",
212-
&alert_threshold_ua)) {
213-
if (st->r_sense_uohm)
214-
/*
215-
* set maximum default value from datasheet based on
216-
* shunt-resistor
217-
*/
218-
alert_threshold_ua = div_u64(105840000000,
219-
st->r_sense_uohm);
220-
else
221-
alert_threshold_ua = 0;
215+
if (!device_property_read_u32(dev, "adi,shutdown-threshold-microamp",
216+
&prop)) {
217+
alert_threshold_ua = prop;
218+
} else if (st->r_sense_uohm) {
219+
/*
220+
* set maximum default value from datasheet based on
221+
* shunt-resistor
222+
*/
223+
alert_threshold_ua = div_u64(105840000000ULL,
224+
st->r_sense_uohm);
225+
} else {
226+
alert_threshold_ua = 0;
222227
}
223228
st->vrange_high = device_property_read_bool(dev,
224229
"adi,vrange-high-enable");
225-
if (alert_threshold_ua && st->r_sense_uohm)
226-
adm1177_write_alert_thr(st, alert_threshold_ua);
230+
if (alert_threshold_ua && st->r_sense_uohm) {
231+
ret = adm1177_write_alert_thr(st, alert_threshold_ua);
232+
if (ret)
233+
return ret;
234+
}
227235

228236
ret = adm1177_write_cmd(st, ADM1177_CMD_V_CONT |
229237
ADM1177_CMD_I_CONT |

0 commit comments

Comments
 (0)