@@ -358,6 +358,8 @@ struct tb_regs_port_header {
#define PORT_CS_18_BE BIT(8)
#define PORT_CS_18_TCM BIT(9)
#define PORT_CS_18_CPS BIT(10)
+#define PORT_CS_18_WOCS BIT(16)
+#define PORT_CS_18_WODS BIT(17)
#define PORT_CS_18_WOU4S BIT(18)
#define PORT_CS_19 0x13
#define PORT_CS_19_PC BIT(3)
@@ -155,6 +155,8 @@ static inline int usb4_switch_op_data(struct tb_switch *sw, u16 opcode,
static void usb4_switch_check_wakes(struct tb_switch *sw)
{
+ bool wakeup_usb4 = false;
+ struct usb4_port *usb4;
struct tb_port *port;
bool wakeup = false;
u32 val;
@@ -173,20 +175,31 @@ static void usb4_switch_check_wakes(struct tb_switch *sw)
wakeup = val & (ROUTER_CS_6_WOPS | ROUTER_CS_6_WOUS);
}
- /* Check for any connected downstream ports for USB4 wake */
+ /*
+ * Check for any downstream ports for USB4 wake,
+ * connection wake and disconnection wake.
+ */
tb_switch_for_each_port(sw, port) {
- if (!tb_port_has_remote(port))
+ if (!port->cap_usb4)
continue;
if (tb_port_read(port, &val, TB_CFG_PORT,
port->cap_usb4 + PORT_CS_18, 1))
break;
- tb_port_dbg(port, "USB4 wake: %s\n",
- (val & PORT_CS_18_WOU4S) ? "yes" : "no");
+ tb_port_dbg(port, "USB4 wake: %s, connection wake: %s, disconnection wake: %s\n",
+ (val & PORT_CS_18_WOU4S) ? "yes" : "no",
+ (val & PORT_CS_18_WOCS) ? "yes" : "no",
+ (val & PORT_CS_18_WODS) ? "yes" : "no");
+
+ wakeup_usb4 = val & (PORT_CS_18_WOU4S | PORT_CS_18_WOCS |
+ PORT_CS_18_WODS);
+
+ usb4 = port->usb4;
+ if (device_may_wakeup(&usb4->dev) && wakeup_usb4)
+ pm_wakeup_event(&usb4->dev, 0);
- if (val & PORT_CS_18_WOU4S)
- wakeup = true;
+ wakeup |= wakeup_usb4;
}
if (wakeup)
@@ -366,6 +379,7 @@ bool usb4_switch_lane_bonding_possible(struct tb_switch *sw)
*/
int usb4_switch_set_wake(struct tb_switch *sw, unsigned int flags)
{
+ struct usb4_port *usb4;
struct tb_port *port;
u64 route = tb_route(sw);
u32 val;
@@ -395,10 +409,13 @@ int usb4_switch_set_wake(struct tb_switch *sw, unsigned int flags)
val |= PORT_CS_19_WOU4;
} else {
bool configured = val & PORT_CS_19_PC;
+ usb4 = port->usb4;
- if ((flags & TB_WAKE_ON_CONNECT) && !configured)
+ if (((flags & TB_WAKE_ON_CONNECT) |
+ device_may_wakeup(&usb4->dev)) && !configured)
val |= PORT_CS_19_WOC;
- if ((flags & TB_WAKE_ON_DISCONNECT) && configured)
+ if (((flags & TB_WAKE_ON_DISCONNECT) |
+ device_may_wakeup(&usb4->dev)) && configured)
val |= PORT_CS_19_WOD;
if ((flags & TB_WAKE_ON_USB4) && configured)
val |= PORT_CS_19_WOU4;
@@ -282,6 +282,9 @@ struct usb4_port *usb4_port_device_add(struct tb_port *port)
}
}
+ if (!tb_is_upstream_port(port))
+ device_set_wakeup_capable(&usb4->dev, true);
+
pm_runtime_no_callbacks(&usb4->dev);
pm_runtime_set_active(&usb4->dev);
pm_runtime_enable(&usb4->dev);