diff options
author | Marek Szyprowski <m.szyprowski@samsung.com> | 2014-05-08 07:45:59 +0200 |
---|---|---|
committer | Marek Szyprowski <m.szyprowski@samsung.com> | 2014-05-13 05:53:59 -0700 |
commit | 784fdc692477e531df3ff3359cbd26fa75677016 (patch) | |
tree | 8e42944e5ee453c084f4c8a2f65f1db15d89c627 | |
parent | d2f744a23357e447d1f1875354cc6f58bd10b35c (diff) | |
download | linux-3.10-784fdc692477e531df3ff3359cbd26fa75677016.tar.gz linux-3.10-784fdc692477e531df3ff3359cbd26fa75677016.tar.bz2 linux-3.10-784fdc692477e531df3ff3359cbd26fa75677016.zip |
usb: s5p-ehci: add support for more than one usb phy
Based on 'usb: ehci-exynos: Change to use phy provided by the generic
phy framework' patch posted to usb ml.
Signed-off-by: Marek Szyprowski <m.szyprowski@samsung.com>
Change-Id: I5f7574c0659905148f6e7af95ecd197e92e03d16
-rw-r--r-- | drivers/usb/host/ehci-s5p.c | 105 |
1 files changed, 55 insertions, 50 deletions
diff --git a/drivers/usb/host/ehci-s5p.c b/drivers/usb/host/ehci-s5p.c index c321a3b0b6a..cd1282443c8 100644 --- a/drivers/usb/host/ehci-s5p.c +++ b/drivers/usb/host/ehci-s5p.c @@ -53,35 +53,45 @@ static const char * const s5p_ehci_supply_names[] = { "vusb_a", /* analog USB supply */ }; +#define PHY_NUMBER 3 struct s5p_ehci_hcd { struct clk *clk1; struct clk *clk2; int power_on; - struct phy *phy; - struct usb_otg *otg; - struct usb_bus *host; - struct s5p_ehci_platdata *pdata; + struct phy *phy[PHY_NUMBER]; struct regulator_bulk_data supplies[ARRAY_SIZE(s5p_ehci_supply_names)]; }; #define to_s5p_ehci(hcd) (struct s5p_ehci_hcd *)(hcd_to_ehci(hcd)->priv) -static void s5p_ehci_phy_enable(struct s5p_ehci_hcd *s5p_ehci, - struct platform_device *pdev) +static int s5p_ehci_phy_enable(struct s5p_ehci_hcd *s5p_ehci) { - if (s5p_ehci->phy) - phy_power_on(s5p_ehci->phy); - else if (s5p_ehci->pdata->phy_init) - s5p_ehci->pdata->phy_init(pdev, USB_PHY_TYPE_HOST); + struct phy **p = s5p_ehci->phy; + int i; + int ret = 0; + + for (i = 0; ret == 0 && i < PHY_NUMBER; i++) + if (p[i]) + ret = phy_power_on(p[i]); + if (ret) + for (i--; i > 0; i--) + if (p[i]) + phy_power_off(p[i]); + + return ret; } -static void s5p_ehci_phy_disable(struct s5p_ehci_hcd *s5p_ehci, - struct platform_device *pdev) +static int s5p_ehci_phy_disable(struct s5p_ehci_hcd *s5p_ehci) { - if (s5p_ehci->phy) - phy_power_off(s5p_ehci->phy); - else if (s5p_ehci->pdata->phy_exit) - s5p_ehci->pdata->phy_exit(pdev, USB_PHY_TYPE_HOST); + struct phy **p = s5p_ehci->phy; + int i; + int ret = 0; + + for (i = 0; ret == 0 && i < PHY_NUMBER; i++) + if (p[i]) + ret = phy_power_off(p[i]); + + return ret; } static ssize_t show_ehci_power(struct device *dev, @@ -137,14 +147,14 @@ static ssize_t store_ehci_power(struct device *dev, s5p_ehci->power_on = 0; usb_remove_hcd(hcd); - s5p_ehci_phy_disable(s5p_ehci, pdev); + s5p_ehci_phy_disable(s5p_ehci); } else if (power_on) { printk(KERN_DEBUG "%s: EHCI turns on\n", __func__); if (s5p_ehci->power_on) { usb_remove_hcd(hcd); } - s5p_ehci_phy_enable(s5p_ehci, pdev); + s5p_ehci_phy_enable(s5p_ehci); s5p_ehci_configurate(hcd); @@ -197,13 +207,13 @@ static void s5p_setup_vbus_gpio(struct platform_device *pdev) static int s5p_ehci_probe(struct platform_device *pdev) { - struct s5p_ehci_platdata *pdata = pdev->dev.platform_data; struct s5p_ehci_hcd *s5p_ehci; struct phy *phy; + struct device_node *child; struct usb_hcd *hcd; struct ehci_hcd *ehci; struct resource *res; - const char *phy_name; + int phy_number; int irq; int err; int i; @@ -227,20 +237,27 @@ static int s5p_ehci_probe(struct platform_device *pdev) return -ENOMEM; } s5p_ehci = to_s5p_ehci(hcd); - phy_name = of_get_property(pdev->dev.of_node, "phy-names", NULL); - phy = devm_phy_get(&pdev->dev, phy_name); - if (IS_ERR(phy)) { - /* Fallback to pdata */ - if (!pdata) { - usb_put_hcd(hcd); - dev_warn(&pdev->dev, "no platform data or transceiver defined\n"); - return -EPROBE_DEFER; - } else { - s5p_ehci->pdata = pdata; + + for_each_available_child_of_node(pdev->dev.of_node, child) { + err = of_property_read_u32(child, "reg", &phy_number); + if (err) { + dev_err(&pdev->dev, "Failed to parse device tree\n"); + of_node_put(child); + return err; } - } else { - s5p_ehci->phy = phy; -/* s5p_ehci->otg = phy->otg;*/ + if (phy_number >= PHY_NUMBER) { + dev_err(&pdev->dev, "Failed to parse device tree - number out of range\n"); + of_node_put(child); + return -EINVAL; + } + phy = devm_of_phy_get(&pdev->dev, child, 0); + of_node_put(child); + if (IS_ERR(phy)) { + dev_err(&pdev->dev, "Failed to get phy number %d", + phy_number); + return PTR_ERR(phy); + } + s5p_ehci->phy[phy_number] = phy; } s5p_ehci->clk1 = devm_clk_get(&pdev->dev, "usbhost"); @@ -290,7 +307,6 @@ static int s5p_ehci_probe(struct platform_device *pdev) goto fail_io; } - s5p_ehci->host = &hcd->self; /* regulators */ for (i = 0; i < ARRAY_SIZE(s5p_ehci->supplies); i++) s5p_ehci->supplies[i].supply = s5p_ehci_supply_names[i]; @@ -311,7 +327,7 @@ static int s5p_ehci_probe(struct platform_device *pdev) } - s5p_ehci_phy_enable(s5p_ehci, pdev); + s5p_ehci_phy_enable(s5p_ehci); ehci = hcd_to_ehci(hcd); ehci->caps = hcd->regs; @@ -333,7 +349,7 @@ static int s5p_ehci_probe(struct platform_device *pdev) return 0; fail_add_hcd: - s5p_ehci_phy_disable(s5p_ehci, pdev); + s5p_ehci_phy_disable(s5p_ehci); regulator_bulk_disable(ARRAY_SIZE(s5p_ehci->supplies), s5p_ehci->supplies); fail_enable_reg: @@ -356,10 +372,7 @@ static int s5p_ehci_remove(struct platform_device *pdev) remove_ehci_sys_file(hcd_to_ehci(hcd)); usb_remove_hcd(hcd); - if (s5p_ehci->otg) - s5p_ehci->otg->set_host(s5p_ehci->otg, &hcd->self); - - s5p_ehci_phy_disable(s5p_ehci, pdev); + s5p_ehci_phy_disable(s5p_ehci); clk_disable_unprepare(s5p_ehci->clk1); clk_disable_unprepare(s5p_ehci->clk2); @@ -384,17 +397,13 @@ static int s5p_ehci_suspend(struct device *dev) { struct usb_hcd *hcd = dev_get_drvdata(dev); struct s5p_ehci_hcd *s5p_ehci = to_s5p_ehci(hcd); - struct platform_device *pdev = to_platform_device(dev); bool do_wakeup = device_may_wakeup(dev); int rc; rc = ehci_suspend(hcd, do_wakeup); - if (s5p_ehci->otg) - s5p_ehci->otg->set_host(s5p_ehci->otg, &hcd->self); - - s5p_ehci_phy_disable(s5p_ehci, pdev); + s5p_ehci_phy_disable(s5p_ehci); clk_disable_unprepare(s5p_ehci->clk1); clk_disable_unprepare(s5p_ehci->clk2); @@ -406,15 +415,11 @@ static int s5p_ehci_resume(struct device *dev) { struct usb_hcd *hcd = dev_get_drvdata(dev); struct s5p_ehci_hcd *s5p_ehci = to_s5p_ehci(hcd); - struct platform_device *pdev = to_platform_device(dev); clk_prepare_enable(s5p_ehci->clk1); clk_prepare_enable(s5p_ehci->clk2); - if (s5p_ehci->otg) - s5p_ehci->otg->set_host(s5p_ehci->otg, &hcd->self); - - s5p_ehci_phy_enable(s5p_ehci, pdev); + s5p_ehci_phy_enable(s5p_ehci); /* DMA burst Enable */ writel(EHCI_INSNREG00_ENABLE_DMA_BURST, EHCI_INSNREG00(hcd->regs)); |