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.c49
1 files changed, 43 insertions, 6 deletions
diff --git a/drivers/usb/host/ehci-hub.c b/drivers/usb/host/ehci-hub.c
index 796ea0c8900f..ea6184bf48d0 100644
--- a/drivers/usb/host/ehci-hub.c
+++ b/drivers/usb/host/ehci-hub.c
@@ -27,6 +27,7 @@
27 */ 27 */
28 28
29/*-------------------------------------------------------------------------*/ 29/*-------------------------------------------------------------------------*/
30#include <linux/usb/otg.h>
30 31
31#define PORT_WAKE_BITS (PORT_WKOC_E|PORT_WKDISC_E|PORT_WKCONN_E) 32#define PORT_WAKE_BITS (PORT_WKOC_E|PORT_WKDISC_E|PORT_WKCONN_E)
32 33
@@ -106,11 +107,33 @@ static void ehci_handover_companion_ports(struct ehci_hcd *ehci)
106 ehci->owned_ports = 0; 107 ehci->owned_ports = 0;
107} 108}
108 109
109static void ehci_adjust_port_wakeup_flags(struct ehci_hcd *ehci, 110static int ehci_port_change(struct ehci_hcd *ehci)
111{
112 int i = HCS_N_PORTS(ehci->hcs_params);
113
114 /* First check if the controller indicates a change event */
115
116 if (ehci_readl(ehci, &ehci->regs->status) & STS_PCD)
117 return 1;
118
119 /*
120 * Not all controllers appear to update this while going from D3 to D0,
121 * so check the individual port status registers as well
122 */
123
124 while (i--)
125 if (ehci_readl(ehci, &ehci->regs->port_status[i]) & PORT_CSC)
126 return 1;
127
128 return 0;
129}
130
131static __maybe_unused void ehci_adjust_port_wakeup_flags(struct ehci_hcd *ehci,
110 bool suspending, bool do_wakeup) 132 bool suspending, bool do_wakeup)
111{ 133{
112 int port; 134 int port;
113 u32 temp; 135 u32 temp;
136 unsigned long flags;
114 137
115 /* If remote wakeup is enabled for the root hub but disabled 138 /* If remote wakeup is enabled for the root hub but disabled
116 * for the controller, we must adjust all the port wakeup flags 139 * for the controller, we must adjust all the port wakeup flags
@@ -120,6 +143,8 @@ static void ehci_adjust_port_wakeup_flags(struct ehci_hcd *ehci,
120 if (!ehci_to_hcd(ehci)->self.root_hub->do_remote_wakeup || do_wakeup) 143 if (!ehci_to_hcd(ehci)->self.root_hub->do_remote_wakeup || do_wakeup)
121 return; 144 return;
122 145
146 spin_lock_irqsave(&ehci->lock, flags);
147
123 /* clear phy low-power mode before changing wakeup flags */ 148 /* clear phy low-power mode before changing wakeup flags */
124 if (ehci->has_hostpc) { 149 if (ehci->has_hostpc) {
125 port = HCS_N_PORTS(ehci->hcs_params); 150 port = HCS_N_PORTS(ehci->hcs_params);
@@ -131,7 +156,9 @@ static void ehci_adjust_port_wakeup_flags(struct ehci_hcd *ehci,
131 temp = ehci_readl(ehci, hostpc_reg); 156 temp = ehci_readl(ehci, hostpc_reg);
132 ehci_writel(ehci, temp & ~HOSTPC_PHCD, hostpc_reg); 157 ehci_writel(ehci, temp & ~HOSTPC_PHCD, hostpc_reg);
133 } 158 }
159 spin_unlock_irqrestore(&ehci->lock, flags);
134 msleep(5); 160 msleep(5);
161 spin_lock_irqsave(&ehci->lock, flags);
135 } 162 }
136 163
137 port = HCS_N_PORTS(ehci->hcs_params); 164 port = HCS_N_PORTS(ehci->hcs_params);
@@ -168,8 +195,10 @@ static void ehci_adjust_port_wakeup_flags(struct ehci_hcd *ehci,
168 } 195 }
169 196
170 /* Does the root hub have a port wakeup pending? */ 197 /* Does the root hub have a port wakeup pending? */
171 if (!suspending && (ehci_readl(ehci, &ehci->regs->status) & STS_PCD)) 198 if (!suspending && ehci_port_change(ehci))
172 usb_hcd_resume_root_hub(ehci_to_hcd(ehci)); 199 usb_hcd_resume_root_hub(ehci_to_hcd(ehci));
200
201 spin_unlock_irqrestore(&ehci->lock, flags);
173} 202}
174 203
175static int ehci_bus_suspend (struct usb_hcd *hcd) 204static int ehci_bus_suspend (struct usb_hcd *hcd)
@@ -531,14 +560,15 @@ static ssize_t store_companion(struct device *dev,
531} 560}
532static DEVICE_ATTR(companion, 0644, show_companion, store_companion); 561static DEVICE_ATTR(companion, 0644, show_companion, store_companion);
533 562
534static inline void create_companion_file(struct ehci_hcd *ehci) 563static inline int create_companion_file(struct ehci_hcd *ehci)
535{ 564{
536 int i; 565 int i = 0;
537 566
538 /* with integrated TT there is no companion! */ 567 /* with integrated TT there is no companion! */
539 if (!ehci_is_TDI(ehci)) 568 if (!ehci_is_TDI(ehci))
540 i = device_create_file(ehci_to_hcd(ehci)->self.controller, 569 i = device_create_file(ehci_to_hcd(ehci)->self.controller,
541 &dev_attr_companion); 570 &dev_attr_companion);
571 return i;
542} 572}
543 573
544static inline void remove_companion_file(struct ehci_hcd *ehci) 574static inline void remove_companion_file(struct ehci_hcd *ehci)
@@ -688,8 +718,8 @@ ehci_hub_descriptor (
688 desc->bDescLength = 7 + 2 * temp; 718 desc->bDescLength = 7 + 2 * temp;
689 719
690 /* two bitmaps: ports removable, and usb 1.0 legacy PortPwrCtrlMask */ 720 /* two bitmaps: ports removable, and usb 1.0 legacy PortPwrCtrlMask */
691 memset (&desc->bitmap [0], 0, temp); 721 memset(&desc->u.hs.DeviceRemovable[0], 0, temp);
692 memset (&desc->bitmap [temp], 0xff, temp); 722 memset(&desc->u.hs.DeviceRemovable[temp], 0xff, temp);
693 723
694 temp = 0x0008; /* per-port overcurrent reporting */ 724 temp = 0x0008; /* per-port overcurrent reporting */
695 if (HCS_PPC (ehci->hcs_params)) 725 if (HCS_PPC (ehci->hcs_params))
@@ -772,6 +802,13 @@ static int ehci_hub_control (
772 goto error; 802 goto error;
773 if (ehci->no_selective_suspend) 803 if (ehci->no_selective_suspend)
774 break; 804 break;
805#ifdef CONFIG_USB_OTG
806 if ((hcd->self.otg_port == (wIndex + 1))
807 && hcd->self.b_hnp_enable) {
808 otg_start_hnp(ehci->transceiver);
809 break;
810 }
811#endif
775 if (!(temp & PORT_SUSPEND)) 812 if (!(temp & PORT_SUSPEND))
776 break; 813 break;
777 if ((temp & PORT_PE) == 0) 814 if ((temp & PORT_PE) == 0)