diff options
| -rw-r--r-- | drivers/usb/dwc3/gadget.c | 26 |
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)); |
