diff options
-rw-r--r-- | common/usb_pd_protocol.c | 20 | ||||
-rw-r--r-- | common/usb_pd_tcpc.c | 51 | ||||
-rw-r--r-- | driver/tcpm/stub.c | 6 | ||||
-rw-r--r-- | driver/tcpm/tcpci.c | 73 | ||||
-rw-r--r-- | driver/tcpm/tcpci.h | 1 | ||||
-rw-r--r-- | include/config.h | 7 | ||||
-rw-r--r-- | include/usb_pd_tcpc.h | 8 | ||||
-rw-r--r-- | include/usb_pd_tcpm.h | 19 |
8 files changed, 167 insertions, 18 deletions
diff --git a/common/usb_pd_protocol.c b/common/usb_pd_protocol.c index 3b5cd5b445..b124ad0245 100644 --- a/common/usb_pd_protocol.c +++ b/common/usb_pd_protocol.c @@ -20,6 +20,7 @@ #include "task.h" #include "timer.h" #include "util.h" +#include "usb_charge.h" #include "usb_mux.h" #include "usb_pd.h" #include "usb_pd_tcpm.h" @@ -211,6 +212,15 @@ int pd_is_connected(int port) } #ifdef CONFIG_USB_PD_DUAL_ROLE +static inline int pd_is_vbus_present(int port) +{ +#ifdef CONFIG_USB_PD_TCPM_VBUS + return tcpm_get_vbus_level(port); +#else + return pd_snk_is_vbus_provided(port); +#endif +} + static int pd_snk_debug_acc_toggle(int port) { #ifdef CONFIG_CASE_CLOSED_DEBUG @@ -219,7 +229,7 @@ static int pd_snk_debug_acc_toggle(int port) * (without having seen Rp before), that might be a powered debug * accessory, let's toggle to source to try to detect it. */ - return pd_snk_is_vbus_provided(port); + return pd_is_vbus_present(port); #else /* Debug accessories not supported, never toggle */ return 0; @@ -1966,7 +1976,7 @@ void pd_task(void) /* Wait for CC debounce and VBUS present */ if (get_time().val < pd[port].cc_debounce || - !pd_snk_is_vbus_provided(port)) + !pd_is_vbus_present(port)) break; if (pd_try_src_enable && @@ -2044,7 +2054,7 @@ void pd_task(void) PD_STATE_SNK_DISCOVERY); } - if (!pd_snk_is_vbus_provided(port) && + if (!pd_is_vbus_present(port) && !snk_hard_reset_vbus_off) { /* VBUS has gone low, reset timeout */ snk_hard_reset_vbus_off = 1; @@ -2054,7 +2064,7 @@ void pd_task(void) PD_T_SRC_TURN_ON, PD_STATE_SNK_DISCONNECTED); } - if (pd_snk_is_vbus_provided(port) && + if (pd_is_vbus_present(port) && snk_hard_reset_vbus_off) { /* VBUS went high again */ set_state(port, PD_STATE_SNK_DISCOVERY); @@ -2503,7 +2513,7 @@ void pd_task(void) * a hard reset. */ if (pd[port].power_role == PD_ROLE_SINK && - !pd_snk_is_vbus_provided(port) && + !pd_is_vbus_present(port) && pd[port].task_state != PD_STATE_SNK_HARD_RESET_RECOVER && pd[port].task_state != PD_STATE_HARD_RESET_EXECUTE) { /* Sink: detect disconnect by monitoring VBUS */ diff --git a/common/usb_pd_tcpc.c b/common/usb_pd_tcpc.c index d7314b1a53..5c42640d5b 100644 --- a/common/usb_pd_tcpc.c +++ b/common/usb_pd_tcpc.c @@ -227,6 +227,9 @@ static struct pd_port_controller { uint8_t rx_enabled; /* TCPC flags */ uint8_t flags; + /* Power status */ + uint8_t power_status; + uint8_t power_status_mask; /* Last received */ int rx_head[RX_BUFFER_SIZE+1]; @@ -958,6 +961,29 @@ int tcpc_set_polarity(int port, int polarity) return EC_SUCCESS; } +#ifdef CONFIG_USB_PD_TCPM_VBUS +static int tcpc_set_power_status(int port, int vbus_present) +{ + /* Update VBUS present bit */ + if (vbus_present) + pd[port].power_status |= TCPC_REG_POWER_VBUS_PRES; + else + pd[port].power_status &= ~TCPC_REG_POWER_VBUS_PRES; + + /* Set bit Port Power Status bit in Alert register */ + if (pd[port].power_status_mask & TCPC_REG_POWER_VBUS_PRES) + alert(port, TCPC_REG_ALERT_POWER_STATUS); + + return EC_SUCCESS; +} +#endif /* CONFIG_USB_PD_TCPM_VBUS */ + +int tcpc_set_power_status_mask(int port, uint8_t mask) +{ + pd[port].power_status_mask = mask; + return EC_SUCCESS; +} + int tcpc_set_vconn(int port, int enable) { #ifdef CONFIG_USBC_VCONN @@ -1011,6 +1037,25 @@ int tcpc_get_message(int port, uint32_t *payload, int *head) return EC_SUCCESS; } + +#ifdef CONFIG_USB_PD_TCPM_VBUS +void pd_vbus_evt_p0(enum gpio_signal signal) +{ + tcpc_set_power_status(TASK_ID_TO_PD_PORT(TASK_ID_PD_C0), + !gpio_get_level(GPIO_USB_C0_VBUS_WAKE_L)); + task_wake(TASK_ID_PD_C0); +} + +#if CONFIG_USB_PD_PORT_COUNT >= 2 +void pd_vbus_evt_p1(enum gpio_signal signal) +{ + tcpc_set_power_status(TASK_ID_TO_PD_PORT(TASK_ID_PD_C1), + !gpio_get_level(GPIO_USB_C1_VBUS_WAKE_L)); + task_wake(TASK_ID_PD_C1); +} +#endif /* PD_PORT_COUNT >= 2 */ +#endif /* CONFIG_USB_PD_TCPM_VBUS */ + #ifndef CONFIG_USB_POWER_DELIVERY static void tcpc_i2c_write(int port, int reg, int len, uint8_t *payload) { @@ -1044,6 +1089,9 @@ static void tcpc_i2c_write(int port, int reg, int len, uint8_t *payload) tcpc_set_rx_enable(port, payload[1] & TCPC_REG_RX_DETECT_SOP_HRST_MASK); break; + case TCPC_REG_POWER_STATUS_MASK: + tcpc_set_power_status_mask(port, payload[1]); + break; case TCPC_REG_TX_HDR: pd[port].tx_head = (payload[2] << 8) | payload[1]; break; @@ -1114,6 +1162,9 @@ static int tcpc_i2c_read(int port, int reg, uint8_t *payload) memcpy(payload, pd[port].rx_payload[pd[port].rx_buf_tail], sizeof(pd[port].rx_payload[pd[port].rx_buf_tail])); return sizeof(pd[port].rx_payload[pd[port].rx_buf_tail]); + case TCPC_REG_POWER_STATUS: + payload[0] = pd[port].power_status; + return 1; case TCPC_REG_TX_BYTE_CNT: payload[0] = PD_HEADER_CNT(pd[port].tx_head); return 1; diff --git a/driver/tcpm/stub.c b/driver/tcpm/stub.c index 444730fc18..35f0329484 100644 --- a/driver/tcpm/stub.c +++ b/driver/tcpm/stub.c @@ -16,6 +16,7 @@ extern int tcpc_alert_mask_set(int port, uint16_t mask); extern int tcpc_get_cc(int port, int *cc1, int *cc2); extern int tcpc_set_cc(int port, int pull); extern int tcpc_set_polarity(int port, int polarity); +extern int tcpc_set_power_status_mask(int port, uint8_t mask); extern int tcpc_set_vconn(int port, int enable); extern int tcpc_set_msg_header(int port, int power_role, int data_role); extern int tcpc_set_rx_enable(int port, int enable); @@ -63,6 +64,11 @@ int tcpm_set_polarity(int port, int polarity) return tcpc_set_polarity(port, polarity); } +int tcpm_set_power_status_mask(int port, uint8_t mask) +{ + return tcpc_set_power_status_mask(port, mask); +} + int tcpm_set_vconn(int port, int enable) { return tcpc_set_vconn(port, enable); diff --git a/driver/tcpm/tcpci.c b/driver/tcpm/tcpci.c index 606b84e31c..939ab9ccf2 100644 --- a/driver/tcpm/tcpci.c +++ b/driver/tcpm/tcpci.c @@ -9,6 +9,7 @@ #include "task.h" #include "tcpci.h" #include "timer.h" +#include "usb_charge.h" #include "usb_pd.h" #include "usb_pd_tcpc.h" #include "usb_pd_tcpm.h" @@ -17,7 +18,7 @@ /* Convert port number to tcpc i2c address */ #define I2C_ADDR_TCPC(p) (CONFIG_TCPC_I2C_BASE_ADDR + 2*(p)) -static int tcpc_polarity, tcpc_vconn; +static int tcpc_polarity, tcpc_vconn, tcpc_vbus[CONFIG_USB_PD_PORT_COUNT]; static int init_alert_mask(int port) { @@ -30,13 +31,30 @@ static int init_alert_mask(int port) */ mask = TCPC_REG_ALERT_TX_SUCCESS | TCPC_REG_ALERT_TX_FAILED | TCPC_REG_ALERT_TX_DISCARDED | TCPC_REG_ALERT_RX_STATUS | - TCPC_REG_ALERT_RX_HARD_RST | TCPC_REG_ALERT_CC_STATUS; + TCPC_REG_ALERT_RX_HARD_RST | TCPC_REG_ALERT_CC_STATUS +#ifdef CONFIG_USB_PD_TCPM_VBUS + | TCPC_REG_ALERT_POWER_STATUS +#endif + ; /* Set the alert mask in TCPC */ rv = tcpm_alert_mask_set(port, mask); return rv; } +#ifdef CONFIG_USB_PD_TCPM_VBUS +static int init_power_status_mask(int port) +{ + uint8_t mask; + int rv; + + mask = TCPC_REG_POWER_VBUS_PRES; + rv = tcpm_set_power_status_mask(port, mask); + + return rv; +} +#endif + int tcpm_init(int port) { int rv, err = 0; @@ -52,6 +70,10 @@ int tcpm_init(int port) if (rv == EC_SUCCESS && !(err & TCPC_REG_ERROR_STATUS_UNINIT)) { i2c_write16(I2C_PORT_TCPC, I2C_ADDR_TCPC(port), TCPC_REG_ALERT, 0xff); +#ifdef CONFIG_USB_PD_TCPM_VBUS + /* Initialize power_status_mask */ + init_power_status_mask(port); +#endif return init_alert_mask(port); } msleep(10); @@ -85,6 +107,12 @@ int tcpm_get_cc(int port, int *cc1, int *cc2) return rv; } +int tcpm_get_power_status(int port, int *status) +{ + return i2c_read8(I2C_PORT_TCPC, I2C_ADDR_TCPC(port), + TCPC_REG_POWER_STATUS, status); +} + int tcpm_set_cc(int port, int pull) { /* @@ -124,11 +152,9 @@ int tcpm_set_msg_header(int port, int power_role, int data_role) int tcpm_alert_status(int port, int *alert) { - int rv; /* Read TCPC Alert register */ - rv = i2c_read16(I2C_PORT_TCPC, I2C_ADDR_TCPC(port), - TCPC_REG_ALERT, alert); - return rv; + return i2c_read16(I2C_PORT_TCPC, I2C_ADDR_TCPC(port), + TCPC_REG_ALERT, alert); } int tcpm_set_rx_enable(int port, int enable) @@ -139,18 +165,26 @@ int tcpm_set_rx_enable(int port, int enable) enable ? TCPC_REG_RX_DETECT_SOP_HRST_MASK : 0); } -int tcpm_alert_mask_set(int port, uint16_t mask) +int tcpm_set_power_status_mask(int port, uint8_t mask) { - int rv; /* write to the Alert Mask register */ - rv = i2c_write16(I2C_PORT_TCPC, I2C_ADDR_TCPC(port), - TCPC_REG_ALERT_MASK, mask); + return i2c_write8(I2C_PORT_TCPC, I2C_ADDR_TCPC(port), + TCPC_REG_POWER_STATUS_MASK , mask); +} - if (rv) - return rv; +int tcpm_alert_mask_set(int port, uint16_t mask) +{ + /* write to the Alert Mask register */ + return i2c_write16(I2C_PORT_TCPC, I2C_ADDR_TCPC(port), + TCPC_REG_ALERT_MASK, mask); +} - return rv; +#ifdef CONFIG_USB_PD_TCPM_VBUS +int tcpm_get_vbus_level(int port) +{ + return tcpc_vbus[port]; } +#endif int tcpm_get_message(int port, uint32_t *payload, int *head) { @@ -215,6 +249,7 @@ int tcpm_transmit(int port, enum tcpm_transmit_type type, uint16_t header, void tcpc_alert(int port) { int status; + int power_status; /* Read the Alert register from the TCPC */ tcpm_alert_status(port, &status); @@ -231,6 +266,18 @@ void tcpc_alert(int port) /* CC status changed, wake task */ task_set_event(PD_PORT_TO_TASK_ID(port), PD_EVENT_CC, 0); } + if (status & TCPC_REG_ALERT_POWER_STATUS) { + /* Read Power Status register */ + tcpm_get_power_status(port, &power_status); + /* Update VBUS status */ + tcpc_vbus[port] = power_status & + TCPC_REG_POWER_VBUS_PRES ? 1 : 0; +#if defined(CONFIG_USB_PD_TCPM_VBUS) && defined(CONFIG_USB_CHARGER) + /* Update charge manager with new VBUS state */ + usb_charger_vbus_change(port, tcpc_vbus[port]); +#endif /* CONFIG_USB_PD_TCPM_VBUS && CONFIG_USB_CHARGER */ + task_wake(PD_PORT_TO_TASK_ID(port)); + } if (status & TCPC_REG_ALERT_RX_STATUS) { /* message received */ task_set_event(PD_PORT_TO_TASK_ID(port), PD_EVENT_RX, 0); diff --git a/driver/tcpm/tcpci.h b/driver/tcpm/tcpci.h index 18f9a75e95..cbfac0380c 100644 --- a/driver/tcpm/tcpci.h +++ b/driver/tcpm/tcpci.h @@ -45,6 +45,7 @@ #define TCPC_REG_CC_STATUS_CC1(reg) ((reg) & 0x3) #define TCPC_REG_POWER_STATUS 0x19 +#define TCPC_REG_POWER_VBUS_PRES (1<<5) #define TCPC_REG_ERROR_STATUS 0x1a #define TCPC_REG_ERROR_STATUS_UNINIT (1<<7) #define TCPC_REG_ROLE_CTRL 0x1b diff --git a/include/config.h b/include/config.h index 7172f54697..a7555c4acc 100644 --- a/include/config.h +++ b/include/config.h @@ -1628,6 +1628,13 @@ #undef CONFIG_USB_PD_TCPM_STUB #undef CONFIG_USB_PD_TCPM_TCPCI +/* + * Use this option if the TCPC port controller is on a seperate chip from + * the TCPM layer and if VUBS detect GPIO is not available on the TCPM + * mcu. + */ +#undef CONFIG_USB_PD_TCPM_VBUS + /* Define the type-c port controller I2C base address. */ #undef CONFIG_TCPC_I2C_BASE_ADDR diff --git a/include/usb_pd_tcpc.h b/include/usb_pd_tcpc.h index 64d68f1f3a..a640714c4f 100644 --- a/include/usb_pd_tcpc.h +++ b/include/usb_pd_tcpc.h @@ -35,4 +35,12 @@ void tcpc_i2c_process(int read, int port, int len, uint8_t *payload, void (*send_response)(int)); +/** + * Handle VBUS wake interrupts + * + * @param signal The VBUS wake interrupt signal + */ +void pd_vbus_evt_p0(enum gpio_signal signal); +void pd_vbus_evt_p1(enum gpio_signal signal); + #endif /* __CROS_EC_USB_PD_TCPC_H */ diff --git a/include/usb_pd_tcpm.h b/include/usb_pd_tcpm.h index bd4803bf03..8d446bcae8 100644 --- a/include/usb_pd_tcpm.h +++ b/include/usb_pd_tcpm.h @@ -113,6 +113,15 @@ int tcpm_alert_mask_set(int port, uint16_t mask); int tcpm_get_cc(int port, int *cc1, int *cc2); /** + * Read VBUS + * + * @param port Type-C port number + * + * @return 0 => VBUS not detected, 1 => VBUS detected + */ +int tcpm_get_vbus_level(int port); + +/** * Set the CC pull resistor. This sets our role as either source or sink. * * @param port Type-C port number @@ -133,6 +142,16 @@ int tcpm_set_cc(int port, int pull); int tcpm_set_polarity(int port, int polarity); /** + * Set TCPC Power Status Mask + * + * @param port Type-C port number + * @param mask => new mask value + * + * @return EC_SUCCESS or error + */ +int tcpm_set_power_status_mask(int port, uint8_t mask); + +/** * Set Vconn. * * @param port Type-C port number |