static int omap_ehci_bus_suspend(struct usb_hcd *hcd) { struct ehci_hcd_omap *omap; unsigned long flags; int ret = 0; u32 reg; omap = ((struct ehci_hcd *) ((char *)hcd_to_ehci(hcd)))->omap_p; spin_lock_irqsave(&sus_res_lock, flags); ret = ehci_bus_suspend(hcd); if(!omap->suspended){ omap_writel(OHCI_HC_CTRL_SUSPEND, OHCI_HC_CONTROL); mdelay(8); /* MSTANDBY assertion is delayed by ~8ms */ reg = ehci_omap_readl(omap->uhh_base, OMAP_UHH_SYSCONFIG); reg &= ~(3 << 12); reg &= ~(3 << 3); ehci_omap_writel(omap->uhh_base, OMAP_UHH_SYSCONFIG, reg); clk_disable(omap->usbhost_fck); clk_disable(omap->usbhost_fs_fck); reg = ehci_omap_readl(omap->tll_base, OMAP_TLL_SHARED_CONF); reg &=~(1); ehci_omap_writel(omap->tll_base, OMAP_TLL_SHARED_CONF, reg); omap->suspended = 1; clk_disable(omap->usbtll_fck); } spin_unlock_irqrestore(&sus_res_lock, flags); return 0; }
static void ehci_omap_enable(struct ehci_hcd_omap *omap, int enable) { u32 reg; if (enable) { printk(KERN_DEBUG "ehci_omap_enable\n"); ehci_omap_clock_power(omap, 1); /* Enable NoIdle/NoStandby mode */ reg = ehci_omap_readl(omap->uhh_base, OMAP_UHH_SYSCONFIG); reg &= ~(OMAP_UHH_SYSCONFIG_SIDLEMASK | OMAP_UHH_SYSCONFIG_MIDLEMASK); reg |= OMAP_UHH_SYSCONFIG_NOIDLE | OMAP_UHH_SYSCONFIG_NOSTDBY; ehci_omap_writel(omap->uhh_base, OMAP_UHH_SYSCONFIG, reg); omap->suspended = 0; printk("[ehci]OMAP_UHH_SYSCONFIG=0x%x\n",reg); } else { printk(KERN_DEBUG "ehci_omap_enable\n"); /* Enable ForceIdle/ForceStandby mode */ reg = ehci_omap_readl(omap->uhh_base, OMAP_UHH_SYSCONFIG); reg &= ~(OMAP_UHH_SYSCONFIG_SIDLEMASK | OMAP_UHH_SYSCONFIG_MIDLEMASK); reg |= OMAP_UHH_SYSCONFIG_FORCEIDLE | OMAP_UHH_SYSCONFIG_FORCESTDBY; ehci_omap_writel(omap->uhh_base, OMAP_UHH_SYSCONFIG, reg); ehci_omap_clock_power(omap, 0); omap->suspended = 1; } }
static void omap_ehci_soft_phy_reset(struct ehci_hcd_omap *omap, u8 port) { unsigned long timeout = jiffies + msecs_to_jiffies(1000); unsigned reg = 0; reg = ULPI_FUNC_CTRL_RESET /* FUNCTION_CTRL_SET register */ | (ULPI_SET(ULPI_FUNC_CTRL) << EHCI_INSNREG05_ULPI_REGADD_SHIFT) /* Write */ | (2 << EHCI_INSNREG05_ULPI_OPSEL_SHIFT) /* PORTn */ | ((port + 1) << EHCI_INSNREG05_ULPI_PORTSEL_SHIFT) /* start ULPI access*/ | (1 << EHCI_INSNREG05_ULPI_CONTROL_SHIFT); ehci_omap_writel(omap->ehci_base, EHCI_INSNREG05_ULPI, reg); /* Wait for ULPI access completion */ while ((ehci_omap_readl(omap->ehci_base, EHCI_INSNREG05_ULPI) & (1 << EHCI_INSNREG05_ULPI_CONTROL_SHIFT))) { cpu_relax(); if (time_after(jiffies, timeout)) { dev_dbg(omap->dev, "phy reset operation timed out\n"); break; } } }
static int ehci_omap_bus_resume(struct usb_hcd *hcd) { u32 sysconfig; unsigned long flags; struct ehci_hcd_omap *omap = dev_get_drvdata(hcd->self.controller); dev_dbg(hcd->self.controller, "%s %ld %lu\n", __func__, in_interrupt(), jiffies); #ifdef CONFIG_HAS_WAKELOCK wake_lock(&omap->ehci->wake_lock_ehci_pm); #endif spin_lock_irqsave(&usb_clocks_lock, flags); if (!test_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags)) { if (omap->usbtll_fck) clk_enable(omap->usbtll_fck); mdelay(1); ehci_omap_writel(omap->tll_base, OMAP_USBTLL_IRQENABLE, 0); ehci_omap_writel(omap->tll_base, OMAP_USBTLL_IRQSTATUS, 7); ehci_omap_writel(omap->tll_base, OMAP_TLL_SHARED_CONF, 1 | ehci_omap_readl(omap->tll_base, OMAP_TLL_SHARED_CONF)); if (omap->usbhost2_120m_fck) clk_enable(omap->usbhost2_120m_fck); if (omap->usbhost1_48m_fck) clk_enable(omap->usbhost1_48m_fck); /* Put UHH in NoStandby mode */ sysconfig = ehci_omap_readl(omap->uhh_base, OMAP_UHH_SYSCONFIG); sysconfig &= ~OMAP_UHH_SYSCONFIG_MIDLEMODE_MASK; sysconfig |= OMAP_UHH_SYSCONFIG_NOSTBYMODE; ehci_omap_writel(omap->uhh_base, OMAP_UHH_SYSCONFIG, sysconfig); /* Put UHH in NoIdle mode */ sysconfig = ehci_omap_readl(omap->uhh_base, OMAP_UHH_SYSCONFIG); sysconfig &= ~OMAP_UHH_SYSCONFIG_SIDLEMODE_MASK; sysconfig |= OMAP_UHH_SYSCONFIG_NOIDLEMODE; ehci_omap_writel(omap->uhh_base, OMAP_UHH_SYSCONFIG, sysconfig); sysconfig = ehci_omap_readl(omap->uhh_base, OMAP_UHH_SYSCONFIG); set_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags); enable_irq(hcd->irq); } spin_unlock_irqrestore(&usb_clocks_lock, flags); return ehci_bus_resume(hcd); }
/*-------------------------------------------------------------------------*/ static int omap_ehci_bus_suspend(struct device *dev) { struct ehci_hcd_omap *omap = gb_omap; int ret = 0; unsigned reg = 0; if (!omap->suspended) { /* Enable forced idle mode */ reg = ehci_omap_readl(omap->tll_base, OMAP_USBTLL_SYSCONFIG); reg &= ~OMAP_USBTLL_SYSCONFIG_SIDLEMASK; reg |= OMAP_USBTLL_SYSCONFIG_S_FORCED_IDLE; ehci_omap_writel(omap->tll_base, OMAP_USBTLL_SYSCONFIG, reg); /* Enable forced Idle/Standby mode */ reg = ehci_omap_readl(omap->uhh_base, OMAP_UHH_SYSCONFIG); reg &= ~(OMAP_UHH_SYSCONFIG_SIDLEMASK | OMAP_UHH_SYSCONFIG_MIDLEMASK); reg |= OMAP_UHH_SYSCONFIG_S_FORCED_IDLE | OMAP_UHH_SYSCONFIG_M_FORCED_STDBY; ehci_omap_writel(omap->uhh_base, OMAP_UHH_SYSCONFIG, reg); clk_disable(omap->usbtll_fck); clk_put(omap->usbtll_fck); omap->usbtll_fck = NULL; clk_disable(omap->usbhost_ick); clk_put(omap->usbhost_ick); omap->usbhost_ick = NULL; clk_disable(omap->usbhost1_48m_fck); clk_put(omap->usbhost1_48m_fck); omap->usbhost1_48m_fck = NULL; clk_disable(omap->usbhost2_120m_fck); clk_put(omap->usbhost2_120m_fck); omap->usbhost2_120m_fck = NULL; clk_disable(omap->usbtll_ick); clk_put(omap->usbtll_ick); omap->usbtll_ick = NULL; omap->suspended = 1; } return ret; }
static void omap_usb_utmi_init(struct ehci_hcd_omap *omap, u8 tll_channel_mask, u8 tll_channel_count) { unsigned reg; int i; /* Program the 3 TLL channels upfront */ for (i = 0; i < tll_channel_count; i++) { reg = ehci_omap_readl(omap->tll_base, OMAP_TLL_CHANNEL_CONF(i)); /* Disable AutoIdle, BitStuffing and use SDR Mode */ reg &= ~(OMAP_TLL_CHANNEL_CONF_UTMIAUTOIDLE | OMAP_TLL_CHANNEL_CONF_ULPINOBITSTUFF | OMAP_TLL_CHANNEL_CONF_ULPIDDRMODE); ehci_omap_writel(omap->tll_base, OMAP_TLL_CHANNEL_CONF(i), reg); } /* Program Common TLL register */ reg = ehci_omap_readl(omap->tll_base, OMAP_TLL_SHARED_CONF); reg |= (OMAP_TLL_SHARED_CONF_FCLK_IS_ON | OMAP_TLL_SHARED_CONF_USB_DIVRATION | OMAP_TLL_SHARED_CONF_USB_180D_SDR_EN); reg &= ~OMAP_TLL_SHARED_CONF_USB_90D_DDR_EN; ehci_omap_writel(omap->tll_base, OMAP_TLL_SHARED_CONF, reg); /* Enable channels now */ for (i = 0; i < tll_channel_count; i++) { reg = ehci_omap_readl(omap->tll_base, OMAP_TLL_CHANNEL_CONF(i)); /* Enable only the reg that is needed */ if (!(tll_channel_mask & 1<<i)) continue; reg |= OMAP_TLL_CHANNEL_CONF_CHANEN; ehci_omap_writel(omap->tll_base, OMAP_TLL_CHANNEL_CONF(i), reg); ehci_omap_writeb(omap->tll_base, OMAP_TLL_ULPI_SCRATCH_REGISTER(i), 0xbe); dev_dbg(omap->dev, "ULPI_SCRATCH_REG[ch=%d]= 0x%02x\n", i+1, ehci_omap_readb(omap->tll_base, OMAP_TLL_ULPI_SCRATCH_REGISTER(i))); } }
static int omap_ehci_bus_resume(struct usb_hcd *hcd) { struct ehci_hcd_omap *omap; unsigned long flags; int ret = 0; u32 reg; omap = ((struct ehci_hcd *) ((char *)hcd_to_ehci(hcd)))->omap_p; spin_lock_irqsave(&sus_res_lock, flags); if(omap->suspended){ clk_enable(omap->usbtll_fck); reg = ehci_omap_readl(omap->tll_base, OMAP_TLL_SHARED_CONF); reg |=1; ehci_omap_writel(omap->tll_base, OMAP_TLL_SHARED_CONF, reg); clk_enable(omap->usbhost_fck); clk_enable(omap->usbhost_fs_fck); omap_writel(OHCI_HC_CTRL_RESUME, OHCI_HC_CONTROL); reg = ehci_omap_readl(omap->uhh_base, OMAP_UHH_SYSCONFIG); reg &= ~(3 << 12); reg &= ~(3 << 3); reg |= (1 << 12); reg |= (1 << 3); ehci_omap_writel(omap->uhh_base, OMAP_UHH_SYSCONFIG, reg); omap->suspended = 0; ehci_omap_writel(omap->tll_base, OMAP_USBTLL_IRQENABLE, 0); } ret = ehci_bus_resume(hcd); spin_unlock_irqrestore(&sus_res_lock, flags); return 0; }
/*------------------------------------------------------------------------- * */ static int setup_tll(struct ehci_hcd_omap *omap) { unsigned long timeout = jiffies + msecs_to_jiffies(1000); int ret = 0; u8 tll_ch_mask = 0; /* perform TLL soft reset, and wait until reset is complete */ ehci_omap_writel(omap->tll_base, OMAP_USBTLL_SYSCONFIG, OMAP_USBTLL_SYSCONFIG_SOFTRESET); /* Wait for TLL reset to complete */ while (!(ehci_omap_readl(omap->tll_base, OMAP_USBTLL_SYSSTATUS) & OMAP_USBTLL_SYSSTATUS_RESETDONE)) { cpu_relax(); if (time_after(jiffies, timeout)) { dev_dbg(omap->dev, "operation timed out\n"); ret = -EINVAL; return ret; } } dev_dbg(omap->dev, "TLL RESET DONE\n"); /* (1<<3) = no idle mode only for initial debugging */ ehci_omap_writel(omap->tll_base, OMAP_USBTLL_SYSCONFIG, OMAP_USBTLL_SYSCONFIG_ENAWAKEUP | OMAP_USBTLL_SYSCONFIG_SIDLEMODE | OMAP_USBTLL_SYSCONFIG_CACTIVITY); if (omap->port_mode[0] == EHCI_HCD_OMAP_MODE_TLL) tll_ch_mask |= OMAP_TLL_CHANNEL_1_EN_MASK; if (omap->port_mode[1] == EHCI_HCD_OMAP_MODE_TLL) tll_ch_mask |= OMAP_TLL_CHANNEL_2_EN_MASK; if (!cpu_is_omap44xx()) { if (omap->port_mode[2] == EHCI_HCD_OMAP_MODE_TLL) tll_ch_mask |= OMAP_TLL_CHANNEL_3_EN_MASK; if (tll_ch_mask != 0) omap_usb_utmi_init(omap, tll_ch_mask,OMAP_TLL_CHANNEL_COUNT); } else { if (tll_ch_mask != 0) omap_usb_utmi_init(omap, tll_ch_mask, OMAP4_TLL_CHANNEL_COUNT); } return ret; }
static irqreturn_t usbtll_irq(int irq, void *pdev) { unsigned long flags; u32 sysconfig; u32 usbtll_irqstatus; struct ehci_hcd_omap *omap = platform_get_drvdata( (struct platform_device *)pdev); struct usb_hcd *hcd = ehci_to_hcd(omap->ehci); usbtll_irqstatus = ehci_omap_readl( omap->tll_base, OMAP_USBTLL_IRQSTATUS); spin_lock_irqsave(&usb_clocks_lock, flags); if (usbtll_irqstatus & 1) { LOG_USBHOST_ACTIVITY(aUsbHostDbg, iUsbHostDbg, 0x30); LOG_USBHOST_ACTIVITY(aUsbHostDbg, iUsbHostDbg, jiffies); if (test_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags)) { ehci_omap_writel(omap->tll_base, OMAP_USBTLL_IRQSTATUS, usbtll_irqstatus); ehci_omap_writel(omap->tll_base, OMAP_USBTLL_IRQENABLE, 0); spin_unlock_irqrestore(&usb_clocks_lock, flags); return IRQ_HANDLED; } #ifdef CONFIG_HAS_WAKELOCK wake_lock_timeout(&omap->ehci->wake_lock_ehci_rwu, HZ/2); #endif if (omap->usbtll_fck) clk_enable(omap->usbtll_fck); /* Disable usbtll irq to prevent race condition in suspend */ ehci_omap_writel(omap->tll_base, OMAP_TLL_SHARED_CONF, 1 | ehci_omap_readl(omap->tll_base, OMAP_TLL_SHARED_CONF)); ehci_omap_writel(omap->tll_base, OMAP_USBTLL_IRQSTATUS, usbtll_irqstatus); if (omap->usbhost2_120m_fck) clk_enable(omap->usbhost2_120m_fck); if (omap->usbhost1_48m_fck) clk_enable(omap->usbhost1_48m_fck); /* Put UHH in NoStandby mode */ sysconfig = ehci_omap_readl(omap->uhh_base, OMAP_UHH_SYSCONFIG); sysconfig &= ~OMAP_UHH_SYSCONFIG_MIDLEMODE_MASK; sysconfig |= OMAP_UHH_SYSCONFIG_NOSTBYMODE; ehci_omap_writel(omap->uhh_base, OMAP_UHH_SYSCONFIG, sysconfig); /* Put UHH in NoIdle mode */ sysconfig = ehci_omap_readl(omap->uhh_base, OMAP_UHH_SYSCONFIG); sysconfig &= ~OMAP_UHH_SYSCONFIG_SIDLEMODE_MASK; sysconfig |= OMAP_UHH_SYSCONFIG_NOIDLEMODE; ehci_omap_writel(omap->uhh_base, OMAP_UHH_SYSCONFIG, sysconfig); sysconfig = ehci_omap_readl(omap->uhh_base, OMAP_UHH_SYSCONFIG); ehci_omap_writel(omap->tll_base, OMAP_USBTLL_IRQENABLE, 0); set_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags); enable_irq(hcd->irq); } spin_unlock_irqrestore(&usb_clocks_lock, flags); return IRQ_HANDLED; }
static void omap_stop_ehc(struct ehci_hcd_omap *omap, struct usb_hcd *hcd) { unsigned long timeout = jiffies + msecs_to_jiffies(100); dev_dbg(omap->dev, "stopping TI EHCI USB Controller\n"); /* Reset OMAP modules for insmod/rmmod to work */ ehci_omap_writel(omap->uhh_base, OMAP_UHH_SYSCONFIG, OMAP_UHH_SYSCONFIG_SOFTRESET); while (!(ehci_omap_readl(omap->uhh_base, OMAP_UHH_SYSSTATUS) & (1 << 0))) { cpu_relax(); if (time_after(jiffies, timeout)) dev_dbg(omap->dev, "operation timed out\n"); } while (!(ehci_omap_readl(omap->uhh_base, OMAP_UHH_SYSSTATUS) & (1 << 1))) { cpu_relax(); if (time_after(jiffies, timeout)) dev_dbg(omap->dev, "operation timed out\n"); } while (!(ehci_omap_readl(omap->uhh_base, OMAP_UHH_SYSSTATUS) & (1 << 2))) { cpu_relax(); if (time_after(jiffies, timeout)) dev_dbg(omap->dev, "operation timed out\n"); } ehci_omap_writel(omap->tll_base, OMAP_USBTLL_SYSCONFIG, (1 << 1)); while (!(ehci_omap_readl(omap->tll_base, OMAP_USBTLL_SYSSTATUS) & (1 << 0))) { cpu_relax(); if (time_after(jiffies, timeout)) dev_dbg(omap->dev, "operation timed out\n"); } if (omap->usbtll_fck != NULL) { clk_disable(omap->usbtll_fck); clk_put(omap->usbtll_fck); omap->usbtll_fck = NULL; } if (omap->usbhost_ick != NULL) { clk_disable(omap->usbhost_ick); clk_put(omap->usbhost_ick); omap->usbhost_ick = NULL; } if (omap->usbhost1_48m_fck != NULL) { clk_disable(omap->usbhost1_48m_fck); clk_put(omap->usbhost1_48m_fck); omap->usbhost1_48m_fck = NULL; } if (omap->usbhost2_120m_fck != NULL) { clk_disable(omap->usbhost2_120m_fck); clk_put(omap->usbhost2_120m_fck); omap->usbhost2_120m_fck = NULL; } if (omap->usbtll_ick != NULL) { clk_disable(omap->usbtll_ick); clk_put(omap->usbtll_ick); omap->usbtll_ick = NULL; } if (omap->phy_reset) { if (gpio_is_valid(omap->reset_gpio_port[0])) gpio_free(omap->reset_gpio_port[0]); if (gpio_is_valid(omap->reset_gpio_port[1])) gpio_free(omap->reset_gpio_port[1]); } dev_dbg(omap->dev, "Clock to USB host has been disabled\n"); }
/* omap_start_ehc * - Start the TI USBHOST controller */ static int omap_start_ehc(struct ehci_hcd_omap *omap, struct usb_hcd *hcd) { unsigned long timeout = jiffies + msecs_to_jiffies(1000); u8 tll_ch_mask = 0; unsigned reg = 0; int ret = 0; dev_dbg(omap->dev, "starting TI EHCI USB Controller\n"); /* Enable Clocks for USBHOST */ omap->usbhost_ick = clk_get(omap->dev, "usbhost_ick"); if (IS_ERR(omap->usbhost_ick)) { ret = PTR_ERR(omap->usbhost_ick); goto err_host_ick; } clk_enable(omap->usbhost_ick); omap->usbhost2_120m_fck = clk_get(omap->dev, "usbhost_120m_fck"); if (IS_ERR(omap->usbhost2_120m_fck)) { ret = PTR_ERR(omap->usbhost2_120m_fck); goto err_host_120m_fck; } clk_enable(omap->usbhost2_120m_fck); omap->usbhost1_48m_fck = clk_get(omap->dev, "usbhost_48m_fck"); if (IS_ERR(omap->usbhost1_48m_fck)) { ret = PTR_ERR(omap->usbhost1_48m_fck); goto err_host_48m_fck; } clk_enable(omap->usbhost1_48m_fck); if (omap->phy_reset) { /* Refer: ISSUE1 */ if (gpio_is_valid(omap->reset_gpio_port[0])) { gpio_request(omap->reset_gpio_port[0], "USB1 PHY reset"); gpio_direction_output(omap->reset_gpio_port[0], 0); } if (gpio_is_valid(omap->reset_gpio_port[1])) { gpio_request(omap->reset_gpio_port[1], "USB2 PHY reset"); gpio_direction_output(omap->reset_gpio_port[1], 0); } /* Hold the PHY in RESET for enough time till DIR is high */ udelay(10); } /* Configure TLL for 60Mhz clk for ULPI */ omap->usbtll_fck = clk_get(omap->dev, "usbtll_fck"); if (IS_ERR(omap->usbtll_fck)) { ret = PTR_ERR(omap->usbtll_fck); goto err_tll_fck; } clk_enable(omap->usbtll_fck); omap->usbtll_ick = clk_get(omap->dev, "usbtll_ick"); if (IS_ERR(omap->usbtll_ick)) { ret = PTR_ERR(omap->usbtll_ick); goto err_tll_ick; } clk_enable(omap->usbtll_ick); /* perform TLL soft reset, and wait until reset is complete */ ehci_omap_writel(omap->tll_base, OMAP_USBTLL_SYSCONFIG, OMAP_USBTLL_SYSCONFIG_SOFTRESET); /* Wait for TLL reset to complete */ while (!(ehci_omap_readl(omap->tll_base, OMAP_USBTLL_SYSSTATUS) & OMAP_USBTLL_SYSSTATUS_RESETDONE)) { cpu_relax(); if (time_after(jiffies, timeout)) { dev_dbg(omap->dev, "operation timed out\n"); ret = -EINVAL; goto err_sys_status; } } dev_dbg(omap->dev, "TLL RESET DONE\n"); /* (1<<3) = no idle mode only for initial debugging */ ehci_omap_writel(omap->tll_base, OMAP_USBTLL_SYSCONFIG, OMAP_USBTLL_SYSCONFIG_ENAWAKEUP | OMAP_USBTLL_SYSCONFIG_SIDLEMODE | OMAP_USBTLL_SYSCONFIG_CACTIVITY); /* Put UHH in NoIdle/NoStandby mode */ reg = ehci_omap_readl(omap->uhh_base, OMAP_UHH_SYSCONFIG); reg |= (OMAP_UHH_SYSCONFIG_ENAWAKEUP | OMAP_UHH_SYSCONFIG_SIDLEMODE | OMAP_UHH_SYSCONFIG_CACTIVITY | OMAP_UHH_SYSCONFIG_MIDLEMODE); reg &= ~OMAP_UHH_SYSCONFIG_AUTOIDLE; ehci_omap_writel(omap->uhh_base, OMAP_UHH_SYSCONFIG, reg); reg = ehci_omap_readl(omap->uhh_base, OMAP_UHH_HOSTCONFIG); /* setup ULPI bypass and burst configurations */ reg |= (OMAP_UHH_HOSTCONFIG_INCR4_BURST_EN | OMAP_UHH_HOSTCONFIG_INCR8_BURST_EN | OMAP_UHH_HOSTCONFIG_INCR16_BURST_EN); reg &= ~OMAP_UHH_HOSTCONFIG_INCRX_ALIGN_EN; if (omap->port_mode[0] == EHCI_HCD_OMAP_MODE_UNKNOWN) reg &= ~OMAP_UHH_HOSTCONFIG_P1_CONNECT_STATUS; if (omap->port_mode[1] == EHCI_HCD_OMAP_MODE_UNKNOWN) reg &= ~OMAP_UHH_HOSTCONFIG_P2_CONNECT_STATUS; if (omap->port_mode[2] == EHCI_HCD_OMAP_MODE_UNKNOWN) reg &= ~OMAP_UHH_HOSTCONFIG_P3_CONNECT_STATUS; /* Bypass the TLL module for PHY mode operation */ if (omap_rev() <= OMAP3430_REV_ES2_1) { dev_dbg(omap->dev, "OMAP3 ES version <= ES2.1 \n"); if ((omap->port_mode[0] == EHCI_HCD_OMAP_MODE_PHY) || (omap->port_mode[1] == EHCI_HCD_OMAP_MODE_PHY) || (omap->port_mode[2] == EHCI_HCD_OMAP_MODE_PHY)) reg &= ~OMAP_UHH_HOSTCONFIG_ULPI_BYPASS; else reg |= OMAP_UHH_HOSTCONFIG_ULPI_BYPASS; } else { dev_dbg(omap->dev, "OMAP3 ES version > ES2.1\n"); if (omap->port_mode[0] == EHCI_HCD_OMAP_MODE_PHY) reg &= ~OMAP_UHH_HOSTCONFIG_ULPI_P1_BYPASS; else if (omap->port_mode[0] == EHCI_HCD_OMAP_MODE_TLL) reg |= OMAP_UHH_HOSTCONFIG_ULPI_P1_BYPASS; if (omap->port_mode[1] == EHCI_HCD_OMAP_MODE_PHY) reg &= ~OMAP_UHH_HOSTCONFIG_ULPI_P2_BYPASS; else if (omap->port_mode[1] == EHCI_HCD_OMAP_MODE_TLL) reg |= OMAP_UHH_HOSTCONFIG_ULPI_P2_BYPASS; if (omap->port_mode[2] == EHCI_HCD_OMAP_MODE_PHY) reg &= ~OMAP_UHH_HOSTCONFIG_ULPI_P3_BYPASS; else if (omap->port_mode[2] == EHCI_HCD_OMAP_MODE_TLL) reg |= OMAP_UHH_HOSTCONFIG_ULPI_P3_BYPASS; } ehci_omap_writel(omap->uhh_base, OMAP_UHH_HOSTCONFIG, reg); dev_dbg(omap->dev, "UHH setup done, uhh_hostconfig=%x\n", reg); if ((omap->port_mode[0] == EHCI_HCD_OMAP_MODE_TLL) || (omap->port_mode[1] == EHCI_HCD_OMAP_MODE_TLL) || (omap->port_mode[2] == EHCI_HCD_OMAP_MODE_TLL)) { if (omap->port_mode[0] == EHCI_HCD_OMAP_MODE_TLL) tll_ch_mask |= OMAP_TLL_CHANNEL_1_EN_MASK; if (omap->port_mode[1] == EHCI_HCD_OMAP_MODE_TLL) tll_ch_mask |= OMAP_TLL_CHANNEL_2_EN_MASK; if (omap->port_mode[2] == EHCI_HCD_OMAP_MODE_TLL) tll_ch_mask |= OMAP_TLL_CHANNEL_3_EN_MASK; /* Enable UTMI mode for required TLL channels */ omap_usb_utmi_init(omap, tll_ch_mask); } if (omap->phy_reset) { /* Refer ISSUE1: * Hold the PHY in RESET for enough time till * PHY is settled and ready */ udelay(10); if (gpio_is_valid(omap->reset_gpio_port[0])) gpio_set_value(omap->reset_gpio_port[0], 1); if (gpio_is_valid(omap->reset_gpio_port[1])) gpio_set_value(omap->reset_gpio_port[1], 1); } return 0; err_sys_status: clk_disable(omap->usbtll_ick); clk_put(omap->usbtll_ick); err_tll_ick: clk_disable(omap->usbtll_fck); clk_put(omap->usbtll_fck); err_tll_fck: clk_disable(omap->usbhost1_48m_fck); clk_put(omap->usbhost1_48m_fck); if (omap->phy_reset) { if (gpio_is_valid(omap->reset_gpio_port[0])) gpio_free(omap->reset_gpio_port[0]); if (gpio_is_valid(omap->reset_gpio_port[1])) gpio_free(omap->reset_gpio_port[1]); } err_host_48m_fck: clk_disable(omap->usbhost2_120m_fck); clk_put(omap->usbhost2_120m_fck); err_host_120m_fck: clk_disable(omap->usbhost_ick); clk_put(omap->usbhost_ick); err_host_ick: return ret; }
/* omap_start_ehc * - Start the TI USBHOST controller */ static int omap_start_ehc(struct ehci_hcd_omap *omap, struct usb_hcd *hcd) { unsigned long timeout = jiffies + msecs_to_jiffies(1000); unsigned reg = 0; int ret = 0; int reset_delay; int i; dev_dbg(&omap->dev->dev, "starting TI EHCI USB Controller\n"); /* Enable Clocks for USBHOST */ omap->usbhost_ick = clk_get(&omap->dev->dev, "usbhost_ick"); if (IS_ERR(omap->usbhost_ick)) { ret = PTR_ERR(omap->usbhost_ick); goto err_host_ick; } clk_enable(omap->usbhost_ick); omap->usbhost2_120m_fck = clk_get(&omap->dev->dev, "usbhost_120m_fck"); if (IS_ERR(omap->usbhost2_120m_fck)) { ret = PTR_ERR(omap->usbhost2_120m_fck); goto err_host_120m_fck; } clk_enable(omap->usbhost2_120m_fck); omap->usbhost1_48m_fck = clk_get(&omap->dev->dev, "usbhost_48m_fck"); if (IS_ERR(omap->usbhost1_48m_fck)) { ret = PTR_ERR(omap->usbhost1_48m_fck); goto err_host_48m_fck; } clk_enable(omap->usbhost1_48m_fck); reset_delay = 0; for (i = 0; i < OMAP_TLL_CHANNEL_COUNT; i++) { reset_delay = reset_delay > omap->port_data[i].reset_delay ? reset_delay : omap->port_data[i].reset_delay; if (omap->port_data[i].startup) { ret = omap->port_data[i].startup(omap->dev, i); if (ret < 0) return ret; } if (omap->port_data[i].reset) omap->port_data[i].reset(omap->dev, i, 0); } if (reset_delay) udelay(reset_delay); /* Configure TLL for 60Mhz clk for ULPI */ omap->usbtll_fck = clk_get(&omap->dev->dev, "usbtll_fck"); if (IS_ERR(omap->usbtll_fck)) { ret = PTR_ERR(omap->usbtll_fck); goto err_tll_fck; } clk_enable(omap->usbtll_fck); omap->usbtll_ick = clk_get(&omap->dev->dev, "usbtll_ick"); if (IS_ERR(omap->usbtll_ick)) { ret = PTR_ERR(omap->usbtll_ick); goto err_tll_ick; } clk_enable(omap->usbtll_ick); /* perform TLL soft reset, and wait until reset is complete */ ehci_omap_writel(omap->tll_base, OMAP_USBTLL_SYSCONFIG, OMAP_USBTLL_SYSCONFIG_SOFTRESET); /* Wait for TLL reset to complete */ while (!(ehci_omap_readl(omap->tll_base, OMAP_USBTLL_SYSSTATUS) & OMAP_USBTLL_SYSSTATUS_RESETDONE)) { cpu_relax(); if (time_after(jiffies, timeout)) { dev_dbg(&omap->dev->dev, "operation timed out\n"); ret = -EINVAL; goto err_sys_status; } } dev_dbg(&omap->dev->dev, "TLL RESET DONE\n"); /* (1<<3) = no idle mode only for initial debugging */ ehci_omap_writel(omap->tll_base, OMAP_USBTLL_SYSCONFIG, OMAP_USBTLL_SYSCONFIG_ENAWAKEUP | OMAP_USBTLL_SYSCONFIG_SIDLEMODE | OMAP_USBTLL_SYSCONFIG_CACTIVITY); /* Put UHH in NoIdle/NoStandby mode */ ehci_omap_writel(omap->uhh_base, OMAP_UHH_SYSCONFIG, OMAP_UHH_SYSCONFIG_ENAWAKEUP | OMAP_UHH_SYSCONFIG_SIDLEMODE | OMAP_UHH_SYSCONFIG_MIDLEMODE | OMAP_UHH_SYSCONFIG_AUTOIDLE); reg = ehci_omap_readl(omap->uhh_base, OMAP_UHH_HOSTCONFIG); /* setup ULPI bypass and burst configurations */ reg |= (OMAP_UHH_HOSTCONFIG_INCR4_BURST_EN | OMAP_UHH_HOSTCONFIG_INCR8_BURST_EN | OMAP_UHH_HOSTCONFIG_INCR16_BURST_EN); reg &= ~OMAP_UHH_HOSTCONFIG_INCRX_ALIGN_EN; if (omap->port_data[0].flags != EHCI_HCD_OMAP_FLAG_ENABLED) reg &= ~OMAP_UHH_HOSTCONFIG_P1_CONNECT_STATUS; if (omap->port_data[1].flags != EHCI_HCD_OMAP_FLAG_ENABLED) reg &= ~OMAP_UHH_HOSTCONFIG_P2_CONNECT_STATUS; if (omap->port_data[2].flags != EHCI_HCD_OMAP_FLAG_ENABLED) reg &= ~OMAP_UHH_HOSTCONFIG_P3_CONNECT_STATUS; /* Bypass the TLL module for PHY mode operation */ if (omap_rev() <= OMAP3430_REV_ES2_1) { dev_dbg(&omap->dev->dev, "OMAP3 ES version <= ES2.1 \n"); if (omap_usb_port_ulpi_bypass(omap->port_data[0].mode)) reg |= OMAP_UHH_HOSTCONFIG_ULPI_BYPASS; else reg &= ~OMAP_UHH_HOSTCONFIG_ULPI_BYPASS; } else { dev_dbg(&omap->dev->dev, "OMAP3 ES version > ES2.1\n"); if (omap_usb_port_ulpi_bypass(omap->port_data[0].mode)) reg |= OMAP_UHH_HOSTCONFIG_ULPI_P1_BYPASS; else reg &= ~OMAP_UHH_HOSTCONFIG_ULPI_P1_BYPASS; if (omap_usb_port_ulpi_bypass(omap->port_data[1].mode)) reg |= OMAP_UHH_HOSTCONFIG_ULPI_P2_BYPASS; else reg &= ~OMAP_UHH_HOSTCONFIG_ULPI_P2_BYPASS; if (omap_usb_port_ulpi_bypass(omap->port_data[2].mode)) reg |= OMAP_UHH_HOSTCONFIG_ULPI_P3_BYPASS; else reg &= ~OMAP_UHH_HOSTCONFIG_ULPI_P3_BYPASS; } ehci_omap_writel(omap->uhh_base, OMAP_UHH_HOSTCONFIG, reg); dev_dbg(&omap->dev->dev, "UHH setup done, uhh_hostconfig=%x\n", reg); /* Enable UTMI mode for required TLL channels */ omap_usb_utmi_init(omap); reset_delay = 0; for (i = 0; i < OMAP3_HS_USB_PORTS; i++) { reset_delay = reset_delay > omap->port_data[i].reset_delay ? reset_delay : omap->port_data[i].reset_delay; } if (reset_delay) udelay(reset_delay); for (i = 0; i < OMAP3_HS_USB_PORTS; i++) { if (omap->port_data[i].reset) omap->port_data[i].reset(omap->dev, i, 1); } return 0; err_sys_status: clk_disable(omap->usbtll_ick); clk_put(omap->usbtll_ick); err_tll_ick: clk_disable(omap->usbtll_fck); clk_put(omap->usbtll_fck); err_tll_fck: clk_disable(omap->usbhost1_48m_fck); clk_put(omap->usbhost1_48m_fck); err_host_48m_fck: clk_disable(omap->usbhost2_120m_fck); clk_put(omap->usbhost2_120m_fck); err_host_120m_fck: clk_disable(omap->usbhost_ick); clk_put(omap->usbhost_ick); err_host_ick: return ret; }
static void omap_usb_utmi_init(struct ehci_hcd_omap *omap) { unsigned reg; int i; /* Program the 3 TLL channels upfront */ for (i = 0; i < OMAP_TLL_CHANNEL_COUNT; i++) { reg = ehci_omap_readl(omap->tll_base, OMAP_TLL_CHANNEL_CONF(i)); dev_dbg(&omap->dev->dev, "port %d: OMAP_TTL_CHANNEL_CONF_%d=%08x\n", i, i+1, ehci_omap_readl(omap->tll_base, OMAP_TLL_CHANNEL_CONF(i))); if (omap->port_data[i].flags & EHCI_HCD_OMAP_FLAG_NOBITSTUFF) reg |= OMAP_TLL_CHANNEL_CONF_ULPINOBITSTUFF; else reg &= ~OMAP_TLL_CHANNEL_CONF_ULPINOBITSTUFF; if (omap_usb_port_utmi_chanel_config(omap->port_data[i].mode)) { if (omap->port_data[i].flags & EHCI_HCD_OMAP_FLAG_AUTOIDLE) reg |= OMAP_TLL_CHANNEL_CONF_UTMIAUTOIDLE; else reg &= ~OMAP_TLL_CHANNEL_CONF_UTMIAUTOIDLE; } else { if (omap->port_data[i].flags & EHCI_HCD_OMAP_FLAG_AUTOIDLE) reg |= OMAP_TLL_CHANNEL_CONF_ULPI_ULPIAUTOIDLE; else reg &= ~OMAP_TLL_CHANNEL_CONF_ULPI_ULPIAUTOIDLE; } if (omap->port_data[i].mode == EHCI_HCD_OMAP_MODE_ULPI_TLL_DDR) reg |= OMAP_TLL_CHANNEL_CONF_ULPIDDRMODE; else reg &= ~OMAP_TLL_CHANNEL_CONF_ULPIDDRMODE; ehci_omap_writel(omap->tll_base, OMAP_TLL_CHANNEL_CONF(i), reg); } /* Program Common TLL register */ ehci_omap_writel(omap->tll_base, OMAP_TLL_SHARED_CONF, OMAP_TLL_SHARED_CONF_FCLK_IS_ON | OMAP_TLL_SHARED_CONF_USB_DIVRATION); /* Enable channels now */ for (i = 0; i < OMAP_TLL_CHANNEL_COUNT; i++) { /* Enable only the reg that is needed */ if (!(omap->port_data[i].flags & EHCI_HCD_OMAP_FLAG_ENABLED)) continue; reg = ehci_omap_readl(omap->tll_base, OMAP_TLL_CHANNEL_CONF(i)); reg |= OMAP_TLL_CHANNEL_CONF_CHANEN; if (omap_usb_port_utmi_chanel_config(omap->port_data[i].mode)) reg |= OMAP_TLL_CHANNEL_CONF_CHANMODE(1); else reg &= ~OMAP_TLL_CHANNEL_CONF_CHANMODE(3); reg &= ~(OMAP_TLL_CHANNEL_CONF_FSLSMODE(0xf)); reg |= OMAP_TLL_CHANNEL_CONF_FSLSMODE( omap_usb_port_fslsmode(omap->port_data[i].mode)); ehci_omap_writel(omap->tll_base, OMAP_TLL_CHANNEL_CONF(i), reg); dev_dbg(&omap->dev->dev, "port %d enabled: OMAP_TTL_CHANNEL_CONF_%d=%08x:%08x\n", i, i+1, reg, ehci_omap_readl(omap->tll_base, OMAP_TLL_CHANNEL_CONF(i))); ehci_omap_writeb(omap->tll_base, OMAP_TLL_ULPI_SCRATCH_REGISTER(i), 0xbe); dev_dbg(&omap->dev->dev, "ULPI_SCRATCH_REG[ch=%d]= 0x%02x\n", i+1, ehci_omap_readb(omap->tll_base, OMAP_TLL_ULPI_SCRATCH_REGISTER(i))); } }
static int omap_ehci_bus_resume(struct device *dev) { struct ehci_hcd_omap *omap = gb_omap; int ret = 0; unsigned reg = 0; if (omap->suspended) { omap->usbhost_ick = clk_get(omap->dev, "usbhost_ick"); if (IS_ERR(omap->usbhost_ick)) { ret = PTR_ERR(omap->usbhost_ick); goto clk_error_usbhost_ick; } clk_enable(omap->usbhost_ick); udelay(30); omap->usbhost2_120m_fck = clk_get(omap->dev, "usbhost_120m_fck"); if (IS_ERR(omap->usbhost2_120m_fck)) { ret = PTR_ERR(omap->usbhost2_120m_fck); goto clk_error_120m_fck; } clk_enable(omap->usbhost2_120m_fck); udelay(30); omap->usbhost1_48m_fck = clk_get(omap->dev, "usbhost_48m_fck"); if (IS_ERR(omap->usbhost1_48m_fck)) { ret = PTR_ERR(omap->usbhost1_48m_fck); goto clk_error_48m_fck; } clk_enable(omap->usbhost1_48m_fck); udelay(30); omap->usbtll_fck = clk_get(omap->dev, "usbtll_fck"); if (IS_ERR(omap->usbtll_fck)) { ret = PTR_ERR(omap->usbtll_fck); goto clk_error_usbtll_fck; } clk_enable(omap->usbtll_fck); udelay(30); omap->usbtll_ick = clk_get(omap->dev, "usbtll_ick"); if (IS_ERR(omap->usbtll_ick)) { ret = PTR_ERR(omap->usbtll_ick); goto clk_error_usbtll_ick; } clk_enable(omap->usbtll_ick); udelay(30); /* Enable smart idle mode */ reg = ehci_omap_readl(omap->tll_base, OMAP_USBTLL_SYSCONFIG); reg &= ~OMAP_USBTLL_SYSCONFIG_SIDLEMASK; reg |= OMAP_USBTLL_SYSCONFIG_S_SMART_IDLE; ehci_omap_writel(omap->tll_base, OMAP_USBTLL_SYSCONFIG, reg); /* Enable smart Idle/Standby mode */ reg = ehci_omap_readl(omap->uhh_base, OMAP_UHH_SYSCONFIG); reg &= ~(OMAP_UHH_SYSCONFIG_SIDLEMASK | OMAP_UHH_SYSCONFIG_MIDLEMASK); reg |= OMAP_UHH_SYSCONFIG_S_SMART_IDLE | OMAP_UHH_SYSCONFIG_M_SMART_STDBY; ehci_omap_writel(omap->uhh_base, OMAP_UHH_SYSCONFIG, reg); omap->suspended = 0; } return ret; clk_error_usbtll_ick: clk_disable(omap->usbtll_fck); clk_put(omap->usbtll_fck); omap->usbtll_fck = NULL; clk_error_usbtll_fck: clk_disable(omap->usbhost1_48m_fck); clk_put(omap->usbhost1_48m_fck); omap->usbhost1_48m_fck = NULL; clk_error_48m_fck: clk_disable(omap->usbhost2_120m_fck); clk_put(omap->usbhost2_120m_fck); omap->usbhost2_120m_fck = NULL; clk_error_120m_fck: clk_disable(omap->usbhost_ick); clk_put(omap->usbhost_ick); omap->usbhost_ick = NULL; clk_error_usbhost_ick: return ret; }
/* omap_start_ehc * - Start the TI USBHOST controller */ static int omap_start_ehc(struct ehci_hcd_omap *omap, struct usb_hcd *hcd) { unsigned long timeout = jiffies + msecs_to_jiffies(1000); u8 tll_ch_mask = 0; unsigned reg = 0; int ret = 0; dev_dbg(omap->dev, "starting TI EHCI USB Controller\n"); /* Enable Clocks for USBHOST */ omap->usbhost_ick = clk_get(omap->dev, "usbhost_ick"); if (IS_ERR(omap->usbhost_ick)) { ret = PTR_ERR(omap->usbhost_ick); goto err_host_ick; } clk_enable(omap->usbhost_ick); omap->usbhost_hs_fck = clk_get(omap->dev, "hs_fck"); if (IS_ERR(omap->usbhost_hs_fck)) { ret = PTR_ERR(omap->usbhost_hs_fck); goto err_host_120m_fck; } clk_enable(omap->usbhost_hs_fck); omap->usbhost_fs_fck = clk_get(omap->dev, "fs_fck"); if (IS_ERR(omap->usbhost_fs_fck)) { ret = PTR_ERR(omap->usbhost_fs_fck); goto err_host_48m_fck; } clk_enable(omap->usbhost_fs_fck); if (omap->phy_reset) { /* Refer: ISSUE1 */ if (gpio_is_valid(omap->reset_gpio_port[0])) { gpio_request(omap->reset_gpio_port[0], "USB1 PHY reset"); gpio_direction_output(omap->reset_gpio_port[0], 0); } if (gpio_is_valid(omap->reset_gpio_port[1])) { gpio_request(omap->reset_gpio_port[1], "USB2 PHY reset"); gpio_direction_output(omap->reset_gpio_port[1], 0); } /* Hold the PHY in RESET for enough time till DIR is high */ udelay(10); } /* Configure TLL for 60Mhz clk for ULPI */ omap->usbtll_fck = clk_get(omap->dev, "usbtll_fck"); if (IS_ERR(omap->usbtll_fck)) { ret = PTR_ERR(omap->usbtll_fck); goto err_tll_fck; } clk_enable(omap->usbtll_fck); omap->usbtll_ick = clk_get(omap->dev, "usbtll_ick"); if (IS_ERR(omap->usbtll_ick)) { ret = PTR_ERR(omap->usbtll_ick); goto err_tll_ick; } clk_enable(omap->usbtll_ick); omap->omap_ehci_rev = ehci_omap_readl(omap->uhh_base, OMAP_UHH_REVISION); dev_dbg(omap->dev, "OMAP UHH_REVISION 0x%x\n", omap->omap_ehci_rev); /* * Enable per-port clocks as needed (newer controllers only). * - External ULPI clock for PHY mode * - Internal clocks for TLL and HSIC modes (TODO) */ if (is_omap_ehci_rev2(omap)) { switch (omap->port_mode[0]) { case EHCI_HCD_OMAP_MODE_PHY: omap->xclk60mhsp1_ck = clk_get(omap->dev, "xclk60mhsp1_ck"); if (IS_ERR(omap->xclk60mhsp1_ck)) { ret = PTR_ERR(omap->xclk60mhsp1_ck); dev_err(omap->dev, "Unable to get Port1 ULPI clock\n"); } omap->utmi_p1_fck = clk_get(omap->dev, "utmi_p1_gfclk"); if (IS_ERR(omap->utmi_p1_fck)) { ret = PTR_ERR(omap->utmi_p1_fck); dev_err(omap->dev, "Unable to get utmi_p1_fck\n"); } ret = clk_set_parent(omap->utmi_p1_fck, omap->xclk60mhsp1_ck); if (ret != 0) { dev_err(omap->dev, "Unable to set P1 f-clock\n"); } break; case EHCI_HCD_OMAP_MODE_TLL: /* TODO */ default: break; } switch (omap->port_mode[1]) { case EHCI_HCD_OMAP_MODE_PHY: omap->xclk60mhsp2_ck = clk_get(omap->dev, "xclk60mhsp2_ck"); if (IS_ERR(omap->xclk60mhsp2_ck)) { ret = PTR_ERR(omap->xclk60mhsp2_ck); dev_err(omap->dev, "Unable to get Port2 ULPI clock\n"); } omap->utmi_p2_fck = clk_get(omap->dev, "utmi_p2_gfclk"); if (IS_ERR(omap->utmi_p2_fck)) { ret = PTR_ERR(omap->utmi_p2_fck); dev_err(omap->dev, "Unable to get utmi_p2_fck\n"); } ret = clk_set_parent(omap->utmi_p2_fck, omap->xclk60mhsp2_ck); if (ret != 0) { dev_err(omap->dev, "Unable to set P2 f-clock\n"); } break; case EHCI_HCD_OMAP_MODE_TLL: /* TODO */ default: break; } } /* perform TLL soft reset, and wait until reset is complete */ ehci_omap_writel(omap->tll_base, OMAP_USBTLL_SYSCONFIG, OMAP_USBTLL_SYSCONFIG_SOFTRESET); /* Wait for TLL reset to complete */ while (!(ehci_omap_readl(omap->tll_base, OMAP_USBTLL_SYSSTATUS) & OMAP_USBTLL_SYSSTATUS_RESETDONE)) { cpu_relax(); if (time_after(jiffies, timeout)) { dev_dbg(omap->dev, "operation timed out\n"); ret = -EINVAL; goto err_sys_status; } } dev_dbg(omap->dev, "TLL RESET DONE\n"); /* (1<<3) = no idle mode only for initial debugging */ ehci_omap_writel(omap->tll_base, OMAP_USBTLL_SYSCONFIG, OMAP_USBTLL_SYSCONFIG_ENAWAKEUP | OMAP_USBTLL_SYSCONFIG_SIDLEMODE | OMAP_USBTLL_SYSCONFIG_CACTIVITY); /* Put UHH in NoIdle/NoStandby mode */ reg = ehci_omap_readl(omap->uhh_base, OMAP_UHH_SYSCONFIG); if (is_omap_ehci_rev1(omap)) { reg |= (OMAP_UHH_SYSCONFIG_ENAWAKEUP | OMAP_UHH_SYSCONFIG_SIDLEMODE | OMAP_UHH_SYSCONFIG_CACTIVITY | OMAP_UHH_SYSCONFIG_MIDLEMODE); reg &= ~OMAP_UHH_SYSCONFIG_AUTOIDLE; } else if (is_omap_ehci_rev2(omap)) { reg &= ~OMAP4_UHH_SYSCONFIG_IDLEMODE_CLEAR; reg |= OMAP4_UHH_SYSCONFIG_NOIDLE; reg &= ~OMAP4_UHH_SYSCONFIG_STDBYMODE_CLEAR; reg |= OMAP4_UHH_SYSCONFIG_NOSTDBY; } ehci_omap_writel(omap->uhh_base, OMAP_UHH_SYSCONFIG, reg); reg = ehci_omap_readl(omap->uhh_base, OMAP_UHH_HOSTCONFIG); /* setup ULPI bypass and burst configurations */ reg |= (OMAP_UHH_HOSTCONFIG_INCR4_BURST_EN | OMAP_UHH_HOSTCONFIG_INCR8_BURST_EN | OMAP_UHH_HOSTCONFIG_INCR16_BURST_EN); reg &= ~OMAP_UHH_HOSTCONFIG_INCRX_ALIGN_EN; if (is_omap_ehci_rev1(omap)) { if (omap->port_mode[0] == EHCI_HCD_OMAP_MODE_UNKNOWN) reg &= ~OMAP_UHH_HOSTCONFIG_P1_CONNECT_STATUS; if (omap->port_mode[1] == EHCI_HCD_OMAP_MODE_UNKNOWN) reg &= ~OMAP_UHH_HOSTCONFIG_P2_CONNECT_STATUS; if (omap->port_mode[2] == EHCI_HCD_OMAP_MODE_UNKNOWN) reg &= ~OMAP_UHH_HOSTCONFIG_P3_CONNECT_STATUS; /* Bypass the TLL module for PHY mode operation */ if (cpu_is_omap3430() && (omap_rev() <= OMAP3430_REV_ES2_1)) { dev_dbg(omap->dev, "OMAP3 ES version <= ES2.1\n"); if (is_ehci_phy_mode(omap->port_mode[0]) || is_ehci_phy_mode(omap->port_mode[1]) || is_ehci_phy_mode(omap->port_mode[2])) reg &= ~OMAP_UHH_HOSTCONFIG_ULPI_BYPASS; else reg |= OMAP_UHH_HOSTCONFIG_ULPI_BYPASS; } else { dev_dbg(omap->dev, "OMAP3 ES version > ES2.1\n"); if (is_ehci_phy_mode(omap->port_mode[0])) reg &= ~OMAP_UHH_HOSTCONFIG_ULPI_P1_BYPASS; else if (is_ehci_tll_mode(omap->port_mode[0])) reg |= OMAP_UHH_HOSTCONFIG_ULPI_P1_BYPASS; if (is_ehci_phy_mode(omap->port_mode[1])) reg &= ~OMAP_UHH_HOSTCONFIG_ULPI_P2_BYPASS; else if (is_ehci_tll_mode(omap->port_mode[1])) reg |= OMAP_UHH_HOSTCONFIG_ULPI_P2_BYPASS; if (is_ehci_phy_mode(omap->port_mode[2])) reg &= ~OMAP_UHH_HOSTCONFIG_ULPI_P3_BYPASS; else if (is_ehci_tll_mode(omap->port_mode[2])) reg |= OMAP_UHH_HOSTCONFIG_ULPI_P3_BYPASS; } } else if (is_omap_ehci_rev2(omap)) { /* Clear port mode fields for PHY mode*/ reg &= ~OMAP4_P1_MODE_CLEAR; reg &= ~OMAP4_P2_MODE_CLEAR; if (is_ehci_tll_mode(omap->port_mode[0])) reg |= OMAP4_P1_MODE_TLL; else if (is_ehci_hsic_mode(omap->port_mode[0])) reg |= OMAP4_P1_MODE_HSIC; if (is_ehci_tll_mode(omap->port_mode[1])) reg |= OMAP4_P2_MODE_TLL; else if (is_ehci_hsic_mode(omap->port_mode[1])) reg |= OMAP4_P2_MODE_HSIC; } ehci_omap_writel(omap->uhh_base, OMAP_UHH_HOSTCONFIG, reg); dev_dbg(omap->dev, "UHH setup done, uhh_hostconfig=%x\n", reg); /* * An undocumented "feature" in the OMAP3 EHCI controller, * causes suspended ports to be taken out of suspend when * the USBCMD.Run/Stop bit is cleared (for example when * we do ehci_bus_suspend). * This breaks suspend-resume if the root-hub is allowed * to suspend. Writing 1 to this undocumented register bit * disables this feature and restores normal behavior. */ ehci_omap_writel(omap->ehci_base, EHCI_INSNREG04, EHCI_INSNREG04_DISABLE_UNSUSPEND); if ((omap->port_mode[0] == EHCI_HCD_OMAP_MODE_TLL) || (omap->port_mode[1] == EHCI_HCD_OMAP_MODE_TLL) || (omap->port_mode[2] == EHCI_HCD_OMAP_MODE_TLL)) { if (omap->port_mode[0] == EHCI_HCD_OMAP_MODE_TLL) tll_ch_mask |= OMAP_TLL_CHANNEL_1_EN_MASK; if (omap->port_mode[1] == EHCI_HCD_OMAP_MODE_TLL) tll_ch_mask |= OMAP_TLL_CHANNEL_2_EN_MASK; if (omap->port_mode[2] == EHCI_HCD_OMAP_MODE_TLL) tll_ch_mask |= OMAP_TLL_CHANNEL_3_EN_MASK; /* Enable UTMI mode for required TLL channels */ omap_usb_utmi_init(omap, tll_ch_mask, OMAP_TLL_CHANNEL_COUNT); } if (omap->phy_reset) { /* Refer ISSUE1: * Hold the PHY in RESET for enough time till * PHY is settled and ready */ udelay(10); if (gpio_is_valid(omap->reset_gpio_port[0])) gpio_set_value(omap->reset_gpio_port[0], 1); if (gpio_is_valid(omap->reset_gpio_port[1])) gpio_set_value(omap->reset_gpio_port[1], 1); } /* Soft reset the PHY using PHY reset command over ULPI */ if (omap->port_mode[0] == EHCI_HCD_OMAP_MODE_PHY) omap_ehci_soft_phy_reset(omap, 0); if (omap->port_mode[1] == EHCI_HCD_OMAP_MODE_PHY) omap_ehci_soft_phy_reset(omap, 1); return 0; err_sys_status: clk_disable(omap->utmi_p2_fck); clk_put(omap->utmi_p2_fck); clk_disable(omap->xclk60mhsp2_ck); clk_put(omap->xclk60mhsp2_ck); clk_disable(omap->utmi_p1_fck); clk_put(omap->utmi_p1_fck); clk_disable(omap->xclk60mhsp1_ck); clk_put(omap->xclk60mhsp1_ck); clk_disable(omap->usbtll_ick); clk_put(omap->usbtll_ick); err_tll_ick: clk_disable(omap->usbtll_fck); clk_put(omap->usbtll_fck); err_tll_fck: clk_disable(omap->usbhost_fs_fck); clk_put(omap->usbhost_fs_fck); if (omap->phy_reset) { if (gpio_is_valid(omap->reset_gpio_port[0])) gpio_free(omap->reset_gpio_port[0]); if (gpio_is_valid(omap->reset_gpio_port[1])) gpio_free(omap->reset_gpio_port[1]); } err_host_48m_fck: clk_disable(omap->usbhost_hs_fck); clk_put(omap->usbhost_hs_fck); err_host_120m_fck: clk_disable(omap->usbhost_ick); clk_put(omap->usbhost_ick); err_host_ick: return ret; }
static int omap_init_uhh_registers(struct ehci_hcd_omap *omap, struct usb_hcd *hcd) { unsigned long timeout = jiffies + msecs_to_jiffies(1000); u8 tll_ch_mask = 0; unsigned reg = 0; /* perform TLL soft reset, and wait until reset is complete */ ehci_omap_writel(omap->tll_base, OMAP_USBTLL_SYSCONFIG, OMAP_USBTLL_SYSCONFIG_SOFTRESET); /* Wait for TLL reset to complete */ while (!(ehci_omap_readl(omap->tll_base, OMAP_USBTLL_SYSSTATUS) & OMAP_USBTLL_SYSSTATUS_RESETDONE)) { cpu_relax(); if (time_after(jiffies, timeout)) { dev_dbg(omap->dev, "operation timed out\n"); return -EINVAL; } } dev_dbg(omap->dev, "TLL RESET DONE\n"); /* Enable smart-idle, wakeup */ reg = OMAP_USBTLL_SYSCONFIG_CACTIVITY | OMAP_USBTLL_SYSCONFIG_AUTOIDLE | OMAP_USBTLL_SYSCONFIG_ENAWAKEUP | OMAP_USBTLL_SYSCONFIG_SMARTIDLE; ehci_omap_writel(omap->tll_base, OMAP_USBTLL_SYSCONFIG, reg); /* Put UHH in NoIdle/NoStandby mode */ reg = ehci_omap_readl(omap->uhh_base, OMAP_UHH_SYSCONFIG); reg |= OMAP_UHH_SYSCONFIG_CACTIVITY | OMAP_UHH_SYSCONFIG_AUTOIDLE | OMAP_UHH_SYSCONFIG_ENAWAKEUP; reg &= ~(OMAP_UHH_SYSCONFIG_SIDLEMASK | OMAP_UHH_SYSCONFIG_MIDLEMASK); reg |= OMAP_UHH_SYSCONFIG_NOIDLE | OMAP_UHH_SYSCONFIG_NOSTDBY; ehci_omap_writel(omap->uhh_base, OMAP_UHH_SYSCONFIG, reg); reg = ehci_omap_readl(omap->uhh_base, OMAP_UHH_HOSTCONFIG); /* setup ULPI bypass and burst configurations */ reg |= (OMAP_UHH_HOSTCONFIG_INCR4_BURST_EN | OMAP_UHH_HOSTCONFIG_INCR8_BURST_EN | OMAP_UHH_HOSTCONFIG_INCR16_BURST_EN); reg &= ~OMAP_UHH_HOSTCONFIG_INCRX_ALIGN_EN; if (omap->port_mode[0] == EHCI_HCD_OMAP_MODE_UNKNOWN) reg &= ~OMAP_UHH_HOSTCONFIG_P1_CONNECT_STATUS; if (omap->port_mode[1] == EHCI_HCD_OMAP_MODE_UNKNOWN) reg &= ~OMAP_UHH_HOSTCONFIG_P2_CONNECT_STATUS; if (omap->port_mode[2] == EHCI_HCD_OMAP_MODE_UNKNOWN) reg &= ~OMAP_UHH_HOSTCONFIG_P3_CONNECT_STATUS; /* Bypass the TLL module for PHY mode operation */ if (!cpu_is_omap3517() && !cpu_is_omap3505() && (omap_rev() <= OMAP3430_REV_ES2_1)) { dev_dbg(omap->dev, "OMAP3 ES version <= ES2.1 \n"); if ((omap->port_mode[0] == EHCI_HCD_OMAP_MODE_PHY) || (omap->port_mode[1] == EHCI_HCD_OMAP_MODE_PHY) || (omap->port_mode[2] == EHCI_HCD_OMAP_MODE_PHY)) reg &= ~OMAP_UHH_HOSTCONFIG_ULPI_BYPASS; else reg |= OMAP_UHH_HOSTCONFIG_ULPI_BYPASS; } else { dev_dbg(omap->dev, "OMAP3 ES version > ES2.1\n"); if (omap->port_mode[0] == EHCI_HCD_OMAP_MODE_PHY) reg &= ~OMAP_UHH_HOSTCONFIG_ULPI_P1_BYPASS; else if (omap->port_mode[0] == EHCI_HCD_OMAP_MODE_TLL) reg |= OMAP_UHH_HOSTCONFIG_ULPI_P1_BYPASS; if (omap->port_mode[1] == EHCI_HCD_OMAP_MODE_PHY) reg &= ~OMAP_UHH_HOSTCONFIG_ULPI_P2_BYPASS; else if (omap->port_mode[1] == EHCI_HCD_OMAP_MODE_TLL) reg |= OMAP_UHH_HOSTCONFIG_ULPI_P2_BYPASS; if (omap->port_mode[2] == EHCI_HCD_OMAP_MODE_PHY) reg &= ~OMAP_UHH_HOSTCONFIG_ULPI_P3_BYPASS; else if (omap->port_mode[2] == EHCI_HCD_OMAP_MODE_TLL) reg |= OMAP_UHH_HOSTCONFIG_ULPI_P3_BYPASS; } ehci_omap_writel(omap->uhh_base, OMAP_UHH_HOSTCONFIG, reg); dev_dbg(omap->dev, "UHH setup done, uhh_hostconfig=%x\n", reg); /* * An undocumented "feature" in the OMAP3 EHCI controller, * causes suspended ports to be taken out of suspend when * the USBCMD.Run/Stop bit is cleared (for example when * we do ehci_bus_suspend). * This breaks suspend-resume if the root-hub is allowed * to suspend. Writing 1 to this undocumented register bit * disables this feature and restores normal behavior. */ ehci_omap_writel(omap->ehci_base, EHCI_INSNREG04, EHCI_INSNREG04_DISABLE_UNSUSPEND); if ((omap->port_mode[0] == EHCI_HCD_OMAP_MODE_TLL) || (omap->port_mode[1] == EHCI_HCD_OMAP_MODE_TLL) || (omap->port_mode[2] == EHCI_HCD_OMAP_MODE_TLL)) { if (omap->port_mode[0] == EHCI_HCD_OMAP_MODE_TLL) tll_ch_mask |= OMAP_TLL_CHANNEL_1_EN_MASK; if (omap->port_mode[1] == EHCI_HCD_OMAP_MODE_TLL) tll_ch_mask |= OMAP_TLL_CHANNEL_2_EN_MASK; if (omap->port_mode[2] == EHCI_HCD_OMAP_MODE_TLL) tll_ch_mask |= OMAP_TLL_CHANNEL_3_EN_MASK; /* Enable UTMI mode for required TLL channels */ omap_usb_utmi_init(omap, tll_ch_mask); } if (omap->phy_reset) { /* Refer ISSUE1: * Hold the PHY in RESET for enough time till * PHY is settled and ready */ udelay(10); if (gpio_is_valid(omap->reset_gpio_port[0])) gpio_set_value(omap->reset_gpio_port[0], 1); if (gpio_is_valid(omap->reset_gpio_port[1])) gpio_set_value(omap->reset_gpio_port[1], 1); } return 0; }
/* omap_start_ehc * - Start the TI USBHOST controller */ static int omap_start_ehc(struct ehci_hcd_omap *omap, struct usb_hcd *hcd) { unsigned long timeout = jiffies + msecs_to_jiffies(1000); u8 tll_ch_mask = 0; unsigned reg = 0; int ret = 0; printk("omap_start_ehc kernel 2.6.35 V0.5 [07/12/2011] \n"); gpio_direction_output(23, 0); PHY_reset = 0; #ifndef CONFIG_MODEM_SMS gpio_direction_output(4, 1); gpio_direction_output(35, 1); gpio_direction_output(36, 1); modem_PW = 1; #endif dev_dbg(omap->dev, "starting TI EHCI USB Controller\n"); /* Get all the clock handles we need */ omap->usbhost_ick = clk_get(omap->dev, "usbhost_ick"); if (IS_ERR(omap->usbhost_ick)) { dev_err(omap->dev, "could not get usbhost_ick\n"); ret = PTR_ERR(omap->usbhost_ick); goto err_host_ick; } omap->usbhost2_120m_fck = clk_get(omap->dev, "usbhost_120m_fck"); if (IS_ERR(omap->usbhost2_120m_fck)) { dev_err(omap->dev, "could not get usbhost2_120m_fck\n"); ret = PTR_ERR(omap->usbhost2_120m_fck); goto err_host_120m_fck; } omap->usbhost1_48m_fck = clk_get(omap->dev, "usbhost_48m_fck"); if (IS_ERR(omap->usbhost1_48m_fck)) { dev_err(omap->dev, "could not get usbhost_48m_fck\n"); ret = PTR_ERR(omap->usbhost1_48m_fck); goto err_host_48m_fck; } if (omap->phy_reset) { printk(KERN_DEBUG "reset the phys\n"); /* Refer: ISSUE1 */ if (gpio_is_valid(omap->reset_gpio_port[0])) { gpio_request(omap->reset_gpio_port[0], "USB1 PHY reset"); gpio_direction_output(omap->reset_gpio_port[0], 0); } if (gpio_is_valid(omap->reset_gpio_port[1])) { gpio_request(omap->reset_gpio_port[1],"USB2 PHY reset"); gpio_direction_output(omap->reset_gpio_port[1], 0); } /* Hold the PHY in RESET for enough time till DIR is high */ udelay(10); } omap->usbtll_fck = clk_get(omap->dev, "usbtll_fck"); if (IS_ERR(omap->usbtll_fck)) { dev_err(omap->dev, "could not get usbtll_fck\n"); ret = PTR_ERR(omap->usbtll_fck); goto err_tll_fck; } omap->usbtll_ick = clk_get(omap->dev, "usbtll_ick"); if (IS_ERR(omap->usbtll_ick)) { dev_err(omap->dev, "could not get usbtll_ick\n"); ret = PTR_ERR(omap->usbtll_ick); goto err_tll_ick; } /* Now enable all the clocks in the correct order */ ehci_omap_clock_power(omap, 1); /* Put UHH in NoIdle/NoStandby mode */ reg = ehci_omap_readl(omap->uhh_base, OMAP_UHH_SYSCONFIG); reg |= OMAP_UHH_SYSCONFIG_CACTIVITY | OMAP_UHH_SYSCONFIG_AUTOIDLE | OMAP_UHH_SYSCONFIG_ENAWAKEUP; reg &= ~(OMAP_UHH_SYSCONFIG_SIDLEMASK | OMAP_UHH_SYSCONFIG_MIDLEMASK); reg |= OMAP_UHH_SYSCONFIG_NOIDLE | OMAP_UHH_SYSCONFIG_NOSTDBY; ehci_omap_writel(omap->uhh_base, OMAP_UHH_SYSCONFIG, reg); reg = ehci_omap_readl(omap->uhh_base, OMAP_UHH_HOSTCONFIG); /* setup ULPI bypass and burst configurations */ reg |= (OMAP_UHH_HOSTCONFIG_INCR4_BURST_EN | OMAP_UHH_HOSTCONFIG_INCR8_BURST_EN | OMAP_UHH_HOSTCONFIG_INCR16_BURST_EN); reg &= ~OMAP_UHH_HOSTCONFIG_INCRX_ALIGN_EN; if (omap->port_mode[0] == EHCI_HCD_OMAP_MODE_UNKNOWN) reg &= ~OMAP_UHH_HOSTCONFIG_P1_CONNECT_STATUS; if (omap->port_mode[1] == EHCI_HCD_OMAP_MODE_UNKNOWN) reg &= ~OMAP_UHH_HOSTCONFIG_P2_CONNECT_STATUS; if (omap->port_mode[2] == EHCI_HCD_OMAP_MODE_UNKNOWN) reg &= ~OMAP_UHH_HOSTCONFIG_P3_CONNECT_STATUS; /* Bypass the TLL module for PHY mode operation */ if (cpu_is_omap3430() && (omap_rev() <= OMAP3430_REV_ES2_1)) { dev_dbg(omap->dev, "OMAP3 ES version <= ES2.1\n"); if ((omap->port_mode[0] == EHCI_HCD_OMAP_MODE_PHY) || (omap->port_mode[1] == EHCI_HCD_OMAP_MODE_PHY) || (omap->port_mode[2] == EHCI_HCD_OMAP_MODE_PHY)) reg &= ~OMAP_UHH_HOSTCONFIG_ULPI_BYPASS; else reg |= OMAP_UHH_HOSTCONFIG_ULPI_BYPASS; } else { dev_dbg(omap->dev, "OMAP3 ES version > ES2.1\n"); if (omap->port_mode[0] == EHCI_HCD_OMAP_MODE_PHY) reg &= ~OMAP_UHH_HOSTCONFIG_ULPI_P1_BYPASS; else if (omap->port_mode[0] == EHCI_HCD_OMAP_MODE_TLL) reg |= OMAP_UHH_HOSTCONFIG_ULPI_P1_BYPASS; if (omap->port_mode[1] == EHCI_HCD_OMAP_MODE_PHY) reg &= ~OMAP_UHH_HOSTCONFIG_ULPI_P2_BYPASS; else if (omap->port_mode[1] == EHCI_HCD_OMAP_MODE_TLL) reg |= OMAP_UHH_HOSTCONFIG_ULPI_P2_BYPASS; if (omap->port_mode[2] == EHCI_HCD_OMAP_MODE_PHY) reg &= ~OMAP_UHH_HOSTCONFIG_ULPI_P3_BYPASS; else if (omap->port_mode[2] == EHCI_HCD_OMAP_MODE_TLL) reg |= OMAP_UHH_HOSTCONFIG_ULPI_P3_BYPASS; } ehci_omap_writel(omap->uhh_base, OMAP_UHH_HOSTCONFIG, reg); dev_dbg(omap->dev, "UHH setup done, uhh_hostconfig=%x\n", reg); /* * An undocumented "feature" in the OMAP3 EHCI controller, * causes suspended ports to be taken out of suspend when * the USBCMD.Run/Stop bit is cleared (for example when * we do ehci_bus_suspend). * This breaks suspend-resume if the root-hub is allowed * to suspend. Writing 1 to this undocumented register bit * disables this feature and restores normal behavior. */ ehci_omap_writel(omap->ehci_base, EHCI_INSNREG04, EHCI_INSNREG04_DISABLE_UNSUSPEND); if (omap->phy_reset) { printk(KERN_DEBUG "unreset the phys\n"); /* Refer ISSUE1: * Hold the PHY in RESET for enough time till * PHY is settled and ready */ udelay(10); if (gpio_is_valid(omap->reset_gpio_port[0])) gpio_set_value(omap->reset_gpio_port[0], 1); if (gpio_is_valid(omap->reset_gpio_port[1])) gpio_set_value(omap->reset_gpio_port[1], 1); } //gpio_direction_output(21, 1); //gpio_direction_output(36, 1); //gpio_direction_output(35, 1); //msleep(10); printk("RESET USB PHY\n"); gpio_direction_output(23, 1); PHY_reset = 1; return 0; err_sys_status: ehci_omap_clock_power(omap, 0); clk_put(omap->usbtll_ick); err_tll_ick: clk_put(omap->usbtll_fck); err_tll_fck: clk_put(omap->usbhost1_48m_fck); if (omap->phy_reset) { if (gpio_is_valid(omap->reset_gpio_port[0])) gpio_free(omap->reset_gpio_port[0]); if (gpio_is_valid(omap->reset_gpio_port[1])) gpio_free(omap->reset_gpio_port[1]); } err_host_48m_fck: clk_put(omap->usbhost2_120m_fck); err_host_120m_fck: clk_put(omap->usbhost_ick); err_host_ick: return ret; }
/* omap_start_ehc * - Start the TI USBHOST controller */ static int omap_start_ehc(struct ehci_hcd_omap *omap, struct usb_hcd *hcd) { unsigned long timeout = jiffies + msecs_to_jiffies(1000); unsigned reg = 0; int ret = 0; int reset_delay; int i; dev_dbg(&omap->dev->dev, "starting TI EHCI USB Controller\n"); /* Enable Clocks for USBHOST */ omap->usbhost_ick = clk_get(&omap->dev->dev, "usbhost_ick"); if (IS_ERR(omap->usbhost_ick)) { ret = PTR_ERR(omap->usbhost_ick); goto err_host_ick; } clk_enable(omap->usbhost_ick); omap->usbhost2_120m_fck = clk_get(&omap->dev->dev, "usbhost_120m_fck"); if (IS_ERR(omap->usbhost2_120m_fck)) { ret = PTR_ERR(omap->usbhost2_120m_fck); goto err_host_120m_fck; } clk_enable(omap->usbhost2_120m_fck); omap->usbhost1_48m_fck = clk_get(&omap->dev->dev, "usbhost_48m_fck"); if (IS_ERR(omap->usbhost1_48m_fck)) { ret = PTR_ERR(omap->usbhost1_48m_fck); goto err_host_48m_fck; } clk_enable(omap->usbhost1_48m_fck); reset_delay = 0; for (i = 0; i < OMAP_TLL_CHANNEL_COUNT; i++) { reset_delay = reset_delay > omap->port_data[i].reset_delay ? reset_delay : omap->port_data[i].reset_delay; if (omap->port_data[i].startup) { ret = omap->port_data[i].startup(omap->dev, i); if (ret < 0) return ret; } if (omap->port_data[i].reset) omap->port_data[i].reset(omap->dev, i, 0); } if (reset_delay) udelay(reset_delay); /* Configure TLL for 60Mhz clk for ULPI */ omap->usbtll_fck = clk_get(&omap->dev->dev, "usbtll_fck"); if (IS_ERR(omap->usbtll_fck)) { ret = PTR_ERR(omap->usbtll_fck); goto err_tll_fck; } clk_enable(omap->usbtll_fck); omap->usbtll_ick = clk_get(&omap->dev->dev, "usbtll_ick"); if (IS_ERR(omap->usbtll_ick)) { ret = PTR_ERR(omap->usbtll_ick); goto err_tll_ick; } clk_enable(omap->usbtll_ick); set_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags); #ifndef CONFIG_MAPPHONE_2NDBOOT /* perform TLL soft reset, and wait until reset is complete */ ehci_omap_writel(omap->tll_base, OMAP_USBTLL_SYSCONFIG, OMAP_USBTLL_SYSCONFIG_SOFTRESET); /* Wait for TLL reset to complete */ while (!(ehci_omap_readl(omap->tll_base, OMAP_USBTLL_SYSSTATUS) & OMAP_USBTLL_SYSSTATUS_RESETDONE)) { cpu_relax(); if (time_after(jiffies, timeout)) { dev_dbg(&omap->dev->dev, "operation timed out\n"); ret = -EINVAL; goto err_sys_status; } } #endif dev_dbg(&omap->dev->dev, "TLL RESET DONE\n"); /* SmartIdle mode */ ehci_omap_writel(omap->tll_base, OMAP_USBTLL_SYSCONFIG, OMAP_USBTLL_SYSCONFIG_ENAWAKEUP | OMAP_USBTLL_SYSCONFIG_SIDLEMODE | OMAP_USBTLL_SYSCONFIG_AUTOIDLE); /* Put UHH in NoIdle/NoStandby mode */ ehci_omap_writel(omap->uhh_base, OMAP_UHH_SYSCONFIG, OMAP_UHH_SYSCONFIG_ENAWAKEUP | OMAP_UHH_SYSCONFIG_NOIDLEMODE | OMAP_UHH_SYSCONFIG_NOSTBYMODE | OMAP_UHH_SYSCONFIG_AUTOIDLE); #ifdef CONFIG_MACH_MAPPHONE /* We need to suspend OHCI in order for the usbhost * domain to go standby. * OHCI would never be resumed for UMTS modem */ if (!is_cdma_phone()) omap_writel(OHCI_HC_CTRL_SUSPEND, OHCI_HC_CONTROL); #endif reg = ehci_omap_readl(omap->uhh_base, OMAP_UHH_HOSTCONFIG); /* setup ULPI bypass and burst configurations */ reg |= (OMAP_UHH_HOSTCONFIG_INCR4_BURST_EN | OMAP_UHH_HOSTCONFIG_INCR8_BURST_EN | OMAP_UHH_HOSTCONFIG_INCR16_BURST_EN); reg &= ~OMAP_UHH_HOSTCONFIG_INCRX_ALIGN_EN; if (!(omap->port_data[0].flags & EHCI_HCD_OMAP_FLAG_ENABLED)) reg &= ~OMAP_UHH_HOSTCONFIG_P1_CONNECT_STATUS; if (!(omap->port_data[1].flags & EHCI_HCD_OMAP_FLAG_ENABLED)) reg &= ~OMAP_UHH_HOSTCONFIG_P2_CONNECT_STATUS; if (!(omap->port_data[2].flags & EHCI_HCD_OMAP_FLAG_ENABLED)) reg &= ~OMAP_UHH_HOSTCONFIG_P3_CONNECT_STATUS; /* Bypass the TLL module for PHY mode operation */ if (omap_rev() <= OMAP3430_REV_ES2_1) { dev_dbg(&omap->dev->dev, "OMAP3 ES version <= ES2.1 \n"); if (omap_usb_port_ulpi_bypass(omap->port_data[0].mode)) reg |= OMAP_UHH_HOSTCONFIG_ULPI_BYPASS; else reg &= ~OMAP_UHH_HOSTCONFIG_ULPI_BYPASS; } else { dev_dbg(&omap->dev->dev, "OMAP3 ES version > ES2.1\n"); if (omap_usb_port_ulpi_bypass(omap->port_data[0].mode)) reg |= OMAP_UHH_HOSTCONFIG_ULPI_P1_BYPASS; else reg &= ~OMAP_UHH_HOSTCONFIG_ULPI_P1_BYPASS; if (omap_usb_port_ulpi_bypass(omap->port_data[1].mode)) reg |= OMAP_UHH_HOSTCONFIG_ULPI_P2_BYPASS; else reg &= ~OMAP_UHH_HOSTCONFIG_ULPI_P2_BYPASS; if (omap_usb_port_ulpi_bypass(omap->port_data[2].mode)) reg |= OMAP_UHH_HOSTCONFIG_ULPI_P3_BYPASS; else reg &= ~OMAP_UHH_HOSTCONFIG_ULPI_P3_BYPASS; } ehci_omap_writel(omap->uhh_base, OMAP_UHH_HOSTCONFIG, reg); dev_dbg(&omap->dev->dev, "UHH setup done, uhh_hostconfig=%x\n", reg); /* Enable UTMI mode for required TLL channels */ omap_usb_utmi_init(omap); reset_delay = 0; for (i = 0; i < OMAP3_HS_USB_PORTS; i++) { reset_delay = reset_delay > omap->port_data[i].reset_delay ? reset_delay : omap->port_data[i].reset_delay; } if (reset_delay) udelay(reset_delay); for (i = 0; i < OMAP3_HS_USB_PORTS; i++) { if (omap->port_data[i].reset) omap->port_data[i].reset(omap->dev, i, 1); } #if defined(CONFIG_MACH_MAPPHONE) /* Refer ISSUE2: LINK assumes external charge pump */ /* use Port1 VBUS to charge externally Port2: * So for PHY mode operation use Port2 only */ ehci_omap_writel(omap->ehci_base, EHCI_INSNREG05_ULPI, (0xA << EHCI_INSNREG05_ULPI_REGADD_SHIFT) |/* OTG ctrl reg*/ (2 << EHCI_INSNREG05_ULPI_OPSEL_SHIFT) |/* Write */ (2 << EHCI_INSNREG05_ULPI_PORTSEL_SHIFT) |/* Port1 */ (1 << EHCI_INSNREG05_ULPI_CONTROL_SHIFT) |/* Start */ (0x26)); while (!(ehci_omap_readl(omap->ehci_base, EHCI_INSNREG05_ULPI) & (1<<EHCI_INSNREG05_ULPI_CONTROL_SHIFT))) { cpu_relax(); } #endif return 0; err_sys_status: clk_disable(omap->usbtll_ick); clk_put(omap->usbtll_ick); err_tll_ick: clk_disable(omap->usbtll_fck); clk_put(omap->usbtll_fck); err_tll_fck: clk_disable(omap->usbhost1_48m_fck); clk_put(omap->usbhost1_48m_fck); err_host_48m_fck: clk_disable(omap->usbhost2_120m_fck); clk_put(omap->usbhost2_120m_fck); err_host_120m_fck: clk_disable(omap->usbhost_ick); clk_put(omap->usbhost_ick); err_host_ick: return ret; }
/*------------------------------------------------------------------------- * Setup Usb High Speed Host mode. * */ static int set_uhh_mode(struct ehci_hcd_omap *omap) { unsigned reg = 0; if (cpu_is_omap44xx()) { /* Put UHH in NoIdle/NoStandby mode */ reg = ehci_omap_readl(omap->uhh_base, OMAP_UHH_SYSCONFIG); reg &= OMAP_UHH_SYSCONFIG_IDLEMODE_RESET; reg |= OMAP_UHH_SYSCONFIG_NIDLEMODE_SET; reg &= OMAP_UHH_SYSCONFIG_STDYMODE_RESET; reg |= OMAP_UHH_SYSCONFIG_NSTDYMODE_SET; ehci_omap_writel(omap->uhh_base, OMAP_UHH_SYSCONFIG, reg); /* setup ULPI bypass and burst configurations */ reg = ehci_omap_readl(omap->uhh_base, OMAP_UHH_HOSTCONFIG); reg |= (OMAP_UHH_HOSTCONFIG_INCR4_BURST_EN | OMAP_UHH_HOSTCONFIG_INCR8_BURST_EN | OMAP_UHH_HOSTCONFIG_INCR16_BURST_EN); reg &= ~OMAP_UHH_HOSTCONFIG_INCRX_ALIGN_EN; /* set p1 & p2 modes */ reg &= OMAP_UHH_HOST_PORTS_RESET; if (omap->port_mode[0] == EHCI_HCD_OMAP_MODE_PHY) reg |= OMAP_UHH_HOST_P1_SET_ULPIPHY; else if (omap->port_mode[0] == EHCI_HCD_OMAP_MODE_TLL) reg |= OMAP_UHH_HOST_P1_SET_ULPITLL; if (omap->port_mode[1] == EHCI_HCD_OMAP_MODE_PHY) reg |= OMAP_UHH_HOST_P2_SET_ULPIPHY; else if (omap->port_mode[1] == EHCI_HCD_OMAP_MODE_TLL) reg |= OMAP_UHH_HOST_P2_SET_ULPITLL; ehci_omap_writel(omap->uhh_base, OMAP_UHH_HOSTCONFIG, reg); } else { /* Put UHH in NoIdle/NoStandby mode */ reg = ehci_omap_readl(omap->uhh_base, OMAP_UHH_SYSCONFIG); reg |= OMAP_UHH_SYSCONFIG_ENAWAKEUP; reg |= OMAP_UHH_SYSCONFIG_SIDLEMODE; reg |= OMAP_UHH_SYSCONFIG_CACTIVITY; reg |= OMAP_UHH_SYSCONFIG_MIDLEMODE ; reg &= ~OMAP_UHH_SYSCONFIG_AUTOIDLE; ehci_omap_writel(omap->uhh_base, OMAP_UHH_SYSCONFIG, reg); /* setup ULPI bypass and burst configurations */ reg = ehci_omap_readl(omap->uhh_base, OMAP_UHH_HOSTCONFIG); reg |= OMAP_UHH_HOSTCONFIG_INCR4_BURST_EN; reg |= OMAP_UHH_HOSTCONFIG_INCR8_BURST_EN; reg |= OMAP_UHH_HOSTCONFIG_INCR16_BURST_EN; reg &= ~OMAP_UHH_HOSTCONFIG_INCRX_ALIGN_EN; if (omap->port_mode[0] == EHCI_HCD_OMAP_MODE_UNKNOWN) reg &= ~OMAP_UHH_HOSTCONFIG_P1_CONNECT_STATUS; if (omap->port_mode[1] == EHCI_HCD_OMAP_MODE_UNKNOWN) reg &= ~OMAP_UHH_HOSTCONFIG_P2_CONNECT_STATUS; if (omap->port_mode[2] == EHCI_HCD_OMAP_MODE_UNKNOWN) reg &= ~OMAP_UHH_HOSTCONFIG_P3_CONNECT_STATUS; if (cpu_is_omap3430() && (omap_rev() <= OMAP3430_REV_ES2_1)) { dev_dbg(omap->dev, "OMAP3 ES version <= ES2.1\n"); if ((omap->port_mode[0] == EHCI_HCD_OMAP_MODE_PHY)|| (omap->port_mode[1] == EHCI_HCD_OMAP_MODE_PHY)|| (omap->port_mode[2] == EHCI_HCD_OMAP_MODE_PHY)) reg &= ~OMAP_UHH_HOSTCONFIG_ULPI_BYPASS; else reg |= OMAP_UHH_HOSTCONFIG_ULPI_BYPASS; } else { dev_dbg(omap->dev, "OMAP3 ES version > ES2.1\n"); if (omap->port_mode[0] == EHCI_HCD_OMAP_MODE_PHY) reg &= ~OMAP_UHH_HOSTCONFIG_ULPI_P1_BYPASS; else if (omap->port_mode[0] == EHCI_HCD_OMAP_MODE_TLL) reg |= OMAP_UHH_HOSTCONFIG_ULPI_P1_BYPASS; if (omap->port_mode[1] == EHCI_HCD_OMAP_MODE_PHY) reg &= ~OMAP_UHH_HOSTCONFIG_ULPI_P2_BYPASS; else if (omap->port_mode[1] == EHCI_HCD_OMAP_MODE_TLL) reg |= OMAP_UHH_HOSTCONFIG_ULPI_P2_BYPASS; if (omap->port_mode[2] == EHCI_HCD_OMAP_MODE_PHY) reg &= ~OMAP_UHH_HOSTCONFIG_ULPI_P3_BYPASS; else if (omap->port_mode[2] == EHCI_HCD_OMAP_MODE_TLL) reg |= OMAP_UHH_HOSTCONFIG_ULPI_P3_BYPASS; } ehci_omap_writel(omap->uhh_base, OMAP_UHH_HOSTCONFIG, reg); /* * An undocumented "feature" in the OMAP3 EHCI controller, * causes suspended ports to be taken out of suspend when * the USBCMD.Run/Stop bit is cleared (for example when * we do ehci_bus_suspend). * This breaks suspend-resume if the root-hub is allowed * to suspend. Writing 1 to this undocumented register bit * disables this feature and restores normal behavior. */ ehci_omap_writel(omap->ehci_base, EHCI_INSNREG04, EHCI_INSNREG04_DISABLE_UNSUSPEND); } dev_dbg(omap->dev, "UHH setup done, uhh_hostconfig=%x\n", reg); return 0; }
static void omap_stop_ehc(struct ehci_hcd_omap *omap, struct usb_hcd *hcd) { unsigned long timeout = jiffies + msecs_to_jiffies(100); dev_dbg(omap->dev, "stopping TI EHCI USB Controller\n"); printk(KERN_DEBUG " omap_stop_ehc\n"); /* Reset OMAP modules for insmod/rmmod to work */ ehci_omap_writel(omap->uhh_base, OMAP_UHH_SYSCONFIG, OMAP_UHH_SYSCONFIG_SOFTRESET); while (!(ehci_omap_readl(omap->uhh_base, OMAP_UHH_SYSSTATUS) & (1 << 0))) { cpu_relax(); if (time_after(jiffies, timeout)) dev_dbg(omap->dev, "operation timed out\n"); } while (!(ehci_omap_readl(omap->uhh_base, OMAP_UHH_SYSSTATUS) & (1 << 1))) { cpu_relax(); if (time_after(jiffies, timeout)) dev_dbg(omap->dev, "operation timed out\n"); } while (!(ehci_omap_readl(omap->uhh_base, OMAP_UHH_SYSSTATUS) & (1 << 2))) { cpu_relax(); if (time_after(jiffies, timeout)) dev_dbg(omap->dev, "operation timed out\n"); } ehci_omap_clock_power(omap, 0); if (omap->usbtll_fck != NULL) { clk_put(omap->usbtll_fck); omap->usbtll_fck = NULL; } if (omap->usbhost_ick != NULL) { clk_put(omap->usbhost_ick); omap->usbhost_ick = NULL; } if (omap->usbhost1_48m_fck != NULL) { clk_put(omap->usbhost1_48m_fck); omap->usbhost1_48m_fck = NULL; } if (omap->usbhost2_120m_fck != NULL) { clk_put(omap->usbhost2_120m_fck); omap->usbhost2_120m_fck = NULL; } if (omap->usbtll_ick != NULL) { clk_put(omap->usbtll_ick); omap->usbtll_ick = NULL; } if (omap->phy_reset) { printk(KERN_DEBUG " free the reset the GPIOs\n"); if (gpio_is_valid(omap->reset_gpio_port[0])) gpio_free(omap->reset_gpio_port[0]); if (gpio_is_valid(omap->reset_gpio_port[1])) gpio_free(omap->reset_gpio_port[1]); } dev_dbg(omap->dev, "Clock to USB host has been disabled\n"); gpio_direction_output(23, 0); PHY_reset = 0; #ifndef CONFIG_MODEM_SMS if(!modem_resume_state || !g_sim_carddetect_status){ gpio_direction_output(4, 0); gpio_direction_output(35, 0); gpio_direction_output(36, 0); modem_PW = 0; } #endif }
static int ehci_omap_bus_suspend(struct usb_hcd *hcd) { int ret; u32 status; u32 sysconfig; unsigned long flags; struct ehci_hcd *ehci; struct ehci_hcd_omap_platform_data *pdata; struct ehci_hcd_omap *omap = dev_get_drvdata(hcd->self.controller); dev_dbg(hcd->self.controller, "%s %ld %lu\n", __func__, in_interrupt(), jiffies); ehci = hcd_to_ehci(hcd); pdata = omap->dev->dev.platform_data; /* mask interrupt 77 to avoid race condition with ehci_irq */ /* omap_writel(0x2000, 0x482000CC); */ disable_irq(hcd->irq); ret = ehci_bus_suspend(hcd); if (ret) { enable_irq(hcd->irq); return ret; } /* Put UHH in SmartStandby mode */ sysconfig = ehci_omap_readl(omap->uhh_base, OMAP_UHH_SYSCONFIG); sysconfig &= ~OMAP_UHH_SYSCONFIG_MIDLEMODE_MASK; sysconfig |= OMAP_UHH_SYSCONFIG_MIDLEMODE; ehci_omap_writel(omap->uhh_base, OMAP_UHH_SYSCONFIG, sysconfig); spin_lock_irqsave(&usb_clocks_lock, flags); if (test_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags)) { if (pdata->usbhost_standby_status) ret = pdata->usbhost_standby_status(); if (ret == 0) { printk(KERN_ERR "ehci: suspend failed!\n"); ret = -EBUSY; goto end; } else ret = 0; status = ehci_readl(ehci, &ehci->regs->status); if (status & INTR_MASK) { printk(KERN_ERR "ehci: pending irq, resume!\n"); ret = -EBUSY; goto end; } ehci_omap_writel(omap->tll_base, OMAP_TLL_SHARED_CONF, ehci_omap_readl(omap->tll_base, OMAP_TLL_SHARED_CONF) & ~(1)); /* Enable the interrupt so that the remote-wakeup * can be detected */ ehci_omap_writel(omap->tll_base, OMAP_USBTLL_IRQSTATUS, 7); ehci_omap_writel(omap->tll_base, OMAP_USBTLL_IRQENABLE, 1); /* Put UHH in ForceIdle mode */ sysconfig = ehci_omap_readl(omap->uhh_base, OMAP_UHH_SYSCONFIG); sysconfig &= ~OMAP_UHH_SYSCONFIG_SIDLEMODE_MASK; ehci_omap_writel(omap->uhh_base, OMAP_UHH_SYSCONFIG, sysconfig); if (omap->usbhost1_48m_fck) clk_disable(omap->usbhost1_48m_fck); if (omap->usbhost2_120m_fck) clk_disable(omap->usbhost2_120m_fck); if (omap->usbtll_fck) clk_disable(omap->usbtll_fck); clear_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags); LOG_USBHOST_ACTIVITY(aUsbHostDbg, iUsbHostDbg, jiffies); } spin_unlock_irqrestore(&usb_clocks_lock, flags); #ifdef CONFIG_HAS_WAKELOCK wake_unlock(&ehci->wake_lock_ehci_pm); #endif return 0; end: /* Put UHH in NoStandby mode */ sysconfig = ehci_omap_readl(omap->uhh_base, OMAP_UHH_SYSCONFIG); sysconfig &= ~OMAP_UHH_SYSCONFIG_MIDLEMODE_MASK; sysconfig |= OMAP_UHH_SYSCONFIG_NOSTBYMODE; ehci_omap_writel(omap->uhh_base, OMAP_UHH_SYSCONFIG, sysconfig); spin_unlock_irqrestore(&usb_clocks_lock, flags); ehci_bus_resume(hcd); /* unmask irq 77 */ /* omap_writel(0x2000, 0x482000C8); */ enable_irq(hcd->irq); return ret; }