Example #1
0
/* blocking notifier support */
static int musb_otg_notifications(struct notifier_block *nb,
		unsigned long event, void *unused)
{
	struct musb	*musb = container_of(nb, struct musb, nb);
	struct device *dev = musb->controller;
	struct musb_hdrc_platform_data *pdata = dev->platform_data;
	struct omap_musb_board_data *data = pdata->board_data;

	switch (event) {
	case USB_EVENT_ID:
		dev_dbg(musb->controller, "ID GND\n");

		if (is_otg_enabled(musb)) {
			if (musb->gadget_driver) {
				pm_runtime_get_sync(musb->controller);
				otg_init(musb->xceiv);
				omap2430_musb_set_vbus(musb, 1);
			}
		} else {
			pm_runtime_get_sync(musb->controller);
			otg_init(musb->xceiv);
			omap2430_musb_set_vbus(musb, 1);
		}
		break;

	case USB_EVENT_VBUS:
		dev_dbg(musb->controller, "VBUS Connect\n");

		if (musb->gadget_driver)
			pm_runtime_get_sync(musb->controller);
		otg_init(musb->xceiv);
		break;

	case USB_EVENT_NONE:
		dev_dbg(musb->controller, "VBUS Disconnect\n");

		if (is_otg_enabled(musb) || is_peripheral_enabled(musb))
			if (musb->gadget_driver) {
				pm_runtime_mark_last_busy(musb->controller);
				pm_runtime_put_autosuspend(musb->controller);
			}

		if (data->interface_type == MUSB_INTERFACE_UTMI) {
			if (musb->xceiv->set_vbus)
				otg_set_vbus(musb->xceiv, 0);
		}
		otg_shutdown(musb->xceiv);
		break;
	default:
		dev_dbg(musb->controller, "ID float\n");
		return NOTIFY_DONE;
	}

	return NOTIFY_OK;
}
Example #2
0
/* blocking notifier support */
static int musb_otg_notifications(struct notifier_block *nb,
		unsigned long event, void *unused)
{
	struct musb	*musb = container_of(nb, struct musb, nb);
	struct device *dev = musb->controller;
	struct musb_hdrc_platform_data *pdata = dev->platform_data;
	struct omap_musb_board_data *data = pdata->board_data;

	switch (event) {
	case USB_EVENT_ID:
		DBG(4, "ID GND\n");

		if (is_otg_enabled(musb)) {
#ifdef CONFIG_USB_GADGET_MUSB_HDRC
			if (musb->gadget_driver) {
				otg_init(musb->xceiv);

				if (data->interface_type ==
						MUSB_INTERFACE_UTMI)
					omap2430_musb_set_vbus(musb, 1);

			}
#endif
		} else {
			otg_init(musb->xceiv);
			if (data->interface_type ==
					MUSB_INTERFACE_UTMI)
				omap2430_musb_set_vbus(musb, 1);
		}
		break;

	case USB_EVENT_VBUS:
		DBG(4, "VBUS Connect\n");

		otg_init(musb->xceiv);
		break;

	case USB_EVENT_NONE:
		DBG(4, "VBUS Disconnect\n");

		if (data->interface_type == MUSB_INTERFACE_UTMI) {
			if (musb->xceiv->set_vbus)
				otg_set_vbus(musb->xceiv, 0);
		}
		otg_shutdown(musb->xceiv);
		break;
	default:
		DBG(4, "ID float\n");
		return NOTIFY_DONE;
	}

	return NOTIFY_OK;
}
Example #3
0
static void omap2430_musb_enable(struct musb *musb)
{
	struct device *dev = musb->controller;
	struct musb_hdrc_platform_data *pdata = dev->platform_data;
	struct omap_musb_board_data *data = pdata->board_data;
	u32 val;

	switch (musb->xceiv->last_event) {

	case USB_EVENT_ID:
		val = musb_readl(musb->mregs, OTG_INTERFSEL);
		otg_set_suspend(musb->xceiv, 1);
		if (data->interface_type == MUSB_INTERFACE_UTMI) {
			val &= ~ULPI_12PIN;
			val |= UTMI_8BIT;
		} else {
			val |= ULPI_12PIN;
		}

		musb_writel(musb->mregs, OTG_INTERFSEL, val);
		otg_set_suspend(musb->xceiv, 0);
		otg_init(musb->xceiv);
		omap2430_musb_set_vbus(musb, 1);
		break;

	case USB_EVENT_VBUS:
		val = musb_readl(musb->mregs, OTG_INTERFSEL);
		otg_set_suspend(musb->xceiv, 1);
		if (data->interface_type ==
			MUSB_INTERFACE_UTMI) {
			val &= ~ULPI_12PIN;
			val |= UTMI_8BIT;
		} else {
			val |= ULPI_12PIN;
		}
		musb_writel(musb->mregs, OTG_INTERFSEL, val);
		otg_set_suspend(musb->xceiv, 0);
		otg_init(musb->xceiv);
		break;

	case USB_EVENT_CHARGER:
		dev_dbg(musb->controller, "Dedicated charger connect\n");
		musb->is_ac_charger = true;
		break;

	default:
		break;
	}
}
Example #4
0
static void musb_otg_notifier_work(struct work_struct *data_notifier_work)
{
	struct musb *musb = container_of(data_notifier_work, struct musb, otg_notifier_work);
	struct device *dev = musb->controller;
	struct musb_hdrc_platform_data *pdata = dev->platform_data;
	struct omap_musb_board_data *data = pdata->board_data;

	switch (musb->xceiv_event) {
	case USB_EVENT_ID:
		dev_dbg(musb->controller, "ID GND\n");

		if (!is_otg_enabled(musb) || musb->gadget_driver) {
			pm_runtime_get_sync(musb->controller);
			otg_init(musb->xceiv);
			omap2430_musb_set_vbus(musb, 1);
		}
		break;

	case USB_EVENT_VBUS:
		dev_dbg(musb->controller, "VBUS Connect\n");

		if (musb->gadget_driver)
			pm_runtime_get_sync(musb->controller);
		otg_init(musb->xceiv);
		break;

	case USB_EVENT_NONE:
		dev_dbg(musb->controller, "VBUS Disconnect\n");

		if (is_otg_enabled(musb) || is_peripheral_enabled(musb))
			if (musb->gadget_driver) {
				pm_runtime_mark_last_busy(musb->controller);
				pm_runtime_put_autosuspend(musb->controller);
			}

		if (data->interface_type == MUSB_INTERFACE_UTMI) {
			if (musb->xceiv->set_vbus)
				otg_set_vbus(musb->xceiv, 0);
		}
		otg_shutdown(musb->xceiv);
		break;
	default:
		dev_dbg(musb->controller, "ID float\n");
	}
}
Example #5
0
static void omap2430_musb_enable(struct musb *musb)
{
	u8		devctl;
	unsigned long timeout = jiffies + msecs_to_jiffies(1000);
	struct device *dev = musb->controller;
	struct musb_hdrc_platform_data *pdata = dev->platform_data;
	struct omap_musb_board_data *data = pdata->board_data;

	switch (musb->xceiv->last_event) {

	case USB_EVENT_ID:
		otg_init(musb->xceiv);
		if (data->interface_type == MUSB_INTERFACE_UTMI) {
			devctl = musb_readb(musb->mregs, MUSB_DEVCTL);
			/* start the session */
			devctl |= MUSB_DEVCTL_SESSION;
			musb_writeb(musb->mregs, MUSB_DEVCTL, devctl);
			while (musb_readb(musb->mregs, MUSB_DEVCTL) &
						MUSB_DEVCTL_BDEVICE) {
				cpu_relax();

				if (time_after(jiffies, timeout)) {
					dev_err(musb->controller,
					"configured as A device timeout");
					break;
				}
			}
		}
		break;

	case USB_EVENT_VBUS:
		otg_init(musb->xceiv);
		break;

	default:
		break;
	}
}
static int isp1301_otg_enable(struct isp1301 *isp)
{
	power_up(isp);
	otg_init(isp);

	/* NOTE:  since we don't change this, this provides
	 * a few more interrupts than are strictly needed.
	 */
	isp1301_set_bits(isp, ISP1301_INTERRUPT_RISING,
		INTR_VBUS_VLD | INTR_SESS_VLD | INTR_ID_GND);
	isp1301_set_bits(isp, ISP1301_INTERRUPT_FALLING,
		INTR_VBUS_VLD | INTR_SESS_VLD | INTR_ID_GND);

	dev_info(&isp->client->dev, "ready for dual-role USB ...\n");

	return 0;
}
Example #7
0
static void musb_otg_init(struct musb *musb)
{
	unsigned long flags = 0;
	pm_runtime_get_sync(musb->controller);

	/* reset musb controller */
#ifndef CONFIG_USB_SAMSUNG_OMAP_NORPM
	musb_otg_core_reset(musb);
#endif
	spin_lock_irqsave(&musb->lock, flags);
	if (otg_is_active(musb->xceiv))
		otg_set_suspend(musb->xceiv, 1);

	otg_set_suspend(musb->xceiv, 0);
	spin_unlock_irqrestore(&musb->lock, flags);

	otg_init(musb->xceiv);
	msleep(musb->otg_enum_delay);
	omap2430_musb_set_vbus(musb, 1);
	musb->otg_enum_delay = INIT_OTG_DELAY;
}
Example #8
0
 /* blocking notifier support */
int musb_notifier_call(struct notifier_block *nb,
		unsigned long event, void *unused)
{
	struct musb	*musb = container_of(nb, struct musb, nb);
	struct device *dev = musb->controller;
	struct musb_hdrc_platform_data *pdata = dev->platform_data;
	struct omap_musb_board_data *data = pdata->board_data;
	static int hostmode;
	u32 val;

	switch (event) {
	case USB_EVENT_ID:
		DBG(1, "ID GND\n");

		/* configure musb into smartidle with wakeup enabled
		 * smart standby mode.
		 */

		musb_writel(musb->mregs, OTG_FORCESTDBY, 0);
		val = musb_readl(musb->mregs, OTG_SYSCONFIG);
		if (cpu_is_omap44xx())
			val |= SMARTIDLEWKUP | SMARTSTDBY | ENABLEWAKEUP;
		else
			val |= SMARTIDLE | SMARTSTDBY | ENABLEWAKEUP;
		musb_writel(musb->mregs, OTG_SYSCONFIG, val);

		if (data->interface_type == MUSB_INTERFACE_UTMI) {
			otg_init(musb->xceiv);
			hostmode = 1;
			musb_enable_vbus(musb);
		}

		val = __raw_readl(phymux_base +
				USBA0_OTG_CE_PAD1_USBA0_OTG_DP);

		val |= DP_WAKEUPENABLE;
		__raw_writel(val, phymux_base +
					USBA0_OTG_CE_PAD1_USBA0_OTG_DP);

		break;

	case USB_EVENT_VBUS:
		DBG(1, "VBUS Connect\n");

		/* configure musb into smartidle with wakeup enabled
		 * smart standby mode.
		 */
		musb_writel(musb->mregs, OTG_FORCESTDBY, 0);
		val = musb_readl(musb->mregs, OTG_SYSCONFIG);
		if (cpu_is_omap44xx())
			val |= SMARTIDLEWKUP | SMARTSTDBY | ENABLEWAKEUP;
		else
			val |= SMARTIDLE | SMARTSTDBY | ENABLEWAKEUP;
		musb_writel(musb->mregs, OTG_SYSCONFIG, val);

		if (data->interface_type == MUSB_INTERFACE_UTMI) {
			otg_init(musb->xceiv);
			if (!hostmode) {
				/* Enable VBUS Valid, AValid. Clear SESSEND.*/
				__raw_writel(IDDIG | AVALID | VBUSVALID,
					ctrl_base + USBOTGHS_CONTROL);
			}
		}

		break;

	case USB_EVENT_NONE:
		DBG(1, "VBUS Disconnect\n");

		if (data->interface_type == MUSB_INTERFACE_UTMI) {
			/* enable this clock because in suspend interrupt
			 * handler phy clocks are disabled. If phy clocks are
			 * not enabled then DISCONNECT interrupt will not be
			 * reached to mentor
			 */
			otg_set_clk(musb->xceiv, 1);
			__raw_writel(SESSEND | IDDIG, ctrl_base +
							USBOTGHS_CONTROL);
			if (musb->xceiv->set_vbus)
				otg_set_vbus(musb->xceiv, 0);
			otg_shutdown(musb->xceiv);
		}
		hostmode = 0;
		/* configure in force idle/ standby */
		musb_writel(musb->mregs, OTG_FORCESTDBY, 1);
		val = musb_readl(musb->mregs, OTG_SYSCONFIG);
		val &= ~(SMARTIDLEWKUP | SMARTSTDBY | ENABLEWAKEUP);
		val |= FORCEIDLE | FORCESTDBY;
		musb_writel(musb->mregs, OTG_SYSCONFIG, val);

		val = __raw_readl(phymux_base +
				USBA0_OTG_CE_PAD1_USBA0_OTG_DP);

		val &= ~DP_WAKEUPENABLE;
		__raw_writel(val, phymux_base +
					USBA0_OTG_CE_PAD1_USBA0_OTG_DP);
		break;
	default:
		DBG(1, "ID float\n");
		return NOTIFY_DONE;
	}

	return NOTIFY_OK;
}
Example #9
0
static void musb_otg_notifier_work(struct work_struct *data_notifier_work)
{
	struct musb_otg_work *otg_work =
		container_of(data_notifier_work, struct musb_otg_work, work);
        struct musb *musb = otg_work->musb;
	struct device *dev = musb->controller;
	struct musb_hdrc_platform_data *pdata = dev->platform_data;
	struct omap_musb_board_data *data = pdata->board_data;
	enum usb_xceiv_events xceiv_event = otg_work->xceiv_event;

	kfree(otg_work);

	switch (xceiv_event) {
	case USB_EVENT_ID:
		dev_dbg(musb->controller, "ID GND\n");

		if (is_otg_enabled(musb)) {
#ifdef CONFIG_USB_GADGET_MUSB_HDRC
			if (musb->gadget_driver) {
				pm_runtime_get_sync(musb->controller);
				otg_init(musb->xceiv);
				omap2430_musb_set_vbus(musb, 1);
			}
#endif
		} else {
			pm_runtime_get_sync(musb->controller);
			otg_init(musb->xceiv);
			omap2430_musb_set_vbus(musb, 1);
		}
		break;

	case USB_EVENT_CHARGER:
		dev_dbg(musb->controller, "Dedicated charger connect\n");
		musb->is_ac_charger = true;
		break;

	case USB_EVENT_VBUS:
		dev_dbg(musb->controller, "VBUS Connect\n");

#ifdef CONFIG_USB_GADGET_MUSB_HDRC
		if (musb->gadget_driver)
			pm_runtime_get_sync(musb->controller);
#endif
		otg_init(musb->xceiv);
		break;

	case USB_EVENT_NONE:
		if (musb->is_ac_charger) {
			dev_dbg(musb->controller,
				"Dedicated charger disconnect\n");
			musb->is_ac_charger = false;
			break;
		}

		dev_dbg(musb->controller, "VBUS Disconnect\n");

#ifdef CONFIG_USB_GADGET_MUSB_HDRC
		if (is_otg_enabled(musb) || is_peripheral_enabled(musb))
			if (musb->gadget_driver)
#endif
			{
				pm_runtime_mark_last_busy(musb->controller);
				pm_runtime_put_autosuspend(musb->controller);
			}

		if (data->interface_type == MUSB_INTERFACE_UTMI) {
			omap2430_musb_set_vbus(musb, 0);
			if (musb->xceiv->set_vbus)
				otg_set_vbus(musb->xceiv, 0);
		}
		otg_shutdown(musb->xceiv);
		break;
	default:
		dev_dbg(musb->controller, "ID float\n");
		return;
	}

	return;
}
Example #10
0
static void musb_otg_notifier_work(struct work_struct *data_notifier_work)
{
	struct musb_otg_work *otg_work =
		container_of(data_notifier_work, struct musb_otg_work, work);
	struct musb *musb = otg_work->musb;
	struct device *dev = musb->controller;
	struct musb_hdrc_platform_data *pdata = dev->platform_data;
	struct omap_musb_board_data *data = pdata->board_data;
	enum usb_xceiv_events xceiv_event = otg_work->xceiv_event;
	unsigned long	flags;
#ifdef CONFIG_USB_SAMSUNG_OMAP_NORPM
	int ret = 0;
#endif

	kfree(otg_work);

	switch (xceiv_event) {
	case USB_EVENT_ID:
		dev_info(musb->controller, "ID GND\n");
		musb->xceiv->state = OTG_STATE_A_IDLE;
#ifdef CONFIG_USB_SAMSUNG_OMAP_NORPM
		ret = omap2430_async_resume(musb);
		if (ret < 0)
			return;
#endif
		if (is_otg_enabled(musb)) {
#ifdef CONFIG_USB_GADGET_MUSB_HDRC
			if (musb->gadget_driver) {
				musb_otg_init(musb);
			}
#endif
		} else {
			musb_otg_init(musb);
		}
#ifdef CONFIG_USB_SAMSUNG_OMAP_NORPM
		musb_add_hcd(musb);
#endif
		break;
	case USB_EVENT_VBUS_CHARGER:
		dev_info(musb->controller, "USB/TA Connect\n");
		/*  This event received from ta_connect_irq
		 * when a usb cable is connected. Logic has still
		 * not identified whether this is a usb cable or TA.
		 *  So just break here.
		 */
		break;
	case USB_EVENT_VBUS:
		dev_info(musb->controller, "VBUS Connect\n");
#ifdef CONFIG_USB_SAMSUNG_OMAP_NORPM
		ret = omap2430_async_resume(musb);
		if (ret < 0)
			return;
#endif
#ifdef CONFIG_USB_GADGET_MUSB_HDRC
		if (musb->gadget_driver)
			pm_runtime_get_sync(musb->controller);
#endif
		otg_init(musb->xceiv);
#ifdef CONFIG_USB_SAMSUNG_OMAP_NORPM
		musb_start(musb);
		musb_platform_pullup(musb, 1);
#endif
		break;

	case USB_EVENT_CHARGER:
		dev_info(musb->controller, "Dedicated charger connect\n");
		musb->is_ac_charger = true;
		break;
	case USB_EVENT_HOST_NONE:
#ifdef CONFIG_USB_SAMSUNG_OMAP_NORPM
		dev_info(musb->controller, "USB host Disconnect. ID float\n");
		if (!omap2430_async_resumed(musb)) {
			dev_err(musb->controller, "async suspended. abnormal state.\n");
			return;
		}
		musb_stop(musb);
		musb_remove_hcd(musb);
		if (data->interface_type == MUSB_INTERFACE_UTMI) {
			omap2430_musb_set_vbus(musb, 0);
			if (musb->xceiv->set_vbus)
				otg_set_vbus(musb->xceiv, 0);
		}
		otg_shutdown(musb->xceiv);
		musb_otg_core_reset(musb);
		ret = omap2430_async_suspend(musb);
		if (ret < 0)
			return;
		break;
#endif
	case USB_EVENT_NONE:
		if (musb->is_ac_charger) {
			dev_info(musb->controller,
				"Dedicated charger disconnect\n");
			musb->is_ac_charger = false;
			break;
		}

		dev_info(musb->controller, "VBUS Disconnect\n");
#ifndef CONFIG_USB_SAMSUNG_OMAP_NORPM
		if (pm_runtime_suspended(musb->controller)) {
			dev_err(musb->controller, "runtime pm suspended. abnormal state.\n");
			return;
		}
		spin_lock_irqsave(&musb->lock, flags);
		musb_g_disconnect(musb);
		spin_unlock_irqrestore(&musb->lock, flags);

#ifdef CONFIG_USB_GADGET_MUSB_HDRC
		if (is_otg_enabled(musb) || is_peripheral_enabled(musb))
			if (musb->gadget_driver)
#endif
			{
				pm_runtime_mark_last_busy(musb->controller);
				pm_runtime_put_autosuspend(musb->controller);
			}

		if (data->interface_type == MUSB_INTERFACE_UTMI) {
			omap2430_musb_set_vbus(musb, 0);
			if (musb->xceiv->set_vbus)
				otg_set_vbus(musb->xceiv, 0);
		}
		otg_shutdown(musb->xceiv);
#else
		if (!omap2430_async_resumed(musb)) {
			dev_err(musb->controller, "async suspended. abnormal state.\n");
			return;
		}
		musb_platform_pullup(musb, 0);
		spin_lock_irqsave(&musb->lock, flags);
		musb_stop(musb);
		musb_g_disconnect(musb);
		musb_all_ep_flush(musb);
		spin_unlock_irqrestore(&musb->lock, flags);
		if (data->interface_type == MUSB_INTERFACE_UTMI)
			omap2430_musb_set_vbus(musb, 0);
		otg_shutdown(musb->xceiv);
		musb_otg_core_reset(musb);
		ret = omap2430_async_suspend(musb);
		if (ret < 0)
			return;
#endif
		break;
	default:
		dev_info(musb->controller, "ID float\n");
	}
}
Example #11
0
static int ehci_mxc_drv_probe(struct platform_device *pdev)
{
	struct mxc_usbh_platform_data *pdata = pdev->dev.platform_data;
	struct usb_hcd *hcd;
	struct resource *res;
	int irq, ret;
	unsigned int flags;
	struct ehci_mxc_priv *priv;
	struct device *dev = &pdev->dev;
	struct ehci_hcd *ehci;

	dev_info(&pdev->dev, "initializing i.MX USB Controller\n");

	if (!pdata) {
		dev_err(dev, "No platform data given, bailing out.\n");
		return -EINVAL;
	}

	irq = platform_get_irq(pdev, 0);

	hcd = usb_create_hcd(&ehci_mxc_hc_driver, dev, dev_name(dev));
	if (!hcd)
		return -ENOMEM;

	priv = kzalloc(sizeof(*priv), GFP_KERNEL);
	if (!priv) {
		ret = -ENOMEM;
		goto err_alloc;
	}

	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
	if (!res) {
		dev_err(dev, "Found HC with no register addr. Check setup!\n");
		ret = -ENODEV;
		goto err_get_resource;
	}

	hcd->rsrc_start = res->start;
	hcd->rsrc_len = resource_size(res);

	if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len, hcd_name)) {
		dev_dbg(dev, "controller already in use\n");
		ret = -EBUSY;
		goto err_request_mem;
	}

	hcd->regs = ioremap(hcd->rsrc_start, hcd->rsrc_len);
	if (!hcd->regs) {
		dev_err(dev, "error mapping memory\n");
		ret = -EFAULT;
		goto err_ioremap;
	}

	/* enable clocks */
	priv->usbclk = clk_get(dev, "usb");
	if (IS_ERR(priv->usbclk)) {
		ret = PTR_ERR(priv->usbclk);
		goto err_clk;
	}
	clk_enable(priv->usbclk);

	if (!cpu_is_mx35() && !cpu_is_mx25()) {
		priv->ahbclk = clk_get(dev, "usb_ahb");
		if (IS_ERR(priv->ahbclk)) {
			ret = PTR_ERR(priv->ahbclk);
			goto err_clk_ahb;
		}
		clk_enable(priv->ahbclk);
	}

	/* "dr" device has its own clock on i.MX51 */
	if (cpu_is_mx51() && (pdev->id == 0)) {
		priv->phy1clk = clk_get(dev, "usb_phy1");
		if (IS_ERR(priv->phy1clk)) {
			ret = PTR_ERR(priv->phy1clk);
			goto err_clk_phy;
		}
		clk_enable(priv->phy1clk);
	}


	/* call platform specific init function */
	if (pdata->init) {
		ret = pdata->init(pdev);
		if (ret) {
			dev_err(dev, "platform init failed\n");
			goto err_init;
		}
		/* platforms need some time to settle changed IO settings */
		mdelay(10);
	}

	ehci = hcd_to_ehci(hcd);

	/* EHCI registers start at offset 0x100 */
	ehci->caps = hcd->regs + 0x100;
	ehci->regs = hcd->regs + 0x100 +
		HC_LENGTH(ehci, ehci_readl(ehci, &ehci->caps->hc_capbase));

	/* set up the PORTSCx register */
	ehci_writel(ehci, pdata->portsc, &ehci->regs->port_status[0]);

	/* is this really needed? */
	msleep(10);

	/* Initialize the transceiver */
	if (pdata->otg) {
		pdata->otg->io_priv = hcd->regs + ULPI_VIEWPORT_OFFSET;
		ret = otg_init(pdata->otg);
		if (ret) {
			dev_err(dev, "unable to init transceiver, probably missing\n");
			ret = -ENODEV;
			goto err_add;
		}
		ret = otg_set_vbus(pdata->otg, 1);
		if (ret) {
			dev_err(dev, "unable to enable vbus on transceiver\n");
			goto err_add;
		}
	}

	priv->hcd = hcd;
	platform_set_drvdata(pdev, priv);

	ret = usb_add_hcd(hcd, irq, IRQF_DISABLED | IRQF_SHARED);
	if (ret)
		goto err_add;

	if (pdata->otg) {
		/*
		 * efikamx and efikasb have some hardware bug which is
		 * preventing usb to work unless CHRGVBUS is set.
		 * It's in violation of USB specs
		 */
		if (machine_is_mx51_efikamx() || machine_is_mx51_efikasb()) {
			flags = otg_io_read(pdata->otg, ULPI_OTG_CTRL);
			flags |= ULPI_OTG_CTRL_CHRGVBUS;
			ret = otg_io_write(pdata->otg, flags, ULPI_OTG_CTRL);
			if (ret) {
				dev_err(dev, "unable to set CHRVBUS\n");
				goto err_add;
			}
		}
	}

	return 0;

err_add:
	if (pdata && pdata->exit)
		pdata->exit(pdev);
err_init:
	if (priv->phy1clk) {
		clk_disable(priv->phy1clk);
		clk_put(priv->phy1clk);
	}
err_clk_phy:
	if (priv->ahbclk) {
		clk_disable(priv->ahbclk);
		clk_put(priv->ahbclk);
	}
err_clk_ahb:
	clk_disable(priv->usbclk);
	clk_put(priv->usbclk);
err_clk:
	iounmap(hcd->regs);
err_ioremap:
	release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
err_request_mem:
err_get_resource:
	kfree(priv);
err_alloc:
	usb_put_hcd(hcd);
	return ret;
}
Example #12
0
static int ehci_mxc_drv_probe(struct platform_device *pdev)
{
	struct mxc_usbh_platform_data *pdata = pdev->dev.platform_data;
	struct usb_hcd *hcd;
	struct resource *res;
	int irq, ret, temp;
	struct ehci_mxc_priv *priv;
	struct device *dev = &pdev->dev;

	dev_info(&pdev->dev, "initializing i.MX USB Controller\n");

	if (!pdata) {
		dev_err(dev, "No platform data given, bailing out.\n");
		return -EINVAL;
	}

	irq = platform_get_irq(pdev, 0);

	hcd = usb_create_hcd(&ehci_mxc_hc_driver, dev, dev_name(dev));
	if (!hcd)
		return -ENOMEM;

	priv = kzalloc(sizeof(*priv), GFP_KERNEL);
	if (!priv) {
		ret = -ENOMEM;
		goto err_alloc;
	}

	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
	if (!res) {
		dev_err(dev, "Found HC with no register addr. Check setup!\n");
		ret = -ENODEV;
		goto err_get_resource;
	}

	hcd->rsrc_start = res->start;
	hcd->rsrc_len = resource_size(res);

	if (!request_mem_region(hcd->rsrc_start, hcd->rsrc_len, hcd_name)) {
		dev_dbg(dev, "controller already in use\n");
		ret = -EBUSY;
		goto err_request_mem;
	}

	hcd->regs = ioremap(hcd->rsrc_start, hcd->rsrc_len);
	if (!hcd->regs) {
		dev_err(dev, "error mapping memory\n");
		ret = -EFAULT;
		goto err_ioremap;
	}

	/* call platform specific init function */
	if (pdata->init) {
		ret = pdata->init(pdev);
		if (ret) {
			dev_err(dev, "platform init failed\n");
			goto err_init;
		}
		/* platforms need some time to settle changed IO settings */
		mdelay(10);
	}

	/* enable clocks */
	priv->usbclk = clk_get(dev, "usb");
	if (IS_ERR(priv->usbclk)) {
		ret = PTR_ERR(priv->usbclk);
		goto err_clk;
	}
	clk_enable(priv->usbclk);

	if (!cpu_is_mx35() && !cpu_is_mx25()) {
		priv->ahbclk = clk_get(dev, "usb_ahb");
		if (IS_ERR(priv->ahbclk)) {
			ret = PTR_ERR(priv->ahbclk);
			goto err_clk_ahb;
		}
		clk_enable(priv->ahbclk);
	}

	/* set USBMODE to host mode */
	temp = readl(hcd->regs + USBMODE_OFFSET);
	writel(temp | USBMODE_CM_HOST, hcd->regs + USBMODE_OFFSET);

	/* set up the PORTSCx register */
	writel(pdata->portsc, hcd->regs + PORTSC_OFFSET);
	mdelay(10);

	/* setup specific usb hw */
	ret = mxc_initialize_usb_hw(pdev->id, pdata->flags);
	if (ret < 0)
		goto err_init;

	/* Initialize the transceiver */
	if (pdata->otg) {
		pdata->otg->io_priv = hcd->regs + ULPI_VIEWPORT_OFFSET;
		ret = otg_init(pdata->otg);
		if (ret) {
			dev_err(dev, "unable to init transceiver, probably missing\n");
			ret = -ENODEV;
			goto err_add;
		}
		ret = otg_set_vbus(pdata->otg, 1);
		if (ret) {
			dev_err(dev, "unable to enable vbus on transceiver\n");
			goto err_add;
		}
	}

	priv->hcd = hcd;
	platform_set_drvdata(pdev, priv);

	ret = usb_add_hcd(hcd, irq, IRQF_DISABLED | IRQF_SHARED);
	if (ret)
		goto err_add;

	return 0;

err_add:
	if (pdata && pdata->exit)
		pdata->exit(pdev);
err_init:
	if (priv->ahbclk) {
		clk_disable(priv->ahbclk);
		clk_put(priv->ahbclk);
	}
err_clk_ahb:
	clk_disable(priv->usbclk);
	clk_put(priv->usbclk);
err_clk:
	iounmap(hcd->regs);
err_ioremap:
	release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
err_request_mem:
err_get_resource:
	kfree(priv);
err_alloc:
	usb_put_hcd(hcd);
	return ret;
}
Example #13
0
static void musb_otg_notifier_work(struct work_struct *data_notifier_work)
{
	u32 val;
	struct musb_otg_work *otg_work =
		container_of(data_notifier_work, struct musb_otg_work, work);
        struct musb *musb = otg_work->musb;
	struct device *dev = musb->controller;
	struct musb_hdrc_platform_data *pdata = dev->platform_data;
	struct omap_musb_board_data *data = pdata->board_data;
	enum usb_xceiv_events xceiv_event = otg_work->xceiv_event;
	static int last_event = -1;

	kfree(otg_work);

	/* avoid duplicate notifications */
	if (last_event == xceiv_event) {
		WARN(1, "Duplicated event(%d): ignored\n", xceiv_event);
		return;
	}
	/* check for incorrect transitions */
	if ((last_event == USB_EVENT_VBUS && xceiv_event == USB_EVENT_ID) ||
			(last_event == USB_EVENT_ID  && xceiv_event == USB_EVENT_VBUS)) {
		WARN(1, "Incorrect transition (%d)->(%d)\n", last_event, xceiv_event);
	}
	/* store last event */
	last_event = xceiv_event;

	switch (xceiv_event) {
	case USB_EVENT_ID:
		dev_dbg(musb->controller, "ID GND\n");

		if (is_otg_enabled(musb)) {
#ifdef CONFIG_USB_GADGET_MUSB_HDRC
			if (musb->gadget_driver) {
				pm_runtime_get_sync(musb->controller);
				val = musb_readl(musb->mregs, OTG_INTERFSEL);
				otg_set_suspend(musb->xceiv, 1);
				if (data->interface_type ==
						MUSB_INTERFACE_UTMI) {
					val &= ~ULPI_12PIN;
					val |= UTMI_8BIT;
				} else {
					val |= ULPI_12PIN;
				}
				musb_writel(musb->mregs, OTG_INTERFSEL, val);
				otg_set_suspend(musb->xceiv, 0);

				otg_init(musb->xceiv);
				omap2430_musb_set_vbus(musb, 1);
			}
#endif
		} else {
			pm_runtime_get_sync(musb->controller);
			val = musb_readl(musb->mregs, OTG_INTERFSEL);
			otg_set_suspend(musb->xceiv, 1);
			if (data->interface_type == MUSB_INTERFACE_UTMI) {
				val &= ~ULPI_12PIN;
				val |= UTMI_8BIT;
			} else {
				val |= ULPI_12PIN;
			}
			musb_writel(musb->mregs, OTG_INTERFSEL, val);
			otg_set_suspend(musb->xceiv, 0);

			otg_init(musb->xceiv);
			omap2430_musb_set_vbus(musb, 1);
		}
		break;

	case USB_EVENT_CHARGER:
		dev_dbg(musb->controller, "Dedicated charger connect\n");
		musb->is_ac_charger = true;
		break;

	case USB_EVENT_VBUS:
		dev_dbg(musb->controller, "VBUS Connect\n");

#ifdef CONFIG_USB_GADGET_MUSB_HDRC
		if (musb->gadget_driver) {
			pm_runtime_get_sync(musb->controller);
			val = musb_readl(musb->mregs, OTG_INTERFSEL);
			otg_set_suspend(musb->xceiv, 1);
			if (data->interface_type ==
					MUSB_INTERFACE_UTMI) {
				val &= ~ULPI_12PIN;
				val |= UTMI_8BIT;
			} else {
				val |= ULPI_12PIN;
			}
			musb_writel(musb->mregs, OTG_INTERFSEL, val);
			otg_set_suspend(musb->xceiv, 0);
		}

#endif
		otg_init(musb->xceiv);
		break;

	case USB_EVENT_NONE:
		if (musb->is_ac_charger) {
			dev_dbg(musb->controller,
				"Dedicated charger disconnect\n");
			musb->is_ac_charger = false;
			break;
		}

		dev_dbg(musb->controller, "VBUS Disconnect\n");
		pm_runtime_get_sync(musb->controller);

		if (data->interface_type == MUSB_INTERFACE_UTMI) {
			omap2430_musb_set_vbus(musb, 0);
			if (musb->xceiv->set_vbus)
				otg_set_vbus(musb->xceiv, 0);
		}
		otg_shutdown(musb->xceiv);
		otg_set_suspend(musb->xceiv, 1);

		val = musb_readl(musb->mregs, OTG_INTERFSEL);
		val |= ULPI_12PIN;
		musb_writel(musb->mregs, OTG_INTERFSEL, val);
		pm_runtime_mark_last_busy(musb->controller);
		pm_runtime_put_autosuspend(musb->controller);

#ifdef CONFIG_USB_GADGET_MUSB_HDRC
		if (is_otg_enabled(musb) || is_peripheral_enabled(musb))
			if (musb->gadget_driver)
#endif
				pm_runtime_put_autosuspend(musb->controller);
		break;
	default:
		dev_dbg(musb->controller, "ID float\n");
	}

}
Example #14
0
 /* blocking notifier support */
void cpcap_musb_notifier_call(unsigned long event)
{
	struct musb	*musb = g_musb;
	struct device *dev = musb->controller;
	struct musb_hdrc_platform_data *pdata = dev->platform_data;
	struct omap_musb_board_data *data = pdata->board_data;
	static int hostmode;
	u32 val;
	u8 power;

	switch (event) {
	case USB_EVENT_ID:
		DBG(1, "ID GND\n");

		/* configure musb into smartidle with wakeup enabled
		 * smart standby mode.
		 */

		omap_pm_set_max_mpu_wakeup_lat(&pdata->musb_qos_request, 4000);

		musb_writel(musb->mregs, OTG_FORCESTDBY, 0);
		val = musb_readl(musb->mregs, OTG_SYSCONFIG);
		if (cpu_is_omap44xx())
			val |= SMARTIDLEWKUP | SMARTSTDBY | ENABLEWAKEUP;
		else
			val |= SMARTIDLE | SMARTSTDBY | ENABLEWAKEUP;
		musb_writel(musb->mregs, OTG_SYSCONFIG, val);

		if (data->interface_type == MUSB_INTERFACE_UTMI) {
			phy_init();
			otg_init(musb->xceiv);
			/* enable VBUS valid, id groung*/
			__raw_writel(AVALID | VBUSVALID, ctrl_base +
							USBOTGHS_CONTROL);
			val = __raw_readl(phymux_base +
					USBA0_OTG_CE_PAD1_USBA0_OTG_DP);

			val |= DP_WAKEUPENABLE;
			__raw_writel(val, phymux_base +
						USBA0_OTG_CE_PAD1_USBA0_OTG_DP);
		}

		hostmode = 1;
		musb_start(musb);
		musb_set_vbus(musb, 1);

		break;

	case USB_EVENT_VBUS:
		DBG(1, "VBUS Connect\n");

		/* configure musb into smartidle with wakeup enabled
		 * smart standby mode.
		 */
		musb_writel(musb->mregs, OTG_FORCESTDBY, 0);
		val = musb_readl(musb->mregs, OTG_SYSCONFIG);
		if (cpu_is_omap44xx())
			val |= SMARTIDLEWKUP | SMARTSTDBY | ENABLEWAKEUP;
		else
			val |= SMARTIDLE | SMARTSTDBY | ENABLEWAKEUP;
		musb_writel(musb->mregs, OTG_SYSCONFIG, val);

		power = musb_readb(musb->mregs, MUSB_POWER);
		power &= ~MUSB_POWER_SOFTCONN;
		musb_writeb(musb->mregs, MUSB_POWER, power);


		if (data->interface_type == MUSB_INTERFACE_UTMI) {
			phy_init();
			otg_init(musb->xceiv);
			if (!hostmode) {
				/* Enable VBUS Valid, AValid. Clear SESSEND.*/
				__raw_writel(IDDIG | AVALID | VBUSVALID,
					ctrl_base + USBOTGHS_CONTROL);
			}
		}

		break;

	case USB_EVENT_NONE:
		DBG(1, "VBUS Disconnect\n");

		if (data->interface_type == MUSB_INTERFACE_UTMI) {
			/* enable this clock because in suspend interrupt
			 * handler phy clocks are disabled. If phy clocks are
			 * not enabled then DISCONNECT interrupt will not be
			 * reached to mentor
			 */
			otg_set_clk(musb->xceiv, 1);
			__raw_writel(SESSEND | IDDIG, ctrl_base +
							USBOTGHS_CONTROL);
			if (musb->xceiv->set_vbus)
				otg_set_vbus(musb->xceiv, 0);
			otg_shutdown(musb->xceiv);
			phy_shutdown();
		}
		/* configure in force idle/ standby */
		musb_writel(musb->mregs, OTG_FORCESTDBY, 1);
		val = musb_readl(musb->mregs, OTG_SYSCONFIG);
		val &= ~(SMARTIDLEWKUP | SMARTSTDBY | ENABLEWAKEUP);
		val |= FORCEIDLE | FORCESTDBY;
		musb_writel(musb->mregs, OTG_SYSCONFIG, val);

		omap_pm_set_max_mpu_wakeup_lat(&pdata->musb_qos_request, -1);

		if (data->interface_type == MUSB_INTERFACE_UTMI) {
			val = __raw_readl(phymux_base +
					USBA0_OTG_CE_PAD1_USBA0_OTG_DP);

			val &= ~DP_WAKEUPENABLE;
			__raw_writel(val, phymux_base +
						USBA0_OTG_CE_PAD1_USBA0_OTG_DP);
		}

		if (hostmode) {
			musb_stop(musb);
			musb_set_vbus(musb, 0);
		}
		hostmode = 0;
		break;
	default:
		DBG(1, "ID float\n");
	}

}
Example #15
0
static void musb_otg_notifier_work(struct work_struct *data_notifier_work)
{
    u32 val;
    struct musb_otg_work *otg_work =
        container_of(data_notifier_work, struct musb_otg_work, work);
    struct musb *musb = otg_work->musb;
    struct device *dev = musb->controller;
    struct musb_hdrc_platform_data *pdata = dev->platform_data;
    struct omap_musb_board_data *data = pdata->board_data;
    enum usb_xceiv_events xceiv_event = otg_work->xceiv_event;
    int status;

    kfree(otg_work);

    if (xceiv_event == xceiv_event_last) {
        /* sync pm runtime if already got */
        if (xceiv_event == USB_EVENT_VBUS || xceiv_event == USB_EVENT_ID) {
            pm_runtime_put_sync(musb->controller);
        }
    }

    xceiv_event_last = xceiv_event;

    switch (xceiv_event) {
    case USB_EVENT_ID:
        dev_dbg(musb->controller, "ID GND\n");
        pm_runtime_get_sync(musb->controller);

        if (is_otg_enabled(musb)) {
#ifdef CONFIG_USB_GADGET_MUSB_HDRC
            if (musb->gadget_driver) {
                val = musb_readl(musb->mregs, OTG_INTERFSEL);
                if (data->interface_type ==
                        MUSB_INTERFACE_UTMI) {
                    val &= ~ULPI_12PIN;
                    val |= UTMI_8BIT;
                } else {
                    val |= ULPI_12PIN;
                }
                musb_writel(musb->mregs, OTG_INTERFSEL, val);

                otg_init(musb->xceiv);
                omap2430_musb_set_vbus(musb, 1);
            }
#endif
        } else {
            val = musb_readl(musb->mregs, OTG_INTERFSEL);
            if (data->interface_type == MUSB_INTERFACE_UTMI) {
                val &= ~ULPI_12PIN;
                val |= UTMI_8BIT;
            } else {
                val |= ULPI_12PIN;
            }
            musb_writel(musb->mregs, OTG_INTERFSEL, val);

            otg_init(musb->xceiv);
            omap2430_musb_set_vbus(musb, 1);
        }
        break;

    case USB_EVENT_CHARGER:
        dev_dbg(musb->controller, "Dedicated charger connect\n");
        musb->is_ac_charger = true;
        break;

    case USB_EVENT_VBUS:
        dev_dbg(musb->controller, "VBUS Connect\n");
        pm_runtime_get_sync(musb->controller);

#ifdef CONFIG_USB_GADGET_MUSB_HDRC
        if (musb->gadget_driver) {
            val = musb_readl(musb->mregs, OTG_INTERFSEL);
            if (data->interface_type ==
                    MUSB_INTERFACE_UTMI) {
                val &= ~ULPI_12PIN;
                val |= UTMI_8BIT;
            } else {
                val |= ULPI_12PIN;
            }
            musb_writel(musb->mregs, OTG_INTERFSEL, val);
        }

#endif
        otg_init(musb->xceiv);
        break;

    case USB_EVENT_NONE:
        if (musb->is_ac_charger) {
            dev_dbg(musb->controller,
                    "Dedicated charger disconnect\n");
            musb->is_ac_charger = false;
            break;
        }

        dev_dbg(musb->controller, "VBUS Disconnect\n");

//		pm_runtime_get_sync(musb->controller);

        if (data->interface_type == MUSB_INTERFACE_UTMI) {
            omap2430_musb_set_vbus(musb, 0);
            if (musb->xceiv->set_vbus)
                otg_set_vbus(musb->xceiv, 0);
        }
        otg_shutdown(musb->xceiv);
        val = musb_readl(musb->mregs, OTG_INTERFSEL);
        val |= ULPI_12PIN;
        musb_writel(musb->mregs, OTG_INTERFSEL, val);

#ifdef CONFIG_USB_GADGET_MUSB_HDRC
        if (is_otg_enabled(musb) || is_peripheral_enabled(musb)) {
            if (musb->gadget_driver)
#endif
            {
                pm_runtime_mark_last_busy(musb->controller);
                pm_runtime_put_autosuspend(musb->controller);
            }
#ifdef CONFIG_USB_GADGET_MUSB_HDRC
            else {
                pm_runtime_put_sync(musb->controller);
            }
        } else {
            pm_runtime_put_sync(musb->controller);
        }
#endif
        break;
    default:
        dev_dbg(musb->controller, "ID float\n");
    }
}
Example #16
0
/*!
 * zasevb_modinit() - linux module initialization
 *
 * This needs to initialize the hcd, pcd and tcd drivers. This includes tcd and possibly hcd
 * for some architectures.
 *
 */
static int zasevb_modinit (void)
{
        struct otg_instance *otg = NULL;

        #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,15)
        struct clk *clk = clk_get(NULL, "usb_clk");
        clk_enable(clk);
        clk_put(clk);
        #endif

        THROW_UNLESS((otg = otg_create()), error);

        mxc_pcd_ops_init();
        #if !defined(OTG_C99)
        pcd_global_init();
        fs_ocd_global_init();
        zasevb_tcd_global_init();
        fs_pcd_global_init();
        #endif /* !defined(OTG_C99) */

        ZAS = otg_trace_obtain_tag(otg, "zas");

        mxc_procfs_init();

        TRACE_MSG0(ZAS, "1. ZAS");

        #if 0
        /* ZAS EVB Platform setup
         */
        TRACE_MSG4(ZAS, "BCTRL Version: %04x Status: %04x 1: %04x 2: %04x",
                        readw(PBC_BASE_ADDRESS ),
                        readw(PBC_BASE_ADDRESS + PBC_BSTAT),
                        readw(PBC_BASE_ADDRESS + PBC_BCTRL1_SET),
                        readw(PBC_BASE_ADDRESS + PBC_BCTRL2_SET));

        #endif

        /* ZAS EVB Clock setup
         */

#if defined(CONFIG_ARCH_ARGONPLUS) || defined(CONFIG_ARCH_ARGONLV)
#define ZASEVB_MULTIPLIER       12
#define ZASEVB_DIVISOR          775             // ~10.
#else
#define ZASEVB_MULTIPLIER       12
#define ZASEVB_DIVISOR 155
#endif

        TRACE_MSG0(ZAS, "2. Setup GPT");

        THROW_UNLESS(ocd_instance = otg_set_ocd_ops(otg, &ocd_ops), error);
        REMOVE_OCD = ocd_instance->TAG;
        // XXX THROW_IF((ocd_ops.mod_init ? ocd_ops.mod_init() : 0), error);

        #if defined(CONFIG_OTG_GPTR)
        mxc_gptcr_mod_init(ZASEVB_DIVISOR, ZASEVB_MULTIPLIER);
        #endif /* defined(CONFIG_OTG_GPTR) */

        #if defined(CONFIG_OTG_HRT)
        mxc_hrt_mod_init(otg, ZASEVB_DIVISOR, ZASEVB_MULTIPLIER);
        #endif /* defined(CONFIG_OTG_GPTR) */


        #if !defined(CONFIG_USB_HOST)
        TRACE_MSG0(ZAS, "3. PCD");
        THROW_UNLESS(REMOVE_pcd_instance = otg_set_pcd_ops(otg, &pcd_ops), error);
        REMOVE_PCD = REMOVE_pcd_instance->TAG;
        // XXX THROW_IF((pcd_ops.mod_init ? pcd_ops.mod_init() : 0), error);
        #else /* !defined(CONFIG_USB_HOST) */
        printk(KERN_INFO"%s: PCD DRIVER N/A\n", __FUNCTION__);
        #endif /* !defined(CONFIG_USB_HOST) */


        TRACE_MSG0(ZAS, "4. TCD");
        THROW_UNLESS(REMOVE_tcd_instance = otg_set_tcd_ops(otg, &tcd_ops), error);
        REMOVE_TCD = REMOVE_tcd_instance->TAG;
        // XXX THROW_IF((tcd_ops.mod_init ? tcd_ops.mod_init() : 0), error);
#ifdef OTG_USE_I2C
        TRACE_MSG0(ZAS, "0. I2C");
        i2c_mod_init(otg);
#endif


        #if defined(CONFIG_OTG_USB_HOST) || defined(CONFIG_OTG_USB_PERIPHERAL_OR_HOST)|| defined(CONFIG_OTG_DEVICE)
        TRACE_MSG0(ZAS, "5. Host");
        THROW_UNLESS(hcd_instance = otg_set_hcd_ops(otg, &hcd_ops), error);
        HCD = hcd_instance->TAG;
        // XXX THROW_IF((hcd_ops.mod_init) ? hcd_ops.mod_init() : 0, error);
        #else /* defined(CONFIG_OTG_USB_HOST) || defined(CONFIG_OTG_USB_PERIPHERAL_OR_HOST)|| defined(CONFIG_OTG_DEVICE) */
        printk(KERN_INFO"%s: HCD DRIVER N/A\n", __FUNCTION__);
        #endif /* defined(CONFIG_OTG_USB_HOST) || defined(CONFIG_OTG_USB_PERIPHERAL_OR_HOST)|| defined(CONFIG_OTG_DEVICE) */



        TRACE_MSG0(ZAS, "6. Init & check");
        THROW_IF((ocd_ops.mod_init ? ocd_ops.mod_init(otg) : 0), error);

        #if !defined(CONFIG_USB_HOST)
        THROW_IF((pcd_ops.mod_init ? pcd_ops.mod_init(otg) : 0), error);
        #endif /* !defined(CONFIG_USB_HOST) */

        THROW_IF((tcd_ops.mod_init ? tcd_ops.mod_init(otg) : 0), error);

        #if defined(CONFIG_OTG_USB_HOST) || defined(CONFIG_OTG_USB_PERIPHERAL_OR_HOST)|| defined(CONFIG_OTG_DEVICE)
        THROW_IF((hcd_ops.mod_init) ? hcd_ops.mod_init(otg) : 0, error);
        #endif /* defined(CONFIG_OTG_USB_HOST) || defined(CONFIG_OTG_USB_PERIPHERAL_OR_HOST)|| defined(CONFIG_OTG_DEVICE) */

        THROW_UNLESS(ocd_instance && (otg = ocd_instance->otg), error);


        TRACE_MSG0(ZAS, "7. otg_init");
        if (MODPARM(serial_number_str) && strlen(MODPARM(serial_number_str))) {

                TRACE_MSG1(ZAS, "serial_number_str: %s", MODPARM(serial_number_str));
                otg_serial_number (otg, MODPARM(serial_number_str));
        }
        otg_init(otg);

        return 0;

        CATCH(error) {
                //zasevb_modexit();
                return -EINVAL;
        }

        return 0;
}