| From 2f52c448c1b08f807620823deb0a096a26b754d0 Mon Sep 17 00:00:00 2001 |
| From: Guoqing Zhang <guoqing.zhang@intel.com> |
| Date: Fri, 7 Apr 2017 17:56:51 +0300 |
| Subject: [PATCH 178/286] usb: xhci: Add helper function xhci_set_power_on(). |
| |
| Refactoring port power on/off related code into |
| a helper function xhci_set_power_on() which can |
| be reused when enabling test mode. |
| |
| [set port state to neutral before writing port power -Mathias] |
| Signed-off-by: Guoqing Zhang <guoqing.zhang@intel.com> |
| Signed-off-by: Mathias Nyman <mathias.nyman@linux.intel.com> |
| Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> |
| |
| (cherry picked from commit a6ff6cbf1fabe7500d8ac25e133e3346db0a0fca) |
| Signed-off-by: Simon Horman <horms+renesas@verge.net.au> |
| --- |
| drivers/usb/host/xhci-hub.c | 66 ++++++++++++++++++++++++++++++-------------- |
| 1 file changed, 45 insertions(+), 21 deletions(-) |
| |
| --- a/drivers/usb/host/xhci-hub.c |
| +++ b/drivers/usb/host/xhci-hub.c |
| @@ -540,6 +540,49 @@ static int xhci_get_ports(struct usb_hcd |
| 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) |
| { |
| @@ -1095,18 +1138,7 @@ int xhci_hub_control(struct usb_hcd *hcd |
| * 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); |
| @@ -1210,15 +1242,7 @@ int xhci_hub_control(struct usb_hcd *hcd |
| 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; |