Received: by 10.223.185.116 with SMTP id b49csp8524716wrg; Fri, 2 Mar 2018 03:26:37 -0800 (PST) X-Google-Smtp-Source: AG47ELtBtMmKHDROKTNz/iq/vC11DComuN4O6Exu/1CoUozWFzYwpuZ58K8+KowGkEUknpSn27V+ X-Received: by 2002:a17:902:6bc2:: with SMTP id m2-v6mr4460005plt.432.1519989996890; Fri, 02 Mar 2018 03:26:36 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1519989996; cv=none; d=google.com; s=arc-20160816; b=yEf6OLbwQQOhRjxgmNf3ajIvxACa2Bxn6AQ1osQYDuWS0nhBBxDvQ3MJmohg7J2Pz1 Na1H6ZQHGcjFyC5Tv3BEcWF9CIAr5pFZMOlo75y9TkVkoEl8fuJujelPJ4Mok3T90TTG oRbaqs3zjiroVHunroH9d0d9Jk0pVgCj0Ux0gQtrYoohSXFnng7IrA4P9dM0ZQbmcfdm IBem72YGFD9zY/zTUFpu3kj89wDk+9Y/9m7zrU48wFpS3VlnmPNU0oQgqeP2mVK0SMwk Wl5h0005s1Pixgr2/aCIJHVFosl07/GzsFYNma3oC080Z5xAlNUMhXs6R3jr6sf5ZaM6 EHkw== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:sender:references:cms-type:in-reply-to :message-id:date:subject:cc:to:from:dkim-signature:dkim-filter :arc-authentication-results; bh=/PSzQCv3tyk1VVpnetCj/nWiFrH97ZQCqRr6B8Hzuxc=; b=lqGBl/RQp8Lz3Fapw7TUoLl+lcCDoTaEvHfPUqe6dq504/AqhsLYmdOQkh+UXJjV+N n88G590Q6QSesPxCKze1llidm6N1dDF8ouDKiamiPNj/zz1+kBZA/56sofAo0BXDpmXv jrEBmE6prRNH/hjh5kKfmOyDyFsUxZ05fWHoXQM8mbwNWM4s7sgJvQVnag0ntzNowhMM xULmx9BTe9a2p+1Rr2AxsPyuLkGtQVlgQMrRu4QvOpBjsNAa7QEu8hlx+TVQBn3TsgeJ gckjFsfrsYMAK6EyDLbwokTOuuIafKxm9xxZ5/zp76LzhjJJMjAGuoabLpjZzmC5IOin 30Jg== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@samsung.com header.s=mail20170921 header.b=ou+6mX6o; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=samsung.com Return-Path: Received: from vger.kernel.org (vger.kernel.org. [209.132.180.67]) by mx.google.com with ESMTP id t21-v6si4828089plj.269.2018.03.02.03.26.20; Fri, 02 Mar 2018 03:26:36 -0800 (PST) Received-SPF: pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) client-ip=209.132.180.67; Authentication-Results: mx.google.com; dkim=pass header.i=@samsung.com header.s=mail20170921 header.b=ou+6mX6o; spf=pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=NONE sp=NONE dis=NONE) header.from=samsung.com Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1427175AbeCBLYF (ORCPT + 99 others); Fri, 2 Mar 2018 06:24:05 -0500 Received: from mailout1.w1.samsung.com ([210.118.77.11]:32809 "EHLO mailout1.w1.samsung.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1422736AbeCBIvc (ORCPT ); Fri, 2 Mar 2018 03:51:32 -0500 Received: from eucas1p1.samsung.com (unknown [182.198.249.206]) by mailout1.w1.samsung.com (KnoxPortal) with ESMTP id 20180302085130euoutp01d0d7b347e74db5f0729ab291173b436d~YDmKPWNPL2795527955euoutp01A; Fri, 2 Mar 2018 08:51:30 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 mailout1.w1.samsung.com 20180302085130euoutp01d0d7b347e74db5f0729ab291173b436d~YDmKPWNPL2795527955euoutp01A DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=samsung.com; s=mail20170921; t=1519980690; bh=/PSzQCv3tyk1VVpnetCj/nWiFrH97ZQCqRr6B8Hzuxc=; h=From:To:Cc:Subject:Date:In-reply-to:References:From; b=ou+6mX6om2uGEqcF7MH8p9DU1vsuBJZdTibHaunKjggML0QVSzugVuYa1SreyUBil mQr3q837XSSRulEypkH2R/7g33FwJRo2VqQEt/LeRFPST5Tf9MDqhKuoyVdHv6Ub0E IzpswFAujGIiLKYVYbSFI7womNaqVCpz7FvZf95A= Received: from eusmges3new.samsung.com (unknown [203.254.199.245]) by eucas1p1.samsung.com (KnoxPortal) with ESMTP id 20180302085129eucas1p1391e5f6fe4e7d0a958d5f7e76d92379c~YDmJgAT3P1600916009eucas1p1j; Fri, 2 Mar 2018 08:51:29 +0000 (GMT) Received: from eucas1p2.samsung.com ( [182.198.249.207]) by eusmges3new.samsung.com (EUCPMTA) with SMTP id E9.4A.10409.190199A5; Fri, 2 Mar 2018 08:51:29 +0000 (GMT) Received: from eusmgms1.samsung.com (unknown [182.198.249.179]) by eucas1p1.samsung.com (KnoxPortal) with ESMTP id 20180302085129eucas1p165d7e94517ca9c6fee534f53a88125a9~YDmIy6__X1383313833eucas1p1e; Fri, 2 Mar 2018 08:51:29 +0000 (GMT) X-AuditID: cbfec7f5-b5fff700000028a9-4e-5a9910914568 Received: from eusync1.samsung.com ( [203.254.199.211]) by eusmgms1.samsung.com (EUCPMTA) with SMTP id C9.FD.04178.190199A5; Fri, 2 Mar 2018 08:51:29 +0000 (GMT) Received: from AMDC2075.DIGITAL.local ([106.120.51.25]) by eusync1.samsung.com (Oracle Communications Messaging Server 7.0.5.31.0 64bit (built May 5 2014)) with ESMTPA id <0P4Y008BPG7PXE30@eusync1.samsung.com>; Fri, 02 Mar 2018 08:51:29 +0000 (GMT) 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 v5 5/5] regulator: core: Change voltage setting path Date: Fri, 02 Mar 2018 09:42:49 +0100 Message-id: <1519980169-8491-6-git-send-email-m.purski@samsung.com> X-Mailer: git-send-email 2.7.4 In-reply-to: <1519980169-8491-1-git-send-email-m.purski@samsung.com> X-Brightmail-Tracker: H4sIAAAAAAAAA+NgFjrOIsWRmVeSWpSXmKPExsWy7djP87oTBWZGGWx5rWqxccZ6VoupD5+w Wcw/co7V4uyyg2wW3650MFlc3jWHzWLBy1ssFmuP3GW3WHr9IpNF694j7A5cHmvmrWH0mN1w kcVj56y77B6bVnWyefRtWcXo8XmTXABbFJdNSmpOZllqkb5dAlfGxUU7GAuW2VX823yOrYHx rFEXIyeHhICJxORLO1lAbCGBFYwSi+eGQtifGSXOH9eFqTmz5wN7FyMXUHwZo8SyB1vZIJz/ QM63mUAOBwebgJbEmvZ4kAYRARuJtzcOMILUMAscZ5K4PnUjE0hCWMBF4nHHIlYQm0VAVaJv 8lYwm1fAWWL28idsENvkJG6e62QGsTmB6n8+WAW2TEJgCZvEm6sfGSGKXCTmX97KBGELS7w6 voUdwpaR6Ow4CBWvlrj4dRfU0BqJxtsboGqsJT5P2gK2gFmAT2LStunMIA9ICPBKdLQJQZR4 SDyd0Q81xlHiwdsFTBAPT2eUePBrE+MERqkFjAyrGMVTS4tz01OLjfNSy/WKE3OLS/PS9ZLz czcxAqP39L/jX3cw7vuTdIhRgINRiYd3J+eMKCHWxLLiytxDjBIczEoivC0fgEK8KYmVValF +fFFpTmpxYcYpTlYlMR54zTqooQE0hNLUrNTUwtSi2CyTBycUg2Muv0T5P6HSxxWXvf5q77D O32p+aE8JZvmTa3v7l668a35/op9x319/hgkKPhPX62uy5Vz78ZuaeuQF8evNOpNSlTmKtr2 x2fajqfbf7/3rC0KD76hGl8z4UAk+3EJAS7+yGkcD87xHSrVsrvMXvrcSS2keLb8lVfxnqZS e48J3l+e2rPu/dptSizFGYmGWsxFxYkAxde1jdoCAAA= X-Brightmail-Tracker: H4sIAAAAAAAAA+NgFprNLMWRmVeSWpSXmKPExsVy+t/xy7oTBWZGGbyZw2GxccZ6VoupD5+w Wcw/co7V4uyyg2wW3650MFlc3jWHzWLBy1ssFmuP3GW3WHr9IpNF694j7A5cHmvmrWH0mN1w kcVj56y77B6bVnWyefRtWcXo8XmTXABbFJdNSmpOZllqkb5dAlfGxUU7GAuW2VX823yOrYHx rFEXIyeHhICJxJk9H9i7GLk4hASWMErc+L2RGcJpZJK4dug2UIaDg01AS2JNezxIg4iAjcTb GwcYQWqYBU4ySfy5uI4RJCEs4CLxuGMRK4jNIqAq0Td5K5jNK+AsMXv5EzaIbXISN891MoPY nED1Px+sAosLAdU0Hl3HPoGRZwEjwypGkdTS4tz03GJDveLE3OLSvHS95PzcTYzAINt27Ofm HYyXNgYfYhTgYFTi4T3wcUaUEGtiWXFl7iFGCQ5mJRHelg9AId6UxMqq1KL8+KLSnNTiQ4zS HCxK4rznDSqjhATSE0tSs1NTC1KLYLJMHJxSDYz1sRIzkz+oPnh97ZJUVnXijK1W+9j8b9l0 rnbYvvOYi9CXDZ+CUndqin9oPGLgpfOE69mTpH8L9vAmt043f673UDc0dJfVUeZpWy7nzl/r m7NR0vfk6wVnuPYJ/1n4sv3lqdQr7gel5ldVJCtkn930UEHZwYK9UOby4vAOyenB9SqbZr7X XBGlxFKckWioxVxUnAgAQlNOvy4CAAA= X-CMS-MailID: 20180302085129eucas1p165d7e94517ca9c6fee534f53a88125a9 X-Msg-Generator: CA CMS-TYPE: 201P X-CMS-RootMailID: 20180302085129eucas1p165d7e94517ca9c6fee534f53a88125a9 X-RootMTR: 20180302085129eucas1p165d7e94517ca9c6fee534f53a88125a9 References: <1519980169-8491-1-git-send-email-m.purski@samsung.com> Sender: linux-kernel-owner@vger.kernel.org Precedence: bulk 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 | 101 +++++++++++++++++++++++++++++++++++++---------- 1 file changed, 81 insertions(+), 20 deletions(-) diff --git a/drivers/regulator/core.c b/drivers/regulator/core.c index b24a987..dedf737 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 @@ -2199,6 +2232,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; @@ -2208,9 +2246,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); @@ -2316,9 +2355,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); @@ -2367,10 +2407,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--) @@ -2929,8 +2970,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 @@ -2974,6 +3019,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) && @@ -2985,13 +3051,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; @@ -2999,7 +3065,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; @@ -3011,7 +3077,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; } } @@ -3021,7 +3087,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, @@ -3035,11 +3101,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) @@ -3254,12 +3315,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