summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorCaveh Jalali <caveh@chromium.org>2021-08-10 02:41:58 -0700
committerCommit Bot <commit-bot@chromium.org>2021-08-17 23:12:04 +0000
commitcd73e503e98aac047a319aab95710d3dd8422eb0 (patch)
tree0c13ef0918507c75c988852a8104da8e17e58f0e
parentf89340eed3f35f9de9b6aaca83d5628893b95562 (diff)
downloadchrome-ec-cd73e503e98aac047a319aab95710d3dd8422eb0.tar.gz
ps8xxx: Wait for chip to wake up from LPM
The ps8815 can take up to 50ms to fully wake up from sleep/low power mode. When the chip is asleep, the 1st I2C transaction will fail but the chip will begin to wake up within 10ms. After this delay, I2C transactions succeed, but the firmware is still not fully operational. The way to check if the firmware is ready, is to poll the firmware register for a non-zero value. BRANCH=none BUG=b:195087071,b:186189039 TEST=buildall passes Change-Id: If047fc122d7f61ed5fc361f97b47180e5cf08970 Signed-off-by: Caveh Jalali <caveh@chromium.org> Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/ec/+/3084331 Reviewed-by: Keith Short <keithshort@chromium.org>
-rw-r--r--driver/tcpm/ps8xxx.c52
1 files changed, 51 insertions, 1 deletions
diff --git a/driver/tcpm/ps8xxx.c b/driver/tcpm/ps8xxx.c
index c75103688b..cab795ef09 100644
--- a/driver/tcpm/ps8xxx.c
+++ b/driver/tcpm/ps8xxx.c
@@ -58,6 +58,8 @@
#define CPRINTF(format, args...) cprintf(CC_USBPD, format, ## args)
#define CPRINTS(format, args...) cprints(CC_USBPD, format, ## args)
+#define PS8XXX_I2C_RECOVERY_DELAY_MS 10
+
/*
* The product_id per ports here is expected to be set in callback function -
* .init of tcpm_drv by calling board_get_ps8xxx_product_id().
@@ -290,7 +292,7 @@ static struct ps8xxx_variant_map variant_map[] = {
};
static int get_reg_by_product(const int port,
- const enum ps8xxx_variant_regs reg)
+ const enum ps8xxx_variant_regs reg)
{
int i;
@@ -569,6 +571,48 @@ static int ps8815_make_device_id(int port, int *id)
}
#endif
+/*
+ * The ps8815 can take up to 50ms (FW_INIT_DELAY_MS) to fully wake up
+ * from sleep/low power mode - specially when it contains an application
+ * block firmware update. When the chip is asleep, the 1st I2C
+ * transaction will fail but the chip will begin to wake up within 10ms
+ * (I2C_RECOVERY_DELAY_MS). After this delay, I2C transactions succeed,
+ * but the firmware is still not fully operational. The way to check if
+ * the firmware is ready, is to poll the firmware register for a
+ * non-zero value. This logic applies to all ps8xxx family members
+ * supported by this driver.
+ */
+
+static int ps8xxx_lpm_recovery_delay(int port)
+{
+ int val;
+ int status;
+ int fw_reg;
+ timestamp_t deadline;
+
+ fw_reg = get_reg_by_product(port, REG_FW_VER);
+
+ deadline = get_time();
+ deadline.val += PS8815_FW_INIT_DELAY_MS * 1000;
+
+ val = 0;
+ for (;;) {
+ status = tcpc_read(port, fw_reg, &val);
+ if (status != EC_SUCCESS) {
+ /* wait for chip to wake up */
+ msleep(PS8XXX_I2C_RECOVERY_DELAY_MS);
+ continue;
+ }
+ if (val != 0)
+ break;
+ msleep(1);
+ if (timestamp_expired(deadline, NULL))
+ return EC_ERROR_TIMEOUT;
+ }
+
+ return EC_SUCCESS;
+}
+
static int ps8xxx_get_chip_info(int port, int live,
struct ec_response_pd_chip_info_v1 *chip_info)
{
@@ -726,6 +770,12 @@ static int ps8xxx_tcpm_init(int port)
product_id[port] = board_get_ps8xxx_product_id(port);
+ status = ps8xxx_lpm_recovery_delay(port);
+ if (status != EC_SUCCESS) {
+ CPRINTS("C%d: init: LPM recovery failed", port);
+ return status;
+ }
+
if (IS_ENABLED(CONFIG_USB_PD_TCPM_PS8815)) {
status = ps8815_transmit_buffer_workaround_check(port);
if (status != EC_SUCCESS)