static irqreturn_t ux500_musb_interrupt(int irq, void *__hci) { unsigned long flags; irqreturn_t retval = IRQ_NONE; struct musb *musb = __hci; spin_lock_irqsave(&musb->lock, flags); musb->int_usb = musb_readb(musb->mregs, MUSB_INTRUSB); musb->int_tx = musb_readw(musb->mregs, MUSB_INTRTX); musb->int_rx = musb_readw(musb->mregs, MUSB_INTRRX); if (musb->int_usb || musb->int_tx || musb->int_rx) retval = musb_interrupt(musb); spin_unlock_irqrestore(&musb->lock, flags); return retval; }
unsigned int musb_polling_ep0_interrupt(void){ unsigned short intrtx; DBG(0,"polling ep0 interrupt\n"); do{ intrtx = musb_readw(mtk_musb->mregs,MUSB_INTRTX); mb(); musb_writew(mtk_musb->mregs,MUSB_INTRTX,intrtx); if(intrtx&0x1){//ep0 interrupt happen DBG(0,"get ep0 interrupt,csr0=0x%x\n",musb_readw(mtk_musb->mregs, MUSB_OTG_CSR0)); break; } else{ DBG(0,"polling ep0 interrupt,csr0=0x%x\n",musb_readb(mtk_musb->mregs,MUSB_OTG_CSR0)); wait_for_completion_timeout (&stop_event,1); if(!g_exec) return TEST_IS_STOP; } } while(g_exec); return 0; }
/** * funct_host_notify_timer() - Initialize the timer for USB host driver. * @data: usb host data. * * This function runs the timer for the USB host mode. */ static void funct_host_notify_timer(unsigned long data) { if (!cpu_is_u5500()) { struct musb *musb = (struct musb *)data; unsigned long flags; u8 devctl; spin_lock_irqsave(&musb->lock, flags); stm_set_peripheral_clock(PERI5_CLK_ENABLE); devctl = musb_readb(musb->mregs, MUSB_DEVCTL); switch (musb->xceiv->state) { case OTG_STATE_A_WAIT_BCON: 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); } #ifdef CONFIG_PM if (!(devctl & MUSB_DEVCTL_SESSION)) stm_musb_context(USB_DISABLE); #endif break; case OTG_STATE_A_SUSPEND: default: break; } stm_set_peripheral_clock(PERI5_CLK_DISABLE); spin_unlock_irqrestore(&musb->lock, flags); DBG(1, "otg_state %s devctl %d\n", otg_state_string(musb), devctl); } }
static irqreturn_t sunxi_musb_interrupt(int irq, void *__hci) { struct musb *musb = __hci; irqreturn_t retval = IRQ_NONE; /* read and flush interrupts */ musb->int_usb = musb_readb(musb->mregs, MUSB_INTRUSB); if (musb->int_usb) musb_writeb(musb->mregs, MUSB_INTRUSB, musb->int_usb); musb->int_tx = musb_readw(musb->mregs, MUSB_INTRTX); if (musb->int_tx) musb_writew(musb->mregs, MUSB_INTRTX, musb->int_tx); musb->int_rx = musb_readw(musb->mregs, MUSB_INTRRX); if (musb->int_rx) musb_writew(musb->mregs, MUSB_INTRRX, musb->int_rx); if (musb->int_usb || musb->int_tx || musb->int_rx) retval |= musb_interrupt(musb); return retval; }
/** * musb_platform_set_mode() - Set the mode for the USB driver. * @musb: struct musb pointer. * @musb_mode: usb mode. * * This function set the mode for the USB. */ int musb_platform_set_mode(struct musb *musb, u8 musb_mode) { u8 devctl = musb_readb(musb->mregs, MUSB_DEVCTL); devctl |= MUSB_DEVCTL_SESSION; musb_writeb(musb->mregs, MUSB_DEVCTL, devctl); switch (musb_mode) { case MUSB_HOST: otg_set_host(musb->xceiv, musb->xceiv->host); break; case MUSB_PERIPHERAL: otg_set_peripheral(musb->xceiv, musb->xceiv->gadget); break; case MUSB_OTG: break; default: return -EINVAL; } 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 int omap2430_musb_set_mode(struct musb *musb, u8 musb_mode) { u8 devctl = musb_readb(musb->mregs, MUSB_DEVCTL); devctl |= MUSB_DEVCTL_SESSION; /* this bit only works in the b_peripheral state * to start the transition to b_wait_aconn * and would normally be set through as a response * to a b_hnp_enable */ if (musb_mode == MUSB_HOST) { devctl |= MUSB_DEVCTL_HR; if (musb->g.is_otg) musb->g.b_hnp_enable = 1; } else if (musb_mode == MUSB_PERIPHERAL) { devctl &= (~MUSB_DEVCTL_HR); } musb_writeb(musb->mregs, MUSB_DEVCTL, devctl); return 0; }
int __init musb_platform_init(struct musb *musb) { void __iomem *tibase = musb->ctrl_base; u32 revision; musb->mregs += DAVINCI_BASE_OFFSET; clk_enable(musb->clock); /* 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; }
/** * musb_set_session() - Start the USB session * * This function is used to start the USB sessios in USB host mode * once the A cable is plugged in */ void musb_set_session(int is_on) { u8 val; void __iomem *regs; struct musb *musb; if (musb_status == NULL) { printk(KERN_ERR "Error: devctl session cannot be set\n"); return; } musb = musb_status; regs = musb_status->mregs; val = musb_readb(regs, MUSB_DEVCTL); if (is_on) musb_writeb(regs, MUSB_DEVCTL, val | MUSB_DEVCTL_SESSION); else { val &= ~MUSB_DEVCTL_SESSION; musb_writeb(regs, MUSB_DEVCTL, val); musb->xceiv->state = OTG_STATE_B_IDLE; MUSB_DEV_MODE(musb); } }
static int davinci_musb_exit(struct musb *musb) { if (is_host_enabled(musb)) del_timer_sync(&otg_workaround); /* force VBUS off */ if (cpu_is_davinci_dm355()) { u32 deepsleep = __raw_readl(DM355_DEEPSLEEP); deepsleep &= ~DRVVBUS_FORCE; deepsleep |= DRVVBUS_OVERRIDE; __raw_writel(deepsleep, DM355_DEEPSLEEP); } davinci_musb_source_power(musb, 0 /*off*/, 1); /* delay, to avoid problems with module reload */ if (is_host_enabled(musb) && musb->xceiv->default_a) { int maxdelay = 30; u8 devctl, warn = 0; /* if there's no peripheral connected, this can take a * long time to fall, especially on EVM with huge C133. */ do { devctl = musb_readb(musb->mregs, MUSB_DEVCTL); if (!(devctl & MUSB_DEVCTL_VBUS)) break; if ((devctl & MUSB_DEVCTL_VBUS) != warn) { warn = devctl & MUSB_DEVCTL_VBUS; DBG(1, "VBUS %d\n", warn >> MUSB_DEVCTL_VBUS_SHIFT); } msleep(1000); maxdelay--; } while (maxdelay > 0);
static void musb_port_reset(struct musb *musb, bool do_reset) { u8 power; void __iomem *mbase = musb->mregs; if (is_otg_enabled(musb) && musb->xceiv->state == OTG_STATE_B_IDLE) { dev_dbg(musb->controller, "HNP: Returning from HNP; no hub reset from b_idle\n"); musb->port1_status &= ~USB_PORT_STAT_RESET; return; } if (!is_host_enabled(musb)) return; /* NOTE: caller guarantees it will turn off the reset when * the appropriate amount of time has passed */ power = musb_readb(mbase, MUSB_POWER); if (do_reset) { /* * If RESUME is set, we must make sure it stays minimum 20 ms. * Then we must clear RESUME and wait a bit to let musb start * generating SOFs. If we don't do this, OPT HS A 6.8 tests * fail with "Error! Did not receive an SOF before suspend * detected". */ if (power & MUSB_POWER_RESUME) { while (time_before(jiffies, musb->rh_timer)) msleep(1); musb_writeb(mbase, MUSB_POWER, power & ~MUSB_POWER_RESUME); msleep(1); } musb->ignore_disconnect = true; power &= 0xf0; musb_writeb(mbase, MUSB_POWER, power | MUSB_POWER_RESET); musb->port1_status |= USB_PORT_STAT_RESET; musb->port1_status &= ~USB_PORT_STAT_ENABLE; musb->rh_timer = jiffies + msecs_to_jiffies(50); } else { dev_dbg(musb->controller, "root port reset stopped\n"); musb_writeb(mbase, MUSB_POWER, power & ~MUSB_POWER_RESET); musb->ignore_disconnect = false; power = musb_readb(mbase, MUSB_POWER); if (power & MUSB_POWER_HSMODE) { dev_dbg(musb->controller, "high-speed device connected\n"); musb->port1_status |= USB_PORT_STAT_HIGH_SPEED; } musb->port1_status &= ~USB_PORT_STAT_RESET; musb->port1_status |= USB_PORT_STAT_ENABLE | (USB_PORT_STAT_C_RESET << 16) | (USB_PORT_STAT_C_ENABLE << 16); usb_hcd_poll_rh_status(musb_to_hcd(musb)); musb->vbuserr_retry = VBUSERR_RETRY_COUNT; } }
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; }
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; }
int __init musb_platform_init(struct musb *musb) { void __iomem *tibase = musb->ctrl_base; u32 revision; usb_nop_xceiv_register(); musb->xceiv = otg_get_transceiver(); if (!musb->xceiv) return -ENODEV; musb->mregs += DAVINCI_BASE_OFFSET; clk_enable(musb->clock); /* returns zero if e.g. not clocked */ revision = musb_readl(tibase, DAVINCI_USB_VERSION_REG); if (revision == 0) goto fail; 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); /* 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); if (is_host_enabled(musb)) { deepsleep &= ~DRVVBUS_OVERRIDE; } else { deepsleep &= ~DRVVBUS_FORCE; deepsleep |= DRVVBUS_OVERRIDE; } __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_interrupt; return 0; fail: usb_nop_xceiv_unregister(); return -ENODEV; }
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; }
void musb_port_reset(struct musb *musb, bool do_reset) { u8 power; void __iomem *mbase = musb->mregs; if (musb->xceiv->state == OTG_STATE_B_IDLE) { dev_dbg(musb->controller, "HNP: Returning from HNP; no hub reset from b_idle\n"); musb->port1_status &= ~USB_PORT_STAT_RESET; return; } if (!is_host_active(musb)) return; /* NOTE: caller guarantees it will turn off the reset when * the appropriate amount of time has passed */ power = musb_readb(mbase, MUSB_POWER); if (do_reset) { /* * If RESUME is set, we must make sure it stays minimum 20 ms. * Then we must clear RESUME and wait a bit to let musb start * generating SOFs. If we don't do this, OPT HS A 6.8 tests * fail with "Error! Did not receive an SOF before suspend * detected". */ if (power & MUSB_POWER_RESUME) { long remain = (unsigned long) musb->rh_timer - jiffies; if (musb->rh_timer > 0 && remain > 0) { /* take into account the minimum delay after resume */ schedule_delayed_work( &musb->deassert_reset_work, remain); return; } musb_writeb(mbase, MUSB_POWER, power & ~MUSB_POWER_RESUME); /* Give the core 1 ms to clear MUSB_POWER_RESUME */ schedule_delayed_work(&musb->deassert_reset_work, msecs_to_jiffies(1)); return; } power &= 0xf0; musb_writeb(mbase, MUSB_POWER, power | MUSB_POWER_RESET); musb->port1_status |= USB_PORT_STAT_RESET; musb->port1_status &= ~USB_PORT_STAT_ENABLE; schedule_delayed_work(&musb->deassert_reset_work, msecs_to_jiffies(50)); } else { dev_dbg(musb->controller, "root port reset stopped\n"); musb_writeb(mbase, MUSB_POWER, power & ~MUSB_POWER_RESET); power = musb_readb(mbase, MUSB_POWER); if (power & MUSB_POWER_HSMODE) { dev_dbg(musb->controller, "high-speed device connected\n"); musb->port1_status |= USB_PORT_STAT_HIGH_SPEED; } musb->port1_status &= ~USB_PORT_STAT_RESET; musb->port1_status |= USB_PORT_STAT_ENABLE | (USB_PORT_STAT_C_RESET << 16) | (USB_PORT_STAT_C_ENABLE << 16); usb_hcd_poll_rh_status(musb->hcd); musb->vbuserr_retry = VBUSERR_RETRY_COUNT; } }
static irqreturn_t da8xx_musb_interrupt(int irq, void *hci) { struct musb *musb = hci; void __iomem *reg_base = musb->ctrl_base; struct usb_otg *otg = musb->xceiv->otg; unsigned long flags; irqreturn_t ret = IRQ_NONE; u32 status; spin_lock_irqsave(&musb->lock, flags); /* * NOTE: DA8XX shadows the Mentor IRQs. Don't manage them through * the Mentor registers (except for setup), use the TI ones and EOI. */ /* Acknowledge and handle non-CPPI interrupts */ status = musb_readl(reg_base, DA8XX_USB_INTR_SRC_MASKED_REG); if (!status) goto eoi; musb_writel(reg_base, DA8XX_USB_INTR_SRC_CLEAR_REG, status); dev_dbg(musb->controller, "USB IRQ %08x\n", status); musb->int_rx = (status & DA8XX_INTR_RX_MASK) >> DA8XX_INTR_RX_SHIFT; musb->int_tx = (status & DA8XX_INTR_TX_MASK) >> DA8XX_INTR_TX_SHIFT; musb->int_usb = (status & DA8XX_INTR_USB_MASK) >> DA8XX_INTR_USB_SHIFT; /* * DRVVBUS IRQs are the only proxy we have (a very poor one!) for * DA8xx'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 that we know its * value but DEVCTL.BDevice is invalid without DEVCTL.Session set. * Also, DRVVBUS pulses for SRP (but not at 5 V)... */ if (status & (DA8XX_INTR_DRVVBUS << DA8XX_INTR_USB_SHIFT)) { int drvvbus = musb_readl(reg_base, DA8XX_USB_STAT_REG); void __iomem *mregs = musb->mregs; u8 devctl = musb_readb(mregs, MUSB_DEVCTL); int err; 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 for VBUS to stop registering in * devctl. */ musb->int_usb &= ~MUSB_INTR_VBUSERROR; musb->xceiv->otg->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->otg->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->otg->state = OTG_STATE_B_IDLE; portstate(musb->port1_status &= ~USB_PORT_STAT_POWER); } dev_dbg(musb->controller, "VBUS %s (%s)%s, devctl %02x\n", drvvbus ? "on" : "off", usb_otg_state_string(musb->xceiv->otg->state), err ? " ERROR" : "", devctl); ret = IRQ_HANDLED; } if (musb->int_tx || musb->int_rx || musb->int_usb) ret |= musb_interrupt(musb); eoi: /* EOI needs to be written for the IRQ to be re-asserted. */ if (ret == IRQ_HANDLED || status) musb_writel(reg_base, DA8XX_USB_END_OF_INTR_REG, 0); /* Poll for ID change */ if (musb->xceiv->otg->state == OTG_STATE_B_IDLE) mod_timer(&otg_workaround, jiffies + POLL_SECONDS * HZ); spin_unlock_irqrestore(&musb->lock, flags); return ret; }
static irqreturn_t dsps_interrupt(int irq, void *hci) { struct musb *musb = hci; void __iomem *reg_base = musb->ctrl_base; struct device *dev = musb->controller; struct dsps_glue *glue = dev_get_drvdata(dev->parent); const struct dsps_musb_wrapper *wrp = glue->wrp; unsigned long flags; irqreturn_t ret = IRQ_NONE; u32 epintr, usbintr; spin_lock_irqsave(&musb->lock, flags); /* Get endpoint interrupts */ epintr = musb_readl(reg_base, wrp->epintr_status); musb->int_rx = (epintr & wrp->rxep_bitmap) >> wrp->rxep_shift; musb->int_tx = (epintr & wrp->txep_bitmap) >> wrp->txep_shift; if (epintr) musb_writel(reg_base, wrp->epintr_status, epintr); /* Get usb core interrupts */ usbintr = musb_readl(reg_base, wrp->coreintr_status); if (!usbintr && !epintr) goto out; musb->int_usb = (usbintr & wrp->usb_bitmap) >> wrp->usb_shift; if (usbintr) musb_writel(reg_base, wrp->coreintr_status, usbintr); dev_dbg(musb->controller, "usbintr (%x) epintr(%x)\n", usbintr, epintr); if (usbintr & ((1 << wrp->drvvbus) << wrp->usb_shift)) { int drvvbus = musb_readl(reg_base, wrp->status); void __iomem *mregs = musb->mregs; u8 devctl = musb_readb(mregs, MUSB_DEVCTL); int err; 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 for VBUS to stop registering in * devctl. */ musb->int_usb &= ~MUSB_INTR_VBUSERROR; musb->xceiv->otg->state = OTG_STATE_A_WAIT_VFALL; dsps_mod_timer_optional(glue); WARNING("VBUS error workaround (delay coming)\n"); } else if (drvvbus) { MUSB_HST_MODE(musb); musb->xceiv->otg->default_a = 1; musb->xceiv->otg->state = OTG_STATE_A_WAIT_VRISE; dsps_mod_timer_optional(glue); } else { musb->is_active = 0; MUSB_DEV_MODE(musb); musb->xceiv->otg->default_a = 0; musb->xceiv->otg->state = OTG_STATE_B_IDLE; } /* NOTE: this must complete power-on within 100 ms. */ dev_dbg(musb->controller, "VBUS %s (%s)%s, devctl %02x\n", drvvbus ? "on" : "off", usb_otg_state_string(musb->xceiv->otg->state), err ? " ERROR" : "", devctl); ret = IRQ_HANDLED; } if (musb->int_tx || musb->int_rx || musb->int_usb) ret |= musb_interrupt(musb); /* Poll for ID change and connect */ switch (musb->xceiv->otg->state) { case OTG_STATE_B_IDLE: case OTG_STATE_A_WAIT_BCON: dsps_mod_timer_optional(glue); break; default: break; } out: spin_unlock_irqrestore(&musb->lock, flags); return ret; }
static int dsps_musb_init(struct musb *musb) { struct device *dev = musb->controller; struct dsps_glue *glue = dev_get_drvdata(dev->parent); struct platform_device *parent = to_platform_device(dev->parent); const struct dsps_musb_wrapper *wrp = glue->wrp; void __iomem *reg_base; struct resource *r; u32 rev, val; int ret; r = platform_get_resource_byname(parent, IORESOURCE_MEM, "control"); reg_base = devm_ioremap_resource(dev, r); if (IS_ERR(reg_base)) return PTR_ERR(reg_base); musb->ctrl_base = reg_base; /* NOP driver needs change if supporting dual instance */ musb->xceiv = devm_usb_get_phy_by_phandle(dev->parent, "phys", 0); if (IS_ERR(musb->xceiv)) return PTR_ERR(musb->xceiv); musb->phy = devm_phy_get(dev->parent, "usb2-phy"); /* Returns zero if e.g. not clocked */ rev = musb_readl(reg_base, wrp->revision); if (!rev) return -ENODEV; if (IS_ERR(musb->phy)) { musb->phy = NULL; } else { ret = phy_init(musb->phy); if (ret < 0) return ret; ret = phy_power_on(musb->phy); if (ret) { phy_exit(musb->phy); return ret; } } timer_setup(&musb->dev_timer, otg_timer, 0); /* Reset the musb */ musb_writel(reg_base, wrp->control, (1 << wrp->reset)); musb->isr = dsps_interrupt; /* reset the otgdisable bit, needed for host mode to work */ val = musb_readl(reg_base, wrp->phy_utmi); val &= ~(1 << wrp->otg_disable); musb_writel(musb->ctrl_base, wrp->phy_utmi, val); /* * Check whether the dsps version has babble control enabled. * In latest silicon revision the babble control logic is enabled. * If MUSB_BABBLE_CTL returns 0x4 then we have the babble control * logic enabled. */ val = musb_readb(musb->mregs, MUSB_BABBLE_CTL); if (val & MUSB_BABBLE_RCV_DISABLE) { glue->sw_babble_enabled = true; val |= MUSB_BABBLE_SW_SESSION_CTRL; musb_writeb(musb->mregs, MUSB_BABBLE_CTL, val); } dsps_mod_timer(glue, -1); return dsps_musb_dbg_init(musb, glue); }
static void musb_port_suspend(struct musb *musb, bool do_suspend) { u8 power; void __iomem *mbase = musb->mregs; struct device *dev = musb->controller; struct musb_hdrc_platform_data *plat = dev->platform_data; struct omap_musb_board_data *data = plat->board_data; if (!is_host_active(musb)) return; /* NOTE: this doesn't necessarily put PHY into low power mode, * turning off its clock; that's a function of PHY integration and * MUSB_POWER_ENSUSPEND. PHY may need a clock (sigh) to detect * SE0 changing to connect (J) or wakeup (K) states. */ power = musb_readb(mbase, MUSB_POWER); if (do_suspend) { int retries = 10000; power &= ~MUSB_POWER_RESUME; power |= MUSB_POWER_SUSPENDM; if (data->interface_type == MUSB_INTERFACE_UTMI) power |= MUSB_POWER_ENSUSPEND; musb_writeb(mbase, MUSB_POWER, power); /* Needed for OPT A tests */ power = musb_readb(mbase, MUSB_POWER); while (power & MUSB_POWER_SUSPENDM) { power = musb_readb(mbase, MUSB_POWER); if (retries-- < 1) break; } DBG(3, "Root port suspended, power %02x\n", power); musb->port1_status |= USB_PORT_STAT_SUSPEND; switch (musb->xceiv->state) { case OTG_STATE_A_HOST: musb->xceiv->state = OTG_STATE_A_SUSPEND; musb->is_active = is_otg_enabled(musb) && musb->xceiv->host->b_hnp_enable; if (musb->is_active) mod_timer(&musb->otg_timer, jiffies + msecs_to_jiffies( OTG_TIME_A_AIDL_BDIS)); musb_platform_try_idle(musb, 0); /* * disable the phy clock when the device is supended. * this will allow the core retention */ otg_set_clk(musb->xceiv, 0); break; #ifdef CONFIG_USB_MUSB_OTG case OTG_STATE_B_HOST: musb->xceiv->state = OTG_STATE_B_WAIT_ACON; musb->is_active = is_otg_enabled(musb) && musb->xceiv->host->b_hnp_enable; musb_platform_try_idle(musb, 0); break; #endif default: DBG(1, "bogus rh suspend? %s\n", otg_state_string(musb)); } } else if (power & MUSB_POWER_SUSPENDM) { power &= ~MUSB_POWER_SUSPENDM; if (data->interface_type == MUSB_INTERFACE_UTMI) power &= ~MUSB_POWER_ENSUSPEND; power |= MUSB_POWER_RESUME; musb_writeb(mbase, MUSB_POWER, power); otg_set_clk(musb->xceiv, 1); DBG(3, "Root port resuming, power %02x\n", power); /* later, GetPortStatus will stop RESUME signaling */ musb->port1_status |= MUSB_PORT_STAT_RESUME; musb->rh_timer = jiffies + msecs_to_jiffies(20); } }
/* Caller must take musb->lock */ static int dsps_check_status(struct musb *musb, void *unused) { void __iomem *mregs = musb->mregs; struct device *dev = musb->controller; struct dsps_glue *glue = dev_get_drvdata(dev->parent); const struct dsps_musb_wrapper *wrp = glue->wrp; u8 devctl; int skip_session = 0; if (glue->vbus_irq) del_timer(&musb->dev_timer); /* * We poll because DSPS IP'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->otg->state)); switch (musb->xceiv->otg->state) { case OTG_STATE_A_WAIT_VRISE: dsps_mod_timer_optional(glue); break; case OTG_STATE_A_WAIT_BCON: /* keep VBUS on for host-only mode */ if (musb->port_mode == MUSB_PORT_MODE_HOST) { dsps_mod_timer_optional(glue); break; } musb_writeb(musb->mregs, MUSB_DEVCTL, 0); skip_session = 1; /* fall */ case OTG_STATE_A_IDLE: case OTG_STATE_B_IDLE: if (!glue->vbus_irq) { if (devctl & MUSB_DEVCTL_BDEVICE) { musb->xceiv->otg->state = OTG_STATE_B_IDLE; MUSB_DEV_MODE(musb); } else { musb->xceiv->otg->state = OTG_STATE_A_IDLE; MUSB_HST_MODE(musb); } if (!(devctl & MUSB_DEVCTL_SESSION) && !skip_session) musb_writeb(mregs, MUSB_DEVCTL, MUSB_DEVCTL_SESSION); } dsps_mod_timer_optional(glue); break; case OTG_STATE_A_WAIT_VFALL: musb->xceiv->otg->state = OTG_STATE_A_WAIT_VRISE; musb_writel(musb->ctrl_base, wrp->coreintr_set, MUSB_INTR_VBUSERROR << wrp->usb_shift); break; default: break; } return 0; }
static irqreturn_t dma_controller_irq(int irq, void *private_data) { struct musb_dma_controller *controller = private_data; struct musb *musb = controller->private_data; struct musb_dma_channel *musb_channel; struct dma_channel *channel; void __iomem *mbase = controller->base; irqreturn_t retval = IRQ_NONE; unsigned long flags; u8 bchannel; u8 int_hsdma; u32 addr; u16 csr, count; spin_lock_irqsave(&musb->lock, flags); int_hsdma = musb_readb(mbase, MUSB_HSDMA_INTR); if (!int_hsdma) { DBG(2, "spurious DMA irq\n"); for (bchannel = 0; bchannel < MUSB_HSDMA_CHANNELS; bchannel++) { musb_channel = (struct musb_dma_channel *) &(controller->channel[bchannel]); channel = &musb_channel->channel; if (channel->status == MUSB_DMA_STATUS_BUSY) { count = musb_readw(mbase, MUSB_HSDMA_CHANNEL_OFFSET(bchannel, MUSB_HSDMA_COUNT)); if (count == 0) int_hsdma |= (1 << bchannel); } } DBG(2, "int_hsdma = 0x%x\n", int_hsdma); if (!int_hsdma) goto done; } for (bchannel = 0; bchannel < MUSB_HSDMA_CHANNELS; bchannel++) { if (int_hsdma & (1 << bchannel)) { musb_channel = (struct musb_dma_channel *) &(controller->channel[bchannel]); channel = &musb_channel->channel; csr = musb_readw(mbase, MUSB_HSDMA_CHANNEL_OFFSET(bchannel, MUSB_HSDMA_CONTROL)); if (csr & (1 << MUSB_HSDMA_BUSERROR_SHIFT)) { musb_channel->channel.status = MUSB_DMA_STATUS_BUS_ABORT; } else { u8 devctl; addr = musb_read_hsdma_addr(mbase, bchannel); channel->actual_len = addr - musb_channel->start_addr; DBG(2, "ch %p, 0x%x -> 0x%x (%d / %d) %s\n", channel, musb_channel->start_addr, addr, channel->actual_len, musb_channel->len, (channel->actual_len < musb_channel->len) ? "=> reconfig 0" : "=> complete"); devctl = musb_readb(mbase, MUSB_DEVCTL); channel->status = MUSB_DMA_STATUS_FREE; if (musb_channel->transmit) controller->tx_active &= ~(1 << bchannel); else controller->rx_active &= ~(1 << bchannel); /* completed */ if ((devctl & MUSB_DEVCTL_HM) && (musb_channel->transmit) && ((channel->desired_mode == 0) || (channel->actual_len & (musb_channel->max_packet_sz - 1))) ) { u8 epnum = musb_channel->epnum; int offset = MUSB_EP_OFFSET(epnum, MUSB_TXCSR); u16 txcsr; /* * The programming guide says that we * must clear DMAENAB before DMAMODE. */ musb_ep_select(mbase, epnum); txcsr = musb_readw(mbase, offset); txcsr &= ~(MUSB_TXCSR_DMAENAB | MUSB_TXCSR_AUTOSET); musb_writew(mbase, offset, txcsr); /* Send out the packet */ txcsr &= ~MUSB_TXCSR_DMAMODE; txcsr |= MUSB_TXCSR_TXPKTRDY; musb_writew(mbase, offset, txcsr); } musb_dma_completion(musb, musb_channel->epnum, musb_channel->transmit); } } } #ifdef CONFIG_BLACKFIN /* Clear DMA interrup flags */ musb_writeb(mbase, MUSB_HSDMA_INTR, int_hsdma); #endif retval = IRQ_HANDLED; done: spin_unlock_irqrestore(&musb->lock, flags); return retval; }
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; u8 devctl; /* 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); if (!phymux_base) { dev_err(dev, "ioremap failed\n"); wake_lock_destroy(&plat->musb_lock); return -ENOMEM; } ctrl_base = ioremap(0x4A002000, SZ_1K); if (!ctrl_base) { dev_err(dev, "ioremap failed\n"); wake_lock_destroy(&plat->musb_lock); return -ENOMEM; } } /* 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); } /* Keep the old initalization code for revisions < 1.2 * since the new code seem to crash the older boards * when coming out of power off mode */ if (omap_rev() < OMAP3630_REV_ES1_2) { /* 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); } else { devctl = musb_readb(musb->mregs, MUSB_DEVCTL); if ((devctl & MUSB_DEVCTL_VBUS) != (3 << MUSB_DEVCTL_VBUS_SHIFT)) { /* configure in force idle/ standby */ musb_writel(musb->mregs, OTG_FORCESTDBY, 1); val = FORCEIDLE | FORCESTDBY; musb_writel(musb->mregs, OTG_SYSCONFIG, val); } else { /* configure smart idle when usb cable inserted at * * startup*/ val = SMARTIDLE | SMARTSTDBY | ENABLEWAKEUP; 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; }
static void musb_port_suspend(struct musb *musb, bool do_suspend) { u8 power; void __iomem *mbase = musb->mregs; if (!is_host_active(musb)) return; /* NOTE: this doesn't necessarily put PHY into low power mode, * turning off its clock; that's a function of PHY integration and * MUSB_POWER_ENSUSPEND. PHY may need a clock (sigh) to detect * SE0 changing to connect (J) or wakeup (K) states. */ power = musb_readb(mbase, MUSB_POWER); if (do_suspend) { int retries = 10000; power &= ~MUSB_POWER_RESUME; power |= MUSB_POWER_SUSPENDM; musb_writeb(mbase, MUSB_POWER, power); /* Needed for OPT A tests */ power = musb_readb(mbase, MUSB_POWER); while (power & MUSB_POWER_SUSPENDM) { power = musb_readb(mbase, MUSB_POWER); if (retries-- < 1) break; } DBG(3, "Root port suspended, power %02x\n", power); musb->port1_status |= USB_PORT_STAT_SUSPEND; switch (musb->xceiv->state) { case OTG_STATE_A_HOST: musb->xceiv->state = OTG_STATE_A_SUSPEND; musb->is_active = is_otg_enabled(musb) && musb->xceiv->host->b_hnp_enable; if (musb->is_active) mod_timer(&musb->otg_timer, jiffies + msecs_to_jiffies(( OTG_TIME_A_AIDL_BDIS + USB_SUSP_DET_DURATION))); musb_platform_try_idle(musb, 0); break; #ifdef CONFIG_USB_MUSB_OTG case OTG_STATE_B_HOST: musb->xceiv->state = OTG_STATE_B_WAIT_ACON; musb->is_active = is_otg_enabled(musb) && musb->xceiv->host->b_hnp_enable; musb_platform_try_idle(musb, 0); break; #endif default: DBG(1, "bogus rh suspend? %s\n", otg_state_string(musb)); } } else if (power & MUSB_POWER_SUSPENDM) { power &= ~MUSB_POWER_SUSPENDM; power |= MUSB_POWER_RESUME; musb_writeb(mbase, MUSB_POWER, power); DBG(3, "Root port resuming, power %02x\n", power); /* later, GetPortStatus will stop RESUME signaling */ musb->port1_status |= MUSB_PORT_STAT_RESUME; musb->rh_timer = jiffies + msecs_to_jiffies(20); } }
int musb_hub_control( struct usb_hcd *hcd, u16 typeReq, u16 wValue, u16 wIndex, char *buf, u16 wLength) { struct musb *musb = hcd_to_musb(hcd); u32 temp; int retval = 0; unsigned long flags; spin_lock_irqsave(&musb->lock, flags); if (unlikely(!HCD_HW_ACCESSIBLE(hcd))) { spin_unlock_irqrestore(&musb->lock, flags); return -ESHUTDOWN; } /* hub features: always zero, setting is a NOP * port features: reported, sometimes updated when host is active * no indicators */ switch (typeReq) { case ClearHubFeature: case SetHubFeature: switch (wValue) { case C_HUB_OVER_CURRENT: case C_HUB_LOCAL_POWER: break; default: goto error; } break; case ClearPortFeature: if ((wIndex & 0xff) != 1) goto error; switch (wValue) { case USB_PORT_FEAT_ENABLE: break; case USB_PORT_FEAT_SUSPEND: musb_port_suspend(musb, false); break; case USB_PORT_FEAT_POWER: if (!(is_otg_enabled(musb) && hcd->self.is_b_host)) musb_platform_set_vbus(musb, 0); break; case USB_PORT_FEAT_C_CONNECTION: case USB_PORT_FEAT_C_ENABLE: case USB_PORT_FEAT_C_OVER_CURRENT: case USB_PORT_FEAT_C_RESET: case USB_PORT_FEAT_C_SUSPEND: break; default: goto error; } dev_dbg(musb->controller, "clear feature %d\n", wValue); musb->port1_status &= ~(1 << wValue); break; case GetHubDescriptor: { struct usb_hub_descriptor *desc = (void *)buf; desc->bDescLength = 9; desc->bDescriptorType = 0x29; desc->bNbrPorts = 1; desc->wHubCharacteristics = cpu_to_le16( 0x0001 /* per-port power switching */ | 0x0010 /* no overcurrent reporting */ ); desc->bPwrOn2PwrGood = 5; /* msec/2 */ desc->bHubContrCurrent = 0; /* workaround bogus struct definition */ desc->u.hs.DeviceRemovable[0] = 0x02; /* port 1 */ desc->u.hs.DeviceRemovable[1] = 0xff; } break; case GetHubStatus: temp = 0; *(__le32 *) buf = cpu_to_le32(temp); break; case GetPortStatus: if (wIndex != 1) goto error; /* finish RESET signaling? */ if ((musb->port1_status & USB_PORT_STAT_RESET) && time_after_eq(jiffies, musb->rh_timer)) musb_port_reset(musb, false); /* finish RESUME signaling? */ if ((musb->port1_status & MUSB_PORT_STAT_RESUME) && time_after_eq(jiffies, musb->rh_timer)) { u8 power; power = musb_readb(musb->mregs, MUSB_POWER); power &= ~MUSB_POWER_RESUME; dev_dbg(musb->controller, "root port resume stopped, power %02x\n", power); musb_writeb(musb->mregs, MUSB_POWER, power); /* ISSUE: DaVinci (RTL 1.300) disconnects after * resume of high speed peripherals (but not full * speed ones). */ musb->is_active = 1; musb->port1_status &= ~(USB_PORT_STAT_SUSPEND | MUSB_PORT_STAT_RESUME); musb->port1_status |= USB_PORT_STAT_C_SUSPEND << 16; usb_hcd_poll_rh_status(musb_to_hcd(musb)); /* NOTE: it might really be A_WAIT_BCON ... */ musb->xceiv->state = OTG_STATE_A_HOST; } put_unaligned(cpu_to_le32(musb->port1_status & ~MUSB_PORT_STAT_RESUME), (__le32 *) buf); /* port change status is more interesting */ dev_dbg(musb->controller, "port status %08x\n", musb->port1_status); break; case SetPortFeature: if ((wIndex & 0xff) != 1) goto error; switch (wValue) { case USB_PORT_FEAT_POWER: /* NOTE: this controller has a strange state machine * that involves "requesting sessions" according to * magic side effects from incompletely-described * rules about startup... * * This call is what really starts the host mode; be * very careful about side effects if you reorder any * initialization logic, e.g. for OTG, or change any * logic relating to VBUS power-up. */ if (!(is_otg_enabled(musb) && hcd->self.is_b_host)) musb_start(musb); break; case USB_PORT_FEAT_RESET: musb_port_reset(musb, true); break; case USB_PORT_FEAT_SUSPEND: musb_port_suspend(musb, true); break; case USB_PORT_FEAT_TEST: if (unlikely(is_host_enabled(musb))) goto error; wIndex >>= 8; switch (wIndex) { case 1: pr_debug("TEST_J\n"); temp = MUSB_TEST_J; break; case 2: pr_debug("TEST_K\n"); temp = MUSB_TEST_K; break; case 3: pr_debug("TEST_SE0_NAK\n"); temp = MUSB_TEST_SE0_NAK; break; case 4: pr_debug("TEST_PACKET\n"); temp = MUSB_TEST_PACKET; musb_load_testpacket(musb); break; case 5: pr_debug("TEST_FORCE_ENABLE\n"); temp = MUSB_TEST_FORCE_HOST | MUSB_TEST_FORCE_HS; musb_writeb(musb->mregs, MUSB_DEVCTL, MUSB_DEVCTL_SESSION); break; case 6: pr_debug("TEST_FIFO_ACCESS\n"); temp = MUSB_TEST_FIFO_ACCESS; break; default: goto error; } musb_writeb(musb->mregs, MUSB_TESTMODE, temp); if (wIndex == 4) { musb_writew(musb->endpoints[0].regs, MUSB_CSR0, MUSB_CSR0_TXPKTRDY); } break; default: goto error; } dev_dbg(musb->controller, "set feature %d\n", wValue); musb->port1_status |= 1 << wValue; break; default: error: /* "protocol stall" on error */ retval = -EPIPE; } spin_unlock_irqrestore(&musb->lock, flags); return retval; }
void host_test_mode(struct musb *musb, unsigned int wIndex){ unsigned char temp; unsigned char power; struct usb_ctrlrequest setup_packet; struct usb_device_descriptor device_descriptor; setup_packet.bRequestType = USB_DIR_IN|USB_TYPE_STANDARD|USB_RECIP_DEVICE; setup_packet.bRequest = USB_REQ_GET_DESCRIPTOR; setup_packet.wIndex = 0; setup_packet.wValue = 0x0100; setup_packet.wLength = 0x40; musb_otg_set_session (true); msleep(200); DBG(0,"devctl = 0x%x\n",musb_readb(musb->mregs,MUSB_DEVCTL)); switch (wIndex) { case HOST_CMD_TEST_SE0_NAK: DBG(0,"TEST_SE0_NAK\n"); temp = MUSB_TEST_SE0_NAK; musb_writeb(musb->mregs, MUSB_TESTMODE, temp); break; case HOST_CMD_TEST_J: DBG(0,"TEST_J\n"); temp = MUSB_TEST_J; musb_writeb(musb->mregs, MUSB_TESTMODE, temp); break; case HOST_CMD_TEST_K: DBG(0,"TEST_K\n"); temp = MUSB_TEST_K; musb_writeb(musb->mregs, MUSB_TESTMODE, temp); break; case HOST_CMD_TEST_PACKET: DBG(0,"TEST_PACKET\n"); temp = MUSB_TEST_PACKET; musb_host_load_testpacket(musb); musb_writeb(musb->mregs, MUSB_TESTMODE, temp); musb_writew(musb->mregs, 0x102, MUSB_CSR0_TXPKTRDY); break; case HOST_CMD_SUSPEND_RESUME://HS_HOST_PORT_SUSPEND_RESUME DBG(0,"HS_HOST_PORT_SUSPEND_RESUME\n"); msleep(5000);//the host must continue sending SOFs for 15s DBG(0,"please begin to trigger suspend!\n"); msleep(10000); power = musb_readb(musb->mregs,MUSB_POWER); power |= MUSB_POWER_SUSPENDM | MUSB_POWER_ENSUSPEND; musb_writeb(musb->mregs,MUSB_POWER,power); msleep(5000); DBG(0,"please begin to trigger resume!\n"); msleep(10000); power &= ~MUSB_POWER_SUSPENDM; power |= MUSB_POWER_RESUME; musb_writeb(musb->mregs,MUSB_POWER,power); mdelay(25); power &= ~MUSB_POWER_RESUME; musb_writeb(musb->mregs,MUSB_POWER,power); //SOF continue musb_h_setup(&setup_packet); break; case HOST_CMD_GET_DESCRIPTOR://SINGLE_STEP_GET_DEVICE_DESCRIPTOR setup DBG(0,"SINGLE_STEP_GET_DEVICE_DESCRIPTOR\n"); msleep(15000);//the host issues SOFs for 15s allowing the test engineer to raise the scope trigger just above the SOF voltage level. musb_h_setup(&setup_packet); break; case HOST_CMD_SET_FEATURE://SINGLE_STEP_GET_DEVICE_DESCRIPTOR execute DBG(0,"SINGLE_STEP_GET_DEVICE_DESCRIPTOR\n"); //get device descriptor musb_h_setup(&setup_packet); msleep(15000); musb_h_in_data((char*)&device_descriptor,sizeof(struct usb_device_descriptor)); musb_h_out_status(); break; default: break; } //while(1); }
static void omap2430_musb_set_vbus(struct musb *musb, int is_on) { struct usb_otg *otg = musb->xceiv->otg; u8 devctl; unsigned long timeout = jiffies + msecs_to_jiffies(1000); /* HDRC controls CPEN, but beware current surges during device * connect. They can trigger transient overcurrent conditions * that must be ignored. */ devctl = musb_readb(musb->mregs, MUSB_DEVCTL); if (is_on) { if (musb->xceiv->state == OTG_STATE_A_IDLE) { int loops = 100; /* start the session */ devctl |= MUSB_DEVCTL_SESSION; musb_writeb(musb->mregs, MUSB_DEVCTL, devctl); /* * Wait for the musb to set as A device to enable the * VBUS */ while (musb_readb(musb->mregs, MUSB_DEVCTL) & 0x80) { mdelay(5); cpu_relax(); if (time_after(jiffies, timeout) || loops-- <= 0) { dev_err(musb->controller, "configured as A device timeout"); break; } } otg_set_vbus(otg, 1); } else { musb->is_active = 1; otg->default_a = 1; musb->xceiv->state = OTG_STATE_A_WAIT_VRISE; devctl |= MUSB_DEVCTL_SESSION; MUSB_HST_MODE(musb); } } else { musb->is_active = 0; /* NOTE: we're skipping A_WAIT_VFALL -> A_IDLE and * jumping right to B_IDLE... */ otg->default_a = 0; musb->xceiv->state = OTG_STATE_B_IDLE; devctl &= ~MUSB_DEVCTL_SESSION; MUSB_DEV_MODE(musb); } musb_writeb(musb->mregs, MUSB_DEVCTL, devctl); dev_dbg(musb->controller, "VBUS %s, devctl %02x " /* otg %3x conf %08x prcm %08x */ "\n", usb_otg_state_string(musb->xceiv->state), musb_readb(musb->mregs, MUSB_DEVCTL)); }
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; }
void musb_port_suspend(struct musb *musb, bool do_suspend) { struct usb_otg *otg = musb->xceiv->otg; u8 power; void __iomem *mbase = musb->mregs; if (!is_host_active(musb)) return; /* NOTE: this doesn't necessarily put PHY into low power mode, * turning off its clock; that's a function of PHY integration and * MUSB_POWER_ENSUSPEND. PHY may need a clock (sigh) to detect * SE0 changing to connect (J) or wakeup (K) states. */ power = musb_readb(mbase, MUSB_POWER); if (do_suspend) { int retries = 10000; power &= ~MUSB_POWER_RESUME; power |= MUSB_POWER_SUSPENDM; musb_writeb(mbase, MUSB_POWER, power); /* Needed for OPT A tests */ power = musb_readb(mbase, MUSB_POWER); while (power & MUSB_POWER_SUSPENDM) { power = musb_readb(mbase, MUSB_POWER); if (retries-- < 1) break; } dev_dbg(musb->controller, "Root port suspended, power %02x\n", power); musb->port1_status |= USB_PORT_STAT_SUSPEND; switch (musb->xceiv->state) { case OTG_STATE_A_HOST: musb->xceiv->state = OTG_STATE_A_SUSPEND; musb->is_active = otg->host->b_hnp_enable; if (musb->is_active) mod_timer(&musb->otg_timer, jiffies + msecs_to_jiffies( OTG_TIME_A_AIDL_BDIS)); musb_platform_try_idle(musb, 0); break; case OTG_STATE_B_HOST: musb->xceiv->state = OTG_STATE_B_WAIT_ACON; musb->is_active = otg->host->b_hnp_enable; musb_platform_try_idle(musb, 0); break; default: dev_dbg(musb->controller, "bogus rh suspend? %s\n", usb_otg_state_string(musb->xceiv->state)); } } else if (power & MUSB_POWER_SUSPENDM) { power &= ~MUSB_POWER_SUSPENDM; power |= MUSB_POWER_RESUME; musb_writeb(mbase, MUSB_POWER, power); dev_dbg(musb->controller, "Root port resuming, power %02x\n", power); /* later, GetPortStatus will stop RESUME signaling */ musb->port1_status |= MUSB_PORT_STAT_RESUME; schedule_delayed_work(&musb->finish_resume_work, msecs_to_jiffies(USB_RESUME_TIMEOUT)); } }
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); dev_dbg(musb->controller, "Poll devctl %02x (%s)\n", devctl, usb_otg_state_string(musb->xceiv->otg->state)); spin_lock_irqsave(&musb->lock, flags); switch (musb->xceiv->otg->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->otg->state = OTG_STATE_B_IDLE; MUSB_DEV_MODE(musb); } else { musb->xceiv->otg->state = OTG_STATE_A_IDLE; MUSB_HST_MODE(musb); } break; case OTG_STATE_A_WAIT_VFALL: /* * Wait till VBUS falls below SessionEnd (~0.2 V); 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->otg->state = OTG_STATE_A_WAIT_VRISE; musb_writel(musb->ctrl_base, DA8XX_USB_INTR_SRC_SET_REG, MUSB_INTR_VBUSERROR << DA8XX_INTR_USB_SHIFT); break; case OTG_STATE_B_IDLE: /* * 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 bit). * * 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->otg->state = OTG_STATE_A_IDLE; break; default: break; } spin_unlock_irqrestore(&musb->lock, flags); }