summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKevin K Wong <kevin.k.wong@intel.com>2017-01-26 17:55:22 -0800
committerchrome-bot <chrome-bot@chromium.org>2017-02-11 13:06:39 -0800
commit18327455c1a0d9db39d5d76964aaa1cb76c348c1 (patch)
treea7a8906f882bf683a8b063d49c9e627077c73f50
parenteb2e38ec56c5701a1d9bcc3618957b4d4dee50f6 (diff)
downloadchrome-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.c13
-rw-r--r--driver/tcpm/anx74xx.c73
-rw-r--r--driver/tcpm/anx74xx.h4
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, &reg);
+
+ /*
+ * 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;