From a46f2b4821767d374ce4150dae38d74c76693ce4 Mon Sep 17 00:00:00 2001 From: William Wu Date: Wed, 25 Apr 2018 20:10:19 +0800 Subject: [PATCH] usb: dwc3: rockchip: fix usb peripheral connection fail This patch fix the issue that usb peripheral fails to connect to PC after resume from deep sleep. In my test case, I use a rk3399 sapphire excavator board, and test usb as follows: - Let the system enter deep sleep without usb connection. - During deep sleep, connect the Type-C0 of rk3399 with PC usb port. - Press power key to wakeup system, and check if the PC can detect usb. Without this patch, the usb enumeration often fail with the error log "dwc3 fe800000.dwc3: failed to enable ep0out". It's because that after system resume, the dwc3 pm resume and dwc3 pm runtime resume are running asynchronously. If dwc3 runtime resume before pm resume, the dwc3_resume_common() maybe called twice, and cause ep enable failure. This patch use the suspend flag of dev to wait until the dwc3 core resume from PM suspend successfully before do dwc3 pm runtime resume. Change-Id: I6a67ad636630699569e16346ac167b785b800f85 Signed-off-by: William Wu --- drivers/usb/dwc3/dwc3-rockchip.c | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/drivers/usb/dwc3/dwc3-rockchip.c b/drivers/usb/dwc3/dwc3-rockchip.c index e267a65ebaca..afdb6cb1f437 100644 --- a/drivers/usb/dwc3/dwc3-rockchip.c +++ b/drivers/usb/dwc3/dwc3-rockchip.c @@ -408,7 +408,8 @@ static void dwc3_rockchip_otg_extcon_evt_work(struct work_struct *work) unsigned long flags; int ret; int val; - u32 reg, count; + u32 reg; + u32 count = 0; mutex_lock(&rockchip->lock); @@ -442,6 +443,16 @@ static void dwc3_rockchip_otg_extcon_evt_work(struct work_struct *work) udelay(1); reset_control_deassert(rockchip->otg_rst); + /* Wait until dwc3 core resume from PM suspend */ + while (dwc->dev->power.is_suspended) { + if (++count > 1000) { + dev_err(rockchip->dev, + "wait for dwc3 core resume timeout!\n"); + goto out; + } + usleep_range(100, 200); + } + pm_runtime_get_sync(rockchip->dev); pm_runtime_get_sync(dwc->dev); } else { @@ -574,7 +585,6 @@ disconnect: if (hcd->state != HC_STATE_HALT) { xhci->xhc_state |= XHCI_STATE_REMOVING; - count = 0; /* * Wait until XHCI controller resume from