/* * frame functions */ int usbhs_frame_get_num(struct usbhs_priv *priv) { return usbhs_read(priv, FRMNUM) & FRNM_MASK; }
/** * usbhs_omap_probe - initialize TI-based HCDs * * Allocates basic resources for this USB host controller. */ static int usbhs_omap_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; struct usbhs_omap_platform_data *pdata = dev_get_platdata(dev); struct usbhs_hcd_omap *omap; struct resource *res; int ret = 0; int i; bool need_logic_fck; if (dev->of_node) { /* For DT boot we populate platform data from OF node */ pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL); if (!pdata) return -ENOMEM; ret = usbhs_omap_get_dt_pdata(dev, pdata); if (ret) return ret; dev->platform_data = pdata; } if (!pdata) { dev_err(dev, "Missing platform data\n"); return -ENODEV; } if (pdata->nports > OMAP3_HS_USB_PORTS) { dev_info(dev, "Too many num_ports <%d> in platform_data. Max %d\n", pdata->nports, OMAP3_HS_USB_PORTS); return -ENODEV; } omap = devm_kzalloc(dev, sizeof(*omap), GFP_KERNEL); if (!omap) { dev_err(dev, "Memory allocation failed\n"); return -ENOMEM; } res = platform_get_resource(pdev, IORESOURCE_MEM, 0); omap->uhh_base = devm_ioremap_resource(dev, res); if (IS_ERR(omap->uhh_base)) return PTR_ERR(omap->uhh_base); omap->pdata = pdata; /* Initialize the TLL subsystem */ omap_tll_init(pdata); pm_runtime_enable(dev); platform_set_drvdata(pdev, omap); pm_runtime_get_sync(dev); omap->usbhs_rev = usbhs_read(omap->uhh_base, OMAP_UHH_REVISION); /* we need to call runtime suspend before we update omap->nports * to prevent unbalanced clk_disable() */ pm_runtime_put_sync(dev); /* * If platform data contains nports then use that * else make out number of ports from USBHS revision */ if (pdata->nports) { omap->nports = pdata->nports; } else { switch (omap->usbhs_rev) { case OMAP_USBHS_REV1: omap->nports = 3; break; case OMAP_USBHS_REV2: omap->nports = 2; break; default: omap->nports = OMAP3_HS_USB_PORTS; dev_dbg(dev, "USB HOST Rev:0x%x not recognized, assuming %d ports\n", omap->usbhs_rev, omap->nports); break; } pdata->nports = omap->nports; } i = sizeof(struct clk *) * omap->nports; omap->utmi_clk = devm_kzalloc(dev, i, GFP_KERNEL); omap->hsic480m_clk = devm_kzalloc(dev, i, GFP_KERNEL); omap->hsic60m_clk = devm_kzalloc(dev, i, GFP_KERNEL); if (!omap->utmi_clk || !omap->hsic480m_clk || !omap->hsic60m_clk) { dev_err(dev, "Memory allocation failed\n"); ret = -ENOMEM; goto err_mem; } /* Set all clocks as invalid to begin with */ omap->ehci_logic_fck = ERR_PTR(-ENODEV); omap->init_60m_fclk = ERR_PTR(-ENODEV); omap->utmi_p1_gfclk = ERR_PTR(-ENODEV); omap->utmi_p2_gfclk = ERR_PTR(-ENODEV); omap->xclk60mhsp1_ck = ERR_PTR(-ENODEV); omap->xclk60mhsp2_ck = ERR_PTR(-ENODEV); for (i = 0; i < omap->nports; i++) { omap->utmi_clk[i] = ERR_PTR(-ENODEV); omap->hsic480m_clk[i] = ERR_PTR(-ENODEV); omap->hsic60m_clk[i] = ERR_PTR(-ENODEV); } /* for OMAP3 i.e. USBHS REV1 */ if (omap->usbhs_rev == OMAP_USBHS_REV1) { need_logic_fck = false; for (i = 0; i < omap->nports; i++) { if (is_ehci_phy_mode(pdata->port_mode[i]) || is_ehci_tll_mode(pdata->port_mode[i]) || is_ehci_hsic_mode(pdata->port_mode[i])) need_logic_fck |= true; } if (need_logic_fck) { omap->ehci_logic_fck = devm_clk_get(dev, "usbhost_120m_fck"); if (IS_ERR(omap->ehci_logic_fck)) { ret = PTR_ERR(omap->ehci_logic_fck); dev_err(dev, "usbhost_120m_fck failed:%d\n", ret); goto err_mem; } } goto initialize; } /* for OMAP4+ i.e. USBHS REV2+ */ omap->utmi_p1_gfclk = devm_clk_get(dev, "utmi_p1_gfclk"); if (IS_ERR(omap->utmi_p1_gfclk)) { ret = PTR_ERR(omap->utmi_p1_gfclk); dev_err(dev, "utmi_p1_gfclk failed error:%d\n", ret); goto err_mem; } omap->utmi_p2_gfclk = devm_clk_get(dev, "utmi_p2_gfclk"); if (IS_ERR(omap->utmi_p2_gfclk)) { ret = PTR_ERR(omap->utmi_p2_gfclk); dev_err(dev, "utmi_p2_gfclk failed error:%d\n", ret); goto err_mem; } omap->xclk60mhsp1_ck = devm_clk_get(dev, "refclk_60m_ext_p1"); if (IS_ERR(omap->xclk60mhsp1_ck)) { ret = PTR_ERR(omap->xclk60mhsp1_ck); dev_err(dev, "refclk_60m_ext_p1 failed error:%d\n", ret); goto err_mem; } omap->xclk60mhsp2_ck = devm_clk_get(dev, "refclk_60m_ext_p2"); if (IS_ERR(omap->xclk60mhsp2_ck)) { ret = PTR_ERR(omap->xclk60mhsp2_ck); dev_err(dev, "refclk_60m_ext_p2 failed error:%d\n", ret); goto err_mem; } omap->init_60m_fclk = devm_clk_get(dev, "refclk_60m_int"); if (IS_ERR(omap->init_60m_fclk)) { ret = PTR_ERR(omap->init_60m_fclk); dev_err(dev, "refclk_60m_int failed error:%d\n", ret); goto err_mem; } for (i = 0; i < omap->nports; i++) { char clkname[30]; /* clock names are indexed from 1*/ snprintf(clkname, sizeof(clkname), "usb_host_hs_utmi_p%d_clk", i + 1); /* If a clock is not found we won't bail out as not all * platforms have all clocks and we can function without * them */ omap->utmi_clk[i] = devm_clk_get(dev, clkname); if (IS_ERR(omap->utmi_clk[i])) { ret = PTR_ERR(omap->utmi_clk[i]); dev_err(dev, "Failed to get clock : %s : %d\n", clkname, ret); goto err_mem; } snprintf(clkname, sizeof(clkname), "usb_host_hs_hsic480m_p%d_clk", i + 1); omap->hsic480m_clk[i] = devm_clk_get(dev, clkname); if (IS_ERR(omap->hsic480m_clk[i])) { ret = PTR_ERR(omap->hsic480m_clk[i]); dev_err(dev, "Failed to get clock : %s : %d\n", clkname, ret); goto err_mem; } snprintf(clkname, sizeof(clkname), "usb_host_hs_hsic60m_p%d_clk", i + 1); omap->hsic60m_clk[i] = devm_clk_get(dev, clkname); if (IS_ERR(omap->hsic60m_clk[i])) { ret = PTR_ERR(omap->hsic60m_clk[i]); dev_err(dev, "Failed to get clock : %s : %d\n", clkname, ret); goto err_mem; } } if (is_ehci_phy_mode(pdata->port_mode[0])) { ret = clk_set_parent(omap->utmi_p1_gfclk, omap->xclk60mhsp1_ck); if (ret != 0) { dev_err(dev, "xclk60mhsp1_ck set parent failed: %d\n", ret); goto err_mem; } } else if (is_ehci_tll_mode(pdata->port_mode[0])) { ret = clk_set_parent(omap->utmi_p1_gfclk, omap->init_60m_fclk); if (ret != 0) { dev_err(dev, "P0 init_60m_fclk set parent failed: %d\n", ret); goto err_mem; } } if (is_ehci_phy_mode(pdata->port_mode[1])) { ret = clk_set_parent(omap->utmi_p2_gfclk, omap->xclk60mhsp2_ck); if (ret != 0) { dev_err(dev, "xclk60mhsp2_ck set parent failed: %d\n", ret); goto err_mem; } } else if (is_ehci_tll_mode(pdata->port_mode[1])) { ret = clk_set_parent(omap->utmi_p2_gfclk, omap->init_60m_fclk); if (ret != 0) { dev_err(dev, "P1 init_60m_fclk set parent failed: %d\n", ret); goto err_mem; } } initialize: omap_usbhs_init(dev); if (dev->of_node) { ret = of_platform_populate(dev->of_node, usbhs_child_match_table, NULL, dev); if (ret) { dev_err(dev, "Failed to create DT children: %d\n", ret); goto err_mem; } } else { ret = omap_usbhs_alloc_children(pdev); if (ret) { dev_err(dev, "omap_usbhs_alloc_children failed: %d\n", ret); goto err_mem; } } return 0; err_mem: pm_runtime_disable(dev); return ret; }
/* * autonomy * * these functions are used if platform doesn't have external phy. * -> there is no "notify_hotplug" callback from platform * -> call "notify_hotplug" by itself * -> use own interrupt to connect/disconnect * -> it mean module clock is always ON * ~~~~~~~~~~~~~~~~~~~~~~~~~ */ static int usbhsm_autonomy_get_vbus(struct platform_device *pdev) { struct usbhs_priv *priv = usbhs_pdev_to_priv(pdev); return VBSTS & usbhs_read(priv, INTSTS0); }
static int usbhsf_fifo_rcv_len(struct usbhs_priv *priv, struct usbhs_fifo *fifo) { return usbhs_read(priv, fifo->ctr) & DTLN_MASK; }
static void omap_usbhs_init(struct device *dev) { struct usbhs_hcd_omap *omap = dev_get_drvdata(dev); struct usbhs_omap_platform_data *pdata = &omap->platdata; unsigned long flags; unsigned reg; dev_dbg(dev, "starting TI HSUSB Controller\n"); pm_runtime_get_sync(dev); if (pdata->ehci_data->phy_reset) { if (gpio_is_valid(pdata->ehci_data->reset_gpio_port[0])) gpio_request_one(pdata->ehci_data->reset_gpio_port[0], GPIOF_OUT_INIT_LOW, "USB1 PHY reset"); if (gpio_is_valid(pdata->ehci_data->reset_gpio_port[1])) gpio_request_one(pdata->ehci_data->reset_gpio_port[1], GPIOF_OUT_INIT_LOW, "USB2 PHY reset"); if (gpio_is_valid(pdata->ehci_data->reset_gpio_port[2])) gpio_request_one(pdata->ehci_data->reset_gpio_port[2], GPIOF_OUT_INIT_LOW, "USB2 PHY reset"); /* Hold the PHY in RESET for enough time till DIR is high */ udelay(10); } spin_lock_irqsave(&omap->lock, flags); omap->usbhs_rev = usbhs_read(omap->uhh_base, OMAP_UHH_REVISION); dev_dbg(dev, "OMAP UHH_REVISION 0x%x\n", omap->usbhs_rev); reg = usbhs_read(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 |= OMAP4_UHH_HOSTCONFIG_APP_START_CLK; reg &= ~OMAP_UHH_HOSTCONFIG_INCRX_ALIGN_EN; if (is_omap_usbhs_rev1(omap)) { if (pdata->port_mode[0] == OMAP_USBHS_PORT_MODE_UNUSED) reg &= ~OMAP_UHH_HOSTCONFIG_P1_CONNECT_STATUS; if (pdata->port_mode[1] == OMAP_USBHS_PORT_MODE_UNUSED) reg &= ~OMAP_UHH_HOSTCONFIG_P2_CONNECT_STATUS; if (pdata->port_mode[2] == OMAP_USBHS_PORT_MODE_UNUSED) 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(dev, "OMAP3 ES version <= ES2.1\n"); if (is_ehci_phy_mode(pdata->port_mode[0]) || is_ehci_phy_mode(pdata->port_mode[1]) || is_ehci_phy_mode(pdata->port_mode[2])) reg &= ~OMAP_UHH_HOSTCONFIG_ULPI_BYPASS; else reg |= OMAP_UHH_HOSTCONFIG_ULPI_BYPASS; } else { dev_dbg(dev, "OMAP3 ES version > ES2.1\n"); if (is_ehci_phy_mode(pdata->port_mode[0])) reg &= ~OMAP_UHH_HOSTCONFIG_ULPI_P1_BYPASS; else reg |= OMAP_UHH_HOSTCONFIG_ULPI_P1_BYPASS; if (is_ehci_phy_mode(pdata->port_mode[1])) reg &= ~OMAP_UHH_HOSTCONFIG_ULPI_P2_BYPASS; else reg |= OMAP_UHH_HOSTCONFIG_ULPI_P2_BYPASS; if (is_ehci_phy_mode(pdata->port_mode[2])) reg &= ~OMAP_UHH_HOSTCONFIG_ULPI_P3_BYPASS; else reg |= OMAP_UHH_HOSTCONFIG_ULPI_P3_BYPASS; } } else if (is_omap_usbhs_rev2(omap)) { /* Clear port mode fields for PHY mode*/ reg &= ~OMAP4_P1_MODE_CLEAR; reg &= ~OMAP4_P2_MODE_CLEAR; if (is_ehci_tll_mode(pdata->port_mode[0]) || (is_ohci_port(pdata->port_mode[0]))) reg |= OMAP4_P1_MODE_TLL; else if (is_ehci_hsic_mode(pdata->port_mode[0])) reg |= OMAP4_P1_MODE_HSIC; if (is_ehci_tll_mode(pdata->port_mode[1]) || (is_ohci_port(pdata->port_mode[1]))) reg |= OMAP4_P2_MODE_TLL; else if (is_ehci_hsic_mode(pdata->port_mode[1])) reg |= OMAP4_P2_MODE_HSIC; if (is_ehci_hsic_mode(pdata->port_mode[2])) reg |= OMAP5_P3_MODE_HSIC; } usbhs_write(omap->uhh_base, OMAP_UHH_HOSTCONFIG, reg); dev_dbg(dev, "UHH setup done, uhh_hostconfig=%x\n", reg); spin_unlock_irqrestore(&omap->lock, flags); if (pdata->ehci_data->phy_reset) { /* Hold the PHY in RESET for enough time till * PHY is settled and ready */ udelay(10); if (gpio_is_valid(pdata->ehci_data->reset_gpio_port[0])) gpio_set_value(pdata->ehci_data->reset_gpio_port[0], 1); if (gpio_is_valid(pdata->ehci_data->reset_gpio_port[1])) gpio_set_value(pdata->ehci_data->reset_gpio_port[1], 1); if (gpio_is_valid(pdata->ehci_data->reset_gpio_port[2])) gpio_set_value(pdata->ehci_data->reset_gpio_port[2], 1); } pm_runtime_put_sync(dev); }
static void omap_usbhs_init(struct device *dev) { struct usbhs_hcd_omap *omap = dev_get_drvdata(dev); struct usbhs_omap_platform_data *pdata = &omap->platdata; unsigned long flags; unsigned reg; dev_dbg(dev, "starting TI HSUSB Controller\n"); pm_runtime_get_sync(dev); spin_lock_irqsave(&omap->lock, flags); omap->usbhs_rev = usbhs_read(omap->uhh_base, OMAP_UHH_REVISION); dev_dbg(dev, "OMAP UHH_REVISION 0x%x\n", omap->usbhs_rev); reg = usbhs_read(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 |= OMAP4_UHH_HOSTCONFIG_APP_START_CLK; reg &= ~OMAP_UHH_HOSTCONFIG_INCRX_ALIGN_EN; if (is_omap_usbhs_rev1(omap)) { if (pdata->port_mode[0] == OMAP_USBHS_PORT_MODE_UNUSED) reg &= ~OMAP_UHH_HOSTCONFIG_P1_CONNECT_STATUS; if (pdata->port_mode[1] == OMAP_USBHS_PORT_MODE_UNUSED) reg &= ~OMAP_UHH_HOSTCONFIG_P2_CONNECT_STATUS; if (pdata->port_mode[2] == OMAP_USBHS_PORT_MODE_UNUSED) 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(dev, "OMAP3 ES version <= ES2.1\n"); if (is_ehci_phy_mode(pdata->port_mode[0]) || is_ehci_phy_mode(pdata->port_mode[1]) || is_ehci_phy_mode(pdata->port_mode[2])) reg &= ~OMAP_UHH_HOSTCONFIG_ULPI_BYPASS; else reg |= OMAP_UHH_HOSTCONFIG_ULPI_BYPASS; } else { dev_dbg(dev, "OMAP3 ES version > ES2.1\n"); if (is_ehci_phy_mode(pdata->port_mode[0])) reg &= ~OMAP_UHH_HOSTCONFIG_ULPI_P1_BYPASS; else reg |= OMAP_UHH_HOSTCONFIG_ULPI_P1_BYPASS; if (is_ehci_phy_mode(pdata->port_mode[1])) reg &= ~OMAP_UHH_HOSTCONFIG_ULPI_P2_BYPASS; else reg |= OMAP_UHH_HOSTCONFIG_ULPI_P2_BYPASS; if (is_ehci_phy_mode(pdata->port_mode[2])) reg &= ~OMAP_UHH_HOSTCONFIG_ULPI_P3_BYPASS; else reg |= OMAP_UHH_HOSTCONFIG_ULPI_P3_BYPASS; } } else if (is_omap_usbhs_rev2(omap)) { /* Clear port mode fields for PHY mode*/ reg &= ~OMAP4_P1_MODE_CLEAR; reg &= ~OMAP4_P2_MODE_CLEAR; if (is_ehci_tll_mode(pdata->port_mode[0]) || (is_ohci_port(pdata->port_mode[0]))) reg |= OMAP4_P1_MODE_TLL; else if (is_ehci_hsic_mode(pdata->port_mode[0])) reg |= OMAP4_P1_MODE_HSIC; if (is_ehci_tll_mode(pdata->port_mode[1]) || (is_ohci_port(pdata->port_mode[1]))) reg |= OMAP4_P2_MODE_TLL; else if (is_ehci_hsic_mode(pdata->port_mode[1])) reg |= OMAP4_P2_MODE_HSIC; } usbhs_write(omap->uhh_base, OMAP_UHH_HOSTCONFIG, reg); dev_dbg(dev, "UHH setup done, uhh_hostconfig=%x\n", reg); if (is_ehci_tll_mode(pdata->port_mode[0]) || is_ehci_tll_mode(pdata->port_mode[1]) || is_ehci_tll_mode(pdata->port_mode[2]) || (is_ohci_port(pdata->port_mode[0])) || (is_ohci_port(pdata->port_mode[1])) || (is_ohci_port(pdata->port_mode[2]))) { /* Enable UTMI mode for required TLL channels */ if (is_omap_usbhs_rev2(omap)) usbhs_omap_tll_init(dev, OMAP_REV2_TLL_CHANNEL_COUNT); else usbhs_omap_tll_init(dev, OMAP_TLL_CHANNEL_COUNT); } spin_unlock_irqrestore(&omap->lock, flags); pm_runtime_put_sync(dev); }
static void usbhs_disable(struct device *dev) { struct usbhs_hcd_omap *omap = dev_get_drvdata(dev); struct usbhs_omap_platform_data *pdata = &omap->platdata; unsigned long flags = 0; unsigned long timeout; dev_dbg(dev, "stopping TI HSUSB Controller\n"); spin_lock_irqsave(&omap->lock, flags); if (omap->count == 0) goto end_disble; omap->count--; if (omap->count != 0) goto end_disble; /* Reset OMAP modules for insmod/rmmod to work */ usbhs_write(omap->uhh_base, OMAP_UHH_SYSCONFIG, is_omap_usbhs_rev2(omap) ? OMAP4_UHH_SYSCONFIG_SOFTRESET : OMAP_UHH_SYSCONFIG_SOFTRESET); timeout = jiffies + msecs_to_jiffies(100); while (!(usbhs_read(omap->uhh_base, OMAP_UHH_SYSSTATUS) & (1 << 0))) { cpu_relax(); if (time_after(jiffies, timeout)) dev_dbg(dev, "operation timed out\n"); } while (!(usbhs_read(omap->uhh_base, OMAP_UHH_SYSSTATUS) & (1 << 1))) { cpu_relax(); if (time_after(jiffies, timeout)) dev_dbg(dev, "operation timed out\n"); } while (!(usbhs_read(omap->uhh_base, OMAP_UHH_SYSSTATUS) & (1 << 2))) { cpu_relax(); if (time_after(jiffies, timeout)) dev_dbg(dev, "operation timed out\n"); } usbhs_write(omap->tll_base, OMAP_USBTLL_SYSCONFIG, (1 << 1)); while (!(usbhs_read(omap->tll_base, OMAP_USBTLL_SYSSTATUS) & (1 << 0))) { cpu_relax(); if (time_after(jiffies, timeout)) dev_dbg(dev, "operation timed out\n"); } if (is_omap_usbhs_rev2(omap)) { if (is_ehci_tll_mode(pdata->port_mode[0])) clk_enable(omap->usbtll_p1_fck); if (is_ehci_tll_mode(pdata->port_mode[1])) clk_enable(omap->usbtll_p2_fck); clk_disable(omap->utmi_p2_fck); clk_disable(omap->utmi_p1_fck); } pm_runtime_put_sync(dev); /* The gpio_free migh sleep; so unlock the spinlock */ spin_unlock_irqrestore(&omap->lock, flags); if (pdata->ehci_data->phy_reset) { if (gpio_is_valid(pdata->ehci_data->reset_gpio_port[0])) gpio_free(pdata->ehci_data->reset_gpio_port[0]); if (gpio_is_valid(pdata->ehci_data->reset_gpio_port[1])) gpio_free(pdata->ehci_data->reset_gpio_port[1]); } return; end_disble: spin_unlock_irqrestore(&omap->lock, flags); }
static int usbhs_enable(struct device *dev) { struct usbhs_hcd_omap *omap = dev_get_drvdata(dev); struct usbhs_omap_platform_data *pdata = &omap->platdata; unsigned long flags = 0; int ret = 0; unsigned reg; dev_dbg(dev, "starting TI HSUSB Controller\n"); if (!pdata) { dev_dbg(dev, "missing platform_data\n"); return -ENODEV; } spin_lock_irqsave(&omap->lock, flags); if (omap->count > 0) goto end_count; pm_runtime_get_sync(dev); if (pdata->ehci_data->phy_reset) { if (gpio_is_valid(pdata->ehci_data->reset_gpio_port[0])) { gpio_request(pdata->ehci_data->reset_gpio_port[0], "USB1 PHY reset"); gpio_direction_output (pdata->ehci_data->reset_gpio_port[0], 0); } if (gpio_is_valid(pdata->ehci_data->reset_gpio_port[1])) { gpio_request(pdata->ehci_data->reset_gpio_port[1], "USB2 PHY reset"); gpio_direction_output (pdata->ehci_data->reset_gpio_port[1], 0); } /* Hold the PHY in RESET for enough time till DIR is high */ udelay(10); } omap->usbhs_rev = usbhs_read(omap->uhh_base, OMAP_UHH_REVISION); dev_dbg(dev, "OMAP UHH_REVISION 0x%x\n", omap->usbhs_rev); reg = usbhs_read(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 |= OMAP4_UHH_HOSTCONFIG_APP_START_CLK; reg &= ~OMAP_UHH_HOSTCONFIG_INCRX_ALIGN_EN; if (is_omap_usbhs_rev1(omap)) { if (pdata->port_mode[0] == OMAP_USBHS_PORT_MODE_UNUSED) reg &= ~OMAP_UHH_HOSTCONFIG_P1_CONNECT_STATUS; if (pdata->port_mode[1] == OMAP_USBHS_PORT_MODE_UNUSED) reg &= ~OMAP_UHH_HOSTCONFIG_P2_CONNECT_STATUS; if (pdata->port_mode[2] == OMAP_USBHS_PORT_MODE_UNUSED) 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(dev, "OMAP3 ES version <= ES2.1\n"); if (is_ehci_phy_mode(pdata->port_mode[0]) || is_ehci_phy_mode(pdata->port_mode[1]) || is_ehci_phy_mode(pdata->port_mode[2])) reg &= ~OMAP_UHH_HOSTCONFIG_ULPI_BYPASS; else reg |= OMAP_UHH_HOSTCONFIG_ULPI_BYPASS; } else { dev_dbg(dev, "OMAP3 ES version > ES2.1\n"); if (is_ehci_phy_mode(pdata->port_mode[0])) reg &= ~OMAP_UHH_HOSTCONFIG_ULPI_P1_BYPASS; else reg |= OMAP_UHH_HOSTCONFIG_ULPI_P1_BYPASS; if (is_ehci_phy_mode(pdata->port_mode[1])) reg &= ~OMAP_UHH_HOSTCONFIG_ULPI_P2_BYPASS; else reg |= OMAP_UHH_HOSTCONFIG_ULPI_P2_BYPASS; if (is_ehci_phy_mode(pdata->port_mode[2])) reg &= ~OMAP_UHH_HOSTCONFIG_ULPI_P3_BYPASS; else reg |= OMAP_UHH_HOSTCONFIG_ULPI_P3_BYPASS; } } else if (is_omap_usbhs_rev2(omap)) { /* Clear port mode fields for PHY mode*/ reg &= ~OMAP4_P1_MODE_CLEAR; reg &= ~OMAP4_P2_MODE_CLEAR; if (is_ehci_phy_mode(pdata->port_mode[0])) { ret = clk_set_parent(omap->utmi_p1_fck, omap->xclk60mhsp1_ck); if (ret != 0) { dev_err(dev, "xclk60mhsp1_ck set parent" "failed error:%d\n", ret); goto err_tll; } } else if (is_ehci_tll_mode(pdata->port_mode[0])) { ret = clk_set_parent(omap->utmi_p1_fck, omap->init_60m_fclk); if (ret != 0) { dev_err(dev, "init_60m_fclk set parent" "failed error:%d\n", ret); goto err_tll; } clk_enable(omap->usbhost_p1_fck); clk_enable(omap->usbtll_p1_fck); } if (is_ehci_phy_mode(pdata->port_mode[1])) { ret = clk_set_parent(omap->utmi_p2_fck, omap->xclk60mhsp2_ck); if (ret != 0) { dev_err(dev, "xclk60mhsp1_ck set parent" "failed error:%d\n", ret); goto err_tll; } } else if (is_ehci_tll_mode(pdata->port_mode[1])) { ret = clk_set_parent(omap->utmi_p2_fck, omap->init_60m_fclk); if (ret != 0) { dev_err(dev, "init_60m_fclk set parent" "failed error:%d\n", ret); goto err_tll; } clk_enable(omap->usbhost_p2_fck); clk_enable(omap->usbtll_p2_fck); } clk_enable(omap->utmi_p1_fck); clk_enable(omap->utmi_p2_fck); if (is_ehci_tll_mode(pdata->port_mode[0]) || (is_ohci_port(pdata->port_mode[0]))) reg |= OMAP4_P1_MODE_TLL; else if (is_ehci_hsic_mode(pdata->port_mode[0])) reg |= OMAP4_P1_MODE_HSIC; if (is_ehci_tll_mode(pdata->port_mode[1]) || (is_ohci_port(pdata->port_mode[1]))) reg |= OMAP4_P2_MODE_TLL; else if (is_ehci_hsic_mode(pdata->port_mode[1])) reg |= OMAP4_P2_MODE_HSIC; } usbhs_write(omap->uhh_base, OMAP_UHH_HOSTCONFIG, reg); dev_dbg(dev, "UHH setup done, uhh_hostconfig=%x\n", reg); if (is_ehci_tll_mode(pdata->port_mode[0]) || is_ehci_tll_mode(pdata->port_mode[1]) || is_ehci_tll_mode(pdata->port_mode[2]) || (is_ohci_port(pdata->port_mode[0])) || (is_ohci_port(pdata->port_mode[1])) || (is_ohci_port(pdata->port_mode[2]))) { /* Enable UTMI mode for required TLL channels */ if (is_omap_usbhs_rev2(omap)) usbhs_omap_tll_init(dev, OMAP_REV2_TLL_CHANNEL_COUNT); else usbhs_omap_tll_init(dev, OMAP_TLL_CHANNEL_COUNT); } if (pdata->ehci_data->phy_reset) { /* Hold the PHY in RESET for enough time till * PHY is settled and ready */ udelay(10); if (gpio_is_valid(pdata->ehci_data->reset_gpio_port[0])) gpio_set_value (pdata->ehci_data->reset_gpio_port[0], 1); if (gpio_is_valid(pdata->ehci_data->reset_gpio_port[1])) gpio_set_value (pdata->ehci_data->reset_gpio_port[1], 1); } end_count: omap->count++; spin_unlock_irqrestore(&omap->lock, flags); return 0; err_tll: pm_runtime_put_sync(dev); spin_unlock_irqrestore(&omap->lock, flags); if (pdata->ehci_data->phy_reset) { if (gpio_is_valid(pdata->ehci_data->reset_gpio_port[0])) gpio_free(pdata->ehci_data->reset_gpio_port[0]); if (gpio_is_valid(pdata->ehci_data->reset_gpio_port[1])) gpio_free(pdata->ehci_data->reset_gpio_port[1]); } return ret; }
static int usbhs_enable(struct device *dev) { struct usbhs_hcd_omap *omap = dev_get_drvdata(dev); struct usbhs_omap_platform_data *pdata = &omap->platdata; unsigned long flags = 0; int ret = 0; unsigned long timeout; unsigned reg; dev_dbg(dev, "starting TI HSUSB Controller\n"); if (!pdata) { dev_dbg(dev, "missing platform_data\n"); return -ENODEV; } spin_lock_irqsave(&omap->lock, flags); if (omap->count > 0) goto end_count; clk_enable(omap->usbhost_ick); clk_enable(omap->usbhost_hs_fck); clk_enable(omap->usbhost_fs_fck); clk_enable(omap->usbtll_fck); clk_enable(omap->usbtll_ick); if (pdata->ehci_data->phy_reset) { if (gpio_is_valid(pdata->ehci_data->reset_gpio_port[0])) { gpio_request(pdata->ehci_data->reset_gpio_port[0], "USB1 PHY reset"); gpio_direction_output (pdata->ehci_data->reset_gpio_port[0], 0); } if (gpio_is_valid(pdata->ehci_data->reset_gpio_port[1])) { gpio_request(pdata->ehci_data->reset_gpio_port[1], "USB2 PHY reset"); gpio_direction_output (pdata->ehci_data->reset_gpio_port[1], 0); } /* Hold the PHY in RESET for enough time till DIR is high */ udelay(10); } omap->usbhs_rev = usbhs_read(omap->uhh_base, OMAP_UHH_REVISION); dev_dbg(dev, "OMAP UHH_REVISION 0x%x\n", omap->usbhs_rev); /* perform TLL soft reset, and wait until reset is complete */ usbhs_write(omap->tll_base, OMAP_USBTLL_SYSCONFIG, OMAP_USBTLL_SYSCONFIG_SOFTRESET); /* Wait for TLL reset to complete */ timeout = jiffies + msecs_to_jiffies(1000); while (!(usbhs_read(omap->tll_base, OMAP_USBTLL_SYSSTATUS) & OMAP_USBTLL_SYSSTATUS_RESETDONE)) { cpu_relax(); if (time_after(jiffies, timeout)) { dev_dbg(dev, "operation timed out\n"); ret = -EINVAL; goto err_tll; } } dev_dbg(dev, "TLL RESET DONE\n"); /* (1<<3) = no idle mode only for initial debugging */ usbhs_write(omap->tll_base, OMAP_USBTLL_SYSCONFIG, OMAP_USBTLL_SYSCONFIG_ENAWAKEUP | OMAP_USBTLL_SYSCONFIG_SIDLEMODE | OMAP_USBTLL_SYSCONFIG_AUTOIDLE); /* Put UHH in NoIdle/NoStandby mode */ reg = usbhs_read(omap->uhh_base, OMAP_UHH_SYSCONFIG); if (is_omap_usbhs_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_usbhs_rev2(omap)) { reg &= ~OMAP4_UHH_SYSCONFIG_IDLEMODE_CLEAR; reg |= OMAP4_UHH_SYSCONFIG_NOIDLE; reg &= ~OMAP4_UHH_SYSCONFIG_STDBYMODE_CLEAR; reg |= OMAP4_UHH_SYSCONFIG_NOSTDBY; } usbhs_write(omap->uhh_base, OMAP_UHH_SYSCONFIG, reg); reg = usbhs_read(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 |= OMAP4_UHH_HOSTCONFIG_APP_START_CLK; reg &= ~OMAP_UHH_HOSTCONFIG_INCRX_ALIGN_EN; if (is_omap_usbhs_rev1(omap)) { if (pdata->port_mode[0] == OMAP_USBHS_PORT_MODE_UNUSED) reg &= ~OMAP_UHH_HOSTCONFIG_P1_CONNECT_STATUS; if (pdata->port_mode[1] == OMAP_USBHS_PORT_MODE_UNUSED) reg &= ~OMAP_UHH_HOSTCONFIG_P2_CONNECT_STATUS; if (pdata->port_mode[2] == OMAP_USBHS_PORT_MODE_UNUSED) 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(dev, "OMAP3 ES version <= ES2.1\n"); if (is_ehci_phy_mode(pdata->port_mode[0]) || is_ehci_phy_mode(pdata->port_mode[1]) || is_ehci_phy_mode(pdata->port_mode[2])) reg &= ~OMAP_UHH_HOSTCONFIG_ULPI_BYPASS; else reg |= OMAP_UHH_HOSTCONFIG_ULPI_BYPASS; } else { dev_dbg(dev, "OMAP3 ES version > ES2.1\n"); if (is_ehci_phy_mode(pdata->port_mode[0])) reg &= ~OMAP_UHH_HOSTCONFIG_ULPI_P1_BYPASS; else reg |= OMAP_UHH_HOSTCONFIG_ULPI_P1_BYPASS; if (is_ehci_phy_mode(pdata->port_mode[1])) reg &= ~OMAP_UHH_HOSTCONFIG_ULPI_P2_BYPASS; else reg |= OMAP_UHH_HOSTCONFIG_ULPI_P2_BYPASS; if (is_ehci_phy_mode(pdata->port_mode[2])) reg &= ~OMAP_UHH_HOSTCONFIG_ULPI_P3_BYPASS; else reg |= OMAP_UHH_HOSTCONFIG_ULPI_P3_BYPASS; } } else if (is_omap_usbhs_rev2(omap)) { /* Clear port mode fields for PHY mode*/ reg &= ~OMAP4_P1_MODE_CLEAR; reg &= ~OMAP4_P2_MODE_CLEAR; if (is_ehci_phy_mode(pdata->port_mode[0])) { ret = clk_set_parent(omap->utmi_p1_fck, omap->xclk60mhsp1_ck); if (ret != 0) { dev_err(dev, "xclk60mhsp1_ck set parent" "failed error:%d\n", ret); goto err_tll; } } else if (is_ehci_tll_mode(pdata->port_mode[0])) { ret = clk_set_parent(omap->utmi_p1_fck, omap->init_60m_fclk); if (ret != 0) { dev_err(dev, "init_60m_fclk set parent" "failed error:%d\n", ret); goto err_tll; } clk_enable(omap->usbhost_p1_fck); clk_enable(omap->usbtll_p1_fck); } if (is_ehci_phy_mode(pdata->port_mode[1])) { ret = clk_set_parent(omap->utmi_p2_fck, omap->xclk60mhsp2_ck); if (ret != 0) { dev_err(dev, "xclk60mhsp1_ck set parent" "failed error:%d\n", ret); goto err_tll; } } else if (is_ehci_tll_mode(pdata->port_mode[1])) { ret = clk_set_parent(omap->utmi_p2_fck, omap->init_60m_fclk); if (ret != 0) { dev_err(dev, "init_60m_fclk set parent" "failed error:%d\n", ret); goto err_tll; } clk_enable(omap->usbhost_p2_fck); clk_enable(omap->usbtll_p2_fck); } clk_enable(omap->utmi_p1_fck); clk_enable(omap->utmi_p2_fck); if (is_ehci_tll_mode(pdata->port_mode[0]) || (is_ohci_port(pdata->port_mode[0]))) reg |= OMAP4_P1_MODE_TLL; else if (is_ehci_hsic_mode(pdata->port_mode[0])) reg |= OMAP4_P1_MODE_HSIC; if (is_ehci_tll_mode(pdata->port_mode[1]) || (is_ohci_port(pdata->port_mode[1]))) reg |= OMAP4_P2_MODE_TLL; else if (is_ehci_hsic_mode(pdata->port_mode[1])) reg |= OMAP4_P2_MODE_HSIC; } usbhs_write(omap->uhh_base, OMAP_UHH_HOSTCONFIG, reg); dev_dbg(dev, "UHH setup done, uhh_hostconfig=%x\n", reg); if (is_ehci_tll_mode(pdata->port_mode[0]) || is_ehci_tll_mode(pdata->port_mode[1]) || is_ehci_tll_mode(pdata->port_mode[2]) || (is_ohci_port(pdata->port_mode[0])) || (is_ohci_port(pdata->port_mode[1])) || (is_ohci_port(pdata->port_mode[2]))) { /* Enable UTMI mode for required TLL channels */ if (is_omap_usbhs_rev2(omap)) usbhs_omap_tll_init(dev, OMAP_REV2_TLL_CHANNEL_COUNT); else usbhs_omap_tll_init(dev, OMAP_TLL_CHANNEL_COUNT); } if (pdata->ehci_data->phy_reset) { /* Hold the PHY in RESET for enough time till * PHY is settled and ready */ udelay(10); if (gpio_is_valid(pdata->ehci_data->reset_gpio_port[0])) gpio_set_value (pdata->ehci_data->reset_gpio_port[0], 1); if (gpio_is_valid(pdata->ehci_data->reset_gpio_port[1])) gpio_set_value (pdata->ehci_data->reset_gpio_port[1], 1); } end_count: omap->count++; spin_unlock_irqrestore(&omap->lock, flags); return 0; err_tll: if (pdata->ehci_data->phy_reset) { if (gpio_is_valid(pdata->ehci_data->reset_gpio_port[0])) gpio_free(pdata->ehci_data->reset_gpio_port[0]); if (gpio_is_valid(pdata->ehci_data->reset_gpio_port[1])) gpio_free(pdata->ehci_data->reset_gpio_port[1]); } clk_disable(omap->usbtll_ick); clk_disable(omap->usbtll_fck); clk_disable(omap->usbhost_fs_fck); clk_disable(omap->usbhost_hs_fck); clk_disable(omap->usbhost_ick); spin_unlock_irqrestore(&omap->lock, flags); return ret; }
static void omap_usbhs_init(struct device *dev) { struct usbhs_hcd_omap *omap = dev_get_drvdata(dev); struct usbhs_omap_platform_data *pdata = &omap->platdata; unsigned long flags = 0; unsigned reg; dev_dbg(dev, "starting TI HSUSB Controller\n"); pm_runtime_get_sync(dev); spin_lock_irqsave(&omap->lock, flags); if (pdata->ehci_data->phy_reset) { if (gpio_is_valid(pdata->ehci_data->reset_gpio_port[0])) { gpio_request(pdata->ehci_data->reset_gpio_port[0], "USB1 PHY reset"); gpio_direction_output (pdata->ehci_data->reset_gpio_port[0], 0); } if (gpio_is_valid(pdata->ehci_data->reset_gpio_port[1])) { gpio_request(pdata->ehci_data->reset_gpio_port[1], "USB2 PHY reset"); gpio_direction_output (pdata->ehci_data->reset_gpio_port[1], 0); } /* Hold the PHY in RESET for enough time till DIR is high */ udelay(10); } omap->usbhs_rev = usbhs_read(omap->uhh_base, OMAP_UHH_REVISION); dev_dbg(dev, "OMAP UHH_REVISION 0x%x\n", omap->usbhs_rev); /* * Really enable the port clocks * first call of pm_runtime_get_sync does not enable these * port clocks; because omap->usbhs_rev was not available * This omap->usbhs_rev is available now! */ usbhs_runtime_resume(dev); reg = usbhs_read(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); /* Keep ENA_INCR_ALIGN = 0: Known to cause OCP delays */ reg &= ~OMAP_UHH_HOSTCONFIG_INCRX_ALIGN_EN; if (is_omap_usbhs_rev1(omap)) { if (pdata->port_mode[0] == OMAP_USBHS_PORT_MODE_UNUSED) reg &= ~OMAP_UHH_HOSTCONFIG_P1_CONNECT_STATUS; if (pdata->port_mode[1] == OMAP_USBHS_PORT_MODE_UNUSED) reg &= ~OMAP_UHH_HOSTCONFIG_P2_CONNECT_STATUS; if (pdata->port_mode[2] == OMAP_USBHS_PORT_MODE_UNUSED) 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(dev, "OMAP3 ES version <= ES2.1\n"); if (is_ehci_phy_mode(pdata->port_mode[0]) || is_ehci_phy_mode(pdata->port_mode[1]) || is_ehci_phy_mode(pdata->port_mode[2])) reg &= ~OMAP_UHH_HOSTCONFIG_ULPI_BYPASS; else reg |= OMAP_UHH_HOSTCONFIG_ULPI_BYPASS; } else { dev_dbg(dev, "OMAP3 ES version > ES2.1\n"); if (is_ehci_phy_mode(pdata->port_mode[0])) reg &= ~OMAP_UHH_HOSTCONFIG_ULPI_P1_BYPASS; else reg |= OMAP_UHH_HOSTCONFIG_ULPI_P1_BYPASS; if (is_ehci_phy_mode(pdata->port_mode[1])) reg &= ~OMAP_UHH_HOSTCONFIG_ULPI_P2_BYPASS; else reg |= OMAP_UHH_HOSTCONFIG_ULPI_P2_BYPASS; if (is_ehci_phy_mode(pdata->port_mode[2])) reg &= ~OMAP_UHH_HOSTCONFIG_ULPI_P3_BYPASS; else reg |= OMAP_UHH_HOSTCONFIG_ULPI_P3_BYPASS; } } else if (is_omap_usbhs_rev2(omap)) { /* Clear port mode fields for PHY mode*/ reg &= ~OMAP4_P1_MODE_CLEAR; reg &= ~OMAP4_P2_MODE_CLEAR; if (is_ehci_tll_mode(pdata->port_mode[0]) || (is_ohci_port(pdata->port_mode[0]))) reg |= OMAP4_P1_MODE_TLL; else if (is_ehci_hsic_mode(pdata->port_mode[0])) reg |= OMAP4_P1_MODE_HSIC; if (is_ehci_tll_mode(pdata->port_mode[1]) || (is_ohci_port(pdata->port_mode[1]))) reg |= OMAP4_P2_MODE_TLL; else if (is_ehci_hsic_mode(pdata->port_mode[1])) reg |= OMAP4_P2_MODE_HSIC; } usbhs_write(omap->uhh_base, OMAP_UHH_HOSTCONFIG, reg); dev_dbg(dev, "UHH setup done, uhh_hostconfig=%x\n", reg); if (is_ehci_tll_mode(pdata->port_mode[0]) || is_ehci_tll_mode(pdata->port_mode[1]) || is_ehci_tll_mode(pdata->port_mode[2]) || (is_ohci_port(pdata->port_mode[0])) || (is_ohci_port(pdata->port_mode[1])) || (is_ohci_port(pdata->port_mode[2]))) { /* Enable UTMI mode for required TLL channels */ if (is_omap_usbhs_rev2(omap)) usbhs_omap_tll_init(dev, OMAP_REV2_TLL_CHANNEL_COUNT); else usbhs_omap_tll_init(dev, OMAP_TLL_CHANNEL_COUNT); } if (pdata->ehci_data->phy_reset) { /* Hold the PHY in RESET for enough time till * PHY is settled and ready */ udelay(10); if (gpio_is_valid(pdata->ehci_data->reset_gpio_port[0])) gpio_set_value (pdata->ehci_data->reset_gpio_port[0], 1); if (gpio_is_valid(pdata->ehci_data->reset_gpio_port[1])) gpio_set_value (pdata->ehci_data->reset_gpio_port[1], 1); } spin_unlock_irqrestore(&omap->lock, flags); pm_runtime_put_sync(dev); }