return 0;
}
+static int dwc3_udc_init(struct dwc3 *dwc)
+{
+ struct dwc3_ep *dep;
+ int ret = 0;
+ u32 reg;
+
+ reg = dwc3_readl(dwc->regs, DWC3_DCFG);
+ reg &= ~(DWC3_DCFG_SPEED_MASK);
+
+ /**
+ * WORKAROUND: DWC3 revision < 2.20a have an issue
+ * which would cause metastability state on Run/Stop
+ * bit if we try to force the IP to USB2-only mode.
+ *
+ * Because of that, we cannot configure the IP to any
+ * speed other than the SuperSpeed
+ *
+ * Refers to:
+ *
+ * STAR#9000525659: Clock Domain Crossing on DCTL in
+ * USB 2.0 Mode
+ */
+ if (dwc->revision < DWC3_REVISION_220A) {
+ reg |= DWC3_DCFG_SUPERSPEED;
+ } else {
+ switch (dwc->maximum_speed) {
+ case USB_SPEED_LOW:
+ reg |= DWC3_DSTS_LOWSPEED;
+ break;
+ case USB_SPEED_FULL:
+ reg |= DWC3_DSTS_FULLSPEED1;
+ break;
+ case USB_SPEED_HIGH:
+ reg |= DWC3_DSTS_HIGHSPEED;
+ break;
+ case USB_SPEED_SUPER: /* FALLTHROUGH */
+ case USB_SPEED_UNKNOWN: /* FALTHROUGH */
+ default:
+ reg |= DWC3_DSTS_SUPERSPEED;
+ }
+ }
+ dwc3_writel(dwc->regs, DWC3_DCFG, reg);
+
+ dwc->start_config_issued = false;
+
+ /* Start with SuperSpeed Default */
+ dwc3_gadget_ep0_desc.wMaxPacketSize = cpu_to_le16(512);
+
+ dep = dwc->eps[0];
+ ret = __dwc3_gadget_ep_enable(dep, &dwc3_gadget_ep0_desc,
+ NULL, false, false);
+ if (ret) {
+ dev_err(dwc->dev, "failed to enable %s\n", dep->name);
+ goto err0;
+ }
+
+ dep = dwc->eps[1];
+ ret = __dwc3_gadget_ep_enable(dep, &dwc3_gadget_ep0_desc,
+ NULL, false, false);
+ if (ret) {
+ dev_err(dwc->dev, "failed to enable %s\n", dep->name);
+ goto err1;
+ }
+
+ /* begin to receive SETUP packets */
+ dwc->ep0state = EP0_SETUP_PHASE;
+ dwc3_ep0_out_start(dwc);
+
+ return 0;
+
+err1:
+ __dwc3_gadget_ep_disable(dwc->eps[0]);
+
+err0:
+ return ret;
+}
+
+static void dwc3_gadget_enable_irq(struct dwc3 *dwc);
+static void dwc3_gadget_disable_irq(struct dwc3 *dwc);
+
static int dwc3_gadget_run_stop(struct dwc3 *dwc, int is_on, int suspend)
{
u32 reg;
u32 timeout = 500;
+ int ret;
reg = dwc3_readl(dwc->regs, DWC3_DCTL);
if (is_on) {
+ /*
+ * According to the Databook in case of reconnection and
+ * role switching the core should be completely reinitialized.
+ * Exception: first connection as peripheral when core was
+ * initialized during probing.
+ */
+ if (dwc->needs_reinit) {
+ ret = dwc3_core_init(dwc);
+ if (ret) {
+ dev_err(dwc->dev, "failed to reinitialize core\n");
+ return ret;
+ }
+
+ dwc3_event_buffers_setup(dwc);
+ }
+
+ ret = dwc3_udc_init(dwc);
+ if (ret) {
+ dev_err(dwc->dev, "failed to initialize udc\n");
+ return ret;
+ }
+
+ dwc3_gadget_enable_irq(dwc);
+
+ dwc->needs_reinit = 0;
+
if (dwc->revision <= DWC3_REVISION_187A) {
reg &= ~DWC3_DCTL_TRGTULST_MASK;
reg |= DWC3_DCTL_TRGTULST_RX_DET;
dwc->pullups_connected = true;
} else {
+ dwc3_gadget_disable_irq(dwc);
+ __dwc3_gadget_ep_disable(dwc->eps[0]);
+ __dwc3_gadget_ep_disable(dwc->eps[1]);
+
reg &= ~DWC3_DCTL_RUN_STOP;
if (dwc->has_hibernation && !suspend)
udelay(1);
} while (1);
+ if (!is_on) {
+ /* when everything is done, shutdown PHYs */
+ dwc3_core_exit(dwc);
+ dwc->needs_reinit = 1;
+ }
+
dwc3_trace(trace_dwc3_gadget, "gadget %s data soft-%s",
dwc->gadget_driver
? dwc->gadget_driver->function : "no-function",
struct usb_gadget_driver *driver)
{
struct dwc3 *dwc = gadget_to_dwc(g);
- struct dwc3_ep *dep;
unsigned long flags;
int ret = 0;
int irq;
- u32 reg;
irq = platform_get_irq(to_platform_device(dwc->dev), 0);
ret = request_threaded_irq(irq, dwc3_interrupt, dwc3_thread_interrupt,
dwc->gadget_driver = driver;
- reg = dwc3_readl(dwc->regs, DWC3_DCFG);
- reg &= ~(DWC3_DCFG_SPEED_MASK);
-
- /**
- * WORKAROUND: DWC3 revision < 2.20a have an issue
- * which would cause metastability state on Run/Stop
- * bit if we try to force the IP to USB2-only mode.
- *
- * Because of that, we cannot configure the IP to any
- * speed other than the SuperSpeed
- *
- * Refers to:
- *
- * STAR#9000525659: Clock Domain Crossing on DCTL in
- * USB 2.0 Mode
- */
- if (dwc->revision < DWC3_REVISION_220A) {
- reg |= DWC3_DCFG_SUPERSPEED;
- } else {
- switch (dwc->maximum_speed) {
- case USB_SPEED_LOW:
- reg |= DWC3_DSTS_LOWSPEED;
- break;
- case USB_SPEED_FULL:
- reg |= DWC3_DSTS_FULLSPEED1;
- break;
- case USB_SPEED_HIGH:
- reg |= DWC3_DSTS_HIGHSPEED;
- break;
- case USB_SPEED_SUPER: /* FALLTHROUGH */
- case USB_SPEED_UNKNOWN: /* FALTHROUGH */
- default:
- reg |= DWC3_DSTS_SUPERSPEED;
- }
- }
- dwc3_writel(dwc->regs, DWC3_DCFG, reg);
-
- dwc->start_config_issued = false;
-
- /* Start with SuperSpeed Default */
- dwc3_gadget_ep0_desc.wMaxPacketSize = cpu_to_le16(512);
-
- dep = dwc->eps[0];
- ret = __dwc3_gadget_ep_enable(dep, &dwc3_gadget_ep0_desc, NULL, false,
- false);
- if (ret) {
- dev_err(dwc->dev, "failed to enable %s\n", dep->name);
- goto err2;
- }
-
- dep = dwc->eps[1];
- ret = __dwc3_gadget_ep_enable(dep, &dwc3_gadget_ep0_desc, NULL, false,
- false);
- if (ret) {
- dev_err(dwc->dev, "failed to enable %s\n", dep->name);
- goto err3;
- }
-
- /* begin to receive SETUP packets */
- dwc->ep0state = EP0_SETUP_PHASE;
- dwc3_ep0_out_start(dwc);
-
- dwc3_gadget_enable_irq(dwc);
-
spin_unlock_irqrestore(&dwc->lock, flags);
return 0;
-err3:
- __dwc3_gadget_ep_disable(dwc->eps[0]);
-
-err2:
- dwc->gadget_driver = NULL;
-
err1:
spin_unlock_irqrestore(&dwc->lock, flags);