summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJett Rink <jettrink@chromium.org>2018-06-28 15:31:40 -0600
committerchrome-bot <chrome-bot@chromium.org>2018-07-18 18:15:26 -0700
commit16a8f8f4fa5bce677f202ff78892f3f50978065b (patch)
tree5b2b2b9bbe9c79632b00dc1c1d893a598add556a
parentd22bdeeaecd864835eacb9c22e05f09050fb0237 (diff)
downloadchrome-ec-16a8f8f4fa5bce677f202ff78892f3f50978065b.tar.gz
tcpc: debounce entry into low-power mode
We need to keep track of the low-power mode hardware state for each TCPC so we can put a TCPC back into low power mode when it exits low power mode before the software TCPM state machine wants it out of low power mode. This change also breaks the low power mode entry out of the drp_toggle method into its own method: enter_low_power_mode. BRANCH=none BUG=b:77544959 TEST=Verified Analogix does not get into low-power mode loop. Tested other SRC/SNK capabilities as well. Tested the device will go back into low power mode if the AP access the TCPC via the 'ectool usbpdmuxinfo' command. Change-Id: I2fdefeda2bf13c2b79d988f0017629115438d313 Signed-off-by: Jett Rink <jettrink@chromium.org> Reviewed-on: https://chromium-review.googlesource.com/1119255 Reviewed-by: Scott Collyer <scollyer@chromium.org>
-rw-r--r--common/usb_pd_protocol.c95
-rw-r--r--driver/tcpm/anx7447.c15
-rw-r--r--driver/tcpm/anx74xx.c27
-rw-r--r--driver/tcpm/ps8xxx.c3
-rw-r--r--driver/tcpm/tcpci.c49
-rw-r--r--driver/tcpm/tcpci.h3
-rw-r--r--driver/tcpm/tcpm.h38
-rw-r--r--include/usb_pd.h22
-rw-r--r--include/usb_pd_tcpm.h14
9 files changed, 230 insertions, 36 deletions
diff --git a/common/usb_pd_protocol.c b/common/usb_pd_protocol.c
index 42742888a2..03ed5b777c 100644
--- a/common/usb_pd_protocol.c
+++ b/common/usb_pd_protocol.c
@@ -351,6 +351,54 @@ static void set_vconn(int port, int enable)
}
#endif /* defined(CONFIG_USBC_VCONN) */
+#ifdef CONFIG_USB_PD_TCPC_LOW_POWER
+
+/* 10 ms is enough time for any TCPC transaction to complete. */
+#define PD_LPM_DEBOUNCE_US (10 * MSEC)
+static timestamp_t lpm_debounce_deadlines[CONFIG_USB_PD_PORT_COUNT];
+
+/* This is only called from the PD tasks that owns the port. */
+static void handle_device_access(int port)
+{
+ lpm_debounce_deadlines[port].val = get_time().val + PD_LPM_DEBOUNCE_US;
+ if (pd[port].flags & PD_FLAGS_LPM_ENGAGED) {
+ CPRINTS("TCPC p%d Exited Low Power Mode via bus access", port);
+ pd[port].flags &= ~PD_FLAGS_LPM_ENGAGED;
+ }
+}
+
+/* This can be called from any task. */
+void pd_device_accessed(int port)
+{
+ /* If not in the PD TASK that owns data, marshal to that task */
+ if (task_get_current() == PD_PORT_TO_TASK_ID(port))
+ handle_device_access(port);
+ else
+ task_set_event(PD_PORT_TO_TASK_ID(port),
+ PD_EVENT_DEVICE_ACCESSED, 0);
+}
+
+/* This is only called from the PD tasks that owns the port. */
+static void request_low_power_mode(int port, int enable)
+{
+ if (enable)
+ pd[port].flags |= PD_FLAGS_LPM_REQUESTED;
+ else
+ pd[port].flags &= ~PD_FLAGS_LPM_REQUESTED;
+}
+#endif /* CONFIG_USB_PD_TCPC_LOW_POWER */
+
+/* Local convenience method for two method currently always called together. */
+#ifdef CONFIG_USB_PD_DUAL_ROLE_AUTO_TOGGLE
+static void pd_set_drp_toggle(int port, int enable)
+{
+ tcpm_set_drp_toggle(port, enable);
+#ifdef CONFIG_USB_PD_TCPC_LOW_POWER
+ request_low_power_mode(port, enable);
+#endif
+}
+#endif /* CONFIG_USB_PD_DUAL_ROLE_AUTO_TOGGLE */
+
#ifdef CONFIG_USB_PD_DUAL_ROLE
static int get_bbram_idx(int port)
{
@@ -1920,7 +1968,7 @@ void pd_update_dual_role_config(int port)
#if defined(CONFIG_USB_PD_DUAL_ROLE_AUTO_TOGGLE) && \
defined(CONFIG_USB_PD_TCPC_LOW_POWER)
/* When switching drp mode, make sure tcpc is out of standby mode */
- tcpm_set_drp_toggle(port, 0);
+ pd_set_drp_toggle(port, 0);
#endif
}
@@ -2333,6 +2381,11 @@ void pd_task(void *u)
/* wait for next event/packet or timeout expiration */
evt = task_wait_event(timeout);
+#ifdef CONFIG_USB_PD_TCPC_LOW_POWER
+ if (evt & PD_EVENT_DEVICE_ACCESSED)
+ handle_device_access(port);
+#endif
+
#ifdef CONFIG_USB_PD_DUAL_ROLE
if (evt & PD_EVENT_UPDATE_DUAL_ROLE)
pd_update_dual_role_config(port);
@@ -2347,6 +2400,10 @@ void pd_task(void *u)
#else
/* if TCPC has reset, then need to initialize it again */
if (evt & PD_EVENT_TCPC_RESET) {
+#ifdef CONFIG_USB_PD_TCPC_LOW_POWER
+ /* Reset LPM software state after a reset */
+ request_low_power_mode(port, 0);
+#endif
CPRINTS("TCPC p%d reset!", port);
if (tcpm_init(port) != EC_SUCCESS)
CPRINTS("TCPC p%d init failed", port);
@@ -3508,6 +3565,15 @@ void pd_task(void *u)
assert(auto_toggle_supported);
+ /*
+ * If SW decided we should be in a low power state and
+ * the CC lines did not change, then don't talk with the
+ * TCPC otherwise we might wake it up.
+ */
+ if (pd[port].flags & PD_FLAGS_LPM_REQUESTED &&
+ !(evt & PD_EVENT_CC))
+ break;
+
/* Check for connection */
tcpm_get_cc(port, &cc1, &cc2);
@@ -3533,10 +3599,7 @@ void pd_task(void *u)
next_state = PD_STATE_DRP_AUTO_TOGGLE;
if (next_state != PD_STATE_DRP_AUTO_TOGGLE) {
- tcpm_set_drp_toggle(port, 0);
-#ifdef CONFIG_USB_PD_TCPC_LOW_POWER
- CPRINTS("TCPC p%d Exit Low Power Mode", port);
-#endif
+ pd_set_drp_toggle(port, 0);
}
if (next_state == PD_STATE_SNK_DISCONNECTED) {
@@ -3548,12 +3611,9 @@ void pd_task(void *u)
pd_set_power_role(port, PD_ROLE_SOURCE);
timeout = 2*MSEC;
} else {
- tcpm_set_drp_toggle(port, 1);
+ pd_set_drp_toggle(port, 1);
pd[port].flags |= PD_FLAGS_TCPC_DRP_TOGGLE;
timeout = -1;
-#ifdef CONFIG_USB_PD_TCPC_LOW_POWER
- CPRINTS("TCPC p%d Low Power Mode", port);
-#endif
}
set_state(port, next_state);
@@ -3581,6 +3641,23 @@ void pd_task(void *u)
}
}
+#ifdef CONFIG_USB_PD_TCPC_LOW_POWER
+ /* Determine if we need to put the TCPC in low power mode */
+ if (pd[port].flags & PD_FLAGS_LPM_REQUESTED &&
+ !(pd[port].flags & PD_FLAGS_LPM_ENGAGED)) {
+ const int64_t time_left =
+ lpm_debounce_deadlines[port].val - now.val;
+ if (time_left <= 0) {
+ pd[port].flags |= PD_FLAGS_LPM_ENGAGED;
+ tcpm_enter_low_power_mode(port);
+ CPRINTS("TCPC p%d Enter Low Power Mode", port);
+ timeout = -1;
+ } else if (timeout < 0 || timeout > time_left) {
+ timeout = time_left;
+ }
+ }
+#endif
+
/* Check for disconnection if we're connected */
if (!pd_is_connected(port))
continue;
diff --git a/driver/tcpm/anx7447.c b/driver/tcpm/anx7447.c
index 35789e69bd..c04c316cf0 100644
--- a/driver/tcpm/anx7447.c
+++ b/driver/tcpm/anx7447.c
@@ -63,16 +63,24 @@ const struct anx7447_i2c_addr anx7447_i2c_addrs[] = {
static inline int anx7447_reg_write(int port, int reg, int val)
{
- return i2c_write8(tcpc_config[port].i2c_host_port,
+ int rv = i2c_write8(tcpc_config[port].i2c_host_port,
anx[port].i2c_slave_addr,
reg, val);
+#ifdef CONFIG_USB_PD_TCPC_LOW_POWER
+ pd_device_accessed(port);
+#endif
+ return rv;
}
static inline int anx7447_reg_read(int port, int reg, int *val)
{
- return i2c_read8(tcpc_config[port].i2c_host_port,
+ int rv = i2c_read8(tcpc_config[port].i2c_host_port,
anx[port].i2c_slave_addr,
reg, val);
+#ifdef CONFIG_USB_PD_TCPC_LOW_POWER
+ pd_device_accessed(port);
+#endif
+ return rv;
}
void anx7447_hpd_mode_en(int port)
@@ -554,6 +562,9 @@ const struct tcpm_drv anx7447_tcpm_drv = {
.set_snk_ctrl = &tcpci_tcpm_set_snk_ctrl,
.set_src_ctrl = &tcpci_tcpm_set_src_ctrl,
#endif
+#ifdef CONFIG_USB_PD_TCPC_LOW_POWER
+ .enter_low_power_mode = &tcpci_enter_low_power_mode,
+#endif
};
#ifdef CONFIG_USB_PD_TCPM_MUX
diff --git a/driver/tcpm/anx74xx.c b/driver/tcpm/anx74xx.c
index e0b4957f69..f892f05920 100644
--- a/driver/tcpm/anx74xx.c
+++ b/driver/tcpm/anx74xx.c
@@ -141,15 +141,29 @@ static void anx74xx_set_power_mode(int port, int mode)
/* Update cable cable det signal */
anx74xx_update_cable_det(port, mode);
/*
- * Delay between setting cable_det low and setting RESET_L low
- * as recommended the ANX3429 datasheet.
+ * The final piece of entering low power mode is setting the
+ * RESET_L signal low, which is done via
+ * anx74xx_enter_low_power_mode which is called at least 10ms
+ * after setting cable_det low (above).
*/
- msleep(1);
- /* Put chip into standby mode */
- board_set_tcpc_power_mode(port, mode);
}
}
+#ifdef CONFIG_USB_PD_TCPC_LOW_POWER
+static int anx74xx_enter_low_power_mode(int port)
+{
+ /*
+ * The delay between setting cable_det low (in anx74xx_set_power_mode)
+ * and setting RESET_L low in (board_set_tcpc_power_mode) is at least
+ * 1 ms. This should be taken care of by the PD_LM_DEBOUCE_US delay of
+ * 10ms, but we want to protect against any future tweaks of that value.
+ */
+ msleep(1);
+ board_set_tcpc_power_mode(port, ANX74XX_STANDBY_MODE);
+ return EC_SUCCESS;
+}
+#endif
+
void anx74xx_tcpc_set_vbus(int port, int enable)
{
int reg;
@@ -1095,6 +1109,9 @@ const struct tcpm_drv anx74xx_tcpm_drv = {
defined(CONFIG_USB_PD_TCPC_LOW_POWER)
.drp_toggle = &anx74xx_tcpc_drp_toggle,
#endif
+#ifdef CONFIG_USB_PD_TCPC_LOW_POWER
+ .enter_low_power_mode = &anx74xx_enter_low_power_mode,
+#endif
};
#ifdef CONFIG_CMD_I2C_STRESS_TEST_TCPC
diff --git a/driver/tcpm/ps8xxx.c b/driver/tcpm/ps8xxx.c
index 4dc601599e..15580b5d3f 100644
--- a/driver/tcpm/ps8xxx.c
+++ b/driver/tcpm/ps8xxx.c
@@ -189,6 +189,9 @@ const struct tcpm_drv ps8xxx_tcpm_drv = {
.set_src_ctrl = &tcpci_tcpm_set_src_ctrl,
#endif
.get_chip_info = &tcpci_get_chip_info,
+#ifdef CONFIG_USB_PD_TCPC_LOW_POWER
+ .enter_low_power_mode = &tcpci_enter_low_power_mode,
+#endif
};
#ifdef CONFIG_CMD_I2C_STRESS_TEST_TCPC
diff --git a/driver/tcpm/tcpci.c b/driver/tcpm/tcpci.c
index d4518ae608..ec7e6ead50 100644
--- a/driver/tcpm/tcpci.c
+++ b/driver/tcpm/tcpci.c
@@ -156,13 +156,20 @@ int tcpci_tcpc_drp_toggle(int port, int enable)
rv |= tcpc_write(port, TCPC_REG_COMMAND,
TCPC_REG_COMMAND_LOOK4CONNECTION);
-#ifdef CONFIG_USB_PD_TCPC_LOW_POWER
- rv |= tcpc_write(port, TCPC_REG_COMMAND, TCPC_REG_COMMAND_I2CIDLE);
-#endif
return rv;
}
#endif
+#ifdef CONFIG_USB_PD_TCPC_LOW_POWER
+int tcpci_enter_low_power_mode(int port)
+{
+ /* This uses the raw i2c write to bypass the pd_device_accessed call */
+ return i2c_write8(tcpc_config[port].i2c_host_port,
+ tcpc_config[port].i2c_slave_addr,
+ TCPC_REG_COMMAND, TCPC_REG_COMMAND_I2CIDLE);
+}
+#endif
+
int tcpci_tcpm_set_polarity(int port, int polarity)
{
return tcpc_write(port, TCPC_REG_TCPC_CTRL,
@@ -523,14 +530,15 @@ int tcpci_tcpm_mux_set(int i2c_port_addr, mux_state_t mux_state)
{
int reg = 0;
int rv;
+
#ifdef CONFIG_USB_PD_TCPM_TCPCI_MUX_ONLY
- int port = MUX_PORT(i2c_port_addr);
- int addr = MUX_ADDR(i2c_port_addr);
+ /* Parameter is port and i2c address */
+ rv = i2c_read8(MUX_PORT(i2c_port_addr), MUX_ADDR(i2c_port_addr),
+ TCPC_REG_CONFIG_STD_OUTPUT, &reg);
#else
- int port = tcpc_config[i2c_port_addr].i2c_host_port;
- int addr = tcpc_config[i2c_port_addr].i2c_slave_addr;
+ /* Parameter is port only */
+ rv = tcpc_read(i2c_port_addr, TCPC_REG_CONFIG_STD_OUTPUT, &reg);
#endif
- rv = i2c_read8(port, addr, TCPC_REG_CONFIG_STD_OUTPUT, &reg);
if (rv != EC_SUCCESS)
return rv;
@@ -543,7 +551,14 @@ int tcpci_tcpm_mux_set(int i2c_port_addr, mux_state_t mux_state)
if (mux_state & MUX_POLARITY_INVERTED)
reg |= TCPC_REG_CONFIG_STD_OUTPUT_CONNECTOR_FLIPPED;
- return i2c_write8(port, addr, TCPC_REG_CONFIG_STD_OUTPUT, reg);
+#ifdef CONFIG_USB_PD_TCPM_TCPCI_MUX_ONLY
+ /* Parameter is port and i2c address */
+ return i2c_write8(MUX_PORT(i2c_port_addr), MUX_ADDR(i2c_port_addr),
+ TCPC_REG_CONFIG_STD_OUTPUT, reg);
+#else
+ /* Parameter is port only */
+ return tcpc_write(i2c_port_addr, TCPC_REG_CONFIG_STD_OUTPUT, reg);
+#endif
}
/* Reads control register and updates mux_state accordingly */
@@ -551,16 +566,17 @@ int tcpci_tcpm_mux_get(int i2c_port_addr, mux_state_t *mux_state)
{
int reg = 0;
int rv;
+
+ *mux_state = 0;
#ifdef CONFIG_USB_PD_TCPM_TCPCI_MUX_ONLY
- int port = MUX_PORT(i2c_port_addr);
- int addr = MUX_ADDR(i2c_port_addr);
+ /* Parameter is port and i2c address */
+ rv = i2c_read8(MUX_PORT(i2c_port_addr), MUX_ADDR(i2c_port_addr),
+ TCPC_REG_CONFIG_STD_OUTPUT, &reg);
#else
- int port = tcpc_config[i2c_port_addr].i2c_host_port;
- int addr = tcpc_config[i2c_port_addr].i2c_slave_addr;
+ /* Parameter is port only */
+ rv = tcpc_read(i2c_port_addr, TCPC_REG_CONFIG_STD_OUTPUT, &reg);
#endif
- *mux_state = 0;
- rv = i2c_read8(port, addr, TCPC_REG_CONFIG_STD_OUTPUT, &reg);
if (rv != EC_SUCCESS)
return rv;
@@ -610,4 +626,7 @@ const struct tcpm_drv tcpci_tcpm_drv = {
.set_snk_ctrl = &tcpci_tcpm_set_snk_ctrl,
.set_src_ctrl = &tcpci_tcpm_set_src_ctrl,
#endif
+#ifdef CONFIG_USB_PD_TCPC_LOW_POWER
+ .enter_low_power_mode = &tcpci_enter_low_power_mode,
+#endif
};
diff --git a/driver/tcpm/tcpci.h b/driver/tcpm/tcpci.h
index c7cefc4ba4..877e510210 100644
--- a/driver/tcpm/tcpci.h
+++ b/driver/tcpm/tcpci.h
@@ -143,6 +143,9 @@ int tcpci_tcpm_release(int port);
#ifdef CONFIG_USB_PD_DUAL_ROLE_AUTO_TOGGLE
int tcpci_tcpc_drp_toggle(int port, int enable);
#endif
+#ifdef CONFIG_USB_PD_TCPC_LOW_POWER
+int tcpci_enter_low_power_mode(int port);
+#endif
#ifdef CONFIG_USB_PD_DISCHARGE_TCPC
void tcpci_tcpc_discharge_vbus(int port, int enable);
#endif
diff --git a/driver/tcpm/tcpm.h b/driver/tcpm/tcpm.h
index 091527e68a..3b3198d84e 100644
--- a/driver/tcpm/tcpm.h
+++ b/driver/tcpm/tcpm.h
@@ -13,6 +13,7 @@
#include "gpio.h"
#include "i2c.h"
#include "usb_pd_tcpm.h"
+#include "usb_pd.h"
#include "util.h"
#if defined(CONFIG_USB_PD_DUAL_ROLE_AUTO_TOGGLE) && \
@@ -27,30 +28,46 @@ extern const struct tcpc_config_t tcpc_config[];
/* I2C wrapper functions - get I2C port / slave addr from config struct. */
static inline int tcpc_write(int port, int reg, int val)
{
- return i2c_write8(tcpc_config[port].i2c_host_port,
+ int rv = i2c_write8(tcpc_config[port].i2c_host_port,
tcpc_config[port].i2c_slave_addr,
reg, val);
+#ifdef CONFIG_USB_PD_TCPC_LOW_POWER
+ pd_device_accessed(port);
+#endif
+ return rv;
}
static inline int tcpc_write16(int port, int reg, int val)
{
- return i2c_write16(tcpc_config[port].i2c_host_port,
+ int rv = i2c_write16(tcpc_config[port].i2c_host_port,
tcpc_config[port].i2c_slave_addr,
reg, val);
+#ifdef CONFIG_USB_PD_TCPC_LOW_POWER
+ pd_device_accessed(port);
+#endif
+ return rv;
}
static inline int tcpc_read(int port, int reg, int *val)
{
- return i2c_read8(tcpc_config[port].i2c_host_port,
+ int rv = i2c_read8(tcpc_config[port].i2c_host_port,
tcpc_config[port].i2c_slave_addr,
reg, val);
+#ifdef CONFIG_USB_PD_TCPC_LOW_POWER
+ pd_device_accessed(port);
+#endif
+ return rv;
}
static inline int tcpc_read16(int port, int reg, int *val)
{
- return i2c_read16(tcpc_config[port].i2c_host_port,
+ int rv = i2c_read16(tcpc_config[port].i2c_host_port,
tcpc_config[port].i2c_slave_addr,
reg, val);
+#ifdef CONFIG_USB_PD_TCPC_LOW_POWER
+ pd_device_accessed(port);
+#endif
+ return rv;
}
static inline int tcpc_xfer(int port,
@@ -58,11 +75,15 @@ static inline int tcpc_xfer(int port,
uint8_t *in, int in_size,
int flags)
{
- return i2c_xfer(tcpc_config[port].i2c_host_port,
+ int rv = i2c_xfer(tcpc_config[port].i2c_host_port,
tcpc_config[port].i2c_slave_addr,
out, out_size,
in, in_size,
flags);
+#ifdef CONFIG_USB_PD_TCPC_LOW_POWER
+ pd_device_accessed(port);
+#endif
+ return rv;
}
static inline void tcpc_lock(int port, int lock)
@@ -183,6 +204,13 @@ static inline int tcpm_set_drp_toggle(int port, int enable)
}
#endif
+#ifdef CONFIG_USB_PD_TCPC_LOW_POWER
+static inline int tcpm_enter_low_power_mode(int port)
+{
+ return tcpc_config[port].drv->enter_low_power_mode(port);
+}
+#endif
+
#ifdef CONFIG_CMD_I2C_STRESS_TEST_TCPC
static inline int tcpc_i2c_read(const int port, const int addr,
const int reg, int *data)
diff --git a/include/usb_pd.h b/include/usb_pd.h
index 7cdc79c198..b45a113879 100644
--- a/include/usb_pd.h
+++ b/include/usb_pd.h
@@ -43,6 +43,11 @@ enum pd_rx_errors {
#define PD_EVENT_CC (1<<4) /* CC line change event */
#define PD_EVENT_TCPC_RESET (1<<5) /* TCPC has reset */
#define PD_EVENT_UPDATE_DUAL_ROLE (1<<6) /* DRP state has changed */
+/*
+ * A task, other than the task owning the PD port, accessed the TCPC. The task
+ * that owns the port does not send itself this event.
+ */
+#define PD_EVENT_DEVICE_ACCESSED (1<<7)
/* --- PD data message helpers --- */
#define PDO_MAX_OBJECTS 7
@@ -717,6 +722,12 @@ enum pd_states {
#define PD_FLAGS_PARTNER_USB_COMM (1 << 14)/* port partner is USB comms */
#define PD_FLAGS_UPDATE_SRC_CAPS (1 << 15)/* send new source capabilities */
#define PD_FLAGS_TS_DTS_PARTNER (1 << 16)/* partner has rp/rp or rd/rd */
+/*
+ * These PD_FLAGS_LPM* flags track the software state (PD_LPM_FLAGS_REQUESTED)
+ * and hardware state (PD_LPM_FLAGS_ENGAGED) of the TCPC lower power mode.
+ */
+#define PD_FLAGS_LPM_REQUESTED (1 << 17)/* Tracks SW LPM state */
+#define PD_FLAGS_LPM_ENGAGED (1 << 18)/* Tracks HW LPM state */
/* Flags to clear on a disconnect */
#define PD_FLAGS_RESET_ON_DISCONNECT_MASK (PD_FLAGS_PARTNER_DR_POWER | \
PD_FLAGS_PARTNER_DR_DATA | \
@@ -1007,6 +1018,17 @@ int pd_build_request(int port, uint32_t *rdo, uint32_t *ma, uint32_t *mv,
int pd_is_max_request_allowed(void);
/**
+ * Informs the TCPM state machine that code within the EC has accessed the TCPC
+ * via its communication bus (e.g. i2c). This is important to keep track of as
+ * accessing a TCPC may pull the hardware out of low-power mode.
+ *
+ * Note: Call this function after finished accessing the hardware.
+ *
+ * @param port USB-C port number
+ */
+void pd_device_accessed(int port);
+
+/**
* Process source capabilities packet
*
* @param port USB-C port number
diff --git a/include/usb_pd_tcpm.h b/include/usb_pd_tcpm.h
index 1b77e40450..be1139b0e1 100644
--- a/include/usb_pd_tcpm.h
+++ b/include/usb_pd_tcpm.h
@@ -242,6 +242,20 @@ struct tcpm_drv {
*/
int (*set_src_ctrl)(int port, int enable);
#endif
+
+#ifdef CONFIG_USB_PD_TCPC_LOW_POWER
+ /**
+ * Instructs the TCPC to enter into low power mode.
+ *
+ * NOTE: Do no use tcpc_(read|write) style helper methods in this
+ * function. You must use i2c_(read|write) directly.
+ *
+ * @param port Type-C port number
+ *
+ * @return EC_SUCCESS or error
+ */
+ int (*enter_low_power_mode)(int port);
+#endif
};
enum tcpc_alert_polarity {