From: Arun Ramamurthy <arunr...@broadcom.com> Added support for cases where one controller is connected to multiple phys
Signed-off-by: Arun Ramamurthy <arunr...@broadcom.com> Reviewed-by: Ray Jui <r...@broadcom.com> Reviewed-by: Scott Branden <sbran...@broadcom.com> Tested-by: Scott Branden <sbran...@broadcom.com> --- drivers/usb/host/ohci-platform.c | 82 +++++++++++++++++++++++++++++----------- 1 file changed, 60 insertions(+), 22 deletions(-) diff --git a/drivers/usb/host/ohci-platform.c b/drivers/usb/host/ohci-platform.c index b81d202..613d54e 100644 --- a/drivers/usb/host/ohci-platform.c +++ b/drivers/usb/host/ohci-platform.c @@ -38,7 +38,8 @@ struct ohci_platform_priv { struct clk *clks[OHCI_MAX_CLKS]; struct reset_control *rst; - struct phy *phy; + struct phy **phys; + int num_phys; }; static const char hcd_name[] = "ohci-platform"; @@ -47,7 +48,7 @@ static int ohci_platform_power_on(struct platform_device *dev) { struct usb_hcd *hcd = platform_get_drvdata(dev); struct ohci_platform_priv *priv = hcd_to_ohci_priv(hcd); - int clk, ret; + int clk, ret, phy_num; for (clk = 0; clk < OHCI_MAX_CLKS && priv->clks[clk]; clk++) { ret = clk_prepare_enable(priv->clks[clk]); @@ -55,20 +56,28 @@ static int ohci_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]); @@ -80,11 +89,13 @@ static void ohci_platform_power_off(struct platform_device *dev) { struct usb_hcd *hcd = platform_get_drvdata(dev); struct ohci_platform_priv *priv = hcd_to_ohci_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 = OHCI_MAX_CLKS - 1; clk >= 0; clk--) @@ -112,7 +123,8 @@ static int ohci_platform_probe(struct platform_device *dev) struct usb_ohci_pdata *pdata = dev_get_platdata(&dev->dev); struct ohci_platform_priv *priv; struct ohci_hcd *ohci; - int err, irq, clk = 0; + const char *phy_name; + int err, irq, phy_num, clk = 0; if (usb_disabled()) return -ENODEV; @@ -160,12 +172,38 @@ static int ohci_platform_probe(struct platform_device *dev) of_property_read_u32(dev->dev.of_node, "num-ports", &ohci->num_ports); - 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; + 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 < OHCI_MAX_CLKS; clk++) { -- 2.2.2 -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/