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> --- drivers/usb/host/ohci-platform.c | 70 ++++++++++++++++++++++++++++------------ k 1 file changed, 49 insertions(+), 21 deletions(-) diff --git a/drivers/usb/host/ohci-platform.c b/drivers/usb/host/ohci-platform.c index 4369299..eef82f1 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;x + struct phy *phys; + int num_phys; }; static const char hcd_name[] = "ohci-platform"; @@ -61,7 +62,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]); @@ -69,20 +70,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) + for (phy_num = 0; phy_num < priv->num_phys; phy_num++) { + ret = phy_init(&priv->phys[phy_num]); + if (ret) { + if (phy_num == 0) + goto err_disable_clks; + else + 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) { + 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]); @@ -94,11 +103,11 @@ 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++) { + phy_power_off(&priv->phys[phy_num]); + phy_exit(&priv->phys[phy_num]); } for (clk = OHCI_MAX_CLKS - 1; clk >= 0; clk--) @@ -127,7 +136,9 @@ 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; + struct phy *temp_phy; + const char *phy_name; + int err, irq, phy_num, clk = 0; if (usb_disabled()) return -ENODEV; @@ -175,12 +186,29 @@ static int ohci_platform_probe(struct platform_device *dev) if (of_property_read_bool(dev->dev.of_node, "big-endian")) ohci->flags |= OHCI_QUIRK_BE_MMIO | OHCI_QUIRK_BE_DESC; - 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"); + if (priv->num_phys > 0) { + priv->phys = devm_kcalloc(&dev->dev, priv->num_phys, + sizeof(struct phy), GFP_KERNEL); + 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) { + dev_err(&dev->dev, "Phy-names not provided"); + goto err_put_hcd; + } + + temp_phy = devm_of_phy_get(&dev->dev, + dev->dev.of_node, phy_name); + if (IS_ERR(temp_phy)) { + err = PTR_ERR(temp_phy); + goto err_put_hcd; + } else + priv->phys[phy_num] = *temp_phy; + } } for (clk = 0; clk < OHCI_MAX_CLKS; clk++) { -- 2.2.0 -- To unsubscribe from this list: send the line "unsubscribe linux-usb" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html