[PATCH v3] hwmon: (ads7828) Fix external VREF regulator handling
Qingshuang Fu <[email protected]> Wed, 5 Aug 2026 12:21:01 +0800
| Newsgroups | org.kernel.vger.linux-hwmon,org.kernel.vger.linux-kernel |
|---|---|
| Message-ID | <[email protected]> |
From: Qingshuang Fu <[email protected]> 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 <[email protected]> --- Changes in v3: - Switch to devm_regulator_get_enable_read_voltage() to also enable the external regulator, as suggested by Guenter Roeck. Changes in v2: - Broaden the error check to handle all errors except -ENODEV, instead of only checking for -EPROBE_DEFER. This addresses the Sashiko AI review concern about masking genuine errors like -ENOMEM and -EINVAL. drivers/hwmon/ads7828.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/drivers/hwmon/ads7828.c b/drivers/hwmon/ads7828.c index 149cfcec78dc..172da6f6549d 100644 --- a/drivers/hwmon/ads7828.c +++ b/drivers/hwmon/ads7828.c @@ -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,14 +124,15 @@ 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) { vref_mv = DIV_ROUND_CLOSEST(vref_uv, 1000); if (vref_mv < ADS7828_EXT_VREF_MV_MIN || vref_mv > ADS7828_EXT_VREF_MV_MAX) return -EINVAL; ext_vref = true; + } else if (vref_uv != -ENODEV) { + return vref_uv; } } -- 2.25.1