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.c182
1 files changed, 138 insertions, 44 deletions
diff --git a/drivers/usb/host/ehci-hub.c b/drivers/usb/host/ehci-hub.c
index c7178bcde67a..e7d3d8def282 100644
--- a/drivers/usb/host/ehci-hub.c
+++ b/drivers/usb/host/ehci-hub.c
@@ -106,12 +106,75 @@ static void ehci_handover_companion_ports(struct ehci_hcd *ehci)
106 ehci->owned_ports = 0; 106 ehci->owned_ports = 0;
107} 107}
108 108
109static void ehci_adjust_port_wakeup_flags(struct ehci_hcd *ehci,
110 bool suspending)
111{
112 int port;
113 u32 temp;
114
115 /* If remote wakeup is enabled for the root hub but disabled
116 * for the controller, we must adjust all the port wakeup flags
117 * when the controller is suspended or resumed. In all other
118 * cases they don't need to be changed.
119 */
120 if (!ehci_to_hcd(ehci)->self.root_hub->do_remote_wakeup ||
121 device_may_wakeup(ehci_to_hcd(ehci)->self.controller))
122 return;
123
124 /* clear phy low-power mode before changing wakeup flags */
125 if (ehci->has_hostpc) {
126 port = HCS_N_PORTS(ehci->hcs_params);
127 while (port--) {
128 u32 __iomem *hostpc_reg;
129
130 hostpc_reg = (u32 __iomem *)((u8 *) ehci->regs
131 + HOSTPC0 + 4 * port);
132 temp = ehci_readl(ehci, hostpc_reg);
133 ehci_writel(ehci, temp & ~HOSTPC_PHCD, hostpc_reg);
134 }
135 msleep(5);
136 }
137
138 port = HCS_N_PORTS(ehci->hcs_params);
139 while (port--) {
140 u32 __iomem *reg = &ehci->regs->port_status[port];
141 u32 t1 = ehci_readl(ehci, reg) & ~PORT_RWC_BITS;
142 u32 t2 = t1 & ~PORT_WAKE_BITS;
143
144 /* If we are suspending the controller, clear the flags.
145 * If we are resuming the controller, set the wakeup flags.
146 */
147 if (!suspending) {
148 if (t1 & PORT_CONNECT)
149 t2 |= PORT_WKOC_E | PORT_WKDISC_E;
150 else
151 t2 |= PORT_WKOC_E | PORT_WKCONN_E;
152 }
153 ehci_vdbg(ehci, "port %d, %08x -> %08x\n",
154 port + 1, t1, t2);
155 ehci_writel(ehci, t2, reg);
156 }
157
158 /* enter phy low-power mode again */
159 if (ehci->has_hostpc) {
160 port = HCS_N_PORTS(ehci->hcs_params);
161 while (port--) {
162 u32 __iomem *hostpc_reg;
163
164 hostpc_reg = (u32 __iomem *)((u8 *) ehci->regs
165 + HOSTPC0 + 4 * port);
166 temp = ehci_readl(ehci, hostpc_reg);
167 ehci_writel(ehci, temp | HOSTPC_PHCD, hostpc_reg);
168 }
169 }
170}
171
109static int ehci_bus_suspend (struct usb_hcd *hcd) 172static int ehci_bus_suspend (struct usb_hcd *hcd)
110{ 173{
111 struct ehci_hcd *ehci = hcd_to_ehci (hcd); 174 struct ehci_hcd *ehci = hcd_to_ehci (hcd);
112 int port; 175 int port;
113 int mask; 176 int mask;
114 u32 __iomem *hostpc_reg = NULL; 177 int changed;
115 178
116 ehci_dbg(ehci, "suspend root hub\n"); 179 ehci_dbg(ehci, "suspend root hub\n");
117 180
@@ -155,15 +218,13 @@ static int ehci_bus_suspend (struct usb_hcd *hcd)
155 */ 218 */
156 ehci->bus_suspended = 0; 219 ehci->bus_suspended = 0;
157 ehci->owned_ports = 0; 220 ehci->owned_ports = 0;
221 changed = 0;
158 port = HCS_N_PORTS(ehci->hcs_params); 222 port = HCS_N_PORTS(ehci->hcs_params);
159 while (port--) { 223 while (port--) {
160 u32 __iomem *reg = &ehci->regs->port_status [port]; 224 u32 __iomem *reg = &ehci->regs->port_status [port];
161 u32 t1 = ehci_readl(ehci, reg) & ~PORT_RWC_BITS; 225 u32 t1 = ehci_readl(ehci, reg) & ~PORT_RWC_BITS;
162 u32 t2 = t1; 226 u32 t2 = t1 & ~PORT_WAKE_BITS;
163 227
164 if (ehci->has_hostpc)
165 hostpc_reg = (u32 __iomem *)((u8 *)ehci->regs
166 + HOSTPC0 + 4 * (port & 0xff));
167 /* keep track of which ports we suspend */ 228 /* keep track of which ports we suspend */
168 if (t1 & PORT_OWNER) 229 if (t1 & PORT_OWNER)
169 set_bit(port, &ehci->owned_ports); 230 set_bit(port, &ehci->owned_ports);
@@ -172,40 +233,45 @@ static int ehci_bus_suspend (struct usb_hcd *hcd)
172 set_bit(port, &ehci->bus_suspended); 233 set_bit(port, &ehci->bus_suspended);
173 } 234 }
174 235
175 /* enable remote wakeup on all ports */ 236 /* enable remote wakeup on all ports, if told to do so */
176 if (hcd->self.root_hub->do_remote_wakeup) { 237 if (hcd->self.root_hub->do_remote_wakeup) {
177 /* only enable appropriate wake bits, otherwise the 238 /* only enable appropriate wake bits, otherwise the
178 * hardware can not go phy low power mode. If a race 239 * hardware can not go phy low power mode. If a race
179 * condition happens here(connection change during bits 240 * condition happens here(connection change during bits
180 * set), the port change detection will finally fix it. 241 * set), the port change detection will finally fix it.
181 */ 242 */
182 if (t1 & PORT_CONNECT) { 243 if (t1 & PORT_CONNECT)
183 t2 |= PORT_WKOC_E | PORT_WKDISC_E; 244 t2 |= PORT_WKOC_E | PORT_WKDISC_E;
184 t2 &= ~PORT_WKCONN_E; 245 else
185 } else {
186 t2 |= PORT_WKOC_E | PORT_WKCONN_E; 246 t2 |= PORT_WKOC_E | PORT_WKCONN_E;
187 t2 &= ~PORT_WKDISC_E; 247 }
188 }
189 } else
190 t2 &= ~PORT_WAKE_BITS;
191 248
192 if (t1 != t2) { 249 if (t1 != t2) {
193 ehci_vdbg (ehci, "port %d, %08x -> %08x\n", 250 ehci_vdbg (ehci, "port %d, %08x -> %08x\n",
194 port + 1, t1, t2); 251 port + 1, t1, t2);
195 ehci_writel(ehci, t2, reg); 252 ehci_writel(ehci, t2, reg);
196 if (hostpc_reg) { 253 changed = 1;
197 u32 t3; 254 }
255 }
198 256
199 spin_unlock_irq(&ehci->lock); 257 if (changed && ehci->has_hostpc) {
200 msleep(5);/* 5ms for HCD enter low pwr mode */ 258 spin_unlock_irq(&ehci->lock);
201 spin_lock_irq(&ehci->lock); 259 msleep(5); /* 5 ms for HCD to enter low-power mode */
202 t3 = ehci_readl(ehci, hostpc_reg); 260 spin_lock_irq(&ehci->lock);
203 ehci_writel(ehci, t3 | HOSTPC_PHCD, hostpc_reg); 261
204 t3 = ehci_readl(ehci, hostpc_reg); 262 port = HCS_N_PORTS(ehci->hcs_params);
205 ehci_dbg(ehci, "Port%d phy low pwr mode %s\n", 263 while (port--) {
264 u32 __iomem *hostpc_reg;
265 u32 t3;
266
267 hostpc_reg = (u32 __iomem *)((u8 *) ehci->regs
268 + HOSTPC0 + 4 * port);
269 t3 = ehci_readl(ehci, hostpc_reg);
270 ehci_writel(ehci, t3 | HOSTPC_PHCD, hostpc_reg);
271 t3 = ehci_readl(ehci, hostpc_reg);
272 ehci_dbg(ehci, "Port %d phy low-power mode %s\n",
206 port, (t3 & HOSTPC_PHCD) ? 273 port, (t3 & HOSTPC_PHCD) ?
207 "succeeded" : "failed"); 274 "succeeded" : "failed");
208 }
209 } 275 }
210 } 276 }
211 277
@@ -291,6 +357,25 @@ static int ehci_bus_resume (struct usb_hcd *hcd)
291 msleep(8); 357 msleep(8);
292 spin_lock_irq(&ehci->lock); 358 spin_lock_irq(&ehci->lock);
293 359
360 /* clear phy low-power mode before resume */
361 if (ehci->bus_suspended && ehci->has_hostpc) {
362 i = HCS_N_PORTS(ehci->hcs_params);
363 while (i--) {
364 if (test_bit(i, &ehci->bus_suspended)) {
365 u32 __iomem *hostpc_reg;
366
367 hostpc_reg = (u32 __iomem *)((u8 *) ehci->regs
368 + HOSTPC0 + 4 * i);
369 temp = ehci_readl(ehci, hostpc_reg);
370 ehci_writel(ehci, temp & ~HOSTPC_PHCD,
371 hostpc_reg);
372 }
373 }
374 spin_unlock_irq(&ehci->lock);
375 msleep(5);
376 spin_lock_irq(&ehci->lock);
377 }
378
294 /* manually resume the ports we suspended during bus_suspend() */ 379 /* manually resume the ports we suspended during bus_suspend() */
295 i = HCS_N_PORTS (ehci->hcs_params); 380 i = HCS_N_PORTS (ehci->hcs_params);
296 while (i--) { 381 while (i--) {
@@ -659,7 +744,7 @@ static int ehci_hub_control (
659 * Even if OWNER is set, so the port is owned by the 744 * Even if OWNER is set, so the port is owned by the
660 * companion controller, khubd needs to be able to clear 745 * companion controller, khubd needs to be able to clear
661 * the port-change status bits (especially 746 * the port-change status bits (especially
662 * USB_PORT_FEAT_C_CONNECTION). 747 * USB_PORT_STAT_C_CONNECTION).
663 */ 748 */
664 749
665 switch (wValue) { 750 switch (wValue) {
@@ -675,16 +760,25 @@ static int ehci_hub_control (
675 goto error; 760 goto error;
676 if (ehci->no_selective_suspend) 761 if (ehci->no_selective_suspend)
677 break; 762 break;
678 if (temp & PORT_SUSPEND) { 763 if (!(temp & PORT_SUSPEND))
679 if ((temp & PORT_PE) == 0) 764 break;
680 goto error; 765 if ((temp & PORT_PE) == 0)
681 /* resume signaling for 20 msec */ 766 goto error;
682 temp &= ~(PORT_RWC_BITS | PORT_WAKE_BITS); 767
683 ehci_writel(ehci, temp | PORT_RESUME, 768 /* clear phy low-power mode before resume */
684 status_reg); 769 if (hostpc_reg) {
685 ehci->reset_done [wIndex] = jiffies 770 temp1 = ehci_readl(ehci, hostpc_reg);
686 + msecs_to_jiffies (20); 771 ehci_writel(ehci, temp1 & ~HOSTPC_PHCD,
772 hostpc_reg);
773 spin_unlock_irqrestore(&ehci->lock, flags);
774 msleep(5);/* wait to leave low-power mode */
775 spin_lock_irqsave(&ehci->lock, flags);
687 } 776 }
777 /* resume signaling for 20 msec */
778 temp &= ~(PORT_RWC_BITS | PORT_WAKE_BITS);
779 ehci_writel(ehci, temp | PORT_RESUME, status_reg);
780 ehci->reset_done[wIndex] = jiffies
781 + msecs_to_jiffies(20);
688 break; 782 break;
689 case USB_PORT_FEAT_C_SUSPEND: 783 case USB_PORT_FEAT_C_SUSPEND:
690 clear_bit(wIndex, &ehci->port_c_suspend); 784 clear_bit(wIndex, &ehci->port_c_suspend);
@@ -729,12 +823,12 @@ static int ehci_hub_control (
729 823
730 // wPortChange bits 824 // wPortChange bits
731 if (temp & PORT_CSC) 825 if (temp & PORT_CSC)
732 status |= 1 << USB_PORT_FEAT_C_CONNECTION; 826 status |= USB_PORT_STAT_C_CONNECTION << 16;
733 if (temp & PORT_PEC) 827 if (temp & PORT_PEC)
734 status |= 1 << USB_PORT_FEAT_C_ENABLE; 828 status |= USB_PORT_STAT_C_ENABLE << 16;
735 829
736 if ((temp & PORT_OCC) && !ignore_oc){ 830 if ((temp & PORT_OCC) && !ignore_oc){
737 status |= 1 << USB_PORT_FEAT_C_OVER_CURRENT; 831 status |= USB_PORT_STAT_C_OVERCURRENT << 16;
738 832
739 /* 833 /*
740 * Hubs should disable port power on over-current. 834 * Hubs should disable port power on over-current.
@@ -791,7 +885,7 @@ static int ehci_hub_control (
791 if ((temp & PORT_RESET) 885 if ((temp & PORT_RESET)
792 && time_after_eq(jiffies, 886 && time_after_eq(jiffies,
793 ehci->reset_done[wIndex])) { 887 ehci->reset_done[wIndex])) {
794 status |= 1 << USB_PORT_FEAT_C_RESET; 888 status |= USB_PORT_STAT_C_RESET << 16;
795 ehci->reset_done [wIndex] = 0; 889 ehci->reset_done [wIndex] = 0;
796 890
797 /* force reset to complete */ 891 /* force reset to complete */
@@ -833,7 +927,7 @@ static int ehci_hub_control (
833 */ 927 */
834 928
835 if (temp & PORT_CONNECT) { 929 if (temp & PORT_CONNECT) {
836 status |= 1 << USB_PORT_FEAT_CONNECTION; 930 status |= USB_PORT_STAT_CONNECTION;
837 // status may be from integrated TT 931 // status may be from integrated TT
838 if (ehci->has_hostpc) { 932 if (ehci->has_hostpc) {
839 temp1 = ehci_readl(ehci, hostpc_reg); 933 temp1 = ehci_readl(ehci, hostpc_reg);
@@ -842,11 +936,11 @@ static int ehci_hub_control (
842 status |= ehci_port_speed(ehci, temp); 936 status |= ehci_port_speed(ehci, temp);
843 } 937 }
844 if (temp & PORT_PE) 938 if (temp & PORT_PE)
845 status |= 1 << USB_PORT_FEAT_ENABLE; 939 status |= USB_PORT_STAT_ENABLE;
846 940
847 /* maybe the port was unsuspended without our knowledge */ 941 /* maybe the port was unsuspended without our knowledge */
848 if (temp & (PORT_SUSPEND|PORT_RESUME)) { 942 if (temp & (PORT_SUSPEND|PORT_RESUME)) {
849 status |= 1 << USB_PORT_FEAT_SUSPEND; 943 status |= USB_PORT_STAT_SUSPEND;
850 } else if (test_bit(wIndex, &ehci->suspended_ports)) { 944 } else if (test_bit(wIndex, &ehci->suspended_ports)) {
851 clear_bit(wIndex, &ehci->suspended_ports); 945 clear_bit(wIndex, &ehci->suspended_ports);
852 ehci->reset_done[wIndex] = 0; 946 ehci->reset_done[wIndex] = 0;
@@ -855,13 +949,13 @@ static int ehci_hub_control (
855 } 949 }
856 950
857 if (temp & PORT_OC) 951 if (temp & PORT_OC)
858 status |= 1 << USB_PORT_FEAT_OVER_CURRENT; 952 status |= USB_PORT_STAT_OVERCURRENT;
859 if (temp & PORT_RESET) 953 if (temp & PORT_RESET)
860 status |= 1 << USB_PORT_FEAT_RESET; 954 status |= USB_PORT_STAT_RESET;
861 if (temp & PORT_POWER) 955 if (temp & PORT_POWER)
862 status |= 1 << USB_PORT_FEAT_POWER; 956 status |= USB_PORT_STAT_POWER;
863 if (test_bit(wIndex, &ehci->port_c_suspend)) 957 if (test_bit(wIndex, &ehci->port_c_suspend))
864 status |= 1 << USB_PORT_FEAT_C_SUSPEND; 958 status |= USB_PORT_STAT_C_SUSPEND << 16;
865 959
866#ifndef VERBOSE_DEBUG 960#ifndef VERBOSE_DEBUG
867 if (status & ~0xffff) /* only if wPortChange is interesting */ 961 if (status & ~0xffff) /* only if wPortChange is interesting */