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.c62
1 files changed, 57 insertions, 5 deletions
diff --git a/drivers/usb/host/ehci-hub.c b/drivers/usb/host/ehci-hub.c
index f46ad27c9a90..6fef1ee7d101 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
@@ -563,7 +589,8 @@ static int ehci_hub_control (
563 int ports = HCS_N_PORTS (ehci->hcs_params); 589 int ports = HCS_N_PORTS (ehci->hcs_params);
564 u32 __iomem *status_reg = &ehci->regs->port_status[ 590 u32 __iomem *status_reg = &ehci->regs->port_status[
565 (wIndex & 0xff) - 1]; 591 (wIndex & 0xff) - 1];
566 u32 temp, status; 592 u32 __iomem *hostpc_reg = NULL;
593 u32 temp, temp1, status;
567 unsigned long flags; 594 unsigned long flags;
568 int retval = 0; 595 int retval = 0;
569 unsigned selector; 596 unsigned selector;
@@ -575,6 +602,9 @@ static int ehci_hub_control (
575 * power, "this is the one", etc. EHCI spec supports this. 602 * power, "this is the one", etc. EHCI spec supports this.
576 */ 603 */
577 604
605 if (ehci->has_hostpc)
606 hostpc_reg = (u32 __iomem *)((u8 *)ehci->regs
607 + HOSTPC0 + 4 * ((wIndex & 0xff) - 1));
578 spin_lock_irqsave (&ehci->lock, flags); 608 spin_lock_irqsave (&ehci->lock, flags);
579 switch (typeReq) { 609 switch (typeReq) {
580 case ClearHubFeature: 610 case ClearHubFeature:
@@ -773,7 +803,11 @@ static int ehci_hub_control (
773 if (temp & PORT_CONNECT) { 803 if (temp & PORT_CONNECT) {
774 status |= 1 << USB_PORT_FEAT_CONNECTION; 804 status |= 1 << USB_PORT_FEAT_CONNECTION;
775 // status may be from integrated TT 805 // status may be from integrated TT
776 status |= ehci_port_speed(ehci, temp); 806 if (ehci->has_hostpc) {
807 temp1 = ehci_readl(ehci, hostpc_reg);
808 status |= ehci_port_speed(ehci, temp1);
809 } else
810 status |= ehci_port_speed(ehci, temp);
777 } 811 }
778 if (temp & PORT_PE) 812 if (temp & PORT_PE)
779 status |= 1 << USB_PORT_FEAT_ENABLE; 813 status |= 1 << USB_PORT_FEAT_ENABLE;
@@ -832,6 +866,24 @@ static int ehci_hub_control (
832 || (temp & PORT_RESET) != 0) 866 || (temp & PORT_RESET) != 0)
833 goto error; 867 goto error;
834 ehci_writel(ehci, temp | PORT_SUSPEND, status_reg); 868 ehci_writel(ehci, temp | PORT_SUSPEND, status_reg);
869 /* After above check the port must be connected.
870 * Set appropriate bit thus could put phy into low power
871 * mode if we have hostpc feature
872 */
873 if (hostpc_reg) {
874 temp &= ~PORT_WKCONN_E;
875 temp |= (PORT_WKDISC_E | PORT_WKOC_E);
876 ehci_writel(ehci, temp | PORT_SUSPEND,
877 status_reg);
878 msleep(5);/* 5ms for HCD enter low pwr mode */
879 temp1 = ehci_readl(ehci, hostpc_reg);
880 ehci_writel(ehci, temp1 | HOSTPC_PHCD,
881 hostpc_reg);
882 temp1 = ehci_readl(ehci, hostpc_reg);
883 ehci_dbg(ehci, "Port%d phy low pwr mode %s\n",
884 wIndex, (temp1 & HOSTPC_PHCD) ?
885 "succeeded" : "failed");
886 }
835 set_bit(wIndex, &ehci->suspended_ports); 887 set_bit(wIndex, &ehci->suspended_ports);
836 break; 888 break;
837 case USB_PORT_FEAT_POWER: 889 case USB_PORT_FEAT_POWER: