static inline void phy_on(void) { u32 phy_ctrl = __raw_readl(USB_PHY_CTRL); /* power everything up; start the on-chip PHY and its PLL */ phy_ctrl &= ~(USBPHY_OSCPDWN | USBPHY_OTGPDWN | USBPHY_PHYPDWN); phy_ctrl |= USBPHY_SESNDEN | USBPHY_VBDTCTEN | USBPHY_PHYPLLON; if (cpu_is_davinci_dm646x()) { phy_ctrl |= USBPHY_NDATAPOL | USBPHY_SESSION_VBUS; phy_ctrl |= is_peripheral_enabled() ? USBPHY_PERI_USBID : phy_ctrl; phy_ctrl &= ~USBPHY_VBDTCTEN; } if (cpu_is_davinci_dm365()) { /* * DM365 PHYCLKFREQ field [15:12] is set to 2 * to get clock from 24MHz crystal */ phy_ctrl |= USBPHY_CLKFREQ_24MHZ; /*phy_ctrl &= ~USBPHY_PHYPDWN;*/ } __raw_writel(phy_ctrl, USB_PHY_CTRL); /* wait for PLL to lock before proceeding */ while ((__raw_readl(USB_PHY_CTRL) & USBPHY_PHYCLKGD) == 0) cpu_relax(); }
int __init musb_platform_init(struct musb *musb) { struct otg_transceiver *x = otg_get_transceiver(); u32 l; #if defined(CONFIG_ARCH_OMAP2430) omap_cfg_reg(AE5_2430_USB0HS_STP); #endif /* Reset controller */ if (musb->set_clock) musb->set_clock(musb->clock, 1); else clk_enable(musb->clock); l = omap_readl(OTG_SYSCONFIG); l |= SOFTRST; omap_writel(l, OTG_SYSCONFIG); while (!(RESETDONE & omap_readl(OTG_SYSSTATUS))) cpu_relax(); musb->xceiv = *x; musb_platform_resume(musb); l = omap_readl(OTG_SYSCONFIG); l &= ~ENABLEWAKEUP; /* disable wakeup */ l &= ~NOSTDBY; /* remove possible nostdby */ l |= SMARTSTDBY; /* enable smart standby */ l &= ~AUTOIDLE; /* disable auto idle */ l &= ~NOIDLE; /* remove possible noidle */ l |= SMARTIDLE; /* enable smart idle */ /* * MUSB AUTOIDLE don't work in 3430. * Workaround by Richard Woodruff/TI */ if (!cpu_is_omap3430()) l |= AUTOIDLE; /* enable auto idle */ omap_writel(l, OTG_SYSCONFIG); l = omap_readl(OTG_INTERFSEL); l |= ULPI_12PIN; omap_writel(l, OTG_INTERFSEL); pr_debug("HS USB OTG: revision 0x%x, sysconfig 0x%02x, " "sysstatus 0x%x, intrfsel 0x%x, simenable 0x%x\n", omap_readl(OTG_REVISION), omap_readl(OTG_SYSCONFIG), omap_readl(OTG_SYSSTATUS), omap_readl(OTG_INTERFSEL), omap_readl(OTG_SIMENABLE)); omap_vbus_power(musb, musb->board_mode == MUSB_HOST, 1); if (is_host_enabled(musb)) musb->board_set_vbus = omap_set_vbus; if (!musb->xceiv.set_power && is_peripheral_enabled(musb)) musb->xceiv.set_power = omap_set_power; musb->a_wait_bcon = MUSB_TIMEOUT_A_WAIT_BCON; setup_timer(&musb_idle_timer, musb_do_idle, (unsigned long) musb); return 0; }
int __init musb_platform_init(struct musb *musb) { struct otg_transceiver *x = otg_get_transceiver(); u32 l; u8 val; #if defined(CONFIG_ARCH_OMAP2430) omap_cfg_reg(AE5_2430_USB0HS_STP); #endif if (!x) { pr_err("omap: musb: null transceiver found\n"); return -ENODEV; } musb->xceiv = *x; musb_platform_resume(musb); l = omap_readl(OTG_SYSCONFIG); l &= ~ENABLEWAKEUP; /* disable wakeup */ l &= ~NOSTDBY; /* remove possible nostdby */ l |= SMARTSTDBY; /* enable smart standby */ l &= ~AUTOIDLE; /* disable auto idle */ l &= ~NOIDLE; /* remove possible noidle */ l |= SMARTIDLE; /* enable smart idle */ l |= AUTOIDLE; /* enable auto idle */ omap_writel(l, OTG_SYSCONFIG); l = omap_readl(OTG_INTERFSEL); l |= ULPI_12PIN; omap_writel(l, OTG_INTERFSEL); #ifdef CONFIG_MACH_OMAP3EVM /* Program PHY to use external Vbus supply on new OMAP3EVM */ if (get_omap3evm_board_rev() >= OMAP3EVM_BOARD_GEN_2) { val = musb_readb(musb->mregs, MUSB_ULPI_BUSCONTROL); val |= ULPI_USE_EXTVBUS; musb_writeb(musb->mregs, MUSB_ULPI_BUSCONTROL, val); } #endif pr_debug("HS USB OTG: revision 0x%x, sysconfig 0x%02x, " "sysstatus 0x%x, intrfsel 0x%x, simenable 0x%x\n", omap_readl(OTG_REVISION), omap_readl(OTG_SYSCONFIG), omap_readl(OTG_SYSSTATUS), omap_readl(OTG_INTERFSEL), omap_readl(OTG_SIMENABLE)); omap_vbus_power(musb, musb->board_mode == MUSB_HOST, 1); if (is_host_enabled(musb)) musb->board_set_vbus = omap_set_vbus; if (is_peripheral_enabled(musb)) musb->xceiv.set_power = omap_set_power; musb->a_wait_bcon = MUSB_TIMEOUT_A_WAIT_BCON; setup_timer(&musb_idle_timer, musb_do_idle, (unsigned long) musb); return 0; }
static void otg_timer(unsigned long _musb) { struct musb *musb = (void *)_musb; void __iomem *mregs = musb->mregs; u8 devctl; unsigned long flags; /* We poll because DaVinci's won't expose several OTG-critical * status change events (from the transceiver) otherwise. */ devctl = musb_readb(mregs, MUSB_DEVCTL); DBG(7, "poll devctl %02x (%s)\n", devctl, otg_state_string(musb)); spin_lock_irqsave(&musb->lock, flags); switch (musb->xceiv->state) { case OTG_STATE_A_WAIT_VFALL: /* Wait till VBUS falls below SessionEnd (~0.2V); the 1.3 RTL * seems to mis-handle session "start" otherwise (or in our * case "recover"), in routine "VBUS was valid by the time * VBUSERR got reported during enumeration" cases. */ if (devctl & MUSB_DEVCTL_VBUS) { mod_timer(&otg_workaround, jiffies + POLL_SECONDS * HZ); break; } musb->xceiv->state = OTG_STATE_A_WAIT_VRISE; musb_writel(musb->ctrl_base, DAVINCI_USB_INT_SET_REG, MUSB_INTR_VBUSERROR << DAVINCI_USB_USBINT_SHIFT); break; case OTG_STATE_B_IDLE: if (!is_peripheral_enabled(musb)) break; /* There's no ID-changed IRQ, so we have no good way to tell * when to switch to the A-Default state machine (by setting * the DEVCTL.SESSION flag). * * Workaround: whenever we're in B_IDLE, try setting the * session flag every few seconds. If it works, ID was * grounded and we're now in the A-Default state machine. * * NOTE setting the session flag is _supposed_ to trigger * SRP, but clearly it doesn't. */ /* musb_writeb(mregs, MUSB_DEVCTL, devctl | MUSB_DEVCTL_SESSION); */ devctl = musb_readb(mregs, MUSB_DEVCTL); if (devctl & MUSB_DEVCTL_BDEVICE) mod_timer(&otg_workaround, jiffies + POLL_SECONDS * HZ); else musb->xceiv->state = OTG_STATE_A_IDLE; break; default: break; } spin_unlock_irqrestore(&musb->lock, flags); }
/* 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; }
static void otg_timer(unsigned long _musb) { struct musb *musb = (void *)_musb; void __iomem *mregs = musb->mregs; u8 devctl; unsigned long flags; /* * We poll because AM35x's won't expose several OTG-critical * status change events (from the transceiver) otherwise. */ devctl = musb_readb(mregs, MUSB_DEVCTL); dev_dbg(musb->controller, "Poll devctl %02x (%s)\n", devctl, otg_state_string(musb->xceiv->state)); spin_lock_irqsave(&musb->lock, flags); switch (musb->xceiv->state) { case OTG_STATE_A_WAIT_BCON: devctl &= ~MUSB_DEVCTL_SESSION; musb_writeb(musb->mregs, MUSB_DEVCTL, devctl); devctl = musb_readb(musb->mregs, MUSB_DEVCTL); if (devctl & MUSB_DEVCTL_BDEVICE) { musb->xceiv->state = OTG_STATE_B_IDLE; MUSB_DEV_MODE(musb); } else { musb->xceiv->state = OTG_STATE_A_IDLE; MUSB_HST_MODE(musb); } break; case OTG_STATE_A_WAIT_VFALL: musb->xceiv->state = OTG_STATE_A_WAIT_VRISE; musb_writel(musb->ctrl_base, CORE_INTR_SRC_SET_REG, MUSB_INTR_VBUSERROR << AM35X_INTR_USB_SHIFT); break; case OTG_STATE_B_IDLE: if (!is_peripheral_enabled(musb)) break; devctl = musb_readb(mregs, MUSB_DEVCTL); if (devctl & MUSB_DEVCTL_BDEVICE) mod_timer(&otg_workaround, jiffies + POLL_SECONDS * HZ); else musb->xceiv->state = OTG_STATE_A_IDLE; break; default: break; } spin_unlock_irqrestore(&musb->lock, flags); }
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); usb_phy_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); usb_phy_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->otg->set_vbus) otg_set_vbus(musb->xceiv->otg, 0); } usb_phy_shutdown(musb->xceiv); break; default: dev_dbg(musb->controller, "ID float\n"); } }
int __init musb_platform_init(struct musb *musb) { struct otg_transceiver *xceiv; xceiv = kzalloc(sizeof(struct otg_transceiver), GFP_KERNEL); if (!xceiv) return -ENOMEM; xceiv->set_peripheral = sep0611_set_peripheral; otg_set_transceiver(xceiv); musb->xceiv = otg_get_transceiver(); if (!musb->xceiv) { return -ENODEV; } musb_platform_resume(musb); if (is_host_enabled(musb)) musb->xceiv->set_host = sep0611_set_host; musb->board_set_vbus = sep0611_set_vbus; if (is_peripheral_enabled(musb)) musb->xceiv->set_power = sep0611_set_power; musb->a_wait_bcon = MUSB_TIMEOUT_A_WAIT_BCON; setup_timer(&musb_idle_timer, musb_do_idle, (unsigned long) musb); musb_writew(musb->mregs, RX_DPKTBUFDIS, 0xffff); /* disable RX double packet buffer */ musb_writew(musb->mregs, TX_DPKTBUFDIS, 0xffff); /* disable TX double packet buffer */ #ifdef SEP0611_ULPI_RST /*spdw_board has two usb ports,one is otg(port_index=0), the other is host(port_index=1),default is otg port*/ musb->port_index = 0; #endif #ifdef SEP0611_PHY_RST /*demo_board has two usb ports*/ musb->port_index = 0; #endif return 0; }
static void otg_timer(unsigned long _musb) { struct musb *musb = (void *)_musb; void __iomem *mregs = musb->mregs; u8 devctl; unsigned long flags; devctl = musb_readb(mregs, MUSB_DEVCTL); dev_dbg(musb->controller, "poll devctl %02x (%s)\n", devctl, otg_state_string(musb->xceiv->state)); spin_lock_irqsave(&musb->lock, flags); switch (musb->xceiv->state) { case OTG_STATE_A_WAIT_VFALL: if (devctl & MUSB_DEVCTL_VBUS) { mod_timer(&otg_workaround, jiffies + POLL_SECONDS * HZ); break; } musb->xceiv->state = OTG_STATE_A_WAIT_VRISE; musb_writel(musb->ctrl_base, DAVINCI_USB_INT_SET_REG, MUSB_INTR_VBUSERROR << DAVINCI_USB_USBINT_SHIFT); break; case OTG_STATE_B_IDLE: if (!is_peripheral_enabled(musb)) break; musb_writeb(mregs, MUSB_DEVCTL, devctl | MUSB_DEVCTL_SESSION); devctl = musb_readb(mregs, MUSB_DEVCTL); if (devctl & MUSB_DEVCTL_BDEVICE) mod_timer(&otg_workaround, jiffies + POLL_SECONDS * HZ); else musb->xceiv->state = OTG_STATE_A_IDLE; break; default: break; } spin_unlock_irqrestore(&musb->lock, flags); }
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; }
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"); } }
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"); } }
/** * musb_platform_init() - Initialize the platform USB driver. * @musb: struct musb pointer. * * This function initialize the USB controller and Phy. */ int __init musb_platform_init(struct musb *musb, void *board_data) { int ret; usb_nop_xceiv_register(); musb->xceiv = otg_get_transceiver(); if (!musb->xceiv) { pr_err("U8500 USB : no transceiver configured\n"); ret = -ENODEV; goto cleanup0; } ret = musb_stm_hs_otg_init(musb); if (ret < 0) { pr_err("U8500 USB: Failed to init the OTG object\n"); goto cleanup1; } if (is_host_enabled(musb)) musb->board_set_vbus = set_vbus; if (is_peripheral_enabled(musb)) musb->xceiv->set_power = set_power; ret = musb_phy_en(musb->board_mode); if (ret < 0) { pr_err("U8500 USB: Failed to enable PHY\n"); goto cleanup1; } if (musb_status == NULL) { musb_status = musb; spin_lock_init(&musb_ulpi_spinlock); } /* Registering usb device for sysfs */ usbstatus_kobj = kzalloc(sizeof(struct kobject), GFP_KERNEL); if (usbstatus_kobj == NULL) { ret = -ENOMEM; goto cleanup1; } usbstatus_kobj->ktype = &ktype_usbstatus; kobject_init(usbstatus_kobj, usbstatus_kobj->ktype); ret = kobject_set_name(usbstatus_kobj, "usb_status"); if (ret) goto cleanup2; ret = kobject_add(usbstatus_kobj, NULL, "usb_status"); if (ret) { goto cleanup2; } if (musb->board_mode != MUSB_PERIPHERAL) { init_timer(¬ify_timer); notify_timer.expires = jiffies + msecs_to_jiffies(1000); notify_timer.function = funct_host_notify_timer; notify_timer.data = (unsigned long)musb; add_timer(¬ify_timer); } stm_usb_power_wq = create_singlethread_workqueue( "stm_usb_power_wq"); if (stm_usb_power_wq == NULL) { ret = -ENOMEM; goto cleanup2; } INIT_WORK(&stm_prcmu_qos, stm_prcmu_qos_work); ret = musb_force_detect(musb->board_mode); if (ret < 0) goto cleanup2; return 0; cleanup2: kfree(usbstatus_kobj); if (musb->board_mode != MUSB_PERIPHERAL) del_timer_sync(¬ify_timer); cleanup1: otg_put_transceiver(musb->xceiv); cleanup0: usb_nop_xceiv_unregister(); return ret; }
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"); } }