diff options
Diffstat (limited to 'drivers/usb/host/ehci-platform.c')
-rw-r--r-- | drivers/usb/host/ehci-platform.c | 92 |
1 files changed, 68 insertions, 24 deletions
diff --git a/drivers/usb/host/ehci-platform.c b/drivers/usb/host/ehci-platform.c index 8557803e615..d8a75a51d6d 100644 --- a/drivers/usb/host/ehci-platform.c +++ b/drivers/usb/host/ehci-platform.c @@ -43,7 +43,8 @@ struct ehci_platform_priv { struct clk *clks[EHCI_MAX_CLKS]; struct reset_control *rst; - struct phy *phy; + struct phy **phys; + int num_phys; }; static const char hcd_name[] = "ehci-platform"; @@ -78,7 +79,7 @@ static int ehci_platform_power_on(struct platform_device *dev) { struct usb_hcd *hcd = platform_get_drvdata(dev); struct ehci_platform_priv *priv = hcd_to_ehci_priv(hcd); - int clk, ret; + int clk, ret, phy_num; for (clk = 0; clk < EHCI_MAX_CLKS && priv->clks[clk]; clk++) { ret = clk_prepare_enable(priv->clks[clk]); @@ -86,20 +87,28 @@ static int ehci_platform_power_on(struct platform_device *dev) goto err_disable_clks; } - if (priv->phy) { - ret = phy_init(priv->phy); - if (ret) - goto err_disable_clks; - - ret = phy_power_on(priv->phy); - if (ret) - goto err_exit_phy; + for (phy_num = 0; phy_num < priv->num_phys; phy_num++) { + if (priv->phys[phy_num]) { + ret = phy_init(priv->phys[phy_num]); + if (ret) + goto err_exit_phy; + ret = phy_power_on(priv->phys[phy_num]); + if (ret) { + phy_exit(priv->phys[phy_num]); + goto err_exit_phy; + } + } } return 0; err_exit_phy: - phy_exit(priv->phy); + while (--phy_num >= 0) { + if (priv->phys[phy_num]) { + phy_power_off(priv->phys[phy_num]); + phy_exit(priv->phys[phy_num]); + } + } err_disable_clks: while (--clk >= 0) clk_disable_unprepare(priv->clks[clk]); @@ -111,11 +120,13 @@ static void ehci_platform_power_off(struct platform_device *dev) { struct usb_hcd *hcd = platform_get_drvdata(dev); struct ehci_platform_priv *priv = hcd_to_ehci_priv(hcd); - int clk; + int clk, phy_num; - if (priv->phy) { - phy_power_off(priv->phy); - phy_exit(priv->phy); + for (phy_num = 0; phy_num < priv->num_phys; phy_num++) { + if (priv->phys[phy_num]) { + phy_power_off(priv->phys[phy_num]); + phy_exit(priv->phys[phy_num]); + } } for (clk = EHCI_MAX_CLKS - 1; clk >= 0; clk--) @@ -143,7 +154,8 @@ static int ehci_platform_probe(struct platform_device *dev) struct usb_ehci_pdata *pdata = dev_get_platdata(&dev->dev); struct ehci_platform_priv *priv; struct ehci_hcd *ehci; - int err, irq, clk = 0; + const char *phy_name; + int err, irq, phy_num, clk = 0; if (usb_disabled()) return -ENODEV; @@ -155,7 +167,8 @@ static int ehci_platform_probe(struct platform_device *dev) if (!pdata) pdata = &ehci_platform_defaults; - err = dma_coerce_mask_and_coherent(&dev->dev, DMA_BIT_MASK(32)); + err = dma_coerce_mask_and_coherent(&dev->dev, + pdata->dma_mask_64 ? DMA_BIT_MASK(64) : DMA_BIT_MASK(32)); if (err) return err; @@ -185,12 +198,42 @@ static int ehci_platform_probe(struct platform_device *dev) if (of_property_read_bool(dev->dev.of_node, "big-endian")) ehci->big_endian_mmio = ehci->big_endian_desc = 1; - priv->phy = devm_phy_get(&dev->dev, "usb"); - if (IS_ERR(priv->phy)) { - err = PTR_ERR(priv->phy); - if (err == -EPROBE_DEFER) - goto err_put_hcd; - priv->phy = NULL; + if (of_property_read_bool(dev->dev.of_node, + "needs-reset-on-resume")) + pdata->reset_on_resume = 1; + + priv->num_phys = of_count_phandle_with_args(dev->dev.of_node, + "phys", "#phy-cells"); + priv->num_phys = priv->num_phys > 0 ? priv->num_phys : 1; + + priv->phys = devm_kcalloc(&dev->dev, priv->num_phys, + sizeof(struct phy *), GFP_KERNEL); + if (!priv->phys) + return -ENOMEM; + + for (phy_num = 0; phy_num < priv->num_phys; phy_num++) { + err = of_property_read_string_index( + dev->dev.of_node, + "phy-names", phy_num, + &phy_name); + + if (err < 0) { + if (priv->num_phys > 1) { + dev_err(&dev->dev, "phy-names not provided"); + goto err_put_hcd; + } else + phy_name = "usb"; + } + + priv->phys[phy_num] = devm_phy_get(&dev->dev, + phy_name); + if (IS_ERR(priv->phys[phy_num])) { + err = PTR_ERR(priv->phys[phy_num]); + if ((priv->num_phys > 1) || + (err == -EPROBE_DEFER)) + goto err_put_hcd; + priv->phys[phy_num] = NULL; + } } for (clk = 0; clk < EHCI_MAX_CLKS; clk++) { @@ -340,7 +383,7 @@ static int ehci_platform_resume(struct device *dev) return err; } - ehci_resume(hcd, false); + ehci_resume(hcd, pdata->reset_on_resume); return 0; } #endif /* CONFIG_PM_SLEEP */ @@ -349,6 +392,7 @@ static const struct of_device_id vt8500_ehci_ids[] = { { .compatible = "via,vt8500-ehci", }, { .compatible = "wm,prizm-ehci", }, { .compatible = "generic-ehci", }, + { .compatible = "cavium,octeon-6335-ehci", }, {} }; MODULE_DEVICE_TABLE(of, vt8500_ehci_ids); |