diff options
author | Rui Zhang <zr.zhang@vivo.com> | 2022-12-01 11:38:06 +0800 |
---|---|---|
committer | Mark Brown <broonie@kernel.org> | 2022-12-01 11:41:19 +0000 |
commit | 0591b14ce0398125439c759f889647369aa616a0 (patch) | |
tree | c62333a4f76f1b4555f0491dd08b41460c4da161 | |
parent | f39f8709c217d82aabbf51d8669731137ce09aea (diff) | |
download | linux-0591b14ce0398125439c759f889647369aa616a0.tar.gz linux-0591b14ce0398125439c759f889647369aa616a0.tar.bz2 linux-0591b14ce0398125439c759f889647369aa616a0.zip |
regulator: core: fix use_count leakage when handling boot-on
I found a use_count leakage towards supply regulator of rdev with
boot-on option.
┌───────────────────┐ ┌───────────────────┐
│ regulator_dev A │ │ regulator_dev B │
│ (boot-on) │ │ (boot-on) │
│ use_count=0 │◀──supply──│ use_count=1 │
│ │ │ │
└───────────────────┘ └───────────────────┘
In case of rdev(A) configured with `regulator-boot-on', the use_count
of supplying regulator(B) will increment inside
regulator_enable(rdev->supply).
Thus, B will acts like always-on, and further balanced
regulator_enable/disable cannot actually disable it anymore.
However, B was also configured with `regulator-boot-on', we wish it
could be disabled afterwards.
Signed-off-by: Rui Zhang <zr.zhang@vivo.com>
Link: https://lore.kernel.org/r/20221201033806.2567812-1-zr.zhang@vivo.com
Signed-off-by: Mark Brown <broonie@kernel.org>
-rw-r--r-- | drivers/regulator/core.c | 8 |
1 files changed, 7 insertions, 1 deletions
diff --git a/drivers/regulator/core.c b/drivers/regulator/core.c index 989b22249ca2..866401f3fb10 100644 --- a/drivers/regulator/core.c +++ b/drivers/regulator/core.c @@ -1596,7 +1596,13 @@ static int set_machine_constraints(struct regulator_dev *rdev) if (rdev->supply_name && !rdev->supply) return -EPROBE_DEFER; - if (rdev->supply) { + /* If supplying regulator has already been enabled, + * it's not intended to have use_count increment + * when rdev is only boot-on. + */ + if (rdev->supply && + (rdev->constraints->always_on || + !regulator_is_enabled(rdev->supply))) { ret = regulator_enable(rdev->supply); if (ret < 0) { _regulator_put(rdev->supply); |