summaryrefslogtreecommitdiffstats
path: root/drivers/usb/dwc3
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/usb/dwc3')
-rw-r--r--drivers/usb/dwc3/gadget.c52
-rw-r--r--drivers/usb/dwc3/gadget.h1
2 files changed, 42 insertions, 11 deletions
diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c
index 1dee17e7b778..80003952547e 100644
--- a/drivers/usb/dwc3/gadget.c
+++ b/drivers/usb/dwc3/gadget.c
@@ -89,6 +89,42 @@ int dwc3_gadget_set_test_mode(struct dwc3 *dwc, int mode)
return 0;
}
+/**
+ * dwc3_gadget_set_link_state - Sets USB Link to a particular State
+ * @dwc: pointer to our context structure
+ * @state: the state to put link into
+ *
+ * Caller should take care of locking. This function will
+ * return 0 on success or -EINVAL.
+ */
+int dwc3_gadget_set_link_state(struct dwc3 *dwc, enum dwc3_link_state state)
+{
+ int retries = 100;
+ u32 reg;
+
+ reg = dwc3_readl(dwc->regs, DWC3_DCTL);
+ reg &= ~DWC3_DCTL_ULSTCHNGREQ_MASK;
+
+ /* set requested state */
+ reg |= DWC3_DCTL_ULSTCHNGREQ(state);
+ dwc3_writel(dwc->regs, DWC3_DCTL, reg);
+
+ /* wait for a change in DSTS */
+ while (--retries) {
+ reg = dwc3_readl(dwc->regs, DWC3_DSTS);
+
+ /* in HS, means ON */
+ if (DWC3_DSTS_USBLNKST(reg) == state)
+ return 0;
+
+ usleep_range(500, 1500);
+ }
+
+ dev_vdbg(dwc->dev, "link state change request timed out\n");
+
+ return -ETIMEDOUT;
+}
+
void dwc3_map_buffer_to_dma(struct dwc3_request *req)
{
struct dwc3 *dwc = req->dep->dwc;
@@ -1155,17 +1191,11 @@ static int dwc3_gadget_wakeup(struct usb_gadget *g)
goto out;
}
- reg = dwc3_readl(dwc->regs, DWC3_DCTL);
-
- /*
- * Switch link state to Recovery. In HS/FS/LS this means
- * RemoteWakeup Request
- */
- reg |= DWC3_DCTL_ULSTCHNG_RECOVERY;
- dwc3_writel(dwc->regs, DWC3_DCTL, reg);
-
- /* wait for at least 2000us */
- usleep_range(2000, 2500);
+ ret = dwc3_gadget_set_link_state(dwc, DWC3_LINK_STATE_RECOV);
+ if (ret < 0) {
+ dev_err(dwc->dev, "failed to put link in Recovery\n");
+ goto out;
+ }
/* write zeroes to Link Change Request */
reg &= ~DWC3_DCTL_ULSTCHNGREQ_MASK;
diff --git a/drivers/usb/dwc3/gadget.h b/drivers/usb/dwc3/gadget.h
index 2cf6f2989f73..152b6de0649d 100644
--- a/drivers/usb/dwc3/gadget.h
+++ b/drivers/usb/dwc3/gadget.h
@@ -101,6 +101,7 @@ void dwc3_gadget_giveback(struct dwc3_ep *dep, struct dwc3_request *req,
int status);
int dwc3_gadget_set_test_mode(struct dwc3 *dwc, int mode);
+int dwc3_gadget_set_link_state(struct dwc3 *dwc, enum dwc3_link_state state);
void dwc3_ep0_interrupt(struct dwc3 *dwc,
const struct dwc3_event_depevt *event);