diff options
Diffstat (limited to 'driver/tcpm/anx7447.c')
-rw-r--r-- | driver/tcpm/anx7447.c | 861 |
1 files changed, 0 insertions, 861 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 */ - |