static int omap2430_runtime_resume(struct device *dev) { struct omap2430_glue *glue = dev_get_drvdata(dev); struct musb *musb = glue_to_musb(glue); if (musb) { omap2430_low_level_init(musb); musb_writel(musb->mregs, OTG_INTERFSEL, musb->context.otg_interfsel); usb_phy_set_suspend(musb->xceiv, 0); } return 0; }
void musb_platform_save_context(struct musb *musb, struct musb_context_registers *musb_context) { void __iomem *musb_base = musb->mregs; musb_context->otg_sysconfig = musb_readl(musb->mregs, OTG_SYSCONFIG); musb_context->otg_interfacesel = musb_readl(musb->mregs, OTG_INTERFSEL); if (cpu_is_omap44xx()) { musb_context->ctl_dev_conf = __raw_readl(ctrl_base + CONTROL_DEV_CONF); musb_context->usbotg_control = __raw_readl(ctrl_base + USBOTGHS_CONTROL); } musb_writel(musb_base, OTG_FORCESTDBY, 1); }
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 void tusb_omap_dma_release(struct dma_channel *channel) { struct tusb_omap_dma_ch *chdat = to_chdat(channel); struct musb *musb = chdat->musb; void __iomem *tbase = musb->ctrl_base; u32 reg; dev_dbg(musb->controller, "ep%i ch%i\n", chdat->epnum, chdat->ch); reg = musb_readl(tbase, TUSB_DMA_INT_MASK); if (chdat->tx) reg |= (1 << chdat->epnum); else reg |= (1 << (chdat->epnum + 15)); musb_writel(tbase, TUSB_DMA_INT_MASK, reg); reg = musb_readl(tbase, TUSB_DMA_INT_CLEAR); if (chdat->tx) reg |= (1 << chdat->epnum); else reg |= (1 << (chdat->epnum + 15)); musb_writel(tbase, TUSB_DMA_INT_CLEAR, reg); channel->status = MUSB_DMA_STATUS_UNKNOWN; if (chdat->ch >= 0) { omap_stop_dma(chdat->ch); omap_free_dma(chdat->ch); chdat->ch = -1; } if (chdat->dmareq >= 0) tusb_omap_dma_free_dmareq(chdat); channel = NULL; }
static int cppi_controller_stop(struct dma_controller *c) { struct cppi *controller; void __iomem *tibase; int i; struct musb *musb; controller = container_of(c, struct cppi, controller); musb = controller->musb; tibase = controller->tibase; /* DISABLE INDIVIDUAL CHANNEL Interrupts */ musb_writel(tibase, DAVINCI_TXCPPI_INTCLR_REG, DAVINCI_DMA_ALL_CHANNELS_ENABLE); musb_writel(tibase, DAVINCI_RXCPPI_INTCLR_REG, DAVINCI_DMA_ALL_CHANNELS_ENABLE); dev_dbg(musb->controller, "Tearing down RX and TX Channels\n"); for (i = 0; i < ARRAY_SIZE(controller->tx); i++) { /* FIXME restructure of txdma to use bds like rxdma */ controller->tx[i].last_processed = NULL; cppi_pool_free(controller->tx + i); } for (i = 0; i < ARRAY_SIZE(controller->rx); i++) cppi_pool_free(controller->rx + i); /* in Tx Case proper teardown is supported. We resort to disabling * Tx/Rx CPPI after cleanup of Tx channels. Before TX teardown is * complete TX CPPI cannot be disabled. */ /*disable tx/rx cppi */ musb_writel(tibase, DAVINCI_TXCPPI_CTRL_REG, DAVINCI_DMA_CTRL_DISABLE); musb_writel(tibase, DAVINCI_RXCPPI_CTRL_REG, DAVINCI_DMA_CTRL_DISABLE); return 0; }
static void cppi41_autoreq_update(struct cppi41_channel *rx_ch, u8 autoreq) { struct cppi41 *cppi = rx_ch->channel.private_data; if (is_host_active(cppi->musb) && autoreq != rx_ch->autoreq) { void *__iomem reg_base = cppi->musb->ctrl_base; u32 reg_val = musb_readl(reg_base, cppi->automode_reg_offs); u8 ep_num = rx_ch->ch_num + 1; reg_val &= ~USB_RX_AUTOREQ_MASK(ep_num); reg_val |= autoreq << USB_RX_AUTOREQ_SHIFT(ep_num); musb_writel(reg_base, cppi->automode_reg_offs, reg_val); rx_ch->autoreq = autoreq; }
void musb_otg_reset_usb(void){ //reset all of the USB IP, including PHY and MAC unsigned int usb_reset; usb_reset = __raw_readl(PERICFG_BASE); usb_reset |= 1<<29; __raw_writel(usb_reset,PERICFG_BASE); mdelay(10); usb_reset &= ~(1<<29); __raw_writel(usb_reset,PERICFG_BASE); //power on the USB usb_phy_poweron(); //enable interrupt musb_writel(mtk_musb->mregs,USB_L1INTM,0x105); musb_writew(mtk_musb->mregs,MUSB_INTRTXE,1); musb_writeb(mtk_musb->mregs,MUSB_INTRUSBE,0xf7); }
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, usb_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: 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); }
int __init musb_platform_init(struct musb *musb) { void __iomem *tibase = musb->ctrl_base; u32 revision; musb->mregs += DAVINCI_BASE_OFFSET; #if 0 /* REVISIT there's something odd about clocking, this * didn't appear do the job ... */ musb->clock = clk_get(pDevice, "usb"); if (IS_ERR(musb->clock)) return PTR_ERR(musb->clock); status = clk_enable(musb->clock); if (status < 0) return -ENODEV; #endif /* returns zero if e.g. not clocked */ revision = musb_readl(tibase, DAVINCI_USB_VERSION_REG); if (revision == 0) return -ENODEV; if (is_host_enabled(musb)) setup_timer(&otg_workaround, otg_timer, (unsigned long) musb); musb->board_set_vbus = davinci_set_vbus; davinci_source_power(musb, 0, 1); /* reset the controller */ musb_writel(tibase, DAVINCI_USB_CTRL_REG, 0x1); /* start the on-chip PHY and its PLL */ phy_on(); msleep(5); /* NOTE: irqs are in mixed mode, not bypass to pure-musb */ pr_debug("DaVinci OTG revision %08x phy %03x control %02x\n", revision, __raw_readl((void __force __iomem *) IO_ADDRESS(USBPHY_CTL_PADDR)), musb_readb(tibase, DAVINCI_USB_CTRL_REG)); musb->isr = davinci_interrupt; return 0; }
static void cppi41_set_autoreq_mode(struct cppi41_dma_channel *cppi41_channel, unsigned mode) { struct cppi41_dma_controller *controller = cppi41_channel->controller; u32 port; u32 new_mode; u32 old_mode; old_mode = controller->auto_req; port = cppi41_channel->port_num; new_mode = update_ep_mode(port, mode, old_mode); if (new_mode == old_mode) return; controller->auto_req = new_mode; musb_writel(controller->musb->ctrl_base, USB_CTRL_AUTOREQ, new_mode); }
static int omap2430_runtime_resume(struct device *dev) { struct omap2430_glue *glue = dev_get_drvdata(dev); struct musb *musb = glue_to_musb(glue); if (!musb) return 0; phy_init(musb->phy); phy_power_on(musb->phy); omap2430_low_level_init(musb); musb_writel(musb->mregs, OTG_INTERFSEL, musb->context.otg_interfsel); return 0; }
static int am35x_musb_init(struct musb *musb) { struct device *dev = musb->controller; struct musb_hdrc_platform_data *plat = dev->platform_data; struct omap_musb_board_data *data = plat->board_data; void __iomem *reg_base = musb->ctrl_base; u32 rev; musb->mregs += USB_MENTOR_CORE_OFFSET; /* Returns zero if e.g. not clocked */ rev = musb_readl(reg_base, USB_REVISION_REG); if (!rev) return -ENODEV; usb_nop_xceiv_register(); musb->xceiv = otg_get_transceiver(); if (!musb->xceiv) return -ENODEV; if (is_host_enabled(musb)) setup_timer(&otg_workaround, otg_timer, (unsigned long) musb); /* Reset the musb */ if (data->reset) data->reset(); /* Reset the controller */ musb_writel(reg_base, USB_CTRL_REG, AM35X_SOFT_RESET_MASK); /* Start the on-chip PHY and its PLL. */ if (data->set_phy_power) data->set_phy_power(1); msleep(5); musb->isr = am35x_musb_interrupt; /* clear level interrupt */ if (data->clear_irq) data->clear_irq(); return 0; }
/* * Allocate dmareq0 to the current channel unless it's already taken */ static inline int tusb_omap_use_shared_dmareq(struct tusb_omap_dma_ch *chdat) { u32 reg = musb_readl(chdat->tbase, TUSB_DMA_EP_MAP); if (reg != 0) { dev_dbg(chdat->musb->controller, "ep%i dmareq0 is busy for ep%i\n", chdat->epnum, reg & 0xf); return -EAGAIN; } if (chdat->tx) reg = (1 << 4) | chdat->epnum; else reg = chdat->epnum; musb_writel(chdat->tbase, TUSB_DMA_EP_MAP, reg); return 0; }
/* Context: controller irqlocked */ static inline void cppi_rndis_update(struct cppi_channel *c, int is_rx, void __iomem *tibase, int is_rndis) { /* we may need to change the rndis flag for this cppi channel */ if (c->is_rndis != is_rndis) { u32 value = musb_readl(tibase, DAVINCI_RNDIS_REG); u32 temp = 1 << (c->index); if (is_rx) temp <<= 16; if (is_rndis) value |= temp; else value &= ~temp; musb_writel(tibase, DAVINCI_RNDIS_REG, value); c->is_rndis = is_rndis; } }
void static otg_int_init(void) { #ifdef ID_PIN_USE_EX_EINT mt_set_gpio_mode(GPIO_OTG_IDDIG_EINT_PIN, GPIO_OTG_IDDIG_EINT_PIN_M_USB_IDDIG); mt_set_gpio_dir(GPIO_OTG_IDDIG_EINT_PIN, GPIO_DIR_IN); mt_set_gpio_pull_enable(GPIO_OTG_IDDIG_EINT_PIN, GPIO_PULL_ENABLE); mt_set_gpio_pull_select(GPIO_OTG_IDDIG_EINT_PIN, GPIO_PULL_UP); mt_eint_set_sens(IDDIG_EINT_PIN, MT_LEVEL_SENSITIVE); mt_eint_set_hw_debounce(IDDIG_EINT_PIN,64); mt_eint_registration(IDDIG_EINT_PIN, EINTF_TRIGGER_LOW, mt_usb_ext_iddig_int, FALSE); #else u32 phy_id_pull = 0; phy_id_pull = __raw_readl(U2PHYDTM1); phy_id_pull |= ID_PULL_UP; __raw_writel(phy_id_pull,U2PHYDTM1); musb_writel(mtk_musb->mregs,USB_L1INTM,IDDIG_INT_STATUS|musb_readl(mtk_musb->mregs,USB_L1INTM)); #endif }
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_suspend(musb->xceiv, 1); return 0; }
static int musb_platform_resume(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; otg_set_suspend(musb->xceiv, 0); pm_runtime_enable(dev); pm_runtime_get_sync(dev); pdata->disable_wakeup(oh->od); l = musb_readl(musb->mregs, OTG_FORCESTDBY); l &= ~ENABLEFORCE; /* disable MSTANDBY */ musb_writel(musb->mregs, OTG_FORCESTDBY, l); return 0; }
static int da8xx_musb_init(struct musb *musb) { void __iomem *reg_base = musb->ctrl_base; u32 rev; int ret = -ENODEV; musb->mregs += DA8XX_MENTOR_CORE_OFFSET; /* Returns zero if e.g. not clocked */ rev = musb_readl(reg_base, DA8XX_USB_REVISION_REG); if (!rev) goto fail; usb_nop_xceiv_register(); musb->xceiv = usb_get_phy(USB_PHY_TYPE_USB2); if (IS_ERR_OR_NULL(musb->xceiv)) { ret = -EPROBE_DEFER; goto fail; } setup_timer(&otg_workaround, otg_timer, (unsigned long)musb); /* Reset the controller */ musb_writel(reg_base, DA8XX_USB_CTRL_REG, DA8XX_SOFT_RESET_MASK); /* Start the on-chip PHY and its PLL. */ phy_on(); msleep(5); /* NOTE: IRQs are in mixed mode, not bypass to pure MUSB */ pr_debug("DA8xx OTG revision %08x, PHY %03x, control %02x\n", rev, __raw_readl(CFGCHIP2), musb_readb(reg_base, DA8XX_USB_CTRL_REG)); musb->isr = da8xx_musb_interrupt; return 0; fail: return ret; }
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); }
void otg_int_init(void) { //bool is_ready = mtk_musb->is_ready; #ifdef ID_PIN_USE_EX_EINT mt_set_gpio_mode(ID_PIN_GPIO, GPIO_ID_PIN_EINT_PIN_M_EINT); mt_set_gpio_dir(ID_PIN_GPIO, GPIO_DIR_IN); mt_set_gpio_pull_enable(ID_PIN_GPIO, GPIO_PULL_ENABLE); mt_set_gpio_pull_select(ID_PIN_GPIO, GPIO_PULL_UP); #else u32 phy_id_pull = 0; phy_id_pull = __raw_readl(U2PHYDTM1); phy_id_pull |= ID_PULL_UP; __raw_writel(phy_id_pull,U2PHYDTM1); #endif //mt65xx_eint_set_sens(ID_PIN_EINT, MT65xx_LEVEL_SENSITIVE); //mt65xx_eint_set_hw_debounce(ID_PIN_EINT,64); //mtk_musb->is_ready = FALSE; //mt65xx_eint_registration(ID_PIN_EINT, FALSE, !DEVICE_INTTERRUPT, musb_id_pin_interrup,FALSE); //mtk_musb->is_ready = is_ready; musb_writel(mtk_musb->mregs,USB_L1INTM,IDDIG_INT_STATUS|musb_readl(mtk_musb->mregs,USB_L1INTM)); }
int musb_qmu_init(struct musb *musb) { /* set DMA channel 0 burst mode to boost QMU speed */ musb_writel(musb->mregs, 0x204, musb_readl(musb->mregs, 0x204) | 0x600); #ifdef CONFIG_OF qmu_base = (void __iomem *)(mtk_musb->mregs + MUSB_QMUBASE); /* debug variable to check qmu_base issue */ qmu_base_2 = (void __iomem *)(mtk_musb->mregs + MUSB_QMUBASE); #else qmu_base = (void __iomem *)(USB_BASE + MUSB_QMUBASE); /* debug variable to check qmu_base issue */ qmu_base_2 = (void __iomem *)(mtk_musb->mregs + MUSB_QMUBASE); #endif mb(); if (qmu_init_gpd_pool(musb->controller)) { QMU_ERR("[QMU]qmu_init_gpd_pool fail\n"); return -1; } return 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; }
int __init musb_platform_init(struct musb *musb) { u32 l; struct device *dev = musb->controller; struct musb_hdrc_platform_data *plat = dev->platform_data; struct omap_musb_board_data *data = plat->board_data; int status; u32 val; /* We require some kind of external transceiver, hooked * up through ULPI. TWL4030-family PMICs include one, * which needs a driver, drivers aren't always needed. */ musb->xceiv = otg_get_transceiver(); if (!musb->xceiv) { pr_err("HS USB OTG: no transceiver configured\n"); return -ENODEV; } /* Fixme this can be enabled when load the gadget driver also*/ musb_platform_resume(musb); /*powerup the phy as romcode would have put the phy in some state * which is impacting the core retention if the gadget driver is not * loaded. */ l = musb_readl(musb->mregs, OTG_INTERFSEL); if (data->interface_type == MUSB_INTERFACE_UTMI) { /* OMAP4 uses Internal PHY GS70 which uses UTMI interface */ l &= ~ULPI_12PIN; /* Disable ULPI */ l |= UTMI_8BIT; /* Enable UTMI */ } else { l |= ULPI_12PIN; } musb_writel(musb->mregs, OTG_INTERFSEL, l); pr_debug("HS USB OTG: revision 0x%x, sysconfig 0x%02x, " "sysstatus 0x%x, intrfsel 0x%x, simenable 0x%x\n", musb_readl(musb->mregs, OTG_REVISION), musb_readl(musb->mregs, OTG_SYSCONFIG), musb_readl(musb->mregs, OTG_SYSSTATUS), musb_readl(musb->mregs, OTG_INTERFSEL), musb_readl(musb->mregs, OTG_SIMENABLE)); if (is_host_enabled(musb)) musb->board_set_vbus = omap_set_vbus; setup_timer(&musb_idle_timer, musb_do_idle, (unsigned long) musb); plat->is_usb_active = is_musb_active; wake_lock_init(&plat->musb_lock, WAKE_LOCK_SUSPEND, "musb_wake_lock"); if (cpu_is_omap44xx()) { phymux_base = ioremap(0x4A100000, SZ_1K); ctrl_base = ioremap(0x4A002000, SZ_1K); /* register for transciever notification*/ status = otg_register_notifier(musb->xceiv, &musb->nb); if (status) { DBG(1, "notification register failed\n"); wake_lock_destroy(&plat->musb_lock); } ctrl_base = ioremap(0x4A002000, SZ_1K); if (!ctrl_base) { dev_err(dev, "ioremap failed\n"); return -ENOMEM; } } /* configure in force idle/ standby */ musb_writel(musb->mregs, OTG_FORCESTDBY, 1); val = musb_readl(musb->mregs, OTG_SYSCONFIG); val &= ~(SMARTIDLEWKUP | NOSTDBY | ENABLEWAKEUP); val |= FORCEIDLE | FORCESTDBY; musb_writel(musb->mregs, OTG_SYSCONFIG, val); l = musb_readl(musb->mregs, OTG_FORCESTDBY); l &= ~ENABLEFORCE; /* disable MSTANDBY */ musb_writel(musb->mregs, OTG_FORCESTDBY, l); return 0; }
void musb_platform_restore_context(struct musb *musb, struct musb_context_registers *musb_context) { musb_writel(musb->mregs, OTG_SYSCONFIG, musb_context->otg_sysconfig); musb_writel(musb->mregs, OTG_FORCESTDBY, musb_context->otg_forcestandby); }
int __init musb_platform_init(struct musb *musb, void *board_data) { u32 l; struct omap_musb_board_data *data = board_data; #if defined(CONFIG_ARCH_OMAP2430) omap_cfg_reg(AE5_2430_USB0HS_STP); #endif /* We require some kind of external transceiver, hooked * up through ULPI. TWL4030-family PMICs include one, * which needs a driver, drivers aren't always needed. */ musb->xceiv = otg_get_transceiver(); if (!musb->xceiv) { pr_err("HS USB OTG: no transceiver configured\n"); return -ENODEV; } musb_platform_resume(musb); l = musb_readl(musb->mregs, 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 */ musb_writel(musb->mregs, OTG_SYSCONFIG, l); l = musb_readl(musb->mregs, OTG_INTERFSEL); if (data->interface_type == MUSB_INTERFACE_UTMI) { /* OMAP4 uses Internal PHY GS70 which uses UTMI interface */ l &= ~ULPI_12PIN; /* Disable ULPI */ l |= UTMI_8BIT; /* Enable UTMI */ } else { l |= ULPI_12PIN; } musb_writel(musb->mregs, OTG_INTERFSEL, l); pr_debug("HS USB OTG: revision 0x%x, sysconfig 0x%02x, " "sysstatus 0x%x, intrfsel 0x%x, simenable 0x%x\n", musb_readl(musb->mregs, OTG_REVISION), musb_readl(musb->mregs, OTG_SYSCONFIG), musb_readl(musb->mregs, OTG_SYSSTATUS), musb_readl(musb->mregs, OTG_INTERFSEL), musb_readl(musb->mregs, OTG_SIMENABLE)); if (is_host_enabled(musb)) musb->board_set_vbus = omap_set_vbus; setup_timer(&musb_idle_timer, musb_do_idle, (unsigned long) musb); return 0; }
static int omap2430_musb_init(struct musb *musb) { u32 l; int status = 0; struct device *dev = musb->controller; struct omap2430_glue *glue = dev_get_drvdata(dev->parent); struct musb_hdrc_platform_data *plat = dev->platform_data; struct omap_musb_board_data *data = plat->board_data; /* We require some kind of external transceiver, hooked * up through ULPI. TWL4030-family PMICs include one, * which needs a driver, drivers aren't always needed. */ if (dev->parent->of_node) musb->xceiv = devm_usb_get_phy_by_phandle(dev->parent, "usb-phy", 0); else musb->xceiv = devm_usb_get_phy_dev(dev, 0); if (IS_ERR(musb->xceiv)) { status = PTR_ERR(musb->xceiv); if (status == -ENXIO) return status; pr_err("HS USB OTG: no transceiver configured\n"); return -EPROBE_DEFER; } musb->isr = omap2430_musb_interrupt; status = pm_runtime_get_sync(dev); if (status < 0) { dev_err(dev, "pm_runtime_get_sync FAILED %d\n", status); goto err1; } l = musb_readl(musb->mregs, OTG_INTERFSEL); if (data->interface_type == MUSB_INTERFACE_UTMI) { /* OMAP4 uses Internal PHY GS70 which uses UTMI interface */ l &= ~ULPI_12PIN; /* Disable ULPI */ l |= UTMI_8BIT; /* Enable UTMI */ } else { l |= ULPI_12PIN; } musb_writel(musb->mregs, OTG_INTERFSEL, l); pr_debug("HS USB OTG: revision 0x%x, sysconfig 0x%02x, " "sysstatus 0x%x, intrfsel 0x%x, simenable 0x%x\n", musb_readl(musb->mregs, OTG_REVISION), musb_readl(musb->mregs, OTG_SYSCONFIG), musb_readl(musb->mregs, OTG_SYSSTATUS), musb_readl(musb->mregs, OTG_INTERFSEL), musb_readl(musb->mregs, OTG_SIMENABLE)); setup_timer(&musb_idle_timer, musb_do_idle, (unsigned long) musb); if (glue->status != OMAP_MUSB_UNKNOWN) omap_musb_set_mailbox(glue); usb_phy_init(musb->xceiv); pm_runtime_put_noidle(musb->controller); return 0; err1: return status; }
static int davinci_musb_init(struct musb *musb) { void __iomem *tibase = musb->ctrl_base; u32 revision; int ret = -ENODEV; usb_nop_xceiv_register(); musb->xceiv = usb_get_phy(USB_PHY_TYPE_USB2); if (IS_ERR_OR_NULL(musb->xceiv)) { ret = -EPROBE_DEFER; goto unregister; } musb->mregs += DAVINCI_BASE_OFFSET; /* returns zero if e.g. not clocked */ revision = musb_readl(tibase, DAVINCI_USB_VERSION_REG); if (revision == 0) goto fail; setup_timer(&otg_workaround, otg_timer, (unsigned long) musb); davinci_musb_source_power(musb, 0, 1); /* dm355 EVM swaps D+/D- for signal integrity, and * is clocked from the main 24 MHz crystal. */ if (machine_is_davinci_dm355_evm()) { u32 phy_ctrl = __raw_readl(USB_PHY_CTRL); phy_ctrl &= ~(3 << 9); phy_ctrl |= USBPHY_DATAPOL; __raw_writel(phy_ctrl, USB_PHY_CTRL); } /* On dm355, the default-A state machine needs DRVVBUS control. * If we won't be a host, there's no need to turn it on. */ if (cpu_is_davinci_dm355()) { u32 deepsleep = __raw_readl(DM355_DEEPSLEEP); deepsleep &= ~DRVVBUS_FORCE; __raw_writel(deepsleep, DM355_DEEPSLEEP); } /* reset the controller */ musb_writel(tibase, DAVINCI_USB_CTRL_REG, 0x1); /* start the on-chip PHY and its PLL */ phy_on(); msleep(5); /* NOTE: irqs are in mixed mode, not bypass to pure-musb */ pr_debug("DaVinci OTG revision %08x phy %03x control %02x\n", revision, __raw_readl(USB_PHY_CTRL), musb_readb(tibase, DAVINCI_USB_CTRL_REG)); musb->isr = davinci_musb_interrupt; return 0; fail: usb_put_phy(musb->xceiv); unregister: usb_nop_xceiv_unregister(); return ret; }
static irqreturn_t davinci_musb_interrupt(int irq, void *__hci) { unsigned long flags; irqreturn_t retval = IRQ_NONE; struct musb *musb = __hci; struct usb_otg *otg = musb->xceiv->otg; void __iomem *tibase = musb->ctrl_base; struct cppi *cppi; u32 tmp; spin_lock_irqsave(&musb->lock, flags); /* NOTE: DaVinci shadows the Mentor IRQs. Don't manage them through * the Mentor registers (except for setup), use the TI ones and EOI. * * Docs describe irq "vector" registers associated with the CPPI and * USB EOI registers. These hold a bitmask corresponding to the * current IRQ, not an irq handler address. Would using those bits * resolve some of the races observed in this dispatch code?? */ /* CPPI interrupts share the same IRQ line, but have their own * mask, state, "vector", and EOI registers. */ cppi = container_of(musb->dma_controller, struct cppi, controller); if (is_cppi_enabled() && musb->dma_controller && !cppi->irq) retval = cppi_interrupt(irq, __hci); /* ack and handle non-CPPI interrupts */ tmp = musb_readl(tibase, DAVINCI_USB_INT_SRC_MASKED_REG); musb_writel(tibase, DAVINCI_USB_INT_SRC_CLR_REG, tmp); dev_dbg(musb->controller, "IRQ %08x\n", tmp); musb->int_rx = (tmp & DAVINCI_USB_RXINT_MASK) >> DAVINCI_USB_RXINT_SHIFT; musb->int_tx = (tmp & DAVINCI_USB_TXINT_MASK) >> DAVINCI_USB_TXINT_SHIFT; musb->int_usb = (tmp & DAVINCI_USB_USBINT_MASK) >> DAVINCI_USB_USBINT_SHIFT; /* DRVVBUS irqs are the only proxy we have (a very poor one!) for * DaVinci's missing ID change IRQ. We need an ID change IRQ to * switch appropriately between halves of the OTG state machine. * Managing DEVCTL.SESSION per Mentor docs requires we know its * value, but DEVCTL.BDEVICE is invalid without DEVCTL.SESSION set. * Also, DRVVBUS pulses for SRP (but not at 5V) ... */ if (tmp & (DAVINCI_INTR_DRVVBUS << DAVINCI_USB_USBINT_SHIFT)) { int drvvbus = musb_readl(tibase, DAVINCI_USB_STAT_REG); void __iomem *mregs = musb->mregs; u8 devctl = musb_readb(mregs, MUSB_DEVCTL); int err = musb->int_usb & MUSB_INTR_VBUSERROR; err = musb->int_usb & MUSB_INTR_VBUSERROR; if (err) { /* The Mentor core doesn't debounce VBUS as needed * to cope with device connect current spikes. This * means it's not uncommon for bus-powered devices * to get VBUS errors during enumeration. * * This is a workaround, but newer RTL from Mentor * seems to allow a better one: "re"starting sessions * without waiting (on EVM, a **long** time) for VBUS * to stop registering in devctl. */ musb->int_usb &= ~MUSB_INTR_VBUSERROR; musb->xceiv->state = OTG_STATE_A_WAIT_VFALL; mod_timer(&otg_workaround, jiffies + POLL_SECONDS * HZ); WARNING("VBUS error workaround (delay coming)\n"); } else if (drvvbus) { MUSB_HST_MODE(musb); otg->default_a = 1; musb->xceiv->state = OTG_STATE_A_WAIT_VRISE; portstate(musb->port1_status |= USB_PORT_STAT_POWER); del_timer(&otg_workaround); } else { musb->is_active = 0; MUSB_DEV_MODE(musb); otg->default_a = 0; musb->xceiv->state = OTG_STATE_B_IDLE; portstate(musb->port1_status &= ~USB_PORT_STAT_POWER); } /* NOTE: this must complete poweron within 100 msec * (OTG_TIME_A_WAIT_VRISE) but we don't check for that. */ davinci_musb_source_power(musb, drvvbus, 0); dev_dbg(musb->controller, "VBUS %s (%s)%s, devctl %02x\n", drvvbus ? "on" : "off", usb_otg_state_string(musb->xceiv->state), err ? " ERROR" : "", devctl); retval = IRQ_HANDLED; } if (musb->int_tx || musb->int_rx || musb->int_usb) retval |= musb_interrupt(musb); /* irq stays asserted until EOI is written */ musb_writel(tibase, DAVINCI_USB_EOI_REG, 0); /* poll for ID change */ if (musb->xceiv->state == OTG_STATE_B_IDLE) mod_timer(&otg_workaround, jiffies + POLL_SECONDS * HZ); spin_unlock_irqrestore(&musb->lock, flags); return retval; }
int musb_otg_exec_cmd(unsigned int cmd){ unsigned char devctl; unsigned char intrusb; unsigned short intrtx; unsigned char power; unsigned short csr0; unsigned int usb_l1intp; unsigned int usb_l1ints; unsigned int ret; unsigned long timeout; bool timeout_flag = false; if(!mtk_musb){ DBG(0,"mtk_musb is NULL,error!\n"); } switch(cmd){ case HOST_CMD_ENV_INIT: musb_otg_env_init(); return 0; case HOST_CMD_ENV_EXIT: musb_otg_env_exit (); return 0; } //init musb_writeb(mtk_musb->mregs, MUSB_POWER, 0x21); musb_writeb(mtk_musb->mregs, MUSB_DEVCTL, 0); msleep(300); #ifdef DX_DBG devctl = musb_readb (mtk_musb->mregs,MUSB_DEVCTL); power = musb_readb (mtk_musb->mregs,MUSB_POWER); intrusb = musb_readb(mtk_musb->mregs,MUSB_INTRUSB); DBG(0,"1:cmd=%d,devctl=0x%x,power=0x%x,intrusb=0x%x\n",cmd,devctl,power,intrusb); #endif musb_writew(mtk_musb->mregs,MUSB_INTRRX,0xffff); musb_writew(mtk_musb->mregs,MUSB_INTRTX,0xffff); musb_writeb(mtk_musb->mregs,MUSB_INTRUSB,0xff); msleep(10); #ifdef DX_DBG devctl = musb_readb (mtk_musb->mregs,MUSB_DEVCTL); power = musb_readb (mtk_musb->mregs,MUSB_POWER); intrusb = musb_readb(mtk_musb->mregs,MUSB_INTRUSB); DBG(0,"2:cmd=%d,devctl=0x%x,power=0x%x,intrusb=0x%x\n",cmd,devctl,power,intrusb); #endif high_speed = false; g_exec = 1; DBG(0,"before exec:cmd=%d\n",cmd); switch(cmd){ //electrical case OTG_CMD_E_ENABLE_VBUS: DBG(0,"musb::enable VBUS!\n"); musb_otg_set_session (true); #ifdef MTK_FAN5405_SUPPORT fan5405_set_opa_mode(1); fan5405_set_otg_pl(1); fan5405_set_otg_en(1); #elif defined(MTK_BQ24158_SUPPORT) bq24158_set_opa_mode(1); bq24158_set_otg_pl(1); bq24158_set_otg_en(1); #endif while(g_exec) msleep(100); musb_otg_set_session (false); #ifdef MTK_FAN5405_SUPPORT fan5405_config_interface_liao(0x01,0x30); fan5405_config_interface_liao(0x02,0x8e); #elif defined(MTK_BQ24158_SUPPORT) bq24158_config_interface_reg(0x01,0x30); bq24158_config_interface_reg(0x02,0x8e); #endif break; case OTG_CMD_E_ENABLE_SRP: //need to clear session? DBG(0,"musb::enable srp!\n"); musb_otg_reset_usb(); USBPHY_WRITE8 (0x6c, 0x1); USBPHY_WRITE8 (0x6d, 0x1); musb_writeb(mtk_musb->mregs,0x7B,1); musb_otg_set_session (true); while(g_exec){ msleep(100); } musb_otg_set_session (false); break; case OTG_CMD_E_START_DET_SRP: //need as a A-device musb_writeb(mtk_musb->mregs, MUSB_DEVCTL, 0); devctl = musb_readb (mtk_musb->mregs, MUSB_DEVCTL); while(g_exec&&(devctl & 0x18)){//VBUS[1:0] should be 0, it indicate below SessionEnd DBG(0,"musb::not below session end!\n"); msleep(100); devctl = musb_readb (mtk_musb->mregs,MUSB_DEVCTL); } while(g_exec&&(!(devctl & 0x10))){ DBG(0,"musb::not above session end!\n"); msleep(100); devctl = musb_readb (mtk_musb->mregs,MUSB_DEVCTL); } devctl |= MUSB_DEVCTL_SESSION; musb_writeb(mtk_musb->mregs, MUSB_DEVCTL, devctl); while(g_exec) msleep(100); musb_writeb(mtk_musb->mregs, MUSB_DEVCTL, 0); break; case OTG_CMD_E_START_DET_VBUS: usb_l1intp = musb_readl(mtk_musb->mregs,USB_L1INTP); usb_l1intp &= ~(1<<10); musb_writel(mtk_musb->mregs,USB_L1INTP,usb_l1intp); usb_l1ints = musb_readl(mtk_musb->mregs,USB_L1INTS); while((usb_l1ints&(1<<8))==0){ DBG(0,"musb::vbus is 0!\n"); msleep(100); usb_l1ints = musb_readl(mtk_musb->mregs,USB_L1INTS); } DBG(0,"musb::vbus is detected!\n"); power = musb_readb (mtk_musb->mregs,MUSB_POWER); power |= MUSB_POWER_SOFTCONN; musb_writeb(mtk_musb->mregs, MUSB_POWER, power); while(g_exec) msleep(100); musb_writeb(mtk_musb->mregs, MUSB_POWER, 0x21); break; case OTG_CMD_P_B_UUT_TD59: is_td_59 = true; if(is_td_59) DBG(0, "TD5.9 will be tested!\n"); break; //protocal case OTG_CMD_P_A_UUT: DBG(0,"A-UUT starts...\n"); //polling the session req from B-OPT and start a new session device_enumed = false; TD_4_6: musb_otg_reset_usb(); DBG(0,"A-UUT reset success\n"); timeout = jiffies + 5*HZ; musb_writeb(mtk_musb->mregs, MUSB_DEVCTL, 0); devctl = musb_readb (mtk_musb->mregs, MUSB_DEVCTL); while(g_exec&&(devctl & 0x18)){//VBUS[1:0] should be 0, it indicate below SessionEnd DBG(0,"musb::not below session end!\n"); msleep(100); if(time_after(jiffies,timeout)){ timeout_flag = true; break; } devctl = musb_readb (mtk_musb->mregs,MUSB_DEVCTL); } if(timeout_flag){ timeout_flag = false; musb_otg_reset_usb(); DBG(0,"timeout for below session end, after reset usb, devctl=0x%x\n",musb_readb(mtk_musb->mregs,MUSB_DEVCTL)); } DBG(0,"polling session request,begin\n"); ret = musb_polling_bus_interrupt(MUSB_INTR_SESSREQ); DBG(0,"polling session request,done,ret=0x%x\n",ret); if(TEST_IS_STOP == ret) break; musb_otg_set_session(true);//session is set and VBUS will be out. #if 1 power = musb_readb(mtk_musb->mregs,MUSB_POWER); power &= ~MUSB_POWER_SOFTCONN; musb_writeb(mtk_musb->mregs,MUSB_POWER,power); #endif //polling the connect interrupt from B-OPT DBG(0,"polling connect interrupt,begin\n"); ret = musb_polling_bus_interrupt(MUSB_INTR_CONNECT); DBG(0,"polling connect interrupt,done,ret=0x%x\n",ret); if(TEST_IS_STOP == ret) break; if(DEV_NOT_CONNECT == ret){ DBG(0,"device is not connected in 15s\n"); g_otg_message.msg = OTG_MSG_DEV_NOT_RESPONSE; break; } DBG(0,"musb::connect interrupt is detected!\n"); msleep(100);//the test is fail beacuse the reset starts less than100 ms from the B-OPT connect. the IF test needs //reset the bus,check whether it is a hs device musb_h_reset();//should last for more than 50ms, TD.4.2 musb_h_enumerate(); //suspend the bus csr0 = musb_readw(mtk_musb->mregs, MUSB_OTG_CSR0); DBG(0,"after enum B-OPT,csr0=0x%x\n",csr0); musb_h_suspend(); //polling the disconnect interrupt from B-OPT, and remote wakeup(TD.4.8) DBG(0,"polling disconnect or remote wakeup,begin\n"); ret = musb_polling_bus_interrupt(MUSB_INTR_DISCONNECT|MUSB_INTR_RESUME); DBG(0,"polling disconnect or remote wakeup,done,ret=0x%x\n",ret); if(TEST_IS_STOP == ret) break; if(MUSB_INTR_RESUME == ret){ //for TD4.8 musb_h_remote_wakeup(); //maybe need to access the B-OPT, get device descriptor if(g_exec) wait_for_completion (&stop_event); break; } //polling the reset interrupt from B-OPT if(!(ret & MUSB_INTR_RESET)){ DBG(0,"polling reset for B-OPT,begin\n"); ret = musb_polling_bus_interrupt(MUSB_INTR_RESET); DBG(0,"polling reset for B-OPT,done,ret=0x%x\n",ret); if(TEST_IS_STOP == ret) break; if(DEV_NOT_RESET == ret){ if(g_exec) wait_for_completion (&stop_event); break; } } DBG(0,"after receive reset,devctl=0x%x,csr0=0x%x\n",musb_readb(mtk_musb->mregs, MUSB_DEVCTL),musb_readw(mtk_musb->mregs, MUSB_OTG_CSR0)); //enumerate and polling the suspend interrupt form B-OPT do{ intrtx = musb_readw(mtk_musb->mregs, MUSB_INTRTX); mb(); musb_writew(mtk_musb->mregs, MUSB_INTRTX, intrtx); intrusb = musb_readb(mtk_musb->mregs, MUSB_INTRUSB); mb(); musb_writeb(mtk_musb->mregs, MUSB_INTRUSB,intrusb); if(intrtx || (intrusb&MUSB_INTR_SUSPEND)){ if(intrtx){ if(intrtx&0x1) musb_d_enumerated(); } if(intrusb){ if(intrusb&MUSB_INTR_SUSPEND){//maybe receive disconnect interrupt when the session is end if(device_enumed){ break;//return form the while loop } else{//TD.4.6 musb_d_soft_connect (false); goto TD_4_6; } } } } else wait_for_completion_timeout(&stop_event,1); } while(g_exec);//the enum will be repeated for 5 times if(!g_exec){ break;//return form the switch-case } DBG(0,"polling connect form B-OPT,begin\n"); ret = musb_polling_bus_interrupt(MUSB_INTR_CONNECT);//B-OPT will connect again 100ms after A disconnect DBG(0,"polling connect form B-OPT,done,ret=0x%x\n",ret); if(TEST_IS_STOP == ret) break; musb_h_reset();//should reset bus again, TD.4.7 wait_for_completion (&stop_event); DBG(0,"the test as A-UUT is done\n"); break; case OTG_CMD_P_B_UUT: musb_otg_reset_usb(); //The B-UUT issues an SRP to start a session with the A-OPT musb_otg_set_session (true); //100ms after VBUS begins to decay the A-OPT powers VBUS timeout = jiffies + 5 * HZ; devctl = musb_readb (mtk_musb->mregs, MUSB_DEVCTL); while(((devctl & MUSB_DEVCTL_VBUS)>>MUSB_DEVCTL_VBUS_SHIFT)<0x3){ if(time_after(jiffies, timeout)){ timeout_flag = true; break; } msleep(100); devctl = musb_readb (mtk_musb->mregs,MUSB_DEVCTL); } if(timeout_flag){ DBG(0,"B-UUT set vbus timeout\n"); g_otg_message.msg = OTG_MSG_DEV_NOT_RESPONSE; timeout_flag = false; break; } //After detecting the VBUS, B-UUT should connect to the A_OPT power = musb_readb(mtk_musb->mregs, MUSB_POWER); power |= MUSB_POWER_HSENAB; musb_writeb(mtk_musb->mregs, MUSB_POWER,power); //TD5_5: musb_d_soft_connect(true); device_enumed = false; //polling the reset single form the A-OPT DBG(0,"polling reset form A-OPT,begin\n"); ret = musb_polling_bus_interrupt(MUSB_INTR_RESET); DBG(0,"polling reset form A-OPT,done,ret=0x%x\n",ret); if(TEST_IS_STOP == ret) break; power = musb_readb(mtk_musb->mregs,MUSB_POWER); if(power & MUSB_POWER_HSMODE){ high_speed = true; } else high_speed = false; //The A-OPT enumerates the B-UUT TD6_13: do{ intrtx = musb_readw(mtk_musb->mregs, MUSB_INTRTX); mb(); musb_writew(mtk_musb->mregs, MUSB_INTRTX,intrtx); intrusb = musb_readb(mtk_musb->mregs, MUSB_INTRUSB); mb(); musb_writeb(mtk_musb->mregs, MUSB_INTRUSB,intrusb); if(intrtx || (intrusb & 0xf7)){ if(intrtx){ //DBG(0,"B-enum,intrtx=0x%x\n",intrtx); if(intrtx&0x1) DBG(0,"ep0 interrupt\n"); musb_d_enumerated(); } if(intrusb){ if(intrusb & 0xf7) DBG(0,"B-enum,intrusb=0x%x,power=0x%x\n",intrusb,musb_readb(mtk_musb->mregs,MUSB_POWER)); if((device_enumed)&&(intrusb & MUSB_INTR_SUSPEND)){ DBG(0,"suspend interrupt is received,power=0x%x,devctl=0x%x\n",musb_readb(mtk_musb->mregs,MUSB_POWER),musb_readb(mtk_musb->mregs,MUSB_DEVCTL)); break; } } } else{ DBG(0,"power=0x%x,devctl=0x%x,intrtx=0x%x,intrusb=0x%x\n",musb_readb(mtk_musb->mregs,MUSB_POWER),musb_readb(mtk_musb->mregs,MUSB_DEVCTL),musb_readw(mtk_musb->mregs,MUSB_INTRTX),musb_readb(mtk_musb->mregs,MUSB_INTRUSB)); wait_for_completion_timeout (&stop_event,1); } } while(g_exec); if(!g_exec) break; DBG(0,"hnp start\n"); if(intrusb & MUSB_INTR_RESUME) goto TD6_13; if(!(intrusb & MUSB_INTR_CONNECT)){ //polling the connect from A-OPT, the UUT acts as host DBG(0,"polling connect or resume form A-OPT,begin\n"); ret = musb_polling_bus_interrupt(MUSB_INTR_CONNECT|MUSB_INTR_RESUME); DBG(0,"polling connect or resume form A-OPT,done,ret=0x%x\n",ret); if(TEST_IS_STOP == ret) break; if(MUSB_INTR_RESUME == ret){ goto TD6_13; } if(DEV_HNP_TIMEOUT == ret){ DBG(0,"B-UUT HNP timeout\n"); devctl = musb_readb(mtk_musb->mregs,MUSB_DEVCTL); //DBG(0,"hnp timeout,power=0x%x,devctl=0x%x\n",musb_readb(mtk_musb->mregs,MUSB_POWER),devctl); devctl &= ~MUSB_DEVCTL_HR; musb_writeb(mtk_musb->mregs,MUSB_DEVCTL,devctl); if(is_td_59) g_otg_message.msg = OTG_MSG_DEV_NOT_RESPONSE; break; } } //reset the bus and check whether it is a hs device musb_h_reset(); musb_h_enumerate(); //suspend the bus musb_h_suspend(); //polling the disconnect interrupt from A-OPT DBG(0,"polling disconnect form A-OPT,begin\n"); ret = musb_polling_bus_interrupt(MUSB_INTR_DISCONNECT); DBG(0,"polling disconnect form A-OPT,done,ret=0x%x\n",ret); //DBG(0,"power=0x%x,devctl=0x%x,intrusb=0x%x\n",musb_readb(mtk_musb->mregs,MUSB_POWER),musb_readb(mtk_musb->mregs,MUSB_DEVCTL),musb_readb(mtk_musb->mregs,MUSB_INTRUSB)); if(TEST_IS_STOP == ret) break; DBG(0,"A-OPT is disconnected, UUT will be back to device\n"); if(!(ret & MUSB_INTR_RESET)){ musb_d_soft_connect(true); //polling the reset single form the A-OPT DBG(0,"polling reset form A-OPT,begin\n"); ret = musb_polling_bus_interrupt(MUSB_INTR_RESET); //musb_d_reset (); DBG(0,"polling reset form A-OPT,done,ret=0x%x\n",ret); if(TEST_IS_STOP == ret) break; } device_enumed = false; if(g_exec) goto TD6_13;//TD5_5 wait_for_completion(&stop_event); DBG(0,"test as B_UUT is done\n"); break; case HOST_CMD_TEST_SE0_NAK: case HOST_CMD_TEST_J: case HOST_CMD_TEST_K: case HOST_CMD_TEST_PACKET: case HOST_CMD_SUSPEND_RESUME: case HOST_CMD_GET_DESCRIPTOR: case HOST_CMD_SET_FEATURE: musb_host_test_mode(cmd); while(g_exec) msleep(100); break; } DBG(0,"musb_otg_exec_cmd--\n"); return 0; }
int musb_otg_env_init(void){ u8 power; //u8 intrusb; //step1: mask the PMU/PMIC EINT mtk_musb->usb_if = true; mtk_musb->is_host = true;//workaround for PMIC charger detection //mt65xx_eint_mask(EINT_CHR_DET_NUM); upmu_interrupt_chrdet_int_en(0); #ifndef MTK_FAN5405_SUPPORT #ifndef MTK_NCP1851_SUPPORT #ifndef MTK_BQ24196_SUPPORT #ifndef MTK_BQ24158_SUPPORT //set the drvvbus mode as drvvbus(mode 6) #if !(defined(CONFIG_MT6585_FPGA) || defined(CONFIG_MT6577_FPGA) || defined(CONFIG_MT6589_FPGA) || defined(CONFIG_MT6582_FPGA)) #if defined(GPIO_OTG_DRVVBUS_PIN) mt_set_gpio_mode(GPIO_OTG_DRVVBUS_PIN,6); #endif #endif #endif #endif #endif #endif //step5: make sure to power on the USB module if(mtk_musb->power) mtk_musb->power = FALSE; musb_platform_enable(mtk_musb); //step6: clear session bit musb_writeb(mtk_musb->mregs,MUSB_DEVCTL,0); //step7: disable and enable usb interrupt usb_l1intm_store = musb_readl(mtk_musb->mregs,USB_L1INTM); usb_intrrxe_store = musb_readw(mtk_musb->mregs,MUSB_INTRRXE); usb_intrtxe_store = musb_readw(mtk_musb->mregs,MUSB_INTRTXE); usb_intrusbe_store = musb_readb(mtk_musb->mregs,MUSB_INTRUSBE); musb_writel(mtk_musb->mregs,USB_L1INTM,0); musb_writew(mtk_musb->mregs,MUSB_INTRRXE,0); musb_writew(mtk_musb->mregs,MUSB_INTRTXE,0); musb_writeb(mtk_musb->mregs,MUSB_INTRUSBE,0); musb_writew(mtk_musb->mregs,MUSB_INTRRX,0xffff); musb_writew(mtk_musb->mregs,MUSB_INTRTX,0xffff); musb_writeb(mtk_musb->mregs,MUSB_INTRUSB,0xff); free_irq (mtk_musb->nIrq, mtk_musb); musb_writel(mtk_musb->mregs,USB_L1INTM,0x105); musb_writew(mtk_musb->mregs,MUSB_INTRTXE,1); musb_writeb(mtk_musb->mregs,MUSB_INTRUSBE,0xf7); //setp8: set the index to 0 for ep0, maybe no need. Designers said it is better not to use the index register. musb_writeb(mtk_musb->mregs, MUSB_INDEX, 0); //setp9: init message g_otg_message.msg = 0; spin_lock_init(&g_otg_message.lock); init_completion(&stop_event); #ifdef DX_DBG power = musb_readb(mtk_musb->mregs,MUSB_POWER); DBG(0,"start the USB-IF test in EM,power=0x%x!\n",power); #endif return 0; }