예제 #1
0
static int __exit ehci_mxc_drv_remove(struct platform_device *pdev)
{
	struct mxc_usbh_platform_data *pdata = pdev->dev.platform_data;
	struct ehci_mxc_priv *priv = platform_get_drvdata(pdev);
	struct usb_hcd *hcd = priv->hcd;

	if (pdata && pdata->exit)
		pdata->exit(pdev);

	if (pdata->otg)
		otg_shutdown(pdata->otg);

	usb_remove_hcd(hcd);
	iounmap(hcd->regs);
	release_mem_region(hcd->rsrc_start, hcd->rsrc_len);
	usb_put_hcd(hcd);
	platform_set_drvdata(pdev, NULL);

	clk_disable(priv->usbclk);
	clk_put(priv->usbclk);
	if (priv->ahbclk) {
		clk_disable(priv->ahbclk);
		clk_put(priv->ahbclk);
	}
	if (priv->phy1clk) {
		clk_disable(priv->phy1clk);
		clk_put(priv->phy1clk);
	}

	kfree(priv);

	return 0;
}
예제 #2
0
static void omap2430_musb_disable(struct musb *musb)
{
#if 0
	if (musb->xceiv->last_event)
		otg_shutdown(musb->xceiv);
#endif
}
예제 #3
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;
}
예제 #4
0
파일: omap2430.c 프로젝트: ANFS/ANFS-kernel
/* 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;
}
예제 #5
0
void musb_platform_try_idle(struct musb *musb, unsigned long timeout)
{
	unsigned long		default_timeout = jiffies + msecs_to_jiffies(3);
	static unsigned long	last_timer;
	u32 val;

	if (timeout == 0)
		timeout = default_timeout;

	/* Never idle if active, or when VBUS timeout is not set as host */
	if (musb->is_active || ((musb->a_wait_bcon == 0)
			&& (musb->xceiv->state == OTG_STATE_A_WAIT_BCON))) {
		DBG(4, "%s active, deleting timer\n", otg_state_string(musb));
		del_timer(&musb_idle_timer);
		last_timer = jiffies;
		return;
	}

	if (musb->xceiv->state == OTG_STATE_UNDEFINED) {
		/* disable the phy clock when the gadget driver is unloaded.
		* Powerdown the phy and configure the musb sysconfig to
		* force standby/idle.
		* this will allow the core to hit retention and offmode
		*/
		otg_shutdown(musb->xceiv);
		/* configure in force idle/ standby */
		val = musb_readl(musb->mregs, OTG_SYSCONFIG);
		val &= ~(SMARTIDLEWKUP | SMARTSTDBY | NOSTDBY | ENABLEWAKEUP);
		val |= FORCEIDLE | FORCESTDBY;
		musb_writel(musb->mregs, OTG_SYSCONFIG, val);
		musb_writel(musb->mregs, OTG_FORCESTDBY, 1);
	}
	if (time_after(last_timer, timeout)) {
		if (!timer_pending(&musb_idle_timer))
			last_timer = timeout;
		else {
			DBG(4, "Longer idle timer already pending, ignoring\n");
			return;
		}
	}
	last_timer = timeout;

	DBG(4, "%s inactive, for idle timer for %lu ms\n",
		otg_state_string(musb),
		(unsigned long)jiffies_to_msecs(timeout - jiffies));
	mod_timer(&musb_idle_timer, timeout);
}
예제 #6
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");
	}
}
예제 #7
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;
}
예제 #8
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;
}
예제 #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;
	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");
	}
}
예제 #10
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");
	}

}
예제 #11
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");
	}

}
예제 #12
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");
    }
}