aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorArun Ramamurthy <arunrama@broadcom.com>2015-01-19 19:05:30 -0500
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2015-01-25 08:04:21 -0500
commit85cd690d7e08159e8e4d737317a5e8a96140d687 (patch)
tree7003ef0210b95b174382bafc6205fb12d121616f
parent6d2a5663297a0489e7ade3303bba37e544da66e5 (diff)
usb: ohci-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/ohci-platform.c82
1 files changed, 60 insertions, 22 deletions
diff --git a/drivers/usb/host/ohci-platform.c b/drivers/usb/host/ohci-platform.c
index 9c06b0197eb9..185ceee52d47 100644
--- a/drivers/usb/host/ohci-platform.c
+++ b/drivers/usb/host/ohci-platform.c
@@ -38,7 +38,8 @@
38struct ohci_platform_priv { 38struct ohci_platform_priv {
39 struct clk *clks[OHCI_MAX_CLKS]; 39 struct clk *clks[OHCI_MAX_CLKS];
40 struct reset_control *rst; 40 struct reset_control *rst;
41 struct phy *phy; 41 struct phy **phys;
42 int num_phys;
42}; 43};
43 44
44static const char hcd_name[] = "ohci-platform"; 45static const char hcd_name[] = "ohci-platform";
@@ -47,7 +48,7 @@ static int ohci_platform_power_on(struct platform_device *dev)
47{ 48{
48 struct usb_hcd *hcd = platform_get_drvdata(dev); 49 struct usb_hcd *hcd = platform_get_drvdata(dev);
49 struct ohci_platform_priv *priv = hcd_to_ohci_priv(hcd); 50 struct ohci_platform_priv *priv = hcd_to_ohci_priv(hcd);
50 int clk, ret; 51 int clk, ret, phy_num;
51 52
52 for (clk = 0; clk < OHCI_MAX_CLKS && priv->clks[clk]; clk++) { 53 for (clk = 0; clk < OHCI_MAX_CLKS && priv->clks[clk]; clk++) {
53 ret = clk_prepare_enable(priv->clks[clk]); 54 ret = clk_prepare_enable(priv->clks[clk]);
@@ -55,20 +56,28 @@ static int ohci_platform_power_on(struct platform_device *dev)
55 goto err_disable_clks; 56 goto err_disable_clks;
56 } 57 }
57 58
58 if (priv->phy) { 59 for (phy_num = 0; phy_num < priv->num_phys; phy_num++) {
59 ret = phy_init(priv->phy); 60 if (priv->phys[phy_num]) {
60 if (ret) 61 ret = phy_init(priv->phys[phy_num]);
61 goto err_disable_clks; 62 if (ret)
62 63 goto err_exit_phy;
63 ret = phy_power_on(priv->phy); 64 ret = phy_power_on(priv->phys[phy_num]);
64 if (ret) 65 if (ret) {
65 goto err_exit_phy; 66 phy_exit(priv->phys[phy_num]);
67 goto err_exit_phy;
68 }
69 }
66 } 70 }
67 71
68 return 0; 72 return 0;
69 73
70err_exit_phy: 74err_exit_phy:
71 phy_exit(priv->phy); 75 while (--phy_num >= 0) {
76 if (priv->phys[phy_num]) {
77 phy_power_off(priv->phys[phy_num]);
78 phy_exit(priv->phys[phy_num]);
79 }
80 }
72err_disable_clks: 81err_disable_clks:
73 while (--clk >= 0) 82 while (--clk >= 0)
74 clk_disable_unprepare(priv->clks[clk]); 83 clk_disable_unprepare(priv->clks[clk]);
@@ -80,11 +89,13 @@ static void ohci_platform_power_off(struct platform_device *dev)
80{ 89{
81 struct usb_hcd *hcd = platform_get_drvdata(dev); 90 struct usb_hcd *hcd = platform_get_drvdata(dev);
82 struct ohci_platform_priv *priv = hcd_to_ohci_priv(hcd); 91 struct ohci_platform_priv *priv = hcd_to_ohci_priv(hcd);
83 int clk; 92 int clk, phy_num;
84 93
85 if (priv->phy) { 94 for (phy_num = 0; phy_num < priv->num_phys; phy_num++) {
86 phy_power_off(priv->phy); 95 if (priv->phys[phy_num]) {
87 phy_exit(priv->phy); 96 phy_power_off(priv->phys[phy_num]);
97 phy_exit(priv->phys[phy_num]);
98 }
88 } 99 }
89 100
90 for (clk = OHCI_MAX_CLKS - 1; clk >= 0; clk--) 101 for (clk = OHCI_MAX_CLKS - 1; clk >= 0; clk--)
@@ -112,7 +123,8 @@ static int ohci_platform_probe(struct platform_device *dev)
112 struct usb_ohci_pdata *pdata = dev_get_platdata(&dev->dev); 123 struct usb_ohci_pdata *pdata = dev_get_platdata(&dev->dev);
113 struct ohci_platform_priv *priv; 124 struct ohci_platform_priv *priv;
114 struct ohci_hcd *ohci; 125 struct ohci_hcd *ohci;
115 int err, irq, clk = 0; 126 const char *phy_name;
127 int err, irq, phy_num, clk = 0;
116 128
117 if (usb_disabled()) 129 if (usb_disabled())
118 return -ENODEV; 130 return -ENODEV;
@@ -160,12 +172,38 @@ static int ohci_platform_probe(struct platform_device *dev)
160 of_property_read_u32(dev->dev.of_node, "num-ports", 172 of_property_read_u32(dev->dev.of_node, "num-ports",
161 &ohci->num_ports); 173 &ohci->num_ports);
162 174
163 priv->phy = devm_phy_get(&dev->dev, "usb"); 175 priv->num_phys = of_count_phandle_with_args(dev->dev.of_node,
164 if (IS_ERR(priv->phy)) { 176 "phys", "#phy-cells");
165 err = PTR_ERR(priv->phy); 177 priv->num_phys = priv->num_phys > 0 ? priv->num_phys : 1;
166 if (err == -EPROBE_DEFER) 178
167 goto err_put_hcd; 179 priv->phys = devm_kcalloc(&dev->dev, priv->num_phys,
168 priv->phy = NULL; 180 sizeof(struct phy *), GFP_KERNEL);
181 if (!priv->phys)
182 return -ENOMEM;
183
184 for (phy_num = 0; phy_num < priv->num_phys; phy_num++) {
185 err = of_property_read_string_index(
186 dev->dev.of_node,
187 "phy-names", phy_num,
188 &phy_name);
189
190 if (err < 0) {
191 if (priv->num_phys > 1) {
192 dev_err(&dev->dev, "phy-names not provided");
193 goto err_put_hcd;
194 } else
195 phy_name = "usb";
196 }
197
198 priv->phys[phy_num] = devm_phy_get(&dev->dev,
199 phy_name);
200 if (IS_ERR(priv->phys[phy_num])) {
201 err = PTR_ERR(priv->phys[phy_num]);
202 if ((priv->num_phys > 1) ||
203 (err == -EPROBE_DEFER))
204 goto err_put_hcd;
205 priv->phys[phy_num] = NULL;
206 }
169 } 207 }
170 208
171 for (clk = 0; clk < OHCI_MAX_CLKS; clk++) { 209 for (clk = 0; clk < OHCI_MAX_CLKS; clk++) {