summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorHans de Goede <hdegoede@redhat.com>2016-06-02 17:14:06 +0200
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2016-06-08 07:21:41 +0200
commit62d9694a003dba585026df36c181e3ca930aeafc (patch)
tree5f194ca6bb57de2345feb85369c9f638bc37db8b
parentARM: at91/dt: sama5d2: Use new compatible for ohci node (diff)
downloadlinux-62d9694a003dba585026df36c181e3ca930aeafc.tar.xz
linux-62d9694a003dba585026df36c181e3ca930aeafc.zip
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:
- clocks : a list of phandle + clock specifier pairs
- phys : phandle + phy specifier pair
- phy-names : "usb"
-- resets : phandle + reset specifier pair
+- resets : a list of phandle + reset specifier pairs
Example:
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 @@
#define DRIVER_DESC "OHCI generic platform driver"
#define OHCI_MAX_CLKS 3
+#define OHCI_MAX_RESETS 2
#define hcd_to_ohci_priv(h) ((struct ohci_platform_priv *)hcd_to_ohci(h)->priv)
struct ohci_platform_priv {
struct clk *clks[OHCI_MAX_CLKS];
- struct reset_control *rst;
+ struct reset_control *resets[OHCI_MAX_RESETS];
struct phy **phys;
int num_phys;
};
@@ -117,7 +118,7 @@ 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, phy_num, clk = 0;
+ int err, irq, phy_num, clk = 0, rst = 0;
if (usb_disabled())
return -ENODEV;
@@ -195,19 +196,21 @@ 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;
+ for (rst = 0; rst < OHCI_MAX_RESETS; rst++) {
+ priv->resets[rst] =
+ devm_reset_control_get_shared_by_index(
+ &dev->dev, rst);
+ if (IS_ERR(priv->resets[rst])) {
+ err = PTR_ERR(priv->resets[rst]);
+ if (err == -EPROBE_DEFER)
+ goto err_reset;
+ priv->resets[rst] = NULL;
+ break;
+ }
+ err = reset_control_deassert(priv->resets[rst]);
+ if (err)
+ goto err_reset;
+ }
}
if (pdata->big_endian_desc)
@@ -265,8 +268,8 @@ err_power:
if (pdata->power_off)
pdata->power_off(dev);
err_reset:
- if (priv->rst)
- reset_control_assert(priv->rst);
+ while (--rst >= 0)
+ reset_control_assert(priv->resets[rst]);
err_put_clks:
while (--clk >= 0)
clk_put(priv->clks[clk]);
@@ -284,15 +287,15 @@ static int ohci_platform_remove(struct platform_device *dev)
struct usb_hcd *hcd = platform_get_drvdata(dev);
struct usb_ohci_pdata *pdata = dev_get_platdata(&dev->dev);
struct ohci_platform_priv *priv = hcd_to_ohci_priv(hcd);
- int clk;
+ int clk, rst;
usb_remove_hcd(hcd);
if (pdata->power_off)
pdata->power_off(dev);
- if (priv->rst)
- reset_control_assert(priv->rst);
+ for (rst = 0; rst < OHCI_MAX_RESETS && priv->resets[rst]; rst++)
+ reset_control_assert(priv->resets[rst]);
for (clk = 0; clk < OHCI_MAX_CLKS && priv->clks[clk]; clk++)
clk_put(priv->clks[clk]);