diff options
author | Felipe Balbi <balbi@ti.com> | 2012-01-02 18:55:57 +0200 |
---|---|---|
committer | Felipe Balbi <balbi@ti.com> | 2012-02-06 11:48:24 +0200 |
commit | 8598bde7fa125e85bc97decd6513d37dcf1e7bd9 (patch) | |
tree | f33eab7bb8bc5e0197165215703dd0308c862d69 /drivers/usb/dwc3 | |
parent | 080d921fe7a8d27c07eba7723fe53a3bea100327 (diff) |
usb: dwc3: gadget: re-factor Link state change to a function
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>
Diffstat (limited to 'drivers/usb/dwc3')
-rw-r--r-- | drivers/usb/dwc3/gadget.c | 52 | ||||
-rw-r--r-- | drivers/usb/dwc3/gadget.h | 1 |
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); |