Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

regulator: core: disable supply if enabling main regulator fails

For 'always-on' and 'boot-on' regulators, the set_machine_constraints()
may enable supply before enabling the main regulator, however if the
latter fails, the function returns with an error but the supply remains
enabled.

When this happens, the regulator_register() function continues on the
error path where it puts the supply regulator. Since enabling the supply
is not balanced with a disable call, a warning similar to the following
gets issued from _regulator_put():

[ 1.603889] WARNING: CPU: 2 PID: 44 at _regulator_put+0x8c/0xa0
[ 1.603908] Modules linked in:
[ 1.603926] CPU: 2 UID: 0 PID: 44 Comm: kworker/u16:3 Not tainted 6.18.0-rc4 #0 NONE
[ 1.603938] Hardware name: Qualcomm Technologies, Inc. IPQ9574/AP-AL02-C7 (DT)
[ 1.603945] Workqueue: async async_run_entry_fn
[ 1.603958] pstate: 60400005 (nZCv daif +PAN -UAO -TCO -DIT -SSBS BTYPE=--)
[ 1.603967] pc : _regulator_put+0x8c/0xa0
[ 1.603976] lr : _regulator_put+0x7c/0xa0
...
[ 1.604140] Call trace:
[ 1.604145] _regulator_put+0x8c/0xa0 (P)
[ 1.604156] regulator_register+0x2ec/0xbf0
[ 1.604166] devm_regulator_register+0x60/0xb0
[ 1.604178] rpm_reg_probe+0x120/0x208
[ 1.604187] platform_probe+0x64/0xa8
...

In order to avoid this, change the set_machine_constraints() function to
disable the supply if enabling the main regulator fails.

Fixes: 05f224ca6693 ("regulator: core: Clean enabling always-on regulators + their supplies")
Signed-off-by: Gabor Juhos <j4g8y7@gmail.com>
Link: https://patch.msgid.link/20251107-regulator-disable-supply-v1-1-c95f0536f1b5@gmail.com
Signed-off-by: Mark Brown <broonie@kernel.org>

authored by

Gabor Juhos and committed by
Mark Brown
fb1ebb10 2089f086

+5
+5
drivers/regulator/core.c
··· 1631 1631 * and we have control then make sure it is enabled. 1632 1632 */ 1633 1633 if (rdev->constraints->always_on || rdev->constraints->boot_on) { 1634 + bool supply_enabled = false; 1635 + 1634 1636 /* If we want to enable this regulator, make sure that we know 1635 1637 * the supplying regulator. 1636 1638 */ ··· 1652 1650 rdev->supply = NULL; 1653 1651 return ret; 1654 1652 } 1653 + supply_enabled = true; 1655 1654 } 1656 1655 1657 1656 ret = _regulator_do_enable(rdev); 1658 1657 if (ret < 0 && ret != -EINVAL) { 1659 1658 rdev_err(rdev, "failed to enable: %pe\n", ERR_PTR(ret)); 1659 + if (supply_enabled) 1660 + regulator_disable(rdev->supply); 1660 1661 return ret; 1661 1662 } 1662 1663