diff options
author | Rob Barnes <robbarnes@google.com> | 2021-04-20 12:35:07 -0600 |
---|---|---|
committer | Commit Bot <commit-bot@chromium.org> | 2021-04-22 22:40:37 +0000 |
commit | 94af8e1d5e4203f0e5af0732b8adff0649241ddc (patch) | |
tree | cceb510f9080c9ecad9c0c7edd2ebc91b13cee5d | |
parent | 964d97811ecf157c5436288d0aad9ba399e4dd72 (diff) | |
download | chrome-ec-94af8e1d5e4203f0e5af0732b8adff0649241ddc.tar.gz |
ANX7451: Add power off and wake up routines
Add anx7451_power_off and anx7451_wake_up routines. ANX7451 is powered
off whenever both USB and DP are disabled. ANX7451 is woken up via i2c
before mux set or get.
BUG=b:184907521
TEST=Mux is powering off when nothing is connected.
Mux is waking up when cable is connected.
BRANCH=None
Signed-off-by: Rob Barnes <robbarnes@google.com>
Change-Id: Idf1343735cb94eb8bbaebe93794195d2f115b086
Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/ec/+/2840056
Reviewed-by: Diana Z <dzigterman@chromium.org>
-rw-r--r-- | driver/usb_mux/anx7451.c | 62 | ||||
-rw-r--r-- | driver/usb_mux/anx7451.h | 4 |
2 files changed, 56 insertions, 10 deletions
diff --git a/driver/usb_mux/anx7451.c b/driver/usb_mux/anx7451.c index 38d56e8fcb..c46a78acf8 100644 --- a/driver/usb_mux/anx7451.c +++ b/driver/usb_mux/anx7451.c @@ -15,6 +15,13 @@ #include "usb_mux.h" #include "util.h" +/* + * Empirical testing found it takes ~12ms to wake mux. + * Setting timeout to 20ms for some buffer. + */ +#define ANX7451_I2C_WAKE_TIMEOUT_MS 20 +#define ANX7451_I2C_WAKE_RETRY_DELAY_US 500 + #define CPRINTS(format, args...) cprints(CC_USBCHARGE, format, ## args) #define CPRINTF(format, args...) cprintf(CC_USBCHARGE, format, ## args) @@ -30,6 +37,45 @@ static inline int anx7451_write(const struct usb_mux *me, return i2c_write8(me->i2c_port, me->i2c_addr_flags, reg, val); } +static int anx7451_power_off(const struct usb_mux *me) +{ + /* + * The mux will not send an acknowledgment when powered off, so ignore + * response and always return success. + */ + anx7451_write(me, ANX7451_REG_POWER_CNTRL, ANX7451_POWER_CNTRL_OFF); + return EC_SUCCESS; +} + +static int anx7451_wake_up(const struct usb_mux *me) +{ + timestamp_t start; + int rv; + int val; + + if (chipset_in_state(CHIPSET_STATE_HARD_OFF)) + return EC_ERROR_NOT_POWERED; + + /* Keep reading top register until mux wakes up or timesout */ + start = get_time(); + do { + rv = anx7451_read(me, 0x0, &val); + if (!rv) + break; + usleep(ANX7451_I2C_WAKE_RETRY_DELAY_US); + } while (time_since32(start) < ANX7451_I2C_WAKE_TIMEOUT_MS * MSEC); + if (rv) { + CPRINTS("ANX7451: Failed to wake mux rv:%d", rv); + return EC_ERROR_TIMEOUT; + } + + /* ULTRA_LOW_POWER must always be disabled (Fig 2-2) */ + RETURN_ERROR(anx7451_write(me, ANX7451_REG_ULTRA_LOW_POWER, + ANX7451_ULTRA_LOW_POWER_DIS)); + + return EC_SUCCESS; +} + static int anx7451_set_mux(const struct usb_mux *me, mux_state_t mux_state) { int reg; @@ -39,17 +85,11 @@ static int anx7451_set_mux(const struct usb_mux *me, mux_state_t mux_state) return (mux_state == USB_PD_MUX_NONE) ? EC_SUCCESS : EC_ERROR_NOT_POWERED; - /* ULTRA_LOW_POWER must always be disabled (Fig 2-2) */ - RETURN_ERROR(anx7451_write(me, ANX7451_REG_ULTRA_LOW_POWER, - ANX7451_ULTRA_LOW_POWER_DIS)); + /* To disable both DP and USB the mux must be powered off. */ + if (!(mux_state & (USB_PD_MUX_USB_ENABLED | USB_PD_MUX_DP_ENABLED))) + return anx7451_power_off(me); - - /* b/184907521: If both DP and USB disabled, mux will fail */ - if (!(mux_state & (USB_PD_MUX_USB_ENABLED | USB_PD_MUX_DP_ENABLED))) { - CPRINTS("ANX7451 requires USB or DP to be set, " - "forcing USB enabled"); - mux_state |= USB_PD_MUX_USB_ENABLED; - } + RETURN_ERROR(anx7451_wake_up(me)); /* ULP_CFG_MODE_EN overrides pin control. Always set it */ reg = ANX7451_ULP_CFG_MODE_EN; @@ -71,6 +111,8 @@ static int anx7451_get_mux(const struct usb_mux *me, mux_state_t *mux_state) if (chipset_in_state(CHIPSET_STATE_HARD_OFF)) return USB_PD_MUX_NONE; + RETURN_ERROR(anx7451_wake_up(me)); + *mux_state = 0; RETURN_ERROR(anx7451_read(me, ANX7451_REG_ULP_CFG_MODE, ®)); diff --git a/driver/usb_mux/anx7451.h b/driver/usb_mux/anx7451.h index c8d302f5c9..cf7a701f6c 100644 --- a/driver/usb_mux/anx7451.h +++ b/driver/usb_mux/anx7451.h @@ -15,6 +15,10 @@ #define ANX7451_I2C_ADDR2_FLAGS 0x16 #define ANX7451_I2C_ADDR3_FLAGS 0x11 +/* This register is not documented in datasheet. */ +#define ANX7451_REG_POWER_CNTRL 0x2B +#define ANX7451_POWER_CNTRL_OFF 0xFF + /* * Ultra low power control register. * On ANX7451, this register should always be 0 (disabled). |