diff options
-rw-r--r-- | drivers/regulator/core.c | 54 |
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 | |||
2819 | out: | 2869 | out: |
2820 | return ret; | 2870 | return ret; |
2821 | out2: | 2871 | out2: |
@@ -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(®ulator->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(®ulator->rdev->mutex); | 2904 | regulator_unlock_supply(regulator->rdev); |
2855 | 2905 | ||
2856 | return ret; | 2906 | return ret; |
2857 | } | 2907 | } |