From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1427915AbeCBMzY (ORCPT ); Fri, 2 Mar 2018 07:55:24 -0500 Received: from heliosphere.sirena.org.uk ([172.104.155.198]:56996 "EHLO heliosphere.sirena.org.uk" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1423162AbeCBMzT (ORCPT ); Fri, 2 Mar 2018 07:55:19 -0500 From: Mark Brown To: Maciej Purski Cc: Mark Brown , linux-kernel@vger.kernel.org Subject: Applied "regulator: core: Change voltage setting path" to the regulator tree In-Reply-To: Message-Id: Date: Fri, 02 Mar 2018 12:55:15 +0000 Sender: linux-kernel-owner@vger.kernel.org List-ID: X-Mailing-List: linux-kernel@vger.kernel.org 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 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 Signed-off-by: Mark Brown --- 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