Update the ohci-omap3 driver to add support for OMAP4. The OMAP4 has two ports compared to 3 on the OMAP3. Each port has its own functional clock, compared to a single clock for all ports on OMAP3. Register bit positions for mode selections (TLL or PHY) have changed. Signed-off-by: Keshava Munegowda <keshava_mgowda@xxxxxx> Signed-off-by: Anand Gadiyar <gadiyar@xxxxxx> --- drivers/usb/host/ohci-omap3.c | 213 ++++++++++++++++++++++++++++++++++++++---- 1 file changed, 194 insertions(+), 19 deletions(-) Index: linux-2.6/drivers/usb/host/ohci-omap3.c =================================================================== --- linux-2.6.orig/drivers/usb/host/ohci-omap3.c +++ linux-2.6/drivers/usb/host/ohci-omap3.c @@ -106,6 +106,31 @@ #define OMAP_UHH_DEBUG_CSR (0x44) +/* OMAP4 specific */ +#define OMAP_UHH_SYSCONFIG_IDLEMODE_RESET (~(0xC)) +#define OMAP_UHH_SYSCONFIG_FIDLEMODE_SET (0 << 2) +#define OMAP_UHH_SYSCONFIG_NIDLEMODE_SET (1 << 2) +#define OMAP_UHH_SYSCONFIG_SIDLEMODE_SET (2 << 2) +#define OMAP_UHH_SYSCONFIG_SWIDLMODE_SET (3 << 2) + +#define OMAP_UHH_SYSCONFIG_STDYMODE_RESET (~(3 << 4)) +#define OMAP_UHH_SYSCONFIG_FSTDYMODE_SET (0 << 4) +#define OMAP_UHH_SYSCONFIG_NSTDYMODE_SET (1 << 4) +#define OMAP_UHH_SYSCONFIG_SSTDYMODE_SET (2 << 4) +#define OMAP_UHH_SYSCONFIG_SWSTDMODE_SET (3 << 4) + +#define OMAP_UHH_HOST_PORTS_RESET (~(0xF << 16)) +#define OMAP_UHH_HOST_P1_SET_ULPIPHY (0 << 16) +#define OMAP_UHH_HOST_P1_SET_ULPITLL (1 << 16) +#define OMAP_UHH_HOST_P1_SET_HSIC (3 << 16) + +#define OMAP_UHH_HOST_P2_SET_ULPIPHY (0 << 18) +#define OMAP_UHH_HOST_P2_SET_ULPITLL (1 << 18) +#define OMAP_UHH_HOST_P2_SET_HSIC (3 << 18) +#define OMAP4_UHH_SYSCONFIG_SOFTRESET (1 << 0) + +#define OMAP4_TLL_CHANNEL_COUNT 2 + /*-------------------------------------------------------------------------*/ static inline void ohci_omap_writel(void __iomem *base, u32 reg, u32 val) @@ -128,8 +153,6 @@ static inline u8 ohci_omap_readb(void __ return __raw_readb(base + reg); } -/*-------------------------------------------------------------------------*/ - struct ohci_hcd_omap3 { struct ohci_hcd *ohci; struct device *dev; @@ -139,6 +162,10 @@ struct ohci_hcd_omap3 { struct clk *usbhost_fs_fck; struct clk *usbtll_fck; struct clk *usbtll_ick; + struct clk *xclk60mhsp1_ck; + struct clk *xclk60mhsp2_ck; + struct clk *utmi_p1_fck; + struct clk *utmi_p2_fck; /* port_mode: TLL/PHY, 2/3/4/6-PIN, DP-DM/DAT-SE0 */ enum ohci_omap3_port_mode port_mode[OMAP3_HS_USB_PORTS]; @@ -154,17 +181,36 @@ struct ohci_hcd_omap3 { static void ohci_omap3_clock_power(struct ohci_hcd_omap3 *omap, int on) { if (on) { - clk_enable(omap->usbtll_ick); - clk_enable(omap->usbtll_fck); - clk_enable(omap->usbhost_ick); - clk_enable(omap->usbhost_fs_fck); - clk_enable(omap->usbhost_hs_fck); + if (omap->usbtll_ick != NULL) + clk_enable(omap->usbtll_ick); + if (omap->usbtll_fck != NULL) + clk_enable(omap->usbtll_fck); + if (omap->usbhost_ick != NULL) + clk_enable(omap->usbhost_ick); + if (omap->usbhost_fs_fck != NULL) + clk_enable(omap->usbhost_fs_fck); + if (omap->usbhost_hs_fck != NULL) + clk_enable(omap->usbhost_hs_fck); + if (omap->utmi_p1_fck != NULL) + clk_enable(omap->utmi_p1_fck); + if (omap->utmi_p2_fck != NULL) + clk_enable(omap->utmi_p2_fck); + } else { - clk_disable(omap->usbhost_hs_fck); - clk_disable(omap->usbhost_fs_fck); - clk_disable(omap->usbhost_ick); - clk_disable(omap->usbtll_fck); - clk_disable(omap->usbtll_ick); + if (omap->usbtll_ick != NULL) + clk_disable(omap->usbtll_ick); + if (omap->usbtll_fck != NULL) + clk_disable(omap->usbtll_fck); + if (omap->usbhost_ick != NULL) + clk_disable(omap->usbhost_ick); + if (omap->usbhost_fs_fck != NULL) + clk_disable(omap->usbhost_fs_fck); + if (omap->usbhost_hs_fck != NULL) + clk_disable(omap->usbhost_hs_fck); + if (omap->utmi_p1_fck != NULL) + clk_disable(omap->utmi_p1_fck); + if (omap->utmi_p2_fck != NULL) + clk_disable(omap->utmi_p2_fck); } } @@ -291,14 +337,118 @@ static int omap3_start_ohci(struct ohci_ dev_dbg(omap->dev, "starting TI OHCI USB Controller\n"); if (cpu_is_omap44xx()) { - /* TODO */ + /* Enable clocks for OMAP4 USBHOST */ + omap->usbhost_fs_fck = clk_get(omap->dev, "usb_host_fs_fck"); + if (IS_ERR(omap->usbhost_fs_fck)) { + ret = PTR_ERR(omap->usbhost_fs_fck); + goto err_host; + } + + omap->utmi_p1_fck = clk_get(omap->dev, "utmi_p1_gfclk_ck"); + if (IS_ERR(omap->utmi_p1_fck)) { + ret = PTR_ERR(omap->utmi_p1_fck); + goto err_utmi_p1_ck; + } + + omap->utmi_p2_fck = clk_get(omap->dev, "utmi_p2_gfclk_ck"); + if (IS_ERR(omap->utmi_p2_fck)) { + ret = PTR_ERR(omap->utmi_p2_fck); + goto err_utmi_p2_ck; + } + + omap->usbtll_ick = clk_get(omap->dev, "usb_tll_ick"); + if (IS_ERR(omap->usbtll_ick)) { + ret = PTR_ERR(omap->usbtll_ick); + goto err_44tll_ick; + } + + omap->usbhost_hs_fck = NULL; + omap->xclk60mhsp2_ck = NULL; + omap->xclk60mhsp1_ck = NULL; + omap->usbhost_ick = NULL; + + /* Now enable all the clocks in the correct order */ + ohci_omap3_clock_power(omap, 1); + + /* perform TLL soft reset, and wait + * until reset is complete */ + ohci_omap_writel(omap->tll_base, OMAP_USBTLL_SYSCONFIG, + OMAP_USBTLL_SYSCONFIG_SOFTRESET); + + /* Wait for TLL reset to complete */ + while (!(ohci_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_44sys_status; + } + } + + dev_dbg(omap->dev, "TLL RESET DONE\n"); + + /* Put UHH in NoIdle/NoStandby mode */ + reg = ohci_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; + + ohci_omap_writel(omap->uhh_base, OMAP_UHH_SYSCONFIG, reg); + + reg = ohci_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; + + /* set p1 & p2 modes */ + /* OHCI has to go through USBTLL */ + reg &= OMAP_UHH_HOST_PORTS_RESET; + if (omap->port_mode[0] != OMAP_OHCI_PORT_MODE_UNUSED) + reg |= OMAP_UHH_HOST_P1_SET_ULPITLL; + if (omap->port_mode[1] != OMAP_OHCI_PORT_MODE_UNUSED) + reg |= OMAP_UHH_HOST_P2_SET_ULPITLL; + + ohci_omap_writel(omap->uhh_base, OMAP_UHH_HOSTCONFIG, reg); + dev_dbg(omap->dev, "UHH setup done, uhh_hostconfig=%x\n", reg); + + /* (1<<3) = no idle mode only for initial debugging */ + ohci_omap_writel(omap->tll_base, OMAP_USBTLL_SYSCONFIG, + OMAP_USBTLL_SYSCONFIG_ENAWAKEUP | + OMAP_USBTLL_SYSCONFIG_SIDLEMODE | + OMAP_USBTLL_SYSCONFIG_CACTIVITY); + + ohci_omap3_tll_config(omap, OMAP4_TLL_CHANNEL_COUNT); + + return 0; + +err_44sys_status: + ohci_omap3_clock_power(omap, 0); + clk_put(omap->usbtll_ick); + +err_44tll_ick: + clk_put(omap->utmi_p2_fck); + +err_utmi_p2_ck: + clk_put(omap->utmi_p1_fck); + +err_utmi_p1_ck: + clk_put(omap->usbhost_fs_fck); + } else { /* 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; + goto err_host; } omap->usbhost_hs_fck = clk_get(omap->dev, "usbhost_120m_fck"); @@ -445,10 +595,10 @@ err_host_fs_fck: err_host_hs_fck: clk_put(omap->usbhost_ick); - -err_host_ick: - return ret; } + +err_host: + return ret; } static void omap3_stop_ohci(struct ohci_hcd_omap3 *omap, struct usb_hcd *hcd) @@ -458,8 +608,13 @@ static void omap3_stop_ohci(struct ohci_ dev_dbg(omap->dev, "stopping TI EHCI USB Controller\n"); /* Reset USBHOST for insmod/rmmod to work */ - ohci_omap_writel(omap->uhh_base, OMAP_UHH_SYSCONFIG, - OMAP_UHH_SYSCONFIG_SOFTRESET); + if (cpu_is_omap44xx()) + ohci_omap_writel(omap->uhh_base, OMAP_UHH_SYSCONFIG, + OMAP4_UHH_SYSCONFIG_SOFTRESET); + else + ohci_omap_writel(omap->uhh_base, OMAP_UHH_SYSCONFIG, + OMAP_UHH_SYSCONFIG_SOFTRESET); + while (!(ohci_omap_readl(omap->uhh_base, OMAP_UHH_SYSSTATUS) & OMAP_UHH_SYSSTATUS_UHHRESETDONE)) { cpu_relax(); @@ -501,6 +656,26 @@ static void omap3_stop_ohci(struct ohci_ omap->usbtll_fck = NULL; } + if (omap->utmi_p2_fck != NULL) { + clk_put(omap->utmi_p2_fck); + omap->utmi_p2_fck = NULL; + } + + if (omap->utmi_p1_fck != NULL) { + clk_put(omap->utmi_p1_fck); + omap->utmi_p1_fck = NULL; + } + + if (omap->xclk60mhsp2_ck != NULL) { + clk_put(omap->xclk60mhsp2_ck); + omap->xclk60mhsp2_ck = NULL; + } + + if (omap->xclk60mhsp1_ck != NULL) { + clk_put(omap->xclk60mhsp1_ck); + omap->xclk60mhsp1_ck = NULL; + } + if (omap->usbhost_ick != NULL) { clk_put(omap->usbhost_ick); omap->usbhost_ick = NULL; -- To unsubscribe from this list: send the line "unsubscribe linux-usb" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html