mirror of
https://github.com/hardkernel/linux.git
synced 2026-06-07 19:30:30 +09:00
usb: dwc2: Fix dwc2 OTG-HOST resume fails to recognize peripherals
This patch fix following two cases dwc2 resume does not recognize peripherals. 1. plug in device after system suspend, then press the power-on button to wake up,at this time the dr_mode is OTG, op_state is still Peripheral, the Bit[0] of GINTSTS is 1 and the port power is off, dwc2 will not resume at this time. 2. plug in device then press the power-on button to put the system to sleep, then we press the power-on button to wake up the system, At this time, the dr_mode is OTG, op_state is still Host, the Bit[0] of GINTSTS is 1, dwc2 will not resume and working abnormally. To resolve the first exception, we should call the dwc2_hsotg_resume() directly to resume dwc2. To resolve the second exception, if the dwc2 is lost power during suspend like RK3326S platform, wo should reinit the core to device mode, and after do dwc2_hsotg_resume, it can trigger the ID status change interrupt if the OTG cable is still connect. Then we can init it for host mode in the ID status change interrupt handler. We can use the power on bit of Hprt register to distinguish whether it is lost power during suspend. Signed-off-by: Jianwei Zheng <jianwei.zheng@rock-chips.com> Change-Id: I7cd09bce993dcee8e5bfcaddd5fe884cdfab6b52
This commit is contained in:
committed by
William Wu
parent
5452a06eed
commit
25da86fe62
@@ -798,44 +798,44 @@ static int __maybe_unused dwc2_resume(struct device *dev)
|
||||
|
||||
dwc2_drd_resume(dwc2);
|
||||
|
||||
if (dwc2_is_device_mode(dwc2)) {
|
||||
if (dwc2->dr_mode == USB_DR_MODE_HOST) {
|
||||
/* Reinit for Host mode if lost power */
|
||||
dwc2_force_mode(dwc2, true);
|
||||
if (dwc2->dr_mode == USB_DR_MODE_HOST && dwc2_is_device_mode(dwc2)) {
|
||||
/* Reinit for Host mode if lost power */
|
||||
dwc2_force_mode(dwc2, true);
|
||||
|
||||
spin_lock_irqsave(&dwc2->lock, flags);
|
||||
dwc2_hsotg_disconnect(dwc2);
|
||||
spin_unlock_irqrestore(&dwc2->lock, flags);
|
||||
spin_lock_irqsave(&dwc2->lock, flags);
|
||||
dwc2_hsotg_disconnect(dwc2);
|
||||
spin_unlock_irqrestore(&dwc2->lock, flags);
|
||||
|
||||
dwc2->op_state = OTG_STATE_A_HOST;
|
||||
/* Initialize the Core for Host mode */
|
||||
dwc2_core_init(dwc2, false);
|
||||
dwc2_enable_global_interrupts(dwc2);
|
||||
dwc2_hcd_start(dwc2);
|
||||
} else {
|
||||
/* Reinit for OTG in Host mode if lost power */
|
||||
if (dwc2->dr_mode == USB_DR_MODE_OTG &&
|
||||
dwc2->op_state == OTG_STATE_A_HOST) {
|
||||
/*
|
||||
* Reinit the core to device mode, and later
|
||||
* after do dwc2_hsotg_resume, it can trigger
|
||||
* the ID status change interrupt if the OTG
|
||||
* cable is still connected, then we can init
|
||||
* for Host mode in the ID status change
|
||||
* interrupt handler.
|
||||
*/
|
||||
spin_lock_irqsave(&dwc2->lock, flags);
|
||||
dwc2_hcd_disconnect(dwc2, true);
|
||||
dwc2->op_state = OTG_STATE_B_PERIPHERAL;
|
||||
dwc2->lx_state = DWC2_L3;
|
||||
if (!dwc2->driver)
|
||||
dwc2_hsotg_core_init_disconnected(dwc2, false);
|
||||
spin_unlock_irqrestore(&dwc2->lock, flags);
|
||||
dwc2->op_state = OTG_STATE_A_HOST;
|
||||
/* Initialize the Core for Host mode */
|
||||
dwc2_core_init(dwc2, false);
|
||||
dwc2_enable_global_interrupts(dwc2);
|
||||
dwc2_hcd_start(dwc2);
|
||||
} else if (dwc2->dr_mode == USB_DR_MODE_OTG &&
|
||||
dwc2->op_state == OTG_STATE_A_HOST &&
|
||||
!(dwc2_readl(dwc2, HPRT0) & HPRT0_PWR)) {
|
||||
/*
|
||||
* Reinit the core to device mode, and later
|
||||
* after do dwc2_hsotg_resume, it can trigger
|
||||
* the ID status change interrupt if the OTG
|
||||
* cable is still connected, then we can init
|
||||
* for Host mode in the ID status change
|
||||
* interrupt handler.
|
||||
*/
|
||||
spin_lock_irqsave(&dwc2->lock, flags);
|
||||
dwc2_hcd_disconnect(dwc2, true);
|
||||
dwc2->op_state = OTG_STATE_B_PERIPHERAL;
|
||||
dwc2->lx_state = DWC2_L3;
|
||||
if (!dwc2->driver)
|
||||
dwc2_hsotg_core_init_disconnected(dwc2, false);
|
||||
spin_unlock_irqrestore(&dwc2->lock, flags);
|
||||
|
||||
}
|
||||
|
||||
ret = dwc2_hsotg_resume(dwc2);
|
||||
}
|
||||
ret = dwc2_hsotg_resume(dwc2);
|
||||
} else if (dwc2_is_device_mode(dwc2) ||
|
||||
(dwc2_is_host_mode(dwc2) &&
|
||||
dwc2->dr_mode == USB_DR_MODE_OTG &&
|
||||
dwc2->op_state == OTG_STATE_B_PERIPHERAL)) {
|
||||
ret = dwc2_hsotg_resume(dwc2);
|
||||
}
|
||||
|
||||
return ret;
|
||||
|
||||
Reference in New Issue
Block a user