]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
hwmon: (ads7828) Fix external VREF regulator handling
authorQingshuang Fu <fuqingshuang@kylinos.cn>
Wed, 5 Aug 2026 06:16:45 +0000 (14:16 +0800)
committerGuenter Roeck <linux@roeck-us.net>
Fri, 7 Aug 2026 05:37:44 +0000 (22:37 -0700)
The driver currently has two issues with the external VREF regulator
handling in ads7828_probe():

1. All errors from devm_regulator_get_optional() are ignored, causing the
   driver to incorrectly fall back to internal VREF even for transient
   errors like -EPROBE_DEFER or genuine failures like -ENOMEM.

2. The external regulator is never enabled. The driver calls
   regulator_get_voltage() without first calling regulator_enable(),
   so the VREF pin may remain unpowered if the regulator is not
   configured as always-on.

Fix both issues by switching to devm_regulator_get_enable_read_voltage(),
which handles regulator get, enable, and voltage read in one call.
Only -ENODEV (no regulator specified in device tree) should trigger the
fallback to internal VREF. All other errors are propagated to the caller.

Fixes: a8ddfea09566 ("hwmon: (ads7828) Accept optional parameters from device tree")
Signed-off-by: Qingshuang Fu <fuqingshuang@kylinos.cn>
Link: https://lore.kernel.org/r/20260805061645.1331652-1-fffsqian@163.com
Signed-off-by: Guenter Roeck <linux@roeck-us.net>
drivers/hwmon/ads7828.c

index 149cfcec78dcc2c3a567b3fe6d151871adffbf3e..f8f2f621dfeafe83f7b4db5d5e74d7a65a522ea9 100644 (file)
@@ -106,12 +106,11 @@ static int ads7828_probe(struct i2c_client *client)
        struct ads7828_data *data;
        struct device *hwmon_dev;
        unsigned int vref_mv = ADS7828_INT_VREF_MV;
-       unsigned int vref_uv;
+       int vref_uv;
        bool diff_input = false;
        bool ext_vref = false;
        unsigned int regval;
        enum ads7828_chips chip;
-       struct regulator *reg;
 
        data = devm_kzalloc(dev, sizeof(struct ads7828_data), GFP_KERNEL);
        if (!data)
@@ -125,9 +124,11 @@ static int ads7828_probe(struct i2c_client *client)
        } else if (dev->of_node) {
                diff_input = of_property_read_bool(dev->of_node,
                                                   "ti,differential-input");
-               reg = devm_regulator_get_optional(dev, "vref");
-               if (!IS_ERR(reg)) {
-                       vref_uv = regulator_get_voltage(reg);
+               vref_uv = devm_regulator_get_enable_read_voltage(dev, "vref");
+               if (vref_uv < 0) {
+                       if (vref_uv != -ENODEV)
+                               return vref_uv;
+               } else {
                        vref_mv = DIV_ROUND_CLOSEST(vref_uv, 1000);
                        if (vref_mv < ADS7828_EXT_VREF_MV_MIN ||
                            vref_mv > ADS7828_EXT_VREF_MV_MAX)