summaryrefslogtreecommitdiffstats
path: root/drivers/usb/host/ehci-hub.c
diff options
context:
space:
mode:
authorDmitry Torokhov <dmitry.torokhov@gmail.com>2015-02-10 11:35:36 -0800
committerDmitry Torokhov <dmitry.torokhov@gmail.com>2015-02-10 11:35:36 -0800
commit4ba24fef3eb3b142197135223b90ced2f319cd53 (patch)
treea20c125b27740ec7b4c761b11d801108e1b316b2 /drivers/usb/host/ehci-hub.c
parent47c1ffb2b6b630894e9a16442611c056ab21c057 (diff)
parent98a4a59ee31a12105a2b84f5b8b515ac2cb208ef (diff)
Merge branch 'next' into for-linus
Prepare first round of input updates for 3.20.
Diffstat (limited to 'drivers/usb/host/ehci-hub.c')
-rw-r--r--drivers/usb/host/ehci-hub.c55
1 files changed, 37 insertions, 18 deletions
diff --git a/drivers/usb/host/ehci-hub.c b/drivers/usb/host/ehci-hub.c
index 6130b757490..118edb7bdca 100644
--- a/drivers/usb/host/ehci-hub.c
+++ b/drivers/usb/host/ehci-hub.c
@@ -69,10 +69,8 @@ static void ehci_handover_companion_ports(struct ehci_hcd *ehci)
if (test_bit(port, &ehci->owned_ports)) {
reg = &ehci->regs->port_status[port];
status = ehci_readl(ehci, reg) & ~PORT_RWC_BITS;
- if (!(status & PORT_POWER)) {
- status |= PORT_POWER;
- ehci_writel(ehci, status, reg);
- }
+ if (!(status & PORT_POWER))
+ ehci_port_power(ehci, port, true);
}
}
@@ -656,7 +654,7 @@ ehci_hub_status_data (struct usb_hcd *hcd, char *buf)
/*
* Return status information even for ports with OWNER set.
- * Otherwise khubd wouldn't see the disconnect event when a
+ * Otherwise hub_wq wouldn't see the disconnect event when a
* high-speed device is switched over to the companion
* controller by the user.
*/
@@ -902,7 +900,7 @@ int ehci_hub_control(
/*
* Even if OWNER is set, so the port is owned by the
- * companion controller, khubd needs to be able to clear
+ * companion controller, hub_wq needs to be able to clear
* the port-change status bits (especially
* USB_PORT_STAT_C_CONNECTION).
*/
@@ -922,7 +920,7 @@ int ehci_hub_control(
#ifdef CONFIG_USB_OTG
if ((hcd->self.otg_port == (wIndex + 1))
&& hcd->self.b_hnp_enable) {
- otg_start_hnp(hcd->phy->otg);
+ otg_start_hnp(hcd->usb_phy->otg);
break;
}
#endif
@@ -952,9 +950,11 @@ int ehci_hub_control(
clear_bit(wIndex, &ehci->port_c_suspend);
break;
case USB_PORT_FEAT_POWER:
- if (HCS_PPC (ehci->hcs_params))
- ehci_writel(ehci, temp & ~PORT_POWER,
- status_reg);
+ if (HCS_PPC(ehci->hcs_params)) {
+ spin_unlock_irqrestore(&ehci->lock, flags);
+ ehci_port_power(ehci, wIndex, false);
+ spin_lock_irqsave(&ehci->lock, flags);
+ }
break;
case USB_PORT_FEAT_C_CONNECTION:
ehci_writel(ehci, temp | PORT_CSC, status_reg);
@@ -1000,13 +1000,13 @@ int ehci_hub_control(
* However, not all EHCI implementations do this
* automatically, even if they _do_ support per-port
* power switching; they're allowed to just limit the
- * current. khubd will turn the power back on.
+ * current. hub_wq will turn the power back on.
*/
if (((temp & PORT_OC) || (ehci->need_oc_pp_cycle))
&& HCS_PPC(ehci->hcs_params)) {
- ehci_writel(ehci,
- temp & ~(PORT_RWC_BITS | PORT_POWER),
- status_reg);
+ spin_unlock_irqrestore(&ehci->lock, flags);
+ ehci_port_power(ehci, wIndex, false);
+ spin_lock_irqsave(&ehci->lock, flags);
temp = ehci_readl(ehci, status_reg);
}
}
@@ -1085,7 +1085,7 @@ int ehci_hub_control(
}
/*
- * Even if OWNER is set, there's no harm letting khubd
+ * Even if OWNER is set, there's no harm letting hub_wq
* see the wPortStatus values (they should all be 0 except
* for PORT_POWER anyway).
*/
@@ -1187,9 +1187,11 @@ int ehci_hub_control(
set_bit(wIndex, &ehci->suspended_ports);
break;
case USB_PORT_FEAT_POWER:
- if (HCS_PPC (ehci->hcs_params))
- ehci_writel(ehci, temp | PORT_POWER,
- status_reg);
+ if (HCS_PPC(ehci->hcs_params)) {
+ spin_unlock_irqrestore(&ehci->lock, flags);
+ ehci_port_power(ehci, wIndex, true);
+ spin_lock_irqsave(&ehci->lock, flags);
+ }
break;
case USB_PORT_FEAT_RESET:
if (temp & (PORT_SUSPEND|PORT_RESUME))
@@ -1297,3 +1299,20 @@ static int ehci_port_handed_over(struct usb_hcd *hcd, int portnum)
reg = &ehci->regs->port_status[portnum - 1];
return ehci_readl(ehci, reg) & PORT_OWNER;
}
+
+static int ehci_port_power(struct ehci_hcd *ehci, int portnum, bool enable)
+{
+ struct usb_hcd *hcd = ehci_to_hcd(ehci);
+ u32 __iomem *status_reg = &ehci->regs->port_status[portnum];
+ u32 temp = ehci_readl(ehci, status_reg) & ~PORT_RWC_BITS;
+
+ if (enable)
+ ehci_writel(ehci, temp | PORT_POWER, status_reg);
+ else
+ ehci_writel(ehci, temp & ~PORT_POWER, status_reg);
+
+ if (hcd->driver->port_power)
+ hcd->driver->port_power(hcd, portnum, enable);
+
+ return 0;
+}