aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/usb/host/ehci-hub.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/usb/host/ehci-hub.c')
-rw-r--r--drivers/usb/host/ehci-hub.c26
1 files changed, 22 insertions, 4 deletions
diff --git a/drivers/usb/host/ehci-hub.c b/drivers/usb/host/ehci-hub.c
index 47b858fc50b2..7ae0c4d51741 100644
--- a/drivers/usb/host/ehci-hub.c
+++ b/drivers/usb/host/ehci-hub.c
@@ -238,6 +238,7 @@ static int ehci_bus_suspend (struct usb_hcd *hcd)
238 int port; 238 int port;
239 int mask; 239 int mask;
240 int changed; 240 int changed;
241 bool fs_idle_delay;
241 242
242 ehci_dbg(ehci, "suspend root hub\n"); 243 ehci_dbg(ehci, "suspend root hub\n");
243 244
@@ -272,6 +273,7 @@ static int ehci_bus_suspend (struct usb_hcd *hcd)
272 ehci->bus_suspended = 0; 273 ehci->bus_suspended = 0;
273 ehci->owned_ports = 0; 274 ehci->owned_ports = 0;
274 changed = 0; 275 changed = 0;
276 fs_idle_delay = false;
275 port = HCS_N_PORTS(ehci->hcs_params); 277 port = HCS_N_PORTS(ehci->hcs_params);
276 while (port--) { 278 while (port--) {
277 u32 __iomem *reg = &ehci->regs->port_status [port]; 279 u32 __iomem *reg = &ehci->regs->port_status [port];
@@ -300,16 +302,32 @@ static int ehci_bus_suspend (struct usb_hcd *hcd)
300 } 302 }
301 303
302 if (t1 != t2) { 304 if (t1 != t2) {
305 /*
306 * On some controllers, Wake-On-Disconnect will
307 * generate false wakeup signals until the bus
308 * switches over to full-speed idle. For their
309 * sake, add a delay if we need one.
310 */
311 if ((t2 & PORT_WKDISC_E) &&
312 ehci_port_speed(ehci, t2) ==
313 USB_PORT_STAT_HIGH_SPEED)
314 fs_idle_delay = true;
303 ehci_writel(ehci, t2, reg); 315 ehci_writel(ehci, t2, reg);
304 changed = 1; 316 changed = 1;
305 } 317 }
306 } 318 }
319 spin_unlock_irq(&ehci->lock);
320
321 if ((changed && ehci->has_tdi_phy_lpm) || fs_idle_delay) {
322 /*
323 * Wait for HCD to enter low-power mode or for the bus
324 * to switch to full-speed idle.
325 */
326 usleep_range(5000, 5500);
327 }
307 328
308 if (changed && ehci->has_tdi_phy_lpm) { 329 if (changed && ehci->has_tdi_phy_lpm) {
309 spin_unlock_irq(&ehci->lock);
310 msleep(5); /* 5 ms for HCD to enter low-power mode */
311 spin_lock_irq(&ehci->lock); 330 spin_lock_irq(&ehci->lock);
312
313 port = HCS_N_PORTS(ehci->hcs_params); 331 port = HCS_N_PORTS(ehci->hcs_params);
314 while (port--) { 332 while (port--) {
315 u32 __iomem *hostpc_reg = &ehci->regs->hostpc[port]; 333 u32 __iomem *hostpc_reg = &ehci->regs->hostpc[port];
@@ -322,8 +340,8 @@ static int ehci_bus_suspend (struct usb_hcd *hcd)
322 port, (t3 & HOSTPC_PHCD) ? 340 port, (t3 & HOSTPC_PHCD) ?
323 "succeeded" : "failed"); 341 "succeeded" : "failed");
324 } 342 }
343 spin_unlock_irq(&ehci->lock);
325 } 344 }
326 spin_unlock_irq(&ehci->lock);
327 345
328 /* Apparently some devices need a >= 1-uframe delay here */ 346 /* Apparently some devices need a >= 1-uframe delay here */
329 if (ehci->bus_suspended) 347 if (ehci->bus_suspended)