summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChang Wu <kunjinkao.jp@gmail.com>2026-08-19 23:20:27 +0800
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2026-09-01 16:34:56 +0200
commitc9a48db776d7184981630ecc01a3ad30a8f7dc24 (patch)
tree1349edb990bdc569cd94570a1a7796b5daee1e01
parentb58e6200450d350314db0ecda7d6d1bde3281e80 (diff)
downloadlinux-c9a48db776d7184981630ecc01a3ad30a8f7dc24.tar.gz
linux-c9a48db776d7184981630ecc01a3ad30a8f7dc24.zip
usb: typec: hd3ss3220: track VBUS enable state per consumer
regulator_is_enabled() reports the aggregate regulator state, not whether this consumer holds an enable reference. If another consumer enables VBUS first, the driver can skip its own regulator_enable() call and later attempt to drop a reference it never acquired, triggering an unbalanced regulator disable warning. Track successful enable and disable calls locally. Keep the state unchanged when an operation fails so a later role or ID notification retries the operation while this consumer keeps balanced references. Fixes: b3f9d6e491fd ("usb: typec: hd3ss3220: Check if regulator needs to be switched") Cc: stable <stable@kernel.org> Link: https://github.com/qualcomm-linux/kernel/issues/472 Signed-off-by: Chang Wu <kunjinkao.jp@gmail.com> Reviewed-by: Heikki Krogerus <heikki.krogerus@linux.intel.com> Tested-by: Jan Remmet <j.remmet@phytec.de> Reviewed-by: Krishna Kurapati <krishna.kurapati@oss.qualcomm.com> Link: https://patch.msgid.link/20260819152027.90994-1-kunjinkao.jp@gmail.com Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
-rw-r--r--drivers/usb/typec/hd3ss3220.c9
1 files changed, 7 insertions, 2 deletions
diff --git a/drivers/usb/typec/hd3ss3220.c b/drivers/usb/typec/hd3ss3220.c
index d0de5a2488f9..4eec90c82bae 100644
--- a/drivers/usb/typec/hd3ss3220.c
+++ b/drivers/usb/typec/hd3ss3220.c
@@ -62,6 +62,7 @@ struct hd3ss3220 {
int id_irq;
struct regulator *vbus;
+ bool vbus_enabled;
};
static int hd3ss3220_set_power_opmode(struct hd3ss3220 *hd3ss3220, int power_opmode)
@@ -208,7 +209,7 @@ static void hd3ss3220_regulator_control(struct hd3ss3220 *hd3ss3220, bool on)
{
int ret;
- if (regulator_is_enabled(hd3ss3220->vbus) == on)
+ if (hd3ss3220->vbus_enabled == on)
return;
if (on)
@@ -216,9 +217,13 @@ static void hd3ss3220_regulator_control(struct hd3ss3220 *hd3ss3220, bool on)
else
ret = regulator_disable(hd3ss3220->vbus);
- if (ret)
+ if (ret) {
dev_err(hd3ss3220->dev,
"vbus regulator %s failed: %d\n", on ? "enable" : "disable", ret);
+ return;
+ }
+
+ hd3ss3220->vbus_enabled = on;
}
static void hd3ss3220_set_role(struct hd3ss3220 *hd3ss3220)