summaryrefslogtreecommitdiff
path: root/drivers/usb/dwc3
diff options
context:
space:
mode:
authorFelipe Balbi <felipe.balbi@linux.intel.com>2016-04-04 09:46:33 (GMT)
committerFelipe Balbi <felipe.balbi@linux.intel.com>2016-04-18 12:23:42 (GMT)
commitc36d8e947a56a6e6478fc48152c5f4626462db55 (patch)
treedc3f2b9ad069457cc869fe56278cf08332bcdedd /drivers/usb/dwc3
parent218ef7b647e3367c9f81e18f63fbb0066f10b9a5 (diff)
downloadlinux-c36d8e947a56a6e6478fc48152c5f4626462db55.tar.xz
usb: dwc3: gadget: put link to U0 before Start Transfer
Synopsys Databook says we should move link to U0 before issuing a Start Transfer command. We could require the gadget driver to call usb_gadget_wakeup() however I feel that changing all gadget drivers to keep track of Link State and conditionally call usb_gadget_wakeup() would be far too much work. For now we will handle this at the UDC level, but at some point composite.c should be one handling this. Signed-off-by: Felipe Balbi <felipe.balbi@linux.intel.com>
Diffstat (limited to 'drivers/usb/dwc3')
-rw-r--r--drivers/usb/dwc3/gadget.c16
1 files changed, 16 insertions, 0 deletions
diff --git a/drivers/usb/dwc3/gadget.c b/drivers/usb/dwc3/gadget.c
index 2cc2c15..0e27158 100644
--- a/drivers/usb/dwc3/gadget.c
+++ b/drivers/usb/dwc3/gadget.c
@@ -221,6 +221,8 @@ int dwc3_send_gadget_generic_command(struct dwc3 *dwc, unsigned cmd, u32 param)
} while (1);
}
+static int __dwc3_gadget_wakeup(struct dwc3 *dwc);
+
int dwc3_send_gadget_ep_cmd(struct dwc3 *dwc, unsigned ep,
unsigned cmd, struct dwc3_gadget_ep_cmd_params *params)
{
@@ -248,6 +250,20 @@ int dwc3_send_gadget_ep_cmd(struct dwc3 *dwc, unsigned ep,
dwc3_writel(dwc->regs, DWC3_GUSB2PHYCFG(0), reg);
}
+ if (cmd == DWC3_DEPCMD_STARTTRANSFER) {
+ int needs_wakeup;
+
+ needs_wakeup = (dwc->link_state == DWC3_LINK_STATE_U1 ||
+ dwc->link_state == DWC3_LINK_STATE_U2 ||
+ dwc->link_state == DWC3_LINK_STATE_U3);
+
+ if (unlikely(needs_wakeup)) {
+ ret = __dwc3_gadget_wakeup(dwc);
+ dev_WARN_ONCE(dwc->dev, ret, "wakeup failed --> %d\n",
+ ret);
+ }
+ }
+
dwc3_writel(dwc->regs, DWC3_DEPCMDPAR0(ep), params->param0);
dwc3_writel(dwc->regs, DWC3_DEPCMDPAR1(ep), params->param1);
dwc3_writel(dwc->regs, DWC3_DEPCMDPAR2(ep), params->param2);