Signed-off-by: Paul Zimmerman <paulz@xxxxxxxxxxxx> --- drivers/usb/dwc3/gadget.c | 91 +++++++++++++++++++++++++++++++++++++++++++++ drivers/usb/dwc3/gadget.h | 2 + 2 files changed, 93 insertions(+), 0 deletions(-) diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c index af71994..fdaef9a 100644 --- a/drivers/usb/dwc3/gadget.c +++ b/drivers/usb/dwc3/gadget.c @@ -88,6 +88,40 @@ int dwc3_gadget_set_test_mode(struct dwc3 *dwc, int mode) } /** + * dwc3_gadget_get_link_state - Gets current state of USB Link + * @dwc: pointer to our context structure + * + * Caller should take care of locking. + */ +int dwc3_gadget_get_link_state(struct dwc3 *dwc) +{ + u32 reg = dwc3_readl(dwc->regs, DWC3_DSTS); + + /* + * Wait until device controller is ready. Only applies to 1.94a and + * later RTL. + */ + if (dwc->revision >= DWC3_REVISION_194A) { + int retries = 10000; + + while (--retries) { + if (reg & DWC3_DSTS_DCNRD) + udelay(5); + else + break; + reg = dwc3_readl(dwc->regs, DWC3_DSTS); + } + /* + * Don't return anything special on timeout - we would need to + * distinguish error return from link state, and besides it + * "shouldn't happen" + */ + } + + return DWC3_DSTS_USBLNKST(reg); +} + +/** * 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 @@ -338,6 +372,63 @@ int dwc3_send_gadget_ep_cmd(struct dwc3 *dwc, unsigned ep, } while (1); } +static const char *dwc3_gadget_dev_cmd_string(u8 cmd) +{ + switch (cmd) { + case DWC3_DGCMD_SET_LMP: + return "Transmit Set Link Function LMP"; + case DWC3_DGCMD_SET_PERIODIC_PAR: + return "Set Periodic Parameters"; + case DWC3_DGCMD_XMIT_FUNCTION: + return "Transmit Function Wake Device Notification"; + case DWC3_DGCMD_SET_SCRATCHPAD_ADDR_LO: + return "Set Scratchpad Buffer Array Address Lo"; + case DWC3_DGCMD_SET_SCRATCHPAD_ADDR_HI: + return "Set Scratchpad Buffer Array Address Hi"; + case DWC3_DGCMD_SELECTED_FIFO_FLUSH: + return "Selected FIFO Flush"; + case DWC3_DGCMD_ALL_FIFO_FLUSH: + return "All FIFO Flush"; + case DWC3_DGCMD_SET_ENDPOINT_NRDY: + return "Set Endpoint NRDY"; + case DWC3_DGCMD_RUN_SOC_BUS_LOOPBACK: + return "Run SoC Bus LoopBack Test"; + default: + return "UNKNOWN command"; + } +} + +int dwc3_send_gadget_dev_cmd(struct dwc3 *dwc, unsigned cmd, u32 param) +{ + u32 timeout = 500; + u32 reg; + + dev_vdbg(dwc->dev, "%s: cmd '%s' param %08x\n", __func__, + dwc3_gadget_dev_cmd_string(cmd), param); + + dwc3_writel(dwc->regs, DWC3_DGCMDPAR, param); + + dwc3_writel(dwc->regs, DWC3_DGCMD, cmd | DWC3_DGCMD_CMDACT); + do { + reg = dwc3_readl(dwc->regs, DWC3_DGCMD); + if (!(reg & DWC3_DGCMD_CMDACT)) { + dev_vdbg(dwc->dev, "Command Complete --> %d\n", + DWC3_DGCMD_STATUS(reg)); + return 0; + } + + /* + * We can't sleep here, because it is also called from + * interrupt context. + */ + timeout--; + if (!timeout) + return -ETIMEDOUT; + + udelay(1); + } while (1); +} + static dma_addr_t dwc3_trb_dma_offset(struct dwc3_ep *dep, struct dwc3_trb *trb) { diff --git a/drivers/usb/dwc3/gadget.h b/drivers/usb/dwc3/gadget.h index 24c11e3..d668cb1 100644 --- a/drivers/usb/dwc3/gadget.h +++ b/drivers/usb/dwc3/gadget.h @@ -106,6 +106,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_get_link_state(struct dwc3 *dwc); int dwc3_gadget_set_link_state(struct dwc3 *dwc, enum dwc3_link_state state); void dwc3_ep0_interrupt(struct dwc3 *dwc, @@ -116,6 +117,7 @@ int dwc3_gadget_ep0_queue(struct usb_ep *ep, struct usb_request *request, int __dwc3_gadget_ep_set_halt(struct dwc3_ep *dep, int value); int dwc3_send_gadget_ep_cmd(struct dwc3 *dwc, unsigned ep, unsigned cmd, struct dwc3_gadget_ep_cmd_params *params); +int dwc3_send_gadget_dev_cmd(struct dwc3 *dwc, unsigned cmd, u32 param); /** * dwc3_gadget_ep_get_transfer_index - Gets transfer index from HW -- 1.7.4.4 -- To unsubscribe from this list: send the line "unsubscribe linux-usb" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html