diff options
author | Maxime Ripard <maxime.ripard@free-electrons.com> | 2014-05-13 11:44:20 -0400 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2014-05-27 18:53:00 -0400 |
commit | 4615f3bd089fc4c549ed90e14982b360779feb50 (patch) | |
tree | d9a0820c9679ca20a4af417c90f021affc8d55e8 /drivers/usb/host | |
parent | 38e0c109404506266e33c29c77c2da39630954a4 (diff) |
usb: ohci-platform: Enable optional use of reset controller
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>
Diffstat (limited to 'drivers/usb/host')
-rw-r--r-- | drivers/usb/host/ohci-platform.c | 27 |
1 files changed, 24 insertions, 3 deletions
diff --git a/drivers/usb/host/ohci-platform.c b/drivers/usb/host/ohci-platform.c index b6002c951c5c..4369299064c7 100644 --- a/drivers/usb/host/ohci-platform.c +++ b/drivers/usb/host/ohci-platform.c | |||
@@ -24,6 +24,7 @@ | |||
24 | #include <linux/err.h> | 24 | #include <linux/err.h> |
25 | #include <linux/phy/phy.h> | 25 | #include <linux/phy/phy.h> |
26 | #include <linux/platform_device.h> | 26 | #include <linux/platform_device.h> |
27 | #include <linux/reset.h> | ||
27 | #include <linux/usb/ohci_pdriver.h> | 28 | #include <linux/usb/ohci_pdriver.h> |
28 | #include <linux/usb.h> | 29 | #include <linux/usb.h> |
29 | #include <linux/usb/hcd.h> | 30 | #include <linux/usb/hcd.h> |
@@ -36,6 +37,7 @@ | |||
36 | 37 | ||
37 | struct ohci_platform_priv { | 38 | struct ohci_platform_priv { |
38 | struct clk *clks[OHCI_MAX_CLKS]; | 39 | struct clk *clks[OHCI_MAX_CLKS]; |
40 | struct reset_control *rst; | ||
39 | struct phy *phy; | 41 | struct phy *phy; |
40 | }; | 42 | }; |
41 | 43 | ||
@@ -191,6 +193,19 @@ static int ohci_platform_probe(struct platform_device *dev) | |||
191 | break; | 193 | break; |
192 | } | 194 | } |
193 | } | 195 | } |
196 | |||
197 | } | ||
198 | |||
199 | priv->rst = devm_reset_control_get_optional(&dev->dev, NULL); | ||
200 | if (IS_ERR(priv->rst)) { | ||
201 | err = PTR_ERR(priv->rst); | ||
202 | if (err == -EPROBE_DEFER) | ||
203 | goto err_put_clks; | ||
204 | priv->rst = NULL; | ||
205 | } else { | ||
206 | err = reset_control_deassert(priv->rst); | ||
207 | if (err) | ||
208 | goto err_put_clks; | ||
194 | } | 209 | } |
195 | 210 | ||
196 | if (pdata->big_endian_desc) | 211 | if (pdata->big_endian_desc) |
@@ -203,7 +218,7 @@ static int ohci_platform_probe(struct platform_device *dev) | |||
203 | dev_err(&dev->dev, | 218 | dev_err(&dev->dev, |
204 | "Error: CONFIG_USB_OHCI_BIG_ENDIAN_MMIO not set\n"); | 219 | "Error: CONFIG_USB_OHCI_BIG_ENDIAN_MMIO not set\n"); |
205 | err = -EINVAL; | 220 | err = -EINVAL; |
206 | goto err_put_clks; | 221 | goto err_reset; |
207 | } | 222 | } |
208 | #endif | 223 | #endif |
209 | #ifndef CONFIG_USB_OHCI_BIG_ENDIAN_DESC | 224 | #ifndef CONFIG_USB_OHCI_BIG_ENDIAN_DESC |
@@ -211,14 +226,14 @@ static int ohci_platform_probe(struct platform_device *dev) | |||
211 | dev_err(&dev->dev, | 226 | dev_err(&dev->dev, |
212 | "Error: CONFIG_USB_OHCI_BIG_ENDIAN_DESC not set\n"); | 227 | "Error: CONFIG_USB_OHCI_BIG_ENDIAN_DESC not set\n"); |
213 | err = -EINVAL; | 228 | err = -EINVAL; |
214 | goto err_put_clks; | 229 | goto err_reset; |
215 | } | 230 | } |
216 | #endif | 231 | #endif |
217 | 232 | ||
218 | if (pdata->power_on) { | 233 | if (pdata->power_on) { |
219 | err = pdata->power_on(dev); | 234 | err = pdata->power_on(dev); |
220 | if (err < 0) | 235 | if (err < 0) |
221 | goto err_put_clks; | 236 | goto err_reset; |
222 | } | 237 | } |
223 | 238 | ||
224 | hcd->rsrc_start = res_mem->start; | 239 | hcd->rsrc_start = res_mem->start; |
@@ -242,6 +257,9 @@ static int ohci_platform_probe(struct platform_device *dev) | |||
242 | err_power: | 257 | err_power: |
243 | if (pdata->power_off) | 258 | if (pdata->power_off) |
244 | pdata->power_off(dev); | 259 | pdata->power_off(dev); |
260 | err_reset: | ||
261 | if (priv->rst) | ||
262 | reset_control_assert(priv->rst); | ||
245 | err_put_clks: | 263 | err_put_clks: |
246 | while (--clk >= 0) | 264 | while (--clk >= 0) |
247 | clk_put(priv->clks[clk]); | 265 | clk_put(priv->clks[clk]); |
@@ -266,6 +284,9 @@ static int ohci_platform_remove(struct platform_device *dev) | |||
266 | if (pdata->power_off) | 284 | if (pdata->power_off) |
267 | pdata->power_off(dev); | 285 | pdata->power_off(dev); |
268 | 286 | ||
287 | if (priv->rst) | ||
288 | reset_control_assert(priv->rst); | ||
289 | |||
269 | for (clk = 0; clk < OHCI_MAX_CLKS && priv->clks[clk]; clk++) | 290 | for (clk = 0; clk < OHCI_MAX_CLKS && priv->clks[clk]; clk++) |
270 | clk_put(priv->clks[clk]); | 291 | clk_put(priv->clks[clk]); |
271 | 292 | ||