The patch

   regulator: core: Change voltage setting path

has been applied to the regulator tree at

   https://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 71c33626a802be7d45d7c3f9ee003317b12508d9 Mon Sep 17 00:00:00 2001
From: Maciej Purski <m.pur...@samsung.com>
Date: Fri, 2 Mar 2018 09:42:49 +0100
Subject: [PATCH] regulator: core: Change voltage setting path

On Odroid XU3/4 and other Exynos5422 based boards there is a case, that
different devices on the board are supplied by different regulators
with non-fixed voltages. If one of these devices temporarily requires
higher voltage, there might occur a situation that the spread between
two devices' voltages is so high, that there is a risk of changing
'high' and 'low' states on the interconnection between devices powered
by those regulators.

Uncoupled regulators should be a special case of coupled regulators, so
they should share a common voltage setting path. When enabling,
disabling or setting voltage of a coupled regulator, all coupled
regulators should be locked. Regulator's supplies should be locked, when
setting voltage of a single regulator. Enabling a coupled regulator or
setting its voltage should not be possible if some of its coupled
regulators, has not been registered.

Add function for locking coupled regulators. Extract a new function
regulator_set_voltage_rdev() from regulator_set_voltage_unlocked(),
which is called when setting voltage of a single regulator.

Signed-off-by: Maciej Purski <m.pur...@samsung.com>
Signed-off-by: Mark Brown <broo...@kernel.org>
---
 drivers/regulator/core.c | 101 +++++++++++++++++++++++++++++++++++++----------
 1 file changed, 81 insertions(+), 20 deletions(-)

diff --git a/drivers/regulator/core.c b/drivers/regulator/core.c
index 064115875865..d68244ad9423 100644
--- a/drivers/regulator/core.c
+++ b/drivers/regulator/core.c
@@ -107,6 +107,9 @@ static int _regulator_do_set_voltage(struct regulator_dev 
*rdev,
                                     int min_uV, int max_uV);
 static int regulator_balance_voltage(struct regulator_dev *rdev,
                                     suspend_state_t state);
+static int regulator_set_voltage_rdev(struct regulator_dev *rdev,
+                                     int min_uV, int max_uV,
+                                     suspend_state_t state);
 static struct regulator *create_regulator(struct regulator_dev *rdev,
                                          struct device *dev,
                                          const char *supply_name);
@@ -179,6 +182,36 @@ static void regulator_unlock_supply(struct regulator_dev 
*rdev)
        }
 }
 
+/**
+ * regulator_lock_coupled - lock a group of coupled regulators
+ * @rdev:      regulator source
+ */
+static void regulator_lock_coupled(struct regulator_dev *rdev)
+{
+       struct coupling_desc *c_desc = &rdev->coupling_desc;
+       int n_coupled = c_desc->n_coupled;
+       int i;
+
+       for (i = 0; i < n_coupled; i++)
+               if (c_desc->coupled_rdevs[i])
+                       mutex_lock_nested(&c_desc->coupled_rdevs[i]->mutex, i);
+}
+
+/**
+ * regulator_unlock_coupled - unlock a group of coupled regulators
+ * @rdev:      regulator source
+ */
+static void regulator_unlock_coupled(struct regulator_dev *rdev)
+{
+       struct coupling_desc *c_desc = &rdev->coupling_desc;
+       int n_coupled = c_desc->n_coupled;
+       int i;
+
+       for (i = 0; i < n_coupled; i++)
+               if (c_desc->coupled_rdevs[i])
+                       mutex_unlock(&c_desc->coupled_rdevs[i]->mutex);
+}
+
 /**
  * of_get_regulator - get a regulator device node based on supply name
  * @dev: Device pointer for the consumer (of regulator) device
@@ -2193,6 +2226,11 @@ int regulator_enable(struct regulator *regulator)
        struct regulator_dev *rdev = regulator->rdev;
        int ret = 0;
 
+       if (rdev->coupling_desc.n_resolved != rdev->coupling_desc.n_coupled) {
+               rdev_err(rdev, "not all coupled regulators registered\n");
+               return -EPERM;
+       }
+
        if (regulator->always_on)
                return 0;
 
@@ -2202,9 +2240,10 @@ int regulator_enable(struct regulator *regulator)
                        return ret;
        }
 
-       mutex_lock(&rdev->mutex);
+       regulator_lock_coupled(rdev);
        ret = _regulator_enable(rdev);
-       mutex_unlock(&rdev->mutex);
+       regulator_balance_voltage(rdev, PM_SUSPEND_ON);
+       regulator_unlock_coupled(rdev);
 
        if (ret != 0 && rdev->supply)
                regulator_disable(rdev->supply);
@@ -2310,9 +2349,10 @@ int regulator_disable(struct regulator *regulator)
        if (regulator->always_on)
                return 0;
 
-       mutex_lock(&rdev->mutex);
+       regulator_lock_coupled(rdev);
        ret = _regulator_disable(rdev);
-       mutex_unlock(&rdev->mutex);
+       regulator_balance_voltage(rdev, PM_SUSPEND_ON);
+       regulator_unlock_coupled(rdev);
 
        if (ret == 0 && rdev->supply)
                regulator_disable(rdev->supply);
@@ -2361,10 +2401,11 @@ int regulator_force_disable(struct regulator *regulator)
        struct regulator_dev *rdev = regulator->rdev;
        int ret;
 
-       mutex_lock(&rdev->mutex);
+       regulator_lock_coupled(rdev);
        regulator->uA_load = 0;
        ret = _regulator_force_disable(regulator->rdev);
-       mutex_unlock(&rdev->mutex);
+       regulator_balance_voltage(rdev, PM_SUSPEND_ON);
+       regulator_unlock_coupled(rdev);
 
        if (rdev->supply)
                while (rdev->open_count--)
@@ -2923,8 +2964,12 @@ 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 (rdev->coupling_desc.n_resolved != rdev->coupling_desc.n_coupled) {
+               rdev_err(rdev, "not all coupled regulators registered\n");
+               ret = -EPERM;
+               goto out;
+       }
 
        /* If we're setting the same range as last time the change
         * should be a noop (some cpufreq implementations use the same
@@ -2968,6 +3013,27 @@ static int regulator_set_voltage_unlocked(struct 
regulator *regulator,
        if (ret < 0)
                goto out2;
 
+       /* for not coupled regulators this will just set the voltage */
+       ret = regulator_balance_voltage(rdev, state);
+       if (ret < 0)
+               goto out2;
+
+out:
+       return 0;
+out2:
+       voltage->min_uV = old_min_uV;
+       voltage->max_uV = old_max_uV;
+
+       return ret;
+}
+
+static int regulator_set_voltage_rdev(struct regulator_dev *rdev, int min_uV,
+                                     int max_uV, suspend_state_t state)
+{
+       int best_supply_uV = 0;
+       int supply_change_uV = 0;
+       int ret;
+
        if (rdev->supply &&
            regulator_ops_is_valid(rdev->supply->rdev,
                                   REGULATOR_CHANGE_VOLTAGE) &&
@@ -2979,13 +3045,13 @@ static int regulator_set_voltage_unlocked(struct 
regulator *regulator,
                selector = regulator_map_voltage(rdev, min_uV, max_uV);
                if (selector < 0) {
                        ret = selector;
-                       goto out2;
+                       goto out;
                }
 
                best_supply_uV = _regulator_list_voltage(rdev, selector, 0);
                if (best_supply_uV < 0) {
                        ret = best_supply_uV;
-                       goto out2;
+                       goto out;
                }
 
                best_supply_uV += rdev->desc->min_dropout_uV;
@@ -2993,7 +3059,7 @@ static int regulator_set_voltage_unlocked(struct 
regulator *regulator,
                current_supply_uV = _regulator_get_voltage(rdev->supply->rdev);
                if (current_supply_uV < 0) {
                        ret = current_supply_uV;
-                       goto out2;
+                       goto out;
                }
 
                supply_change_uV = best_supply_uV - current_supply_uV;
@@ -3005,7 +3071,7 @@ static int regulator_set_voltage_unlocked(struct 
regulator *regulator,
                if (ret) {
                        dev_err(&rdev->dev, "Failed to increase supply voltage: 
%d\n",
                                        ret);
-                       goto out2;
+                       goto out;
                }
        }
 
@@ -3015,7 +3081,7 @@ static int regulator_set_voltage_unlocked(struct 
regulator *regulator,
                ret = _regulator_do_set_suspend_voltage(rdev, min_uV,
                                                        max_uV, state);
        if (ret < 0)
-               goto out2;
+               goto out;
 
        if (supply_change_uV < 0) {
                ret = regulator_set_voltage_unlocked(rdev->supply,
@@ -3028,11 +3094,6 @@ static int regulator_set_voltage_unlocked(struct 
regulator *regulator,
        }
 
 out:
-       return ret;
-out2:
-       voltage->min_uV = old_min_uV;
-       voltage->max_uV = old_max_uV;
-
        return ret;
 }
 
@@ -3248,12 +3309,12 @@ int regulator_set_voltage(struct regulator *regulator, 
int min_uV, int max_uV)
 {
        int ret = 0;
 
-       regulator_lock_supply(regulator->rdev);
+       regulator_lock_coupled(regulator->rdev);
 
        ret = regulator_set_voltage_unlocked(regulator, min_uV, max_uV,
                                             PM_SUSPEND_ON);
 
-       regulator_unlock_supply(regulator->rdev);
+       regulator_unlock_coupled(regulator->rdev);
 
        return ret;
 }
-- 
2.16.2

Reply via email to