|
@@ -540,6 +540,49 @@ static int xhci_get_ports(struct usb_hcd *hcd, __le32 __iomem ***port_array)
|
|
|
return max_ports;
|
|
|
}
|
|
|
|
|
|
+static __le32 __iomem *xhci_get_port_io_addr(struct usb_hcd *hcd, int index)
|
|
|
+{
|
|
|
+ __le32 __iomem **port_array;
|
|
|
+
|
|
|
+ xhci_get_ports(hcd, &port_array);
|
|
|
+ return port_array[index];
|
|
|
+}
|
|
|
+
|
|
|
+/*
|
|
|
+ * xhci_set_port_power() must be called with xhci->lock held.
|
|
|
+ * It will release and re-aquire the lock while calling ACPI
|
|
|
+ * method.
|
|
|
+ */
|
|
|
+static void xhci_set_port_power(struct xhci_hcd *xhci, struct usb_hcd *hcd,
|
|
|
+ u16 index, bool on)
|
|
|
+{
|
|
|
+ __le32 __iomem *addr;
|
|
|
+ u32 temp;
|
|
|
+ unsigned long flags = 0;
|
|
|
+
|
|
|
+ addr = xhci_get_port_io_addr(hcd, index);
|
|
|
+ temp = readl(addr);
|
|
|
+ temp = xhci_port_state_to_neutral(temp);
|
|
|
+ if (on) {
|
|
|
+ /* Power on */
|
|
|
+ writel(temp | PORT_POWER, addr);
|
|
|
+ temp = readl(addr);
|
|
|
+ xhci_dbg(xhci, "set port power, actual port %d status = 0x%x\n",
|
|
|
+ index, temp);
|
|
|
+ } else {
|
|
|
+ /* Power off */
|
|
|
+ writel(temp & ~PORT_POWER, addr);
|
|
|
+ }
|
|
|
+
|
|
|
+ spin_unlock_irqrestore(&xhci->lock, flags);
|
|
|
+ temp = usb_acpi_power_manageable(hcd->self.root_hub,
|
|
|
+ index);
|
|
|
+ if (temp)
|
|
|
+ usb_acpi_set_power_state(hcd->self.root_hub,
|
|
|
+ index, on);
|
|
|
+ spin_lock_irqsave(&xhci->lock, flags);
|
|
|
+}
|
|
|
+
|
|
|
void xhci_set_link_state(struct xhci_hcd *xhci, __le32 __iomem **port_array,
|
|
|
int port_id, u32 link_state)
|
|
|
{
|
|
@@ -1092,18 +1135,7 @@ int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
|
|
|
* However, hub_wq will ignore the roothub events until
|
|
|
* the roothub is registered.
|
|
|
*/
|
|
|
- writel(temp | PORT_POWER, port_array[wIndex]);
|
|
|
-
|
|
|
- temp = readl(port_array[wIndex]);
|
|
|
- xhci_dbg(xhci, "set port power, actual port %d status = 0x%x\n", wIndex, temp);
|
|
|
-
|
|
|
- spin_unlock_irqrestore(&xhci->lock, flags);
|
|
|
- temp = usb_acpi_power_manageable(hcd->self.root_hub,
|
|
|
- wIndex);
|
|
|
- if (temp)
|
|
|
- usb_acpi_set_power_state(hcd->self.root_hub,
|
|
|
- wIndex, true);
|
|
|
- spin_lock_irqsave(&xhci->lock, flags);
|
|
|
+ xhci_set_port_power(xhci, hcd, wIndex, true);
|
|
|
break;
|
|
|
case USB_PORT_FEAT_RESET:
|
|
|
temp = (temp | PORT_RESET);
|
|
@@ -1207,15 +1239,7 @@ int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue,
|
|
|
port_array[wIndex], temp);
|
|
|
break;
|
|
|
case USB_PORT_FEAT_POWER:
|
|
|
- writel(temp & ~PORT_POWER, port_array[wIndex]);
|
|
|
-
|
|
|
- spin_unlock_irqrestore(&xhci->lock, flags);
|
|
|
- temp = usb_acpi_power_manageable(hcd->self.root_hub,
|
|
|
- wIndex);
|
|
|
- if (temp)
|
|
|
- usb_acpi_set_power_state(hcd->self.root_hub,
|
|
|
- wIndex, false);
|
|
|
- spin_lock_irqsave(&xhci->lock, flags);
|
|
|
+ xhci_set_port_power(xhci, hcd, wIndex, false);
|
|
|
break;
|
|
|
default:
|
|
|
goto error;
|