status_reg = &ehci->regs->port_status[(wIndex & 0xff) - 1];
+ spin_lock_irqsave(&ehci->lock, flags);
+
/*
* In ehci_hub_control() for USB_PORT_FEAT_ENABLE clears the other bits
* that are write on clear, by writing back the register read value, so
* USB_PORT_FEAT_ENABLE is handled by masking the set on clear bits
*/
if (typeReq == ClearPortFeature && wValue == USB_PORT_FEAT_ENABLE) {
- spin_lock_irqsave(&ehci->lock, flags);
temp = ehci_readl(ehci, status_reg);
ehci_writel(ehci, (temp & ~PORT_RWC_BITS) & ~PORT_PE, status_reg);
- spin_unlock_irqrestore(&ehci->lock, flags);
- return retval;
+ goto done;
}
- if (typeReq == GetPortStatus) {
- spin_lock_irqsave(&ehci->lock, flags);
+ else if (typeReq == GetPortStatus) {
temp = ehci_readl(ehci, status_reg);
- if (tegra->port_resuming && !(temp & PORT_SUSPEND)) {
+ if (tegra->port_resuming && !(temp & PORT_SUSPEND)) {
/* resume completed */
tegra->port_resuming = 0;
tegra_usb_phy_postresume(tegra->phy);
}
- spin_unlock_irqrestore(&ehci->lock, flags);
}
- if (typeReq == SetPortFeature && wValue == USB_PORT_FEAT_SUSPEND) {
- spin_lock_irqsave(&ehci->lock, flags);
+ else if (typeReq == SetPortFeature && wValue == USB_PORT_FEAT_SUSPEND) {
temp = ehci_readl(ehci, status_reg);
- if ((temp & PORT_PE) == 0 || (temp & PORT_RESET) != 0)
+ if ((temp & PORT_PE) == 0 || (temp & PORT_RESET) != 0) {
retval = -EPIPE;
+ goto done;
+ }
/* After above check the port must be connected.
* Set appropriate bit thus could put phy into low power
if (handshake(ehci, status_reg, PORT_SUSPEND,
PORT_SUSPEND, 5000))
pr_err("%s: timeout waiting for PORT_SUSPEND\n", __func__);
- spin_unlock_irqrestore(&ehci->lock, flags);
- return retval;
+ goto done;
}
/*
* to set this bit to a zero after the resume duration is timed in the
* driver.
*/
- if (typeReq == ClearPortFeature && wValue == USB_PORT_FEAT_SUSPEND) {
- spin_lock_irqsave(&ehci->lock, flags);
+ else if (typeReq == ClearPortFeature && wValue == USB_PORT_FEAT_SUSPEND) {
temp = ehci_readl(ehci, status_reg);
- if ((temp & PORT_RESET) || !(temp & PORT_PE))
+ if ((temp & PORT_RESET) || !(temp & PORT_PE)) {
retval = -EPIPE;
-
- if (!(temp & PORT_SUSPEND)) {
- spin_unlock_irqrestore(&ehci->lock, flags);
- return retval;
+ goto done;
}
+ if (!(temp & PORT_SUSPEND))
+ goto done;
+
tegra_usb_phy_preresume(tegra->phy);
/* reschedule root hub polling during resume signaling */
/* start resume signalling */
ehci_writel(ehci, temp | PORT_RESUME, status_reg);
+ spin_unlock_irqrestore(&ehci->lock, flags);
+ msleep(20);
+ spin_lock_irqsave(&ehci->lock, flags);
+
/* polling PORT_RESUME until the controller clear this bit */
- if (handshake(ehci, status_reg, PORT_RESUME, 0, 20000))
+ if (handshake(ehci, status_reg, PORT_RESUME, 0, 2000))
pr_err("%s: timeout waiting for PORT_RESUME\n", __func__);
/* write PORT_RESUME to 0 to clear PORT_SUSPEND bit */
pr_err("%s: timeout waiting for PORT_SUSPEND\n", __func__);
tegra->port_resuming = 1;
-
- spin_unlock_irqrestore(&ehci->lock, flags);
- return retval;
+ goto done;
}
+ spin_unlock_irqrestore(&ehci->lock, flags);
+
/* Handle the hub control events here */
return ehci_hub_control(hcd, typeReq, wValue, wIndex, buf, wLength);
+done:
+ spin_unlock_irqrestore(&ehci->lock, flags);
+ return retval;
}
static void tegra_ehci_restart(struct usb_hcd *hcd)