static int musb_platform_suspend(struct musb *musb) { u32 l; struct device *dev = musb->controller; struct musb_hdrc_platform_data *pdata = dev->platform_data; struct omap_hwmod *oh = pdata->oh; if (!musb->clock) return 0; /* in any role */ l = musb_readl(musb->mregs, OTG_FORCESTDBY); l |= ENABLEFORCE; /* enable MSTANDBY */ musb_writel(musb->mregs, OTG_FORCESTDBY, l); pdata->enable_wakeup(oh->od); otg_set_clk(musb->xceiv, 0); otg_set_suspend(musb->xceiv, 1); /* Disable the phy clocks*/ return 0; }
static int musb_platform_resume(struct musb *musb) { u32 l; if (!musb->clock) return 0; otg_set_suspend(musb->xceiv, 0); if (musb->set_clock) musb->set_clock(musb->clock, 1); else clk_enable(musb->clock); l = musb_readl(musb->mregs, OTG_SYSCONFIG); l &= ~ENABLEWAKEUP; /* disable wakeup */ musb_writel(musb->mregs, OTG_SYSCONFIG, l); l = musb_readl(musb->mregs, OTG_FORCESTDBY); l &= ~ENABLEFORCE; /* disable MSTANDBY */ musb_writel(musb->mregs, OTG_FORCESTDBY, l); return 0; }
static int musb_platform_resume(struct musb *musb) { u32 l; if (!musb->clock) return 0; otg_set_suspend(musb->xceiv, 0); if (musb->set_clock) musb->set_clock(musb->clock, 1); else clk_enable(musb->clock); l = omap_readl(OTG_SYSCONFIG); l &= ~ENABLEWAKEUP; omap_writel(l, OTG_SYSCONFIG); l = omap_readl(OTG_FORCESTDBY); l &= ~ENABLEFORCE; omap_writel(l, OTG_FORCESTDBY); return 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"); } }
static void usb_do_work(struct work_struct *w) { struct usb_info *ui = container_of(w, struct usb_info, work); unsigned long iflags; unsigned flags, _vbus; for (;;) { spin_lock_irqsave(&ui->lock, iflags); flags = ui->flags; ui->flags = 0; _vbus = vbus; spin_unlock_irqrestore(&ui->lock, iflags); /* give up if we have nothing to do */ if (flags == 0) break; switch (ui->state) { case USB_STATE_IDLE: if (flags & USB_FLAG_START) { int ret; struct msm_otg *otg = to_msm_otg(ui->xceiv); if (!_vbus) { ui->state = USB_STATE_OFFLINE; break; } msm72k_pm_qos_update(1); pr_info("msm72k_udc: IDLE -> ONLINE\n"); usb_reset(ui); ret = request_irq(otg->irq, usb_interrupt, IRQF_SHARED, ui->pdev->name, ui); /* FIXME: should we call BUG_ON when * requst irq fails */ if (ret) { pr_err("hsusb: peripheral: request irq" " failed:(%d)", ret); msm72k_pm_qos_update(0); break; } ui->irq = otg->irq; msm72k_pullup(&ui->gadget, 1); if (ui->chg_connected) { msleep(500); ui->chg_type = is_wall_charger(ui); ui->chg_current = ui->chg_type ? 1500 : 100; ui->chg_connected(ui->chg_type); } ui->state = USB_STATE_ONLINE; usb_do_work_check_vbus(ui); } break; case USB_STATE_ONLINE: /* If at any point when we were online, we received * the signal to go offline, we must honor it */ if (flags & USB_FLAG_VBUS_OFFLINE) { pr_info("msm72k_udc: ONLINE -> OFFLINE\n"); otg_set_suspend(ui->xceiv, 0); /* synchronize with irq context */ spin_lock_irqsave(&ui->lock, iflags); ui->running = 0; ui->online = 0; msm72k_pullup(&ui->gadget, 0); spin_unlock_irqrestore(&ui->lock, iflags); if (ui->chg_connected) { ui->chg_type = CHG_TYPE_INVALID; ui->chg_current = 0; ui->chg_connected(ui->chg_type); } if (ui->irq) { free_irq(ui->irq, ui); ui->irq = 0; } if (ui->usb_connected) ui->usb_connected(0); /* terminate any transactions, etc */ flush_all_endpoints(ui); if (ui->driver) { printk(KERN_INFO "usb: notify offline\n"); ui->driver->disconnect(&ui->gadget); } /* power down phy, clock down usb */ otg_set_suspend(ui->xceiv, 1); ui->state = USB_STATE_OFFLINE; usb_do_work_check_vbus(ui); msm72k_pm_qos_update(0); break; } if (flags & USB_FLAG_SUSPEND) { /* TBD: Not supporting bus suspend */ ui->chg_vbus_draw(0); break; } if (flags & USB_FLAG_CONFIGURED) { ui->chg_current = ui->b_max_pow; ui->chg_vbus_draw(ui->b_max_pow); break; } if (flags & USB_FLAG_RESET) { pr_info("msm72k_udc: ONLINE -> RESET\n"); msm72k_pullup(&ui->gadget, 0); usb_reset(ui); msm72k_pullup(&ui->gadget, 1); pr_info("msm72k_udc: RESET -> ONLINE\n"); break; } break; case USB_STATE_OFFLINE: /* If we were signaled to go online and vbus is still * present when we received the signal, go online. */ if ((flags & USB_FLAG_VBUS_ONLINE) && _vbus) { int ret; struct msm_otg *otg = to_msm_otg(ui->xceiv); pr_info("msm72k_udc: OFFLINE -> ONLINE\n"); msm72k_pm_qos_update(1); otg_set_suspend(ui->xceiv, 0); usb_reset(ui); if (ui->usb_connected) ui->usb_connected(1); ui->state = USB_STATE_ONLINE; usb_do_work_check_vbus(ui); ret = request_irq(otg->irq, usb_interrupt, IRQF_SHARED, ui->pdev->name, ui); /* FIXME: should we call BUG_ON when * requst irq fails */ if (ret) { pr_err("hsusb: peripheral: request irq" " failed:(%d)", ret); break; } ui->irq = otg->irq; enable_irq_wake(otg->irq); msm72k_pullup(&ui->gadget, 1); if (ui->chg_connected) { msleep(500); ui->chg_type = is_wall_charger(ui); ui->chg_current = ui->chg_type ? 1500 : 100; ui->chg_connected(ui->chg_type); } } break; } } }