summaryrefslogtreecommitdiff
path: root/driver/tcpm/anx7447.c
diff options
context:
space:
mode:
authorJack Rosenthal <jrosenth@chromium.org>2021-11-04 12:11:58 -0600
committerCommit Bot <commit-bot@chromium.org>2021-11-05 04:22:34 +0000
commit252457d4b21f46889eebad61d4c0a65331919cec (patch)
tree01856c4d31d710b20e85a74c8d7b5836e35c3b98 /driver/tcpm/anx7447.c
parent08f5a1e6fc2c9467230444ac9b582dcf4d9f0068 (diff)
downloadchrome-ec-stabilize-14526.57.B-ish.tar.gz
In the interest of making long-term branch maintenance incur as little technical debt on us as possible, we should not maintain any files on the branch we are not actually using. This has the added effect of making it extremely clear when merging CLs from the main branch when changes have the possibility to affect us. The follow-on CL adds a convenience script to actually pull updates from the main branch and generate a CL for the update. BUG=b:204206272 BRANCH=ish TEST=make BOARD=arcada_ish && make BOARD=drallion_ish Signed-off-by: Jack Rosenthal <jrosenth@chromium.org> Change-Id: I17e4694c38219b5a0823e0a3e55a28d1348f4b18 Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/ec/+/3262038 Reviewed-by: Jett Rink <jettrink@chromium.org> Reviewed-by: Tom Hughes <tomhughes@chromium.org>
Diffstat (limited to 'driver/tcpm/anx7447.c')
-rw-r--r--driver/tcpm/anx7447.c861
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, &reg);
- 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, &reg);
- 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, &reg);
- 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, &reg);
- 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, &reg);
- 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, &reg);
- 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, &reg);
- 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);
- 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, &reg);
-
- 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, &reg);
-
- 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, &reg);
- 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, &reg);
- 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 */
-