void musb_otg_set_session(bool set){ unsigned char devctl = musb_readb (mtk_musb->mregs, MUSB_DEVCTL); if(set) devctl |= MUSB_DEVCTL_SESSION; else devctl &= ~MUSB_DEVCTL_SESSION; musb_writeb(mtk_musb->mregs, MUSB_DEVCTL, devctl); return; }
void usb_reset_root_port(void) { void *mbase = host->mregs; u8 power; power = musb_readb(mbase, MUSB_POWER); power &= 0xf0; musb_writeb(mbase, MUSB_POWER, MUSB_POWER_RESET | power); mdelay(50); power = musb_readb(mbase, MUSB_POWER); musb_writeb(mbase, MUSB_POWER, ~MUSB_POWER_RESET & power); host->isr(0, host); host_speed = (musb_readb(mbase, MUSB_POWER) & MUSB_POWER_HSMODE) ? USB_SPEED_HIGH : (musb_readb(mbase, MUSB_DEVCTL) & MUSB_DEVCTL_FSDEV) ? USB_SPEED_FULL : USB_SPEED_LOW; mdelay((host_speed == USB_SPEED_LOW) ? 200 : 50); }
static int omap2430_musb_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); return 0; }
static void otg_timer(unsigned long _musb) { struct musb *musb = (void *)_musb; void __iomem *mregs = musb->mregs; u8 devctl; unsigned long flags; /* We poll because DaVinci's won't expose several OTG-critical * status change events (from the transceiver) otherwise. */ devctl = musb_readb(mregs, MUSB_DEVCTL); DBG(7, "poll devctl %02x (%s)\n", devctl, otg_state_string(musb)); spin_lock_irqsave(&musb->lock, flags); switch (musb->xceiv.state) { case OTG_STATE_A_WAIT_VFALL: /* Wait till VBUS falls below SessionEnd (~0.2V); the 1.3 RTL * seems to mis-handle session "start" otherwise (or in our * case "recover"), in routine "VBUS was valid by the time * VBUSERR got reported during enumeration" cases. */ if (devctl & MUSB_DEVCTL_VBUS) { mod_timer(&otg_workaround, jiffies + POLL_SECONDS * HZ); break; } musb->xceiv.state = OTG_STATE_A_WAIT_VRISE; musb_writel(musb->ctrl_base, DAVINCI_USB_INT_SET_REG, MUSB_INTR_VBUSERROR << DAVINCI_USB_USBINT_SHIFT); break; case OTG_STATE_B_IDLE: if (!is_peripheral_enabled(musb)) break; /* There's no ID-changed IRQ, so we have no good way to tell * when to switch to the A-Default state machine (by setting * the DEVCTL.SESSION flag). * * Workaround: whenever we're in B_IDLE, try setting the * session flag every few seconds. If it works, ID was * grounded and we're now in the A-Default state machine. * * NOTE setting the session flag is _supposed_ to trigger * SRP, but clearly it doesn't. */ musb_writeb(mregs, MUSB_DEVCTL, devctl | MUSB_DEVCTL_SESSION); devctl = musb_readb(mregs, MUSB_DEVCTL); if (devctl & MUSB_DEVCTL_BDEVICE) mod_timer(&otg_workaround, jiffies + POLL_SECONDS * HZ); else musb->xceiv.state = OTG_STATE_A_IDLE; break; default: break; } spin_unlock_irqrestore(&musb->lock, flags); }
/* * Tries to start B-device HNP negotiation if enabled via sysfs */ static inline void musb_try_b_hnp_enable(struct musb *musb) { void __iomem *mbase = musb->mregs; u8 devctl; DBG(1, "HNP: Setting HR\n"); devctl = musb_readb(mbase, MUSB_DEVCTL); musb_writeb(mbase, MUSB_DEVCTL, devctl | MUSB_DEVCTL_HR); }
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); return 0; }
int musb_otg_env_exit(void){ DBG(0,"stop the USB-IF test in EM!\n"); 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); musb_writel(mtk_musb->mregs,USB_L1INTM,usb_l1intm_store); musb_writew(mtk_musb->mregs,MUSB_INTRRXE,usb_intrrxe_store); musb_writew(mtk_musb->mregs,MUSB_INTRTXE,usb_intrtxe_store); musb_writeb(mtk_musb->mregs,MUSB_INTRUSBE,usb_intrusbe_store); mtk_musb->usb_if = false; mtk_musb->is_host = false; upmu_interrupt_chrdet_int_en(1); 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; } 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); } }
void musb_read_clear_generic_interrupt(struct musb *musb) { 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); mb(); musb_writew(musb->mregs,MUSB_INTRRX,musb->int_rx); musb_writew(musb->mregs,MUSB_INTRTX,musb->int_tx); musb_writeb(musb->mregs,MUSB_INTRUSB,musb->int_usb); }
void musb_d_soft_connect(bool connect){ unsigned char power; power = musb_readb(mtk_musb->mregs, MUSB_POWER); if(connect) power |= MUSB_POWER_SOFTCONN; else power &= ~MUSB_POWER_SOFTCONN; musb_writeb(mtk_musb->mregs, MUSB_POWER, power); return; }
/* * am35x_musb_disable - disable HDRC and flush interrupts */ static void am35x_musb_disable(struct musb *musb) { void __iomem *reg_base = musb->ctrl_base; musb_writel(reg_base, CORE_INTR_MASK_CLEAR_REG, AM35X_INTR_USB_MASK); musb_writel(reg_base, EP_INTR_MASK_CLEAR_REG, AM35X_TX_INTR_MASK | AM35X_RX_INTR_MASK); musb_writeb(musb->mregs, MUSB_DEVCTL, 0); musb_writel(reg_base, USB_END_OF_INTR_REG, 0); }
/** * da8xx_musb_disable - disable HDRC and flush interrupts */ static void da8xx_musb_disable(struct musb *musb) { void __iomem *reg_base = musb->ctrl_base; musb_writel(reg_base, DA8XX_USB_INTR_MASK_CLEAR_REG, DA8XX_INTR_USB_MASK | DA8XX_INTR_TX_MASK | DA8XX_INTR_RX_MASK); musb_writeb(musb->mregs, MUSB_DEVCTL, 0); musb_writel(reg_base, DA8XX_USB_END_OF_INTR_REG, 0); }
u8 musb_read_clear_dma_interrupt(struct musb *musb) { u8 int_hsdma = 0; int_hsdma = musb_readb(musb->mregs, MUSB_HSDMA_INTR); mb(); musb_writeb(musb->mregs,MUSB_HSDMA_INTR,int_hsdma); return int_hsdma; }
static void musb_do_idle(unsigned long _musb) { struct musb *musb = (void *)_musb; unsigned long flags; #ifdef CONFIG_USB_MUSB_HDRC_HCD u8 power; #endif u8 devctl; spin_lock_irqsave(&musb->lock, flags); switch (musb->xceiv->state) { case OTG_STATE_A_WAIT_BCON: 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; #ifdef CONFIG_USB_MUSB_HDRC_HCD case OTG_STATE_A_SUSPEND: /* finish RESUME signaling? */ if (musb->port1_status & MUSB_PORT_STAT_RESUME) { power = musb_readb(musb->mregs, MUSB_POWER); power &= ~MUSB_POWER_RESUME; DBG(1, "root port resume stopped, power %02x\n", power); musb_writeb(musb->mregs, MUSB_POWER, power); 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; } break; #endif #ifdef CONFIG_USB_MUSB_HDRC_HCD case OTG_STATE_A_HOST: devctl = musb_readb(musb->mregs, MUSB_DEVCTL); if (devctl & MUSB_DEVCTL_BDEVICE) musb->xceiv->state = OTG_STATE_B_IDLE; else musb->xceiv->state = OTG_STATE_A_WAIT_BCON; #endif default: break; } spin_unlock_irqrestore(&musb->lock, flags); }
/* * Program the HDRC to start (enable interrupts, dma, etc.). */ static void musb_start(struct musb *musb) { void __iomem *regs = musb->mregs; u8 devctl = musb_readb(regs, MUSB_DEVCTL); dev_dbg(musb->controller, "<== devctl %02x\n", devctl); /* Set INT enable registers, enable interrupts */ musb->intrtxe = musb->epmask; musb_writew(regs, MUSB_INTRTXE, musb->intrtxe); musb->intrrxe = musb->epmask & 0xfffe; musb_writew(regs, MUSB_INTRRXE, musb->intrrxe); musb_writeb(regs, MUSB_INTRUSBE, 0xf7); musb_writeb(regs, MUSB_TESTMODE, 0); /* put into basic highspeed mode and start session */ musb_writeb(regs, MUSB_POWER, MUSB_POWER_ISOUPDATE | MUSB_POWER_HSENAB /* ENSUSPEND wedges tusb */ /* | MUSB_POWER_ENSUSPEND */ ); musb->is_active = 0; devctl = musb_readb(regs, MUSB_DEVCTL); devctl &= ~MUSB_DEVCTL_SESSION; /* session started after: * (a) ID-grounded irq, host mode; * (b) vbus present/connect IRQ, peripheral mode; * (c) peripheral initiates, using SRP */ if (musb->port_mode != MUSB_PORT_MODE_HOST && (devctl & MUSB_DEVCTL_VBUS) == MUSB_DEVCTL_VBUS) { musb->is_active = 1; } else { devctl |= MUSB_DEVCTL_SESSION; } musb_platform_enable(musb); musb_writeb(regs, MUSB_DEVCTL, devctl); }
bool musb_h_reset(void){ unsigned char power; power = musb_readb (mtk_musb->mregs,MUSB_POWER); power |= MUSB_POWER_RESET|MUSB_POWER_HSENAB; musb_writeb(mtk_musb->mregs, MUSB_POWER, power); msleep(60); power &= ~MUSB_POWER_RESET; musb_writeb(mtk_musb->mregs, MUSB_POWER, power); power = musb_readb (mtk_musb->mregs,MUSB_POWER); if(power & MUSB_POWER_HSMODE){ DBG(0,"the device is a hs device!\n"); high_speed = true; return true; } else{ DBG(0,"the device is a fs device!\n"); high_speed = false; return false; } }
static int sunxi_musb_enable(struct musb *musb) { pr_debug("%s():\n", __func__); musb_ep_select(musb->mregs, 0); musb_writeb(musb->mregs, MUSB_FADDR, 0); if (enabled) return 0; /* select PIO mode */ musb_writeb(musb->mregs, USBC_REG_o_VEND0, 0); if (is_host_enabled(musb)) { int id = sunxi_usb_phy_id_detect(0); if (id == 1 && sunxi_usb_phy_power_is_on(0)) sunxi_usb_phy_power_off(0); if (!sunxi_usb_phy_power_is_on(0)) { int vbus = sunxi_usb_phy_vbus_detect(0); if (vbus == 1) { printf("A charger is plugged into the OTG: "); return -ENODEV; } } if (id == 1) { printf("No host cable detected: "); return -ENODEV; } if (!sunxi_usb_phy_power_is_on(0)) sunxi_usb_phy_power_on(0); } USBC_ForceVbusValidToHigh(musb->mregs); enabled = true; return 0; }
static void davinci_musb_disable(struct musb *musb) { musb_writel(musb->ctrl_base, DAVINCI_USB_INT_MASK_CLR_REG, DAVINCI_USB_USBINT_MASK | DAVINCI_USB_TXINT_MASK | DAVINCI_USB_RXINT_MASK); musb_writeb(musb->mregs, MUSB_DEVCTL, 0); musb_writel(musb->ctrl_base, DAVINCI_USB_EOI_REG, 0); if (is_dma_capable() && !dma_off) WARNING("dma still active\n"); }
unsigned int musb_polling_bus_interrupt(unsigned int intr){ unsigned char intrusb; unsigned long timeout; if(MUSB_INTR_CONNECT == intr) timeout = jiffies + 15 * HZ; if((MUSB_INTR_CONNECT|MUSB_INTR_RESUME) == intr) timeout = jiffies + 1; if(MUSB_INTR_RESET == intr) timeout = jiffies + 2*HZ; do{ intrusb = musb_readb(mtk_musb->mregs,MUSB_INTRUSB); mb(); musb_writeb(mtk_musb->mregs,MUSB_INTRUSB, intrusb);//clear the interrupt if(intrusb & intr){ DBG(0,"interrupt happen, intrusb=0x%x, intr=0x%x\n",intrusb,intr); break; } else{ //DBG(0,"still polling,intrusb=0x%x,power=0x%x,devctl=0x%x\n",intrusb,musb_readb(mtk_musb->mregs,MUSB_POWER),musb_readb(mtk_musb->mregs,MUSB_DEVCTL)); //check the timeout if((MUSB_INTR_CONNECT == intr) && time_after(jiffies, timeout)){ DBG(0,"time out for MUSB_INTR_CONNECT\n"); return DEV_NOT_CONNECT; } if(((MUSB_INTR_CONNECT|MUSB_INTR_RESUME) == intr) && time_after(jiffies, timeout)){ DBG(0,"time out for MUSB_INTR_CONNECT|MUSB_INTR_RESUME\n"); return DEV_HNP_TIMEOUT; } if((MUSB_INTR_RESET == intr) && time_after(jiffies, timeout)){ DBG(0,"time out for MUSB_INTR_RESET\n"); return DEV_NOT_RESET; } //delay for the interrupt if(intr != MUSB_INTR_RESET){ wait_for_completion_timeout (&stop_event,1); if(!g_exec) break; } } } while(g_exec); if(!g_exec){ DBG(0,"TEST_IS_STOP\n"); return TEST_IS_STOP; } if(intrusb&MUSB_INTR_RESUME){//for TD.4.8, remote wakeup DBG(0,"MUSB_INTR_RESUME\n"); return MUSB_INTR_RESUME; } else{ return intrusb; } }
static void sunxi_musb_enable(struct musb *musb) { pr_debug("%s():\n", __func__); /* select PIO mode */ musb_writeb(musb->mregs, USBC_REG_o_VEND0, 0); if (is_host_enabled(musb)) { /* port power on */ sunxi_usbc_vbus_enable(0); } }
static ssize_t mt_usb_store_cmode(struct device* dev, struct device_attribute *attr, const char *buf, size_t count) { unsigned int cmode; if (!dev) { DBG(0,"dev is null!!\n"); return count; } else if (1 == sscanf(buf, "%d", &cmode)) { DBG(0, "cmode=%d, cable_mode=%d\n", cmode, cable_mode); if (cmode >= CABLE_MODE_MAX) cmode = CABLE_MODE_NORMAL; if (cable_mode != cmode) { if(cmode == CABLE_MODE_CHRG_ONLY) { // IPO shutdown, disable USB if(mtk_musb) { mtk_musb->in_ipo_off = true; } } else if(cmode == CABLE_MODE_NORMAL) { // IPO bootup, enable USB if(mtk_musb) { mtk_musb->in_ipo_off = false; } } mt_usb_disconnect(); cable_mode = cmode; msleep(10); //ALPS00114502 //check that "if USB cable connected and than call mt_usb_connect" //Then, the Bat_Thread won't be always wakeup while no USB/chatger cable and IPO mode //mt_usb_connect(); usb_check_connect(); //ALPS00114502 #ifdef CONFIG_USB_MTK_OTG if(cmode == CABLE_MODE_CHRG_ONLY) { if(mtk_musb && mtk_musb->is_host) { // shut down USB host for IPO musb_stop(mtk_musb); /* Think about IPO shutdown with A-cable, then switch to B-cable and IPO bootup. We need a point to clear session bit */ musb_writeb(mtk_musb->mregs, MUSB_DEVCTL, (~MUSB_DEVCTL_SESSION) & musb_readb(mtk_musb->mregs,MUSB_DEVCTL)); } else { switch_int_to_host_and_mask(); // mask ID pin interrupt even if A-cable is not plugged in } } else if(cmode == CABLE_MODE_NORMAL) { switch_int_to_host(); // resotre ID pin interrupt } #endif } } return count; }
/* * Disable the HDRC and flush interrupts */ void musb_platform_disable(struct musb *musb) { /* because we don't set CTRLR.UINT, "important" to: * - not read/write INTRUSB/INTRUSBE * - (except during initial setup, as workaround) * - use INTSETR/INTCLRR instead */ musb_writel(musb->ctrl_base, DAVINCI_USB_INT_MASK_CLR_REG, DAVINCI_USB_USBINT_MASK | DAVINCI_USB_TXINT_MASK | DAVINCI_USB_RXINT_MASK); musb_writeb(musb->pRegs, MGC_O_HDRC_DEVCTL, 0); musb_writel(musb->ctrl_base, DAVINCI_USB_EOI_REG, 0); }
static int musb_ulpi_read(struct usb_phy *phy, u32 offset) { void __iomem *addr = phy->io_priv; int i = 0; u8 r; u8 power; int ret; /* Make sure the transceiver is not in low power mode */ power = musb_readb(addr, MUSB_POWER); power &= ~MUSB_POWER_SUSPENDM; musb_writeb(addr, MUSB_POWER, power); /* REVISIT: musbhdrc_ulpi_an.pdf recommends setting the * ULPICarKitControlDisableUTMI after clearing POWER_SUSPENDM. */ musb_writeb(addr, MUSB_ULPI_REG_ADDR, (u8)offset); musb_writeb(addr, MUSB_ULPI_REG_CONTROL, MUSB_ULPI_REG_REQ | MUSB_ULPI_RDN_WR); while (!(musb_readb(addr, MUSB_ULPI_REG_CONTROL) & MUSB_ULPI_REG_CMPLT)) { i++; if (i == 10000) { ret = -ETIMEDOUT; goto out; } } r = musb_readb(addr, MUSB_ULPI_REG_CONTROL); r &= ~MUSB_ULPI_REG_CMPLT; musb_writeb(addr, MUSB_ULPI_REG_CONTROL, r); ret = musb_readb(addr, MUSB_ULPI_REG_DATA); out: return ret; }
void musb_h_suspend(void){ unsigned char power; //before suspend, should to send SOF for a while (USB-IF plan need) //mdelay(100); power = musb_readb(mtk_musb->mregs,MUSB_POWER); DBG(0,"before suspend,power=0x%x\n",power); if(high_speed) power = 0x63; else power = 0x43; musb_writeb(mtk_musb->mregs, MUSB_POWER, power); return; }
bool musb_is_host(void) { u8 devctl = 0; DBG(0,"will mask PMIC charger detection\n"); #ifndef CONFIG_MT6589_FPGA upmu_interrupt_chrdet_int_en(0); #endif musb_platform_enable(mtk_musb); //musb_set_vbus(mtk_musb,FALSE); //mt65xx_eint_mask(EINT_CHR_DET_NUM); devctl = musb_readb(mtk_musb->mregs,MUSB_DEVCTL); DBG(0, "devctl = %x before end session\n", devctl); devctl &= ~MUSB_DEVCTL_SESSION; // this will cause A-device change back to B-device after A-cable plug out musb_writeb(mtk_musb->mregs, MUSB_DEVCTL, devctl); msleep(delay_time); devctl = musb_readb(mtk_musb->mregs,MUSB_DEVCTL); DBG(0,"devctl = %x before set session\n",devctl); devctl |= MUSB_DEVCTL_SESSION; //musb_set_vbus(mtk_musb,TRUE); musb_writeb(mtk_musb->mregs,MUSB_DEVCTL,devctl); msleep(delay_time1); devctl = musb_readb(mtk_musb->mregs,MUSB_DEVCTL); DBG(0,"devclt = %x\n",devctl); if (devctl & MUSB_DEVCTL_BDEVICE) { usb_is_host = FALSE; DBG(0,"will unmask PMIC charger detection\n"); #ifndef CONFIG_MT6589_FPGA upmu_interrupt_chrdet_int_en(1); #endif return FALSE; } else { usb_is_host = TRUE; return TRUE; } }
static bool dsps_sw_babble_control(struct musb *musb) { u8 babble_ctl; bool session_restart = false; babble_ctl = musb_readb(musb->mregs, MUSB_BABBLE_CTL); dev_dbg(musb->controller, "babble: MUSB_BABBLE_CTL value %x\n", babble_ctl); /* * check line monitor flag to check whether babble is * due to noise */ dev_dbg(musb->controller, "STUCK_J is %s\n", babble_ctl & MUSB_BABBLE_STUCK_J ? "set" : "reset"); if (babble_ctl & MUSB_BABBLE_STUCK_J) { int timeout = 10; /* * babble is due to noise, then set transmit idle (d7 bit) * to resume normal operation */ babble_ctl = musb_readb(musb->mregs, MUSB_BABBLE_CTL); babble_ctl |= MUSB_BABBLE_FORCE_TXIDLE; musb_writeb(musb->mregs, MUSB_BABBLE_CTL, babble_ctl); /* wait till line monitor flag cleared */ dev_dbg(musb->controller, "Set TXIDLE, wait J to clear\n"); do { babble_ctl = musb_readb(musb->mregs, MUSB_BABBLE_CTL); udelay(1); } while ((babble_ctl & MUSB_BABBLE_STUCK_J) && timeout--); /* check whether stuck_at_j bit cleared */ if (babble_ctl & MUSB_BABBLE_STUCK_J) { /* * real babble condition has occurred * restart the controller to start the * session again */ dev_dbg(musb->controller, "J not cleared, misc (%x)\n", babble_ctl); session_restart = true; } } else { session_restart = true; } return session_restart; }
static void otg_timer(unsigned long _musb) { struct musb *musb = (void *)_musb; void __iomem *mregs = musb->mregs; u8 devctl; unsigned long flags; /* * We poll because AM35x's won't expose several OTG-critical * status change events (from the transceiver) otherwise. */ devctl = musb_readb(mregs, MUSB_DEVCTL); dev_dbg(musb->controller, "Poll devctl %02x (%s)\n", devctl, otg_state_string(musb->xceiv->state)); spin_lock_irqsave(&musb->lock, flags); switch (musb->xceiv->state) { case OTG_STATE_A_WAIT_BCON: devctl &= ~MUSB_DEVCTL_SESSION; musb_writeb(musb->mregs, MUSB_DEVCTL, devctl); devctl = musb_readb(musb->mregs, MUSB_DEVCTL); if (devctl & MUSB_DEVCTL_BDEVICE) { musb->xceiv->state = OTG_STATE_B_IDLE; MUSB_DEV_MODE(musb); } else { musb->xceiv->state = OTG_STATE_A_IDLE; MUSB_HST_MODE(musb); } break; case OTG_STATE_A_WAIT_VFALL: musb->xceiv->state = OTG_STATE_A_WAIT_VRISE; musb_writel(musb->ctrl_base, CORE_INTR_SRC_SET_REG, MUSB_INTR_VBUSERROR << AM35X_INTR_USB_SHIFT); break; case OTG_STATE_B_IDLE: if (!is_peripheral_enabled(musb)) break; devctl = musb_readb(mregs, MUSB_DEVCTL); if (devctl & MUSB_DEVCTL_BDEVICE) mod_timer(&otg_workaround, jiffies + POLL_SECONDS * HZ); else musb->xceiv->state = OTG_STATE_A_IDLE; break; default: break; } spin_unlock_irqrestore(&musb->lock, flags); }
/** * musb_stm_hs_otg_init() - Initialize the USB for paltform specific. * @musb: struct musb pointer. * * This function initialize the USB with the given musb structure information. */ int __init musb_stm_hs_otg_init(struct musb *musb) { u8 val; if (musb->clock) clk_enable(musb->clock); /** * usb link status update is not coming properly, so usb controller is * enabled by default now as part of bring up.it will be modified later. */ #if defined(CONFIG_UX500_SOC_DB5500) musb_writeb(musb->mregs, MUSB_POWER, 0x50); #endif /* enable ULPI interface */ val = musb_readb(musb->mregs, OTG_TOPCTRL); val |= OTG_TOPCTRL_MODE_ULPI; musb_writeb(musb->mregs, OTG_TOPCTRL, val); /* do soft reset */ val = musb_readb(musb->mregs, 0x7F); val |= 0x2; musb_writeb(musb->mregs, 0x7F, val); 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 void musb_id_pin_work(struct work_struct *data) { //bool is_ready = mtk_musb->is_ready; //u8 opstate = 0; down(&mtk_musb->musb_lock); DBG(0, "work start, is_host=%d\n", mtk_musb->is_host); if(mtk_musb->in_ipo_off) { DBG(0, "do nothing due to in_ipo_off\n"); goto out; } //mtk_musb->is_ready = FALSE; mtk_musb ->is_host = musb_is_host(); DBG(0,"musb is as %s\n",mtk_musb->is_host?"host":"device"); switch_set_state((struct switch_dev *)&otg_state,mtk_musb->is_host); if(mtk_musb ->is_host) { //setup fifo for host mode ep_config_from_table_for_host(mtk_musb); wake_lock(&mtk_musb->usb_lock); ignore_vbuserr = false; musb_set_vbus(mtk_musb,true); musb_start(mtk_musb); switch_int_to_device(); } else { DBG(0,"devctl is %x\n",musb_readb(mtk_musb->mregs,MUSB_DEVCTL)); dumpTime(funcWriteb, 0); musb_writeb(mtk_musb->mregs,MUSB_DEVCTL,0); wake_unlock(&mtk_musb->usb_lock); musb_set_vbus(mtk_musb,FALSE); /* opstate = musb_readb(mtk_musb->mregs,MUSB_OPSTATE); while(opstate != OTG_IDLE) { msleep(10); DBG(1,"wait OTG enter IDLE,opstate is %d\n",opstate); opstate = musb_readb(mtk_musb->mregs,MUSB_OPSTATE); } */ DBG(0,"musb_stop is called\n"); //switch_int_to_host(); // move to musb_stop musb_stop(mtk_musb); } //mtk_musb->is_ready = is_ready; out: DBG(0, "work end, is_host=%d\n", mtk_musb->is_host); up(&mtk_musb->musb_lock); }