diff --git a/drivers/usb/dwc3/core.h b/drivers/usb/dwc3/core.h index 0e73026711d6..9de5e06430e1 100644 --- a/drivers/usb/dwc3/core.h +++ b/drivers/usb/dwc3/core.h @@ -1021,6 +1021,8 @@ struct dwc3 { unsigned irq_event_count[MAX_INTR_STATS]; unsigned irq_dbg_index; + unsigned long l1_remote_wakeup_cnt; + wait_queue_head_t wait_linkstate; }; diff --git a/drivers/usb/dwc3/debugfs.c b/drivers/usb/dwc3/debugfs.c index 4b4978043d50..068b03a35bd5 100644 --- a/drivers/usb/dwc3/debugfs.c +++ b/drivers/usb/dwc3/debugfs.c @@ -1180,9 +1180,12 @@ static int dwc3_gadget_int_events_show(struct seq_file *s, void *unused) seq_printf(s, "%d\t", dwc->bh_completion_time[i]); seq_putc(s, '\n'); - seq_printf(s, "t_pwr evt irq : %lld\t", + seq_printf(s, "t_pwr evt irq : %lld\n", ktime_to_us(dwc->t_pwr_evt_irq)); + seq_printf(s, "l1_remote_wakeup_cnt : %lu\n", + dwc->l1_remote_wakeup_cnt); + spin_unlock_irqrestore(&dwc->lock, flags); return 0; } diff --git a/drivers/usb/dwc3/ep0.c b/drivers/usb/dwc3/ep0.c index 2b910e09a80a..9cd87513619c 100644 --- a/drivers/usb/dwc3/ep0.c +++ b/drivers/usb/dwc3/ep0.c @@ -236,6 +236,8 @@ int dwc3_gadget_ep0_queue(struct usb_ep *ep, struct usb_request *request, unsigned long flags; int ret; + enum dwc3_link_state link_state; + u32 reg; spin_lock_irqsave(&dwc->lock, flags); if (!dep->endpoint.desc) { @@ -252,6 +254,18 @@ int dwc3_gadget_ep0_queue(struct usb_ep *ep, struct usb_request *request, goto out; } + /* if link stats is in L1 initiate remote wakeup before queuing req */ + if (dwc->speed != DWC3_DSTS_SUPERSPEED) { + link_state = dwc3_get_link_state(dwc); + /* in HS this link state is same as L1 */ + if (link_state == DWC3_LINK_STATE_U2) { + dwc->l1_remote_wakeup_cnt++; + reg = dwc3_readl(dwc->regs, DWC3_DCTL); + reg |= DWC3_DCTL_ULSTCHNG_RECOVERY; + dwc3_writel(dwc->regs, DWC3_DCTL, reg); + } + } + dwc3_trace(trace_dwc3_ep0, "queueing request %pK to %s length %d state '%s'", request, dep->name, request->length, diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c index e2440b7efc58..88350e61f3bd 100644 --- a/drivers/usb/dwc3/gadget.c +++ b/drivers/usb/dwc3/gadget.c @@ -1317,13 +1317,6 @@ static int dwc3_gadget_wakeup(struct usb_gadget *g) return 0; } -static inline enum dwc3_link_state dwc3_get_link_state(struct dwc3 *dwc) -{ - u32 reg; - reg = dwc3_readl(dwc->regs, DWC3_DSTS); - return DWC3_DSTS_USBLNKST(reg); -} - static bool dwc3_gadget_is_suspended(struct dwc3 *dwc) { if (atomic_read(&dwc->in_lpm) || diff --git a/drivers/usb/dwc3/gadget.h b/drivers/usb/dwc3/gadget.h index 3abd6379164e..a21962c8f513 100644 --- a/drivers/usb/dwc3/gadget.h +++ b/drivers/usb/dwc3/gadget.h @@ -84,6 +84,14 @@ static inline void dwc3_gadget_move_request_queued(struct dwc3_request *req) list_move_tail(&req->list, &dep->req_queued); } +static inline enum dwc3_link_state dwc3_get_link_state(struct dwc3 *dwc) +{ + u32 reg; + + reg = dwc3_readl(dwc->regs, DWC3_DSTS); + return DWC3_DSTS_USBLNKST(reg); +} + void dwc3_gadget_giveback(struct dwc3_ep *dep, struct dwc3_request *req, int status);