usb: dwc3: gadget: re-factor Link state change to a function
authorFelipe Balbi <balbi@ti.com>
Mon, 2 Jan 2012 16:55:57 +0000 (18:55 +0200)
committerFelipe Balbi <balbi@ti.com>
Mon, 6 Feb 2012 09:48:24 +0000 (11:48 +0200)
Most link changes will, of course, happen with
the help of a matching host HW, but in some cases
we might want to debug very low level details about
the link and exposing this to debugfs sounds like
a good plan.

This is a preparation for such setup.

Signed-off-by: Felipe Balbi <balbi@ti.com>
drivers/usb/dwc3/gadget.c
drivers/usb/dwc3/gadget.h

index 1dee17e7b778a9beeabd1efad104f96e8f68edd3..80003952547e620d1226721b9da9e979bafeda1d 100644 (file)
@@ -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;
index 2cf6f2989f7375975008096a25a77f11889e8248..152b6de0649d3115663361ce4b8d5fd1cc3fd6cb 100644 (file)
@@ -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);