aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/usb/host/xhci-hub.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/usb/host/xhci-hub.c')
-rw-r--r--drivers/usb/host/xhci-hub.c41
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
425void 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 */
426void xhci_test_and_clear_bit(struct xhci_hcd *xhci, __le32 __iomem **port_array, 452void 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;