usb: ohci-platform: Enable optional use of reset controller
authorMaxime Ripard <maxime.ripard@free-electrons.com>
Tue, 13 May 2014 15:44:20 +0000 (17:44 +0200)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Tue, 27 May 2014 22:53:00 +0000 (15:53 -0700)
The OHCI controllers used in the Allwinner A31 are asserted in reset using a
global reset controller.

Add optional support for such a controller in the OHCI platform driver.

Signed-off-by: Maxime Ripard <maxime.ripard@free-electrons.com>
Reviewed-by: Hans de Goede <hdegoede@redhat.com>
Acked-by: Alan Stern <stern@rowland.harvard.edu>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Documentation/devicetree/bindings/usb/usb-ohci.txt
drivers/usb/host/ohci-platform.c

index 45f67d91e8882dd417e93ea261548aff5ce2060e..b968a1aea9954389206fbe0a80345e07ff6a503b 100644 (file)
@@ -12,6 +12,7 @@ Optional properties:
 - clocks : a list of phandle + clock specifier pairs
 - phys : phandle + phy specifier pair
 - phy-names : "usb"
+- resets : phandle + reset specifier pair
 
 Example:
 
index b6002c951c5cbbede27756b449b9b66e4a97e1fc..4369299064c775836aea25fdb87c3d4ac249d843 100644 (file)
@@ -24,6 +24,7 @@
 #include <linux/err.h>
 #include <linux/phy/phy.h>
 #include <linux/platform_device.h>
+#include <linux/reset.h>
 #include <linux/usb/ohci_pdriver.h>
 #include <linux/usb.h>
 #include <linux/usb/hcd.h>
@@ -36,6 +37,7 @@
 
 struct ohci_platform_priv {
        struct clk *clks[OHCI_MAX_CLKS];
+       struct reset_control *rst;
        struct phy *phy;
 };
 
@@ -191,6 +193,19 @@ static int ohci_platform_probe(struct platform_device *dev)
                                break;
                        }
                }
+
+       }
+
+       priv->rst = devm_reset_control_get_optional(&dev->dev, NULL);
+       if (IS_ERR(priv->rst)) {
+               err = PTR_ERR(priv->rst);
+               if (err == -EPROBE_DEFER)
+                       goto err_put_clks;
+               priv->rst = NULL;
+       } else {
+               err = reset_control_deassert(priv->rst);
+               if (err)
+                       goto err_put_clks;
        }
 
        if (pdata->big_endian_desc)
@@ -203,7 +218,7 @@ static int ohci_platform_probe(struct platform_device *dev)
                dev_err(&dev->dev,
                        "Error: CONFIG_USB_OHCI_BIG_ENDIAN_MMIO not set\n");
                err = -EINVAL;
-               goto err_put_clks;
+               goto err_reset;
        }
 #endif
 #ifndef CONFIG_USB_OHCI_BIG_ENDIAN_DESC
@@ -211,14 +226,14 @@ static int ohci_platform_probe(struct platform_device *dev)
                dev_err(&dev->dev,
                        "Error: CONFIG_USB_OHCI_BIG_ENDIAN_DESC not set\n");
                err = -EINVAL;
-               goto err_put_clks;
+               goto err_reset;
        }
 #endif
 
        if (pdata->power_on) {
                err = pdata->power_on(dev);
                if (err < 0)
-                       goto err_put_clks;
+                       goto err_reset;
        }
 
        hcd->rsrc_start = res_mem->start;
@@ -242,6 +257,9 @@ static int ohci_platform_probe(struct platform_device *dev)
 err_power:
        if (pdata->power_off)
                pdata->power_off(dev);
+err_reset:
+       if (priv->rst)
+               reset_control_assert(priv->rst);
 err_put_clks:
        while (--clk >= 0)
                clk_put(priv->clks[clk]);
@@ -266,6 +284,9 @@ static int ohci_platform_remove(struct platform_device *dev)
        if (pdata->power_off)
                pdata->power_off(dev);
 
+       if (priv->rst)
+               reset_control_assert(priv->rst);
+
        for (clk = 0; clk < OHCI_MAX_CLKS && priv->clks[clk]; clk++)
                clk_put(priv->clks[clk]);