summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--drivers/usb/typec/tcpm/tcpm.c17
-rw-r--r--include/linux/usb/pd.h2
2 files changed, 19 insertions, 0 deletions
diff --git a/drivers/usb/typec/tcpm/tcpm.c b/drivers/usb/typec/tcpm/tcpm.c
index 1c32bdf62852..aedc8bb9532a 100644
--- a/drivers/usb/typec/tcpm/tcpm.c
+++ b/drivers/usb/typec/tcpm/tcpm.c
@@ -4131,6 +4131,23 @@ static void run_state_machine(struct tcpm_port *port)
}
break;
case SNK_TRANSITION_SINK:
+ /* From the USB PD spec:
+ * "The Sink Shall transition to Sink Standby before a positive or
+ * negative voltage transition of VBUS. During Sink Standby
+ * the Sink Shall reduce its power draw to pSnkStdby."
+ *
+ * This is not applicable to PPS though as the port can continue
+ * to draw negotiated power without switching to standby.
+ */
+ if (port->supply_voltage != port->req_supply_voltage && !port->pps_data.active &&
+ port->current_limit * port->supply_voltage / 1000 > PD_P_SNK_STDBY_MW) {
+ u32 stdby_ma = PD_P_SNK_STDBY_MW * 1000 / port->supply_voltage;
+
+ tcpm_log(port, "Setting standby current %u mV @ %u mA",
+ port->supply_voltage, stdby_ma);
+ tcpm_set_current_limit(port, stdby_ma, port->supply_voltage);
+ }
+ fallthrough;
case SNK_TRANSITION_SINK_VBUS:
tcpm_set_state(port, hard_reset_state(port),
PD_T_PS_TRANSITION);
diff --git a/include/linux/usb/pd.h b/include/linux/usb/pd.h
index 70d681918d01..bf00259493e0 100644
--- a/include/linux/usb/pd.h
+++ b/include/linux/usb/pd.h
@@ -493,4 +493,6 @@ static inline unsigned int rdo_max_power(u32 rdo)
#define PD_N_CAPS_COUNT (PD_T_NO_RESPONSE / PD_T_SEND_SOURCE_CAP)
#define PD_N_HARD_RESET_COUNT 2
+#define PD_P_SNK_STDBY_MW 2500 /* 2500 mW */
+
#endif /* __LINUX_USB_PD_H */