From 867c25480117e31ea2c510b414391ba9f43b9875 Mon Sep 17 00:00:00 2001 From: Ionut Catalin Pavel Date: Sun, 12 Feb 2023 18:06:47 +0200 Subject: [PATCH] drivers: regulator: common: skip voltage change at init if already valid The current implementation always sets the voltage before enabling, even if the current voltage is in the allowed range. This has some side effects, i.e. for PMIC regulators that are pre-programmed for a specific value but allow voltage changes during runtime. The side effect being that the regulator will always be reset to the lower value of the voltage range at init. Another usecase would be when a bootloader sets a specific voltage then loads an application that uses the same driver. The proposed fix is to evaluate the current voltage and try to bring the actual voltage in range if the current voltage is not valid according to the min/max constraints. Tested on custom SAMD20 board with a custom RK816 PMIC driver. Signed-off-by: Ionut Catalin Pavel --- drivers/regulator/regulator_common.c | 22 ++++++++++++++++++---- 1 file changed, 18 insertions(+), 4 deletions(-) diff --git a/drivers/regulator/regulator_common.c b/drivers/regulator/regulator_common.c index d00e2f647fe..cc705238a09 100644 --- a/drivers/regulator/regulator_common.c +++ b/drivers/regulator/regulator_common.c @@ -18,6 +18,7 @@ int regulator_common_init(const struct device *dev, bool is_enabled) const struct regulator_driver_api *api = dev->api; const struct regulator_common_config *config = dev->config; struct regulator_common_data *data = dev->data; + int32_t current_uv; int ret; if (config->initial_mode != REGULATOR_INITIAL_MODE_UNKNOWN) { @@ -27,13 +28,26 @@ int regulator_common_init(const struct device *dev, bool is_enabled) } } - /* regulator voltage needs to be within allowed range before enabling */ + /* If we have valid range values, we try to match them before enabling */ if ((config->min_uv > INT32_MIN) || (config->max_uv < INT32_MAX)) { - ret = regulator_set_voltage(dev, config->min_uv, - config->max_uv); - if ((ret < 0) && (ret != -ENOSYS)) { + + ret = regulator_get_voltage(dev, ¤t_uv); + if (ret < 0) { return ret; } + + /* Snap to closest interval value if out of range */ + if (current_uv < config->min_uv) { + ret = regulator_set_voltage(dev, config->min_uv, config->min_uv); + if (ret < 0) { + return ret; + } + } else if (current_uv > config->max_uv) { + ret = regulator_set_voltage(dev, config->max_uv, config->max_uv); + if (ret < 0) { + return ret; + } + } } if (is_enabled) {