summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRob Barnes <robbarnes@google.com>2021-04-20 12:35:07 -0600
committerCommit Bot <commit-bot@chromium.org>2021-04-22 22:40:37 +0000
commit94af8e1d5e4203f0e5af0732b8adff0649241ddc (patch)
treecceb510f9080c9ecad9c0c7edd2ebc91b13cee5d
parent964d97811ecf157c5436288d0aad9ba399e4dd72 (diff)
downloadchrome-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.c62
-rw-r--r--driver/usb_mux/anx7451.h4
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, &reg));
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).