aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSascha Hauer <s.hauer@pengutronix.de>2015-10-20 08:37:28 -0400
committerMark Brown <broonie@kernel.org>2015-10-22 08:34:11 -0400
commitfc42112c0eaa6fc7c7fe61f8c6fb91b204b4d31d (patch)
tree17690576a12144fbaa47315e72c4c0c6175efd68
parent2098bf215f85fd92175bd9f851cfdc5df5b736e4 (diff)
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 <s.hauer@pengutronix.de> Signed-off-by: Mark Brown <broonie@kernel.org>
-rw-r--r--drivers/regulator/core.c54
1 files 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,
2769 int ret = 0; 2769 int ret = 0;
2770 int old_min_uV, old_max_uV; 2770 int old_min_uV, old_max_uV;
2771 int current_uV; 2771 int current_uV;
2772 int best_supply_uV = 0;
2773 int supply_change_uV = 0;
2772 2774
2773 /* If we're setting the same range as last time the change 2775 /* If we're setting the same range as last time the change
2774 * should be a noop (some cpufreq implementations use the same 2776 * should be a noop (some cpufreq implementations use the same
@@ -2812,10 +2814,58 @@ static int regulator_set_voltage_unlocked(struct regulator *regulator,
2812 if (ret < 0) 2814 if (ret < 0)
2813 goto out2; 2815 goto out2;
2814 2816
2817 if (rdev->supply && (rdev->desc->min_dropout_uV ||
2818 !rdev->desc->ops->get_voltage)) {
2819 int current_supply_uV;
2820 int selector;
2821
2822 selector = regulator_map_voltage(rdev, min_uV, max_uV);
2823 if (selector < 0) {
2824 ret = selector;
2825 goto out2;
2826 }
2827
2828 best_supply_uV = _regulator_list_voltage(regulator, selector, 0);
2829 if (best_supply_uV < 0) {
2830 ret = best_supply_uV;
2831 goto out2;
2832 }
2833
2834 best_supply_uV += rdev->desc->min_dropout_uV;
2835
2836 current_supply_uV = _regulator_get_voltage(rdev->supply->rdev);
2837 if (current_supply_uV < 0) {
2838 ret = current_supply_uV;
2839 goto out2;
2840 }
2841
2842 supply_change_uV = best_supply_uV - current_supply_uV;
2843 }
2844
2845 if (supply_change_uV > 0) {
2846 ret = regulator_set_voltage_unlocked(rdev->supply,
2847 best_supply_uV, INT_MAX);
2848 if (ret) {
2849 dev_err(&rdev->dev, "Failed to increase supply voltage: %d\n",
2850 ret);
2851 goto out2;
2852 }
2853 }
2854
2815 ret = _regulator_do_set_voltage(rdev, min_uV, max_uV); 2855 ret = _regulator_do_set_voltage(rdev, min_uV, max_uV);
2816 if (ret < 0) 2856 if (ret < 0)
2817 goto out2; 2857 goto out2;
2818 2858
2859 if (supply_change_uV < 0) {
2860 ret = regulator_set_voltage_unlocked(rdev->supply,
2861 best_supply_uV, INT_MAX);
2862 if (ret)
2863 dev_warn(&rdev->dev, "Failed to decrease supply voltage: %d\n",
2864 ret);
2865 /* No need to fail here */
2866 ret = 0;
2867 }
2868
2819out: 2869out:
2820 return ret; 2870 return ret;
2821out2: 2871out2:
@@ -2847,11 +2897,11 @@ int regulator_set_voltage(struct regulator *regulator, int min_uV, int max_uV)
2847{ 2897{
2848 int ret = 0; 2898 int ret = 0;
2849 2899
2850 mutex_lock(&regulator->rdev->mutex); 2900 regulator_lock_supply(regulator->rdev);
2851 2901
2852 ret = regulator_set_voltage_unlocked(regulator, min_uV, max_uV); 2902 ret = regulator_set_voltage_unlocked(regulator, min_uV, max_uV);
2853 2903
2854 mutex_unlock(&regulator->rdev->mutex); 2904 regulator_unlock_supply(regulator->rdev);
2855 2905
2856 return ret; 2906 return ret;
2857} 2907}