diff options
Diffstat (limited to 'drivers/usb/host/ehci-hub.c')
-rw-r--r-- | drivers/usb/host/ehci-hub.c | 62 |
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: |