aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorArun Ramamurthy <arunrama@broadcom.com>2015-01-19 19:05:29 -0500
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2015-01-25 08:05:10 -0500
commit7e7a0e67f2c2104fb7515008fb2ba72ffb10b493 (patch)
treeabc2414404d44d4b8da4064b6d1d02c849e9e9cc
parent85cd690d7e08159e8e4d737317a5e8a96140d687 (diff)
usb: ehci-platform: add support for multiple phys per controller
Added support for cases where one controller is connected to multiple phys. Signed-off-by: Arun Ramamurthy <arunrama@broadcom.com> Reviewed-by: Ray Jui <rjui@broadcom.com> Reviewed-by: Scott Branden <sbranden@broadcom.com> Tested-by: Scott Branden <sbranden@broadcom.com> Acked-by: Alan Stern <stern@rowland.harvard.edu> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
-rw-r--r--drivers/usb/host/ehci-platform.c82
1 files changed, 60 insertions, 22 deletions
diff --git a/drivers/usb/host/ehci-platform.c b/drivers/usb/host/ehci-platform.c
index 63f2622926c4..d8a75a51d6d4 100644
--- a/drivers/usb/host/ehci-platform.c
+++ b/drivers/usb/host/ehci-platform.c
@@ -43,7 +43,8 @@
43struct ehci_platform_priv { 43struct ehci_platform_priv {
44 struct clk *clks[EHCI_MAX_CLKS]; 44 struct clk *clks[EHCI_MAX_CLKS];
45 struct reset_control *rst; 45 struct reset_control *rst;
46 struct phy *phy; 46 struct phy **phys;
47 int num_phys;
47}; 48};
48 49
49static const char hcd_name[] = "ehci-platform"; 50static const char hcd_name[] = "ehci-platform";
@@ -78,7 +79,7 @@ static int ehci_platform_power_on(struct platform_device *dev)
78{ 79{
79 struct usb_hcd *hcd = platform_get_drvdata(dev); 80 struct usb_hcd *hcd = platform_get_drvdata(dev);
80 struct ehci_platform_priv *priv = hcd_to_ehci_priv(hcd); 81 struct ehci_platform_priv *priv = hcd_to_ehci_priv(hcd);
81 int clk, ret; 82 int clk, ret, phy_num;
82 83
83 for (clk = 0; clk < EHCI_MAX_CLKS && priv->clks[clk]; clk++) { 84 for (clk = 0; clk < EHCI_MAX_CLKS && priv->clks[clk]; clk++) {
84 ret = clk_prepare_enable(priv->clks[clk]); 85 ret = clk_prepare_enable(priv->clks[clk]);
@@ -86,20 +87,28 @@ static int ehci_platform_power_on(struct platform_device *dev)
86 goto err_disable_clks; 87 goto err_disable_clks;
87 } 88 }
88 89
89 if (priv->phy) { 90 for (phy_num = 0; phy_num < priv->num_phys; phy_num++) {
90 ret = phy_init(priv->phy); 91 if (priv->phys[phy_num]) {
91 if (ret) 92 ret = phy_init(priv->phys[phy_num]);
92 goto err_disable_clks; 93 if (ret)
93 94 goto err_exit_phy;
94 ret = phy_power_on(priv->phy); 95 ret = phy_power_on(priv->phys[phy_num]);
95 if (ret) 96 if (ret) {
96 goto err_exit_phy; 97 phy_exit(priv->phys[phy_num]);
98 goto err_exit_phy;
99 }
100 }
97 } 101 }
98 102
99 return 0; 103 return 0;
100 104
101err_exit_phy: 105err_exit_phy:
102 phy_exit(priv->phy); 106 while (--phy_num >= 0) {
107 if (priv->phys[phy_num]) {
108 phy_power_off(priv->phys[phy_num]);
109 phy_exit(priv->phys[phy_num]);
110 }
111 }
103err_disable_clks: 112err_disable_clks:
104 while (--clk >= 0) 113 while (--clk >= 0)
105 clk_disable_unprepare(priv->clks[clk]); 114 clk_disable_unprepare(priv->clks[clk]);
@@ -111,11 +120,13 @@ static void ehci_platform_power_off(struct platform_device *dev)
111{ 120{
112 struct usb_hcd *hcd = platform_get_drvdata(dev); 121 struct usb_hcd *hcd = platform_get_drvdata(dev);
113 struct ehci_platform_priv *priv = hcd_to_ehci_priv(hcd); 122 struct ehci_platform_priv *priv = hcd_to_ehci_priv(hcd);
114 int clk; 123 int clk, phy_num;
115 124
116 if (priv->phy) { 125 for (phy_num = 0; phy_num < priv->num_phys; phy_num++) {
117 phy_power_off(priv->phy); 126 if (priv->phys[phy_num]) {
118 phy_exit(priv->phy); 127 phy_power_off(priv->phys[phy_num]);
128 phy_exit(priv->phys[phy_num]);
129 }
119 } 130 }
120 131
121 for (clk = EHCI_MAX_CLKS - 1; clk >= 0; clk--) 132 for (clk = EHCI_MAX_CLKS - 1; clk >= 0; clk--)
@@ -143,7 +154,8 @@ static int ehci_platform_probe(struct platform_device *dev)
143 struct usb_ehci_pdata *pdata = dev_get_platdata(&dev->dev); 154 struct usb_ehci_pdata *pdata = dev_get_platdata(&dev->dev);
144 struct ehci_platform_priv *priv; 155 struct ehci_platform_priv *priv;
145 struct ehci_hcd *ehci; 156 struct ehci_hcd *ehci;
146 int err, irq, clk = 0; 157 const char *phy_name;
158 int err, irq, phy_num, clk = 0;
147 159
148 if (usb_disabled()) 160 if (usb_disabled())
149 return -ENODEV; 161 return -ENODEV;
@@ -190,12 +202,38 @@ static int ehci_platform_probe(struct platform_device *dev)
190 "needs-reset-on-resume")) 202 "needs-reset-on-resume"))
191 pdata->reset_on_resume = 1; 203 pdata->reset_on_resume = 1;
192 204
193 priv->phy = devm_phy_get(&dev->dev, "usb"); 205 priv->num_phys = of_count_phandle_with_args(dev->dev.of_node,
194 if (IS_ERR(priv->phy)) { 206 "phys", "#phy-cells");
195 err = PTR_ERR(priv->phy); 207 priv->num_phys = priv->num_phys > 0 ? priv->num_phys : 1;
196 if (err == -EPROBE_DEFER) 208
197 goto err_put_hcd; 209 priv->phys = devm_kcalloc(&dev->dev, priv->num_phys,
198 priv->phy = NULL; 210 sizeof(struct phy *), GFP_KERNEL);
211 if (!priv->phys)
212 return -ENOMEM;
213
214 for (phy_num = 0; phy_num < priv->num_phys; phy_num++) {
215 err = of_property_read_string_index(
216 dev->dev.of_node,
217 "phy-names", phy_num,
218 &phy_name);
219
220 if (err < 0) {
221 if (priv->num_phys > 1) {
222 dev_err(&dev->dev, "phy-names not provided");
223 goto err_put_hcd;
224 } else
225 phy_name = "usb";
226 }
227
228 priv->phys[phy_num] = devm_phy_get(&dev->dev,
229 phy_name);
230 if (IS_ERR(priv->phys[phy_num])) {
231 err = PTR_ERR(priv->phys[phy_num]);
232 if ((priv->num_phys > 1) ||
233 (err == -EPROBE_DEFER))
234 goto err_put_hcd;
235 priv->phys[phy_num] = NULL;
236 }
199 } 237 }
200 238
201 for (clk = 0; clk < EHCI_MAX_CLKS; clk++) { 239 for (clk = 0; clk < EHCI_MAX_CLKS; clk++) {