diff options
author | Andiry Xu <andiry.xu@amd.com> | 2011-04-27 06:07:39 -0400 |
---|---|---|
committer | Sarah Sharp <sarah.a.sharp@linux.intel.com> | 2011-05-02 19:42:52 -0400 |
commit | 2c44178032b046c4113c40d0d459a0d36e39b920 (patch) | |
tree | 998a4e5d9594b9d2da6f5cc35af4ac8be50c5171 /drivers/usb/host/xhci-hub.c | |
parent | 85387c0ea3e1cd85ad9d7215917ff5e71ca2aea3 (diff) |
xHCI: Set link state support
This patch adds support for Set Port Feature(PORT_LINK_STATE) request.
The most significant byte (bits 15..8) of the wIndex field specifies
the U state the host software wants to put the link connected to the
port into. This request is only valid when the PORT_ENABLE bit is set
and the PORT_LINK_STATE should not be above value '5' (Rx.Detect).
This request will be later used to replace the set/clear suspend USB3
protocol ports in hub driver.
Signed-off-by: Andiry Xu <andiry.xu@amd.com>
Signed-off-by: Sarah Sharp <sarah.a.sharp@linux.intel.com>
Diffstat (limited to 'drivers/usb/host/xhci-hub.c')
-rw-r--r-- | drivers/usb/host/xhci-hub.c | 41 |
1 files changed, 41 insertions, 0 deletions
diff --git a/drivers/usb/host/xhci-hub.c b/drivers/usb/host/xhci-hub.c index f3bafba4b5c6..b87535442386 100644 --- a/drivers/usb/host/xhci-hub.c +++ b/drivers/usb/host/xhci-hub.c | |||
@@ -387,6 +387,7 @@ int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue, | |||
387 | __le32 __iomem **port_array; | 387 | __le32 __iomem **port_array; |
388 | int slot_id; | 388 | int slot_id; |
389 | struct xhci_bus_state *bus_state; | 389 | struct xhci_bus_state *bus_state; |
390 | u16 link_state = 0; | ||
390 | 391 | ||
391 | if (hcd->speed == HCD_USB3) { | 392 | if (hcd->speed == HCD_USB3) { |
392 | ports = xhci->num_usb3_ports; | 393 | ports = xhci->num_usb3_ports; |
@@ -497,6 +498,8 @@ int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue, | |||
497 | put_unaligned(cpu_to_le32(status), (__le32 *) buf); | 498 | put_unaligned(cpu_to_le32(status), (__le32 *) buf); |
498 | break; | 499 | break; |
499 | case SetPortFeature: | 500 | case SetPortFeature: |
501 | if (wValue == USB_PORT_FEAT_LINK_STATE) | ||
502 | link_state = (wIndex & 0xff00) >> 3; | ||
500 | wIndex &= 0xff; | 503 | wIndex &= 0xff; |
501 | if (!wIndex || wIndex > ports) | 504 | if (!wIndex || wIndex > ports) |
502 | goto error; | 505 | goto error; |
@@ -545,6 +548,44 @@ int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue, | |||
545 | temp = xhci_readl(xhci, port_array[wIndex]); | 548 | temp = xhci_readl(xhci, port_array[wIndex]); |
546 | bus_state->suspended_ports |= 1 << wIndex; | 549 | bus_state->suspended_ports |= 1 << wIndex; |
547 | break; | 550 | break; |
551 | case USB_PORT_FEAT_LINK_STATE: | ||
552 | temp = xhci_readl(xhci, port_array[wIndex]); | ||
553 | /* Software should not attempt to set | ||
554 | * port link state above '5' (Rx.Detect) and the port | ||
555 | * must be enabled. | ||
556 | */ | ||
557 | if ((temp & PORT_PE) == 0 || | ||
558 | (link_state > USB_SS_PORT_LS_RX_DETECT)) { | ||
559 | xhci_warn(xhci, "Cannot set link state.\n"); | ||
560 | goto error; | ||
561 | } | ||
562 | |||
563 | if (link_state == USB_SS_PORT_LS_U3) { | ||
564 | slot_id = xhci_find_slot_id_by_port(hcd, xhci, | ||
565 | wIndex + 1); | ||
566 | if (slot_id) { | ||
567 | /* unlock to execute stop endpoint | ||
568 | * commands */ | ||
569 | spin_unlock_irqrestore(&xhci->lock, | ||
570 | flags); | ||
571 | xhci_stop_device(xhci, slot_id, 1); | ||
572 | spin_lock_irqsave(&xhci->lock, flags); | ||
573 | } | ||
574 | } | ||
575 | |||
576 | temp = xhci_port_state_to_neutral(temp); | ||
577 | temp &= ~PORT_PLS_MASK; | ||
578 | temp |= PORT_LINK_STROBE | link_state; | ||
579 | xhci_writel(xhci, temp, port_array[wIndex]); | ||
580 | |||
581 | spin_unlock_irqrestore(&xhci->lock, flags); | ||
582 | msleep(20); /* wait device to enter */ | ||
583 | spin_lock_irqsave(&xhci->lock, flags); | ||
584 | |||
585 | temp = xhci_readl(xhci, port_array[wIndex]); | ||
586 | if (link_state == USB_SS_PORT_LS_U3) | ||
587 | bus_state->suspended_ports |= 1 << wIndex; | ||
588 | break; | ||
548 | case USB_PORT_FEAT_POWER: | 589 | case USB_PORT_FEAT_POWER: |
549 | /* | 590 | /* |
550 | * Turn on ports, even if there isn't per-port switching. | 591 | * Turn on ports, even if there isn't per-port switching. |