diff options
author | Ting Shen <phoenixshen@google.com> | 2019-11-27 12:50:21 +0800 |
---|---|---|
committer | Commit Bot <commit-bot@chromium.org> | 2019-11-29 10:38:09 +0000 |
commit | 3a90729933c1fa96662bd1361b5454db0ff3ff54 (patch) | |
tree | 864c0cb7aad9e87a9dac1347b945e061a27999b9 | |
parent | 81d2e72bf6f6d726e49d6683eb40980471dc3052 (diff) | |
download | chrome-ec-3a90729933c1fa96662bd1361b5454db0ff3ff54.tar.gz |
fusb302: fix lower power mode
CL:1880773 makes board unable to exit low power mode because interrupt
is not configured correctly, this CL fixes the problem.
BUG=b:142760774,b:145101992
TEST=1) In S0, unplug and replug usb device
make sure the device shows up in `lsusb`
2) suspend, unplug and replug usb device, resume
make sure the device shows up is `lsusb`
3) make sure toggle is disabled in G3 and force source/sink mode.
BRANCH=master
Change-Id: Iae8eb7571241ad8364d460fbb516844c7aa8b86a
Signed-off-by: Ting Shen <phoenixshen@google.com>
Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/ec/+/1939027
Reviewed-by: Eric Yilun Lin <yllin@chromium.org>
Commit-Queue: Ting Shen <phoenixshen@chromium.org>
Tested-by: Ting Shen <phoenixshen@chromium.org>
-rw-r--r-- | driver/tcpm/fusb302.c | 67 | ||||
-rw-r--r-- | driver/tcpm/fusb302.h | 2 |
2 files changed, 66 insertions, 3 deletions
diff --git a/driver/tcpm/fusb302.c b/driver/tcpm/fusb302.c index 66c131fb37..bbb6015e56 100644 --- a/driver/tcpm/fusb302.c +++ b/driver/tcpm/fusb302.c @@ -434,7 +434,6 @@ static int fusb302_tcpm_init(int port) tcpm_set_polarity(port, 0); tcpm_set_vconn(port, 0); - /* Turn on the power! */ /* TODO: Reduce power consumption */ tcpc_write(port, TCPC_REG_POWER, TCPC_REG_POWER_PWR_ALL); @@ -1008,9 +1007,73 @@ void tcpm_set_bist_test_data(int port) } #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) { - return tcpc_write(port, TCPC_REG_POWER, TCPC_REG_POWER_PWR_LOW); + 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_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 diff --git a/driver/tcpm/fusb302.h b/driver/tcpm/fusb302.h index ec418407f7..b4a8599ea8 100644 --- a/driver/tcpm/fusb302.h +++ b/driver/tcpm/fusb302.h @@ -76,7 +76,7 @@ #define TCPC_REG_CONTROL2 0x08 /* two-bit field, valid values below */ -#define TCPC_REG_CONTROL2_MODE (1<<1) +#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) |