diff options
Diffstat (limited to 'drivers/usb/host/ehci-hub.c')
-rw-r--r-- | drivers/usb/host/ehci-hub.c | 84 |
1 files changed, 79 insertions, 5 deletions
diff --git a/drivers/usb/host/ehci-hub.c b/drivers/usb/host/ehci-hub.c index f46ad27c9a90..1b6f1c0e5cee 100644 --- a/drivers/usb/host/ehci-hub.c +++ b/drivers/usb/host/ehci-hub.c | |||
@@ -111,6 +111,7 @@ static int ehci_bus_suspend (struct usb_hcd *hcd) | |||
111 | struct ehci_hcd *ehci = hcd_to_ehci (hcd); | 111 | struct ehci_hcd *ehci = hcd_to_ehci (hcd); |
112 | int port; | 112 | int port; |
113 | int mask; | 113 | int mask; |
114 | u32 __iomem *hostpc_reg = NULL; | ||
114 | 115 | ||
115 | ehci_dbg(ehci, "suspend root hub\n"); | 116 | ehci_dbg(ehci, "suspend root hub\n"); |
116 | 117 | ||
@@ -142,6 +143,9 @@ static int ehci_bus_suspend (struct usb_hcd *hcd) | |||
142 | u32 t1 = ehci_readl(ehci, reg) & ~PORT_RWC_BITS; | 143 | u32 t1 = ehci_readl(ehci, reg) & ~PORT_RWC_BITS; |
143 | u32 t2 = t1; | 144 | u32 t2 = t1; |
144 | 145 | ||
146 | if (ehci->has_hostpc) | ||
147 | hostpc_reg = (u32 __iomem *)((u8 *)ehci->regs | ||
148 | + HOSTPC0 + 4 * (port & 0xff)); | ||
145 | /* keep track of which ports we suspend */ | 149 | /* keep track of which ports we suspend */ |
146 | if (t1 & PORT_OWNER) | 150 | if (t1 & PORT_OWNER) |
147 | set_bit(port, &ehci->owned_ports); | 151 | set_bit(port, &ehci->owned_ports); |
@@ -151,15 +155,37 @@ static int ehci_bus_suspend (struct usb_hcd *hcd) | |||
151 | } | 155 | } |
152 | 156 | ||
153 | /* enable remote wakeup on all ports */ | 157 | /* enable remote wakeup on all ports */ |
154 | if (hcd->self.root_hub->do_remote_wakeup) | 158 | if (hcd->self.root_hub->do_remote_wakeup) { |
155 | t2 |= PORT_WAKE_BITS; | 159 | /* only enable appropriate wake bits, otherwise the |
156 | else | 160 | * hardware can not go phy low power mode. If a race |
161 | * condition happens here(connection change during bits | ||
162 | * set), the port change detection will finally fix it. | ||
163 | */ | ||
164 | if (t1 & PORT_CONNECT) { | ||
165 | t2 |= PORT_WKOC_E | PORT_WKDISC_E; | ||
166 | t2 &= ~PORT_WKCONN_E; | ||
167 | } else { | ||
168 | t2 |= PORT_WKOC_E | PORT_WKCONN_E; | ||
169 | t2 &= ~PORT_WKDISC_E; | ||
170 | } | ||
171 | } else | ||
157 | t2 &= ~PORT_WAKE_BITS; | 172 | t2 &= ~PORT_WAKE_BITS; |
158 | 173 | ||
159 | if (t1 != t2) { | 174 | if (t1 != t2) { |
160 | ehci_vdbg (ehci, "port %d, %08x -> %08x\n", | 175 | ehci_vdbg (ehci, "port %d, %08x -> %08x\n", |
161 | port + 1, t1, t2); | 176 | port + 1, t1, t2); |
162 | ehci_writel(ehci, t2, reg); | 177 | ehci_writel(ehci, t2, reg); |
178 | if (hostpc_reg) { | ||
179 | u32 t3; | ||
180 | |||
181 | msleep(5);/* 5ms for HCD enter low pwr mode */ | ||
182 | t3 = ehci_readl(ehci, hostpc_reg); | ||
183 | ehci_writel(ehci, t3 | HOSTPC_PHCD, hostpc_reg); | ||
184 | t3 = ehci_readl(ehci, hostpc_reg); | ||
185 | ehci_dbg(ehci, "Port%d phy low pwr mode %s\n", | ||
186 | port, (t3 & HOSTPC_PHCD) ? | ||
187 | "succeeded" : "failed"); | ||
188 | } | ||
163 | } | 189 | } |
164 | } | 190 | } |
165 | 191 | ||
@@ -183,6 +209,11 @@ static int ehci_bus_suspend (struct usb_hcd *hcd) | |||
183 | 209 | ||
184 | ehci->next_statechange = jiffies + msecs_to_jiffies(10); | 210 | ehci->next_statechange = jiffies + msecs_to_jiffies(10); |
185 | spin_unlock_irq (&ehci->lock); | 211 | spin_unlock_irq (&ehci->lock); |
212 | |||
213 | /* ehci_work() may have re-enabled the watchdog timer, which we do not | ||
214 | * want, and so we must delete any pending watchdog timer events. | ||
215 | */ | ||
216 | del_timer_sync(&ehci->watchdog); | ||
186 | return 0; | 217 | return 0; |
187 | } | 218 | } |
188 | 219 | ||
@@ -204,6 +235,13 @@ static int ehci_bus_resume (struct usb_hcd *hcd) | |||
204 | return -ESHUTDOWN; | 235 | return -ESHUTDOWN; |
205 | } | 236 | } |
206 | 237 | ||
238 | if (unlikely(ehci->debug)) { | ||
239 | if (ehci->debug && !dbgp_reset_prep()) | ||
240 | ehci->debug = NULL; | ||
241 | else | ||
242 | dbgp_external_startup(); | ||
243 | } | ||
244 | |||
207 | /* Ideally and we've got a real resume here, and no port's power | 245 | /* Ideally and we've got a real resume here, and no port's power |
208 | * was lost. (For PCI, that means Vaux was maintained.) But we | 246 | * was lost. (For PCI, that means Vaux was maintained.) But we |
209 | * could instead be restoring a swsusp snapshot -- so that BIOS was | 247 | * could instead be restoring a swsusp snapshot -- so that BIOS was |
@@ -563,7 +601,8 @@ static int ehci_hub_control ( | |||
563 | int ports = HCS_N_PORTS (ehci->hcs_params); | 601 | int ports = HCS_N_PORTS (ehci->hcs_params); |
564 | u32 __iomem *status_reg = &ehci->regs->port_status[ | 602 | u32 __iomem *status_reg = &ehci->regs->port_status[ |
565 | (wIndex & 0xff) - 1]; | 603 | (wIndex & 0xff) - 1]; |
566 | u32 temp, status; | 604 | u32 __iomem *hostpc_reg = NULL; |
605 | u32 temp, temp1, status; | ||
567 | unsigned long flags; | 606 | unsigned long flags; |
568 | int retval = 0; | 607 | int retval = 0; |
569 | unsigned selector; | 608 | unsigned selector; |
@@ -575,6 +614,9 @@ static int ehci_hub_control ( | |||
575 | * power, "this is the one", etc. EHCI spec supports this. | 614 | * power, "this is the one", etc. EHCI spec supports this. |
576 | */ | 615 | */ |
577 | 616 | ||
617 | if (ehci->has_hostpc) | ||
618 | hostpc_reg = (u32 __iomem *)((u8 *)ehci->regs | ||
619 | + HOSTPC0 + 4 * ((wIndex & 0xff) - 1)); | ||
578 | spin_lock_irqsave (&ehci->lock, flags); | 620 | spin_lock_irqsave (&ehci->lock, flags); |
579 | switch (typeReq) { | 621 | switch (typeReq) { |
580 | case ClearHubFeature: | 622 | case ClearHubFeature: |
@@ -773,7 +815,11 @@ static int ehci_hub_control ( | |||
773 | if (temp & PORT_CONNECT) { | 815 | if (temp & PORT_CONNECT) { |
774 | status |= 1 << USB_PORT_FEAT_CONNECTION; | 816 | status |= 1 << USB_PORT_FEAT_CONNECTION; |
775 | // status may be from integrated TT | 817 | // status may be from integrated TT |
776 | status |= ehci_port_speed(ehci, temp); | 818 | if (ehci->has_hostpc) { |
819 | temp1 = ehci_readl(ehci, hostpc_reg); | ||
820 | status |= ehci_port_speed(ehci, temp1); | ||
821 | } else | ||
822 | status |= ehci_port_speed(ehci, temp); | ||
777 | } | 823 | } |
778 | if (temp & PORT_PE) | 824 | if (temp & PORT_PE) |
779 | status |= 1 << USB_PORT_FEAT_ENABLE; | 825 | status |= 1 << USB_PORT_FEAT_ENABLE; |
@@ -816,6 +862,15 @@ static int ehci_hub_control ( | |||
816 | case SetPortFeature: | 862 | case SetPortFeature: |
817 | selector = wIndex >> 8; | 863 | selector = wIndex >> 8; |
818 | wIndex &= 0xff; | 864 | wIndex &= 0xff; |
865 | if (unlikely(ehci->debug)) { | ||
866 | /* If the debug port is active any port | ||
867 | * feature requests should get denied */ | ||
868 | if (wIndex == HCS_DEBUG_PORT(ehci->hcs_params) && | ||
869 | (readl(&ehci->debug->control) & DBGP_ENABLED)) { | ||
870 | retval = -ENODEV; | ||
871 | goto error_exit; | ||
872 | } | ||
873 | } | ||
819 | if (!wIndex || wIndex > ports) | 874 | if (!wIndex || wIndex > ports) |
820 | goto error; | 875 | goto error; |
821 | wIndex--; | 876 | wIndex--; |
@@ -832,6 +887,24 @@ static int ehci_hub_control ( | |||
832 | || (temp & PORT_RESET) != 0) | 887 | || (temp & PORT_RESET) != 0) |
833 | goto error; | 888 | goto error; |
834 | ehci_writel(ehci, temp | PORT_SUSPEND, status_reg); | 889 | ehci_writel(ehci, temp | PORT_SUSPEND, status_reg); |
890 | /* After above check the port must be connected. | ||
891 | * Set appropriate bit thus could put phy into low power | ||
892 | * mode if we have hostpc feature | ||
893 | */ | ||
894 | if (hostpc_reg) { | ||
895 | temp &= ~PORT_WKCONN_E; | ||
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 */ | ||
900 | temp1 = ehci_readl(ehci, hostpc_reg); | ||
901 | ehci_writel(ehci, temp1 | HOSTPC_PHCD, | ||
902 | hostpc_reg); | ||
903 | temp1 = ehci_readl(ehci, hostpc_reg); | ||
904 | ehci_dbg(ehci, "Port%d phy low pwr mode %s\n", | ||
905 | wIndex, (temp1 & HOSTPC_PHCD) ? | ||
906 | "succeeded" : "failed"); | ||
907 | } | ||
835 | set_bit(wIndex, &ehci->suspended_ports); | 908 | set_bit(wIndex, &ehci->suspended_ports); |
836 | break; | 909 | break; |
837 | case USB_PORT_FEAT_POWER: | 910 | case USB_PORT_FEAT_POWER: |
@@ -894,6 +967,7 @@ error: | |||
894 | /* "stall" on error */ | 967 | /* "stall" on error */ |
895 | retval = -EPIPE; | 968 | retval = -EPIPE; |
896 | } | 969 | } |
970 | error_exit: | ||
897 | spin_unlock_irqrestore (&ehci->lock, flags); | 971 | spin_unlock_irqrestore (&ehci->lock, flags); |
898 | return retval; | 972 | return retval; |
899 | } | 973 | } |