diff options
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 557b6f32db86..673ad120c43e 100644 --- a/drivers/usb/host/xhci-hub.c +++ b/drivers/usb/host/xhci-hub.c | |||
@@ -422,6 +422,32 @@ void xhci_set_link_state(struct xhci_hcd *xhci, __le32 __iomem **port_array, | |||
422 | xhci_writel(xhci, temp, port_array[port_id]); | 422 | xhci_writel(xhci, temp, port_array[port_id]); |
423 | } | 423 | } |
424 | 424 | ||
425 | void xhci_set_remote_wake_mask(struct xhci_hcd *xhci, | ||
426 | __le32 __iomem **port_array, int port_id, u16 wake_mask) | ||
427 | { | ||
428 | u32 temp; | ||
429 | |||
430 | temp = xhci_readl(xhci, port_array[port_id]); | ||
431 | temp = xhci_port_state_to_neutral(temp); | ||
432 | |||
433 | if (wake_mask & USB_PORT_FEAT_REMOTE_WAKE_CONNECT) | ||
434 | temp |= PORT_WKCONN_E; | ||
435 | else | ||
436 | temp &= ~PORT_WKCONN_E; | ||
437 | |||
438 | if (wake_mask & USB_PORT_FEAT_REMOTE_WAKE_DISCONNECT) | ||
439 | temp |= PORT_WKDISC_E; | ||
440 | else | ||
441 | temp &= ~PORT_WKDISC_E; | ||
442 | |||
443 | if (wake_mask & USB_PORT_FEAT_REMOTE_WAKE_OVER_CURRENT) | ||
444 | temp |= PORT_WKOC_E; | ||
445 | else | ||
446 | temp &= ~PORT_WKOC_E; | ||
447 | |||
448 | xhci_writel(xhci, temp, port_array[port_id]); | ||
449 | } | ||
450 | |||
425 | /* Test and clear port RWC bit */ | 451 | /* Test and clear port RWC bit */ |
426 | void xhci_test_and_clear_bit(struct xhci_hcd *xhci, __le32 __iomem **port_array, | 452 | void xhci_test_and_clear_bit(struct xhci_hcd *xhci, __le32 __iomem **port_array, |
427 | int port_id, u32 port_bit) | 453 | int port_id, u32 port_bit) |
@@ -448,6 +474,7 @@ int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue, | |||
448 | int slot_id; | 474 | int slot_id; |
449 | struct xhci_bus_state *bus_state; | 475 | struct xhci_bus_state *bus_state; |
450 | u16 link_state = 0; | 476 | u16 link_state = 0; |
477 | u16 wake_mask = 0; | ||
451 | 478 | ||
452 | max_ports = xhci_get_ports(hcd, &port_array); | 479 | max_ports = xhci_get_ports(hcd, &port_array); |
453 | bus_state = &xhci->bus_state[hcd_index(hcd)]; | 480 | bus_state = &xhci->bus_state[hcd_index(hcd)]; |
@@ -593,6 +620,8 @@ int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue, | |||
593 | case SetPortFeature: | 620 | case SetPortFeature: |
594 | if (wValue == USB_PORT_FEAT_LINK_STATE) | 621 | if (wValue == USB_PORT_FEAT_LINK_STATE) |
595 | link_state = (wIndex & 0xff00) >> 3; | 622 | link_state = (wIndex & 0xff00) >> 3; |
623 | if (wValue == USB_PORT_FEAT_REMOTE_WAKE_MASK) | ||
624 | wake_mask = wIndex & 0xff00; | ||
596 | wIndex &= 0xff; | 625 | wIndex &= 0xff; |
597 | if (!wIndex || wIndex > max_ports) | 626 | if (!wIndex || wIndex > max_ports) |
598 | goto error; | 627 | goto error; |
@@ -703,6 +732,14 @@ int xhci_hub_control(struct usb_hcd *hcd, u16 typeReq, u16 wValue, | |||
703 | temp = xhci_readl(xhci, port_array[wIndex]); | 732 | temp = xhci_readl(xhci, port_array[wIndex]); |
704 | xhci_dbg(xhci, "set port reset, actual port %d status = 0x%x\n", wIndex, temp); | 733 | xhci_dbg(xhci, "set port reset, actual port %d status = 0x%x\n", wIndex, temp); |
705 | break; | 734 | break; |
735 | case USB_PORT_FEAT_REMOTE_WAKE_MASK: | ||
736 | xhci_set_remote_wake_mask(xhci, port_array, | ||
737 | wIndex, wake_mask); | ||
738 | temp = xhci_readl(xhci, port_array[wIndex]); | ||
739 | xhci_dbg(xhci, "set port remote wake mask, " | ||
740 | "actual port %d status = 0x%x\n", | ||
741 | wIndex, temp); | ||
742 | break; | ||
706 | case USB_PORT_FEAT_BH_PORT_RESET: | 743 | case USB_PORT_FEAT_BH_PORT_RESET: |
707 | temp |= PORT_WR; | 744 | temp |= PORT_WR; |
708 | xhci_writel(xhci, temp, port_array[wIndex]); | 745 | xhci_writel(xhci, temp, port_array[wIndex]); |
@@ -883,6 +920,10 @@ int xhci_bus_suspend(struct usb_hcd *hcd) | |||
883 | t2 |= PORT_LINK_STROBE | XDEV_U3; | 920 | t2 |= PORT_LINK_STROBE | XDEV_U3; |
884 | set_bit(port_index, &bus_state->bus_suspended); | 921 | set_bit(port_index, &bus_state->bus_suspended); |
885 | } | 922 | } |
923 | /* USB core sets remote wake mask for USB 3.0 hubs, | ||
924 | * including the USB 3.0 roothub, but only if CONFIG_USB_SUSPEND | ||
925 | * is enabled, so also enable remote wake here. | ||
926 | */ | ||
886 | if (hcd->self.root_hub->do_remote_wakeup) { | 927 | if (hcd->self.root_hub->do_remote_wakeup) { |
887 | if (t1 & PORT_CONNECT) { | 928 | if (t1 & PORT_CONNECT) { |
888 | t2 |= PORT_WKOC_E | PORT_WKDISC_E; | 929 | t2 |= PORT_WKOC_E | PORT_WKDISC_E; |