From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1751341AbeAVObG (ORCPT ); Mon, 22 Jan 2018 09:31:06 -0500 Received: from mailout1.w1.samsung.com ([210.118.77.11]:48219 "EHLO mailout1.w1.samsung.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1751288AbeAVOan (ORCPT ); Mon, 22 Jan 2018 09:30:43 -0500 DKIM-Filter: OpenDKIM Filter v2.11.0 mailout1.w1.samsung.com 20180122143041euoutp01f591ae6395dbbfe68eb06b6a88ead7cb~MKEKcNUmW2788227882euoutp01o X-AuditID: cbfec7f5-f79d06d0000031c7-bf-5a65f58f0322 From: Maciej Purski To: linux-kernel@vger.kernel.org, devicetree@vger.kernel.org Cc: Mark Brown , Liam Girdwood , Rob Herring , Mark Rutland , Marek Szyprowski , Doug Anderson , Bartlomiej Zolnierkiewicz , Maciej Purski Subject: [PATCH v4 7/7] regulator: core: Change voltage setting path Date: Mon, 22 Jan 2018 15:30:12 +0100 Message-id: <1516631412-17542-8-git-send-email-m.purski@samsung.com> X-Mailer: git-send-email 2.7.4 In-reply-to: <1516631412-17542-1-git-send-email-m.purski@samsung.com> X-Brightmail-Tracker: H4sIAAAAAAAAA+NgFrrIIsWRmVeSWpSXmKPExsWy7djPc7r9X1OjDK5e0bPYOGM9q8XUh0/Y LOYfOcdqcXbZQTaLb1c6mCwu75rDZrHg5S0Wi7VH7rJbLL1+kcmide8RdgcujzXz1jB6zG64 yOKxc9Zddo9NqzrZPPq2rGL0+LxJLoAtissmJTUnsyy1SN8ugStj6uajrAXfbSs2nbjM0sC4 xqiLkZNDQsBEYsqxHiYIW0ziwr31bF2MXBxCAksZJZZ/Oc4O4XxmlFh6bik7TMeL+48YIRLL GCXm/OiBavnPKPFky1mgKg4ONgEtiTXt8SANIgI2Em9vHABrYBY4ziRxfepGsH3CAi4Sr35s YwGxWQRUJZrfHGYFsXmB4tc7LzBDbJOTuHmuE8zmFHCV+NM3kQUivoZN4u42bgjbReLi7AVQ 1wlLvDq+BcqWkbg8uRuqvlri4tddbBB2jUTj7Q1QNdYSnydtAZvPLMAnMWnbdGaQ+yUEeCU6 2oQgSjwkVn3bD1XuKNH/6hPU8zMYJY4ev8U6gVF6ASPDKkaR1NLi3PTUYlO94sTc4tK8dL3k /NxNjMCIPv3v+NcdjEuPWR1iFOBgVOLh7TBIjRJiTSwrrsw9xCjBwawkwpu2AijEm5JYWZVa lB9fVJqTWnyIUZqDRUmc1zaqLVJIID2xJDU7NbUgtQgmy8TBKdXAKJteH2xj8u7lPUb/6E+7 fwemFHRsXbAp6G3wa8WKbJGquzcqVTUPHgp26OfLT7PK/GFnJqtzwUlff2eF969U+YbkP6u5 Qo8ff7RZ/12/gPiEV5f+LF1kuTlns9H8iv+mrcyGtoxed604VVLS5t/9qusxk2+jbH127Psb jMHdleXmVz7MLrylxFKckWioxVxUnAgA32B/PuQCAAA= X-Brightmail-Tracker: H4sIAAAAAAAAA+NgFlrGLMWRmVeSWpSXmKPExsVy+t/xa7r9X1OjDCZ/57LYOGM9q8XUh0/Y LOYfOcdqcXbZQTaLb1c6mCwu75rDZrHg5S0Wi7VH7rJbLL1+kcmide8RdgcujzXz1jB6zG64 yOKxc9Zddo9NqzrZPPq2rGL0+LxJLoAtissmJTUnsyy1SN8ugStj6uajrAXfbSs2nbjM0sC4 xqiLkZNDQsBE4sX9R4wQtpjEhXvr2UBsIYEljBIXN5l3MXIB2Y1MErfe32TvYuTgYBPQkljT Hg9SIyJgI/H2xgFGkBpmgZNMEn8urgMbJCzgIvHqxzYWEJtFQFWi+c1hVhCbFyh+vfMCM8Qy OYmb5zrBbE4BV4k/fRNZIBa7SOx98IZ9AiPvAkaGVYwiqaXFuem5xUZ6xYm5xaV56XrJ+bmb GIGht+3Yzy07GLveBR9iFOBgVOLh7TBIjRJiTSwrrsw9xCjBwawkwpu2AijEm5JYWZValB9f VJqTWnyIUZqDRUmct3fP6kghgfTEktTs1NSC1CKYLBMHp1QDY9aJaO3fTX1FJfflH6w9EMPo YX/eMNe2/9Fjs7g5offuex/Z47q+cD7jgjbpI/zyZz9ePufFEZ/t1u9ZY3/gkm6ElX0Q5w1z y2cXE10/cX3wW/5Lt/J50xXlimsxZ+JnWFz6Lc+6XybQ4ZnhtMUvDAIyefU1s58eylJhyX5z p8M3q/TWmR3vlViKMxINtZiLihMBH/D47DkCAAA= X-CMS-MailID: 20180122143039eucas1p2391bb266faeae319e95913c68e706ecf X-Msg-Generator: CA CMS-TYPE: 201P X-CMS-RootMailID: 20180122143039eucas1p2391bb266faeae319e95913c68e706ecf X-RootMTR: 20180122143039eucas1p2391bb266faeae319e95913c68e706ecf References: <1516631412-17542-1-git-send-email-m.purski@samsung.com> Sender: linux-kernel-owner@vger.kernel.org List-ID: X-Mailing-List: linux-kernel@vger.kernel.org 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 --- drivers/regulator/core.c | 103 +++++++++++++++++++++++++++++++++++++---------- 1 file changed, 82 insertions(+), 21 deletions(-) diff --git a/drivers/regulator/core.c b/drivers/regulator/core.c index 0492b0e..ce90246 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); @@ -180,6 +183,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 * @supply: regulator supply name @@ -2184,6 +2217,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; @@ -2193,9 +2231,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); @@ -2301,9 +2340,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); @@ -2352,10 +2392,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--) @@ -2888,8 +2929,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 @@ -2933,6 +2978,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) && @@ -2944,13 +3010,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(regulator, selector, 0); + 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; @@ -2958,7 +3024,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; @@ -2970,13 +3036,13 @@ 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; } } ret = _regulator_do_set_voltage(rdev, min_uV, max_uV); if (ret < 0) - goto out2; + goto out; if (supply_change_uV < 0) { ret = regulator_set_voltage_unlocked(rdev->supply, @@ -2990,11 +3056,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; } static int regulator_get_optimal_voltage(struct regulator_dev *rdev) @@ -3209,12 +3270,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.7.4