* [PATCH v4 0/4] regulator: qcom-rpmh: Add support for off-on-delay and debounce-delay
@ 2026-10-01 12:46 Jishnu Prakash
2026-10-01 12:46 ` [PATCH v4 1/4] regulator: dt-bindings: Add 'regulator-off-on-delay-us' property Jishnu Prakash
` (3 more replies)
0 siblings, 4 replies; 9+ messages in thread
From: Jishnu Prakash @ 2026-10-01 12:46 UTC (permalink / raw)
To: Liam Girdwood, Mark Brown, Rob Herring, Krzysztof Kozlowski,
Conor Dooley
Cc: linux-kernel, devicetree, linux-arm-msm, Manivannan Sadhasivam,
Kamal Wadhwa, Saikiran, Jishnu Prakash
This series adds support for two related delay properties for the Qualcomm
RPMh regulator driver: `regulator-off-on-delay-us` (enforces a minimum
physical off-time before re-enable) and `qcom,regulator-off-debounce-delay-us`
(defers sending a disable request to RPMh so quick disable/enable bounces
never reach the hardware).
Motivation:
On the Lenovo Yoga Slim 7x (Snapdragon X Elite), the camera regulators
(LDO1, LDO3, LDO7) have large bulk capacitors and rely on passive discharge.
When these regulators are disabled, the voltage decays very slowly. If
re-enabled too quickly, the sensor experiences a brownout and fails to
initialize. This can be prevented by specifying a minimum off-time.
Separately, some consumers rapidly toggle a regulator off and on again,
for example, a driver that disables its supply on -EPROBE_DEFER and
re-enables it on the next probe attempt. Sending the disable vote to RPMh
immediately in this case causes needless power cycling, so
qcom,regulator-off-debounce-delay-us lets this be deferred and canceled
if a quick re-enable follows.
Signed-off-by: Jishnu Prakash <jishnu.prakash@oss.qualcomm.com>
---
Changes in v4:
- Taking over upstreaming this series from Saikiran.
- Made the binding change for `regulator-off-on-delay-us` in
Documentation/devicetree/bindings/regulator/regulator.yaml instead of
Documentation/devicetree/bindings/regulator/qcom,rpmh-regulator.yaml,
as this property seems better suited to be a generic one.
- Added new `qcom,regulator-off-debounce-delay-us` property and driver
support for deferring the RPMh disable request to implement Mark's
suggestion.
- Rebased to Linux 7.3-rc5.
- Link to v3: https://patch.msgid.link/20260127190211.14312-1-bjsaikiran@gmail.com
Changes in v3:
- Added Patch 1/2: Update DT bindings to allow `regulator-off-on-delay-us`
for `qcom,rpmh-regulator` (Requested by Mark Brown).
- Updated Patch 2/2: Refined commit message to explicitly mention the
passive discharge and bulk capacitor mechanism on the Yoga Slim 7x
(Requested by Mark Brown).
Changes in v2:
- Moved the motivation/context from the cover letter into the commit
message of the driver patch.
---
Jishnu Prakash (3):
regulator: dt-bindings: Add 'regulator-off-on-delay-us' property
regulator: dt-bindings: qcom,rpmh-regulator: Add debounce delay property
regulator: qcom-rpmh: Add debounce delay before disabling regulator
Saikiran (1):
regulator: qcom-rpmh: Add support for regulator-off-on-delay-us
.../bindings/regulator/qcom,rpmh-regulator.yaml | 18 ++++
.../devicetree/bindings/regulator/regulator.yaml | 5 +
drivers/regulator/qcom-rpmh-regulator.c | 113 ++++++++++++++++++++-
3 files changed, 132 insertions(+), 4 deletions(-)
---
base-commit: 72d3fcf802c45d00b300f25b848a93c3a2bd7c7e
change-id: 20260910-regulator-off-on-delay-2c86cb8f3eb8
Best regards,
--
Jishnu Prakash <jishnu.prakash@oss.qualcomm.com>
^ permalink raw reply [flat|nested] 9+ messages in thread
* [PATCH v4 1/4] regulator: dt-bindings: Add 'regulator-off-on-delay-us' property
2026-10-01 12:46 [PATCH v4 0/4] regulator: qcom-rpmh: Add support for off-on-delay and debounce-delay Jishnu Prakash
@ 2026-10-01 12:46 ` Jishnu Prakash
2026-10-07 20:36 ` Rob Herring (Arm)
2026-10-01 12:46 ` [PATCH v4 2/4] regulator: qcom-rpmh: Add support for regulator-off-on-delay-us Jishnu Prakash
` (2 subsequent siblings)
3 siblings, 1 reply; 9+ messages in thread
From: Jishnu Prakash @ 2026-10-01 12:46 UTC (permalink / raw)
To: Liam Girdwood, Mark Brown, Rob Herring, Krzysztof Kozlowski,
Conor Dooley
Cc: linux-kernel, devicetree, linux-arm-msm, Manivannan Sadhasivam,
Kamal Wadhwa, Saikiran, Jishnu Prakash
Add a new property 'regulator-off-on-delay-us' to specify a minimum delay
between disabling and re-enabling a regulator. This is useful in cases
where a regulator discharges slowly and needs significant time to reach a
safe reset level, and re-enabling it too early may lead to a brownout
event.
Suggested-by: Saikiran <bjsaikiran@gmail.com>
Signed-off-by: Jishnu Prakash <jishnu.prakash@oss.qualcomm.com>
---
Documentation/devicetree/bindings/regulator/regulator.yaml | 5 +++++
1 file changed, 5 insertions(+)
diff --git a/Documentation/devicetree/bindings/regulator/regulator.yaml b/Documentation/devicetree/bindings/regulator/regulator.yaml
index 019aeb664cae..73e1bea87adb 100644
--- a/Documentation/devicetree/bindings/regulator/regulator.yaml
+++ b/Documentation/devicetree/bindings/regulator/regulator.yaml
@@ -243,6 +243,11 @@ properties:
description: Maximum difference between current and target voltages
that can be changed safely in a single step.
+ regulator-off-on-delay-us:
+ description: Specifies a minimum delay in microseconds between disabling and
+ re-enabling the regulator. This is needed for regulators that discharge
+ slowly and require a significant delay to drop below brownout thresholds.
+
patternProperties:
".*-supply$":
description: Input supply phandle(s) for this node
--
2.43.0
^ permalink raw reply related [flat|nested] 9+ messages in thread
* [PATCH v4 2/4] regulator: qcom-rpmh: Add support for regulator-off-on-delay-us
2026-10-01 12:46 [PATCH v4 0/4] regulator: qcom-rpmh: Add support for off-on-delay and debounce-delay Jishnu Prakash
2026-10-01 12:46 ` [PATCH v4 1/4] regulator: dt-bindings: Add 'regulator-off-on-delay-us' property Jishnu Prakash
@ 2026-10-01 12:46 ` Jishnu Prakash
2026-10-07 16:12 ` Mark Brown
2026-10-01 12:46 ` [PATCH v4 3/4] regulator: dt-bindings: qcom,rpmh-regulator: Add debounce delay property Jishnu Prakash
2026-10-01 12:46 ` [PATCH v4 4/4] regulator: qcom-rpmh: Add debounce delay before disabling regulator Jishnu Prakash
3 siblings, 1 reply; 9+ messages in thread
From: Jishnu Prakash @ 2026-10-01 12:46 UTC (permalink / raw)
To: Liam Girdwood, Mark Brown, Rob Herring, Krzysztof Kozlowski,
Conor Dooley
Cc: linux-kernel, devicetree, linux-arm-msm, Manivannan Sadhasivam,
Kamal Wadhwa, Saikiran, Jishnu Prakash
From: Saikiran <bjsaikiran@gmail.com>
The core regulator framework supports enforcing a physical off-time via
standard properties, but the `qcom-rpmh-regulator` driver currently
ignores them.
The issue is platform-specific: The Lenovo Yoga Slim 7x (Snapdragon X
Elite) has large bulk capacitors on the camera rails (LDO1, LDO3, LDO7).
When these regulators are disabled, the voltage decays very slowly
(passive discharge).
If the rail is re-enabled before this discharge completes, the sensor
experiences a brownout and fails to initialize.
Add support for parsing the 'regulator-off-on-delay-us' property from
the device tree to enforce this physical constraint.
Signed-off-by: Saikiran <bjsaikiran@gmail.com>
Signed-off-by: Jishnu Prakash <jishnu.prakash@oss.qualcomm.com>
---
drivers/regulator/qcom-rpmh-regulator.c | 3 +++
1 file changed, 3 insertions(+)
diff --git a/drivers/regulator/qcom-rpmh-regulator.c b/drivers/regulator/qcom-rpmh-regulator.c
index 25c14de3cd8b..4773034b5d42 100644
--- a/drivers/regulator/qcom-rpmh-regulator.c
+++ b/drivers/regulator/qcom-rpmh-regulator.c
@@ -552,6 +552,9 @@ static int rpmh_regulator_init_vreg(struct rpmh_vreg *vreg, struct device *dev,
vreg->always_wait_for_ack = of_property_read_bool(node,
"qcom,always-wait-for-ack");
+ of_property_read_u32(node, "regulator-off-on-delay-us",
+ &vreg->rdesc.off_on_delay);
+
vreg->rdesc.owner = THIS_MODULE;
vreg->rdesc.type = REGULATOR_VOLTAGE;
vreg->rdesc.ops = vreg->hw_data->ops;
--
2.43.0
^ permalink raw reply related [flat|nested] 9+ messages in thread
* [PATCH v4 3/4] regulator: dt-bindings: qcom,rpmh-regulator: Add debounce delay property
2026-10-01 12:46 [PATCH v4 0/4] regulator: qcom-rpmh: Add support for off-on-delay and debounce-delay Jishnu Prakash
2026-10-01 12:46 ` [PATCH v4 1/4] regulator: dt-bindings: Add 'regulator-off-on-delay-us' property Jishnu Prakash
2026-10-01 12:46 ` [PATCH v4 2/4] regulator: qcom-rpmh: Add support for regulator-off-on-delay-us Jishnu Prakash
@ 2026-10-01 12:46 ` Jishnu Prakash
2026-10-07 20:37 ` Rob Herring (Arm)
2026-10-01 12:46 ` [PATCH v4 4/4] regulator: qcom-rpmh: Add debounce delay before disabling regulator Jishnu Prakash
3 siblings, 1 reply; 9+ messages in thread
From: Jishnu Prakash @ 2026-10-01 12:46 UTC (permalink / raw)
To: Liam Girdwood, Mark Brown, Rob Herring, Krzysztof Kozlowski,
Conor Dooley
Cc: linux-kernel, devicetree, linux-arm-msm, Manivannan Sadhasivam,
Kamal Wadhwa, Saikiran, Jishnu Prakash
Add 'qcom,regulator-off-debounce-delay-us' to describe the time to wait
for an enable vote after a disable vote, before actually sending the
disable request to RPMh.
Some consumers toggle a regulator off and back on in quick succession
as part of their normal operation, a behavior this driver has no
control over. The appropriate debounce window to absorb this varies by
which consumer(s) are wired to a given rail and how they use it, so it
is exposed as a per-regulator property rather than a fixed value.
It is placed in the qcom,rpmh-regulator binding and vendor-prefixed
because the underlying deferred-disable mechanism is specific to this
driver's RPMh command handling.
Assisted-by: Claude:claude-sonnet-5
Signed-off-by: Jishnu Prakash <jishnu.prakash@oss.qualcomm.com>
---
.../bindings/regulator/qcom,rpmh-regulator.yaml | 18 ++++++++++++++++++
1 file changed, 18 insertions(+)
diff --git a/Documentation/devicetree/bindings/regulator/qcom,rpmh-regulator.yaml b/Documentation/devicetree/bindings/regulator/qcom,rpmh-regulator.yaml
index eed2ce7fa861..a028f1a9c194 100644
--- a/Documentation/devicetree/bindings/regulator/qcom,rpmh-regulator.yaml
+++ b/Documentation/devicetree/bindings/regulator/qcom,rpmh-regulator.yaml
@@ -135,6 +135,15 @@ properties:
$ref: regulator.yaml#
unevaluatedProperties: false
description: BOB regulator node.
+ properties:
+ qcom,regulator-off-debounce-delay-us:
+ description:
+ Time in microseconds to wait for an enable vote after a disable
+ vote, before actually disabling the regulator in hardware. This is
+ needed for consumers that may toggle a regulator off and back on
+ in quick succession as part of their normal operation, a behavior
+ this driver has no control over, so as to avoid needlessly
+ power-cycling the regulator in hardware.
dependencies:
regulator-allow-set-load: [ regulator-allowed-modes ]
@@ -144,6 +153,15 @@ patternProperties:
$ref: regulator.yaml#
unevaluatedProperties: false
description: smps/ldo regulator nodes(s).
+ properties:
+ qcom,regulator-off-debounce-delay-us:
+ description:
+ Time in microseconds to wait for an enable vote after a disable
+ vote, before actually disabling the regulator in hardware. This is
+ needed for consumers that may toggle a regulator off and back on
+ in quick succession as part of their normal operation, a behavior
+ this driver has no control over, so as to avoid needlessly
+ power-cycling the regulator in hardware.
dependencies:
regulator-allow-set-load: [ regulator-allowed-modes ]
--
2.43.0
^ permalink raw reply related [flat|nested] 9+ messages in thread
* [PATCH v4 4/4] regulator: qcom-rpmh: Add debounce delay before disabling regulator
2026-10-01 12:46 [PATCH v4 0/4] regulator: qcom-rpmh: Add support for off-on-delay and debounce-delay Jishnu Prakash
` (2 preceding siblings ...)
2026-10-01 12:46 ` [PATCH v4 3/4] regulator: dt-bindings: qcom,rpmh-regulator: Add debounce delay property Jishnu Prakash
@ 2026-10-01 12:46 ` Jishnu Prakash
2026-10-01 13:05 ` sashiko-bot
3 siblings, 1 reply; 9+ messages in thread
From: Jishnu Prakash @ 2026-10-01 12:46 UTC (permalink / raw)
To: Liam Girdwood, Mark Brown, Rob Herring, Krzysztof Kozlowski,
Conor Dooley
Cc: linux-kernel, devicetree, linux-arm-msm, Manivannan Sadhasivam,
Kamal Wadhwa, Saikiran, Jishnu Prakash
Some consumers rapidly toggle a regulator off and back on again, for
example a driver that disables its supply on -EPROBE_DEFER and
re-enables it on the next probe attempt. Sending the disable request
to RPMh immediately in this case causes needless power cycling of the
rail, and in some cases the driver instead avoids calling
regulator_disable() altogether to sidestep this, at the cost of
leaving the regulator enabled and triggering the core's
"unbalanced disables" and late-cleanup warnings.
Add support for a new 'qcom,regulator-off-debounce-delay-us' property.
When set, a disable vote is not sent to RPMh immediately; instead a
cancelable delayed work item is queued to send it after the configured
delay. If an enable vote arrives before the delay expires, the pending
work is canceled and the rail is left untouched, avoiding the
unnecessary disable/enable bounce. If no enable vote arrives, the
disable request is sent once the delay elapses.
This complements the existing 'regulator-off-on-delay-us' handling:
that property enforces a minimum time the rail must stay physically
off before it can be safely re-enabled (a hardware discharge/POR
constraint), whereas this new delay defers sending the disable request
in the first place, absorbing quick bounces before they ever reach the
hardware. The two have no dependency on each other and can be used
together.
The deferred disable work item can run after the regulator has been
registered, so cache the regulator_dev pointer in struct rpmh_vreg and
thread it explicitly through _rpmh_regulator_set_enable_state() rather
than relying on the regulator_dev argument that was previously only
available at the regulator core's enable()/disable() call sites.
Assisted-by: Claude:claude-sonnet-5
Signed-off-by: Jishnu Prakash <jishnu.prakash@oss.qualcomm.com>
---
drivers/regulator/qcom-rpmh-regulator.c | 114 ++++++++++++++++++++++++++++++--
1 file changed, 108 insertions(+), 6 deletions(-)
diff --git a/drivers/regulator/qcom-rpmh-regulator.c b/drivers/regulator/qcom-rpmh-regulator.c
index 4773034b5d42..4568abf52dd3 100644
--- a/drivers/regulator/qcom-rpmh-regulator.c
+++ b/drivers/regulator/qcom-rpmh-regulator.c
@@ -5,8 +5,10 @@
#define pr_fmt(fmt) "%s: " fmt, __func__
#include <linux/bits.h>
+#include <linux/delay.h>
#include <linux/err.h>
#include <linux/kernel.h>
+#include <linux/ktime.h>
#include <linux/module.h>
#include <linux/of.h>
#include <linux/platform_device.h>
@@ -15,6 +17,7 @@
#include <linux/regulator/driver.h>
#include <linux/regulator/machine.h>
#include <linux/regulator/of_regulator.h>
+#include <linux/workqueue.h>
#include <soc/qcom/cmd-db.h>
#include <soc/qcom/rpmh.h>
@@ -160,6 +163,27 @@ struct rpmh_vreg_hw_data {
* @voltage_selector: Selector used for get_voltage_sel() and
* set_voltage_sel() callbacks
* @mode: RPMh VRM regulator current framework mode
+ * @rdev: Regulator device pointer registered for this
+ * regulator
+ * @delayed_off_work: Delayed worker used to defer sending a disable
+ * request to RPMh, so that a quick subsequent
+ * enable vote can cancel it instead of causing a
+ * disable/enable bounce on the rail
+ * @debounce_delay: Time in microseconds to wait for an enable vote
+ * after a disable vote, before actually sending
+ * the disable request to RPMh
+ * @off_on_delay: Minimum time in microseconds to wait after the
+ * disable request for this regulator has actually
+ * been sent to RPMh, before allowing it to be
+ * enabled again. This is tracked locally instead
+ * of via rdesc.off_on_delay whenever
+ * debounce_delay is configured so that it can be
+ * measured from the real disable time instead of
+ * from the time the debounced disable request was
+ * merely queued.
+ * @last_off: Time at which the disable request for this
+ * regulator was last actually sent to RPMh. Only
+ * used when debounce_delay is configured.
*/
struct rpmh_vreg {
struct device *dev;
@@ -172,6 +196,11 @@ struct rpmh_vreg {
bool bypassed;
int voltage_selector;
unsigned int mode;
+ struct regulator_dev *rdev;
+ struct delayed_work delayed_off_work;
+ unsigned int debounce_delay;
+ unsigned int off_on_delay;
+ ktime_t last_off;
};
/**
@@ -293,10 +322,9 @@ static int rpmh_regulator_is_enabled(struct regulator_dev *rdev)
return vreg->enabled;
}
-static int rpmh_regulator_set_enable_state(struct regulator_dev *rdev,
- bool enable)
+static int _rpmh_regulator_set_enable_state(struct rpmh_vreg *vreg,
+ struct regulator_dev *rdev, bool enable)
{
- struct rpmh_vreg *vreg = rdev_get_drvdata(rdev);
struct tcs_cmd cmd = {
.addr = vreg->addr + RPMH_REGULATOR_REG_ENABLE,
.data = enable,
@@ -306,7 +334,8 @@ static int rpmh_regulator_set_enable_state(struct regulator_dev *rdev,
if (vreg->enabled == -EINVAL &&
vreg->voltage_selector != -ENOTRECOVERABLE) {
ret = _rpmh_regulator_vrm_set_voltage_sel(rdev,
- vreg->voltage_selector, true);
+ vreg->voltage_selector,
+ true);
if (ret < 0)
return ret;
}
@@ -318,13 +347,54 @@ static int rpmh_regulator_set_enable_state(struct regulator_dev *rdev,
return ret;
}
+static int rpmh_regulator_set_enable_state(struct regulator_dev *rdev,
+ bool enable)
+{
+ struct rpmh_vreg *vreg = rdev_get_drvdata(rdev);
+
+ return _rpmh_regulator_set_enable_state(vreg, rdev, enable);
+}
+
+static void rpmh_delayed_off_work(struct work_struct *work)
+{
+ struct rpmh_vreg *vreg = container_of(work,
+ struct rpmh_vreg, delayed_off_work.work);
+
+ if (!_rpmh_regulator_set_enable_state(vreg, vreg->rdev, false))
+ vreg->last_off = ktime_get_boottime();
+}
+
static int rpmh_regulator_enable(struct regulator_dev *rdev)
{
+ struct rpmh_vreg *vreg = rdev_get_drvdata(rdev);
+ s64 remaining;
+
+ if (vreg->debounce_delay) {
+ if (cancel_delayed_work_sync(&vreg->delayed_off_work))
+ return 0;
+
+ if (vreg->off_on_delay) {
+ remaining = ktime_us_delta(ktime_add_us(vreg->last_off,
+ vreg->off_on_delay),
+ ktime_get_boottime());
+ if (remaining > 0)
+ fsleep(remaining);
+ }
+ }
+
return rpmh_regulator_set_enable_state(rdev, true);
}
static int rpmh_regulator_disable(struct regulator_dev *rdev)
{
+ struct rpmh_vreg *vreg = rdev_get_drvdata(rdev);
+
+ if (vreg->debounce_delay) {
+ queue_delayed_work(system_percpu_wq, &vreg->delayed_off_work,
+ usecs_to_jiffies(vreg->debounce_delay));
+ return 0;
+ }
+
return rpmh_regulator_set_enable_state(rdev, false);
}
@@ -481,6 +551,13 @@ static const struct regulator_ops rpmh_regulator_xob_ops = {
.is_enabled = rpmh_regulator_is_enabled,
};
+static void rpmh_regulator_cancel_delayed_off_work(void *data)
+{
+ struct rpmh_vreg *vreg = data;
+
+ cancel_delayed_work_sync(&vreg->delayed_off_work);
+}
+
/**
* rpmh_regulator_init_vreg() - initialize all attributes of an rpmh-regulator
* @vreg: Pointer to the individual rpmh-regulator resource
@@ -504,6 +581,7 @@ static int rpmh_regulator_init_vreg(struct rpmh_vreg *vreg, struct device *dev,
const struct rpmh_vreg_init_data *rpmh_data;
struct regulator_init_data *init_data;
struct regulator_dev *rdev;
+ u32 off_on_delay = 0;
int ret;
vreg->dev = dev;
@@ -552,8 +630,24 @@ static int rpmh_regulator_init_vreg(struct rpmh_vreg *vreg, struct device *dev,
vreg->always_wait_for_ack = of_property_read_bool(node,
"qcom,always-wait-for-ack");
- of_property_read_u32(node, "regulator-off-on-delay-us",
- &vreg->rdesc.off_on_delay);
+ of_property_read_u32(node, "regulator-off-on-delay-us", &off_on_delay);
+
+ of_property_read_u32(node, "qcom,regulator-off-debounce-delay-us",
+ &vreg->debounce_delay);
+
+ if (vreg->debounce_delay) {
+ /*
+ * The disable request to RPMh is deferred until the debounce
+ * delay elapses, so off_on_delay must be measured from that
+ * point rather than from when disable() returns. Enforce it
+ * locally instead of delegating to the regulator core.
+ */
+ vreg->off_on_delay = off_on_delay;
+
+ INIT_DELAYED_WORK(&vreg->delayed_off_work, rpmh_delayed_off_work);
+ } else {
+ vreg->rdesc.off_on_delay = off_on_delay;
+ }
vreg->rdesc.owner = THIS_MODULE;
vreg->rdesc.type = REGULATOR_VOLTAGE;
@@ -583,6 +677,14 @@ static int rpmh_regulator_init_vreg(struct rpmh_vreg *vreg, struct device *dev,
node, ret);
return ret;
}
+ vreg->rdev = rdev;
+
+ if (vreg->debounce_delay) {
+ ret = devm_add_action_or_reset(dev, rpmh_regulator_cancel_delayed_off_work,
+ vreg);
+ if (ret)
+ return ret;
+ }
dev_dbg(dev, "%pOFn regulator registered for RPMh resource %s @ 0x%05X\n",
node, rpmh_resource_name, vreg->addr);
--
2.43.0
^ permalink raw reply related [flat|nested] 9+ messages in thread
* Re: [PATCH v4 4/4] regulator: qcom-rpmh: Add debounce delay before disabling regulator
2026-10-01 12:46 ` [PATCH v4 4/4] regulator: qcom-rpmh: Add debounce delay before disabling regulator Jishnu Prakash
@ 2026-10-01 13:05 ` sashiko-bot
0 siblings, 0 replies; 9+ messages in thread
From: sashiko-bot @ 2026-10-01 13:05 UTC (permalink / raw)
To: Jishnu Prakash; +Cc: robh, conor+dt, devicetree
Thank you for your contribution! Sashiko AI review found 4 potential issue(s) to consider:
- [High] regulator: qcom-rpmh: Use-After-Free due to devres LIFO ordering
- [High] regulator: qcom-rpmh: Data race in worker thread bypassing regulator_lock
- [High] regulator: qcom-rpmh: NULL pointer dereference if delayed disable fires before init completes
- [Medium] regulator: qcom-rpmh: State desynchronization on driver removal drops pending disable
--
commit b0211424f1ad79c3af4f67d5c03d4546a1bd442e
Author: Jishnu Prakash <jishnu.prakash@oss.qualcomm.com>
regulator: qcom-rpmh: Add debounce delay before disabling regulator
This commit adds a debounce delay to the Qualcomm RPMh regulator driver to
prevent rapid disable/enable cycles. It introduces a delayed work item that
defers sending disable requests to the hardware. A devres action is also
added to cancel the delayed work upon driver removal.
> diff --git a/drivers/regulator/qcom-rpmh-regulator.c b/drivers/regulator/qcom-rpmh-regulator.c
> --- a/drivers/regulator/qcom-rpmh-regulator.c
> +++ b/drivers/regulator/qcom-rpmh-regulator.c
[ ... ]
> @@ -347 +347,54 @@ static int rpmh_regulator_set_enable_state(struct regulator_dev *rdev,
> return ret;
> }
>
> +static void rpmh_delayed_off_work(struct work_struct *work)
> +{
> + struct rpmh_vreg *vreg = container_of(work,
> + struct rpmh_vreg, delayed_off_work.work);
> +
> + if (!_rpmh_regulator_set_enable_state(vreg, vreg->rdev, false))
[Severity: High]
Does this worker thread modify the hardware state without holding the
regulator core lock?
The core consumer APIs execute under the regulator_lock. Running
_rpmh_regulator_set_enable_state() here asynchronously might cause a data
race on shared structures like vreg->enabled and vreg->voltage_selector if a
consumer calls regulator_set_voltage() concurrently.
> + vreg->last_off = ktime_get_boottime();
> +}
[ ... ]
> static int rpmh_regulator_disable(struct regulator_dev *rdev)
> {
> + struct rpmh_vreg *vreg = rdev_get_drvdata(rdev);
> +
> + if (vreg->debounce_delay) {
> + queue_delayed_work(system_percpu_wq, &vreg->delayed_off_work,
> + usecs_to_jiffies(vreg->debounce_delay));
> + return 0;
> + }
[Severity: High]
Can this lead to a use-after-free during driver teardown?
When the driver unbinds, devres destroys resources in LIFO order.
The custom devres action rpmh_regulator_cancel_delayed_off_work runs first,
canceling the delayed work. Then devm_regulator_release() runs, which calls
regulator_unregister().
If regulator_unregister() flushes pending core disables, it invokes
rpmh_regulator_disable() which re-queues the delayed work here. After devres
finishes freeing vreg, the newly queued work would execute and dereference
the freed memory.
> +
> return rpmh_regulator_set_enable_state(rdev, false);
> }
[ ... ]
> @@ -551 +551,13 @@ static const struct regulator_ops rpmh_regulator_xob_ops = {
> .is_enabled = rpmh_regulator_is_enabled,
> };
>
> +static void rpmh_regulator_cancel_delayed_off_work(void *data)
> +{
> + struct rpmh_vreg *vreg = data;
> +
> + cancel_delayed_work_sync(&vreg->delayed_off_work);
> +}
[Severity: Medium]
Does cancelling the work here without syncing the hardware state leave the
regulator permanently enabled if a disable request was pending?
The regulator core would consider it disabled, leading to leaked power and
incorrect hardware state.
> +
> /**
> * rpmh_regulator_init_vreg() - initialize all attributes of an rpmh-regulator
[ ... ]
> @@ -677 +677,14 @@ static int rpmh_regulator_init_vreg(struct rpmh_vreg *vreg, struct device *dev,
> node, ret);
> return ret;
> }
> + vreg->rdev = rdev;
[Severity: High]
Could vreg->rdev be NULL if the delayed disable worker fires too early?
The regulator is exposed to consumers as soon as devm_regulator_register()
returns. If a fast consumer probes, sets a voltage, and immediately disables
the regulator before vreg->rdev is assigned here, the delayed off worker
might execute with vreg->rdev set to NULL.
This would cause a NULL pointer dereference when
_rpmh_regulator_set_enable_state() attempts to set the voltage and passes
the NULL rdev to rdev_get_drvdata().
> +
> + if (vreg->debounce_delay) {
> + ret = devm_add_action_or_reset(dev, rpmh_regulator_cancel_delayed_off_work,
> + vreg);
> + if (ret)
> + return ret;
> + }
>
> dev_dbg(dev, "%pOFn regulator registered for RPMh resource %s @ 0x%05X\n",
> node, rpmh_resource_name, vreg->addr);
--
Sashiko AI review · https://sashiko.dev/#/patchset/20261001-regulator-off-on-delay-v4-0-258ba9612da8@oss.qualcomm.com?part=4
^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: [PATCH v4 2/4] regulator: qcom-rpmh: Add support for regulator-off-on-delay-us
2026-10-01 12:46 ` [PATCH v4 2/4] regulator: qcom-rpmh: Add support for regulator-off-on-delay-us Jishnu Prakash
@ 2026-10-07 16:12 ` Mark Brown
0 siblings, 0 replies; 9+ messages in thread
From: Mark Brown @ 2026-10-07 16:12 UTC (permalink / raw)
To: Jishnu Prakash
Cc: Liam Girdwood, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
linux-kernel, devicetree, linux-arm-msm, Manivannan Sadhasivam,
Kamal Wadhwa, Saikiran
[-- Attachment #1: Type: text/plain, Size: 519 bytes --]
On Thu, Oct 01, 2026 at 06:16:29PM +0530, Jishnu Prakash wrote:
> Add support for parsing the 'regulator-off-on-delay-us' property from
> the device tree to enforce this physical constraint.
>
> Signed-off-by: Saikiran <bjsaikiran@gmail.com>
> Signed-off-by: Jishnu Prakash <jishnu.prakash@oss.qualcomm.com>
> ---
> drivers/regulator/qcom-rpmh-regulator.c | 3 +++
Since this is a generic property I would expect it to be parsed by the
regulator core, is there some reason for making it driver specific?
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 488 bytes --]
^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: [PATCH v4 1/4] regulator: dt-bindings: Add 'regulator-off-on-delay-us' property
2026-10-01 12:46 ` [PATCH v4 1/4] regulator: dt-bindings: Add 'regulator-off-on-delay-us' property Jishnu Prakash
@ 2026-10-07 20:36 ` Rob Herring (Arm)
0 siblings, 0 replies; 9+ messages in thread
From: Rob Herring (Arm) @ 2026-10-07 20:36 UTC (permalink / raw)
To: Jishnu Prakash
Cc: Mark Brown, Manivannan Sadhasivam, linux-kernel, devicetree,
Kamal Wadhwa, Saikiran, Liam Girdwood, linux-arm-msm,
Conor Dooley, Krzysztof Kozlowski
On Thu, 01 Oct 2026 18:16:28 +0530, Jishnu Prakash wrote:
> Add a new property 'regulator-off-on-delay-us' to specify a minimum delay
> between disabling and re-enabling a regulator. This is useful in cases
> where a regulator discharges slowly and needs significant time to reach a
> safe reset level, and re-enabling it too early may lead to a brownout
> event.
>
> Suggested-by: Saikiran <bjsaikiran@gmail.com>
> Signed-off-by: Jishnu Prakash <jishnu.prakash@oss.qualcomm.com>
> ---
> Documentation/devicetree/bindings/regulator/regulator.yaml | 5 +++++
> 1 file changed, 5 insertions(+)
>
Reviewed-by: Rob Herring (Arm) <robh@kernel.org>
^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: [PATCH v4 3/4] regulator: dt-bindings: qcom,rpmh-regulator: Add debounce delay property
2026-10-01 12:46 ` [PATCH v4 3/4] regulator: dt-bindings: qcom,rpmh-regulator: Add debounce delay property Jishnu Prakash
@ 2026-10-07 20:37 ` Rob Herring (Arm)
0 siblings, 0 replies; 9+ messages in thread
From: Rob Herring (Arm) @ 2026-10-07 20:37 UTC (permalink / raw)
To: Jishnu Prakash
Cc: Kamal Wadhwa, linux-kernel, Conor Dooley, Saikiran, devicetree,
Manivannan Sadhasivam, Liam Girdwood, Krzysztof Kozlowski,
linux-arm-msm, Mark Brown
On Thu, 01 Oct 2026 18:16:30 +0530, Jishnu Prakash wrote:
> Add 'qcom,regulator-off-debounce-delay-us' to describe the time to wait
> for an enable vote after a disable vote, before actually sending the
> disable request to RPMh.
>
> Some consumers toggle a regulator off and back on in quick succession
> as part of their normal operation, a behavior this driver has no
> control over. The appropriate debounce window to absorb this varies by
> which consumer(s) are wired to a given rail and how they use it, so it
> is exposed as a per-regulator property rather than a fixed value.
>
> It is placed in the qcom,rpmh-regulator binding and vendor-prefixed
> because the underlying deferred-disable mechanism is specific to this
> driver's RPMh command handling.
>
> Assisted-by: Claude:claude-sonnet-5
> Signed-off-by: Jishnu Prakash <jishnu.prakash@oss.qualcomm.com>
> ---
> .../bindings/regulator/qcom,rpmh-regulator.yaml | 18 ++++++++++++++++++
> 1 file changed, 18 insertions(+)
>
Acked-by: Rob Herring (Arm) <robh@kernel.org>
^ permalink raw reply [flat|nested] 9+ messages in thread
end of thread, other threads:[~2026-10-07 20:37 UTC | newest]
Thread overview: 9+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-10-01 12:46 [PATCH v4 0/4] regulator: qcom-rpmh: Add support for off-on-delay and debounce-delay Jishnu Prakash
2026-10-01 12:46 ` [PATCH v4 1/4] regulator: dt-bindings: Add 'regulator-off-on-delay-us' property Jishnu Prakash
2026-10-07 20:36 ` Rob Herring (Arm)
2026-10-01 12:46 ` [PATCH v4 2/4] regulator: qcom-rpmh: Add support for regulator-off-on-delay-us Jishnu Prakash
2026-10-07 16:12 ` Mark Brown
2026-10-01 12:46 ` [PATCH v4 3/4] regulator: dt-bindings: qcom,rpmh-regulator: Add debounce delay property Jishnu Prakash
2026-10-07 20:37 ` Rob Herring (Arm)
2026-10-01 12:46 ` [PATCH v4 4/4] regulator: qcom-rpmh: Add debounce delay before disabling regulator Jishnu Prakash
2026-10-01 13:05 ` sashiko-bot
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox