Skip to content

Commit c1f615e

Browse files
committed
Merge series "Fix regulators coupling for Exynos5800" from Marek Szyprowski <[email protected]>:
Hi! This patchset is another attempt to fix the regulator coupling on Exynos5800/5422 SoCs. Here are links to the previous attempts: https://lore.kernel.org/linux-samsung-soc/20191008101709.qVNy8eijBi0LynOteWFMnTg4GUwKG599n6OyYoX1Abs@z/ https://lore.kernel.org/lkml/[email protected]/ https://lore.kernel.org/linux-pm/[email protected]/ https://lore.kernel.org/linux-pm/[email protected]/ The problem is with "vdd_int" regulator coupled with "vdd_arm" on Odroid XU3/XU4 boards family. "vdd_arm" is handled by CPUfreq. "vdd_int" is handled by devfreq. CPUfreq initialized quite early during boot and it starts changing OPPs and "vdd_arm" value. Sometimes CPU activity during boot goes down and some low-frequency OPPs are selected, what in turn causes lowering "vdd_arm". This happens before devfreq applies its requirements on "vdd_int". Regulator balancing code reduces "vdd_arm" voltage value, what in turn causes lowering "vdd_int" value to the lowest possible value. This is much below the operation point of the wcore bus, which still runs at the highest frequency. The issue was hard to notice because in the most cases the board managed to boot properly, even when the regulator was set to lowest value allowed by the regulator constraints. However, it caused some random issues, which can be observed as "Unhandled prefetch abort" or low USB stability. Adding more and more special cases to the generic code has been rejected, so the only way to ensure the desired behavior on Exynos5800-based SoCs is to make a custom regulator coupler driver. Best regards, Marek Szyprowski Patch summary: Marek Szyprowski (2): regulator: extract voltage balancing code to separate function soc: samsung: Add simple voltage coupler for Exynos5800 arch/arm/mach-exynos/Kconfig | 1 + drivers/regulator/core.c | 49 ++++++++------- drivers/soc/samsung/Kconfig | 3 + drivers/soc/samsung/Makefile | 1 + .../soc/samsung/exynos-regulator-coupler.c | 59 +++++++++++++++++++ include/linux/regulator/coupler.h | 8 +++ 6 files changed, 101 insertions(+), 20 deletions(-) create mode 100644 drivers/soc/samsung/exynos-regulator-coupler.c -- 2.17.1 base-commit: 8f3d9f3
2 parents 0c680ff + 752db83 commit c1f615e

File tree

2 files changed

+37
-20
lines changed

2 files changed

+37
-20
lines changed

drivers/regulator/core.c

Lines changed: 29 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -3642,36 +3642,19 @@ static int regulator_get_optimal_voltage(struct regulator_dev *rdev,
36423642
return done;
36433643
}
36443644

3645-
static int regulator_balance_voltage(struct regulator_dev *rdev,
3646-
suspend_state_t state)
3645+
int regulator_do_balance_voltage(struct regulator_dev *rdev,
3646+
suspend_state_t state, bool skip_coupled)
36473647
{
36483648
struct regulator_dev **c_rdevs;
36493649
struct regulator_dev *best_rdev;
36503650
struct coupling_desc *c_desc = &rdev->coupling_desc;
3651-
struct regulator_coupler *coupler = c_desc->coupler;
36523651
int i, ret, n_coupled, best_min_uV, best_max_uV, best_c_rdev;
36533652
unsigned int delta, best_delta;
36543653
unsigned long c_rdev_done = 0;
36553654
bool best_c_rdev_done;
36563655

36573656
c_rdevs = c_desc->coupled_rdevs;
3658-
n_coupled = c_desc->n_coupled;
3659-
3660-
/*
3661-
* If system is in a state other than PM_SUSPEND_ON, don't check
3662-
* other coupled regulators.
3663-
*/
3664-
if (state != PM_SUSPEND_ON)
3665-
n_coupled = 1;
3666-
3667-
if (c_desc->n_resolved < n_coupled) {
3668-
rdev_err(rdev, "Not all coupled regulators registered\n");
3669-
return -EPERM;
3670-
}
3671-
3672-
/* Invoke custom balancer for customized couplers */
3673-
if (coupler && coupler->balance_voltage)
3674-
return coupler->balance_voltage(coupler, rdev, state);
3657+
n_coupled = skip_coupled ? 1 : c_desc->n_coupled;
36753658

36763659
/*
36773660
* Find the best possible voltage change on each loop. Leave the loop
@@ -3742,6 +3725,32 @@ static int regulator_balance_voltage(struct regulator_dev *rdev,
37423725
return ret;
37433726
}
37443727

3728+
static int regulator_balance_voltage(struct regulator_dev *rdev,
3729+
suspend_state_t state)
3730+
{
3731+
struct coupling_desc *c_desc = &rdev->coupling_desc;
3732+
struct regulator_coupler *coupler = c_desc->coupler;
3733+
bool skip_coupled = false;
3734+
3735+
/*
3736+
* If system is in a state other than PM_SUSPEND_ON, don't check
3737+
* other coupled regulators.
3738+
*/
3739+
if (state != PM_SUSPEND_ON)
3740+
skip_coupled = true;
3741+
3742+
if (c_desc->n_resolved < c_desc->n_coupled) {
3743+
rdev_err(rdev, "Not all coupled regulators registered\n");
3744+
return -EPERM;
3745+
}
3746+
3747+
/* Invoke custom balancer for customized couplers */
3748+
if (coupler && coupler->balance_voltage)
3749+
return coupler->balance_voltage(coupler, rdev, state);
3750+
3751+
return regulator_do_balance_voltage(rdev, state, skip_coupled);
3752+
}
3753+
37453754
/**
37463755
* regulator_set_voltage - set regulator output voltage
37473756
* @regulator: regulator source

include/linux/regulator/coupler.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,8 @@ int regulator_get_voltage_rdev(struct regulator_dev *rdev);
6262
int regulator_set_voltage_rdev(struct regulator_dev *rdev,
6363
int min_uV, int max_uV,
6464
suspend_state_t state);
65+
int regulator_do_balance_voltage(struct regulator_dev *rdev,
66+
suspend_state_t state, bool skip_coupled);
6567
#else
6668
static inline int regulator_coupler_register(struct regulator_coupler *coupler)
6769
{
@@ -92,6 +94,12 @@ static inline int regulator_set_voltage_rdev(struct regulator_dev *rdev,
9294
{
9395
return -EINVAL;
9496
}
97+
static inline int regulator_do_balance_voltage(struct regulator_dev *rdev,
98+
suspend_state_t state,
99+
bool skip_coupled)
100+
{
101+
return -EINVAL;
102+
}
95103
#endif
96104

97105
#endif

0 commit comments

Comments
 (0)