Re: [PATCH] hwmon: adm1177: fix sysfs ABI violation and current unit conversion
From: Nuno Sá
Date: Wed Mar 25 2026 - 06:46:01 EST
On Tue, 2026-03-24 at 18:22 +0000, Pradhan, Sanman wrote:
> From: Sanman Pradhan <psanman@xxxxxxxxxxx>
>
> The adm1177 driver exposes the current alert threshold using
> hwmon_curr_max_alarm. Per the hwmon sysfs ABI, *_alarm attributes
> are read-only status flags; the writable threshold should use
> hwmon_curr_max instead.
>
> Additionally, the threshold is stored internally in microamps
> (alert_threshold_ua) but the ABI requires milliamps for currN_max.
> Convert appropriately on both the read and write paths, and
> propagate the return value of adm1177_write_alert_thr() which was
> previously discarded.
>
> Clamp write values to the range the hardware can represent rather
> than rejecting out-of-range input, and use DIV_ROUND_CLOSEST on the
> read path to minimise rounding error during the uA-to-mA conversion.
>
> Fixes: 09b08ac9e8d5 ("hwmon: (adm1177) Add ADM1177 Hot Swap Controller and Digital Power Monitor
> driver")
> Signed-off-by: Sanman Pradhan <psanman@xxxxxxxxxxx>
> ---
For the AI comment, typically these applications don't go to ohms for rsense so, in practice, it
might be that we never get he overflow. But I would still play safe given it's so trivial. I also
see you only replace hwmon_curr_max_alarm with hwmon_curr_max. It would be nicer to first fix ABI
and then support hwmon_curr_max_alarm (properly). Though might be a big ask if you don't have HW to
test it. Anyways, after AI feedback addressed:
Acked-by: Nuno Sá <nuno.sa@xxxxxxxxxx>
> drivers/hwmon/adm1177.c | 16 +++++++++-------
> 1 file changed, 9 insertions(+), 7 deletions(-)
>
> diff --git a/drivers/hwmon/adm1177.c b/drivers/hwmon/adm1177.c
> index 8b2c965480e3f..8742b8b5314b6 100644
> --- a/drivers/hwmon/adm1177.c
> +++ b/drivers/hwmon/adm1177.c
> @@ -10,6 +10,7 @@
> #include <linux/hwmon.h>
> #include <linux/i2c.h>
> #include <linux/init.h>
> +#include <linux/minmax.h>
> #include <linux/module.h>
> #include <linux/regulator/consumer.h>
>
> @@ -91,8 +92,8 @@ static int adm1177_read(struct device *dev, enum hwmon_sensor_types type,
> *val = div_u64((105840000ull * dummy),
> 4096 * st->r_sense_uohm);
> return 0;
> - case hwmon_curr_max_alarm:
> - *val = st->alert_threshold_ua;
> + case hwmon_curr_max:
> + *val = DIV_ROUND_CLOSEST(st->alert_threshold_ua, 1000);
> return 0;
> default:
> return -EOPNOTSUPP;
> @@ -126,9 +127,10 @@ static int adm1177_write(struct device *dev, enum hwmon_sensor_types type,
> switch (type) {
> case hwmon_curr:
> switch (attr) {
> - case hwmon_curr_max_alarm:
> - adm1177_write_alert_thr(st, val);
> - return 0;
> + case hwmon_curr_max:
> + val = clamp_val(val, 0,
> + div_u64(105840000ULL, st->r_sense_uohm));
> + return adm1177_write_alert_thr(st, val * 1000);
> default:
> return -EOPNOTSUPP;
> }
> @@ -156,7 +158,7 @@ static umode_t adm1177_is_visible(const void *data,
> if (st->r_sense_uohm)
> return 0444;
> return 0;
> - case hwmon_curr_max_alarm:
> + case hwmon_curr_max:
> if (st->r_sense_uohm)
> return 0644;
> return 0;
> @@ -170,7 +172,7 @@ static umode_t adm1177_is_visible(const void *data,
>
> static const struct hwmon_channel_info * const adm1177_info[] = {
> HWMON_CHANNEL_INFO(curr,
> - HWMON_C_INPUT | HWMON_C_MAX_ALARM),
> + HWMON_C_INPUT | HWMON_C_MAX),
> HWMON_CHANNEL_INFO(in,
> HWMON_I_INPUT),
> NULL