usb: dwc2: fix hang during suspend or shutdown
Subsystems (2)
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
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.
--- drivers/usb/dwc2/platform.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-)
drivers/usb/dwc2/platform.c +4 -4
@@ -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
PATCH 2/2 usb: dwc2: fix hang during suspend if set as peripheral
In reply to Jisheng Zhangdwc2 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.
--- drivers/usb/dwc2/platform.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-)
drivers/usb/dwc2/platform.c +8 -1
@@ -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