diff options
author | Alek Du <alek.du@intel.com> | 2010-05-09 23:17:49 -0400 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@suse.de> | 2010-05-20 16:21:45 -0400 |
commit | eab80de01cb398419ef3305f35abcb367c647c8b (patch) | |
tree | 0cbf986a987df044234bba1ad0a1c6565268a4f1 /drivers | |
parent | 17b2765ef8db8dc00a24a9afd4646bb3decffbd2 (diff) |
USB: EHCI: clear PHCD before resuming
This is a bug fix for PHCD (phy clock disable) low power feature:
After PHCD is set, any write to PORTSC register is illegal, so when
resume ports, clear PHCD bit first.
Signed-off-by: Alek Du <alek.du@intel.com>
Cc: David Brownell <dbrownell@users.sourceforge.net>
Cc: Alan Stern <stern@rowland.harvard.edu>
Cc: stable <stable@kernel.org>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/usb/host/ehci-hub.c | 17 |
1 files changed, 17 insertions, 0 deletions
diff --git a/drivers/usb/host/ehci-hub.c b/drivers/usb/host/ehci-hub.c index c44018109a13..ef956220f854 100644 --- a/drivers/usb/host/ehci-hub.c +++ b/drivers/usb/host/ehci-hub.c | |||
@@ -294,6 +294,16 @@ static int ehci_bus_resume (struct usb_hcd *hcd) | |||
294 | /* manually resume the ports we suspended during bus_suspend() */ | 294 | /* manually resume the ports we suspended during bus_suspend() */ |
295 | i = HCS_N_PORTS (ehci->hcs_params); | 295 | i = HCS_N_PORTS (ehci->hcs_params); |
296 | while (i--) { | 296 | while (i--) { |
297 | /* clear phy low power mode before resume */ | ||
298 | if (ehci->has_hostpc) { | ||
299 | u32 __iomem *hostpc_reg = | ||
300 | (u32 __iomem *)((u8 *)ehci->regs | ||
301 | + HOSTPC0 + 4 * (i & 0xff)); | ||
302 | temp = ehci_readl(ehci, hostpc_reg); | ||
303 | ehci_writel(ehci, temp & ~HOSTPC_PHCD, | ||
304 | hostpc_reg); | ||
305 | mdelay(5); | ||
306 | } | ||
297 | temp = ehci_readl(ehci, &ehci->regs->port_status [i]); | 307 | temp = ehci_readl(ehci, &ehci->regs->port_status [i]); |
298 | temp &= ~(PORT_RWC_BITS | PORT_WAKE_BITS); | 308 | temp &= ~(PORT_RWC_BITS | PORT_WAKE_BITS); |
299 | if (test_bit(i, &ehci->bus_suspended) && | 309 | if (test_bit(i, &ehci->bus_suspended) && |
@@ -678,6 +688,13 @@ static int ehci_hub_control ( | |||
678 | if (temp & PORT_SUSPEND) { | 688 | if (temp & PORT_SUSPEND) { |
679 | if ((temp & PORT_PE) == 0) | 689 | if ((temp & PORT_PE) == 0) |
680 | goto error; | 690 | goto error; |
691 | /* clear phy low power mode before resume */ | ||
692 | if (hostpc_reg) { | ||
693 | temp1 = ehci_readl(ehci, hostpc_reg); | ||
694 | ehci_writel(ehci, temp1 & ~HOSTPC_PHCD, | ||
695 | hostpc_reg); | ||
696 | mdelay(5); | ||
697 | } | ||
681 | /* resume signaling for 20 msec */ | 698 | /* resume signaling for 20 msec */ |
682 | temp &= ~(PORT_RWC_BITS | PORT_WAKE_BITS); | 699 | temp &= ~(PORT_RWC_BITS | PORT_WAKE_BITS); |
683 | ehci_writel(ehci, temp | PORT_RESUME, | 700 | ehci_writel(ehci, temp | PORT_RESUME, |