ci->role = ci_get_role(ci);
if (!ci_otg_is_fsm_mode(ci)) {
- /* only update vbus status for peripheral */
- if (ci->role == CI_ROLE_GADGET) {
- /* Pull down DP for possible charger detection */
- hw_write(ci, OP_USBCMD, USBCMD_RS, 0);
- ci_handle_vbus_change(ci);
- }
-
ret = ci_role_start(ci, ci->role);
if (ret) {
dev_err(dev, "can't start %s role\n",
ci_role(ci)->name);
goto stop;
}
+
+ /* only update vbus status for peripheral */
+ if (ci->role == CI_ROLE_GADGET)
+ ci_handle_vbus_change(ci);
}
ret = devm_request_irq(dev, ci->irq, ci_irq_handler, IRQF_SHARED,
{
int retval = 0, i, j;
+ memset(ci->ci_hw_ep, 0, sizeof(ci->ci_hw_ep));
+
for (i = 0; i < ci->hw_ep_max/2; i++)
for (j = RX; j <= TX; j++) {
int k = i + j * ci->hw_ep_max/2;
struct usb_otg_caps *otg_caps = &ci->platdata->ci_otg_caps;
int retval = 0;
+ memset(&ci->gadget, 0, sizeof(ci->gadget));
+
ci->gadget.ops = &usb_gadget_ops;
ci->gadget.speed = USB_SPEED_UNKNOWN;
ci->gadget.max_speed = USB_SPEED_HIGH;
ci->gadget.ep0 = &ci->ep0in->ep;
+ if (ci->platdata->pins_device)
+ pinctrl_select_state(ci->platdata->pctl,
+ ci->platdata->pins_device);
+
retval = usb_add_gadget_udc(dev, &ci->gadget);
if (retval)
goto destroy_eps;
+ ci_udc_enable_vbus_irq(ci, true);
return retval;
destroy_eps:
return retval;
}
-/*
- * ci_hdrc_gadget_destroy: parent remove must call this to remove UDC
- *
- * No interrupts active, the IRQ has been released
+/**
+ * udc_stop: deinitialize gadget role
+ * @ci: chipidea controller
*/
-void ci_hdrc_gadget_destroy(struct ci_hdrc *ci)
+static void udc_stop(struct ci_hdrc *ci)
{
- if (!ci->roles[CI_ROLE_GADGET])
- return;
-
+ ci_udc_enable_vbus_irq(ci, false);
usb_del_gadget_udc(&ci->gadget);
+ ci->vbus_active = 0;
destroy_eps(ci);
dma_pool_destroy(ci->td_pool);
dma_pool_destroy(ci->qh_pool);
-}
-
-static int udc_id_switch_for_device(struct ci_hdrc *ci)
-{
- if (ci->platdata->pins_device)
- pinctrl_select_state(ci->platdata->pctl,
- ci->platdata->pins_device);
-
- ci_udc_enable_vbus_irq(ci, true);
- return 0;
-}
-
-static void udc_id_switch_for_host(struct ci_hdrc *ci)
-{
- ci_udc_enable_vbus_irq(ci, false);
- ci->vbus_active = 0;
if (ci->platdata->pins_device && ci->platdata->pins_default)
pinctrl_select_state(ci->platdata->pctl,
int ci_hdrc_gadget_init(struct ci_hdrc *ci)
{
struct ci_role_driver *rdrv;
- int ret;
if (!hw_read(ci, CAP_DCCPARAMS, DCCPARAMS_DC))
return -ENXIO;
if (!rdrv)
return -ENOMEM;
- rdrv->start = udc_id_switch_for_device;
- rdrv->stop = udc_id_switch_for_host;
+ rdrv->start = udc_start;
+ rdrv->stop = udc_stop;
#ifdef CONFIG_PM_SLEEP
rdrv->suspend = udc_suspend;
rdrv->resume = udc_resume;
rdrv->irq = udc_irq;
rdrv->name = "gadget";
- ret = udc_start(ci);
- if (!ret)
- ci->roles[CI_ROLE_GADGET] = rdrv;
+ ci->roles[CI_ROLE_GADGET] = rdrv;
- return ret;
+ /* Pull down DP for possible charger detection */
+ hw_write(ci, OP_USBCMD, USBCMD_RS, 0);
+ return 0;
+}
+
+/*
+ * ci_hdrc_gadget_destroy: parent remove must call this to remove UDC
+ *
+ * No interrupts active, the IRQ has been released
+ */
+void ci_hdrc_gadget_destroy(struct ci_hdrc *ci)
+{
+ struct device *dev = &ci->gadget.dev;
+
+ if (ci->roles[CI_ROLE_GADGET] && device_is_registered(dev))
+ udc_stop(ci);
}