From 3dd62a63e18927d6f9c87fef6b5160d3f49d88d7 Mon Sep 17 00:00:00 2001 From: Denis Brockus Date: Wed, 27 Nov 2019 11:03:16 -0700 Subject: tcpci: POWER_CTRL auto discharge disconnect init Change TCPCI to use HOOK_USB_PD_CONNECT/DISCONNECT to set/clear TCPC_REG_POWER_CTRL_AUTO_DISCHARGE_DISCONNECT according to the TCPCI spec. Change the definition of HOOK_USB_PD_CONNECT to occur after CC and VBus are stable. BUG=b:144126745,chromium:951683 BRANCH=none TEST=Charger attach/pull with AP not running Change-Id: I625efbba80f190322e3e92de6318b710b3ce7ade Signed-off-by: Denis Brockus Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/ec/+/1940777 --- common/usb_pd_protocol.c | 18 ++++++++-------- driver/tcpm/nct38xx.c | 53 +++++----------------------------------------- driver/tcpm/tcpci.c | 55 ++++++++++++++++++++++++++++++++++++++++++++++-- driver/tcpm/tcpci.h | 2 ++ include/hooks.h | 2 ++ include/usb_pd_tcpm.h | 9 ++++++++ 6 files changed, 80 insertions(+), 59 deletions(-) diff --git a/common/usb_pd_protocol.c b/common/usb_pd_protocol.c index d4f6f0c06b..cee2c5ca0f 100644 --- a/common/usb_pd_protocol.c +++ b/common/usb_pd_protocol.c @@ -28,7 +28,6 @@ #include "usb_pd_tcpm.h" #include "usb_pd_tcpc.h" #include "usbc_ppc.h" -#include "tcpm.h" #include "version.h" #include "vboot.h" @@ -841,10 +840,10 @@ static inline void set_state(int port, enum pd_states next_state) /* Invalidate message IDs. */ invalidate_last_message_id(port); -#ifdef CONFIG_COMMON_RUNTIME + /* detect USB PD cc disconnect */ - hook_notify(HOOK_USB_PD_DISCONNECT); -#endif + if (IS_ENABLED(CONFIG_COMMON_RUNTIME)) + hook_notify(HOOK_USB_PD_DISCONNECT); } #ifdef CONFIG_LOW_POWER_IDLE @@ -3314,9 +3313,6 @@ void pd_task(void *u) break; /* Debounce complete */ - if (IS_ENABLED(CONFIG_COMMON_RUNTIME)) - hook_notify(HOOK_USB_PD_CONNECT); - #ifdef CONFIG_USBC_PPC /* * If the port is latched off, just continue to @@ -3400,6 +3396,10 @@ void pd_task(void *u) PD_FLAGS_CHECK_DR_ROLE; hard_reset_count = 0; timeout = 5*MSEC; + + if (IS_ENABLED(CONFIG_COMMON_RUNTIME)) + hook_notify(HOOK_USB_PD_CONNECT); + set_state(port, PD_STATE_SRC_STARTUP); } /* @@ -3965,8 +3965,6 @@ void pd_task(void *u) } /* We are attached */ - if (IS_ENABLED(CONFIG_COMMON_RUNTIME)) - hook_notify(HOOK_USB_PD_CONNECT); pd[port].polarity = get_snk_polarity(cc1, cc2); set_polarity(port, pd[port].polarity); /* reset message ID on connection */ @@ -4001,6 +3999,8 @@ void pd_task(void *u) &pd_usb_billboard_deferred_data, PD_T_AME); } + if (IS_ENABLED(CONFIG_COMMON_RUNTIME)) + hook_notify(HOOK_USB_PD_CONNECT); break; case PD_STATE_SNK_HARD_RESET_RECOVER: if (pd[port].last_state != pd[port].task_state) diff --git a/driver/tcpm/nct38xx.c b/driver/tcpm/nct38xx.c index 9d91c21b30..8939c52924 100644 --- a/driver/tcpm/nct38xx.c +++ b/driver/tcpm/nct38xx.c @@ -105,29 +105,6 @@ static int nct38xx_tcpm_init(int port) return rv; } -static int tcpci_nct38xx_select_rp_value(int port, int rp) -{ - selected_rp[port] = rp; - return EC_SUCCESS; -} - -static int auto_discharge_disconnect(int port, int enable) -{ - int reg, rv; - - rv = tcpc_read(port, TCPC_REG_POWER_CTRL, ®); - if (rv) - return rv; - - if (enable) - reg = reg | TCPC_REG_POWER_CTRL_AUTO_DISCHARGE_DISCONNECT; - else - reg = reg & ~TCPC_REG_POWER_CTRL_AUTO_DISCHARGE_DISCONNECT; - rv = tcpc_write(port, TCPC_REG_POWER_CTRL, reg); - return rv; - -} - static int tcpci_nct38xx_check_cable_polarity(int port) { int cc, rv; @@ -222,23 +199,9 @@ static int tcpci_nct38xx_get_cc(int port, enum tcpc_cc_voltage_status *cc1, int tcpci_nct38xx_drp_toggle(int port) { - int rv; - cable_polarity[port] = POLARITY_NONE; - /* - * The port was disconnected so it is probably a good place to set - * auto-discharge-disconnect to '0' - * - * TODO(crbug.com/951683: this should be removed when common code adds - * auto discharge. - */ - rv = auto_discharge_disconnect(port, 0); - if (rv) - return rv; - return tcpci_tcpc_drp_toggle(port); - } int tcpci_nct38xx_set_polarity(int port, int polarity) @@ -252,16 +215,7 @@ int tcpci_nct38xx_set_polarity(int port, int polarity) reg = polarity ? (reg | TCPC_REG_TCPC_CTRL_SET(1)) : (reg & ~TCPC_REG_TCPC_CTRL_SET(1)); - rv = tcpc_write(port, TCPC_REG_TCPC_CTRL, reg); - if (rv) - return rv; - - /* - * Polarity is set after connection so it is probably a good time to set - * auto-discharge-disconnect to '1' - */ - rv = auto_discharge_disconnect(port, 1); - return rv; + return tcpc_write(port, TCPC_REG_TCPC_CTRL, reg); } int tcpci_nct38xx_transmit(int port, enum tcpm_transmit_type type, @@ -348,6 +302,7 @@ static void nct38xx_tcpc_alert(int port) nct38xx_ioex_event_handler(port); } + const struct tcpm_drv nct38xx_tcpm_drv = { .init = &nct38xx_tcpm_init, .release = &tcpci_tcpm_release, @@ -355,7 +310,7 @@ const struct tcpm_drv nct38xx_tcpm_drv = { #ifdef CONFIG_USB_PD_VBUS_DETECT_TCPC .get_vbus_level = &tcpci_tcpm_get_vbus_level, #endif - .select_rp_value = &tcpci_nct38xx_select_rp_value, + .select_rp_value = &tcpci_tcpm_select_rp_value, .set_cc = &tcpci_nct38xx_set_cc, .set_polarity = &tcpci_nct38xx_set_polarity, .set_vconn = &tcpci_tcpm_set_vconn, @@ -367,6 +322,8 @@ const struct tcpm_drv nct38xx_tcpm_drv = { #ifdef CONFIG_USB_PD_DISCHARGE_TCPC .tcpc_discharge_vbus = &tcpci_tcpc_discharge_vbus, #endif + .tcpc_connect_state_change = + &tcpci_tcpc_connect_state_change, #ifdef CONFIG_USB_PD_DUAL_ROLE_AUTO_TOGGLE .drp_toggle = &tcpci_nct38xx_drp_toggle, #endif diff --git a/driver/tcpm/tcpci.c b/driver/tcpm/tcpci.c index 9a0e45f1df..74519ef18e 100644 --- a/driver/tcpm/tcpci.c +++ b/driver/tcpm/tcpci.c @@ -10,6 +10,7 @@ #include "compile_time_macros.h" #include "console.h" #include "ec_commands.h" +#include "hooks.h" #include "ps8xxx.h" #include "task.h" #include "tcpci.h" @@ -241,7 +242,6 @@ int tcpci_tcpm_select_rp_value(int port, int rp) return EC_SUCCESS; } -#ifdef CONFIG_USB_PD_DISCHARGE_TCPC void tcpci_tcpc_discharge_vbus(int port, int enable) { int reg; @@ -256,7 +256,56 @@ void tcpci_tcpc_discharge_vbus(int port, int enable) tcpc_write(port, TCPC_REG_POWER_CTRL, reg); } -#endif + +/* + * On a connection state change, it is necessary for TCPCI devices to + * set the AUTO_DISCHARGE_DISCONNECT bit appropriately. + */ +void tcpci_tcpc_connect_state_change(int port, int connected) +{ + int reg, oldreg, rv; + + rv = tcpc_read(port, TCPC_REG_POWER_CTRL, &oldreg); + if (rv) { + /* CPRINTS("%s: failed read POWER_CTRL", __func__); */ + return; + } + + if (connected) + reg = oldreg | TCPC_REG_POWER_CTRL_AUTO_DISCHARGE_DISCONNECT; + else + reg = oldreg & ~TCPC_REG_POWER_CTRL_AUTO_DISCHARGE_DISCONNECT; + + if (reg != oldreg) { + rv = tcpc_write(port, TCPC_REG_POWER_CTRL, reg); + if (rv) { + /* CPRINTS("%s: failed write POWER_CTRL", __func__); */ + return; + } + } +} + +static void connect_state_change(int port, int connected) +{ + const struct tcpm_drv *tcpc = tcpc_config[port].drv; + + if (tcpc->tcpc_connect_state_change) + tcpc->tcpc_connect_state_change(port, connected); +} +static void connect_hook(void) +{ + int port = TASK_ID_TO_PD_PORT(task_get_current()); + + connect_state_change(port, 1); +} +DECLARE_HOOK(HOOK_USB_PD_CONNECT, connect_hook, HOOK_PRIO_DEFAULT); +static void disconnect_hook(void) +{ + int port = TASK_ID_TO_PD_PORT(task_get_current()); + + connect_state_change(port, 0); +} +DECLARE_HOOK(HOOK_USB_PD_DISCONNECT, disconnect_hook, HOOK_PRIO_DEFAULT); static int set_role_ctrl(int port, int toggle, int rp, int pull) { @@ -1016,6 +1065,8 @@ const struct tcpm_drv tcpci_tcpm_drv = { #ifdef CONFIG_USB_PD_DISCHARGE_TCPC .tcpc_discharge_vbus = &tcpci_tcpc_discharge_vbus, #endif + .tcpc_connect_state_change = + &tcpci_tcpc_connect_state_change, #ifdef CONFIG_USB_PD_DUAL_ROLE_AUTO_TOGGLE .drp_toggle = &tcpci_tcpc_drp_toggle, #endif diff --git a/driver/tcpm/tcpci.h b/driver/tcpm/tcpci.h index 81baba83bb..46e1d024aa 100644 --- a/driver/tcpm/tcpci.h +++ b/driver/tcpm/tcpci.h @@ -183,6 +183,8 @@ int tcpci_enter_low_power_mode(int port); void tcpci_tcpc_discharge_vbus(int port, int enable); #endif +void tcpci_tcpc_connect_state_change(int port, int connected); + int tcpci_tcpm_mux_init(int i2c_addr); int tcpci_tcpm_mux_set(int i2c_addr, mux_state_t mux_state); int tcpci_tcpm_mux_get(int i2c_addr, mux_state_t *mux_state); diff --git a/include/hooks.h b/include/hooks.h index e30c420fbb..5c699f9555 100644 --- a/include/hooks.h +++ b/include/hooks.h @@ -216,6 +216,8 @@ enum hook_type { /* * USB PD cc connection event. + * + * CC lines and VBus are stable when this hook is called. */ HOOK_USB_PD_CONNECT, }; diff --git a/include/usb_pd_tcpm.h b/include/usb_pd_tcpm.h index ab70c9a7f7..7a7bd0b3a1 100644 --- a/include/usb_pd_tcpm.h +++ b/include/usb_pd_tcpm.h @@ -266,6 +266,15 @@ struct tcpm_drv { */ void (*tcpc_discharge_vbus)(int port, int enable); + /** + * Connection State Change + * + * @param port Type-C port number + * @param connected Connection state + */ + void (*tcpc_connect_state_change)(int port, + int connected); + #ifdef CONFIG_USB_PD_DUAL_ROLE_AUTO_TOGGLE /** * Enable TCPC auto DRP toggling. -- cgit v1.2.1