diff options
Diffstat (limited to 'driver/tcpm')
34 files changed, 0 insertions, 12866 deletions
diff --git a/driver/tcpm/anx7447.c b/driver/tcpm/anx7447.c deleted file mode 100644 index 9a9a3c7971..0000000000 --- a/driver/tcpm/anx7447.c +++ /dev/null @@ -1,861 +0,0 @@ -/* Copyright 2018 The Chromium OS Authors. All rights reserved. - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ - -/* ANX7447 port manager */ - -#include "common.h" -#include "anx7447.h" -#include "console.h" -#include "hooks.h" -#include "tcpm/tcpci.h" -#include "tcpm/tcpm.h" -#include "timer.h" -#include "usb_mux.h" -#include "usb_pd.h" -#include "util.h" - -#define CPRINTS(format, args...) cprints(CC_USBCHARGE, format, ## args) -#define CPRINTF(format, args...) cprintf(CC_USBCHARGE, format, ## args) - -#define vsafe5v_min (3800/25) -#define vsafe0v_max (800/25) -/* - * These interface are workable while ADC is enabled, before - * calling them should make sure ec driver finished chip initilization. - */ -#define is_equal_greater_safe5v(port) \ - (((anx7447_get_vbus_voltage(port))) > vsafe5v_min) -#define is_equal_greater_safe0v(port) \ - (((anx7447_get_vbus_voltage(port))) > vsafe0v_max) - -struct anx_state { - uint16_t i2c_addr_flags; -}; - -struct anx_usb_mux { - int state; -}; - -static int anx7447_mux_set(const struct usb_mux *me, mux_state_t mux_state, - bool *ack_required); - -static struct anx_state anx[CONFIG_USB_PD_PORT_MAX_COUNT]; -static struct anx_usb_mux mux[CONFIG_USB_PD_PORT_MAX_COUNT]; - -/* - * ANX7447 has two co-existence I2C addresses, TCPC address and - * SPI address. The registers of TCPC address are partly compliant - * with standard USB TCPC specification, and the registers in SPI - * address controls the other functions (ex, hpd_level, mux_switch, and - * so on). It can't use tcpc_read() and tcpc_write() to access SPI - * address because its address has been set as TCPC in the structure - * tcpc_config_t. - * anx7447_reg_write() and anx7447_reg_read() are implemented here to access - * ANX7447 SPI address. - */ -const struct anx7447_i2c_addr anx7447_i2c_addrs_flags[] = { - {AN7447_TCPC0_I2C_ADDR_FLAGS, AN7447_SPI0_I2C_ADDR_FLAGS}, - {AN7447_TCPC1_I2C_ADDR_FLAGS, AN7447_SPI1_I2C_ADDR_FLAGS}, - {AN7447_TCPC2_I2C_ADDR_FLAGS, AN7447_SPI2_I2C_ADDR_FLAGS}, - {AN7447_TCPC3_I2C_ADDR_FLAGS, AN7447_SPI3_I2C_ADDR_FLAGS} -}; - -static inline int anx7447_reg_write(int port, int reg, int val) -{ - int rv = i2c_write8(tcpc_config[port].i2c_info.port, - anx[port].i2c_addr_flags, - 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) -{ - int rv = i2c_read8(tcpc_config[port].i2c_info.port, - anx[port].i2c_addr_flags, - reg, val); -#ifdef CONFIG_USB_PD_TCPC_LOW_POWER - pd_device_accessed(port); -#endif - return rv; -} - -void anx7447_hpd_mode_init(int port) -{ - int reg, rv; - - rv = anx7447_reg_read(port, ANX7447_REG_HPD_CTRL_0, ®); - if (rv) - return; - - /* - * Set ANX7447_REG_HPD_MODE bit as 0, then the TCPC will generate the - * HPD pulse from internal timer (by using ANX7447_REG_HPD_IRQ0) - * instead of using the ANX7447_REG_HPD_OUT to set the HPD IRQ signal. - */ - reg &= ~(ANX7447_REG_HPD_MODE | ANX7447_REG_HPD_PLUG | - ANX7447_REG_HPD_UNPLUG); - anx7447_reg_write(port, ANX7447_REG_HPD_CTRL_0, reg); -} - -void anx7447_hpd_output_en(int port) -{ - int reg, rv; - - rv = anx7447_reg_read(port, ANX7447_REG_HPD_DEGLITCH_H, ®); - if (rv) - return; - - reg |= ANX7447_REG_HPD_OEN; - anx7447_reg_write(port, ANX7447_REG_HPD_DEGLITCH_H, reg); -} - -void anx7447_set_hpd_level(int port, int hpd_lvl) -{ - int reg, rv; - - rv = anx7447_reg_read(port, ANX7447_REG_HPD_CTRL_0, ®); - if (rv) - return; - - /* - * When ANX7447_REG_HPD_MODE is 1, use ANX7447_REG_HPD_OUT - * to generate HPD event, otherwise use ANX7447_REG_HPD_UNPLUG - * and ANX7447_REG_HPD_PLUG. - */ - if (hpd_lvl) { - reg &= ~ANX7447_REG_HPD_UNPLUG; - reg |= ANX7447_REG_HPD_PLUG; - } else { - reg &= ~ANX7447_REG_HPD_PLUG; - reg |= ANX7447_REG_HPD_UNPLUG; - } - anx7447_reg_write(port, ANX7447_REG_HPD_CTRL_0, reg); -} - -#ifdef CONFIG_USB_PD_TCPM_ANX7447_OCM_ERASE_COMMAND -static inline void anx7447_reg_write_and(int port, int reg, int v_and) -{ - int val; - - if (!anx7447_reg_read(port, reg, &val)) - anx7447_reg_write(port, reg, (val & v_and)); -} - -static inline void anx7447_reg_write_or(int port, int reg, int v_or) -{ - int val; - - if (!anx7447_reg_read(port, reg, &val)) - anx7447_reg_write(port, reg, (val | v_or)); -} - -#define ANX7447_FLASH_DONE_TIMEOUT_US (100 * MSEC) - -static int anx7447_wait_for_flash_done(int port) -{ - timestamp_t deadline; - int rv; - int r; - - deadline.val = get_time().val + ANX7447_FLASH_DONE_TIMEOUT_US; - do { - if (timestamp_expired(deadline, NULL)) - return EC_ERROR_TIMEOUT; - rv = anx7447_reg_read(port, ANX7447_REG_R_RAM_CTRL, &r); - if (rv) - return rv; - } while (!(r & ANX7447_R_RAM_CTRL_FLASH_DONE)); - - return EC_SUCCESS; -} - -static int anx7447_flash_write_en(int port) -{ - anx7447_reg_write(port, ANX7447_REG_FLASH_INST_TYPE, - ANX7447_FLASH_INST_TYPE_WRITEENABLE); - anx7447_reg_write_or(port, ANX7447_REG_R_FLASH_RW_CTRL, - ANX7447_R_FLASH_RW_CTRL_GENERAL_INST_EN); - return anx7447_wait_for_flash_done(port); -} - -static int anx7447_flash_op_init(int port) -{ - int rv; - - anx7447_reg_write_or(port, ANX7447_REG_OCM_CTRL_0, - ANX7447_OCM_CTRL_OCM_RESET); - anx7447_reg_write_or(port, ANX7447_REG_ADDR_GPIO_CTRL_0, - ANX7447_ADDR_GPIO_CTRL_0_SPI_WP); - - rv = anx7447_flash_write_en(port); - if (rv) - return rv; - - anx7447_reg_write_and(port, ANX7447_REG_R_FLASH_STATUS_0, - ANX7447_FLASH_STATUS_SPI_STATUS_0); - anx7447_reg_write_or(port, ANX7447_REG_R_FLASH_RW_CTRL, - ANX7447_R_FLASH_RW_CTRL_WRITE_STATUS_EN); - - return anx7447_wait_for_flash_done(port); -} - -static int anx7447_flash_is_empty(int port) -{ - int r; - - anx7447_reg_read(port, ANX7447_REG_OCM_VERSION, &r); - - return ((r == 0) ? 1 : 0); -} - -static int anx7447_flash_erase_internal(int port, int write_console_if_empty) -{ - int rv; - int r; - - tcpc_read(port, TCPC_REG_COMMAND, &r); - usleep(ANX7447_DELAY_IN_US); - - if (anx7447_flash_is_empty(port) == 1) { - if (write_console_if_empty) - CPRINTS("C%d: Nothing to erase!", port); - return EC_SUCCESS; - } - CPRINTS("C%d: Erasing OCM flash...", port); - - rv = anx7447_flash_op_init(port); - if (rv) - return rv; - - usleep(ANX7447_DELAY_IN_US); - - rv = anx7447_flash_write_en(port); - if (rv) - return rv; - - anx7447_reg_write(port, ANX7447_REG_FLASH_ERASE_TYPE, - ANX7447_FLASH_ERASE_TYPE_CHIPERASE); - anx7447_reg_write_or(port, ANX7447_REG_R_FLASH_RW_CTRL, - ANX7447_R_FLASH_RW_CTRL_FLASH_ERASE_EN); - - return anx7447_wait_for_flash_done(port); -} - -int anx7447_flash_erase(int port) -{ - return anx7447_flash_erase_internal(port, - 0 /* suppress console if empty */); -} - -/* Add console command to erase OCM flash if needed. */ -static int command_anx_ocm(int argc, char **argv) -{ - char *e = NULL; - int port; - - if (argc < 2) - return EC_ERROR_PARAM_COUNT; - - /* Get port number from first parameter */ - port = strtoi(argv[1], &e, 0); - if (*e) - return EC_ERROR_PARAM1; - - if (argc > 2) { - int rv; - if (strcasecmp(argv[2], "erase")) - return EC_ERROR_PARAM2; - rv = anx7447_flash_erase_internal( - port, 1 /* write to console if empty */); - if (rv) - ccprintf("C%d: Failed to erase OCM flash (%d)\n", - port, rv); - } - - ccprintf("C%d: OCM flash is %sempty.\n", - port, anx7447_flash_is_empty(port) ? "" : "not "); - - return EC_SUCCESS; -} -DECLARE_CONSOLE_COMMAND(anx_ocm, command_anx_ocm, - "port [erase]", - "Print OCM status or erases OCM for a given port."); -#endif - -static int anx7447_init(int port) -{ - int rv, reg, i; - const struct usb_mux *me = &usb_muxes[port]; - bool unused; - - ASSERT(port < CONFIG_USB_PD_PORT_MAX_COUNT); - - memset(&anx[port], 0, sizeof(struct anx_state)); - - /* - * find corresponding anx7447 SPI address according to - * specified TCPC address - */ - for (i = 0; i < ARRAY_SIZE(anx7447_i2c_addrs_flags); i++) { - if (I2C_STRIP_FLAGS(tcpc_config[port].i2c_info.addr_flags) == - I2C_STRIP_FLAGS( - anx7447_i2c_addrs_flags[i].tcpc_addr_flags)) { - anx[port].i2c_addr_flags = - anx7447_i2c_addrs_flags[i].spi_addr_flags; - break; - } - } - if (!I2C_STRIP_FLAGS(anx[port].i2c_addr_flags)) { - ccprintf("TCPC I2C addr 0x%x is invalid for ANX7447\n", - I2C_STRIP_FLAGS(tcpc_config[port] - .i2c_info.addr_flags)); - return EC_ERROR_UNKNOWN; - } - - - rv = tcpci_tcpm_init(port); - if (rv) - return rv; - -#ifdef CONFIG_USB_PD_TCPM_ANX7447_OCM_ERASE_COMMAND - /* Check and print OCM status to console. */ - CPRINTS("C%d: OCM flash is %sempty", - port, anx7447_flash_is_empty(port) ? "" : "not "); -#endif - - /* - * 7447 has a physical pin to detect the presence of VBUS, VBUS_SENSE - * , and 7447 has a VBUS current protection mechanism through another - * pin input VBUS_OCP. To enable VBUS OCP, OVP protection, driver needs - * to set the threshold to the registers VBUS_VOLTAGE_ALARM_HI_CFG - * (0x76 & 0x77) and VBUS_OCP_HI_THRESHOLD (0xDD &0xDE). These values - * could be customized based on different platform design. - * Disable VBUS protection here since the default values of - * VBUS_VOLTAGE_ALARM_HI_CFG and VBUS_OCP_HI_THRESHOLD are zero. - */ - rv = tcpc_read(port, ANX7447_REG_TCPC_CTRL_2, ®); - if (rv) - return rv; - reg &= ~ANX7447_REG_ENABLE_VBUS_PROTECT; - rv = tcpc_write(port, ANX7447_REG_TCPC_CTRL_2, reg); - if (rv) - return rv; - - /* - * Specifically disable voltage alarms, as VBUS_VOLTAGE_ALARM_HI may - * trigger repeatedly despite being masked (b/153989733) - */ - rv = tcpc_update16(port, TCPC_REG_POWER_CTRL, - TCPC_REG_POWER_CTRL_VBUS_VOL_MONITOR_DIS, MASK_SET); - if (rv) - return rv; - - /* ADC enable, use to monitor VBUS voltage */ - rv = tcpc_read(port, ANX7447_REG_ADC_CTRL_1, ®); - if (rv) - return rv; - reg |= ANX7447_REG_ADCFSM_EN; - rv = tcpc_write(port, ANX7447_REG_ADC_CTRL_1, reg); - if (rv) - return rv; - - /* Set VCONN OCP(Over Current Protection) threshold */ - rv = tcpc_read(port, ANX7447_REG_ANALOG_CTRL_8, ®); - if (rv) - return rv; - reg &= ~ANX7447_REG_VCONN_OCP_MASK; - reg |= ANX7447_REG_VCONN_OCP_440mA; - rv = tcpc_write(port, ANX7447_REG_ANALOG_CTRL_8, reg); - - /* Vconn SW protection time of inrush current */ - rv = tcpc_read(port, ANX7447_REG_ANALOG_CTRL_10, ®); - if (rv) - return rv; - reg &= ~ANX7447_REG_R_VCONN_PWR_PRT_INRUSH_TIME_MASK; - reg |= ANX7447_REG_R_VCONN_PWR_PRT_INRUSH_TIME_2430US; - rv = tcpc_write(port, ANX7447_REG_ANALOG_CTRL_10, reg); - if (rv) - return rv; - -#ifdef CONFIG_USB_PD_TCPM_MUX - /* - * Run mux_set() here for considering CCD(Case-Closed Debugging) case - * If this TCPC is not also the MUX then don't initialize to NONE - */ - while ((me != NULL) && (me->driver != &anx7447_usb_mux_driver)) - me = me->next_mux; - - /* - * Note that bypassing the usb_mux API is okay for internal driver calls - * since the task calling init already holds this port's mux lock. - */ - if (me != NULL && - !(me->flags & USB_MUX_FLAG_NOT_TCPC)) - rv = anx7447_mux_set(me, USB_PD_MUX_NONE, &unused); -#endif /* CONFIG_USB_PD_TCPM_MUX */ - - return rv; -} - -static int anx7447_release(int port) -{ - return EC_SUCCESS; -} - -#ifdef CONFIG_USB_PD_VBUS_DETECT_TCPC -static int anx7447_get_vbus_voltage(int port) -{ - int vbus_volt = 0; - - tcpc_read16(port, TCPC_REG_VBUS_VOLTAGE, &vbus_volt); - - return vbus_volt; -} - -int anx7447_set_power_supply_ready(int port) -{ - int count = 0; - - while (is_equal_greater_safe0v(port)) { - if (count >= 10) - break; - msleep(100); - count++; - } - - return tcpc_write(port, TCPC_REG_COMMAND, 0x77); -} -#endif /* CONFIG_USB_PD_VBUS_DETECT_TCPC */ - -int anx7447_power_supply_reset(int port) -{ - return tcpc_write(port, TCPC_REG_COMMAND, 0x66); -} - -int anx7447_board_charging_enable(int port, int enable) -{ - return tcpc_write(port, TCPC_REG_COMMAND, enable ? 0x55 : 0x44); -} - -static void anx7447_tcpc_alert(int port) -{ - /* process and clear alert status */ - tcpci_tcpc_alert(port); -} - -/* - * timestamp of the next possible toggle to ensure the 2-ms spacing - * between IRQ_HPD. - */ -static uint64_t hpd_deadline[CONFIG_USB_PD_PORT_MAX_COUNT]; - -void anx7447_tcpc_update_hpd_status(const struct usb_mux *me, - mux_state_t mux_state) -{ - int reg = 0; - int port = me->usb_port; - int hpd_lvl = (mux_state & USB_PD_MUX_HPD_LVL) ? 1 : 0; - int hpd_irq = (mux_state & USB_PD_MUX_HPD_IRQ) ? 1 : 0; - - /* - * All calls within this method need to update to a mux_read/write calls - * that use the secondary address. This is a non-trival change and no - * one is using the anx7447 as a mux only (and probably never will since - * it doesn't have a re-driver). If that changes, we need to update this - * code. - */ - ASSERT(!(me->flags & USB_MUX_FLAG_NOT_TCPC)); - - anx7447_set_hpd_level(port, hpd_lvl); - - if (hpd_irq) { - uint64_t now = get_time().val; - /* wait for the minimum spacing between IRQ_HPD if needed */ - if (now < hpd_deadline[port]) - usleep(hpd_deadline[port] - now); - - /* - * For generate hardware HPD IRQ, need clear bit - * ANX7447_REG_HPD_IRQ0 first, then set it. This bit is not - * write clear. - */ - anx7447_reg_read(port, ANX7447_REG_HPD_CTRL_0, ®); - reg &= ~ANX7447_REG_HPD_IRQ0; - anx7447_reg_write(port, ANX7447_REG_HPD_CTRL_0, reg); - reg |= ANX7447_REG_HPD_IRQ0; - anx7447_reg_write(port, ANX7447_REG_HPD_CTRL_0, reg); - } - /* enforce 2-ms delay between HPD pulses */ - hpd_deadline[port] = get_time().val + HPD_USTREAM_DEBOUNCE_LVL; -} - -void anx7447_tcpc_clear_hpd_status(int port) -{ - anx7447_hpd_output_en(port); - anx7447_set_hpd_level(port, 0); -} - -#ifdef CONFIG_USB_PD_TCPM_MUX -static int anx7447_mux_init(const struct usb_mux *me) -{ - int port = me->usb_port; - bool unused; - - ASSERT(port < CONFIG_USB_PD_PORT_MAX_COUNT); - - memset(&mux[port], 0, sizeof(struct anx_usb_mux)); - - /* init hpd status */ - anx7447_hpd_mode_init(port); - anx7447_set_hpd_level(port, 0); - anx7447_hpd_output_en(port); - - /* - * ANX initializes its muxes to (USB_PD_MUX_USB_ENABLED | - * USB_PD_MUX_DP_ENABLED) when reinitialized, we need to force - * initialize it to USB_PD_MUX_NONE - */ - return anx7447_mux_set(me, USB_PD_MUX_NONE, &unused); -} - -#ifdef CONFIG_USB_PD_TCPM_ANX7447_AUX_PU_PD -static void anx7447_mux_safemode(const struct usb_mux *me, int on_off) -{ - int reg; - - mux_read(me, ANX7447_REG_ANALOG_CTRL_9, ®); - - if (on_off) - reg |= ANX7447_REG_SAFE_MODE; - else - reg &= ~(ANX7447_REG_SAFE_MODE); - - mux_write(me, ANX7447_REG_ANALOG_CTRL_9, reg); - CPRINTS("C%d set mux to safemode %s, reg = 0x%x", - me->usb_port, (on_off) ? "on" : "off", reg); -} - -static inline void anx7447_configure_aux_src(const struct usb_mux *me, - int on_off) -{ - int reg; - - mux_read(me, ANX7447_REG_ANALOG_CTRL_9, ®); - - if (on_off) - reg |= ANX7447_REG_R_AUX_RES_PULL_SRC; - else - reg &= ~(ANX7447_REG_R_AUX_RES_PULL_SRC); - - mux_write(me, ANX7447_REG_ANALOG_CTRL_9, reg); - - CPRINTS("C%d set aux_src to %s, reg = 0x%x", - me->usb_port, (on_off) ? "on" : "off", reg); -} -#endif - -/* - * Set mux. - * - * sstx and ssrx are the USB superspeed transmit and receive pairs. ml is the - * DisplayPort Main Link. There are four lanes total. For example, DP cases - * connect them all and dock cases connect 2 DP and USB. - * - * a2, a3, a10, a11, b2, b3, b10, b11 are pins on the USB-C connector. - */ -static int anx7447_mux_set(const struct usb_mux *me, mux_state_t mux_state, - bool *ack_required) -{ - int cc_direction; - mux_state_t mux_type; - int sw_sel = 0x00, aux_sw = 0x00; - int rv; - int port = me->usb_port; - - /* This driver does not use host command ACKs */ - *ack_required = false; - - cc_direction = mux_state & USB_PD_MUX_POLARITY_INVERTED; - mux_type = mux_state & USB_PD_MUX_DOCK; - CPRINTS("C%d mux_state = 0x%x, mux_type = 0x%x", - port, mux_state, mux_type); - if (cc_direction == 0) { - /* cc1 connection */ - if (mux_type == USB_PD_MUX_DOCK) { - /* ml0-a10/11, ml1-b2/b3, sstx-a2/a3, ssrx-b10/11 */ - sw_sel = 0x21; - /* aux+ <-> sbu1, aux- <-> sbu2 */ - aux_sw = 0x03; - } else if (mux_type == USB_PD_MUX_DP_ENABLED) { - /* ml0-a10/11, ml1-b2/b3, ml2-a2/a3, ml3-b10/11 */ - sw_sel = 0x09; - /* aux+ <-> sbu1, aux- <-> sbu2 */ - aux_sw = 0x03; - } else if (mux_type == USB_PD_MUX_USB_ENABLED) { - /* ssrxp<->b11, ssrxn<->b10, sstxp<->a2, sstxn<->a3 */ - sw_sel = 0x20; - } - } else { - /* cc2 connection */ - if (mux_type == USB_PD_MUX_DOCK) { - /* ml0-b10/11, ml1-a2/b3, sstx-b2/a3, ssrx-a10/11 */ - sw_sel = 0x12; - /* aux+ <-> sbu2, aux- <-> sbu1 */ - aux_sw = 0x0C; - } else if (mux_type == USB_PD_MUX_DP_ENABLED) { - /* ml0-b10/11, ml1-a2/b3, ml2-b2/a3, ml3-a10/11 */ - sw_sel = 0x06; - /* aux+ <-> sbu2, aux- <-> sbu1 */ - aux_sw = 0x0C; - } else if (mux_type == USB_PD_MUX_USB_ENABLED) { - /* ssrxp<->a11, ssrxn<->a10, sstxp<->b2, sstxn<->b3 */ - sw_sel = 0x10; - } - } - - /* - * Once need to configure the Mux, should set the mux to safe mode - * first. After the mux configured, should set mux to normal mode. - */ -#ifdef CONFIG_USB_PD_TCPM_ANX7447_AUX_PU_PD - anx7447_mux_safemode(me, 1); -#endif - rv = mux_write(me, ANX7447_REG_TCPC_SWITCH_0, sw_sel); - rv |= mux_write(me, ANX7447_REG_TCPC_SWITCH_1, sw_sel); - rv |= mux_write(me, ANX7447_REG_TCPC_AUX_SWITCH, aux_sw); - - mux[port].state = mux_state; - -#ifdef CONFIG_USB_PD_TCPM_ANX7447_AUX_PU_PD - /* - * DP and Dock mode: after configured the Mux, change the Mux to - * normal mode, otherwise: keep safe mode. - */ - if (mux_type != USB_PD_MUX_NONE) { - anx7447_configure_aux_src(me, 1); - anx7447_mux_safemode(me, 0); - } else - anx7447_configure_aux_src(me, 0); -#endif - - return rv; -} - -/* current mux state */ -static int anx7447_mux_get(const struct usb_mux *me, mux_state_t *mux_state) -{ - int port = me->usb_port; - - *mux_state = mux[port].state; - - return EC_SUCCESS; -} -#endif /* CONFIG_USB_PD_TCPM_MUX */ - -#ifdef CONFIG_USB_PD_DUAL_ROLE_AUTO_TOGGLE -static int anx7447_tcpc_drp_toggle(int port) -{ - int rv, reg; - - rv = tcpc_read(port, ANX7447_REG_ANALOG_CTRL_10, ®); - if (rv) - return rv; - /* - * When using Look4Connection command to toggle CC under normal mode - * the CABLE_DET_DIG shall be clear first. - */ - if (reg & ANX7447_REG_CABLE_DET_DIG) { - reg &= ~ANX7447_REG_CABLE_DET_DIG; - rv = tcpc_write(port, ANX7447_REG_ANALOG_CTRL_10, reg); - if (rv) - return rv; - } - - return tcpci_tcpc_drp_toggle(port); -} -#endif - -/* Override for tcpci_tcpm_set_cc */ -static int anx7447_set_cc(int port, int pull) -{ - int rp, reg; - - rp = tcpc_read(port, ANX7447_REG_ANALOG_CTRL_10, ®); - if (rp) - return rp; - /* - * When setting CC status, should be confirm that the CC toggling - * process is stopped, the CABLE_DET_DIG shall be set to one. - */ - if ((reg & ANX7447_REG_CABLE_DET_DIG) == 0) { - reg |= ANX7447_REG_CABLE_DET_DIG; - rp = tcpc_write(port, ANX7447_REG_ANALOG_CTRL_10, reg); - if (rp) - return rp; - } - - rp = tcpci_get_cached_rp(port); - - /* Set manual control, and set both CC lines to the same pull */ - return tcpc_write(port, TCPC_REG_ROLE_CTRL, - TCPC_REG_ROLE_CTRL_SET(0, rp, pull, pull)); -} - -/* Override for tcpci_tcpm_set_polarity */ -static int anx7447_set_polarity(int port, - enum tcpc_cc_polarity polarity) -{ - return tcpc_update8(port, - TCPC_REG_TCPC_CTRL, - TCPC_REG_TCPC_CTRL_SET(1), - polarity_rm_dts(polarity) - ? MASK_SET : MASK_CLR); -} - -#ifdef CONFIG_CMD_TCPC_DUMP -static const struct tcpc_reg_dump_map anx7447_regs[] = { - { - .addr = ANX7447_REG_TCPC_SWITCH_0, - .name = "SWITCH_0", - .size = 1, - }, - { - .addr = ANX7447_REG_TCPC_SWITCH_1, - .name = "SWITCH_1", - .size = 1, - }, - { - .addr = ANX7447_REG_TCPC_AUX_SWITCH, - .name = "AUX_SWITCH", - .size = 1, - }, - { - .addr = ANX7447_REG_ADC_CTRL_1, - .name = "ADC_CTRL_1", - .size = 1, - }, - { - .addr = ANX7447_REG_ANALOG_CTRL_8, - .name = "ANALOG_CTRL_8", - .size = 1, - }, - { - .addr = ANX7447_REG_ANALOG_CTRL_10, - .name = "ANALOG_CTRL_10", - .size = 1, - }, - { - .addr = ANX7447_REG_TCPC_CTRL_2, - .name = "TCPC_CTRL_2", - .size = 1, - }, -}; - -const struct { - const char *name; - uint8_t addr; -} anx7447_alt_regs[] = { - { - .name = "HPD_CTRL_0", - .addr = ANX7447_REG_HPD_CTRL_0, - }, - { - .name = "HPD_DEGLITCH_H", - .addr = ANX7447_REG_HPD_DEGLITCH_H, - }, - { - .name = "INTP_SOURCE_0", - .addr = ANX7447_REG_INTP_SOURCE_0, - }, - { - .name = "INTP_MASK_0", - .addr = ANX7447_REG_INTP_MASK_0, - }, - { - .name = "INTP_CTRL_0", - .addr = ANX7447_REG_INTP_CTRL_0, - }, - { - .name = "PAD_INTP_CTRL", - .addr = ANX7447_REG_PAD_INTP_CTRL, - }, -}; - -/* - * Dump registers for debug command. - */ -static void anx7447_dump_registers(int port) -{ - int i, val; - - tcpc_dump_std_registers(port); - tcpc_dump_registers(port, anx7447_regs, ARRAY_SIZE(anx7447_regs)); - for (i = 0; i < ARRAY_SIZE(anx7447_alt_regs); i++) { - anx7447_reg_read(port, anx7447_alt_regs[i].addr, &val); - ccprintf(" %-26s(ALT/0x%02x) = 0x%02x\n", - anx7447_alt_regs[i].name, - anx7447_alt_regs[i].addr, (uint8_t)val); - cflush(); - } -} -#endif /* defined(CONFIG_CMD_TCPC_DUMP) */ - -/* - * ANX7447 is a TCPCI compatible port controller, with some caveats. - * It seems to require both CC lines to be set always, instead of just - * one at a time, according to TCPCI spec. Thus, now that the TCPCI - * driver more closely follows the spec, this driver requires - * overrides for set_cc and set_polarity. - */ -const struct tcpm_drv anx7447_tcpm_drv = { - .init = &anx7447_init, - .release = &anx7447_release, - .get_cc = &tcpci_tcpm_get_cc, -#ifdef CONFIG_USB_PD_VBUS_DETECT_TCPC - .check_vbus_level = &tcpci_tcpm_check_vbus_level, -#endif - .select_rp_value = &tcpci_tcpm_select_rp_value, - .set_cc = &anx7447_set_cc, - .set_polarity = &anx7447_set_polarity, -#ifdef CONFIG_USB_PD_DECODE_SOP - .sop_prime_enable = &tcpci_tcpm_sop_prime_enable, -#endif - .set_vconn = &tcpci_tcpm_set_vconn, - .set_msg_header = &tcpci_tcpm_set_msg_header, - .set_rx_enable = &tcpci_tcpm_set_rx_enable, - .get_message_raw = &tcpci_tcpm_get_message_raw, - .transmit = &tcpci_tcpm_transmit, - .tcpc_alert = &anx7447_tcpc_alert, -#ifdef CONFIG_USB_PD_DISCHARGE_TCPC - .tcpc_discharge_vbus = &tcpci_tcpc_discharge_vbus, -#endif -#ifdef CONFIG_USB_PD_DUAL_ROLE_AUTO_TOGGLE - .drp_toggle = anx7447_tcpc_drp_toggle, -#endif - .get_chip_info = &tcpci_get_chip_info, -#ifdef CONFIG_USB_PD_PPC - .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 - .set_bist_test_mode = &tcpci_set_bist_test_mode, -#ifdef CONFIG_CMD_TCPC_DUMP - .dump_registers = &anx7447_dump_registers, -#endif -}; - -#ifdef CONFIG_USB_PD_TCPM_MUX -const struct usb_mux_driver anx7447_usb_mux_driver = { - .init = anx7447_mux_init, - .set = anx7447_mux_set, - .get = anx7447_mux_get, -}; -#endif /* CONFIG_USB_PD_TCPM_MUX */ - diff --git a/driver/tcpm/anx7447.h b/driver/tcpm/anx7447.h deleted file mode 100644 index 75982e6b91..0000000000 --- a/driver/tcpm/anx7447.h +++ /dev/null @@ -1,156 +0,0 @@ -/* Copyright 2018 The Chromium OS Authors. All rights reserved. - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ - -#include "usb_mux.h" - -/* USB Power delivery port management */ - -#ifndef __CROS_EC_USB_PD_TCPM_ANX7447_H -#define __CROS_EC_USB_PD_TCPM_ANX7447_H - -/* Registers: TCPC address used */ -#define ANX7447_REG_TCPC_SWITCH_0 0xB4 -#define ANX7447_REG_TCPC_SWITCH_1 0xB5 -#define ANX7447_REG_TCPC_AUX_SWITCH 0xB6 - -#define ANX7447_REG_INTR_ALERT_MASK_0 0xC9 - -#define ANX7447_REG_TCPC_CTRL_2 0xCD -#define ANX7447_REG_ENABLE_VBUS_PROTECT 0x20 - -#define ANX7447_REG_ADC_CTRL_1 0xBF -#define ANX7447_REG_ADCFSM_EN 0x20 - -/* Registers: SPI address used */ -#define ANX7447_REG_INTP_SOURCE_0 0x67 - -#define ANX7447_REG_HPD_CTRL_0 0x7E -#define ANX7447_REG_HPD_MODE 0x01 -#define ANX7447_REG_HPD_OUT 0x02 -#define ANX7447_REG_HPD_IRQ0 0x04 -#define ANX7447_REG_HPD_PLUG 0x08 -#define ANX7447_REG_HPD_UNPLUG 0x10 - -#define ANX7447_REG_HPD_DEGLITCH_H 0x80 -#define ANX7447_REG_HPD_DETECT 0x80 -#define ANX7447_REG_HPD_OEN 0x40 - -#define ANX7447_REG_PAD_INTP_CTRL 0x85 - -#define ANX7447_REG_INTP_MASK_0 0x86 - -#define ANX7447_REG_INTP_CTRL_0 0x9E - -#define ANX7447_REG_ANALOG_CTRL_8 0xA8 -#define ANX7447_REG_VCONN_OCP_MASK 0x0C -#define ANX7447_REG_VCONN_OCP_240mA 0x00 -#define ANX7447_REG_VCONN_OCP_310mA 0x04 -#define ANX7447_REG_VCONN_OCP_370mA 0x08 -#define ANX7447_REG_VCONN_OCP_440mA 0x0C - -#define ANX7447_REG_ANALOG_CTRL_10 0xAA -#define ANX7447_REG_CABLE_DET_DIG 0x40 - -#define ANX7447_REG_R_VCONN_PWR_PRT_INRUSH_TIME_MASK 0x38 -#define ANX7447_REG_R_VCONN_PWR_PRT_INRUSH_TIME_19US 0x00 -#define ANX7447_REG_R_VCONN_PWR_PRT_INRUSH_TIME_38US 0x08 -#define ANX7447_REG_R_VCONN_PWR_PRT_INRUSH_TIME_76US 0x10 -#define ANX7447_REG_R_VCONN_PWR_PRT_INRUSH_TIME_152US 0x18 -#define ANX7447_REG_R_VCONN_PWR_PRT_INRUSH_TIME_303US 0x20 -#define ANX7447_REG_R_VCONN_PWR_PRT_INRUSH_TIME_607US 0x28 -#define ANX7447_REG_R_VCONN_PWR_PRT_INRUSH_TIME_1210US 0x30 -#define ANX7447_REG_R_VCONN_PWR_PRT_INRUSH_TIME_2430US 0x38 - -#define ANX7447_REG_ANALOG_CTRL_9 0xA9 -#define ANX7447_REG_SAFE_MODE 0x80 -#define ANX7447_REG_R_AUX_RES_PULL_SRC 0x20 - -/* - * This section of defines are only required to support the config option - * CONFIG_USB_PD_TCPM_ANX7447_OCM_ERASE_COMMAND. - */ -/* SPI registers used for OCM flash operations */ -#define ANX7447_DELAY_IN_US (20*1000) - -#define ANX7447_REG_R_RAM_CTRL 0x05 -#define ANX7447_REG_R_FLASH_RW_CTRL 0x30 -#define ANX7447_REG_R_FLASH_STATUS_0 0x31 -#define ANX7447_REG_FLASH_INST_TYPE 0x33 -#define ANX7447_REG_FLASH_ERASE_TYPE 0x34 -#define ANX7447_REG_OCM_CTRL_0 0x6E -#define ANX7447_REG_ADDR_GPIO_CTRL_0 0x88 -#define ANX7447_REG_OCM_VERSION 0xB4 - -/* R_RAM_CTRL bit definitions */ -#define ANX7447_R_RAM_CTRL_FLASH_DONE (1<<7) - -/* R_FLASH_RW_CTRL bit definitions */ -#define ANX7447_R_FLASH_RW_CTRL_GENERAL_INST_EN (1<<6) -#define ANX7447_R_FLASH_RW_CTRL_FLASH_ERASE_EN (1<<5) -#define ANX7447_R_FLASH_RW_CTRL_WRITE_STATUS_EN (1<<2) -#define ANX7447_R_FLASH_RW_CTRL_FLASH_READ (1<<1) -#define ANX7447_R_FLASH_RW_CTRL_FLASH_WRITE (1<<0) - -/* R_FLASH_STATUS_0 definitions */ -#define ANX7447_FLASH_STATUS_SPI_STATUS_0 0x43 - -/* FLASH_ERASE_TYPE bit definitions */ -#define ANX7447_FLASH_INST_TYPE_WRITEENABLE 0x06 -#define ANX7447_FLASH_ERASE_TYPE_CHIPERASE 0x60 - -/* OCM_CTRL_0 bit definitions */ -#define ANX7447_OCM_CTRL_OCM_RESET (1<<6) - -/* ADDR_GPIO_CTRL_0 bit definitions */ -#define ANX7447_ADDR_GPIO_CTRL_0_SPI_WP (1<<7) -#define ANX7447_ADDR_GPIO_CTRL_0_SPI_CLK_ENABLE (1<<6) -/* End of defines used for CONFIG_USB_PD_TCPM_ANX7447_OCM_ERASE_COMMAND */ - -struct anx7447_i2c_addr { - uint16_t tcpc_addr_flags; - uint16_t spi_addr_flags; -}; - -#define AN7447_TCPC0_I2C_ADDR_FLAGS 0x2C -#define AN7447_TCPC1_I2C_ADDR_FLAGS 0x2B -#define AN7447_TCPC2_I2C_ADDR_FLAGS 0x2A -#define AN7447_TCPC3_I2C_ADDR_FLAGS 0x29 - -#define AN7447_SPI0_I2C_ADDR_FLAGS 0x3F -#define AN7447_SPI1_I2C_ADDR_FLAGS 0x37 -#define AN7447_SPI2_I2C_ADDR_FLAGS 0x32 -#define AN7447_SPI3_I2C_ADDR_FLAGS 0x31 - -/* - * Time TEST_R must be held high for a reset - */ -#define ANX74XX_RESET_HOLD_MS 1 -/* - * Time after TEST_R reset to wait for eFuse loading - */ -#define ANX74XX_RESET_FINISH_MS 2 - -int anx7447_set_power_supply_ready(int port); -int anx7447_power_supply_reset(int port); -int anx7447_board_charging_enable(int port, int enable); - -void anx7447_hpd_mode_en(int port); -void anx7447_hpd_output_en(int port); - -extern const struct tcpm_drv anx7447_tcpm_drv; -extern const struct usb_mux_driver anx7447_usb_mux_driver; -void anx7447_tcpc_clear_hpd_status(int port); -void anx7447_tcpc_update_hpd_status(const struct usb_mux *me, - mux_state_t mux_state); - -/** - * Erase OCM flash if it's not empty - * - * @param port: USB-C port number - * @return: EC_SUCCESS or EC_ERROR_* - */ -int anx7447_flash_erase(int port); - -#endif /* __CROS_EC_USB_PD_TCPM_ANX7688_H */ diff --git a/driver/tcpm/anx74xx.c b/driver/tcpm/anx74xx.c deleted file mode 100644 index 567005920e..0000000000 --- a/driver/tcpm/anx74xx.c +++ /dev/null @@ -1,1210 +0,0 @@ -/* Copyright 2016 The Chromium OS Authors. All rights reserved. - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - * - * Author : Analogix Semiconductor. - */ - -/* Type-C port manager for Analogix's anx74xx chips */ - -#include "console.h" -#include "anx74xx.h" -#include "task.h" -#include "tcpm/tcpci.h" -#include "tcpm/tcpm.h" -#include "timer.h" -#include "usb_charge.h" -#include "usb_mux.h" -#include "usb_pd.h" -#include "usb_pd_tcpc.h" -#include "usb_pd_tcpm.h" -#include "util.h" - -#if !defined(CONFIG_USB_PD_TCPM_TCPCI) -#error "ANX74xx is using part of standard TCPCI control" -#error "Please upgrade your board configuration" -#endif - -#if defined(CONFIG_USB_PD_REV30) -#error "ANX74xx chips were developed before PD 3.0 and aren't PD 3.0 compliant" -#error "Please undefine PD 3.0. See b/159253723 for details" -#endif - -#define CPRINTF(format, args...) cprintf(CC_USBPD, format, ## args) -#define CPRINTS(format, args...) cprints(CC_USBPD, format, ## args) - -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; \ - rv = tcpc_read(port, ANX74XX_REG_RECVD_MSG_INT, ®); \ - if (!rv) \ - tcpc_write(port, ANX74XX_REG_RECVD_MSG_INT, \ - reg | 0x01); \ - } while (0) - -static struct anx_state anx[CONFIG_USB_PD_PORT_MAX_COUNT]; - -#ifdef CONFIG_USB_PD_DECODE_SOP -/* Save the message address */ -static int msg_sop[CONFIG_USB_PD_PORT_MAX_COUNT]; -#endif - -static int anx74xx_tcpm_init(int port); - -static void anx74xx_tcpm_set_auto_good_crc(int port, int enable) -{ - int reply_sop_en = 0; - - if (enable) { - reply_sop_en = ANX74XX_REG_REPLY_SOP_EN; -#ifdef CONFIG_USB_PD_DECODE_SOP - /* - * Only the VCONN Source is allowed to communicate - * with the Cable Plugs. - */ - if (anx[port].vconn_en) { - reply_sop_en |= ANX74XX_REG_REPLY_SOP_1_EN | - ANX74XX_REG_REPLY_SOP_2_EN; - } -#endif - } - - tcpc_write(port, ANX74XX_REG_TX_AUTO_GOODCRC_2, reply_sop_en); -} - -static void anx74xx_update_cable_det(int port, int mode) -{ -#ifdef CONFIG_USB_PD_TCPC_LOW_POWER - int reg; - - if (anx[port].prev_mode == mode) - return; - - /* Update power mode */ - anx[port].prev_mode = mode; - - /* Get ANALOG_CTRL_0 for cable det bit */ - if (tcpc_read(port, ANX74XX_REG_ANALOG_CTRL_0, ®)) - return; - - if (mode == ANX74XX_STANDBY_MODE) { - int cc_reg; - - /* - * The ANX4329 enters standby mode by setting PWR_EN signal - * low. In addition, RESET_L must be set low to keep the ANX3429 - * in standby mode. - * - * Clearing bit 7 of ANX74XX_REG_ANALOG_CTRL_0 will cause the - * ANX3429 to clear the cable_det signal that goes from the - * ANX3429 to the EC. If this bit is cleared when a cable is - * attached then cable_det will go high once standby is entered. - * - * In some cases, such as when the chipset power state is - * S3/S5/G3 and a sink only adapter is connected to the port, - * this behavior is undesirable. The constant toggling between - * standby and normal mode means that effectively the ANX3429 is - * not in standby mode only consumes ~1 mW less than just - * remaining in normal mode. However when an E mark cable is - * connected, clearing bit 7 is required so that while the E - * mark cable configuration happens, the USB PD state machine - * will continue to wake up until the USB PD attach event can be - * regtistered. - * - * Therefore, the decision to clear bit 7 is based on the - * current CC status of the port. If the CC status is open for - * both CC lines OR if either CC line is showing Ra, then clear - * bit 7. Not clearing bit 7 has no impact for normal cables and - * prevents the constant toggle of standby<->normal when an - * adapter is connected that isn't allowed to attach. Clearing - * bit 7 when CC status reads Ra for either CC line allows the - * USB PD state machine to be woken until the attach event can - * happen. Note that in the case an E mark cable is connected - * and can't attach (i.e. sink only port <- Emark cable -> sink - * only adapter), then the ANX3429 will toggle indefinitely, - * until either the cable is removed, or the port drp status - * changes so the attach event can occur. - * . - */ - - /* Read CC status to see if cable_det bit should be cleared */ - if (tcpc_read(port, ANX74XX_REG_CC_STATUS, &cc_reg)) - return; - /* If open or either CC line is Ra, then clear cable_det */ - if (!cc_reg || (cc_reg & ANX74XX_CC_RA_MASK && - !(cc_reg & ANX74XX_CC_RD_MASK))) - reg &= ~ANX74XX_REG_R_PIN_CABLE_DET; - } else { - reg |= ANX74XX_REG_R_PIN_CABLE_DET; - } - - tcpc_write(port, ANX74XX_REG_ANALOG_CTRL_0, reg); -#endif -} - -static void anx74xx_set_power_mode(int port, int mode) -{ - /* - * Update PWR_EN and RESET_N signals to the correct level. High for - * Normal mode and low for Standby mode. When transitioning from standby - * to normal mode, must set the PWR_EN and RESET_N before attempting to - * modify cable_det bit of analog_ctrl_0. If going from Normal to - * Standby, updating analog_ctrl_0 must happen before setting PWR_EN and - * RESET_N low. - */ - if (mode == ANX74XX_NORMAL_MODE) { - /* Take chip out of standby mode */ - board_set_tcpc_power_mode(port, mode); - /* Update the cable det signal */ - anx74xx_update_cable_det(port, mode); - } else { - /* 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. - */ - msleep(1); - /* Put chip into standby mode */ - board_set_tcpc_power_mode(port, mode); - } -} - -#if defined(CONFIG_USB_PD_DUAL_ROLE_AUTO_TOGGLE) && \ - defined(CONFIG_USB_PD_TCPC_LOW_POWER) - -static int anx74xx_tcpc_drp_toggle(int port) -{ - /* - * The ANX3429 always auto-toggles when in low power mode. Since this is - * not configurable, there is nothing to do here. DRP auto-toggle will - * happen once low power mode is set via anx74xx_enter_low_power_mode(). - * Note: this means the ANX3429 auto-toggles in PD_DRP_FORCE_SINK mode, - * which is undesirable (b/72007056). - */ - return EC_SUCCESS; -} - -static int anx74xx_enter_low_power_mode(int port) -{ - anx74xx_set_power_mode(port, ANX74XX_STANDBY_MODE); - return EC_SUCCESS; -} - -#endif - -void anx74xx_tcpc_set_vbus(int port, int enable) -{ - int reg; - - tcpc_read(port, ANX74XX_REG_GPIO_CTRL_4_5, ®); - if (enable) - reg |= ANX74XX_REG_SET_VBUS; - else - reg &= ~ANX74XX_REG_SET_VBUS; - tcpc_write(port, ANX74XX_REG_GPIO_CTRL_4_5, reg); -} - -#ifdef CONFIG_USB_PD_DISCHARGE_TCPC -static void anx74xx_tcpc_discharge_vbus(int port, int enable) -{ - int reg; - - tcpc_read(port, ANX74XX_REG_HPD_CTRL_0, ®); - if (enable) - reg |= ANX74XX_REG_DISCHARGE_CTRL; - else - reg &= ~ANX74XX_REG_DISCHARGE_CTRL; - tcpc_write(port, ANX74XX_REG_HPD_CTRL_0, reg); -} -#endif - -/* - * timestamp of the next possible toggle to ensure the 2-ms spacing - * between IRQ_HPD. - */ -static uint64_t hpd_deadline[CONFIG_USB_PD_PORT_MAX_COUNT]; - -void anx74xx_tcpc_update_hpd_status(const struct usb_mux *me, - mux_state_t mux_state) -{ - int reg; - int port = me->usb_port; - int hpd_lvl = (mux_state & USB_PD_MUX_HPD_LVL) ? 1 : 0; - int hpd_irq = (mux_state & USB_PD_MUX_HPD_IRQ) ? 1 : 0; - - mux_read(me, ANX74XX_REG_HPD_CTRL_0, ®); - if (hpd_lvl) - reg |= ANX74XX_REG_HPD_OUT_DATA; - else - reg &= ~ANX74XX_REG_HPD_OUT_DATA; - mux_write(me, ANX74XX_REG_HPD_CTRL_0, reg); - - if (hpd_irq) { - uint64_t now = get_time().val; - /* wait for the minimum spacing between IRQ_HPD if needed */ - if (now < hpd_deadline[port]) - usleep(hpd_deadline[port] - now); - - mux_read(me, ANX74XX_REG_HPD_CTRL_0, ®); - reg &= ~ANX74XX_REG_HPD_OUT_DATA; - mux_write(me, ANX74XX_REG_HPD_CTRL_0, reg); - usleep(HPD_DSTREAM_DEBOUNCE_IRQ); - reg |= ANX74XX_REG_HPD_OUT_DATA; - mux_write(me, ANX74XX_REG_HPD_CTRL_0, reg); - } - /* enforce 2-ms delay between HPD pulses */ - hpd_deadline[port] = get_time().val + HPD_USTREAM_DEBOUNCE_LVL; -} - -void anx74xx_tcpc_clear_hpd_status(int port) -{ - int reg; - - tcpc_read(port, ANX74XX_REG_HPD_CTRL_0, ®); - reg &= 0xcf; - tcpc_write(port, ANX74XX_REG_HPD_CTRL_0, reg); -} - -#ifdef CONFIG_USB_PD_TCPM_MUX -static int anx74xx_tcpm_mux_init(const struct usb_mux *me) -{ - /* Nothing to do here, ANX initializes its muxes - * as (USB_PD_MUX_USB_ENABLED | USB_PD_MUX_DP_ENABLED) - */ - anx[me->usb_port].mux_state = USB_PD_MUX_USB_ENABLED | - USB_PD_MUX_DP_ENABLED; - - return EC_SUCCESS; -} - -static int anx74xx_tcpm_mux_enter_safe_mode(int port) -{ - int reg; - const struct usb_mux *me = &usb_muxes[port]; - - if (mux_read(me, ANX74XX_REG_ANALOG_CTRL_2, ®)) - return EC_ERROR_UNKNOWN; - if (mux_write(me, ANX74XX_REG_ANALOG_CTRL_2, reg | - ANX74XX_REG_MODE_TRANS)) - return EC_ERROR_UNKNOWN; - - - return EC_SUCCESS; -} - -static int anx74xx_tcpm_mux_exit_safe_mode(int port) -{ - int reg; - const struct usb_mux *me = &usb_muxes[port]; - - if (mux_read(me, ANX74XX_REG_ANALOG_CTRL_2, ®)) - return EC_ERROR_UNKNOWN; - if (mux_write(me, ANX74XX_REG_ANALOG_CTRL_2, reg & - ~ANX74XX_REG_MODE_TRANS)) - return EC_ERROR_UNKNOWN; - - - return EC_SUCCESS; -} - -static int anx74xx_tcpm_mux_exit(int port) -{ - int reg; - const struct usb_mux *me = &usb_muxes[port]; - - /* - * Safe mode must be entered before any changes are made to the mux - * settings used to enable ALT_DP mode. This function is called either - * from anx74xx_tcpm_mux_set when USB_PD_MUX_NONE is selected as the - * new mux state, or when both cc lines are determined to be - * TYPEC_CC_VOLT_OPEN. Therefore, safe mode must be entered and exited - * here so that both entry paths are handled. - */ - if (anx74xx_tcpm_mux_enter_safe_mode(port)) - return EC_ERROR_UNKNOWN; - - /* Disconnect aux from sbu */ - if (mux_read(me, ANX74XX_REG_ANALOG_CTRL_2, ®)) - return EC_ERROR_UNKNOWN; - if (mux_write(me, ANX74XX_REG_ANALOG_CTRL_2, reg & 0xf)) - return EC_ERROR_UNKNOWN; - - /* Clear Bit[7:0] R_SWITCH */ - if (mux_write(me, ANX74XX_REG_ANALOG_CTRL_1, 0x0)) - return EC_ERROR_UNKNOWN; - /* Clear Bit[7:4] R_SWITCH_H */ - if (mux_read(me, ANX74XX_REG_ANALOG_CTRL_5, ®)) - return EC_ERROR_UNKNOWN; - if (mux_write(me, ANX74XX_REG_ANALOG_CTRL_5, reg & 0x0f)) - return EC_ERROR_UNKNOWN; - - /* Exit safe mode */ - if (anx74xx_tcpm_mux_exit_safe_mode(port)) - return EC_ERROR_UNKNOWN; - - return EC_SUCCESS; -} - - -static int anx74xx_mux_aux_to_sbu(int port, int polarity, int enabled) -{ - int reg; - const int aux_mask = ANX74XX_REG_AUX_SWAP_SET_CC2 | - ANX74XX_REG_AUX_SWAP_SET_CC1; - const struct usb_mux *me = &usb_muxes[port]; - - /* - * Get the current value of analog_ctrl_2 register. Note, that safe mode - * is enabled and exited by the calling function, so only have to worry - * about setting the correct value for the upper 4 bits of analog_ctrl_2 - * here. - */ - if (mux_read(me, ANX74XX_REG_ANALOG_CTRL_2, ®)) - return EC_ERROR_UNKNOWN; - - /* Assume aux_p/n lines are not connected */ - reg &= ~aux_mask; - - if (enabled) { - /* If enabled, connect aux to sbu based on desired polarity */ - if (polarity) - reg |= ANX74XX_REG_AUX_SWAP_SET_CC2; - else - reg |= ANX74XX_REG_AUX_SWAP_SET_CC1; - } - /* Write new aux <-> sbu settings */ - if (mux_write(me, ANX74XX_REG_ANALOG_CTRL_2, reg)) - return EC_ERROR_UNKNOWN; - - return EC_SUCCESS; -} - -static int anx74xx_tcpm_mux_set(const struct usb_mux *me, - mux_state_t mux_state, - bool *ack_required) -{ - int ctrl5; - int ctrl1 = 0; - int rv; - int port = me->usb_port; - - /* This driver does not use host command ACKs */ - *ack_required = false; - - if (!(mux_state & ~USB_PD_MUX_POLARITY_INVERTED)) { - anx[port].mux_state = mux_state; - return anx74xx_tcpm_mux_exit(port); - } - - rv = mux_read(me, ANX74XX_REG_ANALOG_CTRL_5, &ctrl5); - if (rv) - return EC_ERROR_UNKNOWN; - ctrl5 &= 0x0f; - - if (mux_state & USB_PD_MUX_USB_ENABLED) { - /* Connect USB SS switches */ - if (mux_state & USB_PD_MUX_POLARITY_INVERTED) { - ctrl1 = ANX74XX_REG_MUX_SSRX_RX2; - ctrl5 |= ANX74XX_REG_MUX_SSTX_TX2; - } else { - ctrl1 = ANX74XX_REG_MUX_SSRX_RX1; - ctrl5 |= ANX74XX_REG_MUX_SSTX_TX1; - } - if (mux_state & USB_PD_MUX_DP_ENABLED) { - /* Set pin assignment D */ - if (mux_state & USB_PD_MUX_POLARITY_INVERTED) - ctrl1 |= (ANX74XX_REG_MUX_ML0_RX1 | - ANX74XX_REG_MUX_ML1_TX1); - else - ctrl1 |= (ANX74XX_REG_MUX_ML0_RX2 | - ANX74XX_REG_MUX_ML1_TX2); - } - /* Keep ML0/ML1 unconnected if DP is not enabled */ - } else if (mux_state & USB_PD_MUX_DP_ENABLED) { - /* Set pin assignment C */ - if (mux_state & USB_PD_MUX_POLARITY_INVERTED) { - ctrl1 = (ANX74XX_REG_MUX_ML0_RX1 | - ANX74XX_REG_MUX_ML1_TX1 | - ANX74XX_REG_MUX_ML3_RX2); - ctrl5 |= ANX74XX_REG_MUX_ML2_TX2; - } else { - ctrl1 = (ANX74XX_REG_MUX_ML0_RX2 | - ANX74XX_REG_MUX_ML1_TX2 | - ANX74XX_REG_MUX_ML3_RX1); - ctrl5 |= ANX74XX_REG_MUX_ML2_TX1; - } - } else if (!mux_state) { - return anx74xx_tcpm_mux_exit(port); - } else { - return EC_ERROR_UNIMPLEMENTED; - } - - /* - * Safe mode must be entererd prior to any changes to the mux related to - * ALT_DP mode. Therefore, first enable safe mode prior to updating the - * values for analog_ctrl_1, analog_ctrl_5, and analog_ctrl_2. - */ - if (anx74xx_tcpm_mux_enter_safe_mode(port)) - return EC_ERROR_UNKNOWN; - - /* Write updated pin assignment */ - rv = mux_write(me, ANX74XX_REG_ANALOG_CTRL_1, ctrl1); - /* Write Rswitch config bits */ - rv |= mux_write(me, ANX74XX_REG_ANALOG_CTRL_5, ctrl5); - if (rv) - return EC_ERROR_UNKNOWN; - - /* Configure DP aux to sbu settings */ - if (anx74xx_mux_aux_to_sbu(port, - mux_state & USB_PD_MUX_POLARITY_INVERTED, - mux_state & USB_PD_MUX_DP_ENABLED)) - return EC_ERROR_UNKNOWN; - - /* Exit safe mode */ - if (anx74xx_tcpm_mux_exit_safe_mode(port)) - return EC_ERROR_UNKNOWN; - - anx[port].mux_state = mux_state; - - return EC_SUCCESS; -} - -/* current mux state */ -static int anx74xx_tcpm_mux_get(const struct usb_mux *me, - mux_state_t *mux_state) -{ - *mux_state = anx[me->usb_port].mux_state; - - return EC_SUCCESS; -} - -const struct usb_mux_driver anx74xx_tcpm_usb_mux_driver = { - .init = &anx74xx_tcpm_mux_init, - .set = &anx74xx_tcpm_mux_set, - .get = &anx74xx_tcpm_mux_get, -}; -#endif /* CONFIG_USB_PD_TCPM_MUX */ - -static int anx74xx_init_analog(int port) -{ - int reg, rv = EC_SUCCESS; - - /* Analog settings for chip */ - rv |= tcpc_write(port, ANX74XX_REG_HPD_CONTROL, - ANX74XX_REG_HPD_OP_MODE); - rv |= tcpc_write(port, ANX74XX_REG_HPD_CTRL_0, - ANX74XX_REG_HPD_DEFAULT); - if (rv) - return rv; - rv = tcpc_read(port, ANX74XX_REG_GPIO_CTRL_4_5, ®); - if (rv) - return rv; - reg &= ANX74XX_REG_VBUS_GPIO_MODE; - reg |= ANX74XX_REG_VBUS_OP_ENABLE; - rv = tcpc_write(port, ANX74XX_REG_GPIO_CTRL_4_5, reg); - if (rv) - return rv; - rv = tcpc_read(port, ANX74XX_REG_CC_SOFTWARE_CTRL, ®); - if (rv) - return rv; - reg |= ANX74XX_REG_TX_MODE_ENABLE; - rv = tcpc_write(port, ANX74XX_REG_CC_SOFTWARE_CTRL, reg); - - return rv; -} - -static int anx74xx_send_message(int port, uint16_t header, - const uint32_t *payload, - int type, - uint8_t len) -{ - int reg, rv = EC_SUCCESS; - uint8_t *buf = NULL; - int num_retry = 0, i = 0; - /* If sending Soft_reset, clear received message */ - /* Soft Reset Message type = 1101 and Number of Data Object = 0 */ - if ((header & 0x700f) == 0x000d) { - /* - * When sending soft reset, - * the Rx buffer of ANX3429 shall be clear - */ - rv = tcpc_read(port, ANX74XX_REG_CTRL_FW, ®); - rv |= tcpc_write( - port, ANX74XX_REG_CTRL_FW, reg | CLEAR_RX_BUFFER); - if (rv) - return EC_ERROR_UNKNOWN; - tcpc_write(port, ANX74XX_REG_RECVD_MSG_INT, 0xFF); - } - /* Inform chip about message length and TX type - * type->bit-0..2, len->bit-3..7 - */ - reg = (len << 3) & 0xf8; - reg |= type & 0x07; - rv |= tcpc_write(port, ANX74XX_REG_TX_CTRL_2, reg); - if (rv) - return EC_ERROR_UNKNOWN; - - /* Enqueue Header */ - rv = tcpc_write(port, ANX74XX_REG_TX_HEADER_L, (header & 0xff)); - if (rv) - return EC_ERROR_UNKNOWN; - rv = tcpc_write(port, ANX74XX_REG_TX_HEADER_H, (header >> 8)); - if (rv) - return EC_ERROR_UNKNOWN; - /* Enqueue payload */ - if (len > 2) { - len -= 2; - buf = (uint8_t *)payload; - while (1) { - if (i < 18) - rv = tcpc_write(port, - ANX74XX_REG_TX_START_ADDR_0 + i, - *buf); - else - rv = tcpc_write(port, - ANX74XX_REG_TX_START_ADDR_1 + i - 18, - *buf); - if (rv) { - num_retry++; - } else { - buf++; - len--; - num_retry = 0; - i++; - } - if (len == 0 || num_retry >= 3) - break; - } - /* If enqueue failed, do not request anx to transmit - * messages, FIFO will get cleared in next call - * before enqueue. - * num_retry = 0, refer to success - */ - if (num_retry) - return EC_ERROR_UNKNOWN; - } - /* Request a data transmission - * This bit will be cleared by ANX after TX success - */ - rv = tcpc_read(port, ANX74XX_REG_CTRL_COMMAND, ®); - if (rv) - return EC_ERROR_UNKNOWN; - reg |= ANX74XX_REG_TX_SEND_DATA_REQ; - rv |= tcpc_write(port, ANX74XX_REG_CTRL_COMMAND, reg); - - return rv; -} - -static int anx74xx_read_pd_obj(int port, - uint8_t *buf, - int plen) -{ - int rv = EC_SUCCESS, i; - int reg, addr = ANX74XX_REG_PD_RX_DATA_OBJ; - - /* Read PD data objects from ANX */ - for (i = 0; i < plen ; i++) { - /* Register sequence changes for last two bytes, if - * plen is greater than 26 - */ - if (i == 26) - addr = ANX74XX_REG_PD_RX_DATA_OBJ_M; - rv = tcpc_read(port, addr + i, ®); - if (rv) - break; - buf[i] = reg; - } - clear_recvd_msg_int(port); - return rv; -} - -static int anx74xx_check_cc_type(int cc_reg) -{ - int cc; - - switch (cc_reg & ANX74XX_REG_CC_STATUS_MASK) { - case BIT_VALUE_OF_SRC_CC_RD: - cc = TYPEC_CC_VOLT_RD; - break; - - case BIT_VALUE_OF_SRC_CC_RA: - cc = TYPEC_CC_VOLT_RA; - break; - - case BIT_VALUE_OF_SNK_CC_DEFAULT: - cc = TYPEC_CC_VOLT_RP_DEF; - break; - - case BIT_VALUE_OF_SNK_CC_1_P_5: - cc = TYPEC_CC_VOLT_RP_1_5; - break; - - case BIT_VALUE_OF_SNK_CC_3_P_0: - cc = TYPEC_CC_VOLT_RP_3_0; - break; - - default: - /* If no bits are set, then nothing is attached */ - cc = TYPEC_CC_VOLT_OPEN; - } - - return cc; -} - -static int anx74xx_tcpm_get_cc(int port, enum tcpc_cc_voltage_status *cc1, - enum tcpc_cc_voltage_status *cc2) -{ - int rv = EC_SUCCESS; - int reg = 0; - - /* Read tcpc cc status register */ - rv |= tcpc_read(port, ANX74XX_REG_CC_STATUS, ®); - /* Check for cc1 type */ - *cc1 = anx74xx_check_cc_type(reg); - /* - * Check for cc2 type (note cc2 bits are upper 4 of cc status - * register. - */ - *cc2 = anx74xx_check_cc_type(reg >> 4); - - /* clear HPD status*/ - if (!(*cc1) && !(*cc2)) { - anx74xx_tcpc_clear_hpd_status(port); -#ifdef CONFIG_USB_PD_TCPM_MUX - anx74xx_tcpm_mux_exit(port); -#endif - } - - return EC_SUCCESS; -} - -static int anx74xx_rp_control(int port, int rp) -{ - int reg; - int rv; - - rv = tcpc_read(port, ANX74XX_REG_ANALOG_CTRL_6, ®); - if (rv) - return EC_ERROR_UNKNOWN; - - /* clear Bit[0,1] R_RP to default Rp's value */ - reg &= ~0x03; - - switch (rp) { - case TYPEC_RP_1A5: - /* Set Rp strength to 12K for presenting 1.5A */ - reg |= ANX74XX_REG_CC_PULL_RP_12K; - break; - case TYPEC_RP_3A0: - /* Set Rp strength to 4K for presenting 3A */ - reg |= ANX74XX_REG_CC_PULL_RP_4K; - break; - case TYPEC_RP_USB: - default: - /* default: Set Rp strength to 36K */ - break; - } - - return tcpc_write(port, ANX74XX_REG_ANALOG_CTRL_6, reg); -} - -static int anx74xx_tcpm_select_rp_value(int port, int rp) -{ - /* Keep track of current RP value */ - tcpci_set_cached_rp(port, rp); - - /* For ANX3429 cannot get cc correctly when Rp != USB_Default */ - return EC_SUCCESS; -} - - -static int anx74xx_cc_software_ctrl(int port, int enable) -{ - int rv; - int reg; - - rv = tcpc_read(port, ANX74XX_REG_CC_SOFTWARE_CTRL, ®); - if (rv) - return EC_ERROR_UNKNOWN; - - if (enable) - reg |= ANX74XX_REG_CC_SW_CTRL_ENABLE; - else - reg &= ~ANX74XX_REG_CC_SW_CTRL_ENABLE; - - rv |= tcpc_write(port, ANX74XX_REG_CC_SOFTWARE_CTRL, reg); - return rv; -} - -static int anx74xx_tcpm_set_cc(int port, int pull) -{ - int rv = EC_SUCCESS; - int reg; - - /* Enable CC software Control */ - rv = anx74xx_cc_software_ctrl(port, 1); - if (rv) - return EC_ERROR_UNKNOWN; - - switch (pull) { - case TYPEC_CC_RP: - /* Enable Rp */ - rv |= tcpc_read(port, ANX74XX_REG_ANALOG_STATUS, ®); - if (rv) - return EC_ERROR_UNKNOWN; - reg |= ANX74XX_REG_CC_PULL_RP; - rv |= tcpc_write(port, ANX74XX_REG_ANALOG_STATUS, reg); - break; - case TYPEC_CC_RD: - /* Enable Rd */ - rv |= tcpc_read(port, ANX74XX_REG_ANALOG_STATUS, ®); - if (rv) - return EC_ERROR_UNKNOWN; - reg &= ANX74XX_REG_CC_PULL_RD; - rv |= tcpc_write(port, ANX74XX_REG_ANALOG_STATUS, reg); - break; - default: - rv = EC_ERROR_UNKNOWN; - break; - } - - return rv; -} - -static int anx74xx_tcpm_set_polarity(int port, enum tcpc_cc_polarity polarity) -{ - int reg, mux_state, rv = EC_SUCCESS; - const struct usb_mux *me = &usb_muxes[port]; - bool unused; - - rv |= tcpc_read(port, ANX74XX_REG_CC_SOFTWARE_CTRL, ®); - if (polarity_rm_dts(polarity)) /* Inform ANX to use CC2 */ - reg &= ~ANX74XX_REG_SELECT_CC1; - else /* Inform ANX to use CC1 */ - reg |= ANX74XX_REG_SELECT_CC1; - rv |= tcpc_write(port, ANX74XX_REG_CC_SOFTWARE_CTRL, reg); - - anx[port].polarity = polarity; - - /* Update mux polarity */ -#ifdef CONFIG_USB_PD_TCPM_MUX - mux_state = anx[port].mux_state & ~USB_PD_MUX_POLARITY_INVERTED; - if (polarity_rm_dts(polarity)) - mux_state |= USB_PD_MUX_POLARITY_INVERTED; - anx74xx_tcpm_mux_set(me, mux_state, &unused); -#endif - return rv; -} - -static int anx74xx_tcpm_set_vconn(int port, int enable) -{ - int reg, rv = EC_SUCCESS; - - /* switch VCONN to Non CC line */ - rv |= tcpc_read(port, ANX74XX_REG_INTP_VCONN_CTRL, ®); - if (rv) - return EC_ERROR_UNKNOWN; - if (enable) { - if (anx[port].polarity) - reg |= ANX74XX_REG_VCONN_1_ENABLE; - else - reg |= ANX74XX_REG_VCONN_2_ENABLE; - } else { - reg &= ANX74XX_REG_VCONN_DISABLE; - } - rv |= tcpc_write(port, ANX74XX_REG_INTP_VCONN_CTRL, reg); - anx[port].vconn_en = enable; - -#ifdef CONFIG_USB_PD_DECODE_SOP - rv |= tcpc_read(port, ANX74XX_REG_TX_AUTO_GOODCRC_2, ®); - if (rv) - return EC_ERROR_UNKNOWN; - - if (reg & ANX74XX_REG_REPLY_SOP_EN) { - if (enable) { - reg |= ANX74XX_REG_REPLY_SOP_1_EN | - ANX74XX_REG_REPLY_SOP_2_EN; - } else { - reg &= ~(ANX74XX_REG_REPLY_SOP_1_EN | - ANX74XX_REG_REPLY_SOP_2_EN); - } - - tcpc_write(port, ANX74XX_REG_TX_AUTO_GOODCRC_2, reg); - } -#endif - return rv; -} - -static int anx74xx_tcpm_set_msg_header(int port, int power_role, int data_role) -{ - return tcpc_write(port, ANX74XX_REG_TX_AUTO_GOODCRC_1, - ANX74XX_REG_AUTO_GOODCRC_SET(!!data_role, !!power_role)); -} - -static int anx74xx_tcpm_set_rx_enable(int port, int enable) -{ - int reg, rv; - - rv = tcpc_read(port, ANX74XX_REG_IRQ_SOURCE_RECV_MSG_MASK, ®); - if (rv) - return rv; - if (enable) { - reg &= ~(ANX74XX_REG_IRQ_CC_MSG_INT); - anx74xx_tcpm_set_auto_good_crc(port, 1); - anx74xx_rp_control(port, tcpci_get_cached_rp(port)); - } else { - /* Disable RX message by masking interrupt */ - reg |= (ANX74XX_REG_IRQ_CC_MSG_INT); - anx74xx_tcpm_set_auto_good_crc(port, 0); - anx74xx_rp_control(port, TYPEC_RP_USB); - } - /*When this function was call, the interrupt status shall be cleared*/ - tcpc_write(port, ANX74XX_REG_IRQ_SOURCE_RECV_MSG, 0); - - return tcpc_write(port, ANX74XX_REG_IRQ_SOURCE_RECV_MSG_MASK, reg); -} - -#ifdef CONFIG_USB_PD_VBUS_DETECT_TCPC -static bool anx74xx_tcpm_check_vbus_level(int port, enum vbus_level level) -{ - int reg = 0; - - tcpc_read(port, ANX74XX_REG_ANALOG_STATUS, ®); - if (level == VBUS_PRESENT) - return ((reg & ANX74XX_REG_VBUS_STATUS) ? 1 : 0); - else - return ((reg & ANX74XX_REG_VBUS_STATUS) ? 0 : 1); -} -#endif - -static int anx74xx_tcpm_get_message_raw(int port, uint32_t *payload, int *head) -{ - int reg; - int len; - - /* Fetch the header */ - if (tcpc_read16(port, ANX74XX_REG_PD_HEADER, ®)) { - clear_recvd_msg_int(port); - return EC_ERROR_UNKNOWN; - } - *head = reg; -#ifdef CONFIG_USB_PD_DECODE_SOP - *head |= PD_HEADER_SOP(msg_sop[port]); -#endif - - len = PD_HEADER_CNT(*head) * 4; - if (!len) { - clear_recvd_msg_int(port); - return EC_SUCCESS; - } - - /* Receive message : assuming payload have enough - * memory allocated - */ - return anx74xx_read_pd_obj(port, (uint8_t *)payload, len); -} - -static int anx74xx_tcpm_transmit(int port, enum tcpci_msg_type type, - uint16_t header, - const uint32_t *data) -{ - uint8_t len = 0; - int ret = 0, reg = 0; - - switch (type) { - /* ANX is aware of type */ - case TCPCI_MSG_SOP: - case TCPCI_MSG_SOP_PRIME: - case TCPCI_MSG_SOP_PRIME_PRIME: - len = PD_HEADER_CNT(header) * 4 + 2; - ret = anx74xx_send_message(port, header, - data, type, len); - break; - case TCPCI_MSG_TX_HARD_RESET: - /* Request HARD RESET */ - tcpc_read(port, ANX74XX_REG_TX_CTRL_1, ®); - reg |= ANX74XX_REG_TX_HARD_RESET_REQ; - ret = tcpc_write(port, ANX74XX_REG_TX_CTRL_1, reg); - /*After Hard Reset, TCPM shall disable goodCRC*/ - anx74xx_tcpm_set_auto_good_crc(port, 0); - break; - case TCPCI_MSG_CABLE_RESET: - /* Request CABLE RESET */ - tcpc_read(port, ANX74XX_REG_TX_CTRL_1, ®); - reg |= ANX74XX_REG_TX_CABLE_RESET_REQ; - ret = tcpc_write(port, ANX74XX_REG_TX_CTRL_1, reg); - break; - case TCPCI_MSG_TX_BIST_MODE_2: - /* Request BIST MODE 2 */ - reg = ANX74XX_REG_TX_BIST_START - | ANX74XX_REG_TX_BIXT_FOREVER | (0x02 << 4); - ret = tcpc_write(port, ANX74XX_REG_TX_BIST_CTRL, reg); - msleep(1); - ret = tcpc_write(port, ANX74XX_REG_TX_BIST_CTRL, - reg | ANX74XX_REG_TX_BIST_ENABLE); - msleep(30); - tcpc_read(port, ANX74XX_REG_TX_BIST_CTRL, ®); - ret = tcpc_write(port, ANX74XX_REG_TX_BIST_CTRL, - reg | ANX74XX_REG_TX_BIST_STOP); - ret = tcpc_write(port, ANX74XX_REG_TX_BIST_CTRL, - reg & (~ANX74XX_REG_TX_BIST_STOP)); - ret = tcpc_write(port, ANX74XX_REG_TX_BIST_CTRL, 0); - break; - default: - return EC_ERROR_UNIMPLEMENTED; - } - - return ret; -} - -/* - * Don't let the TCPC try to pull from the RX buffer forever. We typical only - * have 1 or 2 messages waiting. - */ -#define MAX_ALLOW_FAILED_RX_READS 10 - -void anx74xx_tcpc_alert(int port) -{ - int reg; - int failed_attempts; - - /* Clear soft irq bit */ - tcpc_write(port, ANX74XX_REG_IRQ_EXT_SOURCE_3, - ANX74XX_REG_CLEAR_SOFT_IRQ); - - /* Read main alert register for pending alerts */ - reg = 0; - tcpc_read(port, ANX74XX_REG_IRQ_SOURCE_RECV_MSG, ®); - - /* Prioritize TX completion because PD state machine is waiting */ - if (reg & ANX74XX_REG_IRQ_GOOD_CRC_INT) - pd_transmit_complete(port, TCPC_TX_COMPLETE_SUCCESS); - - if (reg & ANX74XX_REG_IRQ_TX_FAIL_INT) - pd_transmit_complete(port, TCPC_TX_COMPLETE_FAILED); - - /* Pull all RX messages from TCPC into EC memory */ - failed_attempts = 0; - while (reg & ANX74XX_REG_IRQ_CC_MSG_INT) { - if (tcpm_enqueue_message(port)) - ++failed_attempts; - if (tcpc_read(port, ANX74XX_REG_IRQ_SOURCE_RECV_MSG, ®)) - ++failed_attempts; - - /* Ensure we don't loop endlessly */ - if (failed_attempts >= MAX_ALLOW_FAILED_RX_READS) { - CPRINTF("C%d Cannot consume RX buffer after %d failed " - "attempts!", port, failed_attempts); - /* - * The port is in a bad state, we don't want to consume - * all EC resources so suspend the port for a little - * while. - */ - pd_set_suspend(port, 1); - pd_deferred_resume(port); - return; - } - } - - /* Clear all pending alerts */ - tcpc_write(port, ANX74XX_REG_RECVD_MSG_INT, reg); - - if (reg & ANX74XX_REG_IRQ_CC_STATUS_INT) - /* CC status changed, wake task */ - task_set_event(PD_PORT_TO_TASK_ID(port), PD_EVENT_CC); - - /* Read and clear extended alert register 1 */ - reg = 0; - tcpc_read(port, ANX74XX_REG_IRQ_EXT_SOURCE_1, ®); - tcpc_write(port, ANX74XX_REG_IRQ_EXT_SOURCE_1, reg); - -#ifdef CONFIG_USB_PD_DECODE_SOP - if (reg & ANX74XX_REG_EXT_SOP) - msg_sop[port] = TCPCI_MSG_SOP; - else if (reg & ANX74XX_REG_EXT_SOP_PRIME) - msg_sop[port] = TCPCI_MSG_SOP_PRIME; -#endif - - /* Check for Hard Reset done bit */ - if (reg & ANX74XX_REG_ALERT_TX_HARD_RESETOK) - /* ANX hardware clears the request bit */ - pd_transmit_complete(port, TCPC_TX_COMPLETE_SUCCESS); - - /* Read and clear TCPC extended alert register 2 */ - reg = 0; - tcpc_read(port, ANX74XX_REG_IRQ_EXT_SOURCE_2, ®); - tcpc_write(port, ANX74XX_REG_IRQ_EXT_SOURCE_2, reg); - -#ifdef CONFIG_USB_PD_DECODE_SOP - if (reg & ANX74XX_REG_EXT_SOP_PRIME_PRIME) - msg_sop[port] = TCPCI_MSG_SOP_PRIME_PRIME; -#endif - - if (reg & ANX74XX_REG_EXT_HARD_RST) { - /* hard reset received */ - task_set_event(PD_PORT_TO_TASK_ID(port), - PD_EVENT_RX_HARD_RESET); - } -} - -static int anx74xx_tcpm_init(int port) -{ - int rv = 0, reg; - - memset(&anx[port], 0, sizeof(struct anx_state)); - /* Bring chip in normal mode to work */ - anx74xx_set_power_mode(port, ANX74XX_NORMAL_MODE); - - /* Initialize analog section of ANX */ - rv |= anx74xx_init_analog(port); - - /* disable all interrupts */ - rv |= tcpc_write(port, ANX74XX_REG_IRQ_EXT_MASK_1, - ANX74XX_REG_CLEAR_SET_BITS); - - /* Initialize interrupt open-drain */ - rv |= tcpc_read(port, ANX74XX_REG_INTP_VCONN_CTRL, ®); - if (tcpc_config[port].flags & TCPC_FLAGS_ALERT_OD) - reg |= ANX74XX_REG_R_INTERRUPT_OPEN_DRAIN; - else - reg &= ~ANX74XX_REG_R_INTERRUPT_OPEN_DRAIN; - rv |= tcpc_write(port, ANX74XX_REG_INTP_VCONN_CTRL, reg); - - /* Initialize interrupt polarity */ - reg = tcpc_config[port].flags & TCPC_FLAGS_ALERT_ACTIVE_HIGH ? - ANX74XX_REG_IRQ_POL_HIGH : ANX74XX_REG_IRQ_POL_LOW; - rv |= tcpc_write(port, ANX74XX_REG_IRQ_STATUS, reg); - - /* unmask interrupts */ - rv |= tcpc_read(port, ANX74XX_REG_IRQ_EXT_MASK_1, ®); - reg &= (~ANX74XX_REG_ALERT_TX_MSG_ERROR); - reg &= (~ANX74XX_REG_ALERT_TX_CABLE_RESETOK); - reg &= (~ANX74XX_REG_ALERT_TX_HARD_RESETOK); - rv |= tcpc_write(port, ANX74XX_REG_IRQ_EXT_MASK_1, reg); - - rv |= tcpc_read(port, ANX74XX_REG_IRQ_EXT_MASK_2, ®); - reg &= (~ANX74XX_REG_EXT_HARD_RST); - rv |= tcpc_write(port, ANX74XX_REG_IRQ_EXT_MASK_2, reg); - - /* HPD pin output enable*/ - rv |= tcpc_write(port, ANX74XX_REG_HPD_CTRL_0, ANX74XX_REG_HPD_DEFAULT); - - if (rv) - return EC_ERROR_UNKNOWN; - - /* Set AVDD10_BMC to 1.08 */ - rv |= tcpc_read(port, ANX74XX_REG_ANALOG_CTRL_5, ®); - if (rv) - return EC_ERROR_UNKNOWN; - rv = tcpc_write(port, ANX74XX_REG_ANALOG_CTRL_5, (reg & 0xf3)); - if (rv) - return EC_ERROR_UNKNOWN; - - /* Decrease BMC TX lowest swing voltage */ - rv |= tcpc_read(port, ANX74XX_REG_ANALOG_CTRL_11, ®); - if (rv) - return EC_ERROR_UNKNOWN; - rv = tcpc_write(port, ANX74XX_REG_ANALOG_CTRL_11, (reg & 0x3f) | 0x40); - if (rv) - return EC_ERROR_UNKNOWN; - - /* Set BMC TX cap slew rate to 400ns */ - rv = tcpc_write(port, ANX74XX_REG_ANALOG_CTRL_12, 0x4); - if (rv) - return EC_ERROR_UNKNOWN; - - tcpm_get_chip_info(port, 1, NULL); - - return EC_SUCCESS; -} - -static int anx74xx_get_chip_info(int port, int live, - struct ec_response_pd_chip_info_v1 *chip_info) -{ - int rv = tcpci_get_chip_info(port, live, chip_info); - int val; - - if (rv) - return rv; - - if (chip_info->fw_version_number == 0 || - chip_info->fw_version_number == -1 || live) { - rv = tcpc_read(port, ANX74XX_REG_FW_VERSION, &val); - - if (rv) - return rv; - - chip_info->fw_version_number = val; - } - -#ifdef CONFIG_USB_PD_TCPM_ANX3429 - /* - * Min firmware version of ANX3429 to ensure that false SOP' detection - * doesn't occur for e-marked cables. See b/116255749#comment8 and - * b/64752060#comment11 - */ - chip_info->min_req_fw_version_number = 0x16; -#endif - - return rv; -} - -/* - * Dissociate from the TCPC. - */ - -static int anx74xx_tcpm_release(int port) -{ - return EC_SUCCESS; -} - -const struct tcpm_drv anx74xx_tcpm_drv = { - .init = &anx74xx_tcpm_init, - .release = &anx74xx_tcpm_release, - .get_cc = &anx74xx_tcpm_get_cc, -#ifdef CONFIG_USB_PD_VBUS_DETECT_TCPC - .check_vbus_level = &anx74xx_tcpm_check_vbus_level, -#endif - .select_rp_value = &anx74xx_tcpm_select_rp_value, - .set_cc = &anx74xx_tcpm_set_cc, - .set_polarity = &anx74xx_tcpm_set_polarity, -#ifdef CONFIG_USB_PD_DECODE_SOP - .sop_prime_enable = &tcpci_tcpm_sop_prime_enable, -#endif - .set_vconn = &anx74xx_tcpm_set_vconn, - .set_msg_header = &anx74xx_tcpm_set_msg_header, - .set_rx_enable = &anx74xx_tcpm_set_rx_enable, - .get_message_raw = &anx74xx_tcpm_get_message_raw, - .transmit = &anx74xx_tcpm_transmit, - .tcpc_alert = &anx74xx_tcpc_alert, -#ifdef CONFIG_USB_PD_DISCHARGE_TCPC - .tcpc_discharge_vbus = &anx74xx_tcpc_discharge_vbus, -#endif - .get_chip_info = &anx74xx_get_chip_info, -#if defined(CONFIG_USB_PD_DUAL_ROLE_AUTO_TOGGLE) && \ - defined(CONFIG_USB_PD_TCPC_LOW_POWER) - .drp_toggle = &anx74xx_tcpc_drp_toggle, - .enter_low_power_mode = &anx74xx_enter_low_power_mode, -#endif - .set_bist_test_mode = &tcpci_set_bist_test_mode, -}; - -#ifdef CONFIG_CMD_I2C_STRESS_TEST_TCPC -struct i2c_stress_test_dev anx74xx_i2c_stress_test_dev = { - .reg_info = { - .read_reg = ANX74XX_REG_VENDOR_ID_L, - .read_val = ANX74XX_VENDOR_ID & 0xFF, - .write_reg = ANX74XX_REG_CC_SOFTWARE_CTRL, - }, - .i2c_read = &tcpc_i2c_read, - .i2c_write = &tcpc_i2c_write, -}; -#endif /* CONFIG_CMD_I2C_STRESS_TEST_TCPC */ diff --git a/driver/tcpm/anx74xx.h b/driver/tcpm/anx74xx.h deleted file mode 100644 index 8d700d4d86..0000000000 --- a/driver/tcpm/anx74xx.h +++ /dev/null @@ -1,229 +0,0 @@ -/* Copyright 2016 The Chromium OS Authors. All rights reserved. - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - * - * Author : Analogix Semiconductor. - */ - -#include "usb_mux.h" - -/* USB Power delivery port management */ - -#ifndef __CROS_EC_USB_PD_TCPM_ANX74XX_H -#define __CROS_EC_USB_PD_TCPM_ANX74XX_H - -/* I2C interface */ -#define ANX74XX_I2C_ADDR1_FLAGS 0x28 -#define ANX74XX_I2C_ADDR2_FLAGS 0x39 -#define ANX74XX_I2C_ADDR3_FLAGS 0x3E -#define ANX74XX_I2C_ADDR4_FLAGS 0x40 - -#define ANX74XX_REG_IRQ_POL_LOW 0x00 -#define ANX74XX_REG_IRQ_POL_HIGH 0x02 - -#define ANX74XX_REG_VENDOR_ID_L 0x00 -#define ANX74XX_REG_VENDOR_ID_H 0x01 -#define ANX74XX_VENDOR_ID 0xAAAA - -/* ANX F/W version:0x50:0x44 which contains otp firmware version */ -#define ANX74XX_REG_FW_VERSION 0x44 - -#define ANX74XX_REG_IRQ_STATUS 0x53 - -#define ANX74XX_REG_INTP_VCONN_CTRL 0x33 -#define ANX74XX_REG_VCONN_DISABLE 0x0f -#define ANX74XX_REG_VCONN_1_ENABLE BIT(4) -#define ANX74XX_REG_VCONN_2_ENABLE BIT(5) -#define ANX74XX_REG_R_INTERRUPT_OPEN_DRAIN BIT(2) - -#define ANX74XX_STANDBY_MODE (0) -#define ANX74XX_NORMAL_MODE (1) - -#define ANX74XX_REG_TX_CTRL_1 0x81 -#define ANX74XX_REG_TX_HARD_RESET_REQ BIT(1) -#define ANX74XX_REG_TX_CABLE_RESET_REQ BIT(2) - -#define ANX74XX_REG_TX_CTRL_2 0x82 -#define ANX74XX_REG_TX_WR_FIFO 0x83 -#define ANX74XX_REG_TX_FIFO_CTRL 0x9a -#define ANX74XX_REG_TX_HEADER_L 0x2c -#define ANX74XX_REG_TX_HEADER_H 0x2d -#define ANX74XX_REG_TX_START_ADDR_0 0x6d -#define ANX74XX_REG_TX_START_ADDR_1 0xd0 - -#define ANX74XX_REG_CTRL_COMMAND 0xdb -#define ANX74XX_REG_TX_SEND_DATA_REQ BIT(0) -#define ANX74XX_REG_TX_HARD_RST_REQ BIT(1) - -#define ANX74XX_REG_TX_BIST_CTRL 0x9D -#define ANX74XX_REG_TX_BIST_MODE BIT(4) -#define ANX74XX_REG_TX_BIST_STOP BIT(3) -#define ANX74XX_REG_TX_BIXT_FOREVER BIT(2) -#define ANX74XX_REG_TX_BIST_ENABLE BIT(1) -#define ANX74XX_REG_TX_BIST_START BIT(0) - -#define ANX74XX_REG_PD_HEADER 0x69 -#define ANX74XX_REG_PD_RX_DATA_OBJ 0x11 -#define ANX74XX_REG_PD_RX_DATA_OBJ_M 0x4d - -#define ANX74XX_REG_ANALOG_STATUS 0x40 -#define ANX74XX_REG_VBUS_STATUS BIT(4) -#define ANX74XX_REG_CC_PULL_RD 0xfd -#define ANX74XX_REG_CC_PULL_RP 0x02 - - -#define ANX74XX_REG_TX_AUTO_GOODCRC_2 0x94 -#define ANX74XX_REG_REPLY_SOP_EN BIT(3) -#define ANX74XX_REG_REPLY_SOP_1_EN BIT(4) -#define ANX74XX_REG_REPLY_SOP_2_EN BIT(5) - -#define ANX74XX_REG_TX_AUTO_GOODCRC_1 0x9c -#define ANX74XX_REG_SPEC_REV_BIT_POS (3) -#define ANX74XX_REG_DATA_ROLE_BIT_POS (2) -#define ANX74XX_REG_PWR_ROLE_BIT_POS (1) -#define ANX74XX_REG_AUTO_GOODCRC_EN BIT(0) -#define ANX74XX_REG_AUTO_GOODCRC_SET(drole, prole) \ - ((PD_REV20 << ANX74XX_REG_SPEC_REV_BIT_POS) | \ - ((drole) << ANX74XX_REG_DATA_ROLE_BIT_POS) | \ - ((prole) << ANX74XX_REG_PWR_ROLE_BIT_POS) | \ - ANX74XX_REG_AUTO_GOODCRC_EN) - - -#define ANX74XX_REG_ANALOG_CTRL_0 0x41 -#define ANX74XX_REG_R_PIN_CABLE_DET BIT(7) - -#define ANX74XX_REG_ANALOG_CTRL_1 0x42 -#define ANX74XX_REG_ANALOG_CTRL_5 0x46 -#define ANX74XX_REG_ANALOG_CTRL_6 0x47 -#define ANX74XX_REG_CC_PULL_RP_36K 0x00 -#define ANX74XX_REG_CC_PULL_RP_12K 0x01 -#define ANX74XX_REG_CC_PULL_RP_4K 0x02 - -#define ANX74XX_REG_R_SWITCH_CC_CLR 0x0f -#define ANX74XX_REG_R_SWITCH_CC2_SET 0x10 -#define ANX74XX_REG_R_SWITCH_CC1_SET 0x20 -#define ANX74XX_REG_AUX_SWAP_SET_CC1 0x30 -#define ANX74XX_REG_AUX_SWAP_SET_CC2 0xc0 - -#define ANX74XX_REG_ANALOG_CTRL_11 0x4c -#define ANX74XX_REG_ANALOG_CTRL_12 0x4d - -#define ANX74XX_REG_MUX_ML0_RX2 BIT(0) -#define ANX74XX_REG_MUX_ML0_RX1 BIT(1) -#define ANX74XX_REG_MUX_ML3_RX2 BIT(2) -#define ANX74XX_REG_MUX_ML3_RX1 BIT(3) -#define ANX74XX_REG_MUX_SSRX_RX2 BIT(4) -#define ANX74XX_REG_MUX_SSRX_RX1 BIT(5) -#define ANX74XX_REG_MUX_ML1_TX2 BIT(6) -#define ANX74XX_REG_MUX_ML1_TX1 BIT(7) - -#define ANX74XX_REG_MUX_ML2_TX2 BIT(4) -#define ANX74XX_REG_MUX_ML2_TX1 BIT(5) -#define ANX74XX_REG_MUX_SSTX_TX2 BIT(6) -#define ANX74XX_REG_MUX_SSTX_TX1 BIT(7) - -#define ANX74XX_REG_CC_SOFTWARE_CTRL 0x4a -#define ANX74XX_REG_CC_SW_CTRL_ENABLE 0x01 -#define ANX74XX_REG_TX_MODE_ENABLE 0x04 - -#define ANX74XX_REG_SELECT_CC1 0x02 - -#define ANX74XX_REG_GPIO_CTRL_4_5 0x3f -#define ANX74XX_REG_VBUS_OP_ENABLE 0x04 -#define ANX74XX_REG_VBUS_GPIO_MODE 0xfe - -#define ANX74XX_REG_IRQ_EXT_MASK_1 0x3b -#define ANX74XX_REG_IRQ_EXT_MASK_2 0x3c -#define ANX74XX_REG_IRQ_EXT_SOURCE_1 0x3e -#define ANX74XX_REG_EXT_SOP BIT(6) -#define ANX74XX_REG_EXT_SOP_PRIME BIT(7) -#define ANX74XX_REG_IRQ_EXT_SOURCE_2 0x4e -#define ANX74XX_REG_EXT_SOP_PRIME_PRIME BIT(0) -#define ANX74XX_REG_EXT_HARD_RST BIT(2) -#define ANX74XX_REG_IRQ_EXT_SOURCE_3 0x4f -#define ANX74XX_REG_CLEAR_SOFT_IRQ BIT(2) - -#define ANX74XX_REG_IRQ_SOURCE_RECV_MSG 0x6b -#define ANX74XX_REG_IRQ_CC_MSG_INT BIT(0) -#define ANX74XX_REG_IRQ_CC_STATUS_INT BIT(1) -#define ANX74XX_REG_IRQ_GOOD_CRC_INT BIT(2) -#define ANX74XX_REG_IRQ_TX_FAIL_INT BIT(3) -#define ANX74XX_REG_IRQ_SOURCE_RECV_MSG_MASK 0x6c - -#define ANX74XX_REG_CLEAR_SET_BITS 0xff -#define ANX74XX_REG_ALERT_HARD_RST_RECV BIT(6) -#define ANX74XX_REG_ALERT_MSG_RECV BIT(5) -#define ANX74XX_REG_ALERT_TX_MSG_ERROR BIT(4) -#define ANX74XX_REG_ALERT_TX_ACK_RECV BIT(3) -#define ANX74XX_REG_ALERT_TX_CABLE_RESETOK BIT(2) -#define ANX74XX_REG_ALERT_TX_HARD_RESETOK BIT(1) -#define ANX74XX_REG_ALERT_CC_CHANGE BIT(0) - -#define ANX74XX_REG_ANALOG_CTRL_2 0x43 -#define ANX74XX_REG_MODE_TRANS 0x01 - -#define ANX74XX_REG_SET_VBUS 0x20 - -#define ANX74XX_REG_ANALOG_CTRL_7 0x48 -#define ANX74XX_REG_STATUS_CC_RD 0x01 -#define ANX74XX_REG_STATUS_CC_RA 0x03 -#define ANX74XX_REG_STATUS_CC1(reg) ((reg & 0x0C) >> 2) -#define ANX74XX_REG_STATUS_CC2(reg) ((reg & 0x03) >> 0) - -#define ANX74XX_REG_HPD_CONTROL 0xfd - -#define ANX74XX_REG_HPD_CTRL_0 0x36 -#define ANX74XX_REG_DISCHARGE_CTRL 0x80 -#define ANX74XX_REG_HPD_OP_MODE 0x08 -#define ANX74XX_REG_HPD_DEFAULT 0x00 -#define ANX74XX_REG_HPD_OUT_DATA 0x10 - -#define ANX74XX_REG_RECVD_MSG_INT 0x98 -#define ANX74XX_REG_CC_STATUS 0x99 -#define ANX74XX_REG_CTRL_FW 0x2E -#define CLEAR_RX_BUFFER (1) -#define ANX74XX_REG_POWER_DOWN_CTRL 0x0d -#define ANX74XX_REG_STATUS_CC1_VRD_USB BIT(7) -#define ANX74XX_REG_STATUS_CC1_VRD_1P5 BIT(6) -#define ANX74XX_REG_STATUS_CC1_VRD_3P0 BIT(5) -#define ANX74XX_REG_STATUS_CC2_VRD_USB BIT(4) -#define ANX74XX_REG_STATUS_CC2_VRD_1P5 BIT(3) -#define ANX74XX_REG_STATUS_CC2_VRD_3P0 BIT(2) - -/* defined in the inter-bock Spec: 4.2.10 CC Detect Status */ -#define ANX74XX_REG_CC_STATUS_MASK 0xf -#define BIT_VALUE_OF_SRC_CC_RD 0x01 -#define BIT_VALUE_OF_SRC_CC_RA 0x02 -#define BIT_VALUE_OF_SNK_CC_DEFAULT 0x04 -#define BIT_VALUE_OF_SNK_CC_1_P_5 0x08 -#define BIT_VALUE_OF_SNK_CC_3_P_0 0x0C -#define ANX74XX_CC_RA_MASK (BIT_VALUE_OF_SRC_CC_RA | \ - (BIT_VALUE_OF_SRC_CC_RA << 4)) -#define ANX74XX_CC_RD_MASK (BIT_VALUE_OF_SRC_CC_RD | \ - (BIT_VALUE_OF_SRC_CC_RD << 4)) - -/* - * RESETN low to PWR_EN low delay - */ -#define ANX74XX_RST_L_PWR_L_DELAY_MS 1 -/* - * minimum power off-to-on delay to reset chip - */ -#define ANX74XX_PWR_L_PWR_H_DELAY_MS 10 -/* - * parameter T4: PWR_EN high to RESETN high delay - */ -#define ANX74XX_PWR_H_RST_H_DELAY_MS 10 - -extern const struct tcpm_drv anx74xx_tcpm_drv; -extern const struct usb_mux_driver anx74xx_tcpm_usb_mux_driver; -void anx74xx_tcpc_set_vbus(int port, int enable); -void anx74xx_tcpc_clear_hpd_status(int port); -void anx74xx_tcpc_update_hpd_status(const struct usb_mux *me, - mux_state_t mux_state); - -#ifdef CONFIG_CMD_I2C_STRESS_TEST_TCPC -extern struct i2c_stress_test_dev anx74xx_i2c_stress_test_dev; -#endif - -#endif /* __CROS_EC_USB_PD_TCPM_ANX74XX_H */ diff --git a/driver/tcpm/anx7688.c b/driver/tcpm/anx7688.c deleted file mode 100644 index 5e37352bc5..0000000000 --- a/driver/tcpm/anx7688.c +++ /dev/null @@ -1,225 +0,0 @@ -/* Copyright 2016 The Chromium OS Authors. All rights reserved. - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ - -/* ANX7688 port manager */ - -#include "hooks.h" -#include "tcpm/tcpci.h" -#include "tcpm/tcpm.h" -#include "timer.h" -#include "usb_mux.h" - -#if defined(CONFIG_USB_PD_DUAL_ROLE_AUTO_TOGGLE) || \ - defined(CONFIG_USB_PD_TCPC_LOW_POWER) || \ - defined(CONFIG_USB_PD_DISCHARGE_TCPC) -#error "Unsupported config options of anx7688 PD driver" -#endif - -#define ANX7688_VENDOR_ALERT BIT(15) - -#define ANX7688_REG_STATUS 0x82 -#define ANX7688_REG_STATUS_LINK BIT(0) - -#define ANX7688_REG_HPD 0x83 -#define ANX7688_REG_HPD_HIGH BIT(0) -#define ANX7688_REG_HPD_IRQ BIT(1) -#define ANX7688_REG_HPD_ENABLE BIT(2) - -#define ANX7688_USBC_ADDR_FLAGS 0x28 -#define ANX7688_REG_RAMCTRL 0xe7 -#define ANX7688_REG_RAMCTRL_BOOT_DONE BIT(6) - -static int anx7688_init(int port) -{ - int rv = 0; - int mask = 0; - - /* - * 7688 POWER_STATUS[6] is not reliable for tcpci_tcpm_init() to poll - * due to it is default 0 in HW, and we cannot write TCPC until it is - * ready, or something goes wrong. (Issue 52772) - * Instead we poll TCPC 0x50:0xe7 bit6 here to make sure bootdone is - * ready(50ms). Then PD main flow can process cc debounce in 50ms ~ - * 100ms to follow cts. - */ - while (1) { - rv = i2c_read8(I2C_PORT_TCPC, ANX7688_USBC_ADDR_FLAGS, - ANX7688_REG_RAMCTRL, &mask); - - if (rv == EC_SUCCESS && (mask & ANX7688_REG_RAMCTRL_BOOT_DONE)) - break; - msleep(10); - } - - rv = tcpci_tcpm_drv.init(port); - if (rv) - return rv; - - rv = tcpc_read16(port, TCPC_REG_ALERT_MASK, &mask); - if (rv) - return rv; - - /* enable vendor specific alert */ - mask |= ANX7688_VENDOR_ALERT; - rv = tcpc_write16(port, TCPC_REG_ALERT_MASK, mask); - return rv; -} - -static int anx7688_release(int port) -{ - return EC_ERROR_UNIMPLEMENTED; -} - -static void anx7688_update_hpd_enable(int port) -{ - int status, reg, rv; - - rv = tcpc_read(port, ANX7688_REG_STATUS, &status); - rv |= tcpc_read(port, ANX7688_REG_HPD, ®); - if (rv) - return; - - if (!(reg & ANX7688_REG_HPD_ENABLE) || - !(status & ANX7688_REG_STATUS_LINK)) { - reg &= ~ANX7688_REG_HPD_IRQ; - tcpc_write(port, ANX7688_REG_HPD, - (status & ANX7688_REG_STATUS_LINK) - ? reg | ANX7688_REG_HPD_ENABLE - : reg & ~ANX7688_REG_HPD_ENABLE); - } -} - -int anx7688_hpd_disable(int port) -{ - return tcpc_write(port, ANX7688_REG_HPD, 0); -} - -int anx7688_update_hpd(int port, int level, int irq) -{ - int reg, rv; - - rv = tcpc_read(port, ANX7688_REG_HPD, ®); - if (rv) - return rv; - - if (level) - reg |= ANX7688_REG_HPD_HIGH; - else - reg &= ~ANX7688_REG_HPD_HIGH; - - if (irq) - reg |= ANX7688_REG_HPD_IRQ; - else - reg &= ~ANX7688_REG_HPD_IRQ; - - return tcpc_write(port, ANX7688_REG_HPD, reg); -} - -int anx7688_enable_cable_detection(int port) -{ - return tcpc_write(port, TCPC_REG_COMMAND, 0xff); -} - -int anx7688_set_power_supply_ready(int port) -{ - return tcpc_write(port, TCPC_REG_COMMAND, 0x77); -} - -int anx7688_power_supply_reset(int port) -{ - return tcpc_write(port, TCPC_REG_COMMAND, 0x66); -} - -static void anx7688_tcpc_alert(int port) -{ - int alert, rv; - - rv = tcpc_read16(port, TCPC_REG_ALERT, &alert); - /* process and clear alert status */ - tcpci_tcpc_alert(port); - - if (!rv && (alert & ANX7688_VENDOR_ALERT)) - anx7688_update_hpd_enable(port); -} - -static int anx7688_mux_set(const struct usb_mux *me, mux_state_t mux_state, - bool *ack_required) -{ - int reg = 0; - int rv, polarity; - - /* This driver does not use host command ACKs */ - *ack_required = false; - - rv = mux_read(me, TCPC_REG_CONFIG_STD_OUTPUT, ®); - if (rv != EC_SUCCESS) - return rv; - - reg &= ~TCPC_REG_CONFIG_STD_OUTPUT_MUX_MASK; - if (mux_state & USB_PD_MUX_USB_ENABLED) - reg |= TCPC_REG_CONFIG_STD_OUTPUT_MUX_USB; - if (mux_state & USB_PD_MUX_DP_ENABLED) - reg |= TCPC_REG_CONFIG_STD_OUTPUT_MUX_DP; - - /* ANX7688 needs to set bit0 */ - rv = mux_read(me, TCPC_REG_TCPC_CTRL, &polarity); - if (rv != EC_SUCCESS) - return rv; - - /* copy the polarity from TCPC_CTRL[0], take care clear then set */ - reg &= ~TCPC_REG_TCPC_CTRL_POLARITY(1); - reg |= TCPC_REG_TCPC_CTRL_POLARITY(polarity); - return mux_write(me, TCPC_REG_CONFIG_STD_OUTPUT, reg); -} - -#ifdef CONFIG_USB_PD_VBUS_DETECT_TCPC -static bool anx7688_tcpm_check_vbus_level(int port, enum vbus_level level) -{ - int reg = 0; - - /* On ANX7688, POWER_STATUS.VBusPresent (bit 2) is averaged 16 times, so - * its value may not be set to 1 quickly enough during power role swap. - * Therefore, we use a proprietary register to read the unfiltered VBus - * value. See crosbug.com/p/55221 . - */ - i2c_read8(I2C_PORT_TCPC, 0x28, 0x40, ®); - - if (level == VBUS_PRESENT) - return ((reg & 0x10) ? 1 : 0); - else - return ((reg & 0x10) ? 0 : 1); -} -#endif - -/* ANX7688 is a TCPCI compatible port controller */ -const struct tcpm_drv anx7688_tcpm_drv = { - .init = &anx7688_init, - .release = &anx7688_release, - .get_cc = &tcpci_tcpm_get_cc, -#ifdef CONFIG_USB_PD_VBUS_DETECT_TCPC - .check_vbus_level = &anx7688_tcpm_check_vbus_level, -#endif - .select_rp_value = &tcpci_tcpm_select_rp_value, - .set_cc = &tcpci_tcpm_set_cc, - .set_polarity = &tcpci_tcpm_set_polarity, -#ifdef CONFIG_USB_PD_DECODE_SOP - .sop_prime_enable = &tcpci_tcpm_sop_prime_enable, -#endif - .set_vconn = &tcpci_tcpm_set_vconn, - .set_msg_header = &tcpci_tcpm_set_msg_header, - .set_rx_enable = &tcpci_tcpm_set_rx_enable, - .get_message_raw = &tcpci_tcpm_get_message_raw, - .transmit = &tcpci_tcpm_transmit, - .tcpc_alert = &anx7688_tcpc_alert, - .set_bist_test_mode = &tcpci_set_bist_test_mode, -}; - -#ifdef CONFIG_USB_PD_TCPM_MUX -const struct usb_mux_driver anx7688_usb_mux_driver = { - .init = tcpci_tcpm_mux_init, - .set = anx7688_mux_set, - .get = tcpci_tcpm_mux_get, -}; -#endif /* CONFIG_USB_PD_TCPM_MUX */ diff --git a/driver/tcpm/anx7688.h b/driver/tcpm/anx7688.h deleted file mode 100644 index 534e4155b1..0000000000 --- a/driver/tcpm/anx7688.h +++ /dev/null @@ -1,21 +0,0 @@ -/* Copyright 2016 The Chromium OS Authors. All rights reserved. - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ - -/* USB Power delivery port management */ - -#ifndef __CROS_EC_USB_PD_TCPM_ANX7688_H -#define __CROS_EC_USB_PD_TCPM_ANX7688_H - -int anx7688_update_hpd(int port, int level, int irq); -int anx7688_set_dp_pin_mode(int port, int pin_mode); -int anx7688_enable_cable_detection(int port); -int anx7688_set_power_supply_ready(int port); -int anx7688_power_supply_reset(int port); -int anx7688_hpd_disable(int port); - -extern struct tcpm_drv anx7688_tcpm_drv; -extern struct usb_mux_driver anx7688_usb_mux_driver; - -#endif /* __CROS_EC_USB_PD_TCPM_ANX7688_H */ diff --git a/driver/tcpm/ccgxxf.h b/driver/tcpm/ccgxxf.h deleted file mode 100644 index f4b3deb355..0000000000 --- a/driver/tcpm/ccgxxf.h +++ /dev/null @@ -1,62 +0,0 @@ -/* Copyright 2021 The Chromium OS Authors. All rights reserved. - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ - -/* - * USB Power delivery port management For Cypress EZ-PD CCG6DF, CCG6SF - * CCGXXF FW is designed to adapt standard TCPM driver procedures. - */ -#ifndef __CROS_EC_DRIVER_TCPM_CCGXXF_H -#define __CROS_EC_DRIVER_TCPM_CCGXXF_H - -#define CCGXXF_I2C_ADDR1_FLAGS 0x0B -#define CCGXXF_I2C_ADDR2_FLAGS 0x1B - -/* CCGXXF built in I/O expander definitions */ -#ifdef CONFIG_IO_EXPANDER_CCGXXF - -/* CCGXXF I/O ports that can be referenced in gpio.inc */ -enum ccgxxf_io_ports { - CCGXXF_PORT_0, - CCGXXF_PORT_1, - CCGXXF_PORT_2, - CCGXXF_PORT_3 -}; - -/* CCGXXF I/O pins that can be referenced in gpio.inc */ -enum ccgxxf_io_pins { - CCGXXF_IO_0, - CCGXXF_IO_1, - CCGXXF_IO_2, - CCGXXF_IO_3, - CCGXXF_IO_4, - CCGXXF_IO_5, - CCGXXF_IO_6, - CCGXXF_IO_7 -}; - -#define CCGXXF_REG_GPIO_CONTROL(port) ((port) + 0x80) -#define CCGXXF_REG_GPIO_STATUS(port) ((port) + 0x84) - -#define CCGXXF_REG_GPIO_MODE 0x88 -#define CCGXXF_GPIO_PIN_MASK_SHIFT 8 -#define CCGXXF_GPIO_PIN_MODE_SHIFT 2 -#define CCGXXF_GPIO_1P8V_SEL BIT(7) - -enum ccgxxf_gpio_mode { - CCGXXF_GPIO_MODE_HIZ_ANALOG, - CCGXXF_GPIO_MODE_HIZ_DIGITAL, - CCGXXF_GPIO_MODE_RES_UP, - CCGXXF_GPIO_MODE_RES_DWN, - CCGXXF_GPIO_MODE_OD_LOW, - CCGXXF_GPIO_MODE_OD_HIGH, - CCGXXF_GPIO_MODE_STRONG, - CCGXXF_GPIO_MODE_RES_UPDOWN -}; - -extern const struct ioexpander_drv ccgxxf_ioexpander_drv; - -#endif /* CONFIG_IO_EXPANDER_CCGXXF */ - -#endif /* __CROS_EC_DRIVER_TCPM_CCGXXF_H */ diff --git a/driver/tcpm/fusb302.c b/driver/tcpm/fusb302.c deleted file mode 100644 index 0098906d32..0000000000 --- a/driver/tcpm/fusb302.c +++ /dev/null @@ -1,1205 +0,0 @@ -/* Copyright 2015 The Chromium OS Authors. All rights reserved. - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - * - * Author: Gabe Noblesmith - */ - -/* Type-C port manager for Fairchild's FUSB302 */ - -#include "console.h" -#include "fusb302.h" -#include "task.h" -#include "hooks.h" -#include "tcpm/tcpci.h" -#include "tcpm/tcpm.h" -#include "timer.h" -#include "usb_charge.h" -#include "usb_pd.h" -#include "usb_pd_tcpc.h" -#include "usb_pd_tcpm.h" -#include "util.h" - -#if defined(CONFIG_USB_PD_DUAL_ROLE_AUTO_TOGGLE) || \ - defined(CONFIG_USB_PD_DISCHARGE_TCPC) -#error "Unsupported config options of fusb302 PD driver" -#endif - -#define PACKET_IS_GOOD_CRC(head) (PD_HEADER_TYPE(head) == PD_CTRL_GOOD_CRC && \ - PD_HEADER_CNT(head) == 0) - -static struct fusb302_chip_state { - int cc_polarity; - int vconn_enabled; - /* 1 = pulling up (DFP) 0 = pulling down (UFP) */ - int pulling_up; - int rx_enable; - uint8_t mdac_vnc; - uint8_t mdac_rd; -} state[CONFIG_USB_PD_PORT_MAX_COUNT]; - -static struct mutex measure_lock; - -/* - * Bring the FUSB302 out of reset after Hard Reset signaling. This will - * automatically flush both the Rx and Tx FIFOs. - */ -static void fusb302_pd_reset(int port) -{ - tcpc_write(port, TCPC_REG_RESET, TCPC_REG_RESET_PD_RESET); -} - -/* - * Flush our Rx FIFO. To prevent packet framing issues, this function should - * only be called when Rx is disabled. - */ -static void fusb302_flush_rx_fifo(int port) -{ - /* - * other bits in the register _should_ be 0 - * until the day we support other SOP* types... - * then we'll have to keep a shadow of what this register - * value should be so we don't clobber it here! - */ - tcpc_write(port, TCPC_REG_CONTROL1, TCPC_REG_CONTROL1_RX_FLUSH); -} - -static void fusb302_flush_tx_fifo(int port) -{ - int reg; - - tcpc_read(port, TCPC_REG_CONTROL0, ®); - reg |= TCPC_REG_CONTROL0_TX_FLUSH; - tcpc_write(port, TCPC_REG_CONTROL0, reg); -} - -static void fusb302_auto_goodcrc_enable(int port, int enable) -{ - int reg; - - tcpc_read(port, TCPC_REG_SWITCHES1, ®); - - if (enable) - reg |= TCPC_REG_SWITCHES1_AUTO_GCRC; - else - reg &= ~TCPC_REG_SWITCHES1_AUTO_GCRC; - - tcpc_write(port, TCPC_REG_SWITCHES1, reg); -} - -/* Convert BC LVL values (in FUSB302) to Type-C CC Voltage Status */ -static int convert_bc_lvl(int port, int bc_lvl) -{ - /* assume OPEN unless one of the following conditions is true... */ - int ret = TYPEC_CC_VOLT_OPEN; - - if (state[port].pulling_up) { - if (bc_lvl == 0x00) - ret = TYPEC_CC_VOLT_RA; - else if (bc_lvl < 0x3) - ret = TYPEC_CC_VOLT_RD; - } else { - if (bc_lvl == 0x1) - ret = TYPEC_CC_VOLT_RP_DEF; - else if (bc_lvl == 0x2) - ret = TYPEC_CC_VOLT_RP_1_5; - else if (bc_lvl == 0x3) - ret = TYPEC_CC_VOLT_RP_3_0; - } - - return ret; -} - -static int measure_cc_pin_source(int port, int cc_measure) -{ - int switches0_reg; - int reg; - int cc_lvl; - - mutex_lock(&measure_lock); - - /* Read status register */ - tcpc_read(port, TCPC_REG_SWITCHES0, ®); - /* Save current value */ - switches0_reg = reg; - /* Clear pull-up register settings and measure bits */ - reg &= ~(TCPC_REG_SWITCHES0_MEAS_CC1 | TCPC_REG_SWITCHES0_MEAS_CC2); - /* Set desired pullup register bit */ - if (cc_measure == TCPC_REG_SWITCHES0_MEAS_CC1) - reg |= TCPC_REG_SWITCHES0_CC1_PU_EN; - else - reg |= TCPC_REG_SWITCHES0_CC2_PU_EN; - /* Set CC measure bit */ - reg |= cc_measure; - - /* Set measurement switch */ - tcpc_write(port, TCPC_REG_SWITCHES0, reg); - - /* Set MDAC for Open vs Rd/Ra comparison */ - tcpc_write(port, TCPC_REG_MEASURE, state[port].mdac_vnc); - - /* Wait on measurement */ - usleep(250); - - /* Read status register */ - tcpc_read(port, TCPC_REG_STATUS0, ®); - - /* Assume open */ - cc_lvl = TYPEC_CC_VOLT_OPEN; - - /* CC level is below the 'no connect' threshold (vOpen) */ - if ((reg & TCPC_REG_STATUS0_COMP) == 0) { - /* Set MDAC for Rd vs Ra comparison */ - tcpc_write(port, TCPC_REG_MEASURE, state[port].mdac_rd); - - /* Wait on measurement */ - usleep(250); - - /* Read status register */ - tcpc_read(port, TCPC_REG_STATUS0, ®); - - cc_lvl = (reg & TCPC_REG_STATUS0_COMP) ? TYPEC_CC_VOLT_RD - : TYPEC_CC_VOLT_RA; - } - - /* Restore SWITCHES0 register to its value prior */ - tcpc_write(port, TCPC_REG_SWITCHES0, switches0_reg); - - mutex_unlock(&measure_lock); - - return cc_lvl; -} - -/* Determine cc pin state for source when in manual detect mode */ -static void detect_cc_pin_source_manual(int port, - enum tcpc_cc_voltage_status *cc1_lvl, - enum tcpc_cc_voltage_status *cc2_lvl) -{ - int cc1_measure = TCPC_REG_SWITCHES0_MEAS_CC1; - int cc2_measure = TCPC_REG_SWITCHES0_MEAS_CC2; - - if (state[port].vconn_enabled) { - /* If VCONN enabled, measure cc_pin that matches polarity */ - if (state[port].cc_polarity) - *cc2_lvl = measure_cc_pin_source(port, cc2_measure); - else - *cc1_lvl = measure_cc_pin_source(port, cc1_measure); - } else { - /* If VCONN not enabled, measure both cc1 and cc2 */ - *cc1_lvl = measure_cc_pin_source(port, cc1_measure); - *cc2_lvl = measure_cc_pin_source(port, cc2_measure); - } - -} - -/* Determine cc pin state for sink */ -static void detect_cc_pin_sink(int port, enum tcpc_cc_voltage_status *cc1, - enum tcpc_cc_voltage_status *cc2) -{ - int reg; - int orig_meas_cc1; - int orig_meas_cc2; - int bc_lvl_cc1; - int bc_lvl_cc2; - - mutex_lock(&measure_lock); - - /* - * Measure CC1 first. - */ - tcpc_read(port, TCPC_REG_SWITCHES0, ®); - - /* save original state to be returned to later... */ - if (reg & TCPC_REG_SWITCHES0_MEAS_CC1) - orig_meas_cc1 = 1; - else - orig_meas_cc1 = 0; - - if (reg & TCPC_REG_SWITCHES0_MEAS_CC2) - orig_meas_cc2 = 1; - else - orig_meas_cc2 = 0; - - - /* Disable CC2 measurement switch, enable CC1 measurement switch */ - reg &= ~TCPC_REG_SWITCHES0_MEAS_CC2; - reg |= TCPC_REG_SWITCHES0_MEAS_CC1; - - tcpc_write(port, TCPC_REG_SWITCHES0, reg); - - /* CC1 is now being measured by FUSB302. */ - - /* Wait on measurement */ - usleep(250); - - tcpc_read(port, TCPC_REG_STATUS0, &bc_lvl_cc1); - - /* mask away unwanted bits */ - bc_lvl_cc1 &= (TCPC_REG_STATUS0_BC_LVL0 | TCPC_REG_STATUS0_BC_LVL1); - - /* - * Measure CC2 next. - */ - - tcpc_read(port, TCPC_REG_SWITCHES0, ®); - - /* Disable CC1 measurement switch, enable CC2 measurement switch */ - reg &= ~TCPC_REG_SWITCHES0_MEAS_CC1; - reg |= TCPC_REG_SWITCHES0_MEAS_CC2; - - tcpc_write(port, TCPC_REG_SWITCHES0, reg); - - /* CC2 is now being measured by FUSB302. */ - - /* Wait on measurement */ - usleep(250); - - tcpc_read(port, TCPC_REG_STATUS0, &bc_lvl_cc2); - - /* mask away unwanted bits */ - bc_lvl_cc2 &= (TCPC_REG_STATUS0_BC_LVL0 | TCPC_REG_STATUS0_BC_LVL1); - - *cc1 = convert_bc_lvl(port, bc_lvl_cc1); - *cc2 = convert_bc_lvl(port, bc_lvl_cc2); - - /* return MEAS_CC1/2 switches to original state */ - tcpc_read(port, TCPC_REG_SWITCHES0, ®); - if (orig_meas_cc1) - reg |= TCPC_REG_SWITCHES0_MEAS_CC1; - else - reg &= ~TCPC_REG_SWITCHES0_MEAS_CC1; - if (orig_meas_cc2) - reg |= TCPC_REG_SWITCHES0_MEAS_CC2; - else - reg &= ~TCPC_REG_SWITCHES0_MEAS_CC2; - - tcpc_write(port, TCPC_REG_SWITCHES0, reg); - - mutex_unlock(&measure_lock); -} - -/* Parse header bytes for the size of packet */ -static int get_num_bytes(uint16_t header) -{ - int rv; - - /* Grab the Number of Data Objects field.*/ - rv = PD_HEADER_CNT(header); - - /* Multiply by four to go from 32-bit words -> bytes */ - rv *= 4; - - /* Plus 2 for header */ - rv += 2; - - return rv; -} - -static int fusb302_send_message(int port, uint16_t header, const uint32_t *data, - uint8_t *buf, int buf_pos) -{ - int rv; - int reg; - int len; - - len = get_num_bytes(header); - - /* - * packsym tells the TXFIFO that the next X bytes are payload, - * and should not be interpreted as special tokens. - * The 5 LSBs represent X, the number of bytes. - */ - reg = FUSB302_TKN_PACKSYM; - reg |= (len & 0x1F); - - buf[buf_pos++] = reg; - - /* write in the header */ - reg = header; - buf[buf_pos++] = reg & 0xFF; - - reg >>= 8; - buf[buf_pos++] = reg & 0xFF; - - /* header is done, subtract from length to make this for-loop simpler */ - len -= 2; - - /* write data objects, if present */ - memcpy(&buf[buf_pos], data, len); - buf_pos += len; - - /* put in the CRC */ - buf[buf_pos++] = FUSB302_TKN_JAMCRC; - - /* put in EOP */ - buf[buf_pos++] = FUSB302_TKN_EOP; - - /* Turn transmitter off after sending message */ - buf[buf_pos++] = FUSB302_TKN_TXOFF; - - /* Start transmission */ - reg = FUSB302_TKN_TXON; - buf[buf_pos++] = FUSB302_TKN_TXON; - - /* burst write for speed! */ - rv = tcpc_xfer(port, buf, buf_pos, 0, 0); - - return rv; -} - -static int fusb302_tcpm_select_rp_value(int port, int rp) -{ - int reg; - int rv; - uint8_t vnc, rd; - - /* Keep track of current RP value */ - tcpci_set_cached_rp(port, rp); - - rv = tcpc_read(port, TCPC_REG_CONTROL0, ®); - if (rv) - return rv; - - /* Set the current source for Rp value */ - reg &= ~TCPC_REG_CONTROL0_HOST_CUR_MASK; - switch (rp) { - case TYPEC_RP_1A5: - reg |= TCPC_REG_CONTROL0_HOST_CUR_1A5; - vnc = TCPC_REG_MEASURE_MDAC_MV(PD_SRC_1_5_VNC_MV); - rd = TCPC_REG_MEASURE_MDAC_MV(PD_SRC_1_5_RD_THRESH_MV); - break; - case TYPEC_RP_3A0: - reg |= TCPC_REG_CONTROL0_HOST_CUR_3A0; - vnc = TCPC_REG_MEASURE_MDAC_MV(PD_SRC_3_0_VNC_MV); - rd = TCPC_REG_MEASURE_MDAC_MV(PD_SRC_3_0_RD_THRESH_MV); - break; - case TYPEC_RP_USB: - default: - reg |= TCPC_REG_CONTROL0_HOST_CUR_USB; - vnc = TCPC_REG_MEASURE_MDAC_MV(PD_SRC_DEF_VNC_MV); - rd = TCPC_REG_MEASURE_MDAC_MV(PD_SRC_DEF_RD_THRESH_MV); - } - state[port].mdac_vnc = vnc; - state[port].mdac_rd = rd; - return tcpc_write(port, TCPC_REG_CONTROL0, reg); -} - -static int fusb302_tcpm_init(int port) -{ - int reg; - - /* set default */ - state[port].cc_polarity = -1; - - /* set the voltage threshold for no connect detection (vOpen) */ - state[port].mdac_vnc = TCPC_REG_MEASURE_MDAC_MV(PD_SRC_DEF_VNC_MV); - /* set the voltage threshold for Rd vs Ra detection */ - state[port].mdac_rd = TCPC_REG_MEASURE_MDAC_MV(PD_SRC_DEF_RD_THRESH_MV); - - /* all other variables assumed to default to 0 */ - - /* Restore default settings */ - tcpc_write(port, TCPC_REG_RESET, TCPC_REG_RESET_SW_RESET); - - /* Turn on retries and set number of retries */ - tcpc_read(port, TCPC_REG_CONTROL3, ®); - reg |= TCPC_REG_CONTROL3_AUTO_RETRY; - reg |= (CONFIG_PD_RETRY_COUNT & 0x3) << TCPC_REG_CONTROL3_N_RETRIES_POS; - tcpc_write(port, TCPC_REG_CONTROL3, reg); - - /* Create interrupt masks */ - reg = 0xFF; - /* CC level changes */ - reg &= ~TCPC_REG_MASK_BC_LVL; - /* collisions */ - reg &= ~TCPC_REG_MASK_COLLISION; - /* misc alert */ - reg &= ~TCPC_REG_MASK_ALERT; -#ifdef CONFIG_USB_PD_VBUS_DETECT_TCPC - /* TODO(crbug.com/791109): Clean up VBUS notification. */ - - /* VBUS threshold crossed (~4.0V) */ - reg &= ~TCPC_REG_MASK_VBUSOK; -#endif - tcpc_write(port, TCPC_REG_MASK, reg); - - reg = 0xFF; - /* when all pd message retries fail... */ - reg &= ~TCPC_REG_MASKA_RETRYFAIL; - /* when fusb302 send a hard reset. */ - reg &= ~TCPC_REG_MASKA_HARDSENT; - /* when fusb302 receives GoodCRC ack for a pd message */ - reg &= ~TCPC_REG_MASKA_TX_SUCCESS; - /* when fusb302 receives a hard reset */ - reg &= ~TCPC_REG_MASKA_HARDRESET; - tcpc_write(port, TCPC_REG_MASKA, reg); - - reg = 0xFF; - /* when fusb302 sends GoodCRC to ack a pd message */ - reg &= ~TCPC_REG_MASKB_GCRCSENT; - tcpc_write(port, TCPC_REG_MASKB, reg); - - /* Interrupt Enable */ - tcpc_read(port, TCPC_REG_CONTROL0, ®); - reg &= ~TCPC_REG_CONTROL0_INT_MASK; - tcpc_write(port, TCPC_REG_CONTROL0, reg); - - /* Set VCONN switch defaults */ - tcpm_set_polarity(port, 0); - tcpm_set_vconn(port, 0); - - /* TODO: Reduce power consumption */ - tcpc_write(port, TCPC_REG_POWER, TCPC_REG_POWER_PWR_ALL); - -#if defined(CONFIG_USB_PD_VBUS_DETECT_TCPC) && defined(CONFIG_USB_CHARGER) - /* Wait for the reference voltage to stablize */ - usleep(250); - /* - * Initialize VBUS supplier when VBUS is already present before - * init (e.g. Cold reboot with charger plugged). - */ - tcpc_read(port, TCPC_REG_STATUS0, ®); - if (reg & TCPC_REG_STATUS0_VBUSOK) - usb_charger_vbus_change(port, 1); -#endif - - return 0; -} - -static int fusb302_tcpm_release(int port) -{ - return EC_ERROR_UNIMPLEMENTED; -} - -static int fusb302_tcpm_get_cc(int port, enum tcpc_cc_voltage_status *cc1, - enum tcpc_cc_voltage_status *cc2) -{ - if (state[port].pulling_up) { - /* Source mode? */ - detect_cc_pin_source_manual(port, cc1, cc2); - } else { - /* Sink mode? */ - detect_cc_pin_sink(port, cc1, cc2); - } - - return 0; -} - -static int fusb302_tcpm_set_cc(int port, int pull) -{ - int reg; - - /* NOTE: FUSB302 toggles a single pull-up between CC1 and CC2 */ - /* NOTE: FUSB302 Does not support Ra. */ - switch (pull) { - case TYPEC_CC_RP: - /* enable the pull-up we know to be necessary */ - tcpc_read(port, TCPC_REG_SWITCHES0, ®); - - reg &= ~(TCPC_REG_SWITCHES0_CC2_PU_EN | - TCPC_REG_SWITCHES0_CC1_PU_EN | - TCPC_REG_SWITCHES0_CC1_PD_EN | - TCPC_REG_SWITCHES0_CC2_PD_EN | - TCPC_REG_SWITCHES0_VCONN_CC1 | - TCPC_REG_SWITCHES0_VCONN_CC2); - - reg |= TCPC_REG_SWITCHES0_CC1_PU_EN | - TCPC_REG_SWITCHES0_CC2_PU_EN; - - if (state[port].vconn_enabled) - reg |= state[port].cc_polarity ? - TCPC_REG_SWITCHES0_VCONN_CC1 : - TCPC_REG_SWITCHES0_VCONN_CC2; - - tcpc_write(port, TCPC_REG_SWITCHES0, reg); - - state[port].pulling_up = 1; - break; - case TYPEC_CC_RD: - /* Enable UFP Mode */ - - /* turn off toggle */ - tcpc_read(port, TCPC_REG_CONTROL2, ®); - reg &= ~TCPC_REG_CONTROL2_TOGGLE; - tcpc_write(port, TCPC_REG_CONTROL2, reg); - - /* enable pull-downs, disable pullups */ - tcpc_read(port, TCPC_REG_SWITCHES0, ®); - - reg &= ~(TCPC_REG_SWITCHES0_CC2_PU_EN); - reg &= ~(TCPC_REG_SWITCHES0_CC1_PU_EN); - reg |= (TCPC_REG_SWITCHES0_CC1_PD_EN); - reg |= (TCPC_REG_SWITCHES0_CC2_PD_EN); - tcpc_write(port, TCPC_REG_SWITCHES0, reg); - - state[port].pulling_up = 0; - break; - case TYPEC_CC_OPEN: - /* Disable toggling */ - tcpc_read(port, TCPC_REG_CONTROL2, ®); - reg &= ~TCPC_REG_CONTROL2_TOGGLE; - tcpc_write(port, TCPC_REG_CONTROL2, reg); - - /* Ensure manual switches are opened */ - tcpc_read(port, TCPC_REG_SWITCHES0, ®); - reg &= ~TCPC_REG_SWITCHES0_CC1_PU_EN; - reg &= ~TCPC_REG_SWITCHES0_CC2_PU_EN; - reg &= ~TCPC_REG_SWITCHES0_CC1_PD_EN; - reg &= ~TCPC_REG_SWITCHES0_CC2_PD_EN; - tcpc_write(port, TCPC_REG_SWITCHES0, reg); - - state[port].pulling_up = 0; - break; - default: - /* Unsupported... */ - return EC_ERROR_UNIMPLEMENTED; - } - return 0; -} - -static int fusb302_tcpm_set_polarity(int port, enum tcpc_cc_polarity polarity) -{ - /* Port polarity : 0 => CC1 is CC line, 1 => CC2 is CC line */ - int reg; - - tcpc_read(port, TCPC_REG_SWITCHES0, ®); - - /* clear VCONN switch bits */ - reg &= ~TCPC_REG_SWITCHES0_VCONN_CC1; - reg &= ~TCPC_REG_SWITCHES0_VCONN_CC2; - - if (state[port].vconn_enabled) { - /* set VCONN switch to be non-CC line */ - if (polarity_rm_dts(polarity)) - reg |= TCPC_REG_SWITCHES0_VCONN_CC1; - else - reg |= TCPC_REG_SWITCHES0_VCONN_CC2; - } - - /* clear meas_cc bits (RX line select) */ - reg &= ~TCPC_REG_SWITCHES0_MEAS_CC1; - reg &= ~TCPC_REG_SWITCHES0_MEAS_CC2; - - /* set rx polarity */ - if (polarity_rm_dts(polarity)) - reg |= TCPC_REG_SWITCHES0_MEAS_CC2; - else - reg |= TCPC_REG_SWITCHES0_MEAS_CC1; - - tcpc_write(port, TCPC_REG_SWITCHES0, reg); - - tcpc_read(port, TCPC_REG_SWITCHES1, ®); - - /* clear tx_cc bits */ - reg &= ~TCPC_REG_SWITCHES1_TXCC1_EN; - reg &= ~TCPC_REG_SWITCHES1_TXCC2_EN; - - /* set tx polarity */ - if (polarity_rm_dts(polarity)) - reg |= TCPC_REG_SWITCHES1_TXCC2_EN; - else - reg |= TCPC_REG_SWITCHES1_TXCC1_EN; - - tcpc_write(port, TCPC_REG_SWITCHES1, reg); - - /* Save the polarity for later */ - state[port].cc_polarity = polarity; - - return 0; -} - -__maybe_unused static int fusb302_tcpm_decode_sop_prime_enable(int port, - bool enable) -{ - int reg; - - if (tcpc_read(port, TCPC_REG_CONTROL1, ®)) - return EC_ERROR_UNKNOWN; - - if (enable) - reg |= (TCPC_REG_CONTROL1_ENSOP1 | - TCPC_REG_CONTROL1_ENSOP2); - else - reg &= ~(TCPC_REG_CONTROL1_ENSOP1 | - TCPC_REG_CONTROL1_ENSOP2); - - return tcpc_write(port, TCPC_REG_CONTROL1, reg); -} - -static int fusb302_tcpm_set_vconn(int port, int enable) -{ - /* - * FUSB302 does not have dedicated VCONN Enable switch. - * We'll get through this by disabling both of the - * VCONN - CC* switches to disable, and enabling the - * saved polarity when enabling. - * Therefore at startup, tcpm_set_polarity should be called first, - * or else live with the default put into tcpm_init. - */ - int reg; - - /* save enable state for later use */ - state[port].vconn_enabled = enable; - - if (enable) { - /* set to saved polarity */ - tcpm_set_polarity(port, state[port].cc_polarity); - - if (IS_ENABLED(CONFIG_USB_PD_DECODE_SOP)) { - if (state[port].rx_enable) { - if (fusb302_tcpm_decode_sop_prime_enable(port, - true)) - return EC_ERROR_UNKNOWN; - } - } - } else { - - tcpc_read(port, TCPC_REG_SWITCHES0, ®); - - /* clear VCONN switch bits */ - reg &= ~TCPC_REG_SWITCHES0_VCONN_CC1; - reg &= ~TCPC_REG_SWITCHES0_VCONN_CC2; - - tcpc_write(port, TCPC_REG_SWITCHES0, reg); - - if (IS_ENABLED(CONFIG_USB_PD_DECODE_SOP)) { - if (state[port].rx_enable) { - if (fusb302_tcpm_decode_sop_prime_enable(port, - false)) - return EC_ERROR_UNKNOWN; - } - } - } - - return 0; -} - -static int fusb302_tcpm_set_msg_header(int port, int power_role, int data_role) -{ - int reg; - - tcpc_read(port, TCPC_REG_SWITCHES1, ®); - - reg &= ~TCPC_REG_SWITCHES1_POWERROLE; - reg &= ~TCPC_REG_SWITCHES1_DATAROLE; - - if (power_role) - reg |= TCPC_REG_SWITCHES1_POWERROLE; - if (data_role) - reg |= TCPC_REG_SWITCHES1_DATAROLE; - - tcpc_write(port, TCPC_REG_SWITCHES1, reg); - - return 0; -} - -static int fusb302_tcpm_set_rx_enable(int port, int enable) -{ - int reg; - - state[port].rx_enable = enable; - - /* Get current switch state */ - tcpc_read(port, TCPC_REG_SWITCHES0, ®); - - /* Clear CC1/CC2 measure bits */ - reg &= ~TCPC_REG_SWITCHES0_MEAS_CC1; - reg &= ~TCPC_REG_SWITCHES0_MEAS_CC2; - - if (enable) { - switch (state[port].cc_polarity) { - /* if CC polarity hasnt been determined, can't enable */ - case -1: - return EC_ERROR_UNKNOWN; - case 0: - reg |= TCPC_REG_SWITCHES0_MEAS_CC1; - break; - case 1: - reg |= TCPC_REG_SWITCHES0_MEAS_CC2; - break; - default: - /* "shouldn't get here" */ - return EC_ERROR_UNKNOWN; - } - tcpc_write(port, TCPC_REG_SWITCHES0, reg); - - /* Disable BC_LVL interrupt when enabling PD comm */ - if (!tcpc_read(port, TCPC_REG_MASK, ®)) - tcpc_write(port, TCPC_REG_MASK, - reg | TCPC_REG_MASK_BC_LVL); - - /* flush rx fifo in case messages have been coming our way */ - fusb302_flush_rx_fifo(port); - - - } else { - tcpc_write(port, TCPC_REG_SWITCHES0, reg); - - /* Enable BC_LVL interrupt when disabling PD comm */ - if (!tcpc_read(port, TCPC_REG_MASK, ®)) - tcpc_write(port, TCPC_REG_MASK, - reg & ~TCPC_REG_MASK_BC_LVL); - } - -#ifdef CONFIG_USB_PD_DECODE_SOP - /* - * Only the VCONN Source is allowed to communicate - * with the Cable Plugs. - */ - if (state[port].vconn_enabled) { - if (tcpc_read(port, TCPC_REG_CONTROL1, ®)) - return EC_ERROR_UNKNOWN; - - reg |= (TCPC_REG_CONTROL1_ENSOP1 | TCPC_REG_CONTROL1_ENSOP2); - tcpc_write(port, TCPC_REG_CONTROL1, reg); - } -#endif - - fusb302_auto_goodcrc_enable(port, enable); - - return 0; -} - -/* Return true if our Rx FIFO is empty */ -static int fusb302_rx_fifo_is_empty(int port) -{ - int reg; - - return (!tcpc_read(port, TCPC_REG_STATUS1, ®)) && - (reg & TCPC_REG_STATUS1_RX_EMPTY); -} - -static int fusb302_tcpm_get_message_raw(int port, uint32_t *payload, int *head) -{ - /* - * This is the buffer that will get the burst-read data - * from the fusb302. - * - * It's re-used in a couple different spots, the worst of which - * is the PD packet (not header) and CRC. - * maximum size necessary = 28 + 4 = 32 - */ - uint8_t buf[32]; - int rv, len; - - /* Read until we have a non-GoodCRC packet or an empty FIFO */ - do { - buf[0] = TCPC_REG_FIFOS; - tcpc_lock(port, 1); - - /* - * PART 1 OF BURST READ: Write in register address. - * Issue a START, no STOP. - */ - rv = tcpc_xfer_unlocked(port, buf, 1, 0, 0, I2C_XFER_START); - - /* - * PART 2 OF BURST READ: Read up to the header. - * Issue a repeated START, no STOP. - * only grab three bytes so we can get the header - * and determine how many more bytes we need to read. - * TODO: Check token to ensure valid packet. - */ - rv |= tcpc_xfer_unlocked(port, 0, 0, buf, 3, I2C_XFER_START); - - /* Grab the header */ - *head = (buf[1] & 0xFF); - *head |= ((buf[2] << 8) & 0xFF00); - - /* figure out packet length, subtract header bytes */ - len = get_num_bytes(*head) - 2; - - /* - * PART 3 OF BURST READ: Read everything else. - * No START, but do issue a STOP at the end. - * add 4 to len to read CRC out - */ - rv |= tcpc_xfer_unlocked(port, 0, 0, buf, len+4, I2C_XFER_STOP); - - tcpc_lock(port, 0); - } while (!rv && PACKET_IS_GOOD_CRC(*head) && - !fusb302_rx_fifo_is_empty(port)); - - if (!rv) { - /* Discard GoodCRC packets */ - if (PACKET_IS_GOOD_CRC(*head)) - rv = EC_ERROR_UNKNOWN; - else - memcpy(payload, buf, len); - } - -#ifdef CONFIG_USB_PD_DECODE_SOP - { - int reg; - - if (tcpc_read(port, TCPC_REG_STATUS1, ®)) - return EC_ERROR_UNKNOWN; - - if (reg & TCPC_REG_STATUS1_RXSOP1) - *head |= PD_HEADER_SOP(TCPCI_MSG_SOP_PRIME); - else if (reg & TCPC_REG_STATUS1_RXSOP2) - *head |= PD_HEADER_SOP(TCPCI_MSG_SOP_PRIME_PRIME); - } -#endif - - return rv; -} - -static int fusb302_tcpm_transmit(int port, enum tcpci_msg_type type, - uint16_t header, const uint32_t *data) -{ - /* - * this is the buffer that will be burst-written into the fusb302 - * maximum size necessary = - * 1: FIFO register address - * 4: SOP* tokens - * 1: Token that signifies "next X bytes are not tokens" - * 30: 2 for header and up to 7*4 = 28 for rest of message - * 1: "Insert CRC" Token - * 1: EOP Token - * 1: "Turn transmitter off" token - * 1: "Star Transmission" Command - * - - * 40: 40 bytes worst-case - */ - uint8_t buf[40]; - int buf_pos = 0; - - int reg; - - /* Flush the TXFIFO */ - fusb302_flush_tx_fifo(port); - - switch (type) { - case TCPCI_MSG_SOP: - - /* put register address first for of burst tcpc write */ - buf[buf_pos++] = TCPC_REG_FIFOS; - - /* Write the SOP Ordered Set into TX FIFO */ - buf[buf_pos++] = FUSB302_TKN_SYNC1; - buf[buf_pos++] = FUSB302_TKN_SYNC1; - buf[buf_pos++] = FUSB302_TKN_SYNC1; - buf[buf_pos++] = FUSB302_TKN_SYNC2; - - return fusb302_send_message(port, header, data, buf, buf_pos); - case TCPCI_MSG_SOP_PRIME: - - /* put register address first for of burst tcpc write */ - buf[buf_pos++] = TCPC_REG_FIFOS; - - /* Write the SOP' Ordered Set into TX FIFO */ - buf[buf_pos++] = FUSB302_TKN_SYNC1; - buf[buf_pos++] = FUSB302_TKN_SYNC1; - buf[buf_pos++] = FUSB302_TKN_SYNC3; - buf[buf_pos++] = FUSB302_TKN_SYNC3; - - return fusb302_send_message(port, header, data, buf, buf_pos); - case TCPCI_MSG_SOP_PRIME_PRIME: - - /* put register address first for of burst tcpc write */ - buf[buf_pos++] = TCPC_REG_FIFOS; - - /* Write the SOP'' Ordered Set into TX FIFO */ - buf[buf_pos++] = FUSB302_TKN_SYNC1; - buf[buf_pos++] = FUSB302_TKN_SYNC3; - buf[buf_pos++] = FUSB302_TKN_SYNC1; - buf[buf_pos++] = FUSB302_TKN_SYNC3; - - return fusb302_send_message(port, header, data, buf, buf_pos); - case TCPCI_MSG_TX_HARD_RESET: - /* Simply hit the SEND_HARD_RESET bit */ - tcpc_read(port, TCPC_REG_CONTROL3, ®); - reg |= TCPC_REG_CONTROL3_SEND_HARDRESET; - tcpc_write(port, TCPC_REG_CONTROL3, reg); - - break; - case TCPCI_MSG_TX_BIST_MODE_2: - /* Hit the BIST_MODE2 bit and start TX */ - tcpc_read(port, TCPC_REG_CONTROL1, ®); - reg |= TCPC_REG_CONTROL1_BIST_MODE2; - tcpc_write(port, TCPC_REG_CONTROL1, reg); - - tcpc_read(port, TCPC_REG_CONTROL0, ®); - reg |= TCPC_REG_CONTROL0_TX_START; - tcpc_write(port, TCPC_REG_CONTROL0, reg); - - task_wait_event(PD_T_BIST_TRANSMIT); - - /* Clear BIST mode bit, TX_START is self-clearing */ - tcpc_read(port, TCPC_REG_CONTROL1, ®); - reg &= ~TCPC_REG_CONTROL1_BIST_MODE2; - tcpc_write(port, TCPC_REG_CONTROL1, reg); - - break; - default: - return EC_ERROR_UNIMPLEMENTED; - } - - return 0; -} - -#ifdef CONFIG_USB_PD_VBUS_DETECT_TCPC -static bool fusb302_tcpm_check_vbus_level(int port, enum vbus_level level) -{ - int reg; - - /* Read status register */ - tcpc_read(port, TCPC_REG_STATUS0, ®); - - if (level == VBUS_PRESENT) - return (reg & TCPC_REG_STATUS0_VBUSOK) ? 1 : 0; - else - return (reg & TCPC_REG_STATUS0_VBUSOK) ? 0 : 1; -} -#endif - -void fusb302_tcpc_alert(int port) -{ - /* interrupt has been received */ - int interrupt; - int interrupta; - int interruptb; - - /* reading interrupt registers clears them */ - - tcpc_read(port, TCPC_REG_INTERRUPT, &interrupt); - tcpc_read(port, TCPC_REG_INTERRUPTA, &interrupta); - tcpc_read(port, TCPC_REG_INTERRUPTB, &interruptb); - - /* - * Ignore BC_LVL changes when transmitting / receiving PD, - * since CC level will constantly change. - */ - if (state[port].rx_enable) - interrupt &= ~TCPC_REG_INTERRUPT_BC_LVL; - - if (interrupt & TCPC_REG_INTERRUPT_BC_LVL) { - /* CC Status change */ - task_set_event(PD_PORT_TO_TASK_ID(port), PD_EVENT_CC); - } - - if (interrupt & TCPC_REG_INTERRUPT_COLLISION) { - /* packet sending collided */ - pd_transmit_complete(port, TCPC_TX_COMPLETE_FAILED); - } - -#ifdef CONFIG_USB_PD_VBUS_DETECT_TCPC - if (interrupt & TCPC_REG_INTERRUPT_VBUSOK) { - /* VBUS crossed threshold */ -#ifdef CONFIG_USB_CHARGER - usb_charger_vbus_change(port, - fusb302_tcpm_check_vbus_level(port, - VBUS_PRESENT)); -#else - if (!fusb302_tcpm_check_vbus_level(port, VBUS_PRESENT)) - pd_vbus_low(port); -#endif - task_wake(PD_PORT_TO_TASK_ID(port)); - hook_notify(HOOK_AC_CHANGE); - } -#endif - - /* GoodCRC was received, our FIFO is now non-empty */ - if (interrupta & TCPC_REG_INTERRUPTA_TX_SUCCESS) { - pd_transmit_complete(port, TCPC_TX_COMPLETE_SUCCESS); - } - - if (interrupta & TCPC_REG_INTERRUPTA_RETRYFAIL) { - /* all retries have failed to get a GoodCRC */ - pd_transmit_complete(port, TCPC_TX_COMPLETE_FAILED); - } - - if (interrupta & TCPC_REG_INTERRUPTA_HARDSENT) { - /* hard reset has been sent */ - - /* bring FUSB302 out of reset */ - fusb302_pd_reset(port); - - pd_transmit_complete(port, TCPC_TX_COMPLETE_SUCCESS); - } - - if (interrupta & TCPC_REG_INTERRUPTA_HARDRESET) { - /* hard reset has been received */ - - /* bring FUSB302 out of reset */ - fusb302_pd_reset(port); - task_set_event(PD_PORT_TO_TASK_ID(port), - PD_EVENT_RX_HARD_RESET); - } - - if (interruptb & TCPC_REG_INTERRUPTB_GCRCSENT) { - /* Packet received and GoodCRC sent */ - /* (this interrupt fires after the GoodCRC finishes) */ - if (state[port].rx_enable) { - /* Pull all RX messages from TCPC into EC memory */ - while (!fusb302_rx_fifo_is_empty(port)) - tcpm_enqueue_message(port); - } else { - /* flush rx fifo if rx isn't enabled */ - fusb302_flush_rx_fifo(port); - } - } - -} - -/* For BIST receiving */ -void tcpm_set_bist_test_data(int port) -{ - int reg; - - /* Read control3 register */ - tcpc_read(port, TCPC_REG_CONTROL3, ®); - - /* Set the BIST_TMODE bit (Clears on Hard Reset) */ - reg |= TCPC_REG_CONTROL3_BIST_TMODE; - - /* Write the updated value */ - tcpc_write(port, TCPC_REG_CONTROL3, reg); -} - -#ifdef CONFIG_USB_PD_TCPC_LOW_POWER -static int fusb302_set_toggle_mode(int port, int mode) -{ - int reg, rv; - - rv = i2c_read8(tcpc_config[port].i2c_info.port, - tcpc_config[port].i2c_info.addr_flags, - TCPC_REG_CONTROL2, ®); - if (rv) - return rv; - - reg &= ~TCPC_REG_CONTROL2_MODE_MASK; - reg |= mode << TCPC_REG_CONTROL2_MODE_POS; - return i2c_write8(tcpc_config[port].i2c_info.port, - tcpc_config[port].i2c_info.addr_flags, - TCPC_REG_CONTROL2, reg); -} - -static int fusb302_tcpm_enter_low_power_mode(int port) -{ - int reg, rv, mode = TCPC_REG_CONTROL2_MODE_DRP; - - /** - * vendor's suggested LPM flow: - * - enable low power mode and set up other things - * - sleep 250 us - * - start toggling - */ - rv = i2c_write8(tcpc_config[port].i2c_info.port, - tcpc_config[port].i2c_info.addr_flags, - TCPC_REG_POWER, TCPC_REG_POWER_PWR_LOW); - if (rv) - return rv; - - switch (pd_get_dual_role(port)) { - case PD_DRP_TOGGLE_ON: - mode = TCPC_REG_CONTROL2_MODE_DRP; - break; - case PD_DRP_TOGGLE_OFF: - mode = TCPC_REG_CONTROL2_MODE_UFP; - break; - case PD_DRP_FREEZE: - mode = pd_get_power_role(port) == PD_ROLE_SINK ? - TCPC_REG_CONTROL2_MODE_UFP : - TCPC_REG_CONTROL2_MODE_DFP; - break; - case PD_DRP_FORCE_SINK: - mode = TCPC_REG_CONTROL2_MODE_UFP; - break; - case PD_DRP_FORCE_SOURCE: - mode = TCPC_REG_CONTROL2_MODE_DFP; - break; - } - rv = fusb302_set_toggle_mode(port, mode); - if (rv) - return rv; - - usleep(250); - - rv = i2c_read8(tcpc_config[port].i2c_info.port, - tcpc_config[port].i2c_info.addr_flags, - TCPC_REG_CONTROL2, ®); - if (rv) - return rv; - reg |= TCPC_REG_CONTROL2_TOGGLE; - return i2c_write8(tcpc_config[port].i2c_info.port, - tcpc_config[port].i2c_info.addr_flags, - TCPC_REG_CONTROL2, reg); -} -#endif - -/* - * Compare VBUS voltage with given mdac reference voltage. - * returns non-zero if VBUS voltage >= (mdac + 1) * 420 mV - */ -static int fusb302_compare_mdac(int port, int mdac) -{ - int orig_reg, status0; - - mutex_lock(&measure_lock); - - /* backup REG_MEASURE */ - tcpc_read(port, TCPC_REG_MEASURE, &orig_reg); - /* set reg_measure bit 0~5 to mdac, and bit6 to 1(measure vbus) */ - tcpc_write(port, TCPC_REG_MEASURE, - (mdac & TCPC_REG_MEASURE_MDAC_MASK) | TCPC_REG_MEASURE_VBUS); - - /* Wait on measurement */ - usleep(350); - - /* - * Read status register, if STATUS0_COMP=1 then vbus is higher than - * (mdac + 1) * 0.42V - */ - tcpc_read(port, TCPC_REG_STATUS0, &status0); - /* write back original value */ - tcpc_write(port, TCPC_REG_MEASURE, orig_reg); - - mutex_unlock(&measure_lock); - - return status0 & TCPC_REG_STATUS0_COMP; -} - -int tcpc_get_vbus_voltage(int port) -{ - int mdac = 0, i; - - /* - * Implement by comparing VBUS with MDAC reference voltage, and binary - * search the value of MDAC. - * - * MDAC register has 6 bits, so we can simply search 1 bit per - * iteration, from MSB to LSB. - */ - for (i = 5; i >= 0; i--) { - if (fusb302_compare_mdac(port, mdac | BIT(i))) - mdac |= BIT(i); - } - - return (mdac + 1) * 420; -} - -const struct tcpm_drv fusb302_tcpm_drv = { - .init = &fusb302_tcpm_init, - .release = &fusb302_tcpm_release, - .get_cc = &fusb302_tcpm_get_cc, -#ifdef CONFIG_USB_PD_VBUS_DETECT_TCPC - .check_vbus_level = &fusb302_tcpm_check_vbus_level, -#endif - .select_rp_value = &fusb302_tcpm_select_rp_value, - .set_cc = &fusb302_tcpm_set_cc, - .set_polarity = &fusb302_tcpm_set_polarity, -#ifdef CONFIG_USB_PD_DECODE_SOP - .sop_prime_enable = &fusb302_tcpm_decode_sop_prime_enable, -#endif - .set_vconn = &fusb302_tcpm_set_vconn, - .set_msg_header = &fusb302_tcpm_set_msg_header, - .set_rx_enable = &fusb302_tcpm_set_rx_enable, - .get_message_raw = &fusb302_tcpm_get_message_raw, - .transmit = &fusb302_tcpm_transmit, - .tcpc_alert = &fusb302_tcpc_alert, -#ifdef CONFIG_USB_PD_TCPC_LOW_POWER - .enter_low_power_mode = &fusb302_tcpm_enter_low_power_mode, -#endif -}; diff --git a/driver/tcpm/fusb302.h b/driver/tcpm/fusb302.h deleted file mode 100644 index 717b28df18..0000000000 --- a/driver/tcpm/fusb302.h +++ /dev/null @@ -1,211 +0,0 @@ -/* Copyright 2015 The Chromium OS Authors. All rights reserved. - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - * - * Author: Gabe Noblesmith - */ - -/* USB Power delivery port management */ -/* For Fairchild FUSB302 */ -#ifndef __CROS_EC_DRIVER_TCPM_FUSB302_H -#define __CROS_EC_DRIVER_TCPM_FUSB302_H - -/* Chip Device ID - 302A or 302B */ -#define FUSB302_DEVID_302A 0x08 -#define FUSB302_DEVID_302B 0x09 - -/* I2C address varies by part number */ -/* FUSB302BUCX / FUSB302BMPX */ -#define FUSB302_I2C_ADDR_FLAGS 0x22 -/* FUSB302B01MPX */ -#define FUSB302_I2C_ADDR_B01_FLAGS 0x23 -/* FUSB302B10MPX */ -#define FUSB302_I2C_ADDR_B10_FLAGS 0x24 -/* FUSB302B11MPX */ -#define FUSB302_I2C_ADDR_B11_FLAGS 0x25 - -#define TCPC_REG_DEVICE_ID 0x01 - -#define TCPC_REG_SWITCHES0 0x02 -#define TCPC_REG_SWITCHES0_CC2_PU_EN (1<<7) -#define TCPC_REG_SWITCHES0_CC1_PU_EN (1<<6) -#define TCPC_REG_SWITCHES0_VCONN_CC2 (1<<5) -#define TCPC_REG_SWITCHES0_VCONN_CC1 (1<<4) -#define TCPC_REG_SWITCHES0_MEAS_CC2 (1<<3) -#define TCPC_REG_SWITCHES0_MEAS_CC1 (1<<2) -#define TCPC_REG_SWITCHES0_CC2_PD_EN (1<<1) -#define TCPC_REG_SWITCHES0_CC1_PD_EN (1<<0) - -#define TCPC_REG_SWITCHES1 0x03 -#define TCPC_REG_SWITCHES1_POWERROLE (1<<7) -#define TCPC_REG_SWITCHES1_SPECREV1 (1<<6) -#define TCPC_REG_SWITCHES1_SPECREV0 (1<<5) -#define TCPC_REG_SWITCHES1_DATAROLE (1<<4) -#define TCPC_REG_SWITCHES1_AUTO_GCRC (1<<2) -#define TCPC_REG_SWITCHES1_TXCC2_EN (1<<1) -#define TCPC_REG_SWITCHES1_TXCC1_EN (1<<0) - -#define TCPC_REG_MEASURE 0x04 -#define TCPC_REG_MEASURE_MDAC_MASK 0x3F -#define TCPC_REG_MEASURE_VBUS (1<<6) -/* - * MDAC reference voltage step size is 42 mV. Round our thresholds to reduce - * maximum error, which also matches suggested thresholds in datasheet - * (Table 3. Host Interrupt Summary). - */ -#define TCPC_REG_MEASURE_MDAC_MV(mv) (DIV_ROUND_NEAREST((mv), 42) & 0x3f) - -#define TCPC_REG_CONTROL0 0x06 -#define TCPC_REG_CONTROL0_TX_FLUSH (1<<6) -#define TCPC_REG_CONTROL0_INT_MASK (1<<5) -#define TCPC_REG_CONTROL0_HOST_CUR_MASK (3<<2) -#define TCPC_REG_CONTROL0_HOST_CUR_3A0 (3<<2) -#define TCPC_REG_CONTROL0_HOST_CUR_1A5 (2<<2) -#define TCPC_REG_CONTROL0_HOST_CUR_USB (1<<2) -#define TCPC_REG_CONTROL0_TX_START (1<<0) - -#define TCPC_REG_CONTROL1 0x07 -#define TCPC_REG_CONTROL1_ENSOP2DB (1<<6) -#define TCPC_REG_CONTROL1_ENSOP1DB (1<<5) -#define TCPC_REG_CONTROL1_BIST_MODE2 (1<<4) -#define TCPC_REG_CONTROL1_RX_FLUSH (1<<2) -#define TCPC_REG_CONTROL1_ENSOP2 (1<<1) -#define TCPC_REG_CONTROL1_ENSOP1 (1<<0) - -#define TCPC_REG_CONTROL2 0x08 -/* two-bit field, valid values below */ -#define TCPC_REG_CONTROL2_MODE_MASK (0x3<<TCPC_REG_CONTROL2_MODE_POS) -#define TCPC_REG_CONTROL2_MODE_DFP (0x3) -#define TCPC_REG_CONTROL2_MODE_UFP (0x2) -#define TCPC_REG_CONTROL2_MODE_DRP (0x1) -#define TCPC_REG_CONTROL2_MODE_POS (1) -#define TCPC_REG_CONTROL2_TOGGLE (1<<0) - -#define TCPC_REG_CONTROL3 0x09 -#define TCPC_REG_CONTROL3_SEND_HARDRESET (1<<6) -#define TCPC_REG_CONTROL3_BIST_TMODE (1<<5) /* 302B Only */ -#define TCPC_REG_CONTROL3_AUTO_HARDRESET (1<<4) -#define TCPC_REG_CONTROL3_AUTO_SOFTRESET (1<<3) -/* two-bit field */ -#define TCPC_REG_CONTROL3_N_RETRIES (1<<1) -#define TCPC_REG_CONTROL3_N_RETRIES_POS (1) -#define TCPC_REG_CONTROL3_N_RETRIES_SIZE (2) -#define TCPC_REG_CONTROL3_AUTO_RETRY (1<<0) - -#define TCPC_REG_MASK 0x0A -#define TCPC_REG_MASK_VBUSOK (1<<7) -#define TCPC_REG_MASK_ACTIVITY (1<<6) -#define TCPC_REG_MASK_COMP_CHNG (1<<5) -#define TCPC_REG_MASK_CRC_CHK (1<<4) -#define TCPC_REG_MASK_ALERT (1<<3) -#define TCPC_REG_MASK_WAKE (1<<2) -#define TCPC_REG_MASK_COLLISION (1<<1) -#define TCPC_REG_MASK_BC_LVL (1<<0) - -#define TCPC_REG_POWER 0x0B -#define TCPC_REG_POWER_PWR (1<<0) /* four-bit field */ -#define TCPC_REG_POWER_PWR_LOW 0x1 /* Bandgap + Wake circuitry */ -#define TCPC_REG_POWER_PWR_MEDIUM 0x3 /* LOW + Receiver + Current refs */ -#define TCPC_REG_POWER_PWR_HIGH 0x7 /* MEDIUM + Measure block */ -#define TCPC_REG_POWER_PWR_ALL 0xF /* HIGH + Internal Oscillator */ - -#define TCPC_REG_RESET 0x0C -#define TCPC_REG_RESET_PD_RESET (1<<1) -#define TCPC_REG_RESET_SW_RESET (1<<0) - -#define TCPC_REG_MASKA 0x0E -#define TCPC_REG_MASKA_OCP_TEMP (1<<7) -#define TCPC_REG_MASKA_TOGDONE (1<<6) -#define TCPC_REG_MASKA_SOFTFAIL (1<<5) -#define TCPC_REG_MASKA_RETRYFAIL (1<<4) -#define TCPC_REG_MASKA_HARDSENT (1<<3) -#define TCPC_REG_MASKA_TX_SUCCESS (1<<2) -#define TCPC_REG_MASKA_SOFTRESET (1<<1) -#define TCPC_REG_MASKA_HARDRESET (1<<0) - -#define TCPC_REG_MASKB 0x0F -#define TCPC_REG_MASKB_GCRCSENT (1<<0) - -#define TCPC_REG_STATUS0A 0x3C -#define TCPC_REG_STATUS0A_SOFTFAIL (1<<5) -#define TCPC_REG_STATUS0A_RETRYFAIL (1<<4) -#define TCPC_REG_STATUS0A_POWER (1<<2) /* two-bit field */ -#define TCPC_REG_STATUS0A_RX_SOFT_RESET (1<<1) -#define TCPC_REG_STATUS0A_RX_HARD_RESEt (1<<0) - -#define TCPC_REG_STATUS1A 0x3D -/* three-bit field, valid values below */ -#define TCPC_REG_STATUS1A_TOGSS (1<<3) -#define TCPC_REG_STATUS1A_TOGSS_RUNNING 0x0 -#define TCPC_REG_STATUS1A_TOGSS_SRC1 0x1 -#define TCPC_REG_STATUS1A_TOGSS_SRC2 0x2 -#define TCPC_REG_STATUS1A_TOGSS_SNK1 0x5 -#define TCPC_REG_STATUS1A_TOGSS_SNK2 0x6 -#define TCPC_REG_STATUS1A_TOGSS_AA 0x7 -#define TCPC_REG_STATUS1A_TOGSS_POS (3) -#define TCPC_REG_STATUS1A_TOGSS_MASK (0x7) - -#define TCPC_REG_STATUS1A_RXSOP2DB (1<<2) -#define TCPC_REG_STATUS1A_RXSOP1DB (1<<1) -#define TCPC_REG_STATUS1A_RXSOP (1<<0) - -#define TCPC_REG_INTERRUPTA 0x3E -#define TCPC_REG_INTERRUPTA_OCP_TEMP (1<<7) -#define TCPC_REG_INTERRUPTA_TOGDONE (1<<6) -#define TCPC_REG_INTERRUPTA_SOFTFAIL (1<<5) -#define TCPC_REG_INTERRUPTA_RETRYFAIL (1<<4) -#define TCPC_REG_INTERRUPTA_HARDSENT (1<<3) -#define TCPC_REG_INTERRUPTA_TX_SUCCESS (1<<2) -#define TCPC_REG_INTERRUPTA_SOFTRESET (1<<1) -#define TCPC_REG_INTERRUPTA_HARDRESET (1<<0) - -#define TCPC_REG_INTERRUPTB 0x3F -#define TCPC_REG_INTERRUPTB_GCRCSENT (1<<0) - -#define TCPC_REG_STATUS0 0x40 -#define TCPC_REG_STATUS0_VBUSOK (1<<7) -#define TCPC_REG_STATUS0_ACTIVITY (1<<6) -#define TCPC_REG_STATUS0_COMP (1<<5) -#define TCPC_REG_STATUS0_CRC_CHK (1<<4) -#define TCPC_REG_STATUS0_ALERT (1<<3) -#define TCPC_REG_STATUS0_WAKE (1<<2) -#define TCPC_REG_STATUS0_BC_LVL1 (1<<1) /* two-bit field */ -#define TCPC_REG_STATUS0_BC_LVL0 (1<<0) /* two-bit field */ - -#define TCPC_REG_STATUS1 0x41 -#define TCPC_REG_STATUS1_RXSOP2 (1<<7) -#define TCPC_REG_STATUS1_RXSOP1 (1<<6) -#define TCPC_REG_STATUS1_RX_EMPTY (1<<5) -#define TCPC_REG_STATUS1_RX_FULL (1<<4) -#define TCPC_REG_STATUS1_TX_EMPTY (1<<3) -#define TCPC_REG_STATUS1_TX_FULL (1<<2) - -#define TCPC_REG_INTERRUPT 0x42 -#define TCPC_REG_INTERRUPT_VBUSOK (1<<7) -#define TCPC_REG_INTERRUPT_ACTIVITY (1<<6) -#define TCPC_REG_INTERRUPT_COMP_CHNG (1<<5) -#define TCPC_REG_INTERRUPT_CRC_CHK (1<<4) -#define TCPC_REG_INTERRUPT_ALERT (1<<3) -#define TCPC_REG_INTERRUPT_WAKE (1<<2) -#define TCPC_REG_INTERRUPT_COLLISION (1<<1) -#define TCPC_REG_INTERRUPT_BC_LVL (1<<0) - -#define TCPC_REG_FIFOS 0x43 - -/* Tokens defined for the FUSB302 TX FIFO */ -enum fusb302_txfifo_tokens { - FUSB302_TKN_TXON = 0xA1, - FUSB302_TKN_SYNC1 = 0x12, - FUSB302_TKN_SYNC2 = 0x13, - FUSB302_TKN_SYNC3 = 0x1B, - FUSB302_TKN_RST1 = 0x15, - FUSB302_TKN_RST2 = 0x16, - FUSB302_TKN_PACKSYM = 0x80, - FUSB302_TKN_JAMCRC = 0xFF, - FUSB302_TKN_EOP = 0x14, - FUSB302_TKN_TXOFF = 0xFE, -}; - -extern const struct tcpm_drv fusb302_tcpm_drv; - -#endif /* __CROS_EC_DRIVER_TCPM_FUSB302_H */ diff --git a/driver/tcpm/fusb307.c b/driver/tcpm/fusb307.c deleted file mode 100644 index e8804a2661..0000000000 --- a/driver/tcpm/fusb307.c +++ /dev/null @@ -1,103 +0,0 @@ -/* Copyright 2020 The Chromium OS Authors. All rights reserved. - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ - -/* Type-C port manager for Fairchild's FUSB307 */ - -#include "console.h" -#include "fusb307.h" -#include "hooks.h" -#include "task.h" -#include "tcpm/tcpci.h" -#include "tcpm/tcpm.h" -#include "timer.h" -#include "util.h" - -#define CPRINTF(format, args...) cprintf(CC_USBPD, format, ## args) -#define CPRINTS(format, args...) cprints(CC_USBPD, format, ## args) - -int fusb307_power_supply_reset(int port) -{ - return tcpc_write(port, TCPC_REG_COMMAND, 0x66); -} - -static int fusb307_tcpm_init(int port) -{ - int rv; - - rv = tcpci_tcpm_init(port); - - rv = tcpci_set_role_ctrl(port, TYPEC_DRP, TYPEC_RP_USB, TYPEC_CC_RD); - pd_set_dual_role(port, PD_DRP_TOGGLE_ON); - - return rv; -} - -int fusb307_tcpm_set_polarity(int port, enum tcpc_cc_polarity polarity) -{ - int rv; - enum tcpc_cc_voltage_status cc1, cc2; - - rv = tcpci_tcpm_set_polarity(port, polarity); - - tcpm_get_cc(port, &cc1, &cc2); - if (cc1) { - if (pd_get_power_role(port) == PD_ROLE_SINK) { - int role = TCPC_REG_ROLE_CTRL_SET(0, - tcpci_get_cached_rp(port), TYPEC_CC_RD, TYPEC_CC_OPEN); - - tcpc_write(port, TCPC_REG_ROLE_CTRL, role); - } else { - int role = TCPC_REG_ROLE_CTRL_SET(0, - tcpci_get_cached_rp(port), TYPEC_CC_RP, TYPEC_CC_OPEN); - - tcpc_write(port, TCPC_REG_ROLE_CTRL, role); - } - } else if (cc2) { - if (pd_get_power_role(port) == PD_ROLE_SINK) { - int role = TCPC_REG_ROLE_CTRL_SET(0, - tcpci_get_cached_rp(port), TYPEC_CC_OPEN, TYPEC_CC_RD); - - tcpc_write(port, TCPC_REG_ROLE_CTRL, role); - } else { - int role = TCPC_REG_ROLE_CTRL_SET(0, - tcpci_get_cached_rp(port), TYPEC_CC_OPEN, TYPEC_CC_RP); - - tcpc_write(port, TCPC_REG_ROLE_CTRL, role); - } - } else { - if (pd_get_power_role(port) == PD_ROLE_SINK) - tcpci_tcpm_set_cc(port, TYPEC_CC_RD); - else - tcpci_tcpm_set_cc(port, TYPEC_CC_RP); - } - - return rv; -} - -const struct tcpm_drv fusb307_tcpm_drv = { - .init = &fusb307_tcpm_init, - .release = &tcpci_tcpm_release, - .get_cc = &tcpci_tcpm_get_cc, -#ifdef CONFIG_USB_PD_VBUS_DETECT_TCPC - .check_vbus_level = &tcpci_tcpm_check_vbus_level, -#endif - .select_rp_value = &tcpci_tcpm_select_rp_value, - .set_cc = &tcpci_tcpm_set_cc, - .set_polarity = &fusb307_tcpm_set_polarity, - .set_vconn = &tcpci_tcpm_set_vconn, - .set_msg_header = &tcpci_tcpm_set_msg_header, - .set_rx_enable = &tcpci_tcpm_set_rx_enable, - .get_message_raw = &tcpci_tcpm_get_message_raw, - .transmit = &tcpci_tcpm_transmit, - .tcpc_alert = &tcpci_tcpc_alert, - .tcpc_enable_auto_discharge_disconnect = - &tcpci_tcpc_enable_auto_discharge_disconnect, - .get_chip_info = &tcpci_get_chip_info, -#if defined(CONFIG_USB_PD_DUAL_ROLE_AUTO_TOGGLE) - .drp_toggle = &tcpci_tcpc_drp_toggle, -#endif - .set_bist_test_mode = &tcpci_set_bist_test_mode, -}; - diff --git a/driver/tcpm/fusb307.h b/driver/tcpm/fusb307.h deleted file mode 100644 index 3f1f12901d..0000000000 --- a/driver/tcpm/fusb307.h +++ /dev/null @@ -1,28 +0,0 @@ -/* Copyright 2020 The Chromium OS Authors. All rights reserved. - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ - -/* USB Power delivery port management */ -/* For Fairchild FUSB307 */ -#ifndef __CROS_EC_FUSB307_H -#define __CROS_EC_FUSB307_H - -#include "usb_pd.h" - -#define FUSB307_I2C_ADDR_FLAGS 0x50 - -#define TCPC_REG_RESET 0xA2 -#define TCPC_REG_RESET_PD_RESET BIT(1) -#define TCPC_REG_RESET_SW_RESET BIT(0) - -#define TCPC_REG_GPIO1_CFG 0xA4 -#define TCPC_REG_GPIO1_CFG_GPO1_VAL BIT(2) -#define TCPC_REG_GPIO1_CFG_GPI1_EN BIT(1) -#define TCPC_REG_GPIO1_CFG_GPO1_EN BIT(0) - -int fusb307_power_supply_reset(int port); - -extern const struct tcpm_drv fusb307_tcpm_drv; - -#endif /* __CROS_EC_FUSB307_H */ diff --git a/driver/tcpm/it83xx.c b/driver/tcpm/it83xx.c deleted file mode 100644 index 7bd2913bd7..0000000000 --- a/driver/tcpm/it83xx.c +++ /dev/null @@ -1,910 +0,0 @@ -/* Copyright 2016 The Chromium OS Authors. All rights reserved. - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ - -/* TCPM for MCU also running TCPC */ - -#include "common.h" -#include "config.h" -#include "console.h" -#include "it83xx_pd.h" -#include "registers.h" -#include "system.h" -#include "task.h" -#include "tcpm/tcpci.h" -#include "timer.h" -#include "util.h" -#include "usb_common.h" -#include "usb_pd.h" -#include "usb_pd_tcpm.h" -#include "hooks.h" - -#ifdef CONFIG_USB_PD_TCPMV1 -#if defined(CONFIG_USB_PD_DUAL_ROLE_AUTO_TOGGLE) || \ - defined(CONFIG_USB_PD_VBUS_DETECT_TCPC) || \ - defined(CONFIG_USB_PD_TCPC_LOW_POWER) || \ - defined(CONFIG_USB_PD_DISCHARGE_TCPC) -#error "Unsupported config options of IT83xx PD driver" -#endif -#endif - -#ifdef CONFIG_USB_PD_TCPMV2 -#if defined(CONFIG_USB_PD_VBUS_DETECT_TCPC) || \ - defined(CONFIG_USB_PD_DISCHARGE_TCPC) -#error "Unsupported config options of IT83xx PD driver" -#endif -#endif - -int rx_en[IT83XX_USBPD_PHY_PORT_COUNT]; -STATIC_IF(CONFIG_USB_PD_DECODE_SOP) - bool sop_prime_en[IT83XX_USBPD_PHY_PORT_COUNT]; - -const struct usbpd_ctrl_t usbpd_ctrl_regs[] = { - {&IT83XX_GPIO_GPCRF4, &IT83XX_GPIO_GPCRF5, IT83XX_IRQ_USBPD0}, - {&IT83XX_GPIO_GPCRH1, &IT83XX_GPIO_GPCRH2, IT83XX_IRQ_USBPD1}, -}; -BUILD_ASSERT(ARRAY_SIZE(usbpd_ctrl_regs) == IT83XX_USBPD_PHY_PORT_COUNT); - -static int it83xx_tcpm_set_rx_enable(int port, int enable); -static int it83xx_tcpm_set_vconn(int port, int enable); - -/* - * Disable cc analog and pd digital module, but only left Rd_5.1K (Not - * Dead Battery) analog module alive to assert Rd on CCs. EC reset or - * calling _init() are able to re-active cc and pd. - */ -void it83xx_Rd_5_1K_only_for_hibernate(int port) -{ - /* This only apply to active PD port */ - if (*usbpd_ctrl_regs[port].cc1 == IT83XX_USBPD_CC_PIN_CONFIG && - *usbpd_ctrl_regs[port].cc2 == IT83XX_USBPD_CC_PIN_CONFIG) { - /* Disable PD PHY */ - IT83XX_USBPD_GCR(port) &= ~(BIT(0) | BIT(4)); - /* - * Disable CCs voltage detector, and - * connect CCs analog module (ex.UP/RD/DET/TX/RX), and - * connect CCs 5.1K to GND - */ - IT83XX_USBPD_CCCSR(port) = 0x22; - /* Disconnect CCs 5V tolerant */ - IT83XX_USBPD_CCPSR(port) |= - (USBPD_REG_MASK_DISCONNECT_POWER_CC2 | - USBPD_REG_MASK_DISCONNECT_POWER_CC1); - /* - * Select Rp reserved value for not current leakage, and - * CCs assert Rd, and - * enable CCs analog module - */ - IT83XX_USBPD_BMCSR(port) &= ~0x08; - IT83XX_USBPD_CCGCR(port) &= ~0x1f; - } -} - -static enum tcpc_cc_voltage_status it83xx_get_cc( - enum usbpd_port port, - enum usbpd_cc_pin cc_pin) -{ - enum usbpd_ufp_volt_status ufp_volt; - enum usbpd_dfp_volt_status dfp_volt; - enum tcpc_cc_voltage_status cc_state = TYPEC_CC_VOLT_OPEN; - int pull; - - pull = (cc_pin == USBPD_CC_PIN_1) ? - USBPD_GET_CC1_PULL_REGISTER_SELECTION(port) : - USBPD_GET_CC2_PULL_REGISTER_SELECTION(port); - - /* select Rp */ - if (pull) - CLEAR_MASK(cc_state, BIT(2)); - /* select Rd */ - else - SET_MASK(cc_state, BIT(2)); - - /* sink */ - if (USBPD_GET_POWER_ROLE(port) == USBPD_POWER_ROLE_CONSUMER) { - if (cc_pin == USBPD_CC_PIN_1) - ufp_volt = IT83XX_USBPD_UFPVDR(port) & 0x7; - else - ufp_volt = (IT83XX_USBPD_UFPVDR(port) >> 4) & 0x7; - - switch (ufp_volt) { - case USBPD_UFP_STATE_SNK_DEF: - cc_state |= (TYPEC_CC_VOLT_RP_DEF & 3); - break; - case USBPD_UFP_STATE_SNK_1_5: - cc_state |= (TYPEC_CC_VOLT_RP_1_5 & 3); - break; - case USBPD_UFP_STATE_SNK_3_0: - cc_state |= (TYPEC_CC_VOLT_RP_3_0 & 3); - break; - case USBPD_UFP_STATE_SNK_OPEN: - cc_state = TYPEC_CC_VOLT_OPEN; - break; - default: - cc_state = TYPEC_CC_VOLT_OPEN; - break; - } - /* source */ - } else { - if (cc_pin == USBPD_CC_PIN_1) - dfp_volt = IT83XX_USBPD_DFPVDR(port) & 0xf; - else - dfp_volt = (IT83XX_USBPD_DFPVDR(port) >> 4) & 0xf; - - switch (dfp_volt) { - case USBPD_DFP_STATE_SRC_RA: - cc_state |= TYPEC_CC_VOLT_RA; - break; - case USBPD_DFP_STATE_SRC_RD: - cc_state |= TYPEC_CC_VOLT_RD; - break; - case USBPD_DFP_STATE_SRC_OPEN: - cc_state = TYPEC_CC_VOLT_OPEN; - break; - default: - cc_state = TYPEC_CC_VOLT_OPEN; - break; - } - } - - return cc_state; -} - -static int it83xx_tcpm_get_message_raw(int port, uint32_t *buf, int *head) -{ - int cnt = PD_HEADER_CNT(IT83XX_USBPD_RMH(port)); - - if (!USBPD_IS_RX_DONE(port)) - return EC_ERROR_UNKNOWN; - - /* store header */ - *head = IT83XX_USBPD_RMH(port); - /* check data message */ - if (cnt) - memcpy(buf, (uint32_t *)&IT83XX_USBPD_RDO0(port), cnt * 4); - - if (IS_ENABLED(CONFIG_USB_PD_DECODE_SOP)) { - int type = USBPD_REG_GET_SOP_TYPE_RX(IT83XX_USBPD_MRSR(port)); - *head |= PD_HEADER_SOP(type); - } - /* - * Note: clear RX done interrupt after get the data. - * If clear this bit, USBPD receives next packet - */ - IT83XX_USBPD_MRSR(port) = USBPD_REG_MASK_RX_MSG_VALID; - - return EC_SUCCESS; -} - -static enum tcpc_transmit_complete it83xx_tx_data( - enum usbpd_port port, - enum tcpci_msg_type type, - uint16_t header, - const uint32_t *buf) -{ - int r; - uint32_t evt; - uint8_t length = PD_HEADER_CNT(header); - - /* set message header */ - IT83XX_USBPD_TMHLR(port) = (uint8_t)header; - IT83XX_USBPD_TMHHR(port) = (header >> 8); - - /* - * SOP type bit[6~4]: - * on bx version and before: - * x00b=SOP, x01b=SOP', x10b=SOP", bit[6] is reserved. - * on dx version: - * 000b=SOP, 001b=SOP', 010b=SOP", 011b=Debug SOP', 100b=Debug SOP''. - */ - IT83XX_USBPD_MTSR1(port) = - (IT83XX_USBPD_MTSR1(port) & ~0x70) | ((type & 0x7) << 4); - /* bit7: transmit message is send to cable or not */ - if (type == TCPCI_MSG_SOP) - IT83XX_USBPD_MTSR0(port) &= ~USBPD_REG_MASK_CABLE_ENABLE; - else - IT83XX_USBPD_MTSR0(port) |= USBPD_REG_MASK_CABLE_ENABLE; - /* clear msg length */ - IT83XX_USBPD_MTSR1(port) &= (~0x7); - /* Limited by PD_HEADER_CNT() */ - ASSERT(length <= 0x7); - - if (length) { - /* set data bit */ - IT83XX_USBPD_MTSR0(port) |= BIT(4); - /* set data length setting */ - IT83XX_USBPD_MTSR1(port) |= length; - /* set data */ - memcpy((uint32_t *)&IT83XX_USBPD_TDO(port), buf, length * 4); - } - - for (r = 0; r <= CONFIG_PD_RETRY_COUNT; r++) { - /* Start TX */ - USBPD_KICK_TX_START(port); - evt = task_wait_event_mask(TASK_EVENT_PHY_TX_DONE, - PD_T_TCPC_TX_TIMEOUT); - /* check TX status */ - if (USBPD_IS_TX_ERR(port) || (evt & TASK_EVENT_TIMER)) { - /* - * If discard, means HW doesn't send the msg and resend. - */ - if (USBPD_IS_TX_DISCARD(port)) - continue; - /* - * Or port partner doesn't respond GoodCRC - */ - else - return TCPC_TX_COMPLETE_FAILED; - } else { - break; - } - } - - if (r > CONFIG_PD_RETRY_COUNT) - return TCPC_TX_COMPLETE_DISCARDED; - - return TCPC_TX_COMPLETE_SUCCESS; -} - -static enum tcpc_transmit_complete it83xx_send_hw_reset(enum usbpd_port port, - enum tcpci_msg_type reset_type) -{ - if (reset_type == TCPCI_MSG_CABLE_RESET) - IT83XX_USBPD_MTSR0(port) |= USBPD_REG_MASK_CABLE_ENABLE; - else - IT83XX_USBPD_MTSR0(port) &= ~USBPD_REG_MASK_CABLE_ENABLE; - - /* send hard reset */ - USBPD_SEND_HARD_RESET(port); - usleep(MSEC); - - if (USBPD_IS_HARD_CABLE_RESET_TX_DONE(port)) { - IT83XX_USBPD_ISR(port) = - USBPD_REG_MASK_HARD_CABLE_RESET_TX_DONE; - return TCPC_TX_COMPLETE_SUCCESS; - } - - return TCPC_TX_COMPLETE_FAILED; -} - -static void it83xx_send_bist_mode2_pattern(enum usbpd_port port) -{ - USBPD_ENABLE_SEND_BIST_MODE_2(port); - usleep(PD_T_BIST_TRANSMIT); - USBPD_DISABLE_SEND_BIST_MODE_2(port); -} - -static void it83xx_enable_vconn(enum usbpd_port port, int enabled) -{ - enum usbpd_cc_pin cc_pin; - - if (USBPD_GET_PULL_CC_SELECTION(port)) - cc_pin = USBPD_CC_PIN_1; - else - cc_pin = USBPD_CC_PIN_2; - - if (enabled) { - /* Disable unused CC to become VCONN */ - if (cc_pin == USBPD_CC_PIN_1) { - IT83XX_USBPD_CCCSR(port) = USBPD_CC2_DISCONNECTED(port); - IT83XX_USBPD_CCPSR(port) = (IT83XX_USBPD_CCPSR(port) - & ~USBPD_REG_MASK_DISCONNECT_POWER_CC2) - | USBPD_REG_MASK_DISCONNECT_POWER_CC1; - } else { - IT83XX_USBPD_CCCSR(port) = USBPD_CC1_DISCONNECTED(port); - IT83XX_USBPD_CCPSR(port) = (IT83XX_USBPD_CCPSR(port) - & ~USBPD_REG_MASK_DISCONNECT_POWER_CC1) - | USBPD_REG_MASK_DISCONNECT_POWER_CC2; - } - } else { - /* Enable cc1 and cc2 */ - IT83XX_USBPD_CCCSR(port) &= ~0xaa; - IT83XX_USBPD_CCPSR(port) |= - (USBPD_REG_MASK_DISCONNECT_POWER_CC1 | - USBPD_REG_MASK_DISCONNECT_POWER_CC2); - } -} - -static void it83xx_enable_cc(enum usbpd_port port, int enable) -{ - if (enable) - CLEAR_MASK(IT83XX_USBPD_CCGCR(port), BIT(4)); - else - SET_MASK(IT83XX_USBPD_CCGCR(port), BIT(4)); -} - -static void it83xx_set_power_role(enum usbpd_port port, int power_role) -{ - /* PD_ROLE_SINK 0, PD_ROLE_SOURCE 1 */ - if (power_role == PD_ROLE_SOURCE) { - /* - * bit[2,3] BMC Rx threshold setting - * 00b: power neutral - * 01b: sinking power => - * High to low Y3Rx threshold = 0.38, - * Low to high Y3Rx threshold = 0.54. - * 10b: sourcing power => - * High to low Y3Rx threshold = 0.64, - * Low to high Y3Rx threshold = 0.79. - */ - IT83XX_USBPD_CCADCR(port) = 0x08; - /* bit0: source */ - SET_MASK(IT83XX_USBPD_PDMSR(port), BIT(0)); - /* bit1: CC1 select Rp */ - SET_MASK(IT83XX_USBPD_CCGCR(port), BIT(1)); - /* bit3: CC2 select Rp */ - SET_MASK(IT83XX_USBPD_BMCSR(port), BIT(3)); - } else { - /* - * bit[2,3] BMC Rx threshold setting - * 00b: power neutral - * 01b: sinking power => - * High to low Y3Rx threshold = 0.38, - * Low to high Y3Rx threshold = 0.54 - * 10b: sourcing power => - * High to low Y3Rx threshold = 0.64, - * Low to high Y3Rx threshold = 0.79 - */ - IT83XX_USBPD_CCADCR(port) = 0x04; - /* bit0: sink */ - CLEAR_MASK(IT83XX_USBPD_PDMSR(port), BIT(0)); - /* bit1: CC1 select Rd */ - CLEAR_MASK(IT83XX_USBPD_CCGCR(port), BIT(1)); - /* bit3: CC2 select Rd */ - CLEAR_MASK(IT83XX_USBPD_BMCSR(port), BIT(3)); - } -} - -static void it83xx_set_data_role(enum usbpd_port port, int pd_role) -{ - /* 0: PD_ROLE_UFP 1: PD_ROLE_DFP */ - IT83XX_USBPD_PDMSR(port) = - (IT83XX_USBPD_PDMSR(port) & ~0xc) | ((pd_role & 0x1) << 2); -} - -#ifdef CONFIG_USB_PD_FRS_TCPC -static int it83xx_tcpm_set_frs_enable(int port, int enable) -{ - uint8_t mask = (USBPD_REG_FAST_SWAP_REQUEST_ENABLE | - USBPD_REG_FAST_SWAP_DETECT_ENABLE); - - if (enable) { - /* - * Disable HW auto turn off FRS requestion and detection - * when we receive soft or hard reset. - */ - IT83XX_USBPD_PDPSR(port) &= ~USBPD_REG_MASK_AUTO_FRS_DISABLE; - /* W/C status */ - IT83XX_USBPD_PD30IR(port) = 0x3f; - /* Enable FRS detection (cc to GND) interrupt */ - IT83XX_USBPD_MPD30IR(port) &= ~(USBPD_REG_MASK_PD30_ISR | - USBPD_REG_MASK_FAST_SWAP_DETECT_ISR); - /* Enable FRS detection (cc to GND) */ - IT83XX_USBPD_PDQSCR(port) = (IT83XX_USBPD_PDQSCR(port) & ~mask) - | USBPD_REG_FAST_SWAP_DETECT_ENABLE; - } else { - /* Disable FRS detection (cc to GND) interrupt */ - IT83XX_USBPD_MPD30IR(port) |= (USBPD_REG_MASK_PD30_ISR | - USBPD_REG_MASK_FAST_SWAP_DETECT_ISR); - /* Disable FRS detection and requestion */ - IT83XX_USBPD_PDQSCR(port) &= ~mask; - } - - return EC_SUCCESS; -} -#endif - -static void it83xx_init(enum usbpd_port port, int role) -{ -#ifdef IT83XX_USBPD_CC_PARAMETER_RELOAD - /* bit7: Reload CC parameter setting. */ - IT83XX_USBPD_CCPSR0(port) |= BIT(7); -#endif - /* reset and disable HW auto generate message header */ - IT83XX_USBPD_GCR(port) = BIT(5); - USBPD_SW_RESET(port); - /* - * According PD version set the total number of HW attempts - * (= retry count + 1) - */ - IT83XX_USBPD_BMCSR(port) = (IT83XX_USBPD_BMCSR(port) & ~0x70) | - ((CONFIG_PD_RETRY_COUNT + 1) << 4); - /* Disable Rx decode */ - it83xx_tcpm_set_rx_enable(port, 0); - if (IS_ENABLED(CONFIG_USB_PD_TCPMV1)) { - uint8_t flags = 0; - /* - * If explicit contract is set in bbram when EC boot up, then - * TCPMv1 set soft reset as first state instead of - * unattached.SNK, so we need to enable BMC PHY for tx module. - * - * NOTE: If the platform is without battery and connects to - * adapter, then cold reset EC, our Rd is always asserted on cc, - * so adapter keeps providing 5v and data in BBRAM are still - * alive. - */ - if ((pd_get_saved_port_flags(port, &flags) == EC_SUCCESS) && - (flags & PD_BBRMFLG_EXPLICIT_CONTRACT)) - USBPD_ENABLE_BMC_PHY(port); - } - /* W/C status */ - IT83XX_USBPD_ISR(port) = 0xff; - /* enable cc, select cc1 and Rd. */ - IT83XX_USBPD_CCGCR(port) = 0xd; - /* change data role as the same power role */ - it83xx_set_data_role(port, role); - /* set power role */ - it83xx_set_power_role(port, role); - /* disable all interrupts */ - IT83XX_USBPD_IMR(port) = 0xff; - /* enable tx done and reset detect interrupt */ - IT83XX_USBPD_IMR(port) &= ~(USBPD_REG_MASK_MSG_TX_DONE | - USBPD_REG_MASK_HARD_RESET_DETECT); -#ifdef IT83XX_INTC_PLUG_IN_OUT_SUPPORT - /* - * when tcpc detect type-c plug in (cc lines voltage change), it will - * interrupt fw to wake pd task, so task can react immediately. - * - * w/c status and unmask TCDCR (detect type-c plug in interrupt default - * is enable). - */ - IT83XX_USBPD_TCDCR(port) = USBPD_REG_PLUG_IN_OUT_DETECT_STAT; -#endif - /* cc connect */ - IT83XX_USBPD_CCCSR(port) = 0; - /* disable vconn */ - it83xx_tcpm_set_vconn(port, 0); - /* TX start from high */ - IT83XX_USBPD_CCADCR(port) |= BIT(6); - /* enable cc1/cc2 */ - *usbpd_ctrl_regs[port].cc1 = IT83XX_USBPD_CC_PIN_CONFIG; - *usbpd_ctrl_regs[port].cc2 = IT83XX_USBPD_CC_PIN_CONFIG; - task_clear_pending_irq(usbpd_ctrl_regs[port].irq); - task_enable_irq(usbpd_ctrl_regs[port].irq); - USBPD_START(port); - /* - * Disconnect CCs Rd_DB from GND - * NOTE: CCs assert both Rd_5.1k and Rd_DB from USBPD_START() to - * disconnect Rd_DB about 1.5us. - */ - IT83XX_USBPD_CCPSR(port) |= (USBPD_REG_MASK_DISCONNECT_5_1K_CC2_DB | - USBPD_REG_MASK_DISCONNECT_5_1K_CC1_DB); -} - -static void it83xx_select_polarity(enum usbpd_port port, - enum usbpd_cc_pin cc_pin) -{ - /* cc1/cc2 selection */ - if (cc_pin == USBPD_CC_PIN_1) - SET_MASK(IT83XX_USBPD_CCGCR(port), BIT(0)); - else - CLEAR_MASK(IT83XX_USBPD_CCGCR(port), BIT(0)); -} - -static int it83xx_set_cc(enum usbpd_port port, int pull) -{ - int enable_cc = 1; - - switch (pull) { - case TYPEC_CC_RD: - it83xx_set_power_role(port, PD_ROLE_SINK); - break; - case TYPEC_CC_RP: - it83xx_set_power_role(port, PD_ROLE_SOURCE); - break; - case TYPEC_CC_OPEN: - /* Power-down CC1 & CC2 to remove Rp/Rd */ - enable_cc = 0; - break; - default: - return EC_ERROR_UNIMPLEMENTED; - } - - it83xx_enable_cc(port, enable_cc); - return EC_SUCCESS; -} - -static int it83xx_tcpm_init(int port) -{ - /* Initialize physical layer */ - it83xx_init(port, PD_ROLE_DEFAULT(port)); - - return EC_SUCCESS; -} - -static int it83xx_tcpm_release(int port) -{ - return EC_ERROR_UNIMPLEMENTED; -} - -static int it83xx_tcpm_get_cc(int port, enum tcpc_cc_voltage_status *cc1, - enum tcpc_cc_voltage_status *cc2) -{ - *cc2 = it83xx_get_cc(port, USBPD_CC_PIN_2); - *cc1 = it83xx_get_cc(port, USBPD_CC_PIN_1); - - return EC_SUCCESS; -} - -static int it83xx_tcpm_select_rp_value(int port, int rp_sel) -{ - uint8_t rp; - - /* Keep track of current RP value */ - tcpci_set_cached_rp(port, rp_sel); - - /* - * bit[3-2]: CC output current (when Rp selected) - * 00: reserved - * 01: 330uA outpt (3.0A) - * 10: 180uA outpt (1.5A) - * 11: 80uA outpt (USB default) - */ - switch (rp_sel) { - case TYPEC_RP_1A5: - rp = 2 << 2; - break; - case TYPEC_RP_3A0: - rp = BIT(2); - break; - case TYPEC_RP_USB: - default: - rp = 3 << 2; - break; - } - IT83XX_USBPD_CCGCR(port) = (IT83XX_USBPD_CCGCR(port) & ~(3 << 2)) | rp; - - return EC_SUCCESS; -} - -static int it83xx_tcpm_set_cc(int port, int pull) -{ - return it83xx_set_cc(port, pull); -} - -static int it83xx_tcpm_set_polarity(int port, enum tcpc_cc_polarity polarity) -{ - enum usbpd_cc_pin cc_pin = - (polarity == POLARITY_CC1 || polarity == POLARITY_CC1_DTS) ? - USBPD_CC_PIN_1 : USBPD_CC_PIN_2; - - it83xx_select_polarity(port, cc_pin); - - return EC_SUCCESS; -} - -__maybe_unused static int it83xx_tcpm_decode_sop_prime_enable(int port, - bool enable) -{ - /* Save SOP'/SOP'' enable state */ - sop_prime_en[port] = enable; - - if (rx_en[port]) { - if (enable) - IT83XX_USBPD_PDMSR(port) |= - (USBPD_REG_MASK_SOPP_ENABLE | - USBPD_REG_MASK_SOPPP_ENABLE); - else - IT83XX_USBPD_PDMSR(port) &= - ~(USBPD_REG_MASK_SOPP_ENABLE | - USBPD_REG_MASK_SOPPP_ENABLE); - } - - return EC_SUCCESS; -} - -static int it83xx_tcpm_set_vconn(int port, int enable) -{ - /* - * IT83XX doesn't have integrated circuit to source CC lines for VCONN. - * An external device like PPC or Power Switch has to source the VCONN. - */ - if (IS_ENABLED(CONFIG_USBC_VCONN)) { - if (enable) { - /* - * Unused cc will become Vconn SRC, disable cc analog - * module (ex.UP/RD/DET/Tx/Rx) and enable 5v tolerant. - */ - it83xx_enable_vconn(port, enable); - if (IS_ENABLED(CONFIG_USB_PD_DECODE_SOP)) - /* Enable tcpc receive SOP' and SOP'' packet */ - it83xx_tcpm_decode_sop_prime_enable(port, true); - /* Turn on Vconn power switch. */ - board_pd_vconn_ctrl(port, - USBPD_GET_PULL_CC_SELECTION(port) ? - USBPD_CC_PIN_2 : USBPD_CC_PIN_1, - enable); - } else { - /* - * If the pd port has previous connection and supplies - * Vconn, then RO jumping to RW reset the system, - * we never know which cc is the previous Vconn pin, - * so we always turn both cc pins off when disable - * Vconn power switch. - */ - board_pd_vconn_ctrl(port, USBPD_CC_PIN_1, enable); - board_pd_vconn_ctrl(port, USBPD_CC_PIN_2, enable); - /* Disable tcpc receive SOP' and SOP'' packet */ - if (IS_ENABLED(CONFIG_USB_PD_DECODE_SOP)) - it83xx_tcpm_decode_sop_prime_enable(port, - false); - /* - * Before disabling cc 5v tolerant, we need to make - * sure cc voltage detector is enabled and Vconn is - * dropped below 3.3v (>500us) to avoid the potential - * risk of voltage fed back into Vcore. - */ - usleep(IT83XX_USBPD_T_VCONN_BELOW_3_3V); - /* - * Since our cc are not Vconn SRC, enable cc analog - * module (ex.UP/RD/DET/Tx/Rx) and disable 5v tolerant. - */ - it83xx_enable_vconn(port, enable); - } - } - - return EC_SUCCESS; -} - -static int it83xx_tcpm_set_msg_header(int port, int power_role, int data_role) -{ - /* PD_ROLE_SINK 0, PD_ROLE_SOURCE 1 */ - if (power_role == PD_ROLE_SOURCE) - /* bit0: source */ - SET_MASK(IT83XX_USBPD_PDMSR(port), BIT(0)); - else - /* bit0: sink */ - CLEAR_MASK(IT83XX_USBPD_PDMSR(port), BIT(0)); - - it83xx_set_data_role(port, data_role); - - return EC_SUCCESS; -} - -static int it83xx_tcpm_set_rx_enable(int port, int enable) -{ - /* Save rx_on */ - rx_en[port] = enable; - - if (enable) { - IT83XX_USBPD_IMR(port) &= ~USBPD_REG_MASK_MSG_RX_DONE; - IT83XX_USBPD_PDMSR(port) |= USBPD_REG_MASK_SOP_ENABLE; - IT83XX_USBPD_VDMMCSR(port) |= USBPD_REG_MASK_HARD_RESET_DECODE; - if (IS_ENABLED(CONFIG_USB_PD_DECODE_SOP)) - it83xx_tcpm_decode_sop_prime_enable(port, - sop_prime_en[port]); - } else { - IT83XX_USBPD_IMR(port) |= USBPD_REG_MASK_MSG_RX_DONE; - IT83XX_USBPD_PDMSR(port) &= ~(USBPD_REG_MASK_SOP_ENABLE | - USBPD_REG_MASK_SOPP_ENABLE | - USBPD_REG_MASK_SOPPP_ENABLE); - IT83XX_USBPD_VDMMCSR(port) &= ~USBPD_REG_MASK_HARD_RESET_DECODE; - } - - return EC_SUCCESS; -} - -static int it83xx_tcpm_transmit(int port, - enum tcpci_msg_type type, - uint16_t header, - const uint32_t *data) -{ - int status = TCPC_TX_COMPLETE_FAILED; - - switch (type) { - case TCPCI_MSG_SOP: - case TCPCI_MSG_SOP_PRIME: - case TCPCI_MSG_SOP_PRIME_PRIME: - case TCPCI_MSG_SOP_DEBUG_PRIME: - case TCPCI_MSG_SOP_DEBUG_PRIME_PRIME: - status = it83xx_tx_data(port, - type, - header, - data); - break; - case TCPCI_MSG_TX_BIST_MODE_2: - it83xx_send_bist_mode2_pattern(port); - status = TCPC_TX_COMPLETE_SUCCESS; - break; - case TCPCI_MSG_TX_HARD_RESET: - case TCPCI_MSG_CABLE_RESET: - status = it83xx_send_hw_reset(port, type); - break; - default: - status = TCPC_TX_COMPLETE_FAILED; - break; - } - pd_transmit_complete(port, status); - - return EC_SUCCESS; -} - -static int it83xx_tcpm_get_chip_info(int port, int live, - struct ec_response_pd_chip_info_v1 *chip_info) -{ - chip_info->vendor_id = USB_VID_ITE; - chip_info->product_id = ((IT83XX_GCTRL_CHIPID1 << 8) | - IT83XX_GCTRL_CHIPID2); - chip_info->device_id = IT83XX_GCTRL_CHIPVER & 0xf; - chip_info->fw_version_number = 0xEC; - - return EC_SUCCESS; -} - -#ifdef CONFIG_USB_PD_TCPC_LOW_POWER -static int it83xx_tcpm_enter_low_power_mode(int port) -{ - /* - * ITE embedded TCPC SLEEP_MASK_USB_PD flag is only controlled by - * it83xx driver in set_pd_sleep_mask(), and do low power mode in - * idle_task(). - * In deep sleep mode, ITE TCPC clock is turned off, and the - * timer every 5ms to exit the mode and wakeup PD task to run - * (ex. change the CC lines termination). - */ - return EC_SUCCESS; -} -#endif - -static void it83xx_tcpm_switch_plug_out_type(int port) -{ - enum tcpc_cc_voltage_status cc1, cc2; - - /* Check what do we and partner cc assert */ - it83xx_tcpm_get_cc(port, &cc1, &cc2); - - if ((cc1 == TYPEC_CC_VOLT_RD && cc2 == TYPEC_CC_VOLT_RD) || - (cc1 == TYPEC_CC_VOLT_RA && cc2 == TYPEC_CC_VOLT_RA)) - /* We're source, switch to detect audio/debug plug out. */ - IT83XX_USBPD_TCDCR(port) = (IT83XX_USBPD_TCDCR(port) & - ~USBPD_REG_PLUG_IN_OUT_DETECT_DISABLE) | - USBPD_REG_PLUG_OUT_DETECT_TYPE_SELECT | - USBPD_REG_PLUG_OUT_SELECT; - else if (cc1 == TYPEC_CC_VOLT_RD || cc2 == TYPEC_CC_VOLT_RD) - /* We're source, switch to detect sink plug out. */ - IT83XX_USBPD_TCDCR(port) = (IT83XX_USBPD_TCDCR(port) & - ~USBPD_REG_PLUG_IN_OUT_DETECT_DISABLE & - ~USBPD_REG_PLUG_OUT_DETECT_TYPE_SELECT) | - USBPD_REG_PLUG_OUT_SELECT; - else if (cc1 >= TYPEC_CC_VOLT_RP_DEF || cc2 >= TYPEC_CC_VOLT_RP_DEF) - /* - * We're sink, disable detect interrupt, so messages on cc line - * won't trigger interrupt. - * NOTE: Plug out is detected by TCPM polling Vbus. - */ - IT83XX_USBPD_TCDCR(port) |= - USBPD_REG_PLUG_IN_OUT_DETECT_DISABLE; - /* - * If not above cases, plug in interrupt will fire again, - * and call switch_plug_out_type() to set the right state. - */ -} - -void switch_plug_out_type(enum usbpd_port port) -{ - it83xx_tcpm_switch_plug_out_type(port); -} - -void set_pd_sleep_mask(int port) -{ - int i; - bool prevent_deep_sleep = false; - - /* - * Set SLEEP_MASK_USB_PD for deep sleep mode: - * 1.Enable deep sleep mode, when all ITE ports are in Unattach.SRC/SNK - * state (HOOK_DISCONNECT called) and other ports aren't pd_capable(). - * 2.Disable deep sleep mode, when one of ITE port is in Attach.SRC/SNK - * state (HOOK_CONNECT called) or one of other ports is pd_capable(). - */ - for (i = 0; i < CONFIG_USB_PD_ITE_ACTIVE_PORT_COUNT; ++i) { - if (IT83XX_USBPD_GCR(i) & USBPD_REG_MASK_BMC_PHY) { - prevent_deep_sleep = true; - break; - } - } - - /* - * Check if any other ports have a PD port partner connected. Deep - * sleep is forbidden if any PD port partner is connected. Above, we - * only checked for the ITE ports. - */ - if (!prevent_deep_sleep) { - for (; i < board_get_usb_pd_port_count(); i++) - if (pd_capable(i)) - prevent_deep_sleep = true; - } - - if (prevent_deep_sleep) - disable_sleep(SLEEP_MASK_USB_PD); - else - enable_sleep(SLEEP_MASK_USB_PD); -} - -static void it83xx_tcpm_hook_connect(void) -{ - int port = TASK_ID_TO_PD_PORT(task_get_current()); - -#ifdef CONFIG_USB_PD_TCPMV2 - /* - * There are five cases that hook_connect() be called by TCPMv2: - * 1)AttachWait.SNK -> Attached.SNK: disable detect interrupt. - * 2)AttachWait.SRC -> Attached.SRC: enable detect plug out. - * 3)AttachWait.SNK -> Try.SRC -> TryWait.SNK -> Attached.SNK: we do - * Try.SRC fail, disable detect interrupt. - * 4)AttachWait.SNK -> Try.SRC -> Attached.SRC: we do Try.SRC - * successfully, need to switch to detect plug out. - * 5)Attached.SRC -> TryWait.SNK -> Attached.SNK: partner do Try.SRC - * successfully, disable detect interrupt. - * - * NOTE: Try.SRC and TryWait.SNK are embedded respectively in - * SRC_DISCONNECT and SNK_DISCONNECT in TCPMv1. Every time we go to - * Try.SRC/TryWait.SNK state, the plug in interrupt will be enabled and - * fire for 3), 4), 5) cases, then set correctly for the SRC detect plug - * out or the SNK disable detect, so TCPMv1 needn't this. - */ - it83xx_tcpm_switch_plug_out_type(port); -#endif - /* Enable PD PHY Tx and Rx module since type-c has connected. */ - USBPD_ENABLE_BMC_PHY(port); - set_pd_sleep_mask(port); -} - -DECLARE_HOOK(HOOK_USB_PD_CONNECT, it83xx_tcpm_hook_connect, HOOK_PRIO_DEFAULT); - -static void it83xx_tcpm_hook_disconnect(void) -{ - int port = TASK_ID_TO_PD_PORT(task_get_current()); - - if (IS_ENABLED(IT83XX_INTC_PLUG_IN_OUT_SUPPORT)) - /* - * Switch to detect plug in and enable detect plug in interrupt, - * since pd task has detected a type-c physical disconnected. - */ - IT83XX_USBPD_TCDCR(port) &= ~(USBPD_REG_PLUG_OUT_SELECT | - USBPD_REG_PLUG_IN_OUT_DETECT_DISABLE); - - /* exit BIST test data mode */ - USBPD_SW_RESET(port); - - /* - * Init rx status and disable PD PHY Tx and Rx module for better power - * consumption since type-c has disconnected. - */ - rx_en[port] = 0; - if (IS_ENABLED(CONFIG_USB_PD_DECODE_SOP)) - sop_prime_en[port] = 0; - USBPD_DISABLE_BMC_PHY(port); - set_pd_sleep_mask(port); -} - -DECLARE_HOOK(HOOK_USB_PD_DISCONNECT, it83xx_tcpm_hook_disconnect, - HOOK_PRIO_DEFAULT); - -const struct tcpm_drv it83xx_tcpm_drv = { - .init = &it83xx_tcpm_init, - .release = &it83xx_tcpm_release, - .get_cc = &it83xx_tcpm_get_cc, - .select_rp_value = &it83xx_tcpm_select_rp_value, - .set_cc = &it83xx_tcpm_set_cc, - .set_polarity = &it83xx_tcpm_set_polarity, -#ifdef CONFIG_USB_PD_DECODE_SOP - .sop_prime_enable = &it83xx_tcpm_decode_sop_prime_enable, -#endif - .set_vconn = &it83xx_tcpm_set_vconn, - .set_msg_header = &it83xx_tcpm_set_msg_header, - .set_rx_enable = &it83xx_tcpm_set_rx_enable, - .get_message_raw = &it83xx_tcpm_get_message_raw, - .transmit = &it83xx_tcpm_transmit, -#ifdef CONFIG_USB_PD_DUAL_ROLE_AUTO_TOGGLE - .drp_toggle = NULL, -#endif - .get_chip_info = &it83xx_tcpm_get_chip_info, -#ifdef CONFIG_USB_PD_TCPC_LOW_POWER - .enter_low_power_mode = &it83xx_tcpm_enter_low_power_mode, -#endif -#ifdef CONFIG_USB_PD_FRS_TCPC - .set_frs_enable = &it83xx_tcpm_set_frs_enable, -#endif -}; diff --git a/driver/tcpm/it83xx_pd.h b/driver/tcpm/it83xx_pd.h deleted file mode 100644 index ff7c231f23..0000000000 --- a/driver/tcpm/it83xx_pd.h +++ /dev/null @@ -1,458 +0,0 @@ -/* Copyright 2016 The Chromium OS Authors. All rights reserved. - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ - -/* USB Power delivery port management */ -#ifndef __CROS_EC_DRIVER_TCPM_IT83XX_H -#define __CROS_EC_DRIVER_TCPM_IT83XX_H - -#include "driver/tcpm/it8xxx2_pd_public.h" - -/* USBPD Controller */ -#if defined(CONFIG_USB_PD_TCPM_DRIVER_IT83XX) -#define IT83XX_USBPD_BASE(port) (0x00F03700 + (0x100 * (port))) - -#define IT83XX_USBPD_GCR(p) REG8(IT83XX_USBPD_BASE(p)+0x0) -#define USBPD_REG_MASK_SW_RESET_BIT BIT(7) -#define USBPD_REG_MASK_TYPE_C_DETECT_RESET BIT(6) -#define USBPD_REG_MASK_BMC_PHY BIT(4) -#define USBPD_REG_MASK_AUTO_SEND_SW_RESET BIT(3) -#define USBPD_REG_MASK_AUTO_SEND_HW_RESET BIT(2) -#define USBPD_REG_MASK_SNIFFER_MODE BIT(1) -#define USBPD_REG_MASK_GLOBAL_ENABLE BIT(0) -#define IT83XX_USBPD_PDMSR(p) REG8(IT83XX_USBPD_BASE(p)+0x01) -#define USBPD_REG_MASK_SOPPP_ENABLE BIT(7) -#define USBPD_REG_MASK_SOPP_ENABLE BIT(6) -#define USBPD_REG_MASK_SOP_ENABLE BIT(5) -#define IT83XX_USBPD_CCGCR(p) REG8(IT83XX_USBPD_BASE(p)+0x04) -#define USBPD_REG_MASK_DISABLE_CC BIT(4) -#define IT83XX_USBPD_CCCSR(p) REG8(IT83XX_USBPD_BASE(p)+0x05) -#define USBPD_REG_MASK_CC2_DISCONNECT BIT(7) -#define USBPD_REG_MASK_CC2_DISCONNECT_5_1K_TO_GND BIT(6) -#define USBPD_REG_MASK_CC1_DISCONNECT BIT(3) -#define USBPD_REG_MASK_CC1_DISCONNECT_5_1K_TO_GND BIT(2) -#ifdef IT83XX_USBPD_CC_VOLTAGE_DETECTOR_INDEPENDENT -#define USBPD_REG_MASK_DISABLE_CC_VOL_DETECTOR (BIT(5) | BIT(1)) -#else -#define USBPD_REG_MASK_DISABLE_CC_VOL_DETECTOR BIT(1) -#endif -#define IT83XX_USBPD_CCPSR(p) REG8(IT83XX_USBPD_BASE(p)+0x06) -#define USBPD_REG_MASK_DISCONNECT_5_1K_CC2_DB BIT(6) -#define USBPD_REG_MASK_DISCONNECT_POWER_CC2 BIT(5) -#define USBPD_REG_MASK_DISCONNECT_5_1K_CC1_DB BIT(2) -#define USBPD_REG_MASK_DISCONNECT_POWER_CC1 BIT(1) -#define IT83XX_USBPD_DFPVDR(p) REG8(IT83XX_USBPD_BASE(p)+0x08) -#define IT83XX_USBPD_UFPVDR(p) REG8(IT83XX_USBPD_BASE(p)+0x09) -#define IT83XX_USBPD_PDPSR(p) REG8(IT83XX_USBPD_BASE(p)+0x0B) -#define USBPD_REG_MASK_AUTO_FRS_DISABLE BIT(7) -#define IT83XX_USBPD_CCADCR(p) REG8(IT83XX_USBPD_BASE(p)+0x0C) -#define IT83XX_USBPD_ISR(p) REG8(IT83XX_USBPD_BASE(p)+0x14) -#define USBPD_REG_MASK_TYPE_C_DETECT BIT(7) -#define USBPD_REG_MASK_CABLE_RESET_DETECT BIT(6) -#define USBPD_REG_MASK_HARD_RESET_DETECT BIT(5) -#define USBPD_REG_MASK_MSG_RX_DONE BIT(4) -#define USBPD_REG_MASK_AUTO_SOFT_RESET_TX_DONE BIT(3) -#define USBPD_REG_MASK_HARD_CABLE_RESET_TX_DONE BIT(2) -#define USBPD_REG_MASK_MSG_TX_DONE BIT(1) -#define USBPD_REG_MASK_TIMER_TIMEOUT BIT(0) -#define IT83XX_USBPD_IMR(p) REG8(IT83XX_USBPD_BASE(p)+0x15) -#define IT83XX_USBPD_MTCR(p) REG8(IT83XX_USBPD_BASE(p)+0x18) -#define USBPD_REG_MASK_SW_RESET_TX_STAT BIT(3) -#define USBPD_REG_MASK_TX_BUSY_STAT BIT(2) -#define USBPD_REG_MASK_TX_DISCARD_STAT BIT(2) -#ifdef IT83XX_PD_TX_ERROR_STATUS_BIT5 -#define USBPD_REG_MASK_TX_ERR_STAT BIT(5) -#else -#define USBPD_REG_MASK_TX_ERR_STAT BIT(1) -#endif -#define USBPD_REG_MASK_TX_START BIT(0) -#define IT83XX_USBPD_MTSR0(p) REG8(IT83XX_USBPD_BASE(p)+0x19) -#define USBPD_REG_MASK_CABLE_ENABLE BIT(7) -#define USBPD_REG_MASK_SEND_HW_RESET BIT(6) -#define USBPD_REG_MASK_SEND_BIST_MODE_2 BIT(5) -#define IT83XX_USBPD_MTSR1(p) REG8(IT83XX_USBPD_BASE(p)+0x1A) -#define IT83XX_USBPD_VDMMCSR(p) REG8(IT83XX_USBPD_BASE(p)+0x1B) -#define USBPD_REG_MASK_HARD_RESET_DECODE BIT(0) -#define IT83XX_USBPD_MRSR(p) REG8(IT83XX_USBPD_BASE(p)+0x1C) -#define USBPD_REG_GET_SOP_TYPE_RX(mrsr) (((mrsr) >> 4) & 0x7) -#define USBPD_REG_MASK_RX_MSG_VALID BIT(0) -#define IT83XX_USBPD_PEFSMR(p) REG8(IT83XX_USBPD_BASE(p)+0x1D) -#define IT83XX_USBPD_PES0R(p) REG8(IT83XX_USBPD_BASE(p)+0x1E) -#define IT83XX_USBPD_PES1R(p) REG8(IT83XX_USBPD_BASE(p)+0x1F) -#define IT83XX_USBPD_TDO(p) REG32(IT83XX_USBPD_BASE(p)+0x20) -#define IT83XX_USBPD_AGTMHLR(p) REG8(IT83XX_USBPD_BASE(p)+0x3C) -#define IT83XX_USBPD_AGTMHHR(p) REG8(IT83XX_USBPD_BASE(p)+0x3D) -#define IT83XX_USBPD_TMHLR(p) REG8(IT83XX_USBPD_BASE(p)+0x3E) -#define IT83XX_USBPD_TMHHR(p) REG8(IT83XX_USBPD_BASE(p)+0x3F) -#define IT83XX_USBPD_RDO0(p) REG32(IT83XX_USBPD_BASE(p)+0x40) -#define IT83XX_USBPD_RMH(p) REG16(IT83XX_USBPD_BASE(p)+0x5E) -#define IT83XX_USBPD_CCPSR0(p) REG8(IT83XX_USBPD_BASE(p)+0x60) -#define IT83XX_USBPD_BMCSR(p) REG8(IT83XX_USBPD_BASE(p)+0x64) -#define IT83XX_USBPD_PDMHSR(p) REG8(IT83XX_USBPD_BASE(p)+0x65) -#define IT83XX_USBPD_TCDCR(p) REG8(IT83XX_USBPD_BASE(p)+0x67) -#define USBPD_REG_PLUG_OUT_DETECT_TYPE_SELECT BIT(7) -#define USBPD_REG_MASK_TYPEC_PLUG_IN_OUT_ISR BIT(4) -#define USBPD_REG_PLUG_OUT_SELECT BIT(3) -#define USBPD_REG_PLUG_IN_OUT_DETECT_DISABLE BIT(1) -#define USBPD_REG_PLUG_IN_OUT_DETECT_STAT BIT(0) -#define IT83XX_USBPD_PDQSCR(p) REG8(IT83XX_USBPD_BASE(p)+0x70) -#define USBPD_REG_FAST_SWAP_REQUEST_ENABLE BIT(1) -#define USBPD_REG_FAST_SWAP_DETECT_ENABLE BIT(0) -#define IT83XX_USBPD_PD30IR(p) REG8(IT83XX_USBPD_BASE(p)+0x78) -#define USBPD_REG_FAST_SWAP_DETECT_STAT BIT(4) -#define IT83XX_USBPD_MPD30IR(p) REG8(IT83XX_USBPD_BASE(p)+0x7A) -#define USBPD_REG_MASK_PD30_ISR BIT(7) -#define USBPD_REG_MASK_FAST_SWAP_DETECT_ISR BIT(4) - -#elif defined(CONFIG_USB_PD_TCPM_DRIVER_IT8XXX2) -#define IT83XX_USBPD_BASE(port) (0x00F03700 + (0x100 * (port) * (port))) - -#define IT83XX_USBPD_PDGCR(p) REG8(IT83XX_USBPD_BASE(p)+0x0) -#define USBPD_REG_MASK_SW_RESET_BIT BIT(7) -#define USBPD_REG_MASK_PROTOCOL_STATE_CLEAR BIT(6) -#define USBPD_REG_MASK_BIST_DATA_MODE BIT(4) -#define USBPD_REG_MASK_AUTO_BIST_RESPONSE BIT(3) -#define USBPD_REG_MASK_TX_MESSAGE_ENABLE BIT(2) -#define USBPD_REG_MASK_SNIFFER_MODE BIT(1) -#define USBPD_REG_MASK_BMC_PHY BIT(0) -#define IT83XX_USBPD_PDCSR0(p) REG8(IT83XX_USBPD_BASE(p)+0x01) -#define IT83XX_USBPD_PDMSR(p) REG8(IT83XX_USBPD_BASE(p)+0x02) -#define USBPD_REG_MASK_DISABLE_AUTO_GEN_TX_HEADER BIT(7) -#define USBPD_REG_MASK_AUTO_FRS_DISABLE BIT(6) -#define IT83XX_USBPD_PDCSR1(p) REG8(IT83XX_USBPD_BASE(p)+0x03) -#define USBPD_REG_MASK_CABLE_RESET_RX_ENABLE BIT(6) -#define USBPD_REG_MASK_HARD_RESET_RX_ENABLE BIT(5) -#define USBPD_REG_MASK_SOPPP_RX_ENABLE BIT(2) -#define USBPD_REG_MASK_SOPP_RX_ENABLE BIT(1) -#define USBPD_REG_MASK_SOP_RX_ENABLE BIT(0) -#define IT83XX_USBPD_CCGCR(p) REG8(IT83XX_USBPD_BASE(p)+0x04) -#define USBPD_REG_MASK_DISABLE_CC BIT(7) -#define USBPD_REG_MASK_DISABLE_CC_VOL_DETECTOR BIT(6) -#define USBPD_REG_MASK_CC_SELECT_RP_RESERVED (BIT(3) | BIT(2) | BIT(1)) -#define USBPD_REG_MASK_CC_SELECT_RP_DEF (BIT(3) | BIT(2)) -#define USBPD_REG_MASK_CC_SELECT_RP_1A5 BIT(3) -#define USBPD_REG_MASK_CC_SELECT_RP_3A0 BIT(2) -#define USBPD_REG_MASK_CC1_CC2_SELECTION BIT(0) -#define IT83XX_USBPD_CCCSR(p) REG8(IT83XX_USBPD_BASE(p)+0x05) -#define USBPD_REG_MASK_CC2_DISCONNECT BIT(7) -#define USBPD_REG_MASK_CC2_DISCONNECT_5_1K_TO_GND BIT(6) -#define USBPD_REG_MASK_CC1_DISCONNECT BIT(3) -#define USBPD_REG_MASK_CC1_DISCONNECT_5_1K_TO_GND BIT(2) -#ifdef IT83XX_USBPD_CC1_CC2_RESISTANCE_SEPARATE -#define USBPD_REG_MASK_CC1_CC2_RP_RD_SELECT (BIT(1) | BIT(5)) -#else -#define USBPD_REG_MASK_CC1_CC2_RP_RD_SELECT BIT(1) -#endif -#define IT83XX_USBPD_CCPSR(p) REG8(IT83XX_USBPD_BASE(p)+0x06) -#define USBPD_REG_MASK_DISCONNECT_5_1K_CC2_DB BIT(6) -#define USBPD_REG_MASK_DISCONNECT_POWER_CC2 BIT(5) -#define USBPD_REG_MASK_DISCONNECT_5_1K_CC1_DB BIT(2) -#define USBPD_REG_MASK_DISCONNECT_POWER_CC1 BIT(1) -#define IT83XX_USBPD_SRCVCRR(p) REG8(IT83XX_USBPD_BASE(p)+0x08) -#define USBPD_REG_MASK_SRC_COMPARE_CC2_VOLT_H BIT(5) -#define USBPD_REG_MASK_SRC_COMPARE_CC2_VOLT_L BIT(4) -#define USBPD_REG_MASK_SRC_COMPARE_CC1_VOLT_H BIT(1) -#define USBPD_REG_MASK_SRC_COMPARE_CC1_VOLT_L BIT(0) -#define IT83XX_USBPD_SNKVCRR(p) REG8(IT83XX_USBPD_BASE(p)+0x09) -#define USBPD_REG_MASK_SNK_COMPARE_CC2_VOLT_H BIT(6) -#define USBPD_REG_MASK_SNK_COMPARE_CC2_VOLT_M BIT(5) -#define USBPD_REG_MASK_SNK_COMPARE_CC2_VOLT_L BIT(4) -#define USBPD_REG_MASK_SNK_COMPARE_CC1_VOLT_H BIT(2) -#define USBPD_REG_MASK_SNK_COMPARE_CC1_VOLT_M BIT(1) -#define USBPD_REG_MASK_SNK_COMPARE_CC1_VOLT_L BIT(0) -#define IT83XX_USBPD_PDFSCR(p) REG8(IT83XX_USBPD_BASE(p)+0x0C) -#define USBPD_REG_FAST_SWAP_REQUEST_ENABLE BIT(1) -#define USBPD_REG_FAST_SWAP_DETECT_ENABLE BIT(0) -#define IT83XX_USBPD_IFS(p) REG8(IT83XX_USBPD_BASE(p)+0x12) -#define USBPD_REG_FAST_SWAP_DETECT_STAT BIT(4) -#define IT83XX_USBPD_MIFS(p) REG8(IT83XX_USBPD_BASE(p)+0x13) -#define USBPD_REG_MASK_FAST_SWAP_ISR BIT(7) -#define USBPD_REG_MASK_FAST_SWAP_DETECT_ISR BIT(4) -#define IT83XX_USBPD_ISR(p) REG8(IT83XX_USBPD_BASE(p)+0x14) -#define USBPD_REG_MASK_CABLE_RESET_DETECT BIT(6) -#define USBPD_REG_MASK_HARD_RESET_DETECT BIT(5) -#define USBPD_REG_MASK_MSG_RX_DONE BIT(4) -#define USBPD_REG_MASK_TX_ERROR_STAT BIT(3) -#define USBPD_REG_MASK_CABLE_RESET_TX_DONE BIT(2) -#define USBPD_REG_MASK_HARD_RESET_TX_DONE BIT(1) -#define USBPD_REG_MASK_MSG_TX_DONE BIT(0) -#define IT83XX_USBPD_IMR(p) REG8(IT83XX_USBPD_BASE(p)+0x15) -#define IT83XX_USBPD_MTCR(p) REG8(IT83XX_USBPD_BASE(p)+0x18) -#define USBPD_REG_MASK_TX_DISCARD_STAT BIT(7) -#define USBPD_REG_MASK_TX_NO_RESPONSE_STAT BIT(6) -#define USBPD_REG_MASK_TX_NOT_EN_STAT BIT(5) -#define USBPD_REG_MASK_CABLE_RESET BIT(3) -#define USBPD_REG_MASK_SEND_HW_RESET BIT(2) -#define USBPD_REG_MASK_SEND_BIST_MODE_2 BIT(1) -#define USBPD_REG_MASK_TX_START BIT(0) -#define IT83XX_USBPD_MTSR0(p) REG8(IT83XX_USBPD_BASE(p)+0x19) -#define IT83XX_USBPD_MHSR0(p) REG8(IT83XX_USBPD_BASE(p)+0x1A) -#define USBPD_REG_MASK_SOP_PORT_DATA_ROLE BIT(5) -#define IT83XX_USBPD_MHSR1(p) REG8(IT83XX_USBPD_BASE(p)+0x1B) -#define USBPD_REG_MASK_SOP_PORT_POWER_ROLE BIT(0) -#define IT83XX_USBPD_TDO(p) REG32(IT83XX_USBPD_BASE(p)+0x22) -#define IT83XX_USBPD_RMH(p) REG16(IT83XX_USBPD_BASE(p)+0x42) -#define IT83XX_USBPD_RDO(p) REG32(IT83XX_USBPD_BASE(p)+0x44) -#define IT83XX_USBPD_BMCDR0(p) REG8(IT83XX_USBPD_BASE(p)+0x61) -#define USBPD_REG_MASK_BMC_RX_THRESHOLD_SRC BIT(5) -#define USBPD_REG_MASK_BMC_RX_THRESHOLD_SNK BIT(1) -#define IT83XX_USBPD_TCDCR(p) REG8(IT83XX_USBPD_BASE(p)+0x67) -#define USBPD_REG_PLUG_OUT_DETECT_TYPE_SELECT BIT(7) -#define USBPD_REG_PLUG_OUT_SELECT BIT(6) -#define USBPD_REG_PD3_0_SNK_TX_OK_DISABLE BIT(5) -#define USBPD_REG_PD3_0_SNK_TX_NG_DISABLE BIT(3) -#define USBPD_REG_PLUG_IN_OUT_DETECT_DISABLE BIT(1) -#define USBPD_REG_PLUG_IN_OUT_DETECT_STAT BIT(0) -#define IT83XX_USBPD_CCPSR0(p) REG8(IT83XX_USBPD_BASE(p)+0x70) -#define IT83XX_USBPD_CCPSR3_RISE(p) REG8(IT83XX_USBPD_BASE(p)+0x73) -#define IT83XX_USBPD_CCPSR4_FALL(p) REG8(IT83XX_USBPD_BASE(p)+0x74) -#endif /* !defined(CONFIG_USB_PD_TCPM_DRIVER_IT83XX) */ - -/* - * Dedicated setting for CC pin. - * This setting will connect CC pin to internal PD module directly without - * applying any GPIO/ALT configuration. - */ -#define IT83XX_USBPD_CC_PIN_CONFIG 0x86 -#define IT83XX_USBPD_CC_PIN_CONFIG2 0x06 - -/* - * Before disabling cc 5v tolerant, we need to make sure cc voltage - * detector is enabled and Vconn is dropped below 3.3v (>500us) to avoid - * the potential risk of voltage fed back into Vcore. - */ -#define IT83XX_USBPD_T_VCONN_BELOW_3_3V 500 /* us */ - -#ifndef CONFIG_USB_PD_TCPM_ITE_ON_CHIP -#define CONFIG_USB_PD_ITE_ACTIVE_PORT_COUNT 0 -#endif - -#define TASK_EVENT_PHY_TX_DONE TASK_EVENT_CUSTOM_BIT(PD_EVENT_FIRST_FREE_BIT) - -#define SET_MASK(reg, bit_mask) ((reg) |= (bit_mask)) -#define CLEAR_MASK(reg, bit_mask) ((reg) &= (~(bit_mask))) -#define IS_MASK_SET(reg, bit_mask) (((reg) & (bit_mask)) != 0) -#define IS_MASK_CLEAR(reg, bit_mask) (((reg) & (bit_mask)) == 0) - -#if defined(CONFIG_USB_PD_TCPM_DRIVER_IT83XX) -/* macros for set */ -#define USBPD_KICK_TX_START(port) \ - SET_MASK(IT83XX_USBPD_MTCR(port), \ - USBPD_REG_MASK_TX_START) -#define USBPD_SEND_HARD_RESET(port) \ - SET_MASK(IT83XX_USBPD_MTSR0(port), \ - USBPD_REG_MASK_SEND_HW_RESET) -#define USBPD_SW_RESET(port) \ - SET_MASK(IT83XX_USBPD_GCR(port), \ - USBPD_REG_MASK_SW_RESET_BIT) -#define USBPD_ENABLE_BMC_PHY(port) \ - SET_MASK(IT83XX_USBPD_GCR(port), \ - USBPD_REG_MASK_BMC_PHY) -#define USBPD_DISABLE_BMC_PHY(port) \ - CLEAR_MASK(IT83XX_USBPD_GCR(port), \ - USBPD_REG_MASK_BMC_PHY) -#define USBPD_START(port) \ - CLEAR_MASK(IT83XX_USBPD_CCGCR(port), \ - USBPD_REG_MASK_DISABLE_CC) -#define USBPD_ENABLE_SEND_BIST_MODE_2(port) \ - SET_MASK(IT83XX_USBPD_MTSR0(port), \ - USBPD_REG_MASK_SEND_BIST_MODE_2) -#define USBPD_DISABLE_SEND_BIST_MODE_2(port) \ - CLEAR_MASK(IT83XX_USBPD_MTSR0(port), \ - USBPD_REG_MASK_SEND_BIST_MODE_2) -#define USBPD_CLEAR_FRS_DETECT_STATUS(port) \ - (IT83XX_USBPD_PD30IR(port) = USBPD_REG_FAST_SWAP_DETECT_STAT) -#define USBPD_CC1_DISCONNECTED(p) \ - ((IT83XX_USBPD_CCCSR(p) | USBPD_REG_MASK_CC1_DISCONNECT) & \ - ~USBPD_REG_MASK_CC2_DISCONNECT) -#define USBPD_CC2_DISCONNECTED(p) \ - ((IT83XX_USBPD_CCCSR(p) | USBPD_REG_MASK_CC2_DISCONNECT) & \ - ~USBPD_REG_MASK_CC1_DISCONNECT) - -/* macros for get */ -#define USBPD_GET_POWER_ROLE(port) \ - (IT83XX_USBPD_PDMSR(port) & 1) -#define USBPD_GET_CC1_PULL_REGISTER_SELECTION(port) \ - (IT83XX_USBPD_CCGCR(port) & BIT(1)) -#define USBPD_GET_CC2_PULL_REGISTER_SELECTION(port) \ - (IT83XX_USBPD_BMCSR(port) & BIT(3)) -#define USBPD_GET_PULL_CC_SELECTION(port) \ - (IT83XX_USBPD_CCGCR(port) & 1) - -/* macros for check */ -#define USBPD_IS_TX_ERR(port) \ - IS_MASK_SET(IT83XX_USBPD_MTCR(port), USBPD_REG_MASK_TX_ERR_STAT) -#define USBPD_IS_TX_DISCARD(port) \ - IS_MASK_SET(IT83XX_USBPD_MTCR(port), USBPD_REG_MASK_TX_DISCARD_STAT) - -#elif defined(CONFIG_USB_PD_TCPM_DRIVER_IT8XXX2) -/* macros for set */ -#define USBPD_SW_RESET(port) \ - SET_MASK(IT83XX_USBPD_PDGCR(port), \ - USBPD_REG_MASK_SW_RESET_BIT) -#define USBPD_ENABLE_BMC_PHY(port) \ - SET_MASK(IT83XX_USBPD_PDGCR(port), \ - USBPD_REG_MASK_BMC_PHY) -#define USBPD_DISABLE_BMC_PHY(port) \ - CLEAR_MASK(IT83XX_USBPD_PDGCR(port), \ - USBPD_REG_MASK_BMC_PHY) -#define USBPD_START(port) \ - CLEAR_MASK(IT83XX_USBPD_CCGCR(port), \ - USBPD_REG_MASK_DISABLE_CC) -#define USBPD_SEND_HARD_RESET(port) \ - SET_MASK(IT83XX_USBPD_MTCR(port), \ - USBPD_REG_MASK_SEND_HW_RESET) -#define USBPD_SEND_CABLE_RESET(port) \ - SET_MASK(IT83XX_USBPD_MTCR(port), \ - USBPD_REG_MASK_CABLE_RESET) -#define USBPD_ENABLE_SEND_BIST_MODE_2(port) \ - SET_MASK(IT83XX_USBPD_MTCR(port), \ - USBPD_REG_MASK_SEND_BIST_MODE_2) -#define USBPD_DISABLE_SEND_BIST_MODE_2(port) \ - CLEAR_MASK(IT83XX_USBPD_MTCR(port), \ - USBPD_REG_MASK_SEND_BIST_MODE_2) -#define USBPD_KICK_TX_START(port) \ - SET_MASK(IT83XX_USBPD_MTCR(port), \ - USBPD_REG_MASK_TX_START) -#define USBPD_CLEAR_FRS_DETECT_STATUS(port) \ - (IT83XX_USBPD_IFS(port) = USBPD_REG_FAST_SWAP_DETECT_STAT) -#define USBPD_CC1_DISCONNECTED(p) \ - ((IT83XX_USBPD_CCCSR(p) | USBPD_REG_MASK_CC1_DISCONNECT) & \ - ~USBPD_REG_MASK_CC2_DISCONNECT) -#define USBPD_CC2_DISCONNECTED(p) \ - ((IT83XX_USBPD_CCCSR(p) | USBPD_REG_MASK_CC2_DISCONNECT) & \ - ~USBPD_REG_MASK_CC1_DISCONNECT) - -/* macros for get */ -#define USBPD_GET_POWER_ROLE(port) \ - (IT83XX_USBPD_MHSR1(port) & BIT(0)) -#define USBPD_GET_CC1_PULL_REGISTER_SELECTION(port) \ - (IT83XX_USBPD_CCCSR(port) & BIT(1)) -#define USBPD_GET_CC2_PULL_REGISTER_SELECTION(port) \ - (IT83XX_USBPD_CCCSR(port) & BIT(1)) -#define USBPD_GET_PULL_CC_SELECTION(port) \ - (IT83XX_USBPD_CCGCR(port) & BIT(0)) -#define USBPD_GET_SNK_COMPARE_CC1_VOLT(port) \ - (IT83XX_USBPD_SNKVCRR(port) & \ - (USBPD_REG_MASK_SNK_COMPARE_CC1_VOLT_L | \ - USBPD_REG_MASK_SNK_COMPARE_CC1_VOLT_M | \ - USBPD_REG_MASK_SNK_COMPARE_CC1_VOLT_H)) -#define USBPD_GET_SNK_COMPARE_CC2_VOLT(port) \ - ((IT83XX_USBPD_SNKVCRR(port) & \ - (USBPD_REG_MASK_SNK_COMPARE_CC2_VOLT_L | \ - USBPD_REG_MASK_SNK_COMPARE_CC2_VOLT_M | \ - USBPD_REG_MASK_SNK_COMPARE_CC2_VOLT_H)) >> 4) -#define USBPD_GET_SRC_COMPARE_CC1_VOLT(port) \ - (IT83XX_USBPD_SRCVCRR(port) & \ - (USBPD_REG_MASK_SRC_COMPARE_CC1_VOLT_L | \ - USBPD_REG_MASK_SRC_COMPARE_CC1_VOLT_H)) -#define USBPD_GET_SRC_COMPARE_CC2_VOLT(port) \ - ((IT83XX_USBPD_SRCVCRR(port) & \ - (USBPD_REG_MASK_SRC_COMPARE_CC2_VOLT_L | \ - USBPD_REG_MASK_SRC_COMPARE_CC2_VOLT_H)) >> 4) - -/* macros for check */ -#define USBPD_IS_TX_ERR(port) \ - IS_MASK_SET(IT83XX_USBPD_ISR(port), USBPD_REG_MASK_TX_ERROR_STAT) -#endif /* !defined(CONFIG_USB_PD_TCPM_DRIVER_IT83XX) */ - -/* macros for PD ISR */ -#define USBPD_IS_HARD_RESET_DETECT(port) \ - IS_MASK_SET(IT83XX_USBPD_ISR(port), USBPD_REG_MASK_HARD_RESET_DETECT) -#define USBPD_IS_HARD_CABLE_RESET_TX_DONE(port) \ - IS_MASK_SET(IT83XX_USBPD_ISR(port), \ - USBPD_REG_MASK_HARD_CABLE_RESET_TX_DONE) -#define USBPD_IS_TX_DONE(port) \ - IS_MASK_SET(IT83XX_USBPD_ISR(port), USBPD_REG_MASK_MSG_TX_DONE) -#define USBPD_IS_RX_DONE(port) \ - IS_MASK_SET(IT83XX_USBPD_ISR(port), USBPD_REG_MASK_MSG_RX_DONE) -#define USBPD_IS_PLUG_IN_OUT_DETECT(port)\ - IS_MASK_SET(IT83XX_USBPD_TCDCR(port), USBPD_REG_PLUG_IN_OUT_DETECT_STAT) -#define USBPD_IS_PLUG_IN(port) \ - IS_MASK_CLEAR(IT83XX_USBPD_TCDCR(port), USBPD_REG_PLUG_OUT_SELECT) -#if defined(CONFIG_USB_PD_TCPM_DRIVER_IT83XX) -#define USBPD_IS_FAST_SWAP_DETECT(port) \ - IS_MASK_SET(IT83XX_USBPD_PD30IR(port), USBPD_REG_FAST_SWAP_DETECT_STAT) -#elif defined(CONFIG_USB_PD_TCPM_DRIVER_IT8XXX2) -#define USBPD_IS_FAST_SWAP_DETECT(port) \ - IS_MASK_SET(IT83XX_USBPD_IFS(port), USBPD_REG_FAST_SWAP_DETECT_STAT) -#endif - -#if defined(CONFIG_USB_PD_TCPM_ITE_ON_CHIP) && defined(CONFIG_ZEPHYR) -/* Use the Zephyr names here. When upstreaming we can update this */ -#include <dt-bindings/interrupt-controller/ite-intc.h> - -#define IT83XX_GPIO_GPCRF4 GPCRF4 -#define IT83XX_GPIO_GPCRF5 GPCRF5 -#define IT83XX_GPIO_GPCRH1 GPCRH1 -#define IT83XX_GPIO_GPCRH2 GPCRH2 -#define IT83XX_GPIO_GPCRP0 IT8XXX2_GPIO_GPCRP0 -#define IT83XX_GPIO_GPCRP1 IT8XXX2_GPIO_GPCRP1 -#define IT83XX_IRQ_USBPD0 IT8XXX2_IRQ_USBPD0 -#define IT83XX_IRQ_USBPD1 IT8XXX2_IRQ_USBPD1 -#define IT83XX_IRQ_USBPD2 IT8XXX2_IRQ_USBPD2 -#define USB_VID_ITE 0x048d - -/* ITE chip supports PD features */ -#define IT83XX_INTC_FAST_SWAP_SUPPORT -#define IT83XX_INTC_PLUG_IN_OUT_SUPPORT -#endif - -enum usbpd_port { - USBPD_PORT_A, - USBPD_PORT_B, - USBPD_PORT_C, -}; - -enum usbpd_ufp_volt_status { - USBPD_UFP_STATE_SNK_OPEN = 0, - USBPD_UFP_STATE_SNK_DEF = 1, - USBPD_UFP_STATE_SNK_1_5 = 3, - USBPD_UFP_STATE_SNK_3_0 = 7, -}; - -enum usbpd_dfp_volt_status { - USBPD_DFP_STATE_SRC_RA = 0, - USBPD_DFP_STATE_SRC_RD = 1, - USBPD_DFP_STATE_SRC_OPEN = 3, -}; - -enum usbpd_power_role { - USBPD_POWER_ROLE_CONSUMER, - USBPD_POWER_ROLE_PROVIDER, - USBPD_POWER_ROLE_CONSUMER_PROVIDER, - USBPD_POWER_ROLE_PROVIDER_CONSUMER, -}; - -enum tuning_unit { - IT83XX_TX_PRE_DRIVING_TIME_DEFAULT, - IT83XX_TX_PRE_DRIVING_TIME_1_UNIT, - IT83XX_TX_PRE_DRIVING_TIME_2_UNIT, - IT83XX_TX_PRE_DRIVING_TIME_3_UNIT, -}; - -struct usbpd_ctrl_t { - volatile uint8_t *cc1; - volatile uint8_t *cc2; - uint8_t irq; -}; - -/* Data structure for board to adjust pd port rising and falling time */ -struct cc_para_t { - enum tuning_unit rising_time; - enum tuning_unit falling_time; -}; - -extern const struct usbpd_ctrl_t usbpd_ctrl_regs[]; -void it8xxx2_clear_tx_error_status(enum usbpd_port port); -void it8xxx2_get_tx_error_status(enum usbpd_port port); -void it83xx_Rd_5_1K_only_for_hibernate(int port); -void switch_plug_out_type(enum usbpd_port port); -/* - * Board-level callback function to get cc tuning parameters - * NOTE: board must define CONFIG_IT83XX_TUNE_CC_PHY - */ -const struct cc_para_t *board_get_cc_tuning_parameter(enum usbpd_port port); - -#endif /* __CROS_EC_DRIVER_TCPM_IT83XX_H */ diff --git a/driver/tcpm/it8xxx2.c b/driver/tcpm/it8xxx2.c deleted file mode 100644 index dd5d1231fc..0000000000 --- a/driver/tcpm/it8xxx2.c +++ /dev/null @@ -1,968 +0,0 @@ -/* Copyright 2020 The Chromium OS Authors. All rights reserved. - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ - -/* TCPM on ITE chip it8xxx2 with embedded TCPC */ - -#include "common.h" -#include "config.h" -#include "console.h" -#include "it83xx_pd.h" -#include "ite_pd_intc.h" -#include "registers.h" -#include "system.h" -#include "task.h" -#include "timer.h" -#include "util.h" -#include "usb_common.h" -#include "usb_pd.h" -#include "usb_pd_tcpm.h" -#include "hooks.h" - -#ifdef CONFIG_USB_PD_TCPMV1 -#if defined(CONFIG_USB_PD_DUAL_ROLE_AUTO_TOGGLE) || \ - defined(CONFIG_USB_PD_VBUS_DETECT_TCPC) || \ - defined(CONFIG_USB_PD_TCPC_LOW_POWER) || \ - defined(CONFIG_USB_PD_DISCHARGE_TCPC) -#error "Unsupported config options of IT8xxx2 PD driver" -#endif -#endif - -#ifdef CONFIG_USB_PD_TCPMV2 -#if defined(CONFIG_USB_PD_VBUS_DETECT_TCPC) || \ - defined(CONFIG_USB_PD_DISCHARGE_TCPC) -#error "Unsupported config options of IT8xxx2 PD driver" -#endif -#endif - -#define CPRINTS(format, args...) cprints(CC_USBPD, format, ## args) - -bool rx_en[IT83XX_USBPD_PHY_PORT_COUNT]; -STATIC_IF(CONFIG_USB_PD_DECODE_SOP) - bool sop_prime_en[IT83XX_USBPD_PHY_PORT_COUNT]; -static uint8_t tx_error_status[IT83XX_USBPD_PHY_PORT_COUNT] = {0}; - -const struct usbpd_ctrl_t usbpd_ctrl_regs[] = { - {&IT83XX_GPIO_GPCRF4, &IT83XX_GPIO_GPCRF5, IT83XX_IRQ_USBPD0}, - {&IT83XX_GPIO_GPCRH1, &IT83XX_GPIO_GPCRH2, IT83XX_IRQ_USBPD1}, - {&IT83XX_GPIO_GPCRP0, &IT83XX_GPIO_GPCRP1, IT83XX_IRQ_USBPD2}, -}; -BUILD_ASSERT(ARRAY_SIZE(usbpd_ctrl_regs) >= IT83XX_USBPD_PHY_PORT_COUNT); - -/* - * Disable cc analog and pd digital module, but only left Rd_5.1K (Not - * Rd_DB) analog module alive to assert Rd on CCs. EC reset or calling - * _init() are able to re-active cc and pd. - */ -void it83xx_Rd_5_1K_only_for_hibernate(int port) -{ - uint8_t cc_config = (port == USBPD_PORT_C ? - IT83XX_USBPD_CC_PIN_CONFIG2 : - IT83XX_USBPD_CC_PIN_CONFIG); - - /* This only apply to active PD port */ - if (*usbpd_ctrl_regs[port].cc1 == cc_config && - *usbpd_ctrl_regs[port].cc2 == cc_config) { - /* Disable PD Tx and Rx PHY */ - IT83XX_USBPD_PDGCR(port) &= ~USBPD_REG_MASK_BMC_PHY; - /* Disable CCs voltage detector */ - IT83XX_USBPD_CCGCR(port) |= - USBPD_REG_MASK_DISABLE_CC_VOL_DETECTOR; - /* Select Rp reserved value for not current leakage */ - IT83XX_USBPD_CCGCR(port) |= - USBPD_REG_MASK_CC_SELECT_RP_RESERVED; - /* - * Connect CCs analog module (ex.UP/RD/DET/TX/RX), and - * connect CCs 5.1K to GND, and - * CCs assert Rd - */ - IT83XX_USBPD_CCCSR(port) &= - ~(USBPD_REG_MASK_CC2_DISCONNECT | - USBPD_REG_MASK_CC2_DISCONNECT_5_1K_TO_GND | - USBPD_REG_MASK_CC1_DISCONNECT | - USBPD_REG_MASK_CC1_DISCONNECT_5_1K_TO_GND | - USBPD_REG_MASK_CC1_CC2_RP_RD_SELECT); - /* Disconnect CCs 5V tolerant */ - IT83XX_USBPD_CCPSR(port) |= - (USBPD_REG_MASK_DISCONNECT_POWER_CC2 | - USBPD_REG_MASK_DISCONNECT_POWER_CC1); - /* Enable CCs analog module */ - IT83XX_USBPD_CCGCR(port) &= ~USBPD_REG_MASK_DISABLE_CC; - } -} - -static enum tcpc_cc_voltage_status it8xxx2_get_cc(enum usbpd_port port, - enum usbpd_cc_pin cc_pin) -{ - enum usbpd_ufp_volt_status ufp_volt; - enum usbpd_dfp_volt_status dfp_volt; - enum tcpc_cc_voltage_status cc_state = TYPEC_CC_VOLT_OPEN; - - /* - * Because the message header bit(8) field has different definition - * between SOP and SOP'/SOP'', in order to not happen misjudgement - * when we receive SOP or SOP'/SOP'', the getting power role synchronize - * with pd[port].power_role (also synchronization with tcpm_set_cc) - * instead of message header. - */ - /* Sink */ - if (pd_get_power_role(port) == PD_ROLE_SINK) { - if (cc_pin == USBPD_CC_PIN_1) - ufp_volt = USBPD_GET_SNK_COMPARE_CC1_VOLT(port); - else - ufp_volt = USBPD_GET_SNK_COMPARE_CC2_VOLT(port); - - switch (ufp_volt) { - case USBPD_UFP_STATE_SNK_DEF: - cc_state = TYPEC_CC_VOLT_RP_DEF; - break; - case USBPD_UFP_STATE_SNK_1_5: - cc_state = TYPEC_CC_VOLT_RP_1_5; - break; - case USBPD_UFP_STATE_SNK_3_0: - cc_state = TYPEC_CC_VOLT_RP_3_0; - break; - case USBPD_UFP_STATE_SNK_OPEN: - cc_state = TYPEC_CC_VOLT_OPEN; - break; - default: - cc_state = TYPEC_CC_VOLT_OPEN; - break; - } - /* Source */ - } else { - if (cc_pin == USBPD_CC_PIN_1) - dfp_volt = USBPD_GET_SRC_COMPARE_CC1_VOLT(port); - else - dfp_volt = USBPD_GET_SRC_COMPARE_CC2_VOLT(port); - - switch (dfp_volt) { - case USBPD_DFP_STATE_SRC_RA: - cc_state = TYPEC_CC_VOLT_RA; - break; - case USBPD_DFP_STATE_SRC_RD: - cc_state = TYPEC_CC_VOLT_RD; - break; - case USBPD_DFP_STATE_SRC_OPEN: - cc_state = TYPEC_CC_VOLT_OPEN; - break; - default: - cc_state = TYPEC_CC_VOLT_OPEN; - break; - } - } - - return cc_state; -} - -static int it8xxx2_tcpm_get_message_raw(int port, uint32_t *buf, int *head) -{ - int cnt = PD_HEADER_CNT(IT83XX_USBPD_RMH(port)); - - if (!USBPD_IS_RX_DONE(port)) - return EC_ERROR_UNKNOWN; - - /* Store header */ - *head = IT83XX_USBPD_RMH(port); - - /* - * BIT[6:4] SOP type of Rx message - * 000b=SOP, 001b=SOP', 010b=SOP", 011b=Debug SOP', 100b=Debug SOP" - * 101b=HRDRST, 110b=CBLRST - * 000b~100b is aligned to enum tcpci_msg_type. - * - */ - if (IS_ENABLED(CONFIG_USB_PD_DECODE_SOP)) - *head |= PD_HEADER_SOP((IT83XX_USBPD_MTSR0(port) >> 4) & 0x7); - - /* Check data message */ - if (cnt) - memcpy(buf, (uint32_t *)&IT83XX_USBPD_RDO(port), cnt * 4); - - return EC_SUCCESS; -} - -void it8xxx2_clear_tx_error_status(enum usbpd_port port) -{ - tx_error_status[port] = 0; -} - -void it8xxx2_get_tx_error_status(enum usbpd_port port) -{ - tx_error_status[port] = IT83XX_USBPD_MTCR(port) & - (USBPD_REG_MASK_TX_NOT_EN_STAT | - USBPD_REG_MASK_TX_DISCARD_STAT | - USBPD_REG_MASK_TX_NO_RESPONSE_STAT); -} - -static enum tcpc_transmit_complete it8xxx2_tx_data(enum usbpd_port port, - enum tcpci_msg_type type, - uint16_t header, - const uint32_t *buf) -{ - int r; - uint32_t evt; - uint8_t length = PD_HEADER_CNT(header); - - /* Set message header */ - IT83XX_USBPD_MHSR0(port) = (uint8_t)header; - IT83XX_USBPD_MHSR1(port) = (header >> 8); - - /* - * Bit[2:0] Tx message type - * 000b=SOP, 001b=SOP', 010b=SOP", 011b=Debug SOP', 100b=Debug SOP''. - */ - IT83XX_USBPD_MTSR0(port) = - (IT83XX_USBPD_MTSR0(port) & ~0x7) | (type & 0x7); - - /* Limited by PD_HEADER_CNT() */ - ASSERT(length <= 0x7); - - if (length) - /* Set data */ - memcpy((uint32_t *)&IT83XX_USBPD_TDO(port), buf, length * 4); - - for (r = 0; r <= CONFIG_PD_RETRY_COUNT; r++) { - /* Start Tx */ - USBPD_KICK_TX_START(port); - evt = task_wait_event_mask(TASK_EVENT_PHY_TX_DONE, - PD_T_TCPC_TX_TIMEOUT); - - /* - * Check Tx error status (TCPC won't set multi tx errors at one - * time transmission): - * 1) If we doesn't enable Tx. - * 2) If discard, means HW doesn't send the msg and resend. - * 3) If port partner doesn't respond GoodCRC. - * 4) If Tx timeout. - */ - if (tx_error_status[port] || (evt & TASK_EVENT_TIMER)) { - if (tx_error_status[port] & - USBPD_REG_MASK_TX_NOT_EN_STAT) { - CPRINTS("p%d TxErr: Tx EN and resend", port); - tx_error_status[port] &= - ~USBPD_REG_MASK_TX_NOT_EN_STAT; - IT83XX_USBPD_PDGCR(port) |= - USBPD_REG_MASK_TX_MESSAGE_ENABLE; - continue; - } else if (tx_error_status[port] & - USBPD_REG_MASK_TX_DISCARD_STAT) { - CPRINTS("p%d TxErr: Discard and resend", port); - tx_error_status[port] &= - ~USBPD_REG_MASK_TX_DISCARD_STAT; - continue; - } else if (tx_error_status[port] & - USBPD_REG_MASK_TX_NO_RESPONSE_STAT) { - /* HW had automatically resent message twice */ - tx_error_status[port] &= - ~USBPD_REG_MASK_TX_NO_RESPONSE_STAT; - return TCPC_TX_COMPLETE_FAILED; - } else if (evt & TASK_EVENT_TIMER) { - CPRINTS("p%d TxErr: Timeout", port); - return TCPC_TX_UNSET; - } - } else - break; - } - - if (r > CONFIG_PD_RETRY_COUNT) - return TCPC_TX_COMPLETE_DISCARDED; - - return TCPC_TX_COMPLETE_SUCCESS; -} - -static enum tcpc_transmit_complete it8xxx2_send_hw_reset(enum usbpd_port port) -{ - /* Send hard reset */ - USBPD_SEND_HARD_RESET(port); - usleep(MSEC); - - if (!(IT83XX_USBPD_ISR(port) & USBPD_REG_MASK_HARD_RESET_TX_DONE)) - return TCPC_TX_COMPLETE_FAILED; - IT83XX_USBPD_ISR(port) = USBPD_REG_MASK_HARD_RESET_TX_DONE; - - return TCPC_TX_COMPLETE_SUCCESS; -} - -static enum tcpc_transmit_complete it8xxx2_send_cable_reset( - enum usbpd_port port) -{ - /* Send cable reset */ - USBPD_SEND_CABLE_RESET(port); - usleep(MSEC); - - if (!(IT83XX_USBPD_ISR(port) & USBPD_REG_MASK_CABLE_RESET_TX_DONE)) - return TCPC_TX_COMPLETE_FAILED; - IT83XX_USBPD_ISR(port) = USBPD_REG_MASK_CABLE_RESET_TX_DONE; - - return TCPC_TX_COMPLETE_SUCCESS; -} - -static void it8xxx2_send_bist_mode2_pattern(enum usbpd_port port) -{ - USBPD_ENABLE_SEND_BIST_MODE_2(port); - usleep(PD_T_BIST_TRANSMIT); - USBPD_DISABLE_SEND_BIST_MODE_2(port); -} - -static void it8xxx2_enable_vconn(enum usbpd_port port, int enabled) -{ - enum usbpd_cc_pin cc_pin; - - if (USBPD_GET_PULL_CC_SELECTION(port)) - cc_pin = USBPD_CC_PIN_1; - else - cc_pin = USBPD_CC_PIN_2; - - if (enabled) { - /* Disable unused CC to become VCONN */ - if (cc_pin == USBPD_CC_PIN_1) { - IT83XX_USBPD_CCCSR(port) = USBPD_CC2_DISCONNECTED(port); - IT83XX_USBPD_CCPSR(port) = (IT83XX_USBPD_CCPSR(port) - & ~USBPD_REG_MASK_DISCONNECT_POWER_CC2) - | USBPD_REG_MASK_DISCONNECT_POWER_CC1; - } else { - IT83XX_USBPD_CCCSR(port) = USBPD_CC1_DISCONNECTED(port); - IT83XX_USBPD_CCPSR(port) = (IT83XX_USBPD_CCPSR(port) - & ~USBPD_REG_MASK_DISCONNECT_POWER_CC1) - | USBPD_REG_MASK_DISCONNECT_POWER_CC2; - } - } else { - /* Connect cc analog module (ex.UP/RD/DET/TX/RX) */ - IT83XX_USBPD_CCCSR(port) &= ~(USBPD_REG_MASK_CC2_DISCONNECT | - USBPD_REG_MASK_CC1_DISCONNECT); - /* Disable cc 5v tolerant */ - IT83XX_USBPD_CCPSR(port) |= - (USBPD_REG_MASK_DISCONNECT_POWER_CC1 | - USBPD_REG_MASK_DISCONNECT_POWER_CC2); - } -} - -static void it8xxx2_enable_cc(enum usbpd_port port, int enable) -{ - if (enable) - IT83XX_USBPD_CCGCR(port) &= ~USBPD_REG_MASK_DISABLE_CC; - else - IT83XX_USBPD_CCGCR(port) |= USBPD_REG_MASK_DISABLE_CC; -} - -static void it8xxx2_set_power_role(enum usbpd_port port, int power_role) -{ - /* 0: PD_ROLE_SINK, 1: PD_ROLE_SOURCE */ - if (power_role == PD_ROLE_SOURCE) { - /* - * Bit[0:6] BMC Rx threshold setting - * 000 1000b: power neutral - * 010 0000b: sinking power => - * High to low Y3Rx threshold = 0.38, - * Low to high Y3Rx threshold = 0.54. - * 000 0010b: sourcing power => - * High to low Y3Rx threshold = 0.64, - * Low to high Y3Rx threshold = 0.79. - */ - IT83XX_USBPD_BMCDR0(port) = USBPD_REG_MASK_BMC_RX_THRESHOLD_SRC; - /* Bit0: source */ - IT83XX_USBPD_MHSR1(port) |= USBPD_REG_MASK_SOP_PORT_POWER_ROLE; - /* Bit1: CC1 and CC2 select Rp */ - IT83XX_USBPD_CCCSR(port) |= USBPD_REG_MASK_CC1_CC2_RP_RD_SELECT; - } else { - /* - * Bit[0:6] BMC Rx threshold setting - * 000 1000b: power neutral - * 010 0000b: sinking power => - * High to low Y3Rx threshold = 0.38, - * Low to high Y3Rx threshold = 0.54. - * 000 0010b: sourcing power => - * High to low Y3Rx threshold = 0.64, - * Low to high Y3Rx threshold = 0.79. - */ - IT83XX_USBPD_BMCDR0(port) = USBPD_REG_MASK_BMC_RX_THRESHOLD_SNK; - /* Bit0: sink */ - IT83XX_USBPD_MHSR1(port) &= ~USBPD_REG_MASK_SOP_PORT_POWER_ROLE; - /* Bit1: CC1 and CC2 select Rd */ - IT83XX_USBPD_CCCSR(port) &= - ~USBPD_REG_MASK_CC1_CC2_RP_RD_SELECT; - } -} - -static void it8xxx2_set_data_role(enum usbpd_port port, int data_role) -{ - /* 0: PD_ROLE_UFP 1: PD_ROLE_DFP */ - if (data_role == PD_ROLE_DFP) - /* Bit5: DFP */ - IT83XX_USBPD_MHSR0(port) |= USBPD_REG_MASK_SOP_PORT_DATA_ROLE; - else - /* Bit5: UFP */ - IT83XX_USBPD_MHSR0(port) &= ~USBPD_REG_MASK_SOP_PORT_DATA_ROLE; -} - -static void it8xxx2_select_polarity(enum usbpd_port port, - enum usbpd_cc_pin cc_pin) -{ - /* CC1/CC2 selection */ - if (cc_pin == USBPD_CC_PIN_1) - IT83XX_USBPD_CCGCR(port) |= USBPD_REG_MASK_CC1_CC2_SELECTION; - else - IT83XX_USBPD_CCGCR(port) &= ~USBPD_REG_MASK_CC1_CC2_SELECTION; -} - -static int it8xxx2_set_cc(enum usbpd_port port, int pull) -{ - int enable_cc = 1; - - switch (pull) { - case TYPEC_CC_RD: - it8xxx2_set_power_role(port, PD_ROLE_SINK); - break; - case TYPEC_CC_RP: - it8xxx2_set_power_role(port, PD_ROLE_SOURCE); - break; - case TYPEC_CC_OPEN: - /* Power-down CC1 & CC2 to remove Rp/Rd */ - enable_cc = 0; - break; - default: - return EC_ERROR_UNIMPLEMENTED; - } - - it8xxx2_enable_cc(port, enable_cc); - return EC_SUCCESS; -} - -static int it8xxx2_tcpm_release(int port) -{ - return EC_ERROR_UNIMPLEMENTED; -} - -static int it8xxx2_tcpm_get_cc(int port, - enum tcpc_cc_voltage_status *cc1, - enum tcpc_cc_voltage_status *cc2) -{ - *cc2 = it8xxx2_get_cc(port, USBPD_CC_PIN_2); - *cc1 = it8xxx2_get_cc(port, USBPD_CC_PIN_1); - - return EC_SUCCESS; -} - -static int it8xxx2_tcpm_select_rp_value(int port, int rp_sel) -{ - uint8_t rp; - - /* - * Bit[3-1]: CC output current (effective when Rp assert in 05h Bit[1]) - * 111: reserved - * 010: 330uA outpt (3.0A) - * 100: 180uA outpt (1.5A) - * 110: 80uA outpt (USB default) - */ - switch (rp_sel) { - case TYPEC_RP_1A5: - rp = USBPD_REG_MASK_CC_SELECT_RP_1A5; - break; - case TYPEC_RP_3A0: - rp = USBPD_REG_MASK_CC_SELECT_RP_3A0; - break; - case TYPEC_RP_USB: - default: - rp = USBPD_REG_MASK_CC_SELECT_RP_DEF; - break; - } - IT83XX_USBPD_CCGCR(port) = (IT83XX_USBPD_CCGCR(port) & ~(7 << 1)) | rp; - - return EC_SUCCESS; -} - -static int it8xxx2_tcpm_set_cc(int port, int pull) -{ - return it8xxx2_set_cc(port, pull); -} - -static int it8xxx2_tcpm_set_polarity(int port, enum tcpc_cc_polarity polarity) -{ - enum usbpd_cc_pin cc_pin = - (polarity == POLARITY_CC1 || polarity == POLARITY_CC1_DTS) ? - USBPD_CC_PIN_1 : USBPD_CC_PIN_2; - - it8xxx2_select_polarity(port, cc_pin); - - return EC_SUCCESS; -} - -__maybe_unused static int it8xxx2_tcpm_decode_sop_prime_enable(int port, - bool enable) -{ - /* Save SOP'/SOP'' enable state */ - sop_prime_en[port] = enable; - - if (!rx_en[port]) - return EC_SUCCESS; - - if (enable) - IT83XX_USBPD_PDCSR1(port) |= - (USBPD_REG_MASK_SOPP_RX_ENABLE | - USBPD_REG_MASK_SOPPP_RX_ENABLE); - else - IT83XX_USBPD_PDCSR1(port) &= - ~(USBPD_REG_MASK_SOPP_RX_ENABLE | - USBPD_REG_MASK_SOPPP_RX_ENABLE); - - return EC_SUCCESS; -} - -static int it8xxx2_tcpm_set_vconn(int port, int enable) -{ - /* - * IT8xxx2 doesn't have integrated circuit to source CC lines for VCONN. - * An external device like PPC or Power Switch has to source the VCONN. - */ - if (IS_ENABLED(CONFIG_USBC_VCONN)) { - if (enable) { - /* - * Unused cc will become Vconn SRC, disable cc analog - * module (ex.UP/RD/DET/Tx/Rx) and enable 5v tolerant. - */ - it8xxx2_enable_vconn(port, enable); - if (IS_ENABLED(CONFIG_USB_PD_DECODE_SOP)) - /* Enable tcpc receive SOP' and SOP'' packet */ - it8xxx2_tcpm_decode_sop_prime_enable(port, - true); - /* Turn on Vconn power switch. */ - board_pd_vconn_ctrl(port, - USBPD_GET_PULL_CC_SELECTION(port) ? - USBPD_CC_PIN_2 : USBPD_CC_PIN_1, - enable); - } else { - /* - * If the pd port has previous connection and supplies - * Vconn, then RO jumping to RW reset the system, - * we never know which cc is the previous Vconn pin, - * so we always turn both cc pins off when disable - * Vconn power switch. - */ - board_pd_vconn_ctrl(port, USBPD_CC_PIN_1, enable); - board_pd_vconn_ctrl(port, USBPD_CC_PIN_2, enable); - if (IS_ENABLED(CONFIG_USB_PD_DECODE_SOP)) - /* Disable tcpc receive SOP' and SOP'' packet */ - it8xxx2_tcpm_decode_sop_prime_enable(port, - false); - /* - * Before disabling cc 5v tolerant, we need to make - * sure cc voltage detector is enabled and Vconn is - * dropped below 3.3v (>500us) to avoid the potential - * risk of voltage fed back into Vcore. - */ - usleep(IT83XX_USBPD_T_VCONN_BELOW_3_3V); - /* - * Since our cc are not Vconn SRC, enable cc analog - * module (ex.UP/RD/DET/Tx/Rx) and disable 5v tolerant. - */ - it8xxx2_enable_vconn(port, enable); - } - } - - return EC_SUCCESS; -} - -static int it8xxx2_tcpm_set_msg_header(int port, int power_role, int data_role) -{ - /* 0: PD_ROLE_SINK, 1: PD_ROLE_SOURCE */ - if (power_role == PD_ROLE_SOURCE) - /* Bit0: source */ - IT83XX_USBPD_MHSR1(port) |= USBPD_REG_MASK_SOP_PORT_POWER_ROLE; - else - /* Bit0: sink */ - IT83XX_USBPD_MHSR1(port) &= ~USBPD_REG_MASK_SOP_PORT_POWER_ROLE; - - it8xxx2_set_data_role(port, data_role); - - return EC_SUCCESS; -} - -static int it8xxx2_tcpm_set_rx_enable(int port, int enable) -{ - /* Save rx_on */ - rx_en[port] = !!enable; - - if (enable) { - IT83XX_USBPD_IMR(port) &= ~USBPD_REG_MASK_MSG_RX_DONE; - IT83XX_USBPD_PDCSR1(port) |= - (USBPD_REG_MASK_SOP_RX_ENABLE | - USBPD_REG_MASK_HARD_RESET_RX_ENABLE); - if (IS_ENABLED(CONFIG_USB_PD_DECODE_SOP)) - it8xxx2_tcpm_decode_sop_prime_enable(port, - sop_prime_en[port]); - } else { - IT83XX_USBPD_IMR(port) |= USBPD_REG_MASK_MSG_RX_DONE; - IT83XX_USBPD_PDCSR1(port) &= ~(USBPD_REG_MASK_SOP_RX_ENABLE | - USBPD_REG_MASK_SOPP_RX_ENABLE | - USBPD_REG_MASK_SOPPP_RX_ENABLE | - USBPD_REG_MASK_HARD_RESET_RX_ENABLE); - } - - return EC_SUCCESS; -} - -static int it8xxx2_tcpm_transmit(int port, - enum tcpci_msg_type type, - uint16_t header, - const uint32_t *data) -{ - int status = TCPC_TX_COMPLETE_FAILED; - - switch (type) { - case TCPCI_MSG_SOP: - case TCPCI_MSG_SOP_PRIME: - case TCPCI_MSG_SOP_PRIME_PRIME: - case TCPCI_MSG_SOP_DEBUG_PRIME: - case TCPCI_MSG_SOP_DEBUG_PRIME_PRIME: - status = it8xxx2_tx_data(port, - type, - header, - data); - break; - case TCPCI_MSG_TX_BIST_MODE_2: - it8xxx2_send_bist_mode2_pattern(port); - status = TCPC_TX_COMPLETE_SUCCESS; - break; - case TCPCI_MSG_TX_HARD_RESET: - status = it8xxx2_send_hw_reset(port); - break; - case TCPCI_MSG_CABLE_RESET: - status = it8xxx2_send_cable_reset(port); - break; - default: - status = TCPC_TX_COMPLETE_FAILED; - break; - } - pd_transmit_complete(port, status); - - return EC_SUCCESS; -} - -static int it8xxx2_tcpm_get_chip_info(int port, int live, - struct ec_response_pd_chip_info_v1 *chip_info) -{ - chip_info->vendor_id = USB_VID_ITE; - chip_info->product_id = ((IT83XX_GCTRL_CHIPID1 << 8) | - IT83XX_GCTRL_CHIPID2); - chip_info->device_id = IT83XX_GCTRL_CHIPVER & 0xf; - chip_info->fw_version_number = 0xEC; - - return EC_SUCCESS; -} - -#ifdef CONFIG_USB_PD_TCPC_LOW_POWER -static int it8xxx2_tcpm_enter_low_power_mode(int port) -{ - /* - * ITE embedded TCPC SLEEP_MASK_USB_PD flag is only controlled by - * it8xxx2 driver in it8xxx2_set_pd_sleep_mask(), and do low power - * mode in idle_task(). - * In deep sleep mode, ITE TCPC clock is turned off, and the - * timer every 5ms to exit the mode and wakeup PD task to run - * (ex. change the CC lines termination). - */ - return EC_SUCCESS; -} -#endif - -#ifdef CONFIG_USB_PD_FRS_TCPC -static int it8xxx2_tcpm_set_frs_enable(int port, int enable) -{ - uint8_t mask = (USBPD_REG_FAST_SWAP_REQUEST_ENABLE | - USBPD_REG_FAST_SWAP_DETECT_ENABLE); - - if (enable) { - /* - * Disable HW auto turn off FRS requestion and detection - * when we receive soft or hard reset. - */ - IT83XX_USBPD_PDMSR(port) &= ~USBPD_REG_MASK_AUTO_FRS_DISABLE; - /* W/C status */ - IT83XX_USBPD_IFS(port) = 0x33; - /* Enable FRS detection (cc to GND) interrupt */ - IT83XX_USBPD_MIFS(port) &= ~(USBPD_REG_MASK_FAST_SWAP_ISR | - USBPD_REG_MASK_FAST_SWAP_DETECT_ISR); - /* Enable FRS detection (cc to GND) */ - IT83XX_USBPD_PDFSCR(port) = (IT83XX_USBPD_PDFSCR(port) & ~mask) - | USBPD_REG_FAST_SWAP_DETECT_ENABLE; - /* - * TODO(b/160210457): Enable HW auto trigger - * GPH3(port0)/GPH4(port1) output H/L after we detect FRS cc - * low signal. - */ - } else { - /* Disable FRS detection (cc to GND) interrupt */ - IT83XX_USBPD_MIFS(port) |= (USBPD_REG_MASK_FAST_SWAP_ISR | - USBPD_REG_MASK_FAST_SWAP_DETECT_ISR); - /* Disable FRS detection and requestion */ - IT83XX_USBPD_PDFSCR(port) &= ~mask; - /* - * TODO(b/160210457): Disable HW auto trigger - * GPH3(port0)/GPH4(port1) output H/L after we detect FRS cc - * low signal. - */ - } - - return EC_SUCCESS; -} -#endif - -static void it8xxx2_tcpm_switch_plug_out_type(int port) -{ - enum tcpc_cc_voltage_status cc1, cc2; - - /* Check what do we and partner cc assert */ - it8xxx2_tcpm_get_cc(port, &cc1, &cc2); - - if ((cc1 == TYPEC_CC_VOLT_RD && cc2 == TYPEC_CC_VOLT_RD) || - (cc1 == TYPEC_CC_VOLT_RA && cc2 == TYPEC_CC_VOLT_RA)) - /* We're source, switch to detect audio/debug plug out. */ - IT83XX_USBPD_TCDCR(port) = (IT83XX_USBPD_TCDCR(port) & - ~USBPD_REG_PLUG_IN_OUT_DETECT_DISABLE) | - USBPD_REG_PLUG_OUT_DETECT_TYPE_SELECT | - USBPD_REG_PLUG_OUT_SELECT; - else if (cc1 == TYPEC_CC_VOLT_RD || cc2 == TYPEC_CC_VOLT_RD) - /* We're source, switch to detect sink plug out. */ - IT83XX_USBPD_TCDCR(port) = (IT83XX_USBPD_TCDCR(port) & - ~USBPD_REG_PLUG_IN_OUT_DETECT_DISABLE & - ~USBPD_REG_PLUG_OUT_DETECT_TYPE_SELECT) | - USBPD_REG_PLUG_OUT_SELECT; - else if (cc1 >= TYPEC_CC_VOLT_RP_DEF || cc2 >= TYPEC_CC_VOLT_RP_DEF) - /* - * We're sink, disable detect interrupt, so messages on cc line - * won't trigger interrupt. - * NOTE: Plug out is detected by TCPM polling Vbus. - */ - IT83XX_USBPD_TCDCR(port) |= - USBPD_REG_PLUG_IN_OUT_DETECT_DISABLE; - /* - * If not above cases, plug in interrupt will fire again, - * and call switch_plug_out_type() to set the right state. - */ -} - -void switch_plug_out_type(enum usbpd_port port) -{ - it8xxx2_tcpm_switch_plug_out_type(port); -} - -static void it8xxx2_init(enum usbpd_port port, int role) -{ - uint8_t cc_config = (port == USBPD_PORT_C ? - IT83XX_USBPD_CC_PIN_CONFIG2 : - IT83XX_USBPD_CC_PIN_CONFIG); - - if (IS_ENABLED(CONFIG_IT83XX_TUNE_CC_PHY)) { - /* Tune cc Tx pre-driving time */ - const struct cc_para_t *ptr = - board_get_cc_tuning_parameter(port); - - IT83XX_USBPD_CCPSR3_RISE(port) = ptr->rising_time; - IT83XX_USBPD_CCPSR4_FALL(port) = ptr->falling_time; - } - /* Reset and disable HW auto generate message header */ - IT83XX_USBPD_PDMSR(port) &= ~USBPD_REG_MASK_DISABLE_AUTO_GEN_TX_HEADER; - USBPD_SW_RESET(port); - /* According PD version set HW auto retry count */ - IT83XX_USBPD_PDCSR0(port) = (IT83XX_USBPD_PDCSR0(port) & ~0xC0) | - (CONFIG_PD_RETRY_COUNT << 6); - /* Disable Rx decode */ - it8xxx2_tcpm_set_rx_enable(port, 0); - if (IS_ENABLED(CONFIG_USB_PD_TCPMV1)) { - uint8_t flags = 0; - /* - * If explicit contract is set in bbram when EC boot up, then - * TCPMv1 set soft reset as first state instead of - * unattached.SNK, so we need to enable BMC PHY for tx module. - * - * NOTE: If the platform is without battery and connects to - * adapter, then cold reset EC, our Rd is always asserted on cc, - * so adapter keeps providing 5v and data in BBRAM are still - * alive. - */ - if ((pd_get_saved_port_flags(port, &flags) == EC_SUCCESS) && - (flags & PD_BBRMFLG_EXPLICIT_CONTRACT)) - USBPD_ENABLE_BMC_PHY(port); - } - /* Disable all interrupts */ - IT83XX_USBPD_IMR(port) = 0xff; - /* W/C status */ - IT83XX_USBPD_ISR(port) = 0xff; - /* Enable cc voltage detector */ - IT83XX_USBPD_CCGCR(port) &= ~USBPD_REG_MASK_DISABLE_CC_VOL_DETECTOR; - /* Select Rp value USB-DEFAULT (Rd value default connect with 5.1k) */ - it8xxx2_tcpm_select_rp_value(port, TYPEC_RP_USB); - /* Which cc pin connect in attached state. Default to cc1 */ - it8xxx2_select_polarity(port, USBPD_CC_PIN_1); - /* Change data role as the same power role */ - it8xxx2_set_data_role(port, role); - /* Set default power role and assert Rp/Rd */ - it8xxx2_set_power_role(port, role); - /* Disable vconn: connect cc analog module, disable cc 5v tolerant */ - it8xxx2_tcpm_set_vconn(port, 0); - /* Enable tx done and hard reset detect interrupt */ - IT83XX_USBPD_IMR(port) &= ~(USBPD_REG_MASK_MSG_TX_DONE | - USBPD_REG_MASK_HARD_RESET_DETECT); -#ifdef IT83XX_INTC_PLUG_IN_OUT_SUPPORT - /* - * When tcpc detect type-c plug in (cc lines voltage change), it will - * interrupt fw to wake pd task, so task can react immediately. - * - * W/C status and enable type-c plug-in detect interrupt. - */ - IT83XX_USBPD_TCDCR(port) = (IT83XX_USBPD_TCDCR(port) & - ~(USBPD_REG_PLUG_IN_OUT_DETECT_DISABLE | - USBPD_REG_PLUG_OUT_SELECT)) | - USBPD_REG_PLUG_IN_OUT_DETECT_STAT; -#endif - /* Set cc1/cc2 pins alternate mode */ - *usbpd_ctrl_regs[port].cc1 = cc_config; - *usbpd_ctrl_regs[port].cc2 = cc_config; - task_clear_pending_irq(usbpd_ctrl_regs[port].irq); -#ifdef CONFIG_ZEPHYR - irq_connect_dynamic(usbpd_ctrl_regs[port].irq, 0, - (void (*)(const void *))chip_pd_irq, (void *)port, 0); -#endif - task_enable_irq(usbpd_ctrl_regs[port].irq); - USBPD_START(port); - /* - * Disconnect CCs Rd_DB from GND - * NOTE: CCs assert both Rd_5.1k and Rd_DB from USBPD_START() to - * disconnect Rd_DB about 1.5us. - */ - IT83XX_USBPD_CCPSR(port) |= (USBPD_REG_MASK_DISCONNECT_5_1K_CC2_DB | - USBPD_REG_MASK_DISCONNECT_5_1K_CC1_DB); -} - -static int it8xxx2_tcpm_init(int port) -{ - /* Initialize physical layer */ - it8xxx2_init(port, PD_ROLE_DEFAULT(port)); - - return EC_SUCCESS; -} - -static void it8xxx2_set_pd_sleep_mask(int port) -{ - int i; - bool prevent_deep_sleep = false; - - /* - * Set SLEEP_MASK_USB_PD for deep sleep mode: - * 1.Enable deep sleep mode, when all ITE ports are in Unattach.SRC/SNK - * state (HOOK_DISCONNECT called) and other ports aren't pd_capable(). - * 2.Disable deep sleep mode, when one of ITE port is in Attach.SRC/SNK - * state (HOOK_CONNECT called) or one of other ports is pd_capable(). - */ - for (i = 0; i < CONFIG_USB_PD_ITE_ACTIVE_PORT_COUNT; ++i) { - if (IT83XX_USBPD_PDGCR(i) & USBPD_REG_MASK_BMC_PHY) { - prevent_deep_sleep = true; - break; - } - } - - /* - * Check if any other ports have a PD port partner connected. Deep - * sleep is forbidden if any PD port partner is connected. Above, we - * only checked for the ITE ports. - */ - if (!prevent_deep_sleep) { - for (; i < board_get_usb_pd_port_count(); i++) - if (pd_capable(i)) - prevent_deep_sleep = true; - } - - if (prevent_deep_sleep) - disable_sleep(SLEEP_MASK_USB_PD); - else - enable_sleep(SLEEP_MASK_USB_PD); -} - -static void it8xxx2_tcpm_hook_connect(void) -{ - int port = TASK_ID_TO_PD_PORT(task_get_current()); - -#ifdef CONFIG_USB_PD_TCPMV2 - /* - * There are five cases that hook_connect() be called by TCPMv2: - * 1)AttachWait.SNK -> Attached.SNK: disable detect interrupt. - * 2)AttachWait.SRC -> Attached.SRC: enable detect plug out. - * 3)AttachWait.SNK -> Try.SRC -> TryWait.SNK -> Attached.SNK: we do - * Try.SRC fail, disable detect interrupt. - * 4)AttachWait.SNK -> Try.SRC -> Attached.SRC: we do Try.SRC - * successfully, need to switch to detect plug out. - * 5)Attached.SRC -> TryWait.SNK -> Attached.SNK: partner do Try.SRC - * successfully, disable detect interrupt. - * - * NOTE: Try.SRC and TryWait.SNK are embedded respectively in - * SRC_DISCONNECT and SNK_DISCONNECT in TCPMv1. Every time we go to - * Try.SRC/TryWait.SNK state, the plug in interrupt will be enabled and - * fire for 3), 4), 5) cases, then set correctly for the SRC detect plug - * out or the SNK disable detect, so TCPMv1 needn't this. - */ - it8xxx2_tcpm_switch_plug_out_type(port); -#endif - /* Enable PD PHY Tx and Rx module since type-c has connected. */ - USBPD_ENABLE_BMC_PHY(port); - it8xxx2_set_pd_sleep_mask(port); -} - -DECLARE_HOOK(HOOK_USB_PD_CONNECT, it8xxx2_tcpm_hook_connect, HOOK_PRIO_DEFAULT); - -static void it8xxx2_tcpm_hook_disconnect(void) -{ - int port = TASK_ID_TO_PD_PORT(task_get_current()); - - if (IS_ENABLED(IT83XX_INTC_PLUG_IN_OUT_SUPPORT)) - /* - * Switch to detect plug in and enable detect plug in interrupt, - * since pd task has detected a type-c physical disconnected. - */ - IT83XX_USBPD_TCDCR(port) &= ~(USBPD_REG_PLUG_OUT_SELECT | - USBPD_REG_PLUG_IN_OUT_DETECT_DISABLE); - - /* Exit BIST test data mode */ - USBPD_SW_RESET(port); - - /* - * Init rx status and disable PD PHY Tx and Rx module for better power - * consumption since type-c has disconnected. - */ - rx_en[port] = 0; - if (IS_ENABLED(CONFIG_USB_PD_DECODE_SOP)) - sop_prime_en[port] = 0; - USBPD_DISABLE_BMC_PHY(port); - it8xxx2_set_pd_sleep_mask(port); -} - -DECLARE_HOOK(HOOK_USB_PD_DISCONNECT, it8xxx2_tcpm_hook_disconnect, - HOOK_PRIO_DEFAULT); - -const struct tcpm_drv it8xxx2_tcpm_drv = { - .init = &it8xxx2_tcpm_init, - .release = &it8xxx2_tcpm_release, - .get_cc = &it8xxx2_tcpm_get_cc, - .select_rp_value = &it8xxx2_tcpm_select_rp_value, - .set_cc = &it8xxx2_tcpm_set_cc, - .set_polarity = &it8xxx2_tcpm_set_polarity, -#ifdef CONFIG_USB_PD_DECODE_SOP - .sop_prime_enable = &it8xxx2_tcpm_decode_sop_prime_enable, -#endif - .set_vconn = &it8xxx2_tcpm_set_vconn, - .set_msg_header = &it8xxx2_tcpm_set_msg_header, - .set_rx_enable = &it8xxx2_tcpm_set_rx_enable, - .get_message_raw = &it8xxx2_tcpm_get_message_raw, - .transmit = &it8xxx2_tcpm_transmit, -#ifdef CONFIG_USB_PD_DUAL_ROLE_AUTO_TOGGLE - .drp_toggle = NULL, -#endif - .get_chip_info = &it8xxx2_tcpm_get_chip_info, -#ifdef CONFIG_USB_PD_TCPC_LOW_POWER - .enter_low_power_mode = &it8xxx2_tcpm_enter_low_power_mode, -#endif -#ifdef CONFIG_USB_PD_FRS_TCPC - .set_frs_enable = &it8xxx2_tcpm_set_frs_enable, -#endif -}; diff --git a/driver/tcpm/ite_pd_intc.c b/driver/tcpm/ite_pd_intc.c deleted file mode 100644 index 2b5a391dfe..0000000000 --- a/driver/tcpm/ite_pd_intc.c +++ /dev/null @@ -1,87 +0,0 @@ -/* Copyright 2021 The Chromium OS Authors. All rights reserved. - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ - -#include "common.h" -#include "it83xx_pd.h" -#include "ite_pd_intc.h" -#include "task.h" -#include "tcpm/tcpm.h" -#include "usb_pd.h" - -void chip_pd_irq(enum usbpd_port port) -{ - task_clear_pending_irq(usbpd_ctrl_regs[port].irq); - - /* check status */ - if (IS_ENABLED(IT83XX_INTC_FAST_SWAP_SUPPORT) && - IS_ENABLED(CONFIG_USB_PD_FRS_TCPC) && - IS_ENABLED(CONFIG_USB_PD_REV30)) { - /* - * FRS detection must handle first, because we need to short - * the interrupt -> board_frs_handler latency-critical time. - */ - if (USBPD_IS_FAST_SWAP_DETECT(port)) { - /* clear detect FRS signal (cc to GND) status */ - USBPD_CLEAR_FRS_DETECT_STATUS(port); - if (board_frs_handler) - board_frs_handler(port); - /* inform TCPMv2 to change state */ - pd_got_frs_signal(port); - } - } - - if (USBPD_IS_HARD_RESET_DETECT(port)) { - /* clear interrupt */ - IT83XX_USBPD_ISR(port) = USBPD_REG_MASK_HARD_RESET_DETECT; - USBPD_SW_RESET(port); - task_set_event(PD_PORT_TO_TASK_ID(port), - PD_EVENT_RX_HARD_RESET); - } - - if (USBPD_IS_RX_DONE(port)) { - tcpm_enqueue_message(port); - /* clear RX done interrupt */ - IT83XX_USBPD_ISR(port) = USBPD_REG_MASK_MSG_RX_DONE; - } - - if (USBPD_IS_TX_DONE(port)) { -#ifdef CONFIG_USB_PD_TCPM_DRIVER_IT8XXX2 - it8xxx2_clear_tx_error_status(port); - /* check TX status, clear by TX_DONE status too */ - if (USBPD_IS_TX_ERR(port)) - it8xxx2_get_tx_error_status(port); -#endif - /* clear TX done interrupt */ - IT83XX_USBPD_ISR(port) = USBPD_REG_MASK_MSG_TX_DONE; - task_set_event(PD_PORT_TO_TASK_ID(port), - TASK_EVENT_PHY_TX_DONE); - } - - if (IS_ENABLED(IT83XX_INTC_PLUG_IN_OUT_SUPPORT)) { - if (USBPD_IS_PLUG_IN_OUT_DETECT(port)) { - if (USBPD_IS_PLUG_IN(port)) - /* - * When tcpc detect type-c plug in: - * 1)If we are sink, disable detect interrupt, - * messages on cc line won't trigger interrupt. - * 2)If we are source, then set plug out - * detection. - */ - switch_plug_out_type(port); - else - /* - * When tcpc detect type-c plug out: - * switch to detect plug in. - */ - IT83XX_USBPD_TCDCR(port) &= - ~USBPD_REG_PLUG_OUT_SELECT; - - /* clear type-c device plug in/out detect interrupt */ - IT83XX_USBPD_TCDCR(port) |= - USBPD_REG_PLUG_IN_OUT_DETECT_STAT; - task_set_event(PD_PORT_TO_TASK_ID(port), PD_EVENT_CC); - } - } -} diff --git a/driver/tcpm/ite_pd_intc.h b/driver/tcpm/ite_pd_intc.h deleted file mode 100644 index 8123e1a233..0000000000 --- a/driver/tcpm/ite_pd_intc.h +++ /dev/null @@ -1,22 +0,0 @@ -/* Copyright 2021 The Chromium OS Authors. All rights reserved. - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ - -/* ITE PD INTC control module */ - -#ifndef __CROS_EC_ITE_PD_INTC_H -#define __CROS_EC_ITE_PD_INTC_H - -/** - * ITE embedded PD interrupt routine - * - * NOTE: Enable ITE embedded PD that it requires CONFIG_USB_PD_TCPM_ITE_ON_CHIP - * - * @param port Type-C port number - * - * @return none - */ -void chip_pd_irq(enum usbpd_port port); - -#endif /* __CROS_EC_ITE_PD_INTC_H */ diff --git a/driver/tcpm/mt6370.c b/driver/tcpm/mt6370.c deleted file mode 100644 index 100a4d9eeb..0000000000 --- a/driver/tcpm/mt6370.c +++ /dev/null @@ -1,222 +0,0 @@ -/* Copyright 2018 The Chromium OS Authors. All rights reserved. - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - * - * MT6370 TCPC Driver - */ - -#include "console.h" -#include "hooks.h" -#include "mt6370.h" -#include "task.h" -#include "tcpm/tcpci.h" -#include "tcpm/tcpm.h" -#include "timer.h" -#include "usb_mux.h" -#include "usb_pd.h" -#include "util.h" - -#define CPRINTS(format, args...) cprints(CC_USBCHARGE, format, ## args) -#define CPRINTF(format, args...) cprintf(CC_USBCHARGE, format, ## args) - -static int mt6370_polarity; - -/* i2c_write function which won't wake TCPC from low power mode. */ -static int mt6370_i2c_write8(int port, int reg, int val) -{ - return i2c_write8(tcpc_config[port].i2c_info.port, - tcpc_config[port].i2c_info.addr_flags, reg, val); -} - -static int mt6370_init(int port) -{ - int rv, val; - - rv = tcpc_read(port, MT6370_REG_IDLE_CTRL, &val); - - /* Only do soft-reset in shipping mode. (b:122017882) */ - if (!(val & MT6370_REG_SHIPPING_OFF)) { - - /* Software reset. */ - rv = tcpc_write(port, MT6370_REG_SWRESET, 1); - if (rv) - return rv; - - /* Need 1 ms for software reset. */ - msleep(1); - } - - /* The earliest point that we can do generic init. */ - rv = tcpci_tcpm_init(port); - - if (rv) - return rv; - - /* - * AUTO IDLE off, shipping off, select CK_300K from BICIO_320K, - * PD3.0 ext-msg on. - */ - rv = tcpc_write(port, MT6370_REG_IDLE_CTRL, - MT6370_REG_IDLE_SET(0, 1, 0, 0)); - /* CC Detect Debounce 5 */ - rv |= tcpc_write(port, MT6370_REG_TTCPC_FILTER, 5); - /* DRP Duty */ - rv |= tcpc_write(port, MT6370_REG_DRP_TOGGLE_CYCLE, 4); - rv |= tcpc_write16(port, MT6370_REG_DRP_DUTY_CTRL, 400); - /* Vconn OC on */ - rv |= tcpc_write(port, MT6370_REG_VCONN_CLIMITEN, 1); - /* PHY control */ - rv |= tcpc_write(port, MT6370_REG_PHY_CTRL1, - MT6370_REG_PHY_CTRL1_SET(0, 7, 0, 1)); - rv |= tcpc_write(port, MT6370_REG_PHY_CTRL3, 0x82); - - return rv; -} - -static inline int mt6370_init_cc_params(int port, int cc_res) -{ - int rv, en, sel; - - if (cc_res == TYPEC_CC_VOLT_RP_DEF) { /* RXCC threshold : 0.55V */ - en = 1; - sel = MT6370_OCCTRL_600MA | MT6370_MASK_BMCIO_RXDZSEL; - } else { /* RD threshold : 0.4V & RP threshold : 0.7V */ - en = 0; - sel = MT6370_OCCTRL_600MA; - } - rv = tcpc_write(port, MT6370_REG_BMCIO_RXDZEN, en); - if (!rv) - rv = tcpc_write(port, MT6370_REG_BMCIO_RXDZSEL, sel); - return rv; -} - -static int mt6370_get_cc(int port, enum tcpc_cc_voltage_status *cc1, - enum tcpc_cc_voltage_status *cc2) -{ - int status; - int rv; - int role, is_snk; - - rv = tcpc_read(port, TCPC_REG_CC_STATUS, &status); - - /* If tcpc read fails, return error and CC as open */ - if (rv) { - *cc1 = TYPEC_CC_VOLT_OPEN; - *cc2 = TYPEC_CC_VOLT_OPEN; - return rv; - } - - *cc1 = TCPC_REG_CC_STATUS_CC1(status); - *cc2 = TCPC_REG_CC_STATUS_CC2(status); - - /* - * If status is not open, then OR in termination to convert to - * enum tcpc_cc_voltage_status. - * - * MT6370 TCPC follows USB PD 1.0 protocol. When DRP not auto-toggling, - * it will not update the DRP_RESULT bits in TCPC_REG_CC_STATUS, - * instead, we should check CC1/CC2 bits in TCPC_REG_ROLE_CTRL. - */ - rv = tcpc_read(port, TCPC_REG_ROLE_CTRL, &role); - - if (TCPC_REG_ROLE_CTRL_DRP(role)) - is_snk = TCPC_REG_CC_STATUS_TERM(status); - else - /* CC1/CC2 states are the same, checking one-side is enough. */ - is_snk = TCPC_REG_CC_STATUS_CC1(role) == TYPEC_CC_RD; - - if (is_snk) { - if (*cc1 != TYPEC_CC_VOLT_OPEN) - *cc1 |= 0x04; - if (*cc2 != TYPEC_CC_VOLT_OPEN) - *cc2 |= 0x04; - } - - rv = mt6370_init_cc_params(port, (int)mt6370_polarity ? *cc1 : *cc2); - return rv; -} - -static int mt6370_set_cc(int port, int pull) -{ - if (pull == TYPEC_CC_RD) - mt6370_init_cc_params(port, TYPEC_CC_VOLT_RP_DEF); - return tcpci_tcpm_set_cc(port, pull); -} - -#ifdef CONFIG_USB_PD_TCPC_LOW_POWER -static int mt6370_enter_low_power_mode(int port) -{ - int rv; - - /* VBUS_DET_EN for detecting charger plug. */ - rv = tcpc_write(port, MT6370_REG_BMC_CTRL, - MT6370_REG_BMCIO_LPEN | MT6370_REG_VBUS_DET_EN); - - if (rv) - return rv; - - return tcpci_enter_low_power_mode(port); -} -#endif - -static int mt6370_set_polarity(int port, enum tcpc_cc_polarity polarity) -{ - enum tcpc_cc_voltage_status cc1, cc2; - - mt6370_polarity = polarity; - mt6370_get_cc(port, &cc1, &cc2); - return tcpci_tcpm_set_polarity(port, polarity); -} - -int mt6370_vconn_discharge(int port) -{ - /* - * Write to mt6370 in low-power mode may return fail, but it is - * actually written. So we just ignore its return value. - */ - mt6370_i2c_write8(port, MT6370_REG_OVP_FLAG_SEL, - MT6370_REG_DISCHARGE_LVL); - /* Set MT6370_REG_DISCHARGE_EN bit and also the rest default value. */ - mt6370_i2c_write8(port, MT6370_REG_BMC_CTRL, - MT6370_REG_DISCHARGE_EN | - MT6370_REG_BMC_CTRL_DEFAULT); - - return EC_SUCCESS; -} - -/* MT6370 is a TCPCI compatible port controller */ -const struct tcpm_drv mt6370_tcpm_drv = { - .init = &mt6370_init, - .release = &tcpci_tcpm_release, - .get_cc = &mt6370_get_cc, -#ifdef CONFIG_USB_PD_VBUS_DETECT_TCPC - .check_vbus_level = &tcpci_tcpm_check_vbus_level, -#endif - .select_rp_value = &tcpci_tcpm_select_rp_value, - .set_cc = &mt6370_set_cc, - .set_polarity = &mt6370_set_polarity, -#ifdef CONFIG_USB_PD_DECODE_SOP - .sop_prime_enable = &tcpci_tcpm_sop_prime_enable, -#endif - .set_vconn = &tcpci_tcpm_set_vconn, - .set_msg_header = &tcpci_tcpm_set_msg_header, - .set_rx_enable = &tcpci_tcpm_set_rx_enable, - .get_message_raw = &tcpci_tcpm_get_message_raw, - .transmit = &tcpci_tcpm_transmit, - .tcpc_alert = &tcpci_tcpc_alert, -#ifdef CONFIG_USB_PD_DISCHARGE_TCPC - .tcpc_discharge_vbus = &tcpci_tcpc_discharge_vbus, -#endif -#ifdef CONFIG_USB_PD_DUAL_ROLE_AUTO_TOGGLE - .drp_toggle = &tcpci_tcpc_drp_toggle, -#endif - .get_chip_info = &tcpci_get_chip_info, -#ifdef CONFIG_USB_PD_PPC - .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 = &mt6370_enter_low_power_mode, -#endif - .set_bist_test_mode = &tcpci_set_bist_test_mode, -}; diff --git a/driver/tcpm/mt6370.h b/driver/tcpm/mt6370.h deleted file mode 100644 index cdc3112a3e..0000000000 --- a/driver/tcpm/mt6370.h +++ /dev/null @@ -1,200 +0,0 @@ -/* Copyright 2018 The Chromium OS Authors. All rights reserved. - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - * - * MT6370 TCPC Driver - */ - -#ifndef __CROS_EC_USB_PD_TCPM_MT6370_H -#define __CROS_EC_USB_PD_TCPM_MT6370_H - -/* MT6370 Private RegMap */ - -#define MT6370_REG_PHY_CTRL1 0x80 -#define MT6370_REG_PHY_CTRL2 0x81 -#define MT6370_REG_PHY_CTRL3 0x82 -#define MT6370_REG_PHY_CTRL6 0x85 - -#define MT6370_REG_CLK_CTRL2 0x87 -#define MT6370_REG_CLK_CTRL3 0x88 - -#define MT6370_REG_RUST_STATUS 0x8A -#define MT6370_REG_RUST_INT_EVENT 0x8B -#define MT6370_REG_RUST_MASK 0x8C -#define MT6370_REG_BMC_CTRL 0x90 -#define MT6370_REG_BMCIO_RXDZSEL 0x93 -#define MT6370_REG_VCONN_CLIMITEN 0x95 - -#define MT6370_REG_OVP_FLAG_SEL 0x96 - -#define MT6370_REG_RT_STATUS 0x97 -#define MT6370_REG_RT_INT 0x98 -#define MT6370_REG_RT_MASK 0x99 -#define RT5081_REG_BMCIO_RXDZEN 0x9A -#define MT6370_REG_IDLE_CTRL 0x9B -#define MT6370_REG_INTRST_CTRL 0x9C -#define MT6370_REG_WATCHDOG_CTRL 0x9D -#define MT6370_REG_I2CRST_CTRL 0X9E - -#define MT6370_REG_SWRESET 0xA0 -#define MT6370_REG_TTCPC_FILTER 0xA1 -#define MT6370_REG_DRP_TOGGLE_CYCLE 0xA2 -#define MT6370_REG_DRP_DUTY_CTRL 0xA3 -#define MT6370_REG_RUST_DETECTION 0xAD -#define MT6370_REG_RUST_CONTROL 0xAE -#define MT6370_REG_BMCIO_RXDZEN 0xAF -#define MT6370_REG_DRP_RUST 0xB9 - -#define MT6370_REG_UNLOCK_PW2 0xF0 -#define MT6370_REG_UNLOCK_PW1 0xF1 - -#define MT6370_TCPC_I2C_ADDR_FLAGS 0x4E - -/* - * MT6370_REG_PHY_CTRL1 0x80 - */ - -#define MT6370_REG_PHY_CTRL1_SET(retry_discard, toggle_cnt, bus_idle_cnt, \ - rx_filter) \ - ((retry_discard << 7) | (toggle_cnt << 4) | (bus_idle_cnt << 2) | \ - (rx_filter & 0x03)) - -/* - * MT6370_REG_CLK_CTRL2 0x87 - */ - -#define MT6370_REG_CLK_DIV_600K_EN BIT(7) -#define MT6370_REG_CLK_BCLK2_EN BIT(6) -#define MT6370_REG_CLK_BCLK2_TG_EN BIT(5) -#define MT6370_REG_CLK_DIV_300K_EN BIT(3) -#define MT6370_REG_CLK_CK_300K_EN BIT(2) -#define MT6370_REG_CLK_BCLK_EN BIT(1) -#define MT6370_REG_CLK_BCLK_TH_EN BIT(0) - -/* - * MT6370_REG_CLK_CTRL3 0x88 - */ - -#define MT6370_REG_CLK_OSCMUX_RG_EN BIT(7) -#define MT6370_REG_CLK_CK_24M_EN BIT(6) -#define MT6370_REG_CLK_OSC_RG_EN BIT(5) -#define MT6370_REG_CLK_DIV_2P4M_EN BIT(4) -#define MT6370_REG_CLK_CK_2P4M_EN BIT(3) -#define MT6370_REG_CLK_PCLK_EN BIT(2) -#define MT6370_REG_CLK_PCLK_RG_EN BIT(1) -#define MT6370_REG_CLK_PCLK_TG_EN BIT(0) - -/* - * MT6370_REG_RX_TX_DBG 0x8b - */ - -#define MT6370_REG_RX_TX_DBG_RX_BUSY BIT(7) -#define MT6370_REG_RX_TX_DBG_TX_BUSY BIT(6) - -/* - * MT6370_REG_BMC_CTRL 0x90 - */ - -#define MT6370_REG_IDLE_EN BIT(6) -#define MT6370_REG_DISCHARGE_EN BIT(5) -#define MT6370_REG_BMCIO_LPRPRD BIT(4) -#define MT6370_REG_BMCIO_LPEN BIT(3) -#define MT6370_REG_BMCIO_BG_EN BIT(2) -#define MT6370_REG_VBUS_DET_EN BIT(1) -#define MT6370_REG_BMCIO_OSC_EN BIT(0) -#define MT6370_REG_BMC_CTRL_DEFAULT \ - (MT6370_REG_BMCIO_BG_EN | MT6370_REG_VBUS_DET_EN | \ - MT6370_REG_BMCIO_OSC_EN) - -/* - * MT6370_REG_BMCIO_RXDZSEL 0x93 - */ - -#define MT6370_MASK_OCCTRL_SEL 0xE0 -#define MT6370_OCCTRL_600MA 0x80 -#define MT6370_MASK_BMCIO_RXDZSEL BIT(0) - -/* - * MT6370_REG_OVP_FLAG_SEL 0x96 - */ - -#define MT6370_MASK_DISCHARGE_LVL 0x03 -#define MT6370_REG_DISCHARGE_LVL BIT(0) - -/* - * MT6370_REG_RT_STATUS 0x97 - */ - -#define MT6370_REG_RA_DETACH BIT(5) -#define MT6370_REG_VBUS_80 BIT(1) - -/* - * MT6370_REG_RT_INT 0x98 - */ - -#define MT6370_REG_INT_RA_DETACH BIT(5) -#define MT6370_REG_INT_WATCHDOG BIT(2) -#define MT6370_REG_INT_VBUS_80 BIT(1) -#define MT6370_REG_INT_WAKEUP BIT(0) - -/* - * MT6370_REG_RT_MASK 0x99 - */ - -#define MT6370_REG_M_RA_DETACH BIT(5) -#define MT6370_REG_M_WATCHDOG BIT(2) -#define MT6370_REG_M_VBUS_80 BIT(1) -#define MT6370_REG_M_WAKEUP BIT(0) - -/* - * MT6370_REG_IDLE_CTRL 0x9B - */ - -#define MT6370_REG_CK_300K_SEL BIT(7) -#define MT6370_REG_SHIPPING_OFF BIT(5) -#define MT6370_REG_ENEXTMSG BIT(4) -#define MT6370_REG_AUTOIDLE_EN BIT(3) - -/* timeout = (tout*2+1) * 6.4ms */ -#ifdef CONFIG_USB_PD_REV30 -#define MT6370_REG_IDLE_SET(ck300, ship_dis, auto_idle, tout) \ - ((ck300 << 7) | (ship_dis << 5) | (auto_idle << 3) | (tout & 0x07) | \ - MT6370_REG_ENEXTMSG) -#else -#define MT6370_REG_IDLE_SET(ck300, ship_dis, auto_idle, tout) \ - ((ck300 << 7) | (ship_dis << 5) | (auto_idle << 3) | (tout & 0x07)) -#endif - -/* - * MT6370_REG_INTRST_CTRL 0x9C - */ - -#define MT6370_REG_INTRST_EN BIT(7) - -/* timeout = (tout+1) * 0.2sec */ -#define MT6370_REG_INTRST_SET(en, tout) ((en << 7) | (tout & 0x03)) - -/* - * MT6370_REG_WATCHDOG_CTRL 0x9D - */ - -#define MT6370_REG_WATCHDOG_EN BIT(7) - -/* timeout = (tout+1) * 0.4sec */ -#define MT6370_REG_WATCHDOG_CTRL_SET(en, tout) ((en << 7) | (tout & 0x07)) - -/* - * MT6370_REG_I2CRST_CTRL 0x9E - */ - -#define MT6370_REG_I2CRST_EN BIT(7) - -/* timeout = (tout+1) * 12.5ms */ -#define MT6370_REG_I2CRST_SET(en, tout) ((en << 7) | (tout & 0x0f)) - -extern const struct tcpm_drv mt6370_tcpm_drv; - -/* Enable VCONN discharge. */ -int mt6370_vconn_discharge(int port); - -#endif /* __CROS_EC_USB_PD_TCPM_MT6370_H */ diff --git a/driver/tcpm/nct38xx.c b/driver/tcpm/nct38xx.c deleted file mode 100644 index 00240516e5..0000000000 --- a/driver/tcpm/nct38xx.c +++ /dev/null @@ -1,377 +0,0 @@ -/* - * Copyright 2019 The Chromium OS Authors. All rights reserved. - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ - -/* Type-C port manager for Nuvoton NCT38XX. */ - -#include "common.h" -#include "console.h" -#include "hooks.h" -#include "nct38xx.h" -#include "task.h" -#include "tcpm/tcpci.h" -#include "usb_common.h" - -#if !defined(CONFIG_USB_PD_TCPM_TCPCI) -#error "NCT38XX is using part of standard TCPCI control" -#error "Please upgrade your board configuration" -#endif - -#define CPRINTF(format, args...) cprintf(CC_USBPD, format, ## args) -#define CPRINTS(format, args...) cprints(CC_USBPD, format, ## args) - -static enum nct38xx_boot_type boot_type[CONFIG_USB_PD_PORT_MAX_COUNT]; - -enum nct38xx_boot_type nct38xx_get_boot_type(int port) -{ - return boot_type[port]; -} - -void nct38xx_reset_notify(int port) -{ - /* A full reset also resets the chip's dead battery boot status */ - boot_type[port] = NCT38XX_BOOT_UNKNOWN; -} - -static int nct38xx_init(int port) -{ - int rv; - int reg; - - /* - * Detect dead battery boot by the default role control value of 0x0A - * once per EC run - */ - if (boot_type[port] == NCT38XX_BOOT_UNKNOWN) { - RETURN_ERROR(tcpc_read(port, TCPC_REG_ROLE_CTRL, ®)); - - if (reg == NCT38XX_ROLE_CTRL_DEAD_BATTERY) - boot_type[port] = NCT38XX_BOOT_DEAD_BATTERY; - else - boot_type[port] = NCT38XX_BOOT_NORMAL; - } - - RETURN_ERROR(tcpc_read(port, TCPC_REG_POWER_STATUS, ®)); - - /* - * Set TCPC_CONTROL.DebugAccessoryControl = 1 to control by TCPM, - * not TCPC in most cases. This must be left alone if we're on a - * dead battery boot with a debug accessory. CC line detection will - * be delayed if we have booted from a dead battery with a debug - * accessory and change this bit (see b/186799392). - */ - if ((boot_type[port] == NCT38XX_BOOT_DEAD_BATTERY) && - (reg & TCPC_REG_POWER_STATUS_DEBUG_ACC_CON)) - CPRINTS("C%d: Booted in dead battery mode, not changing debug" - " control", port); - else if (tcpc_config[port].flags & TCPC_FLAGS_NO_DEBUG_ACC_CONTROL) - CPRINTS("C%d: NO_DEBUG_ACC_CONTROL", port); - else - RETURN_ERROR(tcpc_update8(port, TCPC_REG_TCPC_CTRL, - TCPC_REG_TCPC_CTRL_DEBUG_ACC_CONTROL, - MASK_SET)); - - /* - * Write to the CONTROL_OUT_EN register to enable: - * [6] - CONNDIREN : Connector direction indication output enable - * [2] - SNKEN : VBUS sink enable output enable - * [0] - SRCEN : VBUS source voltage enable output enable - */ - reg = NCT38XX_REG_CTRL_OUT_EN_SRCEN | - NCT38XX_REG_CTRL_OUT_EN_SNKEN | - NCT38XX_REG_CTRL_OUT_EN_CONNDIREN; - - rv = tcpc_write(port, NCT38XX_REG_CTRL_OUT_EN, reg); - if (rv) - return rv; - - /* Disable OVP */ - rv = tcpc_update8(port, - TCPC_REG_FAULT_CTRL, - TCPC_REG_FAULT_CTRL_VBUS_OVP_FAULT_DIS, - MASK_SET); - if (rv) - return rv; - - /* Enable VBus monitor and Disable FRS */ - rv = tcpc_update8(port, - TCPC_REG_POWER_CTRL, - (TCPC_REG_POWER_CTRL_VBUS_VOL_MONITOR_DIS | - TCPC_REG_POWER_CTRL_FRS_ENABLE), - MASK_CLR); - if (rv) - return rv; - - /* Set FRS direction for SNK detect, if FRS is enabled */ - if (IS_ENABLED(CONFIG_USB_PD_FRS_TCPC)) { - reg = TCPC_REG_DEV_CAP_2_SNK_FR_SWAP; - rv = tcpc_write(port, TCPC_REG_DEV_CAP_2, reg); - if (rv) - return rv; - - reg = TCPC_REG_CONFIG_EXT_1_FR_SWAP_SNK_DIR; - rv = tcpc_write(port, TCPC_REG_CONFIG_EXT_1, reg); - if (rv) - return rv; - } - - /* Start VBus monitor */ - rv = tcpc_write(port, TCPC_REG_COMMAND, - TCPC_REG_COMMAND_ENABLE_VBUS_DETECT); - if (rv) - return rv; - - /** - * Set driver specific ALERT mask bits - * - * Wake up on faults - */ - reg = TCPC_REG_ALERT_FAULT; - - /* - * Enable the Vendor Define alert event only when the IO expander - * feature is defined - */ - if (IS_ENABLED(CONFIG_IO_EXPANDER_NCT38XX)) - reg |= TCPC_REG_ALERT_VENDOR_DEF; - - rv = tcpc_update16(port, - TCPC_REG_ALERT_MASK, - reg, - MASK_SET); - - if (rv) - return rv; - - /* Enable full VCONN protection (Over-Current and Short-Circuit) */ - reg = NCT38XX_REG_VBC_FAULT_CTL_VC_OCP_EN | - NCT38XX_REG_VBC_FAULT_CTL_VC_SCP_EN | - NCT38XX_REG_VBC_FAULT_CTL_FAULT_VC_OFF; - - rv = tcpc_update8(port, - NCT38XX_REG_VBC_FAULT_CTL, - reg, - MASK_SET); - - return rv; -} - -static int nct38xx_tcpm_init(int port) -{ - int rv; - - rv = tcpci_tcpm_init(port); - if (rv) - return rv; - - return nct38xx_init(port); -} - -static int nct38xx_tcpm_set_cc(int port, int pull) -{ - /* - * Setting the CC lines to open/open requires that the NCT CTRL_OUT - * register has sink disabled. Otherwise, when no battery is connected: - * - * 1. You set CC lines to Open/Open. This is physically happening on - * the CC line. - * 2. Since CC is now Open/Open, the internal TCPC HW state machine - * is no longer in Attached.Snk and therefore our TCPC HW - * automatically opens the sink switch (de-assert the VBSNK_EN pin) - * 3. Since sink switch is open, the TCPC VCC voltage starts to drop. - * 4. When TCPC VCC gets below ~2.7V the TCPC will reset and therefore - * it will present Rd/Rd on the CC lines. Also the VBSNK_EN pin - * after reset is Hi-Z, so the sink switch will get closed again. - * - * Disabling SNKEN makes the VBSNK_EN pin Hi-Z, so - * USB_Cx_TCPC_VBSNK_EN_L will be asserted by external - * pull-down, so only do so if already sinking, otherwise - * both source and sink switches can be closed, which should - * never happen (b/166850036). - * - * SNKEN will be re-enabled in nct38xx_init above (from tcpm_init), or - * when CC lines are set again, or when sinking is disabled. - */ - int rv; - enum mask_update_action action = - pull == TYPEC_CC_OPEN && tcpm_get_snk_ctrl(port) ? - MASK_CLR : MASK_SET; - - rv = tcpc_update8(port, - NCT38XX_REG_CTRL_OUT_EN, - NCT38XX_REG_CTRL_OUT_EN_SNKEN, - action); - if (rv) - return rv; - - return tcpci_tcpm_set_cc(port, pull); -} - -#ifdef CONFIG_USB_PD_PPC -static int nct38xx_tcpm_set_snk_ctrl(int port, int enable) -{ - int rv; - - /* - * To disable sinking, SNKEN must be enabled so that - * USB_Cx_TCPC_VBSNK_EN_L will be driven high. - */ - if (!enable) { - rv = tcpc_update8(port, - NCT38XX_REG_CTRL_OUT_EN, - NCT38XX_REG_CTRL_OUT_EN_SNKEN, - MASK_SET); - if (rv) - return rv; - } - - return tcpci_tcpm_set_snk_ctrl(port, enable); -} -#endif - -static inline int tcpc_read_alert_no_lpm_exit(int port, int *val) -{ - return tcpc_addr_read16_no_lpm_exit(port, - tcpc_config[port].i2c_info.addr_flags, - TCPC_REG_ALERT, val); -} - -/* Map Type-C port to IOEX port */ -__overridable int board_map_nct38xx_tcpc_port_to_ioex(int port) -{ - return port; -} - -static void nct38xx_tcpc_alert(int port) -{ - int alert, rv; - - /* - * The nct3808 is a dual port chip with a shared ALERT - * pin. Avoid taking a port out of LPM if it is not alerting. - * - * The nct38xx exits Idle mode when ALERT is signaled, so there - * is no need to run the TCPM LPM exit code to check the ALERT - * register bits (Ref. NCT38n7/8 Datasheet S 2.3.4 "Setting the - * I2C to * Idle"). In fact, running the TCPM LPM exit code - * causes a new CC Status ALERT which has the effect of creating - * a new ALERT as a side-effect of handing an ALERT. - */ - rv = tcpc_read_alert_no_lpm_exit(port, &alert); - if (rv == EC_SUCCESS && alert == TCPC_REG_ALERT_NONE) { - /* No ALERT on this port, return early. */ - return; - } - - /* Process normal TCPC ALERT event and clear status. */ - tcpci_tcpc_alert(port); - - /* - * If the IO expander feature is enabled, use the ALERT register - * value read before it was cleared by calling - * tcpci_tcpc_alert(). Check the Vendor Defined Alert bit to - * handle the IOEX IO's interrupt event. - */ - if (IS_ENABLED(CONFIG_IO_EXPANDER_NCT38XX) && - rv == EC_SUCCESS && (alert & TCPC_REG_ALERT_VENDOR_DEF)) { - int ioexport; - - ioexport = board_map_nct38xx_tcpc_port_to_ioex(port); - nct38xx_ioex_event_handler(ioexport); - } -} - -static int nct3807_handle_fault(int port, int fault) -{ - int rv = EC_SUCCESS; - - /* Registers are set to default, initialize for our use */ - if (fault & TCPC_REG_FAULT_STATUS_ALL_REGS_RESET) { - rv = nct38xx_init(port); - } else { - /* We don't use TCPC OVP, so just disable it */ - if (fault & TCPC_REG_FAULT_STATUS_VBUS_OVER_VOLTAGE) { - /* Disable OVP */ - rv = tcpc_update8(port, - TCPC_REG_FAULT_CTRL, - TCPC_REG_FAULT_CTRL_VBUS_OVP_FAULT_DIS, - MASK_SET); - if (rv) - return rv; - } - /* Failing AutoDischargeDisconnect should disable it */ - if (fault & TCPC_REG_FAULT_STATUS_AUTO_DISCHARGE_FAIL) - tcpm_enable_auto_discharge_disconnect(port, 0); - } - return rv; -} - -__maybe_unused static int nct38xx_set_frs_enable(int port, int enable) -{ - /* - * From b/192012189: Enabling FRS for this chip should: - * - * 1. Make sure that the sink will not disconnect if Vbus will drop - * due to the Fast Role Swap by setting VBUS_SINK_DISCONNECT_THRESHOLD - * to 0 - * 2. Enable the FRS interrupt (already done in TCPCI alert init) - * 3. Set POWER_CONTORL.FastRoleSwapEnable to 1 - */ - RETURN_ERROR(tcpc_write16(port, - TCPC_REG_VBUS_SINK_DISCONNECT_THRESH, - enable ? 0x0000 : - TCPC_REG_VBUS_SINK_DISCONNECT_THRESH_DEFAULT)); - - return tcpc_update8(port, - TCPC_REG_POWER_CTRL, - TCPC_REG_POWER_CTRL_FRS_ENABLE, - enable ? MASK_SET : MASK_CLR); -} - -const struct tcpm_drv nct38xx_tcpm_drv = { - .init = &nct38xx_tcpm_init, - .release = &tcpci_tcpm_release, - .get_cc = &tcpci_tcpm_get_cc, -#ifdef CONFIG_USB_PD_VBUS_DETECT_TCPC - .check_vbus_level = &tcpci_tcpm_check_vbus_level, -#endif - .select_rp_value = &tcpci_tcpm_select_rp_value, - .set_cc = &nct38xx_tcpm_set_cc, - .set_polarity = &tcpci_tcpm_set_polarity, -#ifdef CONFIG_USB_PD_DECODE_SOP - .sop_prime_enable = &tcpci_tcpm_sop_prime_enable, -#endif - .set_vconn = &tcpci_tcpm_set_vconn, - .set_msg_header = &tcpci_tcpm_set_msg_header, - .set_rx_enable = &tcpci_tcpm_set_rx_enable, - .get_message_raw = &tcpci_tcpm_get_message_raw, - .transmit = &tcpci_tcpm_transmit, - .tcpc_alert = &nct38xx_tcpc_alert, -#ifdef CONFIG_USB_PD_DISCHARGE_TCPC - .tcpc_discharge_vbus = &tcpci_tcpc_discharge_vbus, -#endif - .tcpc_enable_auto_discharge_disconnect = - &tcpci_tcpc_enable_auto_discharge_disconnect, - .debug_accessory = &tcpci_tcpc_debug_accessory, - -#ifdef CONFIG_USB_PD_DUAL_ROLE_AUTO_TOGGLE - .drp_toggle = &tcpci_tcpc_drp_toggle, -#endif -#ifdef CONFIG_USB_PD_PPC - .get_snk_ctrl = &tcpci_tcpm_get_snk_ctrl, - .set_snk_ctrl = &nct38xx_tcpm_set_snk_ctrl, - .get_src_ctrl = &tcpci_tcpm_get_src_ctrl, - .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 - .set_bist_test_mode = &tcpci_set_bist_test_mode, -#ifdef CONFIG_USB_PD_FRS_TCPC - .set_frs_enable = &nct38xx_set_frs_enable, -#endif - .handle_fault = &nct3807_handle_fault, -}; diff --git a/driver/tcpm/nct38xx.h b/driver/tcpm/nct38xx.h deleted file mode 100644 index a63a9f0808..0000000000 --- a/driver/tcpm/nct38xx.h +++ /dev/null @@ -1,149 +0,0 @@ -/* - * Copyright 2019 The Chromium OS Authors. All rights reserved. - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ - -/* Nuvoton Type-C port controller */ - -#ifndef __CROS_EC_USB_PD_TCPM_NCT38XX_H -#define __CROS_EC_USB_PD_TCPM_NCT38XX_H - -/* Chip variant ID (Part number) */ -#define NCT38XX_VARIANT_MASK 0x1C -#define NCT38XX_VARIANT_3807 0x0 -#define NCT38XX_VARIANT_3808 0x2 - -/* There are two IO ports in NCT3807 */ -#define NCT38XX_NCT3807_MAX_IO_PORT 2 -/* There is only one IO port in NCT3808 */ -#define NCT38XX_NCT3808_MAX_IO_PORT 1 - -#define NCT38XX_SUPPORT_GPIO_FLAGS (GPIO_OPEN_DRAIN | GPIO_INPUT | \ - GPIO_OUTPUT | GPIO_LOW | GPIO_HIGH | GPIO_INT_F_RISING | \ - GPIO_INT_F_FALLING | GPIO_INT_F_HIGH | GPIO_INT_F_LOW) - -/* I2C interface */ -#define NCT38XX_I2C_ADDR1_1_FLAGS 0x70 -#define NCT38XX_I2C_ADDR1_2_FLAGS 0x71 -#define NCT38XX_I2C_ADDR1_3_FLAGS 0x72 -#define NCT38XX_I2C_ADDR1_4_FLAGS 0x73 - -#define NCT38XX_I2C_ADDR2_1_FLAGS 0x74 -#define NCT38XX_I2C_ADDR2_2_FLAGS 0x75 -#define NCT38XX_I2C_ADDR2_3_FLAGS 0x76 -#define NCT38XX_I2C_ADDR2_4_FLAGS 0x77 - -#define NCT38XX_REG_VENDOR_ID_L 0x00 -#define NCT38XX_REG_VENDOR_ID_H 0x01 -#define NCT38XX_VENDOR_ID 0x0416 - -#define NCT38XX_PRODUCT_ID 0xC301 - -/* - * Default value from the ROLE_CTRL register on first boot will depend on - * whether we're coming from a dead battery state. - */ -#define NCT38XX_ROLE_CTRL_DEAD_BATTERY 0x0A -#define NCT39XX_ROLE_CTRL_GOOD_BATTERY 0x4A - -#define NCT38XX_REG_GPIO_DATA_IN(n) (0xC0 + ((n) * 8)) -#define NCT38XX_REG_GPIO_DATA_OUT(n) (0xC1 + ((n) * 8)) -#define NCT38XX_REG_GPIO_DIR(n) (0xC2 + ((n) * 8)) -#define NCT38XX_REG_GPIO_OD_SEL(n) (0xC3 + ((n) * 8)) -#define NCT38XX_REG_GPIO_ALERT_RISE(n) (0xC4 + ((n) * 8)) -#define NCT38XX_REG_GPIO_ALERT_FALL(n) (0xC5 + ((n) * 8)) -#define NCT38XX_REG_GPIO_ALERT_LEVEL(n) (0xC6 + ((n) * 8)) -#define NCT38XX_REG_GPIO_ALERT_MASK(n) (0xC7 + ((n) * 8)) -#define NCT38XX_REG_MUX_CONTROL 0xD0 -#define NCT38XX_REG_GPIO_ALERT_STAT(n) (0xD4 + (n)) - -/* NCT3808 only supports GPIO 2/3/4/6/7 */ -#define NCT38XXX_3808_VALID_GPIO_MASK 0xDC - -#define NCT38XX_REG_CTRL_OUT_EN 0xD2 -#define NCT38XX_REG_CTRL_OUT_EN_SRCEN (1 << 0) -#define NCT38XX_REG_CTRL_OUT_EN_FASTEN (1 << 1) -#define NCT38XX_REG_CTRL_OUT_EN_SNKEN (1 << 2) -#define NCT38XX_REG_CTRL_OUT_EN_CONNDIREN (1 << 6) - -#define NCT38XX_REG_VBC_FAULT_CTL 0xD7 -#define NCT38XX_REG_VBC_FAULT_CTL_VC_OCP_EN (1 << 0) -#define NCT38XX_REG_VBC_FAULT_CTL_VC_SCP_EN (1 << 1) -#define NCT38XX_REG_VBC_FAULT_CTL_FAULT_VC_OFF (1 << 3) -#define NCT38XX_REG_VBC_FAULT_CTL_VB_OCP_OFF (1 << 4) -#define NCT38XX_REG_VBC_FAULT_CTL_VC_OVP_OFF (1 << 5) - -#define NCT38XX_RESET_HOLD_DELAY_MS 1 - -/* - * From the datasheet (section 4.4.2 Reset Timing) as following: - * | Min | Max | - * ----------------------+-------+-------+ - * NCT3807 (single port) | x | 1.5ms | - * ----------------------+-------+-------+ - * NCT3808 (dual port) | x | 3ms | - * ----------------------+-------+-------+ - */ -#define NCT3807_RESET_POST_DELAY_MS 2 -#define NCT3808_RESET_POST_DELAY_MS 3 - -extern const struct tcpm_drv nct38xx_tcpm_drv; - -/* - * The interrupt handler to handle Vendor Define ALERT event from IOEX chip. - * - * Normally, the Vendor Define event should be checked by the NCT38XX TCPCI - * driver's tcpc_alert function. - * This function is only included when NCT38XX TCPC driver is not included. - * (i.e. CONFIG_USB_PD_TCPM_NCT38XX is not defined) - */ -void nct38xx_ioex_handle_alert(int ioex); - -/* - * Check which IO's interrupt event is triggered. If any, call its - * registered interrupt handler. - * - * @param ioex I/O expander number - * @return EC_SUCCESS on success else error - */ -int nct38xx_ioex_event_handler(int ioex); - -/* - * Board level function to map USB-C port to IOEX port - * - * Default function assumes USB-C port number to be same as the - * I/O expander port number. If this logic differs, add an - * overridable function at the board level. - * - * @param port USB-C port number - * @return IOEX port number - */ -__override_proto int board_map_nct38xx_tcpc_port_to_ioex(int port); - -enum nct38xx_boot_type { - NCT38XX_BOOT_UNKNOWN, - NCT38XX_BOOT_DEAD_BATTERY, - NCT38XX_BOOT_NORMAL, -}; - -/** - * Collect our boot type from the driver - * - * @param port USB-C port number - * @return Returns the boot type detected for this chip - */ -enum nct38xx_boot_type nct38xx_get_boot_type(int port); - -/** - * Notify the driver that the TCPC has been reset, and any stored state from - * the chip should therefore be gathered again. This should be called when - * board_reset_pd_mcu is called after init time. - * - * @param port USB-C port number which has been reset - */ -void nct38xx_reset_notify(int port); - -extern const struct ioexpander_drv nct38xx_ioexpander_drv; - -#endif /* defined(__CROS_EC_USB_PD_TCPM_NCT38XX_H) */ diff --git a/driver/tcpm/ps8xxx.c b/driver/tcpm/ps8xxx.c deleted file mode 100644 index 4643c669c0..0000000000 --- a/driver/tcpm/ps8xxx.c +++ /dev/null @@ -1,1037 +0,0 @@ -/* Copyright 2017 The Chromium OS Authors. All rights reserved. - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ - -/* - * Type-C port manager for Parade PS8XXX with integrated superspeed muxes. - * - * Supported TCPCs: - * - PS8705 - * - PS8751 - * - PS8755 - * - PS8805 - * - PS8815 - */ - -#include "common.h" -#include "console.h" -#include "ps8xxx.h" -#include "tcpm/tcpci.h" -#include "tcpm/tcpm.h" -#include "timer.h" -#include "usb_mux.h" -#include "usb_pd.h" - -#if !defined(CONFIG_USB_PD_TCPM_PS8705) && \ - !defined(CONFIG_USB_PD_TCPM_PS8751) && \ - !defined(CONFIG_USB_PD_TCPM_PS8755) && \ - !defined(CONFIG_USB_PD_TCPM_PS8805) && \ - !defined(CONFIG_USB_PD_TCPM_PS8815) -#error "Unsupported PS8xxx TCPC." -#endif - -#if !defined(CONFIG_USB_PD_TCPM_TCPCI) || \ - !defined(CONFIG_USB_PD_TCPM_MUX) || \ - !defined(CONFIG_USBC_SS_MUX) - -#error "PS8XXX is using a standard TCPCI interface with integrated mux control" -#error "Please upgrade your board configuration" - -#endif - -#ifdef CONFIG_USB_PD_TCPM_PS8751 -/* PS8751 cannot run with PD 3.0 (see b/148554997 for details) */ -#if defined(CONFIG_USB_PD_REV30) -#error "PS8751 cannot run with PD 3.0. Fall back to using PD 2.0" -#endif - -#endif /* CONFIG_USB_PD_TCPM_PS8751 */ - -#ifdef CONFIG_USB_PD_TCPM_PS8751_CUSTOM_MUX_DRIVER -#if !defined(CONFIG_USB_PD_TCPM_PS8751) -#error "Custom MUX driver is available only for PS8751" -#endif - -#endif /* CONFIG_USB_PD_TCPM_PS8751_CUSTOM_MUX_DRIVER */ - -#define CPRINTF(format, args...) cprintf(CC_USBPD, format, ## args) -#define CPRINTS(format, args...) cprints(CC_USBPD, format, ## args) - -#define PS8XXX_I2C_RECOVERY_DELAY_MS 10 - -/* - * The product_id per ports here is expected to be set in callback function - - * .init of tcpm_drv by calling board_get_ps8xxx_product_id(). - * - * In case of CONFIG_USB_PD_TCPM_MULTI_PS8XXX enabled, board code should - * override the board_get_ps8xxx_product_id() for getting the correct id. - */ -static uint16_t product_id[CONFIG_USB_PD_PORT_MAX_COUNT]; - -/* - * Revisions A1 and A0 of the PS8815 can corrupt the transmit buffer when - * updating the transmit buffer within 1ms of writing the ROLE_CONTROL - * register. When this version of silicon is detected, add a 1ms delay before - * all writes to the transmit buffer. - * - * See b/171430855 for details. - */ -static uint8_t ps8xxx_role_control_delay_ms[CONFIG_USB_PD_PORT_MAX_COUNT]; - -/* - * b/178664884, on PS8815, firmware revision 0x10 and older can report an - * incorrect value on the the CC lines. This flag controls when to apply - * the workaround. - */ -static bool ps8815_disable_rp_detect[CONFIG_USB_PD_PORT_MAX_COUNT]; -static bool ps8815_disconnected[CONFIG_USB_PD_PORT_MAX_COUNT]; -/* - * timestamp of the next possible toggle to ensure the 2-ms spacing - * between IRQ_HPD. - */ -static uint64_t hpd_deadline[CONFIG_USB_PD_PORT_MAX_COUNT]; - -void ps8xxx_wake_from_standby(const struct usb_mux *me); - -#if defined(CONFIG_USB_PD_TCPM_PS8705) || \ - defined(CONFIG_USB_PD_TCPM_PS8751) || \ - defined(CONFIG_USB_PD_TCPM_PS8755) || \ - defined(CONFIG_USB_PD_TCPM_PS8805) -/* - * DCI is enabled by default and burns about 40 mW when the port is in - * USB2 mode or when a C-to-A dongle is attached, so force it off. - */ - -static int ps8xxx_addr_dci_disable(int port, int i2c_addr, int i2c_reg) -{ - int status; - int dci; - - status = tcpc_addr_read(port, i2c_addr, i2c_reg, &dci); - if (status != EC_SUCCESS) - return status; - if ((dci & PS8XXX_REG_MUX_USB_DCI_CFG_MODE_MASK) != - PS8XXX_REG_MUX_USB_DCI_CFG_MODE_OFF) { - dci &= ~PS8XXX_REG_MUX_USB_DCI_CFG_MODE_MASK; - dci |= PS8XXX_REG_MUX_USB_DCI_CFG_MODE_OFF; - if (tcpc_addr_write(port, i2c_addr, i2c_reg, dci) != EC_SUCCESS) - return status; - } - return EC_SUCCESS; -} -#endif /* CONFIG_USB_PD_TCPM_PS875[15] || CONFIG_USB_PD_TCPM_PS8[78]05 */ - -#if defined(CONFIG_USB_PD_TCPM_PS8705) || \ - defined(CONFIG_USB_PD_TCPM_PS8755) || \ - defined(CONFIG_USB_PD_TCPM_PS8805) -static int ps8705_dci_disable(int port) -{ - int p1_addr; - int p3_addr; - int regval; - int rv; - - /* Enable access to debug pages. */ - p3_addr = tcpc_config[port].i2c_info.addr_flags; - rv = tcpc_addr_read(port, p3_addr, PS8XXX_REG_I2C_DEBUGGING_ENABLE, - ®val); - if (rv) - return rv; - - rv = tcpc_addr_write(port, p3_addr, PS8XXX_REG_I2C_DEBUGGING_ENABLE, - PS8XXX_REG_I2C_DEBUGGING_ENABLE_ON); - - /* Disable Auto DCI */ - p1_addr = PS8751_P3_TO_P1_FLAGS(p3_addr); - rv = ps8xxx_addr_dci_disable(port, p1_addr, - PS8XXX_P1_REG_MUX_USB_DCI_CFG); - - /* - * PS8705/PS8755/PS8805 will automatically re-assert bit:0 on the - * PS8XXX_REG_I2C_DEBUGGING_ENABLE register. - */ - return rv; -} -#endif /* CONFIG_USB_PD_TCPM_PS8755 || CONFIG_USB_PD_TCPM_PS8[78]05 */ - -#ifdef CONFIG_USB_PD_TCPM_PS8751 -static int ps8751_dci_disable(int port) -{ - int p3_addr; - - p3_addr = tcpc_config[port].i2c_info.addr_flags; - return ps8xxx_addr_dci_disable(port, p3_addr, - PS8751_REG_MUX_USB_DCI_CFG); -} -#endif /* CONFIG_USB_PD_TCPM_PS8751 */ - -#ifdef CONFIG_USB_PD_TCPM_PS8815 -static int ps8815_dci_disable(int port) -{ - /* DCI is disabled on the ps8815 */ - return EC_SUCCESS; -} -#endif /* CONFIG_USB_PD_TCPM_PS8815 */ - -#ifdef CONFIG_USB_PD_TCPM_PS8805 -static int ps8805_gpio_mask[] = { - PS8805_REG_GPIO_0, - PS8805_REG_GPIO_1, - PS8805_REG_GPIO_2, -}; - -int ps8805_gpio_set_level(int port, enum ps8805_gpio signal, int level) -{ - int rv; - int regval; - int mask; - - if (signal >= PS8805_GPIO_NUM) - return EC_ERROR_INVAL; - - rv = i2c_read8(tcpc_config[port].i2c_info.port, - PS8805_VENDOR_DEFINED_I2C_ADDR, - PS8805_REG_GPIO_CONTROL, ®val); - if (rv) - return rv; - - mask = ps8805_gpio_mask[signal]; - if (level) - regval |= mask; - else - regval &= ~mask; - - return i2c_write8(tcpc_config[port].i2c_info.port, - PS8805_VENDOR_DEFINED_I2C_ADDR, - PS8805_REG_GPIO_CONTROL, regval); -} - -int ps8805_gpio_get_level(int port, enum ps8805_gpio signal, int *level) -{ - int regval; - int rv; - - if (signal >= PS8805_GPIO_NUM) - return EC_ERROR_INVAL; - - rv = i2c_read8(tcpc_config[port].i2c_info.port, - PS8805_VENDOR_DEFINED_I2C_ADDR, - PS8805_REG_GPIO_CONTROL, ®val); - if (rv) - return rv; - *level = !!(regval & ps8805_gpio_mask[signal]); - - return EC_SUCCESS; -} -#endif /* CONFIG_USB_PD_TCPM_PS8805 */ - -enum ps8xxx_variant_regs { - REG_FIRST_INDEX = 0, - /* NOTE: The rev will read as 0x00 if the FW has malfunctioned. */ - REG_FW_VER = REG_FIRST_INDEX, - REG_MAX_COUNT, -}; - -struct ps8xxx_variant_map { - int product_id; - int (*dci_disable_ptr)(int port); - int reg_map[REG_MAX_COUNT]; -}; - -/* - * variant_map here is leveraged to lookup from ps8xxx_variant_regs to i2c - * register and corresponding dci_disable function based on product_id. - */ -static struct ps8xxx_variant_map variant_map[] = { -#ifdef CONFIG_USB_PD_TCPM_PS8705 - { - PS8705_PRODUCT_ID, - ps8705_dci_disable, - { - [REG_FW_VER] = 0x82, - } - }, -#endif -#ifdef CONFIG_USB_PD_TCPM_PS8751 - { - PS8751_PRODUCT_ID, - ps8751_dci_disable, - { - [REG_FW_VER] = 0x90, - } - }, -#endif -#ifdef CONFIG_USB_PD_TCPM_PS8755 - { - PS8755_PRODUCT_ID, - ps8705_dci_disable, - { - [REG_FW_VER] = 0x82, - } - }, -#endif -#ifdef CONFIG_USB_PD_TCPM_PS8805 - { - PS8805_PRODUCT_ID, - ps8705_dci_disable, - { - [REG_FW_VER] = 0x82, - } - }, -#endif -#ifdef CONFIG_USB_PD_TCPM_PS8815 - { - PS8815_PRODUCT_ID, - ps8815_dci_disable, - { - [REG_FW_VER] = 0x82, - } - }, -#endif -}; - -static int get_reg_by_product(const int port, - const enum ps8xxx_variant_regs reg) -{ - int i; - - if (reg < REG_FIRST_INDEX || reg >= REG_MAX_COUNT) - return INT32_MAX; - - for (i = 0; i < ARRAY_SIZE(variant_map); i++) { - if (product_id[port] == - variant_map[i].product_id) { - return variant_map[i].reg_map[reg]; - } - } - - CPRINTS("%s: failed to get register number by product_id.", __func__); - return INT32_MAX; -} - -static int dp_set_hpd(const struct usb_mux *me, int enable) -{ - int reg; - int rv; - - rv = mux_read(me, MUX_IN_HPD_ASSERTION_REG, ®); - if (rv) - return rv; - if (enable) - reg |= IN_HPD; - else - reg &= ~IN_HPD; - return mux_write(me, MUX_IN_HPD_ASSERTION_REG, reg); -} - -static int dp_set_irq(const struct usb_mux *me, int enable) -{ - int reg; - int rv; - - rv = mux_read(me, MUX_IN_HPD_ASSERTION_REG, ®); - if (rv) - return rv; - if (enable) - reg |= HPD_IRQ; - else - reg &= ~HPD_IRQ; - return mux_write(me, MUX_IN_HPD_ASSERTION_REG, reg); -} - -__overridable -uint16_t board_get_ps8xxx_product_id(int port) -{ - /* Board supporting multiple chip sources in ps8xxx.c MUST override this - * function to judge the real chip source for this board. For example, - * SKU ID / strappings / provisioning in the factory can be the ways. - */ - - if (IS_ENABLED(CONFIG_USB_PD_TCPM_MULTI_PS8XXX)) { - CPRINTS("%s: board should override this function.", __func__); - return 0; - } else if (IS_ENABLED(CONFIG_USB_PD_TCPM_PS8705)) { - return PS8705_PRODUCT_ID; - } else if (IS_ENABLED(CONFIG_USB_PD_TCPM_PS8751)) { - return PS8751_PRODUCT_ID; - } else if (IS_ENABLED(CONFIG_USB_PD_TCPM_PS8755)) { - return PS8755_PRODUCT_ID; - } else if (IS_ENABLED(CONFIG_USB_PD_TCPM_PS8805)) { - return PS8805_PRODUCT_ID; - } else if (IS_ENABLED(CONFIG_USB_PD_TCPM_PS8815)) { - return PS8815_PRODUCT_ID; - } - - CPRINTS("%s: Any new product id is not defined here?", __func__); - return 0; -} - -bool check_ps8755_chip(int port) -{ - int val; - int p0_addr; - int status; - bool is_ps8755 = false; - - p0_addr = PS8751_P3_TO_P0_FLAGS(tcpc_config[port].i2c_info.addr_flags); - status = tcpc_addr_read(port, p0_addr, PS8755_P0_REG_SM, &val); - if (status == EC_SUCCESS && val == PS8755_P0_REG_SM_VALUE) - is_ps8755 = true; - - return is_ps8755; -} - -void ps8xxx_tcpc_update_hpd_status(const struct usb_mux *me, - mux_state_t mux_state) -{ - int port = me->usb_port; - int hpd_lvl = (mux_state & USB_PD_MUX_HPD_LVL) ? 1 : 0; - int hpd_irq = (mux_state & USB_PD_MUX_HPD_IRQ) ? 1 : 0; - - if (IS_ENABLED(CONFIG_USB_PD_TCPM_PS8751_CUSTOM_MUX_DRIVER) && - product_id[me->usb_port] == PS8751_PRODUCT_ID && - me->flags & USB_MUX_FLAG_NOT_TCPC) - ps8xxx_wake_from_standby(me); - - dp_set_hpd(me, hpd_lvl); - - if (hpd_irq) { - uint64_t now = get_time().val; - /* wait for the minimum spacing between IRQ_HPD if needed */ - if (now < hpd_deadline[port]) - usleep(hpd_deadline[port] - now); - - dp_set_irq(me, 0); - usleep(HPD_DSTREAM_DEBOUNCE_IRQ); - dp_set_irq(me, hpd_irq); - } - /* enforce 2-ms delay between HPD pulses */ - hpd_deadline[port] = get_time().val + HPD_USTREAM_DEBOUNCE_LVL; -} - -static int ps8xxx_tcpc_bist_mode_2(int port) -{ - int rv; - - /* Generate BIST for 50ms. */ - rv = tcpc_write(port, - PS8XXX_REG_BIST_CONT_MODE_BYTE0, PS8751_BIST_COUNTER_BYTE0); - rv |= tcpc_write(port, - PS8XXX_REG_BIST_CONT_MODE_BYTE1, PS8751_BIST_COUNTER_BYTE1); - rv |= tcpc_write(port, - PS8XXX_REG_BIST_CONT_MODE_BYTE2, PS8751_BIST_COUNTER_BYTE2); - - /* Auto stop */ - rv |= tcpc_write(port, PS8XXX_REG_BIST_CONT_MODE_CTR, 0); - - /* Start BIST MODE 2 */ - rv |= tcpc_write(port, TCPC_REG_TRANSMIT, TCPCI_MSG_TX_BIST_MODE_2); - - return rv; -} - -static int ps8xxx_tcpm_transmit(int port, enum tcpci_msg_type type, - uint16_t header, const uint32_t *data) -{ - if (type == TCPCI_MSG_TX_BIST_MODE_2) - return ps8xxx_tcpc_bist_mode_2(port); - else - return tcpci_tcpm_transmit(port, type, header, data); -} - -static int ps8xxx_tcpm_release(int port) -{ - int version; - int status; - int reg = get_reg_by_product(port, REG_FW_VER); - - status = tcpc_read(port, reg, &version); - if (status != 0) { - /* wait for chip to wake up */ - msleep(10); - } - - return tcpci_tcpm_release(port); -} - -static void ps8xxx_role_control_delay(int port) -{ - int delay; - - delay = ps8xxx_role_control_delay_ms[port]; - if (delay) - msleep(delay); -} - -#ifdef CONFIG_USB_PD_DUAL_ROLE_AUTO_TOGGLE -static int ps8xxx_set_role_ctrl(int port, enum tcpc_drp drp, - enum tcpc_rp_value rp, enum tcpc_cc_pull pull) -{ - int rv; - - rv = tcpci_set_role_ctrl(port, drp, rp, pull); - - /* - * b/171430855 delay 1 ms after ROLE_CONTROL updates to prevent - * transmit buffer corruption - */ - ps8xxx_role_control_delay(port); - - return rv; -} - -static int ps8xxx_tcpc_drp_toggle(int port) -{ - int rv; - int status; - int opposite_pull; - - /* - * Workaround for PS8805/PS8815, which can't restart Connection - * Detection if the partner already presents pull. Now starts with - * the opposite pull. Check b/149570002. - */ - if (product_id[port] == PS8805_PRODUCT_ID || - product_id[port] == PS8815_PRODUCT_ID) { - if (ps8815_disable_rp_detect[port]) { - CPRINTS("TCPC%d: rearm Rp disable detect on connect", - port); - ps8815_disconnected[port] = true; - } - - /* Check CC_STATUS for the current pull */ - rv = tcpc_read(port, TCPC_REG_CC_STATUS, &status); - if (status & TCPC_REG_CC_STATUS_CONNECT_RESULT_MASK) { - /* Current pull: Rd */ - opposite_pull = TYPEC_CC_RP; - } else { - /* Current pull: Rp */ - opposite_pull = TYPEC_CC_RD; - } - - /* Set auto drp toggle, starting with the opposite pull */ - rv |= ps8xxx_set_role_ctrl(port, TYPEC_DRP, TYPEC_RP_USB, - opposite_pull); - - /* Set Look4Connection command */ - rv |= tcpc_write(port, TCPC_REG_COMMAND, - TCPC_REG_COMMAND_LOOK4CONNECTION); - - return rv; - } else { - return tcpci_tcpc_drp_toggle(port); - } -} -#endif - -#ifdef CONFIG_USB_PD_TCPM_PS8805_FORCE_DID -static int ps8805_make_device_id(int port, int *id) -{ - int p0_addr; - int val; - int status; - - p0_addr = PS8751_P3_TO_P0_FLAGS(tcpc_config[port].i2c_info.addr_flags); - - status = tcpc_addr_read(port, p0_addr, PS8805_P0_REG_CHIP_REVISION, - &val); - if (status != EC_SUCCESS) - return status; - switch (val & 0xF0) { - case 0x00: /* A2 chip */ - *id = 1; - break; - case 0xa0: /* A3 chip */ - *id = 2; - break; - default: - return EC_ERROR_UNKNOWN; - } - return EC_SUCCESS; -} -#endif - -#ifdef CONFIG_USB_PD_TCPM_PS8815_FORCE_DID -/* - * Early ps8815 A1 firmware reports 0x0001 in the TCPCI Device ID - * registers which makes it indistinguishable from A0. This - * overrides the Device ID based if vendor specific registers - * identify the chip as A1. - * - * See b/159289062. - * - * The ps8815 A2 reports device ID 0x0001 instead of 0x0003 when the - * firmware is bad (mis-programmed). - */ -static int ps8815_make_device_id(int port, int *id) -{ - int p1_addr; - int val; - int status; - - /* P1 registers are always accessible on PS8815 */ - p1_addr = PS8751_P3_TO_P1_FLAGS(tcpc_config[port].i2c_info.addr_flags); - - status = tcpc_addr_read16(port, p1_addr, PS8815_P1_REG_HW_REVISION, - &val); - if (status != EC_SUCCESS) - return status; - - switch (val) { - case 0x0a00: - *id = 1; - break; - case 0x0a01: - *id = 2; - break; - case 0x0a02: - *id = 3; - break; - default: - return EC_ERROR_UNKNOWN; - } - return EC_SUCCESS; -} -#endif - -/* - * The ps8815 can take up to 50ms (FW_INIT_DELAY_MS) to fully wake up - * from sleep/low power mode - specially when it contains an application - * block firmware update. When the chip is asleep, the 1st I2C - * transaction will fail but the chip will begin to wake up within 10ms - * (I2C_RECOVERY_DELAY_MS). After this delay, I2C transactions succeed, - * but the firmware is still not fully operational. The way to check if - * the firmware is ready, is to poll the firmware register for a - * non-zero value. This logic applies to all ps8xxx family members - * supported by this driver. - */ - -static int ps8xxx_lpm_recovery_delay(int port) -{ - int val; - int status; - int fw_reg; - timestamp_t deadline; - - fw_reg = get_reg_by_product(port, REG_FW_VER); - - deadline = get_time(); - deadline.val += PS8815_FW_INIT_DELAY_MS * 1000; - - val = 0; - for (;;) { - if (timestamp_expired(deadline, NULL)) - return EC_ERROR_TIMEOUT; - - status = tcpc_read(port, fw_reg, &val); - if (status != EC_SUCCESS) { - /* wait for chip to wake up */ - msleep(PS8XXX_I2C_RECOVERY_DELAY_MS); - continue; - } - if (val != 0) - break; - msleep(1); - } - - return EC_SUCCESS; -} - -static int ps8xxx_get_chip_info(int port, int live, - struct ec_response_pd_chip_info_v1 *chip_info) -{ - int val; - int reg; - int rv = tcpci_get_chip_info(port, live, chip_info); - - if (rv != EC_SUCCESS) - return rv; - - if (chip_info == NULL) - return EC_SUCCESS; - - if (!live) { - uint16_t pid; - - pid = board_get_ps8xxx_product_id(port); - if (pid == 0) - return EC_ERROR_UNKNOWN; - product_id[port] = pid; - chip_info->vendor_id = PS8XXX_VENDOR_ID; - chip_info->product_id = product_id[port]; - } - -#ifdef CONFIG_USB_PD_TCPM_PS8805_FORCE_DID - if (chip_info->product_id == PS8805_PRODUCT_ID && - chip_info->device_id == 0x0001) { - rv = ps8805_make_device_id(port, &val); - if (rv != EC_SUCCESS) - return rv; - chip_info->device_id = val; - } -#endif -#ifdef CONFIG_USB_PD_TCPM_PS8815_FORCE_DID - if (chip_info->product_id == PS8815_PRODUCT_ID && - chip_info->device_id == 0x0001) { - rv = ps8815_make_device_id(port, &val); - if (rv != EC_SUCCESS) - return rv; - chip_info->device_id = val; - } -#endif - reg = get_reg_by_product(port, REG_FW_VER); - rv = tcpc_read(port, reg, &val); - if (rv != EC_SUCCESS) - return rv; - - chip_info->fw_version_number = val; - - /* Treat unexpected values as error (FW not initiated from reset) */ - if (live && ( - chip_info->vendor_id != PS8XXX_VENDOR_ID || - chip_info->product_id != board_get_ps8xxx_product_id(port) || - chip_info->fw_version_number == 0)) - return EC_ERROR_UNKNOWN; - -#if defined(CONFIG_USB_PD_TCPM_PS8751) && \ - defined(CONFIG_USB_PD_VBUS_DETECT_TCPC) - /* - * Min firmware version of PS8751 to ensure that it can detect Vbus - * properly. See b/109769787#comment7 - */ - chip_info->min_req_fw_version_number = 0x39; -#endif - - return rv; -} - -#ifdef CONFIG_USB_PD_TCPC_LOW_POWER -static int ps8xxx_enter_low_power_mode(int port) -{ - /* - * PS8751 has the auto sleep function that enters low power mode on - * its own in ~2 seconds. Other chips don't have it. Stub it out for - * PS8751. - */ - if (product_id[port] == PS8751_PRODUCT_ID) - return EC_SUCCESS; - - return tcpci_enter_low_power_mode(port); -} -#endif - -static int ps8xxx_dci_disable(int port) -{ - int i; - - for (i = 0; i < ARRAY_SIZE(variant_map); i++) { - if (product_id[port] == variant_map[i].product_id) - return variant_map[i].dci_disable_ptr(port); - } - - CPRINTS("%s: failed to get dci_disable function pointers.", __func__); - return EC_ERROR_INVAL; -} - -__maybe_unused static int ps8815_transmit_buffer_workaround_check(int port) -{ - int p1_addr; - int val; - int status; - - if (product_id[port] != PS8815_PRODUCT_ID) - return EC_SUCCESS; - - /* P1 registers are always accessible on PS8815 */ - p1_addr = PS8751_P3_TO_P1_FLAGS(tcpc_config[port].i2c_info.addr_flags); - - status = tcpc_addr_read16(port, p1_addr, PS8815_P1_REG_HW_REVISION, - &val); - if (status != EC_SUCCESS) - return status; - - switch (val) { - case 0x0a00: - case 0x0a01: - ps8xxx_role_control_delay_ms[port] = 1; - break; - default: - break; - } - - return EC_SUCCESS; -} - -__maybe_unused static int ps8815_disable_rp_detect_workaround_check(int port) -{ - int val; - int rv; - int reg; - - ps8815_disable_rp_detect[port] = false; - ps8815_disconnected[port] = true; - - reg = get_reg_by_product(port, REG_FW_VER); - rv = tcpc_read(port, reg, &val); - if (rv != EC_SUCCESS) - return rv; - - /* - * RP detect is a problem in firmware version 0x10 and older. - */ - if (val <= 0x10) - ps8815_disable_rp_detect[port] = true; - - return EC_SUCCESS; -} - -__overridable void board_ps8xxx_tcpc_init(int port) -{} - -static int ps8xxx_tcpm_init(int port) -{ - int status; - - product_id[port] = board_get_ps8xxx_product_id(port); - - status = ps8xxx_lpm_recovery_delay(port); - if (status != EC_SUCCESS) { - CPRINTS("C%d: init: LPM recovery failed", port); - return status; - } - - if (IS_ENABLED(CONFIG_USB_PD_TCPM_PS8815)) { - status = ps8815_transmit_buffer_workaround_check(port); - if (status != EC_SUCCESS) - return status; - status = ps8815_disable_rp_detect_workaround_check(port); - if (status != EC_SUCCESS) - return status; - } - - board_ps8xxx_tcpc_init(port); - - status = tcpci_tcpm_init(port); - if (status != EC_SUCCESS) - return status; - - return ps8xxx_dci_disable(port); -} - -#ifdef CONFIG_USB_PD_TCPM_PS8751 -/* - * TODO(twawrzynczak): Remove this workaround when no - * longer needed. See: https://issuetracker.google.com/147684491 - * - * This is a workaround for what appears to be a bug in PS8751 firmware - * version 0x44. (Does the bug exist in other PS8751 firmware versions? - * Should this workaround be limited to only 0x44?) - * - * With nothing connected to the port, sometimes after DRP is disabled, - * the CC_STATUS register reads the CC state incorrectly (reading it - * as though a port partner is detected), which ends up confusing - * our TCPM. The workaround for this seems to be a short sleep and - * then re-reading the CC state. In other words, the issue shows up - * as a short glitch or transient, which an extra read and then a short - * delay will allow the transient to disappear. - */ -static int ps8751_get_gcc(int port, enum tcpc_cc_voltage_status *cc1, - enum tcpc_cc_voltage_status *cc2) -{ - int rv; - int status; - rv = tcpc_read(port, TCPC_REG_CC_STATUS, &status); - if (rv) - return rv; - - /* Derived empirically */ - usleep(300); - - return tcpci_tcpm_get_cc(port, cc1, cc2); -} -#endif - -static int ps8xxx_tcpm_set_cc(int port, int pull) -{ - int rv; - - /* - * b/178664884: Before presenting Rp on initial connect, disable - * internal function that checks Rp value. This is a workaround - * in the PS8815 firmware that reports an incorrect value on the CC - * lines. - * - * The PS8815 self-clears these bits. - */ - if (ps8815_disable_rp_detect[port] && ps8815_disconnected[port] && - pull == TYPEC_CC_RP) { - CPRINTS("TCPC%d: disable chip based Rp detect on connection", - port); - tcpc_write(port, PS8XXX_REG_RP_DETECT_CONTROL, - RP_DETECT_DISABLE); - ps8815_disconnected[port] = false; - } - - rv = tcpci_tcpm_set_cc(port, pull); - - /* - * b/171430855 delay 1 ms after ROLE_CONTROL updates to prevent - * transmit buffer corruption - */ - ps8xxx_role_control_delay(port); - - return rv; -} - -static int ps8xxx_tcpm_get_cc(int port, enum tcpc_cc_voltage_status *cc1, - enum tcpc_cc_voltage_status *cc2) -{ -#ifdef CONFIG_USB_PD_TCPM_PS8751 - if (product_id[port] == PS8751_PRODUCT_ID) - return ps8751_get_gcc(port, cc1, cc2); -#endif - - return tcpci_tcpm_get_cc(port, cc1, cc2); -} - -const struct tcpm_drv ps8xxx_tcpm_drv = { - .init = ps8xxx_tcpm_init, - .release = ps8xxx_tcpm_release, - .get_cc = ps8xxx_tcpm_get_cc, -#ifdef CONFIG_USB_PD_VBUS_DETECT_TCPC - .check_vbus_level = tcpci_tcpm_check_vbus_level, -#endif - .select_rp_value = tcpci_tcpm_select_rp_value, - .set_cc = ps8xxx_tcpm_set_cc, - .set_polarity = tcpci_tcpm_set_polarity, -#ifdef CONFIG_USB_PD_DECODE_SOP - .sop_prime_enable = tcpci_tcpm_sop_prime_enable, -#endif - .set_vconn = tcpci_tcpm_set_vconn, - .set_msg_header = tcpci_tcpm_set_msg_header, - .set_rx_enable = tcpci_tcpm_set_rx_enable, - .get_message_raw = tcpci_tcpm_get_message_raw, - .transmit = ps8xxx_tcpm_transmit, - .tcpc_alert = tcpci_tcpc_alert, -#ifdef CONFIG_USB_PD_DISCHARGE_TCPC - .tcpc_discharge_vbus = tcpci_tcpc_discharge_vbus, -#endif -#ifdef CONFIG_USB_PD_DUAL_ROLE_AUTO_TOGGLE - .drp_toggle = ps8xxx_tcpc_drp_toggle, -#endif -#ifdef CONFIG_USB_PD_PPC - .set_snk_ctrl = tcpci_tcpm_set_snk_ctrl, - .set_src_ctrl = tcpci_tcpm_set_src_ctrl, -#endif - .get_chip_info = ps8xxx_get_chip_info, -#ifdef CONFIG_USB_PD_TCPC_LOW_POWER - .enter_low_power_mode = ps8xxx_enter_low_power_mode, -#endif - .set_bist_test_mode = tcpci_set_bist_test_mode, -}; - -#ifdef CONFIG_CMD_I2C_STRESS_TEST_TCPC -struct i2c_stress_test_dev ps8xxx_i2c_stress_test_dev = { - .reg_info = { - .read_reg = PS8XXX_REG_VENDOR_ID_L, - .read_val = PS8XXX_VENDOR_ID & 0xFF, - .write_reg = MUX_IN_HPD_ASSERTION_REG, - }, - .i2c_read = tcpc_i2c_read, - .i2c_write = tcpc_i2c_write, -}; -#endif /* CONFIG_CMD_I2C_STRESS_TEST_TCPC */ - -#ifdef CONFIG_USB_PD_TCPM_PS8751_CUSTOM_MUX_DRIVER - -static int ps8xxx_mux_init(const struct usb_mux *me) -{ - RETURN_ERROR(tcpci_tcpm_mux_init(me)); - - /* If this MUX is also the TCPC, then skip init */ - if (!(me->flags & USB_MUX_FLAG_NOT_TCPC)) - return EC_SUCCESS; - - product_id[me->usb_port] = board_get_ps8xxx_product_id(me->usb_port); - - return EC_SUCCESS; -} - -/* - * PS8751 goes to standby mode automatically when both CC lines are set to RP. - * In standby mode it doesn't respond to first I2C access, but next - * transactions are working fine (until it goes to sleep again). - * - * To wake device documentation recommends read content of 0xA0 register. - */ -void ps8xxx_wake_from_standby(const struct usb_mux *me) -{ - int reg; - - /* Since we are waking up device, this call will most likely fail */ - mux_read(me, PS8XXX_REG_I2C_DEBUGGING_ENABLE, ®); - msleep(10); -} - -static int ps8xxx_mux_set(const struct usb_mux *me, mux_state_t mux_state, - bool *ack_required) -{ - if (product_id[me->usb_port] == PS8751_PRODUCT_ID && - me->flags & USB_MUX_FLAG_NOT_TCPC) { - ps8xxx_wake_from_standby(me); - - /* - * To operate properly, when working as mux only, PS8751 CC - * lines needs to be RD all the time. Changing to RP after - * setting mux breaks SuperSpeed connection. - */ - if (mux_state != USB_PD_MUX_NONE) - RETURN_ERROR(mux_write(me, TCPC_REG_ROLE_CTRL, - TCPC_REG_ROLE_CTRL_SET(TYPEC_NO_DRP, - TYPEC_RP_USB, - TYPEC_CC_RD, - TYPEC_CC_RD))); - } - - return tcpci_tcpm_mux_set(me, mux_state, ack_required); -} - -static int ps8xxx_mux_get(const struct usb_mux *me, mux_state_t *mux_state) -{ - if (product_id[me->usb_port] == PS8751_PRODUCT_ID && - me->flags & USB_MUX_FLAG_NOT_TCPC) - ps8xxx_wake_from_standby(me); - - return tcpci_tcpm_mux_get(me, mux_state); -} - -static int ps8xxx_mux_enter_low_power(const struct usb_mux *me) -{ - /* - * Set PS8751 lines to RP. This allows device to standby - * automatically after ~2 seconds - */ - if (product_id[me->usb_port] == PS8751_PRODUCT_ID && - me->flags & USB_MUX_FLAG_NOT_TCPC) { - /* - * It may happen that this write will fail, but - * RP seems to be set correctly - */ - mux_write(me, TCPC_REG_ROLE_CTRL, - TCPC_REG_ROLE_CTRL_SET(TYPEC_NO_DRP, TYPEC_RP_USB, - TYPEC_CC_RP, TYPEC_CC_RP)); - return EC_SUCCESS; - } - - return tcpci_tcpm_mux_enter_low_power(me); -} - -const struct usb_mux_driver ps8xxx_usb_mux_driver = { - .init = ps8xxx_mux_init, - .set = ps8xxx_mux_set, - .get = ps8xxx_mux_get, - .enter_low_power_mode = ps8xxx_mux_enter_low_power, -}; - -#endif /* CONFIG_USB_PD_TCPM_PS8751_CUSTOM_MUX_DRIVER */ diff --git a/driver/tcpm/ps8xxx.h b/driver/tcpm/ps8xxx.h deleted file mode 100644 index 8458dbb7e5..0000000000 --- a/driver/tcpm/ps8xxx.h +++ /dev/null @@ -1,146 +0,0 @@ -/* Copyright 2017 The Chromium OS Authors. All rights reserved. - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ -#include "usb_mux.h" - -#include "driver/tcpm/ps8xxx_public.h" - -/* Parade Tech Type-C port controller */ - -#ifndef __CROS_EC_USB_PD_TCPM_PS8XXX_H -#define __CROS_EC_USB_PD_TCPM_PS8XXX_H - -#define PS8751_P3_TO_P0_FLAGS(p3_flags) ((p3_flags) - 3) -#define PS8751_P3_TO_P1_FLAGS(p3_flags) ((p3_flags) - 2) - -#define PS8751_BIST_TIMER_FREQ 15000000 -#define PS8751_BIST_DELAY_MS 50 - -#define PS8751_BIST_COUNTER (PS8751_BIST_TIMER_FREQ / MSEC \ - * PS8751_BIST_DELAY_MS) - -#define PS8751_BIST_COUNTER_BYTE0 (PS8751_BIST_COUNTER & 0xff) -#define PS8751_BIST_COUNTER_BYTE1 ((PS8751_BIST_COUNTER >> 8) & 0xff) -#define PS8751_BIST_COUNTER_BYTE2 ((PS8751_BIST_COUNTER >> 16) & 0xff) - -#define PS8XXX_REG_RP_DETECT_CONTROL 0x9B -#define RP_DETECT_DISABLE 0x30 - -#define PS8XXX_REG_I2C_DEBUGGING_ENABLE 0xA0 -#define PS8XXX_REG_I2C_DEBUGGING_ENABLE_ON 0x30 -#define PS8XXX_REG_I2C_DEBUGGING_ENABLE_OFF 0x31 /* default */ -#define PS8XXX_REG_BIST_CONT_MODE_BYTE0 0xBC -#define PS8XXX_REG_BIST_CONT_MODE_BYTE1 0xBD -#define PS8XXX_REG_BIST_CONT_MODE_BYTE2 0xBE -#define PS8XXX_REG_BIST_CONT_MODE_CTR 0xBF -#define PS8XXX_REG_DET_CTRL0 0x08 - -#define PS8XXX_REG_MUX_USB_DCI_CFG_MODE_MASK 0xC0 -#define PS8XXX_REG_MUX_USB_DCI_CFG_MODE_OFF 0x80 - -#define MUX_IN_HPD_ASSERTION_REG 0xD0 -#define IN_HPD BIT(0) -#define HPD_IRQ BIT(1) - -#define PS8XXX_P1_REG_MUX_USB_DCI_CFG 0x4B - -#define PS8755_P0_REG_SM 0x06 -#define PS8755_P0_REG_SM_VALUE 0x80 - -#if defined(CONFIG_USB_PD_TCPM_PS8751) -/* Vendor defined registers */ -#define PS8XXX_REG_VENDOR_ID_L 0x00 -#define PS8XXX_REG_VENDOR_ID_H 0x01 -#define PS8XXX_REG_MUX_DP_EQ_CONFIGURATION 0xD3 -#define PS8XXX_REG_MUX_DP_OUTPUT_CONFIGURATION 0xD4 -#define PS8XXX_REG_MUX_USB_C2SS_EQ 0xE7 -#define PS8XXX_REG_MUX_USB_C2SS_HS_THRESHOLD 0xE8 -#define PS8751_REG_MUX_USB_DCI_CFG 0xED -#endif - -/* Vendor defined registers */ -#define PS8815_P1_REG_HW_REVISION 0xF0 - -/* - * Below register is defined from Parade PS8815 Register Table, - * See b:189587527 for more detail. - */ - -/* Displayport related settings */ -#define PS8815_REG_DP_EQ_SETTING 0xF8 -#define PS8815_AUTO_EQ_DISABLE BIT(7) -#define PS8815_DPEQ_LOSS_UP_21DB 0x09 -#define PS8815_DPEQ_LOSS_UP_20DB 0x08 -#define PS8815_DPEQ_LOSS_UP_19DB 0x07 -#define PS8815_DPEQ_LOSS_UP_18DB 0x06 -#define PS8815_DPEQ_LOSS_UP_17DB 0x05 -#define PS8815_DPEQ_LOSS_UP_16DB 0x04 -#define PS8815_DPEQ_LOSS_UP_13DB 0x03 -#define PS8815_DPEQ_LOSS_UP_12DB 0x02 -#define PS8815_DPEQ_LOSS_UP_10DB 0x01 -#define PS8815_DPEQ_LOSS_UP_9DB 0x00 -#define PS8815_REG_DP_EQ_COMP_SHIFT 3 -#define PS8815_AUX_INTERCEPTION_DISABLE BIT(1) - -/* - * PS8805 register to distinguish chip revision - * bit 7-4: 1010b is A3 chip, 0000b is A2 chip - */ -#define PS8805_P0_REG_CHIP_REVISION 0x62 - -/* - * PS8805 GPIO control register. Note the device I2C address of 0x1A is - * independent of the ADDR pin on the chip, and not the same address being used - * for TCPCI functions. - */ -#define PS8805_VENDOR_DEFINED_I2C_ADDR 0x1A -#define PS8805_REG_GPIO_CONTROL 0x21 -#define PS8805_REG_GPIO_0 BIT(7) -#define PS8805_REG_GPIO_1 BIT(5) -#define PS8805_REG_GPIO_2 BIT(6) - -enum ps8805_gpio { - PS8805_GPIO_0, - PS8805_GPIO_1, - PS8805_GPIO_2, - PS8805_GPIO_NUM, -}; - -/** - * Set PS8805 gpio signal to desired level - * - * @param port: The Type-C port number. - * @param signal PS8805 gpio number (0, 1, or 2) - * @param level desired level - * @return EC_SUCCESS if I2C accesses are successful - */ -int ps8805_gpio_set_level(int port, enum ps8805_gpio signal, int level); - -/** - * Get PS8805 gpio signal value - * - * @param port: The Type-C port number. - * @param signal PS8805 gpio number (0, 1, or 2) - * @param pointer location to store gpio level - * @return EC_SUCCESS if I2C accesses are successful - */ -int ps8805_gpio_get_level(int port, enum ps8805_gpio signal, int *level); - -/** - * Check if the chip is PS8755 - * - * @param port: The Type-C port number. - * @return true if hidden register sm is 0x80 - */ -bool check_ps8755_chip(int port); - -/* - * Allow boards to customize for PS8XXX initial if board has - * specific settings. - * - * @param port: The Type-C port number. - */ -__override_proto void board_ps8xxx_tcpc_init(int port); - -#endif /* defined(__CROS_EC_USB_PD_TCPM_PS8XXX_H) */ diff --git a/driver/tcpm/raa489000.c b/driver/tcpm/raa489000.c deleted file mode 100644 index c4976bab4e..0000000000 --- a/driver/tcpm/raa489000.c +++ /dev/null @@ -1,325 +0,0 @@ -/* Copyright 2020 The Chromium OS Authors. All rights reserved. - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - * - * Renesas RAA489000 TCPC driver - */ - -#include "charge_manager.h" -#include "charger.h" -#include "common.h" -#include "console.h" -#include "driver/charger/isl923x.h" -#include "i2c.h" -#include "raa489000.h" -#include "tcpm/tcpci.h" -#include "tcpm/tcpm.h" -#include "timer.h" - -#define DEFAULT_R_AC 20 -#define R_AC CONFIG_CHARGER_SENSE_RESISTOR_AC -#define AC_CURRENT_TO_REG(CUR) ((CUR) * R_AC / DEFAULT_R_AC) - -#define CPRINTF(format, args...) cprintf(CC_USBPD, format, ## args) -#define CPRINTS(format, args...) cprints(CC_USBPD, format, ## args) - -static int dev_id[CONFIG_USB_PD_PORT_MAX_COUNT] = { -1 }; - -static int raa489000_enter_low_power_mode(int port) -{ - int rv; - - rv = tcpc_write16(port, RAA489000_PD_PHYSICAL_SETTING1, 0); - if (rv) - CPRINTS("RAA489000(%d): Failed to set PD PHY setting1!", port); - - rv = tcpc_write16(port, RAA489000_TCPC_SETTING1, 0); - if (rv) - CPRINTS("RAA489000(%d): Failed to set TCPC setting1!", port); - - return tcpci_enter_low_power_mode(port); -} - -/* Configure output current in the TCPC because it is controlling Vbus */ -int raa489000_set_output_current(int port, enum tcpc_rp_value rp) -{ - int regval; - int selected_cur = rp == TYPEC_RP_3A0 ? - RAA489000_VBUS_CURRENT_TARGET_3A : - RAA489000_VBUS_CURRENT_TARGET_1_5A; - - regval = AC_CURRENT_TO_REG(selected_cur) + - selected_cur % (DEFAULT_R_AC/R_AC); - - return tcpc_write16(port, RAA489000_VBUS_CURRENT_TARGET, - regval); -} - -int raa489000_init(int port) -{ - int rv; - int regval; - int device_id; - int i2c_port; - struct charge_port_info chg = { 0 }; - int vbus_mv = 0; - - /* Perform unlock sequence */ - rv = tcpc_write16(port, 0xAA, 0xDAA0); - if (rv) - CPRINTS("c%d: failed unlock step1", port); - rv = tcpc_write16(port, 0xAA, 0xACE0); - if (rv) - CPRINTS("c%d: failed unlock step2", port); - rv = tcpc_write16(port, 0xAA, 0x0D0B); - if (rv) - CPRINTS("c%d: failed unlock step3", port); - - device_id = -1; - rv = tcpc_read16(port, TCPC_REG_BCD_DEV, &device_id); - if (rv) - CPRINTS("C%d: Failed to read DEV_ID", port); - CPRINTS("%s(%d): DEVICE_ID=%d", __func__, port, device_id); - dev_id[port] = device_id; - - /* Enable the ADC */ - /* - * TODO(b:147316511) Since this register can be accessed by multiple - * tasks, we should add a mutex when modifying this register. - * - * See(b:178981107,b:178728138) When the battery does not exist, - * we must enable ADC function so that charger_get_vbus_voltage - * can get the correct voltage. - */ - i2c_port = tcpc_config[port].i2c_info.port; - rv = i2c_read16(i2c_port, ISL923X_ADDR_FLAGS, - ISL9238_REG_CONTROL3, ®val); - regval |= RAA489000_ENABLE_ADC; - rv |= i2c_write16(i2c_port, ISL923X_ADDR_FLAGS, - ISL9238_REG_CONTROL3, regval); - if (rv) - CPRINTS("c%d: failed to enable ADCs", port); - - /* Enable Vbus detection */ - rv = tcpc_write(port, TCPC_REG_COMMAND, - TCPC_REG_COMMAND_ENABLE_VBUS_DETECT); - if (rv) - CPRINTS("c%d: failed to enable vbus detect cmd", port); - - - /* - * If VBUS is present, start sinking from it if we haven't already - * chosen a charge port and no battery is connected. This is - * *kinda hacky* doing it here, but we must start sinking VBUS now, - * otherwise the board may die (See b/150702984, b/178728138). This - * works as this part is a combined charger IC and TCPC. - */ - usleep(853); - charger_get_vbus_voltage(port, &vbus_mv); - - /* - * Disable the ADC - * - * See(b:178356507) 9mW is reduced on S0iX power consumption - * by clearing 'Enable ADC' bit. - */ - if (IS_ENABLED(CONFIG_OCPC) && (port != 0)) { - i2c_port = tcpc_config[port].i2c_info.port; - rv = i2c_read16(i2c_port, ISL923X_ADDR_FLAGS, - ISL9238_REG_CONTROL3, ®val); - regval &= ~RAA489000_ENABLE_ADC; - rv |= i2c_write16(i2c_port, ISL923X_ADDR_FLAGS, - ISL9238_REG_CONTROL3, regval); - if (rv) - CPRINTS("c%d: failed to disable ADCs", port); - } - - if ((vbus_mv > 3900) && - charge_manager_get_active_charge_port() == CHARGE_PORT_NONE && - !pd_is_battery_capable()) { - chg.current = 500; - chg.voltage = 5000; - charge_manager_update_charge(CHARGE_SUPPLIER_VBUS, port, &chg); - board_set_active_charge_port(port); - } - - if (device_id > 1) { - /* - * A1 silicon has a DEVICE_ID of 1. For B0 and newer, we need - * allow the TCPC to control VBUS in order to start VBUS ADC - * sampling. This is a requirement to clear the TCPC - * initialization status but in POWER_STATUS. Otherwise, the - * common TCPCI init will fail. (See b/154191301) - */ - rv = tcpc_read16(port, RAA489000_TCPC_SETTING1, ®val); - regval |= RAA489000_TCPC_PWR_CNTRL; - rv = tcpc_write16(port, RAA489000_TCPC_SETTING1, regval); - if (rv) - CPRINTS("C%d: failed to set TCPC power control", port); - } - - /* Note: registers may not be ready until TCPCI init succeeds */ - rv = tcpci_tcpm_init(port); - if (rv) - return rv; - - /* - * Set some vendor defined registers to enable the CC comparators and - * remove the dead battery resistors. This only needs to be done on - * early silicon versions. - */ - if (device_id <= 1) { - rv = tcpc_write16(port, RAA489000_TYPEC_SETTING1, - RAA489000_SETTING1_RDOE | - RAA489000_SETTING1_CC2_CMP3_EN | - RAA489000_SETTING1_CC2_CMP2_EN | - RAA489000_SETTING1_CC2_CMP1_EN | - RAA489000_SETTING1_CC1_CMP3_EN | - RAA489000_SETTING1_CC1_CMP2_EN | - RAA489000_SETTING1_CC1_CMP1_EN | - RAA489000_SETTING1_CC_DB_EN); - if (rv) - CPRINTS("c%d: failed to enable CC comparators", port); - } - - /* Set Rx enable for receiver comparator */ - rv = tcpc_read16(port, RAA489000_PD_PHYSICAL_SETTING1, ®val); - regval |= RAA489000_PD_PHY_SETTING1_RECEIVER_EN | - RAA489000_PD_PHY_SETTING1_SQUELCH_EN | - RAA489000_PD_PHY_SETTING1_TX_LDO11_EN; - rv |= tcpc_write16(port, RAA489000_PD_PHYSICAL_SETTING1, regval); - if (rv) - CPRINTS("c%d: failed to set PD PHY setting1", port); - - /* - * Disable VBUS auto discharge, we'll turn it on later as its needed to - * goodcrc. - */ - rv = tcpc_read(port, TCPC_REG_POWER_CTRL, ®val); - regval &= ~TCPC_REG_POWER_CTRL_AUTO_DISCHARGE_DISCONNECT; - rv |= tcpc_write(port, TCPC_REG_POWER_CTRL, regval); - if (rv) - CPRINTS("c%d: failed to set auto discharge", port); - - if (device_id <= 1) { - /* The vendor says to set this setting. */ - rv = tcpc_write16(port, RAA489000_PD_PHYSICAL_PARAMETER1, - 0x6C07); - if (rv) - CPRINTS("c%d: failed to set PD PHY PARAM1", port); - } - - /* Enable the correct TCPCI interface version */ - rv = tcpc_read16(port, RAA489000_TCPC_SETTING1, ®val); - if (!(tcpc_config[port].flags & TCPC_FLAGS_TCPCI_REV2_0)) - regval |= RAA489000_TCPCV1_0_EN; - else - regval &= ~RAA489000_TCPCV1_0_EN; - - if (device_id <= 1) { - /* Allow the TCPC to control VBUS. */ - regval |= RAA489000_TCPC_PWR_CNTRL; - } - - rv = tcpc_write16(port, RAA489000_TCPC_SETTING1, regval); - if (rv) - CPRINTS("c%d: failed to set TCPCIv1.0 mode", port); - - /* - * Set Vbus OCP UV here, PD tasks will set target current - */ - rv = tcpc_write16(port, RAA489000_VBUS_OCP_UV_THRESHOLD, - RAA489000_OCP_THRESHOLD_VALUE); - if (rv) - CPRINTS("c%d: failed to set OCP threshold", port); - - /* Set Vbus Target Voltage */ - rv = tcpc_write16(port, RAA489000_VBUS_VOLTAGE_TARGET, - RAA489000_VBUS_VOLTAGE_TARGET_5160MV); - if (rv) - CPRINTS("c%d: failed to set Vbus Target Voltage", port); - - return rv; -} - -int raa489000_tcpm_set_cc(int port, int pull) -{ - int rv; - - rv = tcpci_tcpm_set_cc(port, pull); - if (dev_id[port] > 1 || rv) - return rv; - - /* Older silicon needs the TCPM to set RDOE to 1 after setting Rp */ - if (pull == TYPEC_CC_RP) - rv = tcpc_update16(port, RAA489000_TYPEC_SETTING1, - RAA489000_SETTING1_RDOE, MASK_SET); - - return rv; -} - -int raa489000_debug_detach(int port) -{ - int rv; - int power_status; - - /* - * Force RAA489000 to see debug detach by running: - * - * 1. Set POWER_CONTROL. AutoDischargeDisconnect=1 - * 2. Set ROLE_CONTROL=0x0F(OPEN,OPEN) - * 3. Set POWER_CONTROL. AutoDischargeDisconnect=0 - * - * Only if we have sufficient battery or are not sinking. Otherwise, - * we would risk brown-out during the CC open set. - */ - RETURN_ERROR(tcpc_read(port, TCPC_REG_POWER_STATUS, &power_status)); - - if (!pd_is_battery_capable() && - (power_status & TCPC_REG_POWER_STATUS_SINKING_VBUS)) - return EC_SUCCESS; - - tcpci_tcpc_enable_auto_discharge_disconnect(port, 1); - - rv = tcpci_tcpm_set_cc(port, TYPEC_CC_OPEN); - - tcpci_tcpc_enable_auto_discharge_disconnect(port, 0); - - return rv; -} - -/* RAA489000 is a TCPCI compatible port controller */ -const struct tcpm_drv raa489000_tcpm_drv = { - .init = &raa489000_init, - .release = &tcpci_tcpm_release, - .get_cc = &tcpci_tcpm_get_cc, -#ifdef CONFIG_USB_PD_VBUS_DETECT_TCPC - .check_vbus_level = &tcpci_tcpm_check_vbus_level, -#endif - .select_rp_value = &tcpci_tcpm_select_rp_value, - .set_cc = &raa489000_tcpm_set_cc, - .set_polarity = &tcpci_tcpm_set_polarity, -#ifdef CONFIG_USB_PD_DECODE_SOP - .sop_prime_enable = &tcpci_tcpm_sop_prime_enable, -#endif - .set_vconn = &tcpci_tcpm_set_vconn, - .set_msg_header = &tcpci_tcpm_set_msg_header, - .set_rx_enable = &tcpci_tcpm_set_rx_enable, - .get_message_raw = &tcpci_tcpm_get_message_raw, - .transmit = &tcpci_tcpm_transmit, - .tcpc_alert = &tcpci_tcpc_alert, -#ifdef CONFIG_USB_PD_DISCHARGE_TCPC - .tcpc_discharge_vbus = &tcpci_tcpc_discharge_vbus, -#endif -#ifdef CONFIG_USB_PD_DUAL_ROLE_AUTO_TOGGLE - .drp_toggle = &tcpci_tcpc_drp_toggle, -#endif - .get_chip_info = &tcpci_get_chip_info, -#ifdef CONFIG_USB_PD_TCPC_LOW_POWER - .enter_low_power_mode = &raa489000_enter_low_power_mode, -#endif - .set_bist_test_mode = &tcpci_set_bist_test_mode, - .tcpc_enable_auto_discharge_disconnect = - &tcpci_tcpc_enable_auto_discharge_disconnect, - .debug_detach = &raa489000_debug_detach, -}; diff --git a/driver/tcpm/raa489000.h b/driver/tcpm/raa489000.h deleted file mode 100644 index 2a4c7c6b3d..0000000000 --- a/driver/tcpm/raa489000.h +++ /dev/null @@ -1,86 +0,0 @@ -/* Copyright 2020 The Chromium OS Authors. All rights reserved. - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - * - * TCPC driver for Renesas RAA489000 Buck-boost charger with TCPC - */ - -#include "compile_time_macros.h" -#include "usb_pd_tcpm.h" - -#ifndef __CROS_EC_USB_PD_TCPM_RAA489000_H -#define __CROS_EC_USB_PD_TCPM_RAA489000_H - -#define RAA489000_TCPC0_I2C_FLAGS 0x22 -#define RAA489000_TCPC1_I2C_FLAGS 0x23 -#define RAA489000_TCPC2_I2C_FLAGS 0x24 -#define RAA489000_TCPC3_I2C_FLAGS 0x25 - -/* Vendor registers */ -#define RAA489000_TCPC_SETTING1 0x80 -#define RAA489000_VBUS_VOLTAGE_TARGET 0x90 -#define RAA489000_VBUS_CURRENT_TARGET 0x92 -#define RAA489000_VBUS_OCP_UV_THRESHOLD 0x94 -#define RAA489000_TYPEC_SETTING1 0xC0 -#define RAA489000_PD_PHYSICAL_SETTING1 0xE0 -#define RAA489000_PD_PHYSICAL_PARAMETER1 0xE8 - -/* TCPC_SETTING_1 */ -#define RAA489000_TCPCV1_0_EN BIT(0) -#define RAA489000_TCPC_PWR_CNTRL BIT(4) - -/* VBUS_CURRENT_TARGET */ -#define RAA489000_VBUS_CURRENT_TARGET_3A 0x66 /* 3.0A + iOvershoot */ -#define RAA489000_VBUS_CURRENT_TARGET_1_5A 0x38 /* 1.5A + iOvershoot */ - -/* VBUS_VOLTAGE_TARGET */ -#define RAA489000_VBUS_VOLTAGE_TARGET_5160MV 0x102 /* 5.16V */ -#define RAA489000_VBUS_VOLTAGE_TARGET_5220MV 0x105 /* 5.22V */ - -/* VBUS_OCP_UV_THRESHOLD */ -/* Detect voltage level of overcurrent protection during Sourcing VBUS */ -#define RAA489000_OCP_THRESHOLD_VALUE 0x00BE /* 4.75V */ - -/* TYPEC_SETTING1 - only older silicon */ -/* Enables for reverse current protection */ -#define RAA489000_SETTING1_IP2_EN BIT(9) -#define RAA489000_SETTING1_IP1_EN BIT(8) - -/* Switches from dead-battery Rd */ -#define RAA489000_SETTING1_RDOE BIT(7) - -/* CC comparator enables */ -#define RAA489000_SETTING1_CC2_CMP3_EN BIT(6) -#define RAA489000_SETTING1_CC2_CMP2_EN BIT(5) -#define RAA489000_SETTING1_CC2_CMP1_EN BIT(4) -#define RAA489000_SETTING1_CC1_CMP3_EN BIT(3) -#define RAA489000_SETTING1_CC1_CMP2_EN BIT(2) -#define RAA489000_SETTING1_CC1_CMP1_EN BIT(1) - -/* CC debounce enable */ -#define RAA489000_SETTING1_CC_DB_EN BIT(0) - -/* PD_PHYSICAL_SETTING_1 */ -#define RAA489000_PD_PHY_SETTING1_RECEIVER_EN BIT(9) -#define RAA489000_PD_PHY_SETTING1_SQUELCH_EN BIT(8) -#define RAA489000_PD_PHY_SETTING1_TX_LDO11_EN BIT(0) - -/* PD_PHYSICAL_PARMETER_1 */ -#define PD_PHY_PARAM1_NOISE_FILTER_CNT_MASK (GENMASK(4, 0)) - -/** - * - * Set output current limit on the TCPC. Note, this chip also offers an OTG - * current level register in the charger i2c page but we must use the TCPC - * current limit because the TCPC is controlling Vbus. - * - * @param port USB-C port number - * @param rp Rp value for current limit (either 1.5A or 3A) - * - * @return Zero if the current limit set was successful, non-zero otherwise - */ -int raa489000_set_output_current(int port, enum tcpc_rp_value rp); - -extern const struct tcpm_drv raa489000_tcpm_drv; - -#endif diff --git a/driver/tcpm/rt1715.c b/driver/tcpm/rt1715.c deleted file mode 100644 index ed3d283bc9..0000000000 --- a/driver/tcpm/rt1715.c +++ /dev/null @@ -1,263 +0,0 @@ -/* Copyright 2021 The Chromium OS Authors. All rights reserved. - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ -/* Richtek RT1715 Type-C port controller */ - -#include "common.h" -#include "rt1715.h" -#include "tcpm/tcpci.h" -#include "tcpm/tcpm.h" -#include "timer.h" -#include "usb_pd.h" -#include "usb_pd_tcpm.h" - -#ifndef CONFIG_USB_PD_TCPM_TCPCI -#error "RT1715 is using a standard TCPCI interface" -#error "Please upgrade your board configuration" -#endif - -static int rt1715_polarity[CONFIG_USB_PD_PORT_MAX_COUNT]; -static bool rt1715_initialized[CONFIG_USB_PD_PORT_MAX_COUNT]; - - -static int rt1715_enable_ext_messages(int port, int enable) -{ - return tcpc_update8(port, RT1715_REG_VENDOR_5, - RT1715_REG_VENDOR_5_ENEXTMSG, - enable ? MASK_SET : MASK_CLR); -} - -static int rt1715_tcpci_tcpm_init(int port) -{ - int rv; - /* - * Do not fully reinitialize the registers when leaving low-power mode. - * TODO(b/179234089): Generalize this concept in the tcpm_drv API. - */ - - /* Only do soft-reset on first init. */ - if (!(rt1715_initialized[port])) { - /* RT1715 has a vendor-defined register reset */ - rv = tcpc_update8(port, RT1715_REG_VENDOR_7, - RT1715_REG_VENDOR_7_SOFT_RESET, MASK_SET); - if (rv) - return rv; - rt1715_initialized[port] = true; - msleep(10); - } - - rv = tcpc_update8(port, RT1715_REG_VENDOR_5, - RT1715_REG_VENDOR_5_SHUTDOWN_OFF, MASK_SET); - if (rv) - return rv; - - if (IS_ENABLED(CONFIG_USB_PD_REV30)) - rt1715_enable_ext_messages(port, 1); - - rv = tcpc_write(port, RT1715_REG_I2CRST_CTRL, - (RT1715_REG_I2CRST_CTRL_EN | - RT1715_REG_I2CRST_CTRL_TOUT_200MS)); - if (rv) - return rv; - - /* Unmask interrupt for LPM wakeup */ - rv = tcpc_write(port, RT1715_REG_RT_MASK, RT1715_REG_RT_MASK_M_WAKEUP); - if (rv) - return rv; - - /* - * Set tTCPCFilter (CC debounce time) to 400 us - * (min 250 us, max 500 us). - */ - rv = tcpc_write(port, RT1715_REG_TTCPC_FILTER, - RT1715_REG_TTCPC_FILTER_400US); - if (rv) - return rv; - - rv = tcpc_write(port, RT1715_REG_DRP_TOGGLE_CYCLE, - RT1715_REG_DRP_TOGGLE_CYCLE_76MS); - if (rv) - return rv; - - /* PHY control */ - /* Set PHY control registers to Richtek recommended values */ - rv = tcpc_write(port, RT1715_REG_PHY_CTRL1, - (RT1715_REG_PHY_CTRL1_ENRETRY | - RT1715_REG_PHY_CTRL1_TRANSCNT_7 | - RT1715_REG_PHY_CTRL1_TRXFILTER_125NS)); - if (rv) - return rv; - - /* Set PHY control registers to Richtek recommended values */ - rv = tcpc_write(port, RT1715_REG_PHY_CTRL2, - RT1715_REG_PHY_CTRL2_CDRTHRESH_2_58US); - if (rv) - return rv; - - return tcpci_tcpm_init(port); -} - -/* - * Selects the CC PHY noise filter voltage level according to the current - * CC voltage level. - * - * @param cc_level The CC voltage level for the port's current role - * @return EC_SUCCESS if writes succeed; failure code otherwise - */ -static inline int rt1715_init_cc_params(int port, int cc_level) -{ - int rv, en, sel; - - if (cc_level == TYPEC_CC_VOLT_RP_DEF) { - /* RXCC threshold : 0.55V */ - en = RT1715_REG_BMCIO_RXDZEN_DISABLE; - - sel = RT1715_REG_BMCIO_RXDZSEL_OCCTRL_600MA - | RT1715_REG_BMCIO_RXDZSEL_SEL; - } else { - /* RD threshold : 0.35V & RP threshold : 0.75V */ - en = RT1715_REG_BMCIO_RXDZEN_ENABLE; - - sel = RT1715_REG_BMCIO_RXDZSEL_OCCTRL_600MA - | RT1715_REG_BMCIO_RXDZSEL_SEL; - } - - rv = tcpc_write(port, RT1715_REG_BMCIO_RXDZEN, en); - if (!rv) - rv = tcpc_write(port, RT1715_REG_BMCIO_RXDZSEL, sel); - - return rv; -} - -static int rt1715_get_cc(int port, enum tcpc_cc_voltage_status *cc1, - enum tcpc_cc_voltage_status *cc2) -{ - int rv; - - rv = tcpci_tcpm_get_cc(port, cc1, cc2); - if (rv) - return rv; - - return rt1715_init_cc_params(port, rt1715_polarity[port] ? *cc2 : *cc1); -} - -/* - * See b/179256608#comment26 for explanation. - * Disable 24MHz oscillator and enable LPM. Upon exit from LPM, the LPEN will be - * reset to 0. - * - * The exit condition for LPM is CC status change, and the wakeup interrupt will - * be set. - */ -#ifdef CONFIG_USB_PD_TCPC_LOW_POWER -static int rt1715_enter_low_power_mode(int port) -{ - int regval; - int rv; - - rv = tcpc_read(port, RT1715_REG_PWR, ®val); - if (rv) - return rv; - - regval |= RT1715_REG_PWR_BMCIO_LPEN; - regval &= ~RT1715_REG_PWR_BMCIO_OSCEN; - rv = tcpc_write(port, RT1715_REG_PWR, regval); - if (rv) - return rv; - - return tcpci_enter_low_power_mode(port); -} -#endif - -static int rt1715_set_vconn(int port, int enable) -{ - int rv; - int regval; - - /* - * Auto-idle cannot be used while sourcing Vconn. - * See b/179256608#comment26 for explanation. - */ - rv = tcpc_read(port, RT1715_REG_VENDOR_5, ®val); - if (rv) - return rv; - - if (enable) - regval &= ~RT1715_REG_VENDOR_5_AUTOIDLE_EN; - else - regval |= RT1715_REG_VENDOR_5_AUTOIDLE_EN; - - rv = tcpc_write(port, RT1715_REG_VENDOR_5, regval); - if (rv) - return rv; - - return tcpci_tcpm_set_vconn(port, enable); -} - -static int rt1715_set_polarity(int port, enum tcpc_cc_polarity polarity) -{ - int rv; - enum tcpc_cc_voltage_status cc1, cc2; - - rt1715_polarity[port] = polarity; - - rv = tcpci_tcpm_get_cc(port, &cc1, &cc2); - if (rv) - return rv; - - rv = rt1715_init_cc_params(port, polarity ? cc2 : cc1); - if (rv) - return rv; - - return tcpci_tcpm_set_polarity(port, polarity); -} - -static void rt1715_alert(int port) -{ - /* - * Make sure the wakeup interrupt is cleared. This bit is set on wakeup - * from LPM. See b/179256608#comment16 for explanation. - */ - tcpc_write(port, RT1715_REG_RT_INT, RT1715_REG_RT_INT_WAKEUP); - - tcpci_tcpc_alert(port); -} - -const struct tcpm_drv rt1715_tcpm_drv = { - .init = &rt1715_tcpci_tcpm_init, - .release = &tcpci_tcpm_release, - .get_cc = &rt1715_get_cc, -#ifdef CONFIG_USB_PD_VBUS_DETECT_TCPC - .check_vbus_level = &tcpci_tcpm_check_vbus_level, -#endif - .select_rp_value = &tcpci_tcpm_select_rp_value, - .set_cc = &tcpci_tcpm_set_cc, - .set_polarity = &rt1715_set_polarity, -#ifdef CONFIG_USB_PD_DECODE_SOP - .sop_prime_enable = &tcpci_tcpm_sop_prime_enable, -#endif - .set_vconn = &rt1715_set_vconn, - .set_msg_header = &tcpci_tcpm_set_msg_header, - .set_rx_enable = &tcpci_tcpm_set_rx_enable, - .get_message_raw = &tcpci_tcpm_get_message_raw, - .transmit = &tcpci_tcpm_transmit, - .tcpc_alert = &rt1715_alert, -#ifdef CONFIG_USB_PD_DISCHARGE_TCPC - .tcpc_discharge_vbus = &tcpci_tcpc_discharge_vbus, -#endif - .tcpc_enable_auto_discharge_disconnect = - &tcpci_tcpc_enable_auto_discharge_disconnect, -#ifdef CONFIG_USB_PD_DUAL_ROLE_AUTO_TOGGLE - .drp_toggle = &tcpci_tcpc_drp_toggle, -#endif -#ifdef CONFIG_USB_PD_PPC - .set_snk_ctrl = &tcpci_tcpm_set_snk_ctrl, - .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 = &rt1715_enter_low_power_mode, -#endif - .set_bist_test_mode = &tcpci_set_bist_test_mode, -}; diff --git a/driver/tcpm/rt1715.h b/driver/tcpm/rt1715.h deleted file mode 100644 index dcf2aa28d4..0000000000 --- a/driver/tcpm/rt1715.h +++ /dev/null @@ -1,85 +0,0 @@ -/* Copyright 2021 The Chromium OS Authors. All rights reserved. - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ -/* Richtek RT1715 Type-C port controller */ -#ifndef __CROS_EC_USB_PD_TCPM_RT1715_H -#define __CROS_EC_USB_PD_TCPM_RT1715_H - -/* I2C interface */ -#define RT1715_I2C_ADDR_FLAGS 0x4E - -#define RT1715_VENDOR_ID 0x29CF - -#define RT1715_REG_VENDOR_7 0xA0 -#define RT1715_REG_VENDOR_7_SOFT_RESET BIT(0) - -#define RT1715_REG_PHY_CTRL1 0x80 -/* Wait for tReceive before retrying transmit in response to a bad GoodCRC */ -#define RT1715_REG_PHY_CTRL1_ENRETRY BIT(7) -/* - * Bit 6:4 <TRANSCNT>: Consider CC to be idle if there are 7 or fewer BMC - * transients observed in <46.67us> - */ -#define RT1715_REG_PHY_CTRL1_TRANSCNT_7 0x70 -/* - * Bit 1:0 <TRXFilter>: RX filter to make sure the stable received PD message. - * default value is 01b - * The debounce time is (register value + 2) * 41.67ns - */ -#define RT1715_REG_PHY_CTRL1_TRXFILTER_125NS 0x01 -#define RT1715_REG_PHY_CTRL2 0x81 -/* - * Decrease the time that the PHY will wait for a second transition to detect - * a BMC-encoded 1 bit from 2.67 us to 2.25 us. - * Timeout = register value * .04167 us. - */ -#define RT1715_REG_PHY_CTRL2_CDRTHRESH_2_25US 54 -#define RT1715_REG_PHY_CTRL2_CDRTHRESH_2_5US 60 -#define RT1715_REG_PHY_CTRL2_CDRTHRESH_2_58US 62 - -#define RT1715_REG_PWR 0x90 -#define RT1715_REG_PWR_BMCIO_LPEN BIT(3) -#define RT1715_REG_PWR_VBUS_DETEN BIT(1) -#define RT1715_REG_PWR_BMCIO_OSCEN BIT(0) - -#define RT1715_REG_BMCIO_RXDZSEL 0x93 -#define RT1715_REG_BMCIO_RXDZSEL_OCCTRL_600MA BIT(7) -#define RT1715_REG_BMCIO_RXDZSEL_SEL BIT(0) - -#define RT1715_REG_RT_INT 0x98 -#define RT1715_REG_RT_INT_WAKEUP BIT(0) - -#define RT1715_REG_RT_MASK 0x99 -#define RT1715_REG_RT_MASK_M_WAKEUP BIT(0) - -#define RT1715_REG_VENDOR_5 0x9B -#define RT1715_REG_VENDOR_5_SHUTDOWN_OFF BIT(5) -#define RT1715_REG_VENDOR_5_ENEXTMSG BIT(4) -#define RT1715_REG_VENDOR_5_AUTOIDLE_EN BIT(3) - -#define RT1715_REG_I2CRST_CTRL 0x9E -/* I2C reset : (val + 1) * 12.5ms */ -#define RT1715_REG_I2CRST_CTRL_TOUT_200MS 0x0F -#define RT1715_REG_I2CRST_CTRL_TOUT_150MS 0x0B -#define RT1715_REG_I2CRST_CTRL_TOUT_100MS 0x07 -#define RT1715_REG_I2CRST_CTRL_EN BIT(7) - - -#define RT1715_REG_TTCPC_FILTER 0xA1 -#define RT1715_REG_TTCPC_FILTER_400US 0x0F - -#define RT1715_REG_DRP_TOGGLE_CYCLE 0xA2 -/* DRP Duty : (51.2 + 6.4 * val) ms */ -#define RT1715_REG_DRP_TOGGLE_CYCLE_76MS 0x04 - -#define RT1715_REG_DRP_DUTY_CTRL 0xA3 -#define RT1715_REG_DRP_DUTY_CTRL_40PERCENT 400 - -#define RT1715_REG_BMCIO_RXDZEN 0xAF -#define RT1715_REG_BMCIO_RXDZEN_ENABLE 0x01 -#define RT1715_REG_BMCIO_RXDZEN_DISABLE 0x00 - -extern const struct tcpm_drv rt1715_tcpm_drv; - -#endif /* defined(__CROS_EC_USB_PD_TCPM_RT1715_H) */ diff --git a/driver/tcpm/rt1718s.c b/driver/tcpm/rt1718s.c deleted file mode 100644 index 9d5a8895ad..0000000000 --- a/driver/tcpm/rt1718s.c +++ /dev/null @@ -1,561 +0,0 @@ -/* Copyright 2021 The Chromium OS Authors. All rights reserved. - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ - -/* - * RT1718S TCPC Driver - */ - -#include "console.h" -#include "driver/tcpm/rt1718s.h" -#include "driver/tcpm/tcpci.h" -#include "driver/tcpm/tcpm.h" -#include "stdint.h" -#include "system.h" -#include "task.h" -#include "timer.h" -#include "usb_mux.h" -#include "usb_pd.h" -#include "util.h" - -#define CPRINTS(format, args...) cprints(CC_USBCHARGE, format, ## args) -#define CPRINTF(format, args...) cprintf(CC_USBCHARGE, format, ## args) - -#define RT1718S_SW_RESET_DELAY_MS 2 - -/* i2c_write function which won't wake TCPC from low power mode. */ -static int rt1718s_write(int port, int reg, int val, int len) -{ - if (reg > 0xFF) { - return i2c_write_offset16( - tcpc_config[port].i2c_info.port, - tcpc_config[port].i2c_info.addr_flags, - reg, val, len); - } else if (len == 1) { - return tcpc_write(port, reg, val); - } else { - return tcpc_write16(port, reg, val); - } -} - -static int rt1718s_read(int port, int reg, int *val, int len) -{ - if (reg > 0xFF) { - return i2c_read_offset16( - tcpc_config[port].i2c_info.port, - tcpc_config[port].i2c_info.addr_flags, - reg, val, len); - } else if (len == 1) { - return tcpc_read(port, reg, val); - } else { - return tcpc_read16(port, reg, val); - } -} - -int rt1718s_write8(int port, int reg, int val) -{ - return rt1718s_write(port, reg, val, 1); -} - -int rt1718s_read8(int port, int reg, int *val) -{ - return rt1718s_read(port, reg, val, 1); -} - -int rt1718s_update_bits8(int port, int reg, int mask, int val) -{ - int reg_val; - - if (mask == 0xFF) - return rt1718s_write8(port, reg, val); - - RETURN_ERROR(rt1718s_read8(port, reg, ®_val)); - - reg_val &= (~mask); - reg_val |= (mask & val); - return rt1718s_write8(port, reg, reg_val); -} - -int rt1718s_write16(int port, int reg, int val) -{ - return rt1718s_write(port, reg, val, 2); -} - -int rt1718s_read16(int port, int reg, int *val) -{ - return rt1718s_read(port, reg, val, 2); -} - - -static int rt1718s_sw_reset(int port) -{ - int rv; - - rv = rt1718s_update_bits8(port, RT1718S_SYS_CTRL3, - RT1718S_SWRESET_MASK, 0xFF); - - msleep(RT1718S_SW_RESET_DELAY_MS); - - return rv; -} - -/* enable bc 1.2 sink function */ -static int rt1718s_enable_bc12_sink(int port, bool en) -{ - return rt1718s_update_bits8(port, RT1718S_RT2_BC12_SNK_FUNC, - RT1718S_RT2_BC12_SNK_FUNC_BC12_SNK_EN, - en ? 0xFF : 0); -} - -static int rt1718s_set_bc12_sink_spec_ta(int port, bool en) -{ - return rt1718s_update_bits8(port, - RT1718S_RT2_BC12_SNK_FUNC, - RT1718S_RT2_BC12_SNK_FUNC_SPEC_TA_EN, en ? 0xFF : 0); -} - -static int rt1718s_set_bc12_sink_dcdt_sel(int port, uint8_t dcdt_sel) -{ - return rt1718s_update_bits8(port, - RT1718S_RT2_BC12_SNK_FUNC, - RT1718S_RT2_BC12_SNK_FUNC_DCDT_SEL_MASK, dcdt_sel); -} - -static int rt1718s_set_bc12_sink_vlgc_option(int port, bool en) -{ - return rt1718s_update_bits8(port, - RT1718S_RT2_BC12_SNK_FUNC, - RT1718S_RT2_BC12_SNK_FUNC_VLGC_OPT, en ? 0xFF : 0); -} - -static int rt1718s_set_bc12_sink_vport_sel(int port, uint8_t sel) -{ - return rt1718s_update_bits8(port, - RT1718S_RT2_DPDM_CTR1_DPDM_SET, - RT1718S_RT2_DPDM_CTR1_DPDM_SET_DPDM_VSRC_SEL_MASK, sel); -} - -static int rt1718s_set_bc12_sink_wait_vbus(int port, bool en) -{ - return rt1718s_update_bits8(port, - RT1718S_RT2_BC12_SNK_FUNC, - RT1718S_RT2_BC12_SNK_FUNC_BC12_WAIT_VBUS, - en ? 0xFF : 0); -} - -/* - * rt1718s BC12 function initial - */ -static int rt1718s_bc12_init(int port) -{ - /* Enable vendor defined BC12 function */ - RETURN_ERROR(rt1718s_write8(port, RT1718S_RT_MASK6, - RT1718S_RT_MASK6_M_BC12_SNK_DONE | - RT1718S_RT_MASK6_M_BC12_TA_CHG)); - - RETURN_ERROR(rt1718s_write8(port, RT1718S_RT2_SBU_CTRL_01, - RT1718S_RT2_SBU_CTRL_01_DPDM_VIEN | - RT1718S_RT2_SBU_CTRL_01_DM_SWEN | - RT1718S_RT2_SBU_CTRL_01_DP_SWEN)); - - /* Disable 2.7v mode */ - RETURN_ERROR(rt1718s_set_bc12_sink_spec_ta(port, false)); - - /* DCDT select 600ms timeout */ - RETURN_ERROR(rt1718s_set_bc12_sink_dcdt_sel(port, - RT1718S_RT2_BC12_SNK_FUNC_DCDT_SEL_600MS)); - - /* Disable vlgc option */ - RETURN_ERROR(rt1718s_set_bc12_sink_vlgc_option(port, false)); - - /* DPDM voltage selection */ - RETURN_ERROR(rt1718s_set_bc12_sink_vport_sel(port, - RT1718S_RT2_DPDM_CTR1_DPDM_SET_DPDM_VSRC_SEL_0_65V)); - - /* Disable sink wait vbus */ - RETURN_ERROR(rt1718s_set_bc12_sink_wait_vbus(port, false)); - - return EC_SUCCESS; -} - -static int rt1718s_workaround(int port) -{ - int device_id; - - RETURN_ERROR(tcpc_read16(port, RT1718S_DEVICE_ID, &device_id)); - - switch (device_id) { - case RT1718S_DEVICE_ID_ES1: - RETURN_ERROR(rt1718s_update_bits8(port, RT1718S_VCONN_CONTROL_3, - RT1718S_VCONN_CONTROL_3_VCONN_OVP_DEG, - 0xFF)); - /* fallthrough */ - case RT1718S_DEVICE_ID_ES2: - RETURN_ERROR(rt1718s_update_bits8(port, TCPC_REG_FAULT_CTRL, - TCPC_REG_FAULT_CTRL_VBUS_OCP_FAULT_DIS, - 0xFF)); - RETURN_ERROR(rt1718s_update_bits8(port, RT1718S_VCON_CTRL4, - RT1718S_VCON_CTRL4_UVP_CP_EN | - RT1718S_VCON_CTRL4_OVP_CP_EN, - 0)); - RETURN_ERROR(rt1718s_update_bits8(port, RT1718S_VCONN_CONTROL_2, - RT1718S_VCONN_CONTROL_2_OVP_EN_CC1 | - RT1718S_VCONN_CONTROL_2_OVP_EN_CC2, - 0xFF)); - break; - default: - /* do nothing */ - break; - } - - return EC_SUCCESS; -} - -static int rt1718s_init(int port) -{ - static bool need_sw_reset = true; - - if (!system_jumped_late() && need_sw_reset) { - RETURN_ERROR(rt1718s_sw_reset(port)); - need_sw_reset = false; - } - - RETURN_ERROR(rt1718s_bc12_init(port)); - - /* Set VBUS_VOL_SEL to 20V */ - RETURN_ERROR(rt1718s_update_bits8(port, RT1718S_RT2_VBUS_VOL_CTRL, - RT1718S_RT2_VBUS_VOL_CTRL_VOL_SEL, - RT1718S_VBUS_VOL_TO_REG(20))); - - /* Disable FOD function */ - RETURN_ERROR(rt1718s_update_bits8(port, 0xCF, 0x40, 0x00)); - - /* Tcpc connect invalid disabled. Exit shipping mode */ - RETURN_ERROR(rt1718s_update_bits8(port, RT1718S_SYS_CTRL1, - RT1718S_SYS_CTRL1_TCPC_CONN_INVALID, 0x00)); - RETURN_ERROR(rt1718s_update_bits8(port, RT1718S_SYS_CTRL1, - RT1718S_SYS_CTRL1_SHIPPING_OFF, 0xFF)); - - /* Clear alert and fault */ - RETURN_ERROR(rt1718s_write8(port, TCPC_REG_FAULT_STATUS, 0xFF)); - RETURN_ERROR(tcpc_write16(port, TCPC_REG_ALERT, 0xFFFF)); - - RETURN_ERROR(tcpci_tcpm_init(port)); - - RETURN_ERROR(rt1718s_workaround(port)); - /* - * Set vendor defined alert unmasked, this must be done after - * tcpci_tcpm_init. - */ - RETURN_ERROR(tcpc_update16(port, TCPC_REG_ALERT_MASK, - TCPC_REG_ALERT_MASK_VENDOR_DEF, - MASK_SET)); - - RETURN_ERROR(board_rt1718s_init(port)); - - return EC_SUCCESS; -} - -__overridable int board_rt1718s_init(int port) -{ - return EC_SUCCESS; -} - -static enum charge_supplier rt1718s_get_bc12_type(int port) -{ - int data; - - if (rt1718s_read8(port, RT1718S_RT2_BC12_STAT, &data)) - return CHARGE_SUPPLIER_OTHER; - - switch (data & RT1718S_RT2_BC12_STAT_PORT_STATUS_MASK) { - case RT1718S_RT2_BC12_STAT_PORT_STATUS_NONE: - return CHARGE_SUPPLIER_NONE; - case RT1718S_RT2_BC12_STAT_PORT_STATUS_SDP: - return CHARGE_SUPPLIER_BC12_SDP; - case RT1718S_RT2_BC12_STAT_PORT_STATUS_CDP: - return CHARGE_SUPPLIER_BC12_CDP; - case RT1718S_RT2_BC12_STAT_PORT_STATUS_DCP: - return CHARGE_SUPPLIER_BC12_DCP; - } - - return CHARGE_SUPPLIER_OTHER; -} - -static int rt1718s_get_bc12_ilim(enum charge_supplier supplier) -{ - switch (supplier) { - case CHARGE_SUPPLIER_BC12_DCP: - case CHARGE_SUPPLIER_BC12_CDP: - return USB_CHARGER_MAX_CURR_MA; - case CHARGE_SUPPLIER_BC12_SDP: - default: - return USB_CHARGER_MIN_CURR_MA; - } -} - -static void rt1718s_update_charge_manager(int port, - enum charge_supplier new_bc12_type) -{ - static enum charge_supplier current_bc12_type = CHARGE_SUPPLIER_NONE; - - if (new_bc12_type != current_bc12_type) { - if (current_bc12_type != CHARGE_SUPPLIER_NONE) - charge_manager_update_charge(current_bc12_type, port, - NULL); - - if (new_bc12_type != CHARGE_SUPPLIER_NONE) { - struct charge_port_info chg = { - .current = rt1718s_get_bc12_ilim(new_bc12_type), - .voltage = USB_CHARGER_VOLTAGE_MV, - }; - - charge_manager_update_charge(new_bc12_type, port, &chg); - } - - current_bc12_type = new_bc12_type; - } -} - -static void rt1718s_bc12_usb_charger_task(const int port) -{ - rt1718s_enable_bc12_sink(port, false); - - while (1) { - uint32_t evt = task_wait_event(-1); - - if (evt & USB_CHG_EVENT_VBUS) { - if (pd_snk_is_vbus_provided(port)) - rt1718s_enable_bc12_sink(port, true); - else - rt1718s_update_charge_manager( - port, CHARGE_SUPPLIER_NONE); - } - - /* detection done, update charge_manager and stop detection */ - if (evt & USB_CHG_EVENT_BC12) { - int type = rt1718s_get_bc12_type(port); - - rt1718s_update_charge_manager( - port, type); - rt1718s_enable_bc12_sink(port, false); - } - } -} - -void rt1718s_vendor_defined_alert(int port) -{ - int rv, value; - - if (IS_ENABLED(CONFIG_USB_PD_FRS_PPC) && - IS_ENABLED(CONFIG_USBC_PPC_RT1718S)) { - int int1; - - rv = rt1718s_read8(port, RT1718S_RT_INT1, &int1); - if (rv) - return; - rv = rt1718s_write8(port, RT1718S_RT_INT1, int1); - if (rv) - return; - - if ((int1 & RT1718S_RT_INT1_INT_RX_FRS)) { - pd_got_frs_signal(port); - - tcpc_write16(port, TCPC_REG_ALERT, - TCPC_REG_ALERT_VENDOR_DEF); - /* ignore other interrupts for faster frs handling */ - return; - } - } - - /* Process BC12 alert */ - rv = rt1718s_read8(port, RT1718S_RT_INT6, &value); - if (rv) - return; - - /* clear BC12 alert */ - rv = rt1718s_write8(port, RT1718S_RT_INT6, value); - if (rv) - return; - - /* check snk done */ - if (value & RT1718S_RT_INT6_INT_BC12_SNK_DONE) - task_set_event(USB_CHG_PORT_TO_TASK_ID(port), - USB_CHG_EVENT_BC12); - - /* clear the alerts from rt1718s_workaround() */ - rv = rt1718s_write8(port, RT1718S_RT_INT2, 0xFF); - if (rv) - return; - /* ES1 workaround: disable Vconn discharge */ - rv = rt1718s_update_bits8(port, RT1718S_SYS_CTRL2, - RT1718S_SYS_CTRL2_VCONN_DISCHARGE_EN, - 0); - if (rv) - return; - - tcpc_write16(port, TCPC_REG_ALERT, TCPC_REG_ALERT_VENDOR_DEF); -} - -static void rt1718s_alert(int port) -{ - int alert; - - tcpc_read16(port, TCPC_REG_ALERT, &alert); - if (alert & TCPC_REG_ALERT_VENDOR_DEF) - rt1718s_vendor_defined_alert(port); - - if (alert & ~TCPC_REG_ALERT_VENDOR_DEF) - tcpci_tcpc_alert(port); -} - -#ifdef CONFIG_USB_PD_TCPC_LOW_POWER -static int rt1718s_enter_low_power_mode(int port) -{ - /* enter low power mode */ - RETURN_ERROR(rt1718s_update_bits8(port, RT1718S_SYS_CTRL2, - RT1718S_SYS_CTRL2_LPWR_EN, 0xFF)); - RETURN_ERROR(rt1718s_update_bits8(port, RT1718S_SYS_CTRL2, - RT1718S_SYS_CTRL2_BMCIO_OSC_EN, 0)); - - /* disable DP/DM/SBU swtiches */ - RETURN_ERROR(rt1718s_write8(port, RT1718S_RT2_SBU_CTRL_01, 0)); - - return tcpci_enter_low_power_mode(port); -} -#endif - -int rt1718s_get_adc(int port, enum rt1718s_adc_channel channel, int *adc_val) -{ - static struct mutex adc_lock; - int rv; - const int max_wait_times = 30; - - if (in_interrupt_context()) { - CPRINTS("Err: use ADC in IRQ"); - return EC_ERROR_INVAL; - } - - mutex_lock(&adc_lock); - - /* Start ADC conversation */ - rv = rt1718s_write16(port, RT1718S_ADC_CTRL_01, BIT(channel)); - if (rv) - goto out; - - /* - * The expected conversion time is 85.3us * number of enabled channels. - * Polling for 3ms should be long enough. - */ - for (int i = 0; i < max_wait_times; i++) { - int adc_done; - - usleep(100); - rv = rt1718s_read8(port, RT1718S_RT_INT6, &adc_done); - if (rv) - goto out; - if (adc_done & RT1718S_RT_INT6_INT_ADC_DONE) - break; - if (i == max_wait_times - 1) { - CPRINTS("conversion fail channel=%d", channel); - rv = EC_ERROR_TIMEOUT; - goto out; - } - } - - /* Read ADC data */ - rv = rt1718s_read16(port, RT1718S_ADC_CHX_VOL_L(channel), adc_val); - if (rv) - goto out; - - /* - * The resolution of VBUS1 ADC is 12.5mV, - * other channels are 4mV. - */ - if (channel == RT1718S_ADC_VBUS1) - *adc_val = *adc_val * 125 / 10; - else - *adc_val *= 4; - -out: - /* Cleanup: disable adc and clear interrupt. Error ignored. */ - rt1718s_write16(port, RT1718S_ADC_CTRL_01, 0); - rt1718s_write8(port, RT1718S_RT_INT6, RT1718S_RT_INT6_INT_ADC_DONE); - - mutex_unlock(&adc_lock); - return rv; -} - -void rt1718s_gpio_set_flags(int port, enum rt1718s_gpio signal, uint32_t flags) -{ - int val = 0; - - if (!(flags & GPIO_OPEN_DRAIN)) - val |= RT1718S_GPIO_CTRL_OD_N; - if (flags & GPIO_PULL_UP) - val |= RT1718S_GPIO_CTRL_PU; - if (flags & GPIO_PULL_DOWN) - val |= RT1718S_GPIO_CTRL_PD; - if (flags & GPIO_HIGH) - val |= RT1718S_GPIO_CTRL_O; - if (flags & GPIO_OUTPUT) - val |= RT1718S_GPIO_CTRL_OE; - - rt1718s_write8(port, RT1718S_GPIO_CTRL(signal), val); -} - -void rt1718s_gpio_set_level(int port, enum rt1718s_gpio signal, int value) -{ - rt1718s_update_bits8(port, RT1718S_GPIO_CTRL(signal), - RT1718S_GPIO_CTRL_O, - value ? 0xFF : 0); -} - -int rt1718s_gpio_get_level(int port, enum rt1718s_gpio signal) -{ - int val; - - rt1718s_read8(port, RT1718S_GPIO_CTRL(signal), &val); - return !!(val & RT1718S_GPIO_CTRL_I); -} - -/* RT1718S is a TCPCI compatible port controller */ -const struct tcpm_drv rt1718s_tcpm_drv = { - .init = &rt1718s_init, - .release = &tcpci_tcpm_release, - .get_cc = &tcpci_tcpm_get_cc, -#ifdef CONFIG_USB_PD_VBUS_DETECT_TCPC - .check_vbus_level = &tcpci_tcpm_check_vbus_level, -#endif - .select_rp_value = &tcpci_tcpm_select_rp_value, - .set_cc = &tcpci_tcpm_set_cc, - .set_polarity = &tcpci_tcpm_set_polarity, -#ifdef CONFIG_USB_PD_DECODE_SOP - .sop_prime_enable = &tcpci_tcpm_sop_prime_enable, -#endif - .set_vconn = &tcpci_tcpm_set_vconn, - .set_msg_header = &tcpci_tcpm_set_msg_header, - .set_rx_enable = &tcpci_tcpm_set_rx_enable, - .get_message_raw = &tcpci_tcpm_get_message_raw, - .transmit = &tcpci_tcpm_transmit, - .tcpc_alert = &rt1718s_alert, -#ifdef CONFIG_USB_PD_DISCHARGE_TCPC - .tcpc_discharge_vbus = &tcpci_tcpc_discharge_vbus, -#endif -#ifdef CONFIG_USB_PD_DUAL_ROLE_AUTO_TOGGLE - .drp_toggle = &tcpci_tcpc_drp_toggle, -#endif - .get_chip_info = &tcpci_get_chip_info, -#ifdef CONFIG_USB_PD_PPC - .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 = &rt1718s_enter_low_power_mode, -#endif -}; - -const struct bc12_drv rt1718s_bc12_drv = { - .usb_charger_task = rt1718s_bc12_usb_charger_task, -}; diff --git a/driver/tcpm/rt1718s.h b/driver/tcpm/rt1718s.h deleted file mode 100644 index 07c3ed3f82..0000000000 --- a/driver/tcpm/rt1718s.h +++ /dev/null @@ -1,245 +0,0 @@ -/* Copyright 2021 The Chromium OS Authors. All rights reserved. - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ -#ifndef __CROS_EC_USB_PD_TCPM_RT1718S_H -#define __CROS_EC_USB_PD_TCPM_RT1718S_H - -#include "util.h" -#include "usb_charge.h" -#include "usb_pd_tcpm.h" - -/* RT1718S Private RegMap */ -#define RT1718S_I2C_ADDR_FLAGS 0x43 - -#define RT1718S_VID 0x29CF -#define RT1718S_PID 0x1718 - -#define RT1718S_DEVICE_ID 0x04 -#define RT1718S_DEVICE_ID_ES1 0x4511 -#define RT1718S_DEVICE_ID_ES2 0x4513 - -#define RT1718S_PHYCTRL1 0x80 -#define RT1718S_PHYCTRL2 0x81 -#define RT1718S_PHYCTRL3 0x82 -#define RT1718S_PHYCTRL7 0x86 -#define RT1718S_VCON_CTRL1 0x8A -#define RT1718S_VCON_CTRL3 0x8C -#define RT1718S_SYS_CTRL1 0x8F -#define RT1718S_SYS_CTRL1_TCPC_CONN_INVALID BIT(6) -#define RT1718S_SYS_CTRL1_SHIPPING_OFF BIT(5) -#define RT1718S_SYS_CTRL2 0x90 -#define RT1718S_SYS_CTRL2_BMCIO_OSC_EN BIT(0) -#define RT1718S_SYS_CTRL2_LPWR_EN BIT(3) - -#define RT1718S_VCONN_CONTROL_2 0x8B -#define RT1718S_VCONN_CONTROL_2_OVP_EN_CC1 BIT(7) -#define RT1718S_VCONN_CONTROL_2_OVP_EN_CC2 BIT(6) -#define RT1718S_VCONN_CONTROL_3 0x8C -#define RT1718S_VCONN_CONTROL_3_VCONN_OVP_DEG BIT(1) - -#define RT1718S_SYS_CTRL2 0x90 -#define RT1718S_SYS_CTRL2_VCONN_DISCHARGE_EN BIT(5) - -#define RT1718S_RT_MASK1 0x91 -#define RT1718S_RT_MASK1_M_VBUS_FRS_LOW BIT(7) -#define RT1718S_RT_MASK1_M_RX_FRS BIT(6) -#define RT1718S_RT_MASK2 0x92 -#define RT1718S_RT_MASK3 0x93 -#define RT1718S_RT_MASK4 0x94 -#define RT1718S_RT_MASK5 0x95 -#define RT1718S_RT_MASK6 0x96 -#define RT1718S_RT_MASK6_M_BC12_SNK_DONE BIT(7) -#define RT1718S_RT_MASK6_M_HVDCP_CHK_DONE BIT(6) -#define RT1718S_RT_MASK6_M_BC12_TA_CHG BIT(5) -#define RT1718S_RT_MASK7 0x97 - -#define RT1718S_RT_INT1 0x98 -#define RT1718S_RT_INT1_INT_VBUS_FRS_LOW BIT(7) -#define RT1718S_RT_INT1_INT_RX_FRS BIT(6) -#define RT1718S_RT_INT2 0x99 -#define RT1718S_RT_INT6 0x9D -#define RT1718S_RT_INT6_INT_BC12_SNK_DONE BIT(7) -#define RT1718S_RT_INT6_INT_HVDCP_CHK_DONE BIT(6) -#define RT1718S_RT_INT6_INT_BC12_TA_CHG BIT(5) -#define RT1718S_RT_INT6_INT_ADC_DONE BIT(0) - -#define RT1718S_RT_ST6 0xA4 -#define RT1718S_RT_ST6_BC12_SNK_DONE BIT(7) -#define RT1718S_RT_ST6_HVDCP_CHK_DONE BIT(6) -#define RT1718S_RT_ST6_BC12_TA_CHG BIT(5) - -#define RT1718S_PHYCTRL9 0xAC - -#define RT1718S_SYS_CTRL3 0xB0 -#define RT1718S_TCPC_CTRL1 0xB1 -#define RT1718S_TCPC_CTRL2 0xB2 -#define RT1718S_TCPC_CTRL3 0xB3 -#define RT1718S_SWRESET_MASK BIT(0) -#define RT1718S_TCPC_CTRL4 0xB4 -#define RT1718S_SYS_CTRL4 0xB8 -#define RT1718S_WATCHDOG_CTRL 0xBE -#define RT1718S_I2C_RST_CTRL 0xBF - -#define RT1718S_HILO_CTRL9 0xC8 -#define RT1718S_SHILED_CTRL1 0xCA -#define RT1718S_FRS_CTRL1 0xCB -#define RT1718S_FRS_CTRL1_FRSWAPRX_MASK 0xF0 -#define RT1718S_FRS_CTRL2 0xCC -#define RT1718S_FRS_CTRL2_RX_FRS_EN BIT(6) -#define RT1718S_FRS_CTRL2_FR_VBUS_SELECT BIT(4) -#define RT1718S_FRS_CTRL2_VBUS_FRS_EN BIT(3) -#define RT1718S_FRS_CTRL3 0xCE -#define RT1718S_FRS_CTRL3_FRS_RX_WAIT_GPIO2 BIT(3) -#define RT1718S_FRS_CTRL3_FRS_RX_WAIT_GPIO1 BIT(2) - -#define RT1718S_DIS_SRC_VBUS_CTRL 0xE0 -#define RT1718S_ENA_SRC_VBUS_CTRL 0xE1 -#define RT1718S_FAULT_OC1_VBUS_CTRL 0xE3 -#define RT1718S_GPIO1_VBUS_CTRL 0xEA -#define RT1718S_GPIO1_VBUS_CTRL_FRS_RX_VBUS BIT(6) -#define RT1718S_GPIO2_VBUS_CTRL 0xEB -#define RT1718S_GPIO2_VBUS_CTRL_FRS_RX_VBUS BIT(6) -#define RT1718S_VBUS_CTRL_EN 0xEC -#define RT1718S_VBUS_CTRL_EN_GPIO2_VBUS_PATH_EN BIT(7) -#define RT1718S_VBUS_CTRL_EN_GPIO1_VBUS_PATH_EN BIT(6) - -#define RT1718S_GPIO_CTRL(n) (0xED + (n)) -#define RT1718S_GPIO_CTRL_PU BIT(5) -#define RT1718S_GPIO_CTRL_PD BIT(4) -#define RT1718S_GPIO_CTRL_OD_N BIT(3) -#define RT1718S_GPIO_CTRL_OE BIT(2) -#define RT1718S_GPIO_CTRL_O BIT(1) -#define RT1718S_GPIO_CTRL_I BIT(0) - -#define RT1718S_UNLOCK_PW_2 0xF0 -#define RT1718S_UNLOCK_PW_1 0xF1 - -#define RT1718S_RT2_SYS_CTRL5 0xF210 - -#define RT1718S_VBUS_VOL_TO_REG(_vol) (CLAMP(_vol, 5, 20) - 5) -#define RT1718S_VBUS_PCT_TO_REG(_pct) (CLAMP(_pct, 5, 20) \ - / 5 - 1) -#define RT1718S_RT2_VBUS_VOL_CTRL 0xF213 -#define RT1718S_RT2_VBUS_VOL_CTRL_OVP_SEL (BIT(5) | BIT(4)) -#define RT1718S_RT2_VBUS_VOL_CTRL_VOL_SEL 0x0F - -#define RT1718S_VCON_CTRL4 0xF211 -#define RT1718S_VCON_CTRL4_UVP_CP_EN BIT(5) -#define RT1718S_VCON_CTRL4_OVP_CP_EN BIT(4) - -#define RT1718S_RT2_VBUS_OCRC_EN 0xF214 -#define RT1718S_RT2_VBUS_OCRC_EN_VBUS_OCP1_EN BIT(0) -#define RT1718S_RT2_VBUS_OCP_CTRL1 0xF216 -#define RT1718S_RT2_VBUS_OCP_CTRL4 0xF219 - -#define RT1718S_RT2_SBU_CTRL_01 0xF23A -#define RT1718S_RT2_SBU_CTRL_01_SBU_VIEN BIT(7) -#define RT1718S_RT2_SBU_CTRL_01_DPDM_VIEN BIT(6) -#define RT1718S_RT2_SBU_CTRL_01_SBU2_SWEN BIT(3) -#define RT1718S_RT2_SBU_CTRL_01_SBU1_SWEN BIT(2) -#define RT1718S_RT2_SBU_CTRL_01_DM_SWEN BIT(1) -#define RT1718S_RT2_SBU_CTRL_01_DP_SWEN BIT(0) - -#define RT1718S_RT2_BC12_SNK_FUNC 0xF260 -#define RT1718S_RT2_BC12_SNK_FUNC_BC12_SNK_EN BIT(7) -#define RT1718S_RT2_BC12_SNK_FUNC_SPEC_TA_EN BIT(6) -#define RT1718S_RT2_BC12_SNK_FUNC_DCDT_SEL_MASK 0x30 -#define RT1718S_RT2_BC12_SNK_FUNC_DCDT_SEL_DISABLE 0x00 -#define RT1718S_RT2_BC12_SNK_FUNC_DCDT_SEL_300MS 0x10 -#define RT1718S_RT2_BC12_SNK_FUNC_DCDT_SEL_600MS 0x20 -#define RT1718S_RT2_BC12_SNK_FUNC_DCDT_SEL_WAIT_DATA 0x30 -#define RT1718S_RT2_BC12_SNK_FUNC_VLGC_OPT BIT(3) -#define RT1718S_RT2_BC12_SNK_FUNC_VPORT_SEL BIT(2) -#define RT1718S_RT2_BC12_SNK_FUNC_BC12_WAIT_VBUS BIT(1) - -#define RT1718S_RT2_BC12_STAT 0xF261 -#define RT1718S_RT2_BC12_STAT_DCDT BIT(4) -#define RT1718S_RT2_BC12_STAT_PORT_STATUS_MASK 0x0F -#define RT1718S_RT2_BC12_STAT_PORT_STATUS_NONE 0x00 -#define RT1718S_RT2_BC12_STAT_PORT_STATUS_SDP 0x0D -#define RT1718S_RT2_BC12_STAT_PORT_STATUS_CDP 0x0E -#define RT1718S_RT2_BC12_STAT_PORT_STATUS_DCP 0x0F - - -#define RT1718S_RT2_DPDM_CTR1_DPDM_SET 0xF263 -#define RT1718S_RT2_DPDM_CTR1_DPDM_SET_DPDM_VSRC_SEL_MASK 0x03 -#define RT1718S_RT2_DPDM_CTR1_DPDM_SET_DPDM_VSRC_SEL_0_55V 0x00 -#define RT1718S_RT2_DPDM_CTR1_DPDM_SET_DPDM_VSRC_SEL_0_60V 0x01 -#define RT1718S_RT2_DPDM_CTR1_DPDM_SET_DPDM_VSRC_SEL_0_65V 0x02 -#define RT1718S_RT2_DPDM_CTR1_DPDM_SET_DPDM_VSRC_SEL_0_70V 0x03 - -#define RT1718S_RT2_BC12_SRC_FUNC 0xF26D -#define RT1718S_RT2_BC12_SRC_FUNC_BC12_SRC_EN BIT(7) -#define RT1718S_RT2_BC12_SRC_FUNC_SRC_MODE_SEL_MASK 0x70 -#define RT1718S_RT2_BC12_SRC_FUNC_SRC_MODE_SEL_BC12_SDP 0x00 -#define RT1718S_RT2_BC12_SRC_FUNC_SRC_MODE_SEL_BC12_CDP 0x10 -#define RT1718S_RT2_BC12_SRC_FUNC_SRC_MODE_SEL_BC12_DCP 0x20 -#define RT1718S_RT2_BC12_SRC_FUNC_WAIT_VBUS_ON BIT(0) - -#define RT1718S_ADC_CTRL_01 0xF2A0 -#define RT1718S_ADC_CTRL_02 0xF2A1 -#define RT1718S_ADC_CHX_VOL_L(ch) (0xF2A6 + (ch) * 2) -#define RT1718S_ADC_CHX_VOL_H(ch) (0xF2A7 + (ch) * 2) - -extern const struct tcpm_drv rt1718s_tcpm_drv; -extern const struct bc12_drv rt1718s_bc12_drv; - -int rt1718s_write8(int port, int reg, int val); -int rt1718s_read8(int port, int reg, int *val); -int rt1718s_update_bits8(int port, int reg, int mask, int val); -int rt1718s_write16(int port, int reg, int val); -int rt1718s_read16(int port, int reg, int *val); -__override_proto int board_rt1718s_init(int port); - -enum rt1718s_adc_channel { - RT1718S_ADC_VBUS1 = 0, - RT1718S_ADC_VBUS2, - RT1718S_ADC_VDC, - RT1718S_ADC_VBUS_CURRENT, - RT1718S_ADC_CC1, - RT1718S_ADC_CC2, - RT1718S_ADC_SBU1, - RT1718S_ADC_SBU2, - RT1718S_ADC_DP, - RT1718S_ADC_DM, - RT1718S_ADC_CH10, - RT1718S_ADC_CH11, -}; - -int rt1718s_get_adc(int port, enum rt1718s_adc_channel channel, int *adc_val); - -enum rt1718s_gpio { - RT1718S_GPIO1 = 0, - RT1718S_GPIO2, - RT1718S_GPIO3, -}; - -/** - * Set flags for GPIO - * - * @param port rt1718s I2C port - * @param signal gpio pin name in enum rt1718s_gpio - * @param flags GPIO_* flags defined in include/gpio.h - */ -void rt1718s_gpio_set_flags(int port, enum rt1718s_gpio signal, uint32_t flags); - -/** - * Set the value of a signal - * - * @param port rt1718s I2C port - * @param signal gpio pin name in enum rt1718s_gpio - * @param value New value for signal (0 = low, non-zero = high) - */ -void rt1718s_gpio_set_level(int port, enum rt1718s_gpio signal, int value); - -/** - * Get the current value of a signal. - * - * @param port rt1718s I2C port - * @param signal gpio pin name in enum rt1718s_gpio - * @return 0 if low, 1 if high. - */ -int rt1718s_gpio_get_level(int port, enum rt1718s_gpio signal); - -#endif /* __CROS_EC_USB_PD_TCPM_MT6370_H */ diff --git a/driver/tcpm/stm32gx.c b/driver/tcpm/stm32gx.c deleted file mode 100644 index 359c7c1108..0000000000 --- a/driver/tcpm/stm32gx.c +++ /dev/null @@ -1,186 +0,0 @@ -/* Copyright 2020 The Chromium OS Authors. All rights reserved. - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ - -/* TCPM for STM32Gx UCPD module */ - -#include "chip/stm32/ucpd-stm32gx.h" -#include "common.h" -#include "config.h" -#include "console.h" -#include "registers.h" -#include "stm32gx.h" -#include "system.h" -#include "task.h" -#include "tcpm/tcpci.h" -#include "timer.h" -#include "util.h" -#include "usb_pd.h" -#include "usb_pd_tcpm.h" -#include "hooks.h" - -/* - * STM32G4 UCPD peripheral does not have the ability to detect VBUS, but - * CONFIG_USB_PD_VBUS_DETECT_TCPC maybe still be defined for another port on the - * same board which uses a TCPC that does have this feature. Therefore, this - * config option is not considered an error. - */ -#if defined(CONFIG_USB_PD_TCPC_LOW_POWER) -#error "Unsupported config options of Stm32gx PD driver" -#endif - -#define CPRINTF(format, args...) cprintf(CC_USBPD, format, ## args) -#define CPRINTS(format, args...) cprints(CC_USBPD, format, ## args) - -/* Wait time for vconn power switch to turn off. */ -#ifndef PD_STM32GX_VCONN_TURN_OFF_DELAY_US -#define PD_STM32GX_VCONN_TURN_OFF_DELAY_US 500 -#endif - -static int cached_rp[CONFIG_USB_PD_PORT_MAX_COUNT]; - - -static int stm32gx_tcpm_get_message_raw(int port, uint32_t *buf, int *head) -{ - return stm32gx_ucpd_get_message_raw(port, buf, head); -} - -static int stm32gx_tcpm_init(int port) -{ - return stm32gx_ucpd_init(port); -} - -static int stm32gx_tcpm_release(int port) -{ - return stm32gx_ucpd_release(port); -} - -static int stm32gx_tcpm_get_cc(int port, enum tcpc_cc_voltage_status *cc1, - enum tcpc_cc_voltage_status *cc2) -{ - /* Get cc_state value for each CC line */ - stm32gx_ucpd_get_cc(port, cc1, cc2); - - return EC_SUCCESS; -} - -static int stm32gx_tcpm_select_rp_value(int port, int rp_sel) -{ - cached_rp[port] = rp_sel; - - return EC_SUCCESS; -} - -static int stm32gx_tcpm_set_cc(int port, int pull) -{ - return stm32gx_ucpd_set_cc(port, pull, cached_rp[port]); -} - -static int stm32gx_tcpm_set_polarity(int port, enum tcpc_cc_polarity polarity) -{ - return stm32gx_ucpd_set_polarity(port, polarity); -} - -static int stm32gx_tcpm_set_vconn(int port, int enable) -{ - stm32gx_ucpd_vconn_disc_rp(port, enable); - - if (IS_ENABLED(CONFIG_USB_PD_DECODE_SOP)) - stm32gx_ucpd_sop_prime_enable(port, enable); - - return EC_SUCCESS; -} - -static int stm32gx_tcpm_set_msg_header(int port, int power_role, int data_role) -{ - return stm32gx_ucpd_set_msg_header(port, power_role, data_role); -} - -static int stm32gx_tcpm_set_rx_enable(int port, int enable) -{ - return stm32gx_ucpd_set_rx_enable(port, enable); -} - -static int stm32gx_tcpm_transmit(int port, - enum tcpci_msg_type type, - uint16_t header, - const uint32_t *data) -{ - return stm32gx_ucpd_transmit(port, type, header, data); -} - -static int stm32gx_tcpm_sop_prime_enable(int port, bool enable) -{ - return stm32gx_ucpd_sop_prime_enable(port, enable); -} - - -static int stm32gx_tcpm_get_chip_info(int port, int live, - struct ec_response_pd_chip_info_v1 *chip_info) -{ - return stm32gx_ucpd_get_chip_info(port, live, chip_info); -} - -static void stm32gx_tcpm_sw_reset(void) -{ - /* - * TODO(b/167601672): Not sure if this hook is required for UCPD as - * opposed to TCPCI compliant TCPC. Leaving this a placeholder so I - * don't forget to pull this back in, if required. - */ -} -DECLARE_HOOK(HOOK_USB_PD_DISCONNECT, stm32gx_tcpm_sw_reset, HOOK_PRIO_DEFAULT); - -static int stm32gx_tcpm_reset_bist_type_2(int port) -{ - /* - * The UCPD peripheral must be disabled, then enabled, to recover from - * starting BIST type-2 mode. Call the init method to accomplish - * this. Then, need to send a hard reset to port partner. - */ - stm32gx_ucpd_init(port); - pd_execute_hard_reset(port); - task_set_event(PD_PORT_TO_TASK_ID(port), TASK_EVENT_WAKE); - - return EC_SUCCESS; -} - -enum ec_error_list stm32gx_tcpm_set_bist_test_mode(const int port, - const bool enable) -{ - return stm32gx_ucpd_set_bist_test_mode(port, enable); -} - -bool stm32gx_tcpm_check_vbus_level(int port, enum vbus_level level) -{ - /* - * UCPD peripheral can't detect VBUS, so always return 0. Any port which - * uses the stm32g4 UCPD peripheral for its TCPC would also have a PPC - * that will handle VBUS detection. However, there may be products which - * don't have a PPC on some ports that will rely on a TCPC to do VBUS - * detection. - */ - return 0; -} - -const struct tcpm_drv stm32gx_tcpm_drv = { - .init = &stm32gx_tcpm_init, - .release = &stm32gx_tcpm_release, - .get_cc = &stm32gx_tcpm_get_cc, - .check_vbus_level = &stm32gx_tcpm_check_vbus_level, - .select_rp_value = &stm32gx_tcpm_select_rp_value, - .set_cc = &stm32gx_tcpm_set_cc, - .set_polarity = &stm32gx_tcpm_set_polarity, -#ifdef CONFIG_USB_PD_DECODE_SOP - .sop_prime_enable = &stm32gx_tcpm_sop_prime_enable, -#endif - .set_vconn = &stm32gx_tcpm_set_vconn, - .set_msg_header = &stm32gx_tcpm_set_msg_header, - .set_rx_enable = &stm32gx_tcpm_set_rx_enable, - .get_message_raw = &stm32gx_tcpm_get_message_raw, - .transmit = &stm32gx_tcpm_transmit, - .get_chip_info = &stm32gx_tcpm_get_chip_info, - .reset_bist_type_2 = &stm32gx_tcpm_reset_bist_type_2, - .set_bist_test_mode = &stm32gx_tcpm_set_bist_test_mode, -}; diff --git a/driver/tcpm/stm32gx.h b/driver/tcpm/stm32gx.h deleted file mode 100644 index de6a803d52..0000000000 --- a/driver/tcpm/stm32gx.h +++ /dev/null @@ -1,14 +0,0 @@ -/* Copyright 2020 The Chromium OS Authors. All rights reserved. - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ - -/* USB Power delivery port management */ -#ifndef __CROS_EC_DRIVER_TCPM_STM32GX_H -#define __CROS_EC_DRIVER_TCPM_STM32GX_H - - -extern const struct tcpm_drv stm32gx_tcpm_drv; - - -#endif /* __CROS_EC_DRIVER_TCPM_STM32GX_H */ diff --git a/driver/tcpm/stub.c b/driver/tcpm/stub.c deleted file mode 100644 index 863a88c044..0000000000 --- a/driver/tcpm/stub.c +++ /dev/null @@ -1,159 +0,0 @@ -/* Copyright 2015 The Chromium OS Authors. All rights reserved. - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ - -/* TCPM for MCU also running TCPC */ - -#include "task.h" -#include "tcpm/tcpci.h" -#include "tcpm/tcpm.h" -#include "usb_pd.h" -#include "usb_pd_tcpc.h" -#include "usb_pd_tcpm.h" - -static int init_alert_mask(int port) -{ - uint16_t mask; - int rv; - - /* - * Create mask of alert events that will cause the TCPC to - * signal the TCPM via the Alert# gpio line. - */ - 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; - /* Set the alert mask in TCPC */ - rv = tcpc_alert_mask_set(port, mask); - - return rv; -} - -static int init_power_status_mask(int port) -{ - return tcpc_set_power_status_mask(port, 0); -} - -int tcpm_init(int port) -{ - int rv; - - tcpc_init(port); - rv = init_alert_mask(port); - if (rv) - return rv; - - return init_power_status_mask(port); -} - -int tcpm_get_cc(int port, enum tcpc_cc_voltage_status *cc1, - enum tcpc_cc_voltage_status *cc2) -{ - return tcpc_get_cc(port, cc1, cc2); -} - -int tcpm_select_rp_value(int port, int rp) -{ - return tcpc_select_rp_value(port, rp); -} - -int tcpm_set_cc(int port, int pull) -{ - return tcpc_set_cc(port, pull); -} - -int tcpm_set_polarity(int port, enum tcpc_cc_polarity polarity) -{ - return tcpc_set_polarity(port, polarity_rm_dts(polarity)); -} - -int tcpm_set_vconn(int port, int enable) -{ - return tcpc_set_vconn(port, enable); -} - -int tcpm_set_msg_header(int port, int power_role, int data_role) -{ - return tcpc_set_msg_header(port, power_role, data_role); -} - -static int tcpm_alert_status(int port, int *alert) -{ - /* Read TCPC Alert register */ - return tcpc_alert_status(port, alert); -} - -int tcpm_set_rx_enable(int port, int enable) -{ - return tcpc_set_rx_enable(port, enable); -} - -void tcpm_enable_auto_discharge_disconnect(int port, int enable) -{ -} - -int tcpm_has_pending_message(int port) -{ - return !rx_buf_is_empty(port); -} - -int tcpm_dequeue_message(int port, uint32_t *payload, int *head) -{ - int ret = tcpc_get_message(port, payload, head); - - /* Read complete, clear RX status alert bit */ - tcpc_alert_status_clear(port, TCPC_REG_ALERT_RX_STATUS); - - return ret; -} - -void tcpm_clear_pending_messages(int port) -{ - rx_buf_clear(port); -} - -int tcpm_transmit(int port, enum tcpci_msg_type type, uint16_t header, - const uint32_t *data) -{ - return tcpc_transmit(port, type, header, data); -} - -void tcpc_alert(int port) -{ - int status; - - /* Read the Alert register from the TCPC */ - tcpm_alert_status(port, &status); - - /* - * Clear alert status for everything except RX_STATUS, which shouldn't - * be cleared until we have successfully retrieved message. - */ - if (status & ~TCPC_REG_ALERT_RX_STATUS) - tcpc_alert_status_clear(port, - status & ~TCPC_REG_ALERT_RX_STATUS); - - if (status & TCPC_REG_ALERT_CC_STATUS) { - /* CC status changed, wake task */ - task_set_event(PD_PORT_TO_TASK_ID(port), PD_EVENT_CC); - } - if (status & TCPC_REG_ALERT_RX_STATUS) { - /* - * message received. since TCPC is compiled in, we - * already woke the PD task up from the phy layer via - * pd_rx_event(), so we don't need to wake it again. - */ - } - if (status & TCPC_REG_ALERT_RX_HARD_RST) { - /* hard reset received */ - task_set_event(PD_PORT_TO_TASK_ID(port), - PD_EVENT_RX_HARD_RESET); - } - if (status & TCPC_REG_ALERT_TX_COMPLETE) { - /* transmit complete */ - pd_transmit_complete(port, status & TCPC_REG_ALERT_TX_SUCCESS ? - TCPC_TX_COMPLETE_SUCCESS : - TCPC_TX_COMPLETE_FAILED); - } -} diff --git a/driver/tcpm/tcpci.c b/driver/tcpm/tcpci.c deleted file mode 100644 index 1e08e0967d..0000000000 --- a/driver/tcpm/tcpci.c +++ /dev/null @@ -1,1838 +0,0 @@ -/* Copyright 2015 The Chromium OS Authors. All rights reserved. - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ - -/* Type-C port manager */ - -#include "atomic.h" -#include "anx74xx.h" -#include "compile_time_macros.h" -#include "console.h" -#include "ec_commands.h" -#include "hooks.h" -#include "i2c.h" -#include "ps8xxx.h" -#include "task.h" -#include "tcpm/tcpci.h" -#include "tcpm/tcpm.h" -#include "timer.h" -#include "usb_charge.h" -#include "usb_common.h" -#include "usb_mux.h" -#include "usb_pd.h" -#include "usb_pd_flags.h" -#include "usb_pd_tcpc.h" -#include "usb_pd_tcpm.h" -#include "util.h" - -#define CPRINTF(format, args...) cprintf(CC_USBPD, format, ## args) -#define CPRINTS(format, args...) cprints(CC_USBPD, format, ## args) - -STATIC_IF(CONFIG_USB_PD_DECODE_SOP) - bool sop_prime_en[CONFIG_USB_PD_PORT_MAX_COUNT]; -STATIC_IF(CONFIG_USB_PD_DECODE_SOP) - int rx_en[CONFIG_USB_PD_PORT_MAX_COUNT]; - -#define TCPC_FLAGS_VSAFE0V(_flags) \ - ((_flags & TCPC_FLAGS_TCPCI_REV2_0) && \ - !(_flags & TCPC_FLAGS_TCPCI_REV2_0_NO_VSAFE0V)) - -/**************************************************************************** - * TCPCI DEBUG Helpers - */ - -/* TCPCI FAULT-0x01 is an invalid I2C operation was performed. This tends - * to have to do with the state of registers and the last write operation. - * Defining DEBUG_I2C_FAULT_LAST_WRITE_OP will track the write operations, - * excluding XFER and BlockWrites, in an attempt to give clues as to what - * was written to the TCPCI that caused the issue. - */ -#undef DEBUG_I2C_FAULT_LAST_WRITE_OP - -struct i2c_wrt_op { - int addr; - int reg; - int val; - int mask; -}; -STATIC_IF(DEBUG_I2C_FAULT_LAST_WRITE_OP) - struct i2c_wrt_op last_write_op[CONFIG_USB_PD_PORT_MAX_COUNT]; - -/* - * AutoDischargeDisconnect has caused a number of issues with the - * feature not being correctly enabled/disabled. Defining - * DEBUG_AUTO_DISCHARGE_DISCONNECT will output a line for each enable - * and disable to help better understand any AutoDischargeDisconnect - * issues. - */ -#undef DEBUG_AUTO_DISCHARGE_DISCONNECT - -/* - * ForcedDischarge debug to help coordinate with AutoDischarge. - * Defining DEBUG_FORCED_DISCHARGE will output a line for each enable - * and disable to help better understand any Discharge issues. - */ -#undef DEBUG_FORCED_DISCHARGE - -/* - * Seeing the CC Status and ROLE Control registers as well as the - * CC that is being determined from this information can be - * helpful. Defining DEBUG_GET_CC will output a line that gives - * this useful information - */ -#undef DEBUG_GET_CC - -struct get_cc_values { - int cc1; - int cc2; - int cc_sts; - int role; -}; -STATIC_IF(DEBUG_GET_CC) - struct get_cc_values last_get_cc[CONFIG_USB_PD_PORT_MAX_COUNT]; - -/* - * Seeing RoleCtrl updates can help determine why GetCC is not - * working as it should be. - */ -#undef DEBUG_ROLE_CTRL_UPDATES - -/****************************************************************************/ - -/* - * Last reported VBus Level - * - * BIT(VBUS_SAFE0V) will indicate if in SAFE0V - * BIT(VBUS_PRESENT) will indicate if in PRESENT in the TCPCI POWER_STATUS - * - * Note that VBUS_REMOVED cannot be distinguished from !VBUS_PRESENT with - * this interface, but the trigger thresholds for Vbus Present should allow the - * same bit to be used safely for both. - * - * TODO(b/149530538): Some TCPCs may be able to implement - * VBUS_SINK_DISCONNECT_THRESHOLD to support vSinkDisconnectPD - */ -static int tcpc_vbus[CONFIG_USB_PD_PORT_MAX_COUNT]; - -/* Cached RP role values */ -static int cached_rp[CONFIG_USB_PD_PORT_MAX_COUNT]; - -/* Cache our Device Capabilities at init for later reference */ -static int dev_cap_1[CONFIG_USB_PD_PORT_MAX_COUNT]; - -#ifdef CONFIG_USB_PD_TCPC_LOW_POWER -int tcpc_addr_write(int port, int i2c_addr, int reg, int val) -{ - int rv; - - pd_wait_exit_low_power(port); - - if (IS_ENABLED(DEBUG_I2C_FAULT_LAST_WRITE_OP)) { - last_write_op[port].addr = i2c_addr; - last_write_op[port].reg = reg; - last_write_op[port].val = val & 0xFF; - last_write_op[port].mask = 0; - } - - rv = i2c_write8(tcpc_config[port].i2c_info.port, - i2c_addr, reg, val); - - pd_device_accessed(port); - return rv; -} - -int tcpc_addr_write16(int port, int i2c_addr, int reg, int val) -{ - int rv; - - pd_wait_exit_low_power(port); - - if (IS_ENABLED(DEBUG_I2C_FAULT_LAST_WRITE_OP)) { - last_write_op[port].addr = i2c_addr; - last_write_op[port].reg = reg; - last_write_op[port].val = val & 0xFFFF; - last_write_op[port].mask = 0; - } - - rv = i2c_write16(tcpc_config[port].i2c_info.port, - i2c_addr, reg, val); - - pd_device_accessed(port); - return rv; -} - -int tcpc_addr_read(int port, int i2c_addr, int reg, int *val) -{ - int rv; - - pd_wait_exit_low_power(port); - - rv = i2c_read8(tcpc_config[port].i2c_info.port, - i2c_addr, reg, val); - - pd_device_accessed(port); - return rv; -} - -int tcpc_addr_read16(int port, int i2c_addr, int reg, int *val) -{ - pd_wait_exit_low_power(port); - - return tcpc_addr_read16_no_lpm_exit(port, i2c_addr, reg, val); -} - -int tcpc_addr_read16_no_lpm_exit(int port, int i2c_addr, int reg, int *val) -{ - int rv; - - rv = i2c_read16(tcpc_config[port].i2c_info.port, - i2c_addr, reg, val); - - pd_device_accessed(port); - return rv; -} - -int tcpc_read_block(int port, int reg, uint8_t *in, int size) -{ - int rv; - - pd_wait_exit_low_power(port); - - rv = i2c_read_block(tcpc_config[port].i2c_info.port, - tcpc_config[port].i2c_info.addr_flags, - reg, in, size); - - pd_device_accessed(port); - return rv; -} - -int tcpc_write_block(int port, int reg, const uint8_t *out, int size) -{ - int rv; - - pd_wait_exit_low_power(port); - - rv = i2c_write_block(tcpc_config[port].i2c_info.port, - tcpc_config[port].i2c_info.addr_flags, - reg, out, size); - - pd_device_accessed(port); - return rv; -} - -int tcpc_xfer(int port, const uint8_t *out, int out_size, - uint8_t *in, int in_size) -{ - int rv; - /* Dispatching to tcpc_xfer_unlocked reduces code size growth. */ - tcpc_lock(port, 1); - rv = tcpc_xfer_unlocked(port, out, out_size, in, in_size, - I2C_XFER_SINGLE); - tcpc_lock(port, 0); - return rv; -} - -int tcpc_xfer_unlocked(int port, const uint8_t *out, int out_size, - uint8_t *in, int in_size, int flags) -{ - int rv; - - pd_wait_exit_low_power(port); - - rv = i2c_xfer_unlocked(tcpc_config[port].i2c_info.port, - tcpc_config[port].i2c_info.addr_flags, - out, out_size, in, in_size, flags); - - pd_device_accessed(port); - return rv; -} - -int tcpc_update8(int port, int reg, - uint8_t mask, - enum mask_update_action action) -{ - int rv; - const int i2c_addr = tcpc_config[port].i2c_info.addr_flags; - - pd_wait_exit_low_power(port); - - if (IS_ENABLED(DEBUG_I2C_FAULT_LAST_WRITE_OP)) { - last_write_op[port].addr = i2c_addr; - last_write_op[port].reg = reg; - last_write_op[port].val = 0; - last_write_op[port].mask = (mask & 0xFF) | (action << 16); - } - - rv = i2c_update8(tcpc_config[port].i2c_info.port, - i2c_addr, reg, mask, action); - - pd_device_accessed(port); - return rv; -} - -int tcpc_update16(int port, int reg, - uint16_t mask, - enum mask_update_action action) -{ - int rv; - const int i2c_addr = tcpc_config[port].i2c_info.addr_flags; - - pd_wait_exit_low_power(port); - - if (IS_ENABLED(DEBUG_I2C_FAULT_LAST_WRITE_OP)) { - last_write_op[port].addr = i2c_addr; - last_write_op[port].reg = reg; - last_write_op[port].val = 0; - last_write_op[port].mask = (mask & 0xFFFF) | (action << 16); - } - - rv = i2c_update16(tcpc_config[port].i2c_info.port, - i2c_addr, reg, mask, action); - - pd_device_accessed(port); - return rv; -} - -#endif /* CONFIG_USB_PD_TCPC_LOW_POWER */ - -/* - * TCPCI maintains and uses cached values for the RP and - * last used PULL values. Since TCPC drivers are allowed - * to use some of the TCPCI functionality, these global - * cached values need to be maintained in case part of the - * used TCPCI functionality relies on these values - */ -void tcpci_set_cached_rp(int port, int rp) -{ - cached_rp[port] = rp; -} - -int tcpci_get_cached_rp(int port) -{ - return cached_rp[port]; -} - -static int init_alert_mask(int port) -{ - int rv; - uint16_t mask; - - /* - * Create mask of alert events that will cause the TCPC to - * signal the TCPM via the Alert# gpio line. - */ - if (get_usb_pd_vbus_detect() == USB_PD_VBUS_DETECT_TCPC) { - 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_FAULT - | TCPC_REG_ALERT_POWER_STATUS - ; - } else { - 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_FAULT - ; - } - - /* TCPCI Rev2 includes SAFE0V alerts */ - if (TCPC_FLAGS_VSAFE0V(tcpc_config[port].flags)) - mask |= TCPC_REG_ALERT_EXT_STATUS; - - if (IS_ENABLED(CONFIG_USB_PD_FRS_TCPC)) - mask |= TCPC_REG_ALERT_ALERT_EXT; - - /* Set the alert mask in TCPC */ - rv = tcpc_write16(port, TCPC_REG_ALERT_MASK, mask); - - if (IS_ENABLED(CONFIG_USB_PD_FRS_TCPC)) { - if (rv) - return rv; - - /* Sink FRS allowed */ - mask = TCPC_REG_ALERT_EXT_SNK_FRS; - rv = tcpc_write(port, TCPC_REG_ALERT_EXTENDED_MASK, mask); - } - return rv; -} - -static int clear_alert_mask(int port) -{ - return tcpc_write16(port, TCPC_REG_ALERT_MASK, 0); -} - -static int init_power_status_mask(int port) -{ - uint8_t mask; - int rv; - - if (get_usb_pd_vbus_detect() == USB_PD_VBUS_DETECT_TCPC) - mask = TCPC_REG_POWER_STATUS_VBUS_PRES; - else - mask = 0; - - rv = tcpc_write(port, TCPC_REG_POWER_STATUS_MASK , mask); - - return rv; -} - -static int clear_power_status_mask(int port) -{ - return tcpc_write(port, TCPC_REG_POWER_STATUS_MASK, 0); -} - -static int tcpci_tcpm_get_power_status(int port, int *status) -{ - return tcpc_read(port, TCPC_REG_POWER_STATUS, status); -} - -int tcpci_tcpm_select_rp_value(int port, int rp) -{ - /* Keep track of current RP value */ - tcpci_set_cached_rp(port, rp); - - return EC_SUCCESS; -} - -void tcpci_tcpc_discharge_vbus(int port, int enable) -{ - if (IS_ENABLED(DEBUG_FORCED_DISCHARGE)) - CPRINTS("C%d: ForceDischarge %sABLED", - port, enable ? "EN" : "DIS"); - - tcpc_update8(port, - TCPC_REG_POWER_CTRL, - TCPC_REG_POWER_CTRL_FORCE_DISCHARGE, - (enable) ? MASK_SET : MASK_CLR); -} - -/* - * Auto Discharge Disconnect is supposed to be enabled when we - * are connected and disabled after we are disconnected and - * VBus is at SafeV0 - */ -void tcpci_tcpc_enable_auto_discharge_disconnect(int port, int enable) -{ - if (IS_ENABLED(DEBUG_AUTO_DISCHARGE_DISCONNECT)) - CPRINTS("C%d: AutoDischargeDisconnect %sABLED", - port, enable ? "EN" : "DIS"); - - tcpc_update8(port, - TCPC_REG_POWER_CTRL, - TCPC_REG_POWER_CTRL_AUTO_DISCHARGE_DISCONNECT, - (enable) ? MASK_SET : MASK_CLR); -} - -int tcpci_tcpc_debug_accessory(int port, bool enable) -{ - return tcpc_update8(port, TCPC_REG_CONFIG_STD_OUTPUT, - TCPC_REG_CONFIG_STD_OUTPUT_DBG_ACC_CONN_N, - enable ? MASK_CLR : MASK_SET); -} - -int tcpci_tcpm_get_cc(int port, enum tcpc_cc_voltage_status *cc1, - enum tcpc_cc_voltage_status *cc2) -{ - int role; - int status; - int cc1_present_rd, cc2_present_rd; - int rv; - - /* errors will return CC as open */ - *cc1 = TYPEC_CC_VOLT_OPEN; - *cc2 = TYPEC_CC_VOLT_OPEN; - - /* Get the ROLE CONTROL and CC STATUS values */ - rv = tcpc_read(port, TCPC_REG_ROLE_CTRL, &role); - if (rv) - return rv; - - rv = tcpc_read(port, TCPC_REG_CC_STATUS, &status); - if (rv) - return rv; - - /* Get the current CC values from the CC STATUS */ - *cc1 = TCPC_REG_CC_STATUS_CC1(status); - *cc2 = TCPC_REG_CC_STATUS_CC2(status); - - /* Determine if we are presenting Rd */ - cc1_present_rd = 0; - cc2_present_rd = 0; - if (role & TCPC_REG_ROLE_CTRL_DRP_MASK) { - /* - * We are doing DRP. We will use the CC STATUS - * ConnectResult to determine if we are presenting - * Rd or Rp. - */ - int term; - - term = TCPC_REG_CC_STATUS_TERM(status); - - if (*cc1 != TYPEC_CC_VOLT_OPEN) - cc1_present_rd = term; - if (*cc2 != TYPEC_CC_VOLT_OPEN) - cc2_present_rd = term; - } else { - /* - * We are not doing DRP. We will use the ROLE CONTROL - * CC values to determine if we are presenting Rd or Rp. - */ - int role_cc1, role_cc2; - - role_cc1 = TCPC_REG_ROLE_CTRL_CC1(role); - role_cc2 = TCPC_REG_ROLE_CTRL_CC2(role); - - if (*cc1 != TYPEC_CC_VOLT_OPEN) - cc1_present_rd = !!(role_cc1 == TYPEC_CC_RD); - if (*cc2 != TYPEC_CC_VOLT_OPEN) - cc2_present_rd = !!(role_cc2 == TYPEC_CC_RD); - } - *cc1 |= cc1_present_rd << 2; - *cc2 |= cc2_present_rd << 2; - - if (IS_ENABLED(DEBUG_GET_CC) && - (last_get_cc[port].cc1 != *cc1 || - last_get_cc[port].cc2 != *cc2 || - last_get_cc[port].cc_sts != status || - last_get_cc[port].role != role)) { - - CPRINTS("C%d: GET_CC cc1=%d cc2=%d cc_sts=0x%X role=0x%X", - port, *cc1, *cc2, status, role); - - last_get_cc[port].cc1 = *cc1; - last_get_cc[port].cc2 = *cc2; - last_get_cc[port].cc_sts = status; - last_get_cc[port].role = role; - } - return rv; -} - -int tcpci_tcpm_set_cc(int port, int pull) -{ - int role = TCPC_REG_ROLE_CTRL_SET(TYPEC_NO_DRP, - tcpci_get_cached_rp(port), - pull, pull); - - if (IS_ENABLED(DEBUG_ROLE_CTRL_UPDATES)) - CPRINTS("C%d: SET_CC pull=%d role=0x%X", port, pull, role); - - return tcpc_write(port, TCPC_REG_ROLE_CTRL, role); -} - -#ifdef CONFIG_USB_PD_DUAL_ROLE_AUTO_TOGGLE -int tcpci_set_role_ctrl(int port, enum tcpc_drp drp, enum tcpc_rp_value rp, - enum tcpc_cc_pull pull) -{ - int role = TCPC_REG_ROLE_CTRL_SET(drp, rp, pull, pull); - - if (IS_ENABLED(DEBUG_ROLE_CTRL_UPDATES)) - CPRINTS("C%d: SET_ROLE_CTRL drp=%d rp=%d pull=%d role=0x%X", - port, drp, rp, pull, role); - - return tcpc_write(port, TCPC_REG_ROLE_CTRL, role); -} - -int tcpci_tcpc_drp_toggle(int port) -{ - int rv; - enum tcpc_cc_pull pull; - - /* - * Set auto drp toggle - * - * Set RC.DRP=1b (DRP) - * Set RC.RpValue=00b (smallest Rp to save power) - * Set RC.CC1=(Rp) or (Rd) - * Set RC.CC2=(Rp) or (Rd) - * - * TCPCI r1 wants both lines to be set to Rd - * TCPCI r2 wants both lines to be set to Rp - * - * Set the Rp Value to be the minimal to save power - */ - pull = (tcpc_config[port].flags & TCPC_FLAGS_TCPCI_REV2_0) - ? TYPEC_CC_RP : TYPEC_CC_RD; - - rv = tcpci_set_role_ctrl(port, TYPEC_DRP, TYPEC_RP_USB, pull); - if (rv) - return rv; - - /* Set up to catch LOOK4CONNECTION alerts */ - rv = tcpc_update8(port, - TCPC_REG_TCPC_CTRL, - TCPC_REG_TCPC_CTRL_EN_LOOK4CONNECTION_ALERT, - MASK_SET); - if (rv) - return rv; - - /* Set Look4Connection command */ - rv = tcpc_write(port, TCPC_REG_COMMAND, - TCPC_REG_COMMAND_LOOK4CONNECTION); - - return rv; -} -#endif - -#ifdef CONFIG_USB_PD_TCPC_LOW_POWER -int tcpci_enter_low_power_mode(int port) -{ - return tcpc_write(port, TCPC_REG_COMMAND, TCPC_REG_COMMAND_I2CIDLE); -} -#endif - -int tcpci_tcpm_set_polarity(int port, enum tcpc_cc_polarity polarity) -{ - return tcpc_update8(port, - TCPC_REG_TCPC_CTRL, - TCPC_REG_TCPC_CTRL_SET(1), - polarity_rm_dts(polarity) - ? MASK_SET : MASK_CLR); -} - -#ifdef CONFIG_USB_PD_PPC -bool tcpci_tcpm_get_snk_ctrl(int port) -{ - int rv; - int pwr_sts; - - rv = tcpci_tcpm_get_power_status(port, &pwr_sts); - - return rv == EC_SUCCESS && - pwr_sts & TCPC_REG_POWER_STATUS_SINKING_VBUS; -} - -int tcpci_tcpm_set_snk_ctrl(int port, int enable) -{ - int cmd = enable ? TCPC_REG_COMMAND_SNK_CTRL_HIGH : - TCPC_REG_COMMAND_SNK_CTRL_LOW; - - return tcpc_write(port, TCPC_REG_COMMAND, cmd); -} - -bool tcpci_tcpm_get_src_ctrl(int port) -{ - int rv; - int pwr_sts; - - rv = tcpci_tcpm_get_power_status(port, &pwr_sts); - - return rv == EC_SUCCESS && - pwr_sts & TCPC_REG_POWER_STATUS_SOURCING_VBUS; -} - -int tcpci_tcpm_set_src_ctrl(int port, int enable) -{ - int cmd = enable ? TCPC_REG_COMMAND_SRC_CTRL_HIGH : - TCPC_REG_COMMAND_SRC_CTRL_LOW; - - return tcpc_write(port, TCPC_REG_COMMAND, cmd); -} -#endif - -__maybe_unused int tcpci_tcpm_sop_prime_enable(int port, bool enable) -{ - /* save SOP'/SOP'' enable state */ - sop_prime_en[port] = enable; - - if (rx_en[port]) { - int detect_sop_en = TCPC_REG_RX_DETECT_SOP_HRST_MASK; - - if (enable) { - detect_sop_en = - TCPC_REG_RX_DETECT_SOP_SOPP_SOPPP_HRST_MASK; - } - - return tcpc_write(port, TCPC_REG_RX_DETECT, detect_sop_en); - } - - return EC_SUCCESS; -} - -int tcpci_tcpm_set_vconn(int port, int enable) -{ - int reg, rv; - - rv = tcpc_read(port, TCPC_REG_POWER_CTRL, ®); - if (rv) - return rv; - - reg &= ~TCPC_REG_POWER_CTRL_VCONN(1); - reg |= TCPC_REG_POWER_CTRL_VCONN(enable); - - /* - * Add delay of writing TCPC_REG_POWER_CTRL makes - * CC status being judged correctly when disable VCONN. - * This may be a PS8XXX firmware issue, Parade is still trying. - * https://partnerissuetracker.corp.google.com/issues/185202064 - */ - if (!enable) - msleep(PS8XXX_VCONN_TURN_OFF_DELAY_US); - - return tcpc_write(port, TCPC_REG_POWER_CTRL, reg); -} - -int tcpci_tcpm_set_msg_header(int port, int power_role, int data_role) -{ - return tcpc_write(port, TCPC_REG_MSG_HDR_INFO, - TCPC_REG_MSG_HDR_INFO_SET(data_role, power_role)); -} - -static int tcpm_alert_status(int port, int *alert) -{ - /* Read TCPC Alert register */ - return tcpc_read16(port, TCPC_REG_ALERT, alert); -} - -static int tcpm_alert_ext_status(int port, int *alert_ext) -{ - /* Read TCPC Extended Alert register */ - return tcpc_read(port, TCPC_REG_ALERT_EXT, alert_ext); -} - -static int tcpm_ext_status(int port, int *ext_status) -{ - /* Read TCPC Extended Status register */ - return tcpc_read(port, TCPC_REG_EXT_STATUS, ext_status); -} - -int tcpci_tcpm_set_rx_enable(int port, int enable) -{ - int detect_sop_en = 0; - - if (IS_ENABLED(CONFIG_USB_PD_DECODE_SOP)) { - /* save rx_on */ - rx_en[port] = enable; - } - - - if (enable) { - detect_sop_en = TCPC_REG_RX_DETECT_SOP_HRST_MASK; - - if (IS_ENABLED(CONFIG_USB_PD_DECODE_SOP) && - sop_prime_en[port]) { - /* - * Only the VCONN Source is allowed to communicate - * with the Cable Plugs. - */ - detect_sop_en = - TCPC_REG_RX_DETECT_SOP_SOPP_SOPPP_HRST_MASK; - } - } - - /* If enable, then set RX detect for SOP and HRST */ - return tcpc_write(port, TCPC_REG_RX_DETECT, detect_sop_en); -} - -#ifdef CONFIG_USB_PD_FRS_TCPC -int tcpci_tcpc_fast_role_swap_enable(int port, int enable) -{ - return tcpc_update8(port, - TCPC_REG_POWER_CTRL, - TCPC_REG_POWER_CTRL_FRS_ENABLE, - (enable) ? MASK_SET : MASK_CLR); -} -#endif - -#ifdef CONFIG_USB_PD_VBUS_DETECT_TCPC -bool tcpci_tcpm_check_vbus_level(int port, enum vbus_level level) -{ - if (level == VBUS_SAFE0V) - return !!(tcpc_vbus[port] & BIT(VBUS_SAFE0V)); - else if (level == VBUS_PRESENT) - return !!(tcpc_vbus[port] & BIT(VBUS_PRESENT)); - else - return !(tcpc_vbus[port] & BIT(VBUS_PRESENT)); -} -#endif - -struct cached_tcpm_message { - uint32_t header; - uint32_t payload[7]; -}; - -static int tcpci_rev2_0_tcpm_get_message_raw(int port, uint32_t *payload, - int *head) -{ - int rv = 0, cnt, reg = TCPC_REG_RX_BUFFER; - int frm; - uint8_t tmp[2]; - /* - * Register 0x30 is Readable Byte Count, Buffer frame type, and RX buf - * byte X. - */ - tcpc_lock(port, 1); - rv = tcpc_xfer_unlocked(port, (uint8_t *)®, 1, tmp, 2, - I2C_XFER_START); - if (rv) { - rv = EC_ERROR_UNKNOWN; - goto clear; - } - cnt = tmp[0]; - frm = tmp[1]; - - /* - * READABLE_BYTE_COUNT includes 3 bytes for frame type and header, and - * may be 0 if the TCPC saw a disconnect before the message read - */ - cnt -= 3; - if ((cnt < 0) || - (cnt > member_size(struct cached_tcpm_message, payload))) { - /* Continue to send the stop bit with the header read */ - rv = EC_ERROR_UNKNOWN; - cnt = 0; - } - - /* The next two bytes are the header */ - rv |= tcpc_xfer_unlocked(port, NULL, 0, (uint8_t *)head, 2, - cnt ? 0 : I2C_XFER_STOP); - - /* Encode message address in bits 31 to 28 */ - *head &= 0x0000ffff; - *head |= PD_HEADER_SOP(frm); - - /* Execute read and I2C_XFER_STOP, even if header read failed */ - if (cnt > 0) { - tcpc_xfer_unlocked(port, NULL, 0, (uint8_t *)payload, cnt, - I2C_XFER_STOP); - } - -clear: - tcpc_lock(port, 0); - /* Read complete, clear RX status alert bit */ - tcpc_write16(port, TCPC_REG_ALERT, TCPC_REG_ALERT_RX_STATUS); - - if (rv) - return EC_ERROR_UNKNOWN; - - return EC_SUCCESS; -} - -static int tcpci_rev1_0_tcpm_get_message_raw(int port, uint32_t *payload, - int *head) -{ - int rv, cnt, reg = TCPC_REG_RX_DATA; - int frm; - - rv = tcpc_read(port, TCPC_REG_RX_BYTE_CNT, &cnt); - - /* RX_BYTE_CNT includes 3 bytes for frame type and header */ - if (rv != EC_SUCCESS || cnt < 3) { - rv = EC_ERROR_UNKNOWN; - goto clear; - } - cnt -= 3; - if (cnt > member_size(struct cached_tcpm_message, payload)) { - rv = EC_ERROR_UNKNOWN; - goto clear; - } - - if (IS_ENABLED(CONFIG_USB_PD_DECODE_SOP)) { - rv = tcpc_read(port, TCPC_REG_RX_BUF_FRAME_TYPE, &frm); - if (rv != EC_SUCCESS) { - rv = EC_ERROR_UNKNOWN; - goto clear; - } - } - - rv = tcpc_read16(port, TCPC_REG_RX_HDR, (int *)head); - - if (IS_ENABLED(CONFIG_USB_PD_DECODE_SOP)) { - /* Encode message address in bits 31 to 28 */ - *head &= 0x0000ffff; - *head |= PD_HEADER_SOP(frm); - } - - if (rv == EC_SUCCESS && cnt > 0) { - tcpc_read_block(port, reg, (uint8_t *)payload, cnt); - } - -clear: - /* Read complete, clear RX status alert bit */ - tcpc_write16(port, TCPC_REG_ALERT, TCPC_REG_ALERT_RX_STATUS); - - return rv; -} - -int tcpci_tcpm_get_message_raw(int port, uint32_t *payload, int *head) -{ - if (tcpc_config[port].flags & TCPC_FLAGS_TCPCI_REV2_0) - return tcpci_rev2_0_tcpm_get_message_raw(port, payload, head); - - return tcpci_rev1_0_tcpm_get_message_raw(port, payload, head); -} - -/* Cache depth needs to be power of 2 */ -/* TODO: Keep track of the high water mark */ -#define CACHE_DEPTH BIT(3) -#define CACHE_DEPTH_MASK (CACHE_DEPTH - 1) - -struct queue { - /* - * Head points to the index of the first empty slot to put a new RX - * message. Must be masked before used in lookup. - */ - uint32_t head; - /* - * Tail points to the index of the first message for the PD task to - * consume. Must be masked before used in lookup. - */ - uint32_t tail; - struct cached_tcpm_message buffer[CACHE_DEPTH]; -}; -static struct queue cached_messages[CONFIG_USB_PD_PORT_MAX_COUNT]; - -/* Note this method can be called from an interrupt context. */ -int tcpm_enqueue_message(const int port) -{ - int rv; - struct queue *const q = &cached_messages[port]; - struct cached_tcpm_message *const head = - &q->buffer[q->head & CACHE_DEPTH_MASK]; - - if (q->head - q->tail == CACHE_DEPTH) { - CPRINTS("C%d RX EC Buffer full!", port); - return EC_ERROR_OVERFLOW; - } - - /* Blank any old message, just in case. */ - memset(head, 0, sizeof(*head)); - /* Call the raw driver without caching */ - rv = tcpc_config[port].drv->get_message_raw(port, head->payload, - &head->header); - if (rv) { - CPRINTS("C%d: Could not retrieve RX message (%d)", port, rv); - return rv; - } - - /* Increment atomically to ensure get_message_raw happens-before */ - atomic_add(&q->head, 1); - - /* Wake PD task up so it can process incoming RX messages */ - task_set_event(PD_PORT_TO_TASK_ID(port), TASK_EVENT_WAKE); - - return EC_SUCCESS; -} - -int tcpm_has_pending_message(const int port) -{ - const struct queue *const q = &cached_messages[port]; - - return q->head != q->tail; -} - -int tcpm_dequeue_message(const int port, uint32_t *const payload, - int *const header) -{ - struct queue *const q = &cached_messages[port]; - struct cached_tcpm_message *const tail = - &q->buffer[q->tail & CACHE_DEPTH_MASK]; - - if (!tcpm_has_pending_message(port)) { - CPRINTS("C%d No message in RX buffer!", port); - return EC_ERROR_BUSY; - } - - /* Copy cache data in to parameters */ - *header = tail->header; - memcpy(payload, tail->payload, sizeof(tail->payload)); - - /* Increment atomically to ensure memcpy happens-before */ - atomic_add(&q->tail, 1); - - return EC_SUCCESS; -} - -void tcpm_clear_pending_messages(int port) -{ - struct queue *const q = &cached_messages[port]; - - q->tail = q->head; -} - -int tcpci_tcpm_transmit(int port, enum tcpci_msg_type type, - uint16_t header, const uint32_t *data) -{ - int reg = TCPC_REG_TX_DATA; - int rv, cnt = 4*PD_HEADER_CNT(header); - - /* If not SOP* transmission, just write to the transmit register */ - if (type >= NUM_SOP_STAR_TYPES) { - /* - * Per TCPCI spec, do not specify retry (although the TCPC - * should ignore retry field for these 3 types). - */ - return tcpc_write(port, TCPC_REG_TRANSMIT, - TCPC_REG_TRANSMIT_SET_WITHOUT_RETRY(type)); - } - - if (tcpc_config[port].flags & TCPC_FLAGS_TCPCI_REV2_0) { - /* - * In TCPCI Rev 2.0, TX_BYTE_CNT and TX_BUF_BYTE_X are the same - * register. - */ - reg = TCPC_REG_TX_BUFFER; - /* TX_BYTE_CNT includes extra bytes for message header */ - cnt += sizeof(header); - tcpc_lock(port, 1); - rv = tcpc_xfer_unlocked(port, (uint8_t *)®, 1, NULL, 0, - I2C_XFER_START); - rv |= tcpc_xfer_unlocked(port, (uint8_t *)&cnt, 1, NULL, 0, 0); - if (cnt > sizeof(header)) { - rv |= tcpc_xfer_unlocked(port, (uint8_t *)&header, - sizeof(header), NULL, 0, 0); - rv |= tcpc_xfer_unlocked(port, (uint8_t *)data, - cnt-sizeof(header), NULL, 0, - I2C_XFER_STOP); - } else { - rv |= tcpc_xfer_unlocked(port, (uint8_t *)&header, - sizeof(header), NULL, 0, I2C_XFER_STOP); - } - tcpc_lock(port, 0); - - /* If tcpc write fails, return error */ - if (rv) - return rv; - } else { - /* TX_BYTE_CNT includes extra bytes for message header */ - rv = tcpc_write(port, TCPC_REG_TX_BYTE_CNT, - cnt + sizeof(header)); - - rv |= tcpc_write16(port, TCPC_REG_TX_HDR, header); - - /* If tcpc write fails, return error */ - if (rv) - return rv; - - if (cnt > 0) { - rv = tcpc_write_block(port, reg, (const uint8_t *)data, - cnt); - - /* If tcpc write fails, return error */ - if (rv) - return rv; - } - } - - /* - * We always retry in TCPC hardware since the TCPM is too slow to - * respond within tRetry (~195 usec). - * - * The retry count used is dependent on the maximum PD revision - * supported at build time. - */ - return tcpc_write(port, TCPC_REG_TRANSMIT, - TCPC_REG_TRANSMIT_SET_WITH_RETRY( - pd_get_retry_count(port, type), type)); -} - -/* - * Returns true if TCPC has reset based on reading mask registers. - */ -static int register_mask_reset(int port) -{ - int mask; - - mask = 0; - tcpc_read16(port, TCPC_REG_ALERT_MASK, &mask); - if (mask == TCPC_REG_ALERT_MASK_ALL) - return 1; - - mask = 0; - tcpc_read(port, TCPC_REG_POWER_STATUS_MASK, &mask); - if (mask == TCPC_REG_POWER_STATUS_MASK_ALL) - return 1; - - return 0; -} - -static int tcpci_get_fault(int port, int *fault) -{ - return tcpc_read(port, TCPC_REG_FAULT_STATUS, fault); -} - -static int tcpci_handle_fault(int port, int fault) -{ - int rv = EC_SUCCESS; - - CPRINTS("C%d FAULT 0x%02X detected", port, fault); - - if (IS_ENABLED(DEBUG_I2C_FAULT_LAST_WRITE_OP) && - fault & TCPC_REG_FAULT_STATUS_I2C_INTERFACE_ERR) { - if (last_write_op[port].mask == 0) - CPRINTS("C%d I2C WR 0x%02X 0x%02X value=0x%X", - port, - last_write_op[port].addr, - last_write_op[port].reg, - last_write_op[port].val); - else - CPRINTS("C%d I2C UP 0x%02X 0x%02X op=%d mask=0x%X", - port, - last_write_op[port].addr, - last_write_op[port].reg, - last_write_op[port].mask >> 16, - last_write_op[port].mask & 0xFFFF); - } - - /* Report overcurrent to the OCP module if enabled */ - if ((dev_cap_1[port] & TCPC_REG_DEV_CAP_1_VBUS_OCP_REPORTING) && - IS_ENABLED(CONFIG_USBC_OCP) && - (fault & TCPC_REG_FAULT_STATUS_VBUS_OVER_CURRENT)) - pd_handle_overcurrent(port); - - if (tcpc_config[port].drv->handle_fault) - rv = tcpc_config[port].drv->handle_fault(port, fault); - - return rv; -} - -enum ec_error_list tcpci_set_bist_test_mode(const int port, - const bool enable) -{ - int rv; - - rv = tcpc_update8(port, TCPC_REG_TCPC_CTRL, - TCPC_REG_TCPC_CTRL_BIST_TEST_MODE, - enable ? MASK_SET : MASK_CLR); - rv |= tcpc_update16(port, TCPC_REG_ALERT_MASK, - TCPC_REG_ALERT_RX_STATUS, enable ? MASK_CLR : MASK_SET); - return rv; -} - -static int tcpci_clear_fault(int port, int fault) -{ - int rv; - - rv = tcpc_write(port, TCPC_REG_FAULT_STATUS, fault); - if (rv) - return rv; - - return tcpc_write16(port, TCPC_REG_ALERT, TCPC_REG_ALERT_FAULT); -} - -static void tcpci_check_vbus_changed(int port, int alert, uint32_t *pd_event) -{ - /* - * Check for VBus change - */ - /* TCPCI Rev2 includes Safe0V detection */ - if (TCPC_FLAGS_VSAFE0V(tcpc_config[port].flags) && - (alert & TCPC_REG_ALERT_EXT_STATUS)) { - int ext_status = 0; - - /* Determine if Safe0V was detected */ - tcpm_ext_status(port, &ext_status); - if (ext_status & TCPC_REG_EXT_STATUS_SAFE0V) - /* Safe0V=1 and Present=0 */ - tcpc_vbus[port] = BIT(VBUS_SAFE0V); - } - - if (alert & TCPC_REG_ALERT_POWER_STATUS) { - int pwr_status = 0; - - /* Determine reason for power status change */ - tcpci_tcpm_get_power_status(port, &pwr_status); - if (pwr_status & TCPC_REG_POWER_STATUS_VBUS_PRES) - /* Safe0V=0 and Present=1 */ - tcpc_vbus[port] = BIT(VBUS_PRESENT); - else if (TCPC_FLAGS_VSAFE0V(tcpc_config[port].flags)) - /* TCPCI Rev2 detects Safe0V, so Present=0 */ - tcpc_vbus[port] &= ~BIT(VBUS_PRESENT); - else { - /* - * TCPCI Rev1 can not detect Safe0V, so treat this - * like a Safe0V detection. - * - * Safe0V=1 and Present=0 - */ - tcpc_vbus[port] = BIT(VBUS_SAFE0V); - } - - if ((get_usb_pd_vbus_detect() == USB_PD_VBUS_DETECT_TCPC) && - IS_ENABLED(CONFIG_USB_CHARGER)) { - /* Update charge manager with new VBUS state */ - usb_charger_vbus_change(port, - !!(tcpc_vbus[port] & BIT(VBUS_PRESENT))); - - if (pd_event) - *pd_event |= TASK_EVENT_WAKE; - } - } -} - -/* - * Don't let the TCPC try to pull from the RX buffer forever. We typical only - * have 1 or 2 messages waiting. - */ -#define MAX_ALLOW_FAILED_RX_READS 10 - -void tcpci_tcpc_alert(int port) -{ - int alert = 0; - int alert_ext = 0; - int failed_attempts; - uint32_t pd_event = 0; - int retval = 0; - - /* Read the Alert register from the TCPC */ - if (tcpm_alert_status(port, &alert)) { - CPRINTS("C%d: Failed to read alert register", port); - return; - } - - /* Get Extended Alert register if needed */ - if (alert & TCPC_REG_ALERT_ALERT_EXT) - tcpm_alert_ext_status(port, &alert_ext); - - /* Clear any pending faults */ - if (alert & TCPC_REG_ALERT_FAULT) { - int fault; - - if (tcpci_get_fault(port, &fault) == EC_SUCCESS && - fault != 0 && - tcpci_handle_fault(port, fault) == EC_SUCCESS && - tcpci_clear_fault(port, fault) == EC_SUCCESS) - CPRINTS("C%d FAULT 0x%02X handled", port, fault); - } - - /* - * Check for TX complete first b/c PD state machine waits on TX - * completion events. This will send an event to the PD tasks - * immediately - */ - if (alert & TCPC_REG_ALERT_TX_COMPLETE) - pd_transmit_complete(port, alert & TCPC_REG_ALERT_TX_SUCCESS ? - TCPC_TX_COMPLETE_SUCCESS : - TCPC_TX_COMPLETE_FAILED); - - /* Pull all RX messages from TCPC into EC memory */ - failed_attempts = 0; - while (alert & TCPC_REG_ALERT_RX_STATUS) { - retval = tcpm_enqueue_message(port); - if (retval) - ++failed_attempts; - if (tcpm_alert_status(port, &alert)) - ++failed_attempts; - - - /* - * EC RX FIFO is full. Deassert ALERT# line to exit interrupt - * handler by discarding pending message from TCPC RX FIFO. - */ - if (retval == EC_ERROR_OVERFLOW) { - CPRINTS("C%d: PD RX OVF!", port); - tcpc_write16(port, TCPC_REG_ALERT, - TCPC_REG_ALERT_RX_STATUS | - TCPC_REG_ALERT_RX_BUF_OVF); - } - - /* Ensure we don't loop endlessly */ - if (failed_attempts >= MAX_ALLOW_FAILED_RX_READS) { - CPRINTS("C%d Cannot consume RX buffer after %d failed attempts!", - port, failed_attempts); - /* - * The port is in a bad state, we don't want to consume - * all EC resources so suspend the port for a little - * while. - */ - pd_set_suspend(port, 1); - pd_deferred_resume(port); - return; - } - } - - /* - * Clear all pending alert bits. Ext first because ALERT.AlertExtended - * is set if any bit of ALERT_EXTENDED is set. - */ - if (alert_ext) - tcpc_write(port, TCPC_REG_ALERT_EXT, alert_ext); - if (alert) - tcpc_write16(port, TCPC_REG_ALERT, alert); - - if (alert & TCPC_REG_ALERT_CC_STATUS) { - if (IS_ENABLED(CONFIG_USB_PD_DUAL_ROLE_AUTO_TOGGLE)) { - enum tcpc_cc_voltage_status cc1; - enum tcpc_cc_voltage_status cc2; - - /* - * Some TCPCs generate CC Alerts when - * drp auto toggle is active and nothing - * is connected to the port. So, get the - * CC line status and only generate a - * PD_EVENT_CC if something is connected. - */ - tcpci_tcpm_get_cc(port, &cc1, &cc2); - if (cc1 != TYPEC_CC_VOLT_OPEN || - cc2 != TYPEC_CC_VOLT_OPEN) - /* CC status cchanged, wake task */ - pd_event |= PD_EVENT_CC; - } else { - /* CC status changed, wake task */ - pd_event |= PD_EVENT_CC; - } - } - - tcpci_check_vbus_changed(port, alert, &pd_event); - - /* Check for Hard Reset received */ - if (alert & TCPC_REG_ALERT_RX_HARD_RST) { - /* hard reset received */ - CPRINTS("C%d Hard Reset received", port); - pd_event |= PD_EVENT_RX_HARD_RESET; - } - - /* USB TCPCI Spec R2 V1.1 Section 4.7.3 Step 2 - * - * The TCPC asserts both ALERT.TransmitSOP*MessageSuccessful and - * ALERT.TransmitSOP*MessageFailed regardless of the outcome of the - * transmission and asserts the Alert# pin. - */ - if (alert & TCPC_REG_ALERT_TX_SUCCESS && - alert & TCPC_REG_ALERT_TX_FAILED) - CPRINTS("C%d Hard Reset sent", port); - - if (IS_ENABLED(CONFIG_USB_PD_FRS_TCPC) - && (alert_ext & TCPC_REG_ALERT_EXT_SNK_FRS)) - pd_got_frs_signal(port); - - /* - * Check registers to see if we can tell that the TCPC has reset. If - * so, perform a tcpc_init. - */ - if (register_mask_reset(port)) - pd_event |= PD_EVENT_TCPC_RESET; - - /* - * Wait until all possible TCPC accesses in this function are complete - * prior to setting events and/or waking the pd task. When the PD - * task is woken and runs (which will happen during I2C transactions in - * this function), the pd task may put the TCPC into low power mode and - * the next I2C transaction to the TCPC will cause it to wake again. - */ - if (pd_event) - task_set_event(PD_PORT_TO_TASK_ID(port), pd_event); -} - -/* - * This call will wake up the TCPC if it is in low power mode upon accessing the - * i2c bus (but the pd state machine should put it back into low power mode). - * - * Once it's called, the chip info will be stored in cache, which can be - * accessed by tcpm_get_chip_info without worrying about chip states. - */ -int tcpci_get_chip_info(int port, int live, - struct ec_response_pd_chip_info_v1 *chip_info) -{ - static struct ec_response_pd_chip_info_v1 - cached_info[CONFIG_USB_PD_PORT_MAX_COUNT]; - struct ec_response_pd_chip_info_v1 *i; - int error; - int val; - - if (port >= board_get_usb_pd_port_count()) - return EC_ERROR_INVAL; - - i = &cached_info[port]; - - - /* If already cached && live data is not asked, return cached value */ - if (i->vendor_id && !live) { - /* - * If chip_info is NULL, chip info will be stored in cache and - * can be read later by another call. - */ - if (chip_info) - memcpy(chip_info, i, sizeof(*i)); - - return EC_SUCCESS; - } - - error = tcpc_read16(port, TCPC_REG_VENDOR_ID, &val); - if (error) - return error; - i->vendor_id = val; - - error = tcpc_read16(port, TCPC_REG_PRODUCT_ID, &val); - if (error) - return error; - i->product_id = val; - - error = tcpc_read16(port, TCPC_REG_BCD_DEV, &val); - if (error) - return error; - i->device_id = val; - - /* - * This varies chip to chip; more specific driver code is expected to - * override this value if it can. - */ - i->fw_version_number = -1; - - /* Copy the cached value to return if chip_info is not NULL */ - if (chip_info) - memcpy(chip_info, i, sizeof(*i)); - - return EC_SUCCESS; -} - -/* - * Dissociate from the TCPC. - */ - -int tcpci_tcpm_release(int port) -{ - int error; - - error = clear_alert_mask(port); - if (error) - return error; - error = clear_power_status_mask(port); - if (error) - return error; - /* Clear pending interrupts */ - error = tcpc_write16(port, TCPC_REG_ALERT, 0xffff); - if (error) - return error; - - return EC_SUCCESS; -} - -/* - * On TCPC i2c failure, make 30 tries (at least 300ms) before giving up - * in order to allow the TCPC time to boot / reset. - */ -#define TCPM_INIT_TRIES 30 - -int tcpci_tcpm_init(int port) -{ - int error; - int power_status; - int tries = TCPM_INIT_TRIES; - - if (port >= board_get_usb_pd_port_count()) - return EC_ERROR_INVAL; - - while (1) { - error = tcpci_tcpm_get_power_status(port, &power_status); - /* - * If read succeeds and the uninitialized bit is clear, then - * initialization is complete, clear all alert bits and write - * the initial alert mask. - */ - if (!error && !(power_status & TCPC_REG_POWER_STATUS_UNINIT)) - break; - if (--tries <= 0) - return error ? error : EC_ERROR_TIMEOUT; - msleep(10); - } - - /* - * For TCPCI Rev 2.0, unless the TCPM sets - * TCPC_CONTROL.EnableLooking4ConnectionAlert bit, TCPC by default masks - * Alert assertion when CC_STATUS.Looking4Connection changes state. - */ - if (tcpc_config[port].flags & TCPC_FLAGS_TCPCI_REV2_0) { - error = tcpc_update8(port, TCPC_REG_TCPC_CTRL, - TCPC_REG_TCPC_CTRL_EN_LOOK4CONNECTION_ALERT, - MASK_SET); - if (error) - CPRINTS("C%d: Failed to init TCPC_CTRL!", port); - } - - /* - * Handle and clear any alerts, since we might be coming out of low - * power mode in response to an alert interrupt from the TCPC. - */ - tcpc_alert(port); - /* Initialize power_status_mask */ - init_power_status_mask(port); - - if (TCPC_FLAGS_VSAFE0V(tcpc_config[port].flags)) { - int ext_status = 0; - - /* Read Extended Status register */ - tcpm_ext_status(port, &ext_status); - /* Initial level, set appropriately */ - if (power_status & TCPC_REG_POWER_STATUS_VBUS_PRES) - tcpc_vbus[port] = BIT(VBUS_PRESENT); - else if (ext_status & TCPC_REG_EXT_STATUS_SAFE0V) - tcpc_vbus[port] = BIT(VBUS_SAFE0V); - else - tcpc_vbus[port] = 0; - } else { - /* Initial level, set appropriately */ - tcpc_vbus[port] = (power_status & - TCPC_REG_POWER_STATUS_VBUS_PRES) - ? BIT(VBUS_PRESENT) - : BIT(VBUS_SAFE0V); - } - - /* - * Force an update to the VBUS status in case the TCPC doesn't send a - * power status changed interrupt later. - */ - tcpci_check_vbus_changed(port, - TCPC_REG_ALERT_POWER_STATUS | TCPC_REG_ALERT_EXT_STATUS, - NULL); - - error = init_alert_mask(port); - if (error) - return error; - - /* Read chip info here when we know the chip is awake. */ - tcpm_get_chip_info(port, 1, NULL); - - /* Cache our device capabilities for future reference */ - tcpc_read16(port, TCPC_REG_DEV_CAP_1, &dev_cap_1[port]); - - return EC_SUCCESS; -} - -#ifdef CONFIG_USB_PD_TCPM_MUX - -/* - * When the TCPC/MUX device is only used for the MUX, we need to initialize it - * via mux init because tcpc_init won't run for the device. This is borrowed - * from tcpc_init. - */ -int tcpci_tcpm_mux_init(const struct usb_mux *me) -{ - int error; - int power_status; - int tries = TCPM_INIT_TRIES; - - /* If this MUX is also the TCPC, then skip init */ - if (!(me->flags & USB_MUX_FLAG_NOT_TCPC)) - return EC_SUCCESS; - - /* Wait for the device to exit low power state */ - while (1) { - error = mux_read(me, TCPC_REG_POWER_STATUS, &power_status); - /* - * If read succeeds and the uninitialized bit is clear, then - * initialization is complete. - */ - if (!error && !(power_status & TCPC_REG_POWER_STATUS_UNINIT)) - break; - if (--tries <= 0) - return error ? error : EC_ERROR_TIMEOUT; - msleep(10); - } - - /* Turn off all alerts and acknowledge any pending IRQ */ - error = mux_write16(me, TCPC_REG_ALERT_MASK, 0); - error |= mux_write16(me, TCPC_REG_ALERT, 0xffff); - - return error ? EC_ERROR_UNKNOWN : EC_SUCCESS; -} - -int tcpci_tcpm_mux_enter_low_power(const struct usb_mux *me) -{ - /* If this MUX is also the TCPC, then skip low power */ - if (!(me->flags & USB_MUX_FLAG_NOT_TCPC)) - return EC_SUCCESS; - - return mux_write(me, TCPC_REG_COMMAND, TCPC_REG_COMMAND_I2CIDLE); -} - -int tcpci_tcpm_mux_set(const struct usb_mux *me, mux_state_t mux_state, - bool *ack_required) -{ - int rv; - int reg = 0; - - /* This driver does not use host command ACKs */ - *ack_required = false; - - /* Parameter is port only */ - rv = mux_read(me, TCPC_REG_CONFIG_STD_OUTPUT, ®); - if (rv != EC_SUCCESS) - return rv; - - reg &= ~(TCPC_REG_CONFIG_STD_OUTPUT_MUX_MASK | - TCPC_REG_CONFIG_STD_OUTPUT_CONNECTOR_FLIPPED); - if (mux_state & USB_PD_MUX_USB_ENABLED) - reg |= TCPC_REG_CONFIG_STD_OUTPUT_MUX_USB; - if (mux_state & USB_PD_MUX_DP_ENABLED) - reg |= TCPC_REG_CONFIG_STD_OUTPUT_MUX_DP; - if (mux_state & USB_PD_MUX_POLARITY_INVERTED) - reg |= TCPC_REG_CONFIG_STD_OUTPUT_CONNECTOR_FLIPPED; - - /* Parameter is port only */ - return mux_write(me, TCPC_REG_CONFIG_STD_OUTPUT, reg); -} - -/* Reads control register and updates mux_state accordingly */ -int tcpci_tcpm_mux_get(const struct usb_mux *me, mux_state_t *mux_state) -{ - int rv; - int reg = 0; - - *mux_state = 0; - - /* Parameter is port only */ - rv = mux_read(me, TCPC_REG_CONFIG_STD_OUTPUT, ®); - if (rv != EC_SUCCESS) - return rv; - - if (reg & TCPC_REG_CONFIG_STD_OUTPUT_MUX_USB) - *mux_state |= USB_PD_MUX_USB_ENABLED; - if (reg & TCPC_REG_CONFIG_STD_OUTPUT_MUX_DP) - *mux_state |= USB_PD_MUX_DP_ENABLED; - if (reg & TCPC_REG_CONFIG_STD_OUTPUT_CONNECTOR_FLIPPED) - *mux_state |= USB_PD_MUX_POLARITY_INVERTED; - - return EC_SUCCESS; -} - -const struct usb_mux_driver tcpci_tcpm_usb_mux_driver = { - .init = &tcpci_tcpm_mux_init, - .set = &tcpci_tcpm_mux_set, - .get = &tcpci_tcpm_mux_get, - .enter_low_power_mode = &tcpci_tcpm_mux_enter_low_power, -}; - -#endif /* CONFIG_USB_PD_TCPM_MUX */ - -#ifdef CONFIG_CMD_TCPC_DUMP -static const struct tcpc_reg_dump_map tcpc_regs[] = { - { - .addr = TCPC_REG_VENDOR_ID, - .name = "VENDOR_ID", - .size = 2, - }, - { - .addr = TCPC_REG_PRODUCT_ID, - .name = "PRODUCT_ID", - .size = 2, - }, - { - .addr = TCPC_REG_BCD_DEV, - .name = "BCD_DEV", - .size = 2, - }, - { - .addr = TCPC_REG_TC_REV, - .name = "TC_REV", - .size = 2, - }, - { - .addr = TCPC_REG_PD_REV, - .name = "PD_REV", - .size = 2, - }, - { - .addr = TCPC_REG_PD_INT_REV, - .name = "PD_INT_REV", - .size = 2, - }, - { - .addr = TCPC_REG_ALERT, - .name = "ALERT", - .size = 2, - }, - { - .addr = TCPC_REG_ALERT_MASK, - .name = "ALERT_MASK", - .size = 2, - }, - { - .addr = TCPC_REG_POWER_STATUS_MASK, - .name = "POWER_STATUS_MASK", - .size = 1, - }, - { - .addr = TCPC_REG_FAULT_STATUS_MASK, - .name = "FAULT_STATUS_MASK", - .size = 1, - }, - { - .addr = TCPC_REG_EXT_STATUS_MASK, - .name = "EXT_STATUS_MASK", - .size = 1 - }, - { - .addr = TCPC_REG_ALERT_EXTENDED_MASK, - .name = "ALERT_EXTENDED_MASK", - .size = 1, - }, - { - .addr = TCPC_REG_CONFIG_STD_OUTPUT, - .name = "CONFIG_STD_OUTPUT", - .size = 1, - }, - { - .addr = TCPC_REG_TCPC_CTRL, - .name = "TCPC_CTRL", - .size = 1, - }, - { - .addr = TCPC_REG_ROLE_CTRL, - .name = "ROLE_CTRL", - .size = 1, - }, - { - .addr = TCPC_REG_FAULT_CTRL, - .name = "FAULT_CTRL", - .size = 1, - }, - { - .addr = TCPC_REG_POWER_CTRL, - .name = "POWER_CTRL", - .size = 1, - }, - { - .addr = TCPC_REG_CC_STATUS, - .name = "CC_STATUS", - .size = 1, - }, - { - .addr = TCPC_REG_POWER_STATUS, - .name = "POWER_STATUS", - .size = 1, - }, - { - .addr = TCPC_REG_FAULT_STATUS, - .name = "FAULT_STATUS", - .size = 1, - }, - { - .addr = TCPC_REG_EXT_STATUS, - .name = "EXT_STATUS", - .size = 1, - }, - { - .addr = TCPC_REG_ALERT_EXT, - .name = "ALERT_EXT", - .size = 1, - }, - { - .addr = TCPC_REG_DEV_CAP_1, - .name = "DEV_CAP_1", - .size = 2, - }, - { - .addr = TCPC_REG_DEV_CAP_2, - .name = "DEV_CAP_2", - .size = 2, - }, - { - .addr = TCPC_REG_STD_INPUT_CAP, - .name = "STD_INPUT_CAP", - .size = 1, - }, - { - .addr = TCPC_REG_STD_OUTPUT_CAP, - .name = "STD_OUTPUT_CAP", - .size = 1, - }, - { - .addr = TCPC_REG_CONFIG_EXT_1, - .name = "CONFIG_EXT_1", - .size = 1, - }, - { - .addr = TCPC_REG_MSG_HDR_INFO, - .name = "MSG_HDR_INFO", - .size = 1, - }, - { - .addr = TCPC_REG_RX_DETECT, - .name = "RX_DETECT", - .size = 1, - }, - { - .addr = TCPC_REG_RX_BYTE_CNT, - .name = "RX_BYTE_CNT", - .size = 1, - }, - { - .addr = TCPC_REG_RX_BUF_FRAME_TYPE, - .name = "RX_BUF_FRAME_TYPE", - .size = 1, - }, - { - .addr = TCPC_REG_TRANSMIT, - .name = "TRANSMIT", - .size = 1, - }, - { - .addr = TCPC_REG_VBUS_VOLTAGE, - .name = "VBUS_VOLTAGE", - .size = 2, - }, - { - .addr = TCPC_REG_VBUS_SINK_DISCONNECT_THRESH, - .name = "VBUS_SINK_DISCONNECT_THRESH", - .size = 2, - }, - { - .addr = TCPC_REG_VBUS_STOP_DISCHARGE_THRESH, - .name = "VBUS_STOP_DISCHARGE_THRESH", - .size = 2, - }, - { - .addr = TCPC_REG_VBUS_VOLTAGE_ALARM_HI_CFG, - .name = "VBUS_VOLTAGE_ALARM_HI_CFG", - .size = 2, - }, - { - .addr = TCPC_REG_VBUS_VOLTAGE_ALARM_LO_CFG, - .name = "VBUS_VOLTAGE_ALARM_LO_CFG", - .size = 2, - }, -}; - -/* - * Dump standard TCPC registers. - */ -void tcpc_dump_std_registers(int port) -{ - tcpc_dump_registers(port, tcpc_regs, ARRAY_SIZE(tcpc_regs)); -} -#endif - -const struct tcpm_drv tcpci_tcpm_drv = { - .init = &tcpci_tcpm_init, - .release = &tcpci_tcpm_release, - .get_cc = &tcpci_tcpm_get_cc, -#ifdef CONFIG_USB_PD_VBUS_DETECT_TCPC - .check_vbus_level = &tcpci_tcpm_check_vbus_level, -#endif - .select_rp_value = &tcpci_tcpm_select_rp_value, - .set_cc = &tcpci_tcpm_set_cc, - .set_polarity = &tcpci_tcpm_set_polarity, -#ifdef CONFIG_USB_PD_DECODE_SOP - .sop_prime_enable = &tcpci_tcpm_sop_prime_enable, -#endif - .set_vconn = &tcpci_tcpm_set_vconn, - .set_msg_header = &tcpci_tcpm_set_msg_header, - .set_rx_enable = &tcpci_tcpm_set_rx_enable, - .get_message_raw = &tcpci_tcpm_get_message_raw, - .transmit = &tcpci_tcpm_transmit, - .tcpc_alert = &tcpci_tcpc_alert, -#ifdef CONFIG_USB_PD_DISCHARGE_TCPC - .tcpc_discharge_vbus = &tcpci_tcpc_discharge_vbus, -#endif - .tcpc_enable_auto_discharge_disconnect = - &tcpci_tcpc_enable_auto_discharge_disconnect, -#ifdef CONFIG_USB_PD_DUAL_ROLE_AUTO_TOGGLE - .drp_toggle = &tcpci_tcpc_drp_toggle, -#endif - .get_chip_info = &tcpci_get_chip_info, -#ifdef CONFIG_USB_PD_PPC - .get_snk_ctrl = &tcpci_tcpm_get_snk_ctrl, - .set_snk_ctrl = &tcpci_tcpm_set_snk_ctrl, - .get_src_ctrl = &tcpci_tcpm_get_src_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 - .set_bist_test_mode = &tcpci_set_bist_test_mode, -#ifdef CONFIG_CMD_TCPC_DUMP - .dump_registers = &tcpc_dump_std_registers, -#endif -}; diff --git a/driver/tcpm/tusb422.c b/driver/tcpm/tusb422.c deleted file mode 100644 index f2a4ec2fb3..0000000000 --- a/driver/tcpm/tusb422.c +++ /dev/null @@ -1,195 +0,0 @@ -/* Copyright 2018 The Chromium OS Authors. All rights reserved. - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ - -/* Type-C port manager for TI TUSB422 Port Controller */ - -#include "common.h" -#include "tusb422.h" -#include "tcpm/tcpci.h" -#include "tcpm/tcpm.h" -#include "timer.h" -#include "usb_pd.h" - -#ifndef CONFIG_USB_PD_TCPM_TCPCI -#error "TUSB422 is using a standard TCPCI interface" -#error "Please upgrade your board configuration" - -#endif - -#if defined(CONFIG_USB_PD_DUAL_ROLE_AUTO_TOGGLE) && \ - !defined(CONFIG_USB_PD_TCPC_LOW_POWER) -#error "TUSB422 driver requires CONFIG_USB_PD_TCPC_LOW_POWER if " \ - "CONFIG_USB_PD_DUAL_ROLE_AUTO_TOGGLE is enabled" -#endif - -#if defined(CONFIG_USB_PD_DUAL_ROLE_AUTO_TOGGLE) && \ - defined(CONFIG_USB_PD_DISCHARGE_TCPC) -#error "TUSB422 must disable TCPC discharge to support enabling Auto " \ - "Discharge Disconnect all the time." -#endif - -enum tusb422_reg_addr { - TUSB422_REG_VBUS_AND_VCONN_CONTROL = 0x98, -}; - -enum vbus_and_vconn_control_mask { - INT_VCONNDIS_DISABLE = BIT(1), - INT_VBUSDIS_DISABLE = BIT(2), -}; - -/* The TUSB422 cannot drive an FRS GPIO, but can detect FRS */ -static int tusb422_set_frs_enable(int port, int enable) -{ - return tcpc_update8(port, TUSB422_REG_PHY_BMC_RX_CTRL, - TUSB422_REG_PHY_BMC_RX_CTRL_FRS_RX_EN, - enable ? MASK_SET : MASK_CLR); -} - -static int tusb422_tcpci_tcpm_init(int port) -{ - int rv; - - /* - * Do not perform TCPC soft reset while waking from Low Power Mode, - * because it makes DRP incapable of looking for connection correctly - * (see b/176986511) and probably breaks firmware_PDTrySrc test - * (see b/179234089). - * - * TODO(b/179234089): Consider implementing function that performs - * only necessary things when leaving Low Power Mode, so we can perform - * TCPC soft reset here. - */ - - rv = tcpci_tcpm_init(port); - if (rv) - return rv; - - if (IS_ENABLED(CONFIG_USB_PD_DUAL_ROLE_AUTO_TOGGLE)) { - /* - * When dual role auto toggle is enabled, the TUSB422 needs - * auto discharge disconnect enabled so that the CC state - * is detected correctly. - * Without this, the CC lines get stuck in the SRC.Open state - * after updating the ROLE Control register on a device connect. - */ - tusb422_tcpm_drv.tcpc_enable_auto_discharge_disconnect(port, 1); - - /* - * Disable internal VBUS discharge. AutoDischargeDisconnect must - * generally remain enabled to keep TUSB422 in active mode. - * However, this will interfere with FRS by default by - * discharging at inappropriate times. Mitigate this by - * disabling internal VBUS discharge. The TUSB422 must rely on - * external VBUS discharge. See TUSB422 datasheet, 7.4.2 Active - * Mode. - */ - tcpc_write(port, TUSB422_REG_VBUS_AND_VCONN_CONTROL, - INT_VBUSDIS_DISABLE); - } - if (IS_ENABLED(CONFIG_USB_PD_FRS_TCPC)) { - /* Disable FRS detection, and enable the FRS detection alert */ - tusb422_set_frs_enable(port, 0); - tcpc_update16(port, TCPC_REG_ALERT_MASK, - TCPC_REG_ALERT_MASK_VENDOR_DEF, MASK_SET); - tcpc_update8(port, TUSB422_REG_VENDOR_INTERRUPTS_MASK, - TUSB422_REG_VENDOR_INTERRUPTS_MASK_FRS_RX, - MASK_SET); - } - /* - * VBUS detection is supposed to be enabled by default, however the - * TUSB422 has this disabled following reset. - */ - /* Enable VBUS detection */ - return tcpc_write16(port, TCPC_REG_COMMAND, - TCPC_REG_COMMAND_ENABLE_VBUS_DETECT); -} - -static int tusb422_tcpm_set_cc(int port, int pull) -{ - /* - * Enable AutoDischargeDisconnect to keep TUSB422 in active mode through - * this transition. Note that the configuration keeps the TCPC from - * actually discharging VBUS in this case. - */ - if (IS_ENABLED(CONFIG_USB_PD_DUAL_ROLE_AUTO_TOGGLE)) - tusb422_tcpm_drv.tcpc_enable_auto_discharge_disconnect(port, 1); - - return tcpci_tcpm_set_cc(port, pull); -} - -#ifdef CONFIG_USB_PD_DUAL_ROLE_AUTO_TOGGLE -static int tusb422_tcpc_drp_toggle(int port) -{ - /* - * The TUSB422 requires auto discharge disconnect to be enabled for - * active mode (not unattached) operation. Make sure it is disabled - * before enabling DRP toggling. - * - * USB Type-C Port Controller Interface Specification revision 2.0, - * Figure 4-21 Source Disconnect and Figure 4-22 Sink Disconnect - */ - tusb422_tcpm_drv.tcpc_enable_auto_discharge_disconnect(port, 0); - - return tcpci_tcpc_drp_toggle(port); -} -#endif - -static void tusb422_tcpci_tcpc_alert(int port) -{ - if (IS_ENABLED(CONFIG_USB_PD_FRS_TCPC)) { - int regval; - - /* FRS detection is a vendor defined alert */ - tcpc_read(port, TUSB422_REG_VENDOR_INTERRUPTS_STATUS, ®val); - if (regval & TUSB422_REG_VENDOR_INTERRUPTS_STATUS_FRS_RX) { - tusb422_set_frs_enable(port, 0); - tcpc_write(port, TUSB422_REG_VENDOR_INTERRUPTS_STATUS, - regval); - pd_got_frs_signal(port); - } - } - tcpci_tcpc_alert(port); -} - -const struct tcpm_drv tusb422_tcpm_drv = { - .init = &tusb422_tcpci_tcpm_init, - .release = &tcpci_tcpm_release, - .get_cc = &tcpci_tcpm_get_cc, -#ifdef CONFIG_USB_PD_VBUS_DETECT_TCPC - .check_vbus_level = &tcpci_tcpm_check_vbus_level, -#endif - .select_rp_value = &tcpci_tcpm_select_rp_value, - .set_cc = &tusb422_tcpm_set_cc, - .set_polarity = &tcpci_tcpm_set_polarity, -#ifdef CONFIG_USB_PD_DECODE_SOP - .sop_prime_enable = &tcpci_tcpm_sop_prime_enable, -#endif - .set_vconn = &tcpci_tcpm_set_vconn, - .set_msg_header = &tcpci_tcpm_set_msg_header, - .set_rx_enable = &tcpci_tcpm_set_rx_enable, - .get_message_raw = &tcpci_tcpm_get_message_raw, - .transmit = &tcpci_tcpm_transmit, - .tcpc_alert = &tusb422_tcpci_tcpc_alert, -#ifdef CONFIG_USB_PD_DISCHARGE_TCPC - .tcpc_discharge_vbus = &tcpci_tcpc_discharge_vbus, -#endif - .tcpc_enable_auto_discharge_disconnect = - &tcpci_tcpc_enable_auto_discharge_disconnect, -#ifdef CONFIG_USB_PD_DUAL_ROLE_AUTO_TOGGLE - .drp_toggle = &tusb422_tcpc_drp_toggle, -#endif -#ifdef CONFIG_USB_PD_PPC - .set_snk_ctrl = &tcpci_tcpm_set_snk_ctrl, - .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 - .set_bist_test_mode = &tcpci_set_bist_test_mode, -#ifdef CONFIG_USB_PD_FRS_TCPC - .set_frs_enable = &tusb422_set_frs_enable, -#endif -}; diff --git a/driver/tcpm/tusb422.h b/driver/tcpm/tusb422.h deleted file mode 100644 index f39939b184..0000000000 --- a/driver/tcpm/tusb422.h +++ /dev/null @@ -1,22 +0,0 @@ -/* Copyright 2018 The Chromium OS Authors. All rights reserved. - * Use of this source code is governed by a BSD-style license that can be - * found in the LICENSE file. - */ - -/* TI TUSB422 Type-C port controller */ - -#ifndef __CROS_EC_USB_PD_TCPM_TUSB422_H -#define __CROS_EC_USB_PD_TCPM_TUSB422_H - -#include "driver/tcpm/tusb422_public.h" - -#define TUSB422_REG_VENDOR_INTERRUPTS_STATUS 0x90 -#define TUSB422_REG_VENDOR_INTERRUPTS_STATUS_FRS_RX BIT(0) - -#define TUSB422_REG_VENDOR_INTERRUPTS_MASK 0x92 -#define TUSB422_REG_VENDOR_INTERRUPTS_MASK_FRS_RX BIT(0) - -#define TUSB422_REG_PHY_BMC_RX_CTRL 0x96 -#define TUSB422_REG_PHY_BMC_RX_CTRL_FRS_RX_EN BIT(3) - -#endif /* defined(__CROS_EC_USB_PD_TCPM_TUSB422_H) */ |