aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorHans de Goede <hdegoede@redhat.com>2016-06-02 11:14:06 -0400
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2016-06-08 01:21:41 -0400
commit62d9694a003dba585026df36c181e3ca930aeafc (patch)
tree5f194ca6bb57de2345feb85369c9f638bc37db8b
parentcab43282682e0f46d6a74dd4f54f52595af5eefa (diff)
ohci-platform: Add support for controllers with multiple reset lines
At least the EHCI/OHCI found on the Allwinnner H3 SoC needs multiple reset lines, the controller will not initialize while the reset for its companion is still asserted, which means we need to de-assert 2 resets for the controller to work. Signed-off-by: Hans de Goede <hdegoede@redhat.com> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
-rw-r--r--Documentation/devicetree/bindings/usb/usb-ohci.txt2
-rw-r--r--drivers/usb/host/ohci-platform.c43
2 files changed, 24 insertions, 21 deletions
diff --git a/Documentation/devicetree/bindings/usb/usb-ohci.txt b/Documentation/devicetree/bindings/usb/usb-ohci.txt
index 19233b7365e1..9df456968596 100644
--- a/Documentation/devicetree/bindings/usb/usb-ohci.txt
+++ b/Documentation/devicetree/bindings/usb/usb-ohci.txt
@@ -14,7 +14,7 @@ Optional properties:
14- clocks : a list of phandle + clock specifier pairs 14- clocks : a list of phandle + clock specifier pairs
15- phys : phandle + phy specifier pair 15- phys : phandle + phy specifier pair
16- phy-names : "usb" 16- phy-names : "usb"
17- resets : phandle + reset specifier pair 17- resets : a list of phandle + reset specifier pairs
18 18
19Example: 19Example:
20 20
diff --git a/drivers/usb/host/ohci-platform.c b/drivers/usb/host/ohci-platform.c
index ae1c988da146..898b74086c12 100644
--- a/drivers/usb/host/ohci-platform.c
+++ b/drivers/usb/host/ohci-platform.c
@@ -33,11 +33,12 @@
33 33
34#define DRIVER_DESC "OHCI generic platform driver" 34#define DRIVER_DESC "OHCI generic platform driver"
35#define OHCI_MAX_CLKS 3 35#define OHCI_MAX_CLKS 3
36#define OHCI_MAX_RESETS 2
36#define hcd_to_ohci_priv(h) ((struct ohci_platform_priv *)hcd_to_ohci(h)->priv) 37#define hcd_to_ohci_priv(h) ((struct ohci_platform_priv *)hcd_to_ohci(h)->priv)
37 38
38struct ohci_platform_priv { 39struct ohci_platform_priv {
39 struct clk *clks[OHCI_MAX_CLKS]; 40 struct clk *clks[OHCI_MAX_CLKS];
40 struct reset_control *rst; 41 struct reset_control *resets[OHCI_MAX_RESETS];
41 struct phy **phys; 42 struct phy **phys;
42 int num_phys; 43 int num_phys;
43}; 44};
@@ -117,7 +118,7 @@ static int ohci_platform_probe(struct platform_device *dev)
117 struct usb_ohci_pdata *pdata = dev_get_platdata(&dev->dev); 118 struct usb_ohci_pdata *pdata = dev_get_platdata(&dev->dev);
118 struct ohci_platform_priv *priv; 119 struct ohci_platform_priv *priv;
119 struct ohci_hcd *ohci; 120 struct ohci_hcd *ohci;
120 int err, irq, phy_num, clk = 0; 121 int err, irq, phy_num, clk = 0, rst = 0;
121 122
122 if (usb_disabled()) 123 if (usb_disabled())
123 return -ENODEV; 124 return -ENODEV;
@@ -195,19 +196,21 @@ static int ohci_platform_probe(struct platform_device *dev)
195 break; 196 break;
196 } 197 }
197 } 198 }
198 199 for (rst = 0; rst < OHCI_MAX_RESETS; rst++) {
199 } 200 priv->resets[rst] =
200 201 devm_reset_control_get_shared_by_index(
201 priv->rst = devm_reset_control_get_optional(&dev->dev, NULL); 202 &dev->dev, rst);
202 if (IS_ERR(priv->rst)) { 203 if (IS_ERR(priv->resets[rst])) {
203 err = PTR_ERR(priv->rst); 204 err = PTR_ERR(priv->resets[rst]);
204 if (err == -EPROBE_DEFER) 205 if (err == -EPROBE_DEFER)
205 goto err_put_clks; 206 goto err_reset;
206 priv->rst = NULL; 207 priv->resets[rst] = NULL;
207 } else { 208 break;
208 err = reset_control_deassert(priv->rst); 209 }
209 if (err) 210 err = reset_control_deassert(priv->resets[rst]);
210 goto err_put_clks; 211 if (err)
212 goto err_reset;
213 }
211 } 214 }
212 215
213 if (pdata->big_endian_desc) 216 if (pdata->big_endian_desc)
@@ -265,8 +268,8 @@ err_power:
265 if (pdata->power_off) 268 if (pdata->power_off)
266 pdata->power_off(dev); 269 pdata->power_off(dev);
267err_reset: 270err_reset:
268 if (priv->rst) 271 while (--rst >= 0)
269 reset_control_assert(priv->rst); 272 reset_control_assert(priv->resets[rst]);
270err_put_clks: 273err_put_clks:
271 while (--clk >= 0) 274 while (--clk >= 0)
272 clk_put(priv->clks[clk]); 275 clk_put(priv->clks[clk]);
@@ -284,15 +287,15 @@ static int ohci_platform_remove(struct platform_device *dev)
284 struct usb_hcd *hcd = platform_get_drvdata(dev); 287 struct usb_hcd *hcd = platform_get_drvdata(dev);
285 struct usb_ohci_pdata *pdata = dev_get_platdata(&dev->dev); 288 struct usb_ohci_pdata *pdata = dev_get_platdata(&dev->dev);
286 struct ohci_platform_priv *priv = hcd_to_ohci_priv(hcd); 289 struct ohci_platform_priv *priv = hcd_to_ohci_priv(hcd);
287 int clk; 290 int clk, rst;
288 291
289 usb_remove_hcd(hcd); 292 usb_remove_hcd(hcd);
290 293
291 if (pdata->power_off) 294 if (pdata->power_off)
292 pdata->power_off(dev); 295 pdata->power_off(dev);
293 296
294 if (priv->rst) 297 for (rst = 0; rst < OHCI_MAX_RESETS && priv->resets[rst]; rst++)
295 reset_control_assert(priv->rst); 298 reset_control_assert(priv->resets[rst]);
296 299
297 for (clk = 0; clk < OHCI_MAX_CLKS && priv->clks[clk]; clk++) 300 for (clk = 0; clk < OHCI_MAX_CLKS && priv->clks[clk]; clk++)
298 clk_put(priv->clks[clk]); 301 clk_put(priv->clks[clk]);