The USB2 Host device node is extracted and used in the probe of the driver to initialize the usb ports and controller. The platform specific initialization is also performed. Signed-off-by: Keshava Munegowda <keshava_mgowda@xxxxxx> --- arch/arm/mach-omap2/usb-host.c | 2 - drivers/mfd/omap-usb-host.c | 163 +++++++++++++++++++++++--------- include/linux/platform_data/usb-omap.h | 19 +++- 3 files changed, 133 insertions(+), 51 deletions(-) diff --git a/arch/arm/mach-omap2/usb-host.c b/arch/arm/mach-omap2/usb-host.c index d1dbe12..239c175 100644 --- a/arch/arm/mach-omap2/usb-host.c +++ b/arch/arm/mach-omap2/usb-host.c @@ -502,8 +502,6 @@ void __init usbhs_init(const struct usbhs_omap_board_data *pdata) } ehci_data.phy_reset = pdata->phy_reset; ohci_data.es2_compatibility = pdata->es2_compatibility; - usbhs_data.ehci_data = &ehci_data; - usbhs_data.ohci_data = &ohci_data; if (cpu_is_omap34xx()) { setup_ehci_io_mux(pdata->port_mode); diff --git a/drivers/mfd/omap-usb-host.c b/drivers/mfd/omap-usb-host.c index cebfe0a..4b3af16 100644 --- a/drivers/mfd/omap-usb-host.c +++ b/drivers/mfd/omap-usb-host.c @@ -24,7 +24,7 @@ #include <linux/clk.h> #include <linux/dma-mapping.h> #include <linux/spinlock.h> -#include <linux/gpio.h> +#include <linux/of_gpio.h> #include <plat/cpu.h> #include <linux/platform_device.h> #include <linux/platform_data/usb-omap.h> @@ -103,8 +103,6 @@ struct usbhs_hcd_omap { void __iomem *uhh_base; - struct usbhs_omap_platform_data platdata; - u32 usbhs_rev; spinlock_t lock; }; @@ -186,8 +184,6 @@ static int omap_usbhs_alloc_children(struct platform_device *pdev) { struct device *dev = &pdev->dev; struct usbhs_hcd_omap *omap; - struct ehci_hcd_omap_platform_data *ehci_data; - struct ohci_hcd_omap_platform_data *ohci_data; struct platform_device *ehci; struct platform_device *ohci; struct resource *res; @@ -195,8 +191,6 @@ static int omap_usbhs_alloc_children(struct platform_device *pdev) int ret; omap = platform_get_drvdata(pdev); - ehci_data = omap->platdata.ehci_data; - ohci_data = omap->platdata.ohci_data; res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "ehci"); if (!res) { @@ -214,8 +208,8 @@ static int omap_usbhs_alloc_children(struct platform_device *pdev) } resources[1] = *res; - ehci = omap_usbhs_alloc_child(OMAP_EHCI_DEVICE, resources, 2, ehci_data, - sizeof(*ehci_data), dev); + ehci = omap_usbhs_alloc_child(OMAP_EHCI_DEVICE, resources, 2, NULL, + 0, dev); if (!ehci) { dev_err(dev, "omap_usbhs_alloc_child failed\n"); @@ -239,8 +233,8 @@ static int omap_usbhs_alloc_children(struct platform_device *pdev) } resources[1] = *res; - ohci = omap_usbhs_alloc_child(OMAP_OHCI_DEVICE, resources, 2, ohci_data, - sizeof(*ohci_data), dev); + ohci = omap_usbhs_alloc_child(OMAP_OHCI_DEVICE, resources, 2, NULL, + 0, dev); if (!ohci) { dev_err(dev, "omap_usbhs_alloc_child failed\n"); ret = -ENOMEM; @@ -279,7 +273,7 @@ static bool is_ohci_port(enum usbhs_omap_port_mode pmode) static int usbhs_runtime_resume(struct device *dev) { struct usbhs_hcd_omap *omap = dev_get_drvdata(dev); - struct usbhs_omap_platform_data *pdata = &omap->platdata; + struct usbhs_omap_platform_data *pdata = dev->platform_data; unsigned long flags; dev_dbg(dev, "usbhs_runtime_resume\n"); @@ -295,6 +289,7 @@ static int usbhs_runtime_resume(struct device *dev) if (omap->ehci_logic_fck && !IS_ERR(omap->ehci_logic_fck)) clk_enable(omap->ehci_logic_fck); + clk_enable(pdata->hub_clk); if (is_ehci_tll_mode(pdata->port_mode[0])) clk_enable(omap->usbhost_p1_fck); if (is_ehci_tll_mode(pdata->port_mode[1])) @@ -311,7 +306,7 @@ static int usbhs_runtime_resume(struct device *dev) static int usbhs_runtime_suspend(struct device *dev) { struct usbhs_hcd_omap *omap = dev_get_drvdata(dev); - struct usbhs_omap_platform_data *pdata = &omap->platdata; + struct usbhs_omap_platform_data *pdata = dev->platform_data; unsigned long flags; dev_dbg(dev, "usbhs_runtime_suspend\n"); @@ -331,6 +326,7 @@ static int usbhs_runtime_suspend(struct device *dev) clk_disable(omap->utmi_p2_fck); clk_disable(omap->utmi_p1_fck); + clk_disable(pdata->hub_clk); if (omap->ehci_logic_fck && !IS_ERR(omap->ehci_logic_fck)) clk_disable(omap->ehci_logic_fck); @@ -343,19 +339,29 @@ static int usbhs_runtime_suspend(struct device *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; + struct usbhs_omap_platform_data *pdata = dev->platform_data; unsigned long flags; unsigned reg; dev_dbg(dev, "starting TI HSUSB Controller\n"); - 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], + if (gpio_is_valid(pdata->hub_power_gpio)) + gpio_request_one(pdata->hub_power_gpio, GPIOF_OUT_INIT_HIGH, + "Hub Power"); + if (gpio_is_valid(pdata->hub_reset_gpio)) { + gpio_request_one(pdata->hub_reset_gpio, GPIOF_OUT_INIT_LOW, + "Hub Reset Power"); + udelay(5); + gpio_set_value_cansleep(pdata->hub_reset_gpio, 1); + } + + if (pdata->phy_reset) { + if (gpio_is_valid(pdata->reset_gpio[0])) + gpio_request_one(pdata->reset_gpio[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], + if (gpio_is_valid(pdata->reset_gpio[1])) + gpio_request_one(pdata->reset_gpio[1], GPIOF_OUT_INIT_LOW, "USB2 PHY reset"); /* Hold the PHY in RESET for enough time till DIR is high */ @@ -431,36 +437,85 @@ static void omap_usbhs_init(struct device *dev) spin_unlock_irqrestore(&omap->lock, flags); pm_runtime_put_sync(dev); - if (pdata->ehci_data->phy_reset) { + if (pdata->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])) + if (gpio_is_valid(pdata->reset_gpio[0])) gpio_set_value_cansleep - (pdata->ehci_data->reset_gpio_port[0], 1); + (pdata->reset_gpio[0], 1); - if (gpio_is_valid(pdata->ehci_data->reset_gpio_port[1])) + if (gpio_is_valid(pdata->reset_gpio[1])) gpio_set_value_cansleep - (pdata->ehci_data->reset_gpio_port[1], 1); + (pdata->reset_gpio[1], 1); } } static void omap_usbhs_deinit(struct device *dev) { - struct usbhs_hcd_omap *omap = dev_get_drvdata(dev); - struct usbhs_omap_platform_data *pdata = &omap->platdata; + struct usbhs_omap_platform_data *pdata = dev->platform_data; - 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 (pdata->phy_reset) { + if (gpio_is_valid(pdata->reset_gpio[0])) + gpio_free(pdata->reset_gpio[0]); - if (gpio_is_valid(pdata->ehci_data->reset_gpio_port[1])) - gpio_free(pdata->ehci_data->reset_gpio_port[1]); + if (gpio_is_valid(pdata->reset_gpio[1])) + gpio_free(pdata->reset_gpio[1]); } } +static struct usbhs_omap_platform_data *of_get_usbhs_pdata(struct device *dev) +{ + struct usbhs_omap_platform_data *pdata; + struct device_node *np = dev->of_node; + struct property *pp; + char hubclk[20]; + + pdata = devm_kzalloc(dev, sizeof(*pdata), GFP_KERNEL); + if (!pdata) + return NULL; /* out of memory */ + + of_property_read_u32(np, "port-0", &pdata->port_mode[0]); + of_property_read_u32(np, "port-1", &pdata->port_mode[1]); + of_property_read_u32(np, "port-2", &pdata->port_mode[2]); + pdata->reset_gpio[0] = of_get_named_gpio(np, "reset-gpio-1", 0); + pdata->reset_gpio[1] = of_get_named_gpio(np, "reset-gpio-2", 0); + pdata->reset_gpio[2] = of_get_named_gpio(np, "reset-gpio-3", 0); + + if (gpio_is_valid(pdata->reset_gpio[0]) || + gpio_is_valid(pdata->reset_gpio[1]) || + gpio_is_valid(pdata->reset_gpio[2])) + pdata->phy_reset = true; + + pp = of_find_property(np, "hub-clk", NULL); + if (pp) { + strncpy(hubclk, pp->value, 20); + pdata->hub_clk = clk_get(NULL, hubclk); + if (IS_ERR(pdata->hub_clk)) { + dev_err(dev, "hub clk failed error: %ld\n", + PTR_ERR(pdata->hub_clk)); + goto err_end; + } + } else { + pdata->hub_clk = NULL; + } + if (pdata->hub_clk) { + of_property_read_u32(np, "hub-clkrate", &pdata->hub_clkrate); + clk_set_rate(pdata->hub_clk, pdata->hub_clkrate); + } + + pdata->hub_power_gpio = of_get_named_gpio(np, "hub-power-gpio", 0); + pdata->hub_reset_gpio = of_get_named_gpio(np, "hub-reset-gpio", 0); + + return pdata; + +err_end: + devm_kfree(dev, pdata); + return NULL; +} + /** * usbhs_omap_probe - initialize TI-based HCDs @@ -470,14 +525,16 @@ static void omap_usbhs_deinit(struct device *dev) static int __devinit usbhs_omap_probe(struct platform_device *pdev) { struct device *dev = &pdev->dev; - struct usbhs_omap_platform_data *pdata = dev->platform_data; + struct usbhs_omap_platform_data *pdata; struct usbhs_hcd_omap *omap; struct resource *res; int ret = 0; int i; + + pdata = of_get_usbhs_pdata(dev); if (!pdata) { - dev_err(dev, "Missing platform data\n"); + dev_err(dev, "function of_get_usbhs_pdata failed\n"); ret = -ENOMEM; goto end_probe; } @@ -486,20 +543,13 @@ static int __devinit usbhs_omap_probe(struct platform_device *pdev) if (!omap) { dev_err(dev, "Memory allocation failed\n"); ret = -ENOMEM; - goto end_probe; + goto err_pdata; } spin_lock_init(&omap->lock); - for (i = 0; i < OMAP3_HS_USB_PORTS; i++) - omap->platdata.port_mode[i] = pdata->port_mode[i]; - - omap->platdata.ehci_data = pdata->ehci_data; - omap->platdata.ohci_data = pdata->ohci_data; - pm_runtime_enable(dev); - for (i = 0; i < OMAP3_HS_USB_PORTS; i++) if (is_ehci_phy_mode(i) || is_ehci_tll_mode(i) || is_ehci_hsic_mode(i)) { @@ -516,7 +566,7 @@ static int __devinit usbhs_omap_probe(struct platform_device *pdev) if (IS_ERR(omap->utmi_p1_fck)) { ret = PTR_ERR(omap->utmi_p1_fck); dev_err(dev, "utmi_p1_gfclk failed error:%d\n", ret); - goto err_end; + goto err_ehci_fck; } omap->xclk60mhsp1_ck = clk_get(dev, "xclk60mhsp1_ck"); @@ -605,6 +655,7 @@ static int __devinit usbhs_omap_probe(struct platform_device *pdev) } platform_set_drvdata(pdev, omap); + dev->platform_data = pdata; omap_usbhs_init(dev); ret = omap_usbhs_alloc_children(pdev); @@ -640,11 +691,15 @@ err_xclk60mhsp1_ck: err_utmi_p1_fck: clk_put(omap->utmi_p1_fck); -err_end: +err_ehci_fck: clk_put(omap->ehci_logic_fck); pm_runtime_disable(dev); kfree(omap); +err_pdata: + clk_put(pdata->hub_clk); + devm_kfree(dev, pdata); + end_probe: return ret; } @@ -657,9 +712,11 @@ end_probe: */ static int __devexit usbhs_omap_remove(struct platform_device *pdev) { - struct usbhs_hcd_omap *omap = platform_get_drvdata(pdev); + struct device *dev = &pdev->dev; + struct usbhs_hcd_omap *omap = platform_get_drvdata(pdev); + struct usbhs_omap_platform_data *pdata = dev->platform_data; - omap_usbhs_deinit(&pdev->dev); + omap_usbhs_deinit(dev); iounmap(omap->uhh_base); clk_put(omap->init_60m_fclk); clk_put(omap->usbhost_p2_fck); @@ -669,7 +726,9 @@ static int __devexit usbhs_omap_remove(struct platform_device *pdev) clk_put(omap->xclk60mhsp1_ck); clk_put(omap->utmi_p1_fck); clk_put(omap->ehci_logic_fck); - pm_runtime_disable(&pdev->dev); + pm_runtime_disable(dev); + clk_put(pdata->hub_clk); + devm_kfree(dev, pdata); kfree(omap); return 0; @@ -680,11 +739,23 @@ static const struct dev_pm_ops usbhsomap_dev_pm_ops = { .runtime_resume = usbhs_runtime_resume, }; +#ifdef CONFIG_OF +static const struct of_device_id omap_usbhs_of_match[] = { + { + .compatible = "ti,usbhs", + }, + {}, +}; +MODULE_DEVICE_TABLE(of, omap_usbhs_of_match); + +#endif + static struct platform_driver usbhs_omap_driver = { .driver = { .name = (char *)usbhs_driver_name, .owner = THIS_MODULE, .pm = &usbhsomap_dev_pm_ops, + .of_match_table = of_match_ptr(omap_usbhs_of_match), }, .remove = __exit_p(usbhs_omap_remove), }; diff --git a/include/linux/platform_data/usb-omap.h b/include/linux/platform_data/usb-omap.h index 8570bcf..04dcf67 100644 --- a/include/linux/platform_data/usb-omap.h +++ b/include/linux/platform_data/usb-omap.h @@ -55,10 +55,23 @@ struct ohci_hcd_omap_platform_data { }; struct usbhs_omap_platform_data { - enum usbhs_omap_port_mode port_mode[OMAP3_HS_USB_PORTS]; + enum usbhs_omap_port_mode port_mode[OMAP3_HS_USB_PORTS]; + int reset_gpio[OMAP3_HS_USB_PORTS]; + + /* + * Regulators for USB PHYs. + * Each PHY can have a separate regulator. + */ + struct regulator *regulator[OMAP3_HS_USB_PORTS]; - struct ehci_hcd_omap_platform_data *ehci_data; - struct ohci_hcd_omap_platform_data *ohci_data; + unsigned phy_reset:1; + + /* Set this to true for ES2.x silicon */ + unsigned es2_compatibility:1; + struct clk *hub_clk; + int hub_clkrate; + int hub_power_gpio; + int hub_reset_gpio; }; /*-------------------------------------------------------------------------*/ -- 1.7.9.5 -- To unsubscribe from this list: send the line "unsubscribe linux-omap" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html