diff options
Diffstat (limited to 'drivers/usb/host/ehci-hub.c')
-rw-r--r-- | drivers/usb/host/ehci-hub.c | 33 |
1 files changed, 27 insertions, 6 deletions
diff --git a/drivers/usb/host/ehci-hub.c b/drivers/usb/host/ehci-hub.c index 2c6571c05f35..19372673bf09 100644 --- a/drivers/usb/host/ehci-hub.c +++ b/drivers/usb/host/ehci-hub.c | |||
@@ -120,9 +120,26 @@ static int ehci_bus_suspend (struct usb_hcd *hcd) | |||
120 | del_timer_sync(&ehci->watchdog); | 120 | del_timer_sync(&ehci->watchdog); |
121 | del_timer_sync(&ehci->iaa_watchdog); | 121 | del_timer_sync(&ehci->iaa_watchdog); |
122 | 122 | ||
123 | port = HCS_N_PORTS (ehci->hcs_params); | ||
124 | spin_lock_irq (&ehci->lock); | 123 | spin_lock_irq (&ehci->lock); |
125 | 124 | ||
125 | /* Once the controller is stopped, port resumes that are already | ||
126 | * in progress won't complete. Hence if remote wakeup is enabled | ||
127 | * for the root hub and any ports are in the middle of a resume or | ||
128 | * remote wakeup, we must fail the suspend. | ||
129 | */ | ||
130 | if (hcd->self.root_hub->do_remote_wakeup) { | ||
131 | port = HCS_N_PORTS(ehci->hcs_params); | ||
132 | while (port--) { | ||
133 | if (ehci->reset_done[port] != 0) { | ||
134 | spin_unlock_irq(&ehci->lock); | ||
135 | ehci_dbg(ehci, "suspend failed because " | ||
136 | "port %d is resuming\n", | ||
137 | port + 1); | ||
138 | return -EBUSY; | ||
139 | } | ||
140 | } | ||
141 | } | ||
142 | |||
126 | /* stop schedules, clean any completed work */ | 143 | /* stop schedules, clean any completed work */ |
127 | if (HC_IS_RUNNING(hcd->state)) { | 144 | if (HC_IS_RUNNING(hcd->state)) { |
128 | ehci_quiesce (ehci); | 145 | ehci_quiesce (ehci); |
@@ -138,6 +155,7 @@ static int ehci_bus_suspend (struct usb_hcd *hcd) | |||
138 | */ | 155 | */ |
139 | ehci->bus_suspended = 0; | 156 | ehci->bus_suspended = 0; |
140 | ehci->owned_ports = 0; | 157 | ehci->owned_ports = 0; |
158 | port = HCS_N_PORTS(ehci->hcs_params); | ||
141 | while (port--) { | 159 | while (port--) { |
142 | u32 __iomem *reg = &ehci->regs->port_status [port]; | 160 | u32 __iomem *reg = &ehci->regs->port_status [port]; |
143 | u32 t1 = ehci_readl(ehci, reg) & ~PORT_RWC_BITS; | 161 | u32 t1 = ehci_readl(ehci, reg) & ~PORT_RWC_BITS; |
@@ -178,7 +196,9 @@ static int ehci_bus_suspend (struct usb_hcd *hcd) | |||
178 | if (hostpc_reg) { | 196 | if (hostpc_reg) { |
179 | u32 t3; | 197 | u32 t3; |
180 | 198 | ||
199 | spin_unlock_irq(&ehci->lock); | ||
181 | msleep(5);/* 5ms for HCD enter low pwr mode */ | 200 | msleep(5);/* 5ms for HCD enter low pwr mode */ |
201 | spin_lock_irq(&ehci->lock); | ||
182 | t3 = ehci_readl(ehci, hostpc_reg); | 202 | t3 = ehci_readl(ehci, hostpc_reg); |
183 | ehci_writel(ehci, t3 | HOSTPC_PHCD, hostpc_reg); | 203 | ehci_writel(ehci, t3 | HOSTPC_PHCD, hostpc_reg); |
184 | t3 = ehci_readl(ehci, hostpc_reg); | 204 | t3 = ehci_readl(ehci, hostpc_reg); |
@@ -886,17 +906,18 @@ static int ehci_hub_control ( | |||
886 | if ((temp & PORT_PE) == 0 | 906 | if ((temp & PORT_PE) == 0 |
887 | || (temp & PORT_RESET) != 0) | 907 | || (temp & PORT_RESET) != 0) |
888 | goto error; | 908 | goto error; |
889 | ehci_writel(ehci, temp | PORT_SUSPEND, status_reg); | 909 | |
890 | /* After above check the port must be connected. | 910 | /* After above check the port must be connected. |
891 | * Set appropriate bit thus could put phy into low power | 911 | * Set appropriate bit thus could put phy into low power |
892 | * mode if we have hostpc feature | 912 | * mode if we have hostpc feature |
893 | */ | 913 | */ |
914 | temp &= ~PORT_WKCONN_E; | ||
915 | temp |= PORT_WKDISC_E | PORT_WKOC_E; | ||
916 | ehci_writel(ehci, temp | PORT_SUSPEND, status_reg); | ||
894 | if (hostpc_reg) { | 917 | if (hostpc_reg) { |
895 | temp &= ~PORT_WKCONN_E; | 918 | spin_unlock_irqrestore(&ehci->lock, flags); |
896 | temp |= (PORT_WKDISC_E | PORT_WKOC_E); | ||
897 | ehci_writel(ehci, temp | PORT_SUSPEND, | ||
898 | status_reg); | ||
899 | msleep(5);/* 5ms for HCD enter low pwr mode */ | 919 | msleep(5);/* 5ms for HCD enter low pwr mode */ |
920 | spin_lock_irqsave(&ehci->lock, flags); | ||
900 | temp1 = ehci_readl(ehci, hostpc_reg); | 921 | temp1 = ehci_readl(ehci, hostpc_reg); |
901 | ehci_writel(ehci, temp1 | HOSTPC_PHCD, | 922 | ehci_writel(ehci, temp1 | HOSTPC_PHCD, |
902 | hostpc_reg); | 923 | hostpc_reg); |