diff options
Diffstat (limited to 'drivers/usb/host/ehci-hub.c')
-rw-r--r-- | drivers/usb/host/ehci-hub.c | 25 |
1 files changed, 21 insertions, 4 deletions
diff --git a/drivers/usb/host/ehci-hub.c b/drivers/usb/host/ehci-hub.c index e7d3d8def282..796ea0c8900f 100644 --- a/drivers/usb/host/ehci-hub.c +++ b/drivers/usb/host/ehci-hub.c | |||
@@ -107,7 +107,7 @@ static void ehci_handover_companion_ports(struct ehci_hcd *ehci) | |||
107 | } | 107 | } |
108 | 108 | ||
109 | static void ehci_adjust_port_wakeup_flags(struct ehci_hcd *ehci, | 109 | static void ehci_adjust_port_wakeup_flags(struct ehci_hcd *ehci, |
110 | bool suspending) | 110 | bool suspending, bool do_wakeup) |
111 | { | 111 | { |
112 | int port; | 112 | int port; |
113 | u32 temp; | 113 | u32 temp; |
@@ -117,8 +117,7 @@ static void ehci_adjust_port_wakeup_flags(struct ehci_hcd *ehci, | |||
117 | * when the controller is suspended or resumed. In all other | 117 | * when the controller is suspended or resumed. In all other |
118 | * cases they don't need to be changed. | 118 | * cases they don't need to be changed. |
119 | */ | 119 | */ |
120 | if (!ehci_to_hcd(ehci)->self.root_hub->do_remote_wakeup || | 120 | if (!ehci_to_hcd(ehci)->self.root_hub->do_remote_wakeup || do_wakeup) |
121 | device_may_wakeup(ehci_to_hcd(ehci)->self.controller)) | ||
122 | return; | 121 | return; |
123 | 122 | ||
124 | /* clear phy low-power mode before changing wakeup flags */ | 123 | /* clear phy low-power mode before changing wakeup flags */ |
@@ -167,6 +166,10 @@ static void ehci_adjust_port_wakeup_flags(struct ehci_hcd *ehci, | |||
167 | ehci_writel(ehci, temp | HOSTPC_PHCD, hostpc_reg); | 166 | ehci_writel(ehci, temp | HOSTPC_PHCD, hostpc_reg); |
168 | } | 167 | } |
169 | } | 168 | } |
169 | |||
170 | /* Does the root hub have a port wakeup pending? */ | ||
171 | if (!suspending && (ehci_readl(ehci, &ehci->regs->status) & STS_PCD)) | ||
172 | usb_hcd_resume_root_hub(ehci_to_hcd(ehci)); | ||
170 | } | 173 | } |
171 | 174 | ||
172 | static int ehci_bus_suspend (struct usb_hcd *hcd) | 175 | static int ehci_bus_suspend (struct usb_hcd *hcd) |
@@ -316,7 +319,7 @@ static int ehci_bus_resume (struct usb_hcd *hcd) | |||
316 | if (time_before (jiffies, ehci->next_statechange)) | 319 | if (time_before (jiffies, ehci->next_statechange)) |
317 | msleep(5); | 320 | msleep(5); |
318 | spin_lock_irq (&ehci->lock); | 321 | spin_lock_irq (&ehci->lock); |
319 | if (!test_bit(HCD_FLAG_HW_ACCESSIBLE, &hcd->flags)) { | 322 | if (!HCD_HW_ACCESSIBLE(hcd)) { |
320 | spin_unlock_irq(&ehci->lock); | 323 | spin_unlock_irq(&ehci->lock); |
321 | return -ESHUTDOWN; | 324 | return -ESHUTDOWN; |
322 | } | 325 | } |
@@ -603,6 +606,7 @@ ehci_hub_status_data (struct usb_hcd *hcd, char *buf) | |||
603 | u32 mask; | 606 | u32 mask; |
604 | int ports, i, retval = 1; | 607 | int ports, i, retval = 1; |
605 | unsigned long flags; | 608 | unsigned long flags; |
609 | u32 ppcd = 0; | ||
606 | 610 | ||
607 | /* if !USB_SUSPEND, root hub timers won't get shut down ... */ | 611 | /* if !USB_SUSPEND, root hub timers won't get shut down ... */ |
608 | if (!HC_IS_RUNNING(hcd->state)) | 612 | if (!HC_IS_RUNNING(hcd->state)) |
@@ -632,7 +636,15 @@ ehci_hub_status_data (struct usb_hcd *hcd, char *buf) | |||
632 | 636 | ||
633 | /* port N changes (bit N)? */ | 637 | /* port N changes (bit N)? */ |
634 | spin_lock_irqsave (&ehci->lock, flags); | 638 | spin_lock_irqsave (&ehci->lock, flags); |
639 | |||
640 | /* get per-port change detect bits */ | ||
641 | if (ehci->has_ppcd) | ||
642 | ppcd = ehci_readl(ehci, &ehci->regs->status) >> 16; | ||
643 | |||
635 | for (i = 0; i < ports; i++) { | 644 | for (i = 0; i < ports; i++) { |
645 | /* leverage per-port change bits feature */ | ||
646 | if (ehci->has_ppcd && !(ppcd & (1 << i))) | ||
647 | continue; | ||
636 | temp = ehci_readl(ehci, &ehci->regs->port_status [i]); | 648 | temp = ehci_readl(ehci, &ehci->regs->port_status [i]); |
637 | 649 | ||
638 | /* | 650 | /* |
@@ -790,6 +802,11 @@ static int ehci_hub_control ( | |||
790 | status_reg); | 802 | status_reg); |
791 | break; | 803 | break; |
792 | case USB_PORT_FEAT_C_CONNECTION: | 804 | case USB_PORT_FEAT_C_CONNECTION: |
805 | if (ehci->has_lpm) { | ||
806 | /* clear PORTSC bits on disconnect */ | ||
807 | temp &= ~PORT_LPM; | ||
808 | temp &= ~PORT_DEV_ADDR; | ||
809 | } | ||
793 | ehci_writel(ehci, (temp & ~PORT_RWC_BITS) | PORT_CSC, | 810 | ehci_writel(ehci, (temp & ~PORT_RWC_BITS) | PORT_CSC, |
794 | status_reg); | 811 | status_reg); |
795 | break; | 812 | break; |