From 314b41b16a71ee824f55e2791fcb92997672da37 Mon Sep 17 00:00:00 2001 From: Wu Liang feng Date: Wed, 24 Dec 2014 18:22:19 +0800 Subject: USB: ehci-platform: Support ehci reset after resume quirk The Rockchip rk3288 EHCI controller doesn't properly detect the case when a device is removed during suspend. Specifically, when usb resume from suspend, the EHCI controller maintaining the USB state (FLAG_CF is 1, Current Connect Status is 1), but a USB device (like a USB camera on rk3288) may have been disconnected actually. Let's add a quirk to force ehci to go into the usb_root_hub_lost_power() path and reset after resume. This should generally reset the whole controller and all ports and initialize everything cleanly again, and bring the devices back up. As part of this, rename the "hibernation" paramter of ehci_resume() to force_reset since hibernation is simply another case where we can't trust the autodetected status and need to force a reset of devices. Signed-off-by: Wu Liang feng Reviewed-by: Julius Werner Reviewed-by: Doug Anderson Reviewed-by: Tomasz Figa Reviewed-by: Pawel Osciak Reviewed-by: Sonny Rao Acked-by: Alan Stern Tested-by: Doug Anderson Signed-off-by: Greg Kroah-Hartman --- drivers/usb/host/ehci-hcd.c | 6 +++--- drivers/usb/host/ehci-platform.c | 6 +++++- drivers/usb/host/ehci.h | 2 +- 3 files changed, 9 insertions(+), 5 deletions(-) (limited to 'drivers') diff --git a/drivers/usb/host/ehci-hcd.c b/drivers/usb/host/ehci-hcd.c index 38bfeed..85e56d1 100644 --- a/drivers/usb/host/ehci-hcd.c +++ b/drivers/usb/host/ehci-hcd.c @@ -1110,7 +1110,7 @@ int ehci_suspend(struct usb_hcd *hcd, bool do_wakeup) EXPORT_SYMBOL_GPL(ehci_suspend); /* Returns 0 if power was preserved, 1 if power was lost */ -int ehci_resume(struct usb_hcd *hcd, bool hibernated) +int ehci_resume(struct usb_hcd *hcd, bool force_reset) { struct ehci_hcd *ehci = hcd_to_ehci(hcd); @@ -1124,12 +1124,12 @@ int ehci_resume(struct usb_hcd *hcd, bool hibernated) return 0; /* Controller is dead */ /* - * If CF is still set and we aren't resuming from hibernation + * If CF is still set and reset isn't forced * then we maintained suspend power. * Just undo the effect of ehci_suspend(). */ if (ehci_readl(ehci, &ehci->regs->configured_flag) == FLAG_CF && - !hibernated) { + !force_reset) { int mask = INTR_MASK; ehci_prepare_ports_for_controller_resume(ehci); diff --git a/drivers/usb/host/ehci-platform.c b/drivers/usb/host/ehci-platform.c index 8557803..db5c29e 100644 --- a/drivers/usb/host/ehci-platform.c +++ b/drivers/usb/host/ehci-platform.c @@ -185,6 +185,10 @@ static int ehci_platform_probe(struct platform_device *dev) if (of_property_read_bool(dev->dev.of_node, "big-endian")) ehci->big_endian_mmio = ehci->big_endian_desc = 1; + if (of_property_read_bool(dev->dev.of_node, + "needs-reset-on-resume")) + pdata->reset_on_resume = 1; + priv->phy = devm_phy_get(&dev->dev, "usb"); if (IS_ERR(priv->phy)) { err = PTR_ERR(priv->phy); @@ -340,7 +344,7 @@ static int ehci_platform_resume(struct device *dev) return err; } - ehci_resume(hcd, false); + ehci_resume(hcd, pdata->reset_on_resume); return 0; } #endif /* CONFIG_PM_SLEEP */ diff --git a/drivers/usb/host/ehci.h b/drivers/usb/host/ehci.h index 6f0577b..52ef084 100644 --- a/drivers/usb/host/ehci.h +++ b/drivers/usb/host/ehci.h @@ -871,7 +871,7 @@ extern int ehci_handshake(struct ehci_hcd *ehci, void __iomem *ptr, #ifdef CONFIG_PM extern int ehci_suspend(struct usb_hcd *hcd, bool do_wakeup); -extern int ehci_resume(struct usb_hcd *hcd, bool hibernated); +extern int ehci_resume(struct usb_hcd *hcd, bool force_reset); #endif /* CONFIG_PM */ extern int ehci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue, -- cgit v1.1