Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

usb: ehci-platform: add optional reset controller retrieval

On the Allwinner's A31 SoC the reset line connected to the EHCI IP has to
be deasserted for the EHCI block to be usable.

Add support for an optional reset controller that will be deasserted on
power off and asserted on power on.

Signed-off-by: Boris BREZILLON <boris.brezillon@free-electrons.com>
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>

authored by

Boris BREZILLON and committed by
Greg Kroah-Hartman
2d87bbd6 4615f3bd

+24 -3
+1
Documentation/devicetree/bindings/usb/usb-ehci.txt
··· 15 15 - clocks : a list of phandle + clock specifier pairs 16 16 - phys : phandle + phy specifier pair 17 17 - phy-names : "usb" 18 + - resets : phandle + reset specifier pair 18 19 19 20 Example (Sequoia 440EPx): 20 21 ehci@e0000300 {
+23 -3
drivers/usb/host/ehci-platform.c
··· 29 29 #include <linux/of.h> 30 30 #include <linux/phy/phy.h> 31 31 #include <linux/platform_device.h> 32 + #include <linux/reset.h> 32 33 #include <linux/usb.h> 33 34 #include <linux/usb/hcd.h> 34 35 #include <linux/usb/ehci_pdriver.h> ··· 42 41 43 42 struct ehci_platform_priv { 44 43 struct clk *clks[EHCI_MAX_CLKS]; 44 + struct reset_control *rst; 45 45 struct phy *phy; 46 46 }; 47 47 ··· 210 208 } 211 209 } 212 210 211 + priv->rst = devm_reset_control_get_optional(&dev->dev, NULL); 212 + if (IS_ERR(priv->rst)) { 213 + err = PTR_ERR(priv->rst); 214 + if (err == -EPROBE_DEFER) 215 + goto err_put_clks; 216 + priv->rst = NULL; 217 + } else { 218 + err = reset_control_deassert(priv->rst); 219 + if (err) 220 + goto err_put_clks; 221 + } 222 + 213 223 if (pdata->big_endian_desc) 214 224 ehci->big_endian_desc = 1; 215 225 if (pdata->big_endian_mmio) ··· 232 218 dev_err(&dev->dev, 233 219 "Error: CONFIG_USB_EHCI_BIG_ENDIAN_MMIO not set\n"); 234 220 err = -EINVAL; 235 - goto err_put_clks; 221 + goto err_reset; 236 222 } 237 223 #endif 238 224 #ifndef CONFIG_USB_EHCI_BIG_ENDIAN_DESC ··· 240 226 dev_err(&dev->dev, 241 227 "Error: CONFIG_USB_EHCI_BIG_ENDIAN_DESC not set\n"); 242 228 err = -EINVAL; 243 - goto err_put_clks; 229 + goto err_reset; 244 230 } 245 231 #endif 246 232 247 233 if (pdata->power_on) { 248 234 err = pdata->power_on(dev); 249 235 if (err < 0) 250 - goto err_put_clks; 236 + goto err_reset; 251 237 } 252 238 253 239 hcd->rsrc_start = res_mem->start; ··· 270 256 err_power: 271 257 if (pdata->power_off) 272 258 pdata->power_off(dev); 259 + err_reset: 260 + if (priv->rst) 261 + reset_control_assert(priv->rst); 273 262 err_put_clks: 274 263 while (--clk >= 0) 275 264 clk_put(priv->clks[clk]); ··· 296 279 297 280 if (pdata->power_off) 298 281 pdata->power_off(dev); 282 + 283 + if (priv->rst) 284 + reset_control_assert(priv->rst); 299 285 300 286 for (clk = 0; clk < EHCI_MAX_CLKS && priv->clks[clk]; clk++) 301 287 clk_put(priv->clks[clk]);