The patch regulator: core: Propagate voltage changes to supply regulators
has been applied to the regulator tree at git://git.kernel.org/pub/scm/linux/kernel/git/broonie/regulator.git All being well this means that it will be integrated into the linux-next tree (usually sometime in the next 24 hours) and sent to Linus during the next merge window (or sooner if it is a bug fix), however if problems are discovered then the patch may be dropped or reverted. You may get further e-mails resulting from automated or manual testing and review of the tree, please engage with people reporting problems and send followup patches addressing any issues that are reported if needed. If any updates are required or you are submitting further changes they should be sent as incremental updates against current git, existing patches will not be replaced. Please add any relevant lists and maintainers to the CCs when replying to this mail. Thanks, Mark >From bb8a41b052bb418b349100a97f0dbc57417d9a9a Mon Sep 17 00:00:00 2001 From: Sascha Hauer <[email protected]> Date: Tue, 20 Oct 2015 14:37:28 +0200 Subject: [PATCH] regulator: core: Propagate voltage changes to supply regulators Until now changing the voltage of a regulator only ever effected the regulator itself, but never its supplies. It's a common pattern though to put LDO regulators behind switching regulators. The switching regulators efficiently drop the input voltage but have a high ripple on their output. The output is then cleaned up by the LDOs. For higher energy efficiency the voltage drop at the LDOs should be minimized. For this scenario we need to propagate the voltage change to the supply regulators. Another scenario where voltage propagation is desired is a regulator which only consists of a switch and thus cannot regulate voltages itself. In this case we can pass setting voltages to the supply. This patch adds support for voltage propagation. We do voltage propagation when the current regulator has a minimum dropout voltage specified or if the current regulator lacks a get_voltage operation (indicating it's a switch and not a regulator). Changing the supply voltage must be done carefully. When we are increasing the current regulators output we must first increase the supply voltage and then the regulator itself. When we are decreasing the current regulators voltage we must decrease the supply voltage after changing the current regulators voltage. Signed-off-by: Sascha Hauer <[email protected]> Signed-off-by: Mark Brown <[email protected]> --- drivers/regulator/core.c | 54 ++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 52 insertions(+), 2 deletions(-) diff --git a/drivers/regulator/core.c b/drivers/regulator/core.c index f15b04548715..771c6235cced 100644 --- a/drivers/regulator/core.c +++ b/drivers/regulator/core.c @@ -2769,6 +2769,8 @@ static int regulator_set_voltage_unlocked(struct regulator *regulator, int ret = 0; int old_min_uV, old_max_uV; int current_uV; + int best_supply_uV = 0; + int supply_change_uV = 0; /* If we're setting the same range as last time the change * should be a noop (some cpufreq implementations use the same @@ -2812,10 +2814,58 @@ static int regulator_set_voltage_unlocked(struct regulator *regulator, if (ret < 0) goto out2; + if (rdev->supply && (rdev->desc->min_dropout_uV || + !rdev->desc->ops->get_voltage)) { + int current_supply_uV; + int selector; + + selector = regulator_map_voltage(rdev, min_uV, max_uV); + if (selector < 0) { + ret = selector; + goto out2; + } + + best_supply_uV = _regulator_list_voltage(regulator, selector, 0); + if (best_supply_uV < 0) { + ret = best_supply_uV; + goto out2; + } + + best_supply_uV += rdev->desc->min_dropout_uV; + + current_supply_uV = _regulator_get_voltage(rdev->supply->rdev); + if (current_supply_uV < 0) { + ret = current_supply_uV; + goto out2; + } + + supply_change_uV = best_supply_uV - current_supply_uV; + } + + if (supply_change_uV > 0) { + ret = regulator_set_voltage_unlocked(rdev->supply, + best_supply_uV, INT_MAX); + if (ret) { + dev_err(&rdev->dev, "Failed to increase supply voltage: %d\n", + ret); + goto out2; + } + } + ret = _regulator_do_set_voltage(rdev, min_uV, max_uV); if (ret < 0) goto out2; + if (supply_change_uV < 0) { + ret = regulator_set_voltage_unlocked(rdev->supply, + best_supply_uV, INT_MAX); + if (ret) + dev_warn(&rdev->dev, "Failed to decrease supply voltage: %d\n", + ret); + /* No need to fail here */ + ret = 0; + } + out: return ret; out2: @@ -2847,11 +2897,11 @@ int regulator_set_voltage(struct regulator *regulator, int min_uV, int max_uV) { int ret = 0; - mutex_lock(®ulator->rdev->mutex); + regulator_lock_supply(regulator->rdev); ret = regulator_set_voltage_unlocked(regulator, min_uV, max_uV); - mutex_unlock(®ulator->rdev->mutex); + regulator_unlock_supply(regulator->rdev); return ret; } -- 2.6.1 -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to [email protected] More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/

