summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--drivers/usb/dwc3/gadget.c26
1 files changed, 25 insertions, 1 deletions
diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c
index c615d5917867..63f90080cb49 100644
--- a/drivers/usb/dwc3/gadget.c
+++ b/drivers/usb/dwc3/gadget.c
@@ -1505,14 +1505,38 @@ static int dwc3_gadget_get_frame(struct usb_gadget *g)
return DWC3_DSTS_SOFFN(reg);
}
+#define DWC3_PM_RESUME_RETRIES 20 /* Max Number of retries */
+#define DWC3_PM_RESUME_DELAY 100 /* 100 msec */
+
static void dwc3_gadget_wakeup_work(struct work_struct *w)
{
struct dwc3 *dwc;
int ret;
+ static int retry_count;
dwc = container_of(w, struct dwc3, wakeup_work);
- pm_runtime_get_sync(dwc->dev);
+ ret = pm_runtime_get_sync(dwc->dev);
+ if (ret) {
+ /* pm_runtime_get_sync returns -EACCES error between
+ * late_suspend and early_resume, wait for system resume to
+ * finish and queue work again
+ */
+ pr_debug("PM runtime get sync failed, ret %d\n", ret);
+ if (ret == -EACCES) {
+ pm_runtime_put_noidle(dwc->dev);
+ if (retry_count == DWC3_PM_RESUME_RETRIES) {
+ retry_count = 0;
+ pr_err("pm_runtime_get_sync timed out\n");
+ return;
+ }
+ msleep(DWC3_PM_RESUME_DELAY);
+ retry_count++;
+ schedule_work(&dwc->wakeup_work);
+ return;
+ }
+ }
+ retry_count = 0;
dbg_event(0xFF, "Gdgwake gsyn",
atomic_read(&dwc->dev->power.usage_count));