]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
hwmon: (pmbus/ina233) Fix error handling and sign extension in shunt voltage read
authorSanman Pradhan <psanman@juniper.net>
Thu, 19 Mar 2026 17:31:19 +0000 (17:31 +0000)
committerGuenter Roeck <linux@roeck-us.net>
Tue, 24 Mar 2026 14:55:08 +0000 (07:55 -0700)
ina233_read_word_data() reads MFR_READ_VSHUNT via pmbus_read_word_data()
but has two issues:

1. The return value is not checked for errors before being used in
   arithmetic. A negative error code from a failed I2C transaction is
   passed directly to DIV_ROUND_CLOSEST(), producing garbage data.

2. MFR_READ_VSHUNT is a 16-bit two's complement value. Negative shunt
   voltages (values with bit 15 set) are treated as large positive
   values since pmbus_read_word_data() returns them zero-extended in an
   int. This leads to incorrect scaling in the VIN coefficient
   conversion.

Fix both issues by adding an error check, casting to s16 for proper
sign extension, and clamping the result to a valid non-negative range.
The clamp is necessary because read_word_data callbacks must return
non-negative values on success (negative values indicate errors to the
pmbus core).

Fixes: b64b6cb163f16 ("hwmon: Add driver for TI INA233 Current and Power Monitor")
Cc: stable@vger.kernel.org
Signed-off-by: Sanman Pradhan <psanman@juniper.net>
Link: https://lore.kernel.org/r/20260319173055.125271-2-sanman.pradhan@hpe.com
[groeck: Fixed clamp to avoid losing the sign bit]
Signed-off-by: Guenter Roeck <linux@roeck-us.net>
drivers/hwmon/pmbus/ina233.c

index 2d8b5a5347edc3bbceb35f4ea8f618f391c798b0..7aebd854763a62367ba4e9d5562ef7259e5fa796 100644 (file)
@@ -72,7 +72,8 @@ static int ina233_read_word_data(struct i2c_client *client, int page,
 
                /* Adjust returned value to match VIN coefficients */
                /* VIN: 1.25 mV VSHUNT: 2.5 uV LSB */
-               ret = DIV_ROUND_CLOSEST(ret * 25, 12500);
+               ret = clamp_val(DIV_ROUND_CLOSEST((s16)ret * 25, 12500),
+                               S16_MIN, S16_MAX) & 0xffff;
                break;
        default:
                ret = -ENODATA;