[PATCH v17 7/7] usb: dwc3: rockchip: fix USB-C reconnect in gadget mode
From: Sebastian Reichel
Date: Fri Oct 16 2026 - 14:56:17 EST
When USB-C is configured in gadget mode and the cable is unplugged
the USB controller is suspended. After plugging in the cable again,
the USB controller stays suspended and thus the port status remains
not-attached.
Fix this by informing the USB core about VBUS updates when the PHY
mode changes.
Signed-off-by: Sebastian Reichel <sebastian.reichel@xxxxxxxxxxxxx>
---
drivers/usb/dwc3/Kconfig | 1 +
drivers/usb/dwc3/dwc3-rockchip.c | 24 ++++++++++++++++++++++++
2 files changed, 25 insertions(+)
diff --git a/drivers/usb/dwc3/Kconfig b/drivers/usb/dwc3/Kconfig
index c86c1ac293bf..4cbc949c6abd 100644
--- a/drivers/usb/dwc3/Kconfig
+++ b/drivers/usb/dwc3/Kconfig
@@ -194,6 +194,7 @@ config USB_DWC3_ROCKCHIP
tristate "Rockchip DWC3 Platform Driver"
depends on ARCH_ROCKCHIP || COMPILE_TEST
depends on PHY_ROCKCHIP_USBDP || !PHY_ROCKCHIP_USBDP
+ depends on USB_GADGET || !USB_GADGET
depends on OF
default USB_DWC3
help
diff --git a/drivers/usb/dwc3/dwc3-rockchip.c b/drivers/usb/dwc3/dwc3-rockchip.c
index 1f32150caa09..5cb5feec8bd4 100644
--- a/drivers/usb/dwc3/dwc3-rockchip.c
+++ b/drivers/usb/dwc3/dwc3-rockchip.c
@@ -25,8 +25,17 @@ struct dwc3_rk_phy_nb {
struct dwc3_rockchip {
struct dwc3 dwc;
u8 phy_reset_active;
+ enum usb_role role;
};
+static void dwc3_rockchip_vbus_handler(struct dwc3 *dwc, bool present)
+{
+ if (!dwc->gadget || !dwc->gadget_driver)
+ return;
+
+ usb_udc_vbus_handler(dwc->gadget, present);
+}
+
static int dwc3_rockchip_phy_pre_reset(struct dwc3_rockchip *dwc_rk, int port)
{
struct dwc3 *dwc = &dwc_rk->dwc;
@@ -51,6 +60,8 @@ static int dwc3_rockchip_phy_pre_reset(struct dwc3_rockchip *dwc_rk, int port)
if (!ret)
return ret;
+ dwc3_rockchip_vbus_handler(dwc, false);
+
/*
* Assert USB3 PHY soft reset within DWC3 before the external
* PHY resets. This disconnects the PIPE interface, preventing
@@ -70,6 +81,8 @@ static int dwc3_rockchip_phy_pre_reset(struct dwc3_rockchip *dwc_rk, int port)
static int dwc3_rockchip_phy_post_reset(struct dwc3_rockchip *dwc_rk, int port)
{
struct dwc3 *dwc = &dwc_rk->dwc;
+ bool gadget_mode = (dwc->current_dr_role == DWC3_GCTL_PRTCAP_DEVICE) ||
+ (dwc_rk->role == USB_ROLE_DEVICE);
unsigned long flags;
u32 reg;
@@ -87,6 +100,8 @@ static int dwc3_rockchip_phy_post_reset(struct dwc3_rockchip *dwc_rk, int port)
dwc3_writel(dwc, DWC3_GUSB3PIPECTL(port), reg);
spin_unlock_irqrestore(&dwc->lock, flags);
+ dwc3_rockchip_vbus_handler(dwc, gadget_mode);
+
pm_runtime_put_autosuspend(dwc->dev);
return 0;
@@ -138,7 +153,16 @@ static int dwc3_rk_phy_register_reset_handler(struct dwc3 *dwc)
return devm_add_action_or_reset(dwc->dev, dwc3_rk_phy_unregister_notifiers, dwc_rk);
}
+static void dwc3_rockchip_set_role(struct dwc3 *dwc, enum usb_role role)
+{
+ struct dwc3_rockchip *dwc_rk = container_of(dwc, struct dwc3_rockchip, dwc);
+
+ dwc_rk->role = role;
+ dwc3_rockchip_vbus_handler(dwc, role == USB_ROLE_DEVICE);
+}
+
static struct dwc3_glue_ops dwc3_rockchip_glue_ops = {
+ .pre_set_role = dwc3_rockchip_set_role,
.post_phy_registration = dwc3_rk_phy_register_reset_handler,
};
--
2.53.0