Skip to contentSkip to conversation

usb: dwc2: fix hang during suspend or shutdown

PATCH New Jisheng Zhang 1 participant 3 messages Nov 4, 2025

Subsystems (2)
lore
Share & tools
lore
#0 lore raw

cover usb: dwc2: fix hang during suspend or shutdown

dwc2 on most platforms needs phy controller, clock and power supply. All of them must be enabled/activated to properly operate. If dwc2 is configured as peripheral mode, then all the above three hardware resources are disabled at the end of the probe:

	/* Gadget code manages lowlevel hw on its own */
	if (hsotg->dr_mode == USB_DR_MODE_PERIPHERAL)
		dwc2_lowlevel_hw_disable(hsotg);

But both dwc2_driver_shutdown() and dwc2_suspend() tries to access the dwc2 registers, this would result in hang during suspend or shutdown if dwc2 is configured as peripheral mode.

This series tries to fix both issues.

Jisheng Zhang (2):
usb: dwc2: fix hang during shutdown if set as peripheral
usb: dwc2: fix hang during suspend if set as peripheral

 drivers/usb/dwc2/platform.c | 17 ++++++++++++-----
 1 file changed, 12 insertions(+), 5 deletions(-)
Signature · 1 line
2.50.0
#1 lore raw

PATCH 1/2 usb: dwc2: fix hang during shutdown if set as peripheral

dwc2 on most platforms needs phy controller, clock and power supply. All of them must be enabled/activated to properly operate. If dwc2 is configured as peripheral mode, then all the above three hardware resources are disabled at the end of the probe:

	/* Gadget code manages lowlevel hw on its own */
	if (hsotg->dr_mode == USB_DR_MODE_PERIPHERAL)
		dwc2_lowlevel_hw_disable(hsotg);

But dwc2_driver_shutdown() tries to disable the interrupts on HW IP level. This would result in hang during shutdown if dwc2 is configured as peripheral mode.

Fix this hang by only disable and sync irq when lowlevel hw is enabled.

Fixes 4fdf228cdf69 ("usb: dwc2: Fix shutdown callback in platform")
---
 drivers/usb/dwc2/platform.c | 8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)
drivers/usb/dwc2/platform.c +4 -4
index 3f83ecc9fc23..b07bdf16326a 100644
@@ -369,11 +369,11 @@ static void dwc2_driver_shutdown(struct platform_device *dev)
 {
 	struct dwc2_hsotg *hsotg = platform_get_drvdata(dev);
 
-	dwc2_disable_global_interrupts(hsotg);
-	synchronize_irq(hsotg->irq);
-
-	if (hsotg->ll_hw_enabled)
+	if (hsotg->ll_hw_enabled) {
+		dwc2_disable_global_interrupts(hsotg);
+		synchronize_irq(hsotg->irq);
 		dwc2_lowlevel_hw_disable(hsotg);
+	}
 }
 
 /**
Signature · 1 line
2.50.0
#2 lore raw

PATCH 2/2 usb: dwc2: fix hang during suspend if set as peripheral

In reply to Jisheng Zhang

dwc2 on most platforms needs phy controller, clock and power supply. All of them must be enabled/activated to properly operate. If dwc2 is configured as peripheral mode, then all the above three hardware resources are disabled at the end of the probe:

	/* Gadget code manages lowlevel hw on its own */
	if (hsotg->dr_mode == USB_DR_MODE_PERIPHERAL)
		dwc2_lowlevel_hw_disable(hsotg);

But the dwc2_suspend() tries to read the dwc2's reg to check whether is_device_mode or not, this would result in hang during suspend if dwc2 is configured as peripheral mode.

Fix this hang by bypassing suspend/resume if lowlevel hw isn't enabled.

Fixes 09a75e857790 ("usb: dwc2: refactor common low-level hw code to platform.c")
---
 drivers/usb/dwc2/platform.c | 9 ++++++++-
 1 file changed, 8 insertions(+), 1 deletion(-)
drivers/usb/dwc2/platform.c +8 -1
index b07bdf16326a..ef0d73077034 100644
@@ -649,9 +649,13 @@ static int dwc2_driver_probe(struct platform_device *dev)
 static int __maybe_unused dwc2_suspend(struct device *dev)
 {
 	struct dwc2_hsotg *dwc2 = dev_get_drvdata(dev);
-	bool is_device_mode = dwc2_is_device_mode(dwc2);
+	bool is_device_mode;
 	int ret = 0;
 
+	if (!dwc2->ll_hw_enabled)
+		return 0;
+
+	is_device_mode = dwc2_is_device_mode(dwc2);
 	if (is_device_mode)
 		dwc2_hsotg_suspend(dwc2);
 
@@ -728,6 +732,9 @@ static int __maybe_unused dwc2_resume(struct device *dev)
 	struct dwc2_hsotg *dwc2 = dev_get_drvdata(dev);
 	int ret = 0;
 
+	if (!dwc2->ll_hw_enabled)
+		return 0;
+
 	if (dwc2->phy_off_for_suspend && dwc2->ll_hw_enabled) {
 		ret = __dwc2_lowlevel_hw_enable(dwc2);
 		if (ret)
Signature · 1 line
2.50.0