diff options
author | Kevin K Wong <kevin.k.wong@intel.com> | 2017-01-26 17:55:22 -0800 |
---|---|---|
committer | chrome-bot <chrome-bot@chromium.org> | 2017-02-11 13:06:39 -0800 |
commit | 18327455c1a0d9db39d5d76964aaa1cb76c348c1 (patch) | |
tree | a7a8906f882bf683a8b063d49c9e627077c73f50 | |
parent | eb2e38ec56c5701a1d9bcc3618957b4d4dee50f6 (diff) | |
download | chrome-ec-18327455c1a0d9db39d5d76964aaa1cb76c348c1.tar.gz |
ANX74xx: add TCPC low power mode for different DRP state
Added code to put the ANX74xx in low power mode for different DRP state.
1. When nothing attached or system is in S3 or S5 disable the auto
toggling and put ANX74xx system in Analog control mode.
2. Using the CABLE_DET interrupt pin (attach event) enable normal power
mode.
BUG=chrome-os-partner:59841, chrome-os-partner:61640
BRANCH=None
TEST=Manually tested on Reef using below dut-control command
dut-control pp3300_pd_a_mw -r <n>
1. S0, S3, S5 - Nothing connected, ANX in low power mode.
2. In S0 SNK (display/USB dongle, eMark cable) connected & put
system to S3, ANX remains in normal mode.
3. In S0 SNK connected & put system to S5, ANX in low power** mode.
4. In S0 nothing connected, put system to S3 or S5, attach
SNK, ANX in low power** mode.
5. Attach SNK at S3/S5 & boot to S0, ANX in normal mode.
6. SRC (AC adapter) with/without eMark cable are detected in
S0, S3, S5, and continue to charge the system after S-state
transition.
low power**: ANX74xx hardware limitation that Ra/Open (Ex: E-Mark cable
only) detection will trigger CABLE_DET continuously, therefore ANX74xx
will go to normal power mode momentarily and then low power mode in a
loop.
Change-Id: I30f7fd7a85e31987fb77e2cab2fe140d59dd3629
Signed-off-by: Kevin K Wong <kevin.k.wong@intel.com>
Signed-off-by: Vijay Hiremath <vijay.p.hiremath@intel.com>
Reviewed-on: https://chromium-review.googlesource.com/415580
Tested-by: Divya S Sasidharan <divya.s.sasidharan@intel.com>
Reviewed-by: Todd Broch <tbroch@chromium.org>
Reviewed-by: Daisuke Nojiri <dnojiri@chromium.org>
-rw-r--r-- | board/reef/board.c | 13 | ||||
-rw-r--r-- | driver/tcpm/anx74xx.c | 73 | ||||
-rw-r--r-- | driver/tcpm/anx74xx.h | 4 |
3 files changed, 73 insertions, 17 deletions
diff --git a/board/reef/board.c b/board/reef/board.c index bbc442944a..6832b5abab 100644 --- a/board/reef/board.c +++ b/board/reef/board.c @@ -81,9 +81,18 @@ static void tcpc_alert_event(enum gpio_signal signal) #ifdef CONFIG_USB_PD_TCPC_LOW_POWER static void anx74xx_cable_det_handler(void) { + int level = gpio_get_level(GPIO_USB_C0_CABLE_DET); + + /* + * Setting the low power is handled by DRP status hence + * handle only the attach event. + */ + if (level) + anx74xx_handle_power_mode(NPCX_I2C_PORT0_0, + ANX74XX_NORMAL_MODE); + /* confirm if cable_det is asserted */ - if (!gpio_get_level(GPIO_USB_C0_CABLE_DET) || - gpio_get_level(GPIO_USB_C0_PD_RST_L)) + if (!level || gpio_get_level(GPIO_USB_C0_PD_RST_L)) return; task_set_event(TASK_ID_PD_C0, PD_EVENT_TCPC_RESET, 0); diff --git a/driver/tcpm/anx74xx.c b/driver/tcpm/anx74xx.c index 5854c62c8f..6311a53446 100644 --- a/driver/tcpm/anx74xx.c +++ b/driver/tcpm/anx74xx.c @@ -27,6 +27,9 @@ struct anx_state { int polarity; int vconn_en; int mux_state; +#ifdef CONFIG_USB_PD_TCPC_LOW_POWER + int prev_mode; +#endif }; #define clear_recvd_msg_int(port) do {\ int reg, rv; \ @@ -43,6 +46,8 @@ static int anx74xx_set_mux(int port, int polarity); /* Save the selected rp value */ static int selected_rp[CONFIG_USB_PD_PORT_COUNT]; +static int anx74xx_tcpm_init(int port); + static void anx74xx_tcpm_set_auto_good_crc(int port, int enable) { int reg; @@ -70,20 +75,30 @@ static void anx74xx_tcpm_set_auto_good_crc(int port, int enable) static void anx74xx_set_power_mode(int port, int mode) { - switch (mode) { - case ANX74XX_NORMAL_MODE: - /* Set PWR_EN and RST_N GPIO pins high */ - board_set_tcpc_power_mode(port, 1); - break; - case ANX74XX_STANDBY_MODE: - /* Disable PWR_EN, keep Digital and analog block - * ON for cable detection + int reg; +#ifdef CONFIG_USB_PD_TCPC_LOW_POWER + anx[port].prev_mode = mode; +#endif + + tcpc_read(port, ANX74XX_REG_ANALOG_CTRL_0, ®); + + /* + * When ANX3429 needs to enter ANX74XX_STANDBY_MODE, Cable det pin + * shall be pulled low first by ANX3429`s register, in this way, + * for use case of E-mark cable only, EC can find cable det pin is + * pulled high again. */ - board_set_tcpc_power_mode(port, 0); - break; - default: - break; - } + if (mode == ANX74XX_STANDBY_MODE) + reg &= ~ANX74XX_REG_R_PIN_CABLE_DET; + else + reg |= ANX74XX_REG_R_PIN_CABLE_DET; + + tcpc_write(port, ANX74XX_REG_ANALOG_CTRL_0, reg); + + /* Delay recommended by Analogix for CABLE_DET setup time */ + msleep(2); + + board_set_tcpc_power_mode(port, mode); } void anx74xx_tcpc_set_vbus(int port, int enable) @@ -554,6 +569,31 @@ static int anx74xx_tcpm_set_cc(int port, int pull) return rv; } +#ifdef CONFIG_USB_PD_DUAL_ROLE_AUTO_TOGGLE +#ifdef CONFIG_USB_PD_TCPC_LOW_POWER +void anx74xx_handle_power_mode(int port, int mode) +{ + if (mode == ANX74XX_STANDBY_MODE) { + anx74xx_set_power_mode(port, mode); + } else if (anx[port].prev_mode != ANX74XX_NORMAL_MODE) { + /* + * TODO: Interrupt high follows CC line hence ignore multiple + * interrupts. + */ + anx74xx_tcpm_init(port); + } +} +#endif /* CONFIG_USB_PD_TCPC_LOW_POWER */ + +static int anx74xx_tcpc_drp_toggle(int port) +{ +#ifdef CONFIG_USB_PD_TCPC_LOW_POWER + anx74xx_handle_power_mode(port, ANX74XX_STANDBY_MODE); +#endif + return EC_SUCCESS; +} +#endif /* CONFIG_USB_PD_DUAL_ROLE_AUTO_TOGGLE */ + static int anx74xx_tcpm_set_polarity(int port, int polarity) { int reg, mux_state, rv = EC_SUCCESS; @@ -829,11 +869,11 @@ void anx74xx_tcpc_alert(int port) } } -int anx74xx_tcpm_init(int port) +static int anx74xx_tcpm_init(int port) { int rv = 0, reg; - memset(anx, 0, CONFIG_USB_PD_PORT_COUNT*sizeof(struct anx_state)); + memset(&anx[port], 0, sizeof(struct anx_state)); /* Bring chip in normal mode to work */ anx74xx_set_power_mode(port, ANX74XX_NORMAL_MODE); @@ -912,6 +952,9 @@ const struct tcpm_drv anx74xx_tcpm_drv = { .tcpc_discharge_vbus = &anx74xx_tcpc_discharge_vbus, #endif .get_chip_info = &tcpci_get_chip_info, +#ifdef CONFIG_USB_PD_DUAL_ROLE_AUTO_TOGGLE + .drp_toggle = &anx74xx_tcpc_drp_toggle, +#endif }; #ifdef CONFIG_CMD_I2C_STRESS_TEST_TCPC diff --git a/driver/tcpm/anx74xx.h b/driver/tcpm/anx74xx.h index 5f0995725d..fcbd38fe41 100644 --- a/driver/tcpm/anx74xx.h +++ b/driver/tcpm/anx74xx.h @@ -68,6 +68,9 @@ #define ANX74XX_REG_AUTO_GOODCRC_EN 0x01 #define ANX74XX_REG_ENABLE_GOODCRC 0x38 +#define ANX74XX_REG_ANALOG_CTRL_0 0x41 +#define ANX74XX_REG_R_PIN_CABLE_DET (1 << 7) + #define ANX74XX_REG_ANALOG_CTRL_1 0x42 #define ANX74XX_REG_ANALOG_CTRL_5 0x46 #define ANX74XX_REG_ANALOG_CTRL_6 0x47 @@ -178,6 +181,7 @@ void anx74xx_tcpc_set_vbus(int port, int enable); void anx74xx_tcpc_update_hpd_status(int port, int hpd_lvl, int hpd_irq); void anx74xx_tcpc_clear_hpd_status(int port); int anx74xx_tcpc_get_fw_version(int port, int *version); +void anx74xx_handle_power_mode(int port, int mode); #ifdef CONFIG_CMD_I2C_STRESS_TEST_TCPC extern struct i2c_stress_test_dev anx74xx_i2c_stress_test_dev; |