summaryrefslogtreecommitdiff
path: root/driver
diff options
context:
space:
mode:
authorCaveh Jalali <caveh@chromium.org>2021-06-21 18:35:46 -0700
committerCommit Bot <commit-bot@chromium.org>2021-06-25 20:58:27 +0000
commita6fd238f8a18cb03bbe22916d73e4c4af8808efc (patch)
treeecfca82635fe0388b72979e5b6af0525f7dbad05 /driver
parent917f3aa53a336bd89cc3bf7ed7b1508a0473967a (diff)
downloadchrome-ec-a6fd238f8a18cb03bbe22916d73e4c4af8808efc.tar.gz
nct38xx: Avoid LPM exit when not alerting
This avoids taking an nct38xx port out of low power mode when it is not alerting. The nct38xx chips exit low power mode when they assert Alert. This means we don't have to explicitly take the port out of LPM to check its Alert status register. So, directly access the Alert register to check if the associated port was the source of the Alert. The nct3808 is a dual port chip with a single Alert pin. We need to be careful when servicing Alerts because the usual tcpc_read(), et. al. functions are wrappers that take the port out of LPM mode. When this happens, the nct3808 generates a CC status change alert on a disconnected port. Servicing this "phantom" Alert causes the other port to similarly generate a "phantom" alert. These CC status Alerts can effectively oscilalte between the two ports for a long time. BRANCH=none BUG=b:191531291 TEST=brya no longer gets into ALERT loops on C0/C2 Change-Id: Ib4be6b49a98f3053e5639477e8651b6ba487a0f9 Signed-off-by: Caveh Jalali <caveh@chromium.org> Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/platform/ec/+/2977473 Reviewed-by: Denis Brockus <dbrockus@chromium.org> Reviewed-by: Diana Z <dzigterman@chromium.org> Commit-Queue: Diana Z <dzigterman@chromium.org>
Diffstat (limited to 'driver')
-rw-r--r--driver/tcpm/nct38xx.c37
1 files changed, 27 insertions, 10 deletions
diff --git a/driver/tcpm/nct38xx.c b/driver/tcpm/nct38xx.c
index c0e44a2e9c..4866af699d 100644
--- a/driver/tcpm/nct38xx.c
+++ b/driver/tcpm/nct38xx.c
@@ -229,29 +229,46 @@ static int nct38xx_tcpm_set_snk_ctrl(int port, int enable)
}
#endif
+static inline int tcpc_read_alert_no_lpm_exit(int port, int *val)
+{
+ return tcpc_addr_read16_no_lpm_exit(port,
+ tcpc_config[port].i2c_info.addr_flags,
+ TCPC_REG_ALERT, val);
+}
+
static void nct38xx_tcpc_alert(int port)
{
int alert, rv;
/*
- * If IO expander feature is defined, read the ALERT register first to
- * keep the status of Vendor Define bit. Otherwise, the status of ALERT
- * register will be cleared after tcpci_tcpc_alert() is executed.
+ * The nct3808 is a dual port chip with a shared ALERT
+ * pin. Avoid taking a port out of LPM if it is not alerting.
+ *
+ * The nct38xx exits Idle mode when ALERT is signaled, so there
+ * is no need to run the TCPM LPM exit code to check the ALERT
+ * register bits (Ref. NCT38n7/8 Datasheet S 2.3.4 "Setting the
+ * I2C to * Idle"). In fact, running the TCPM LPM exit code
+ * causes a new CC Status ALERT which has the effect of creating
+ * a new ALERT as a side-effect of handing an ALERT.
*/
- if (IS_ENABLED(CONFIG_IO_EXPANDER_NCT38XX))
- rv = tcpc_read16(port, TCPC_REG_ALERT, &alert);
+ rv = tcpc_read_alert_no_lpm_exit(port, &alert);
+ if (rv == EC_SUCCESS && alert == TCPC_REG_ALERT_NONE) {
+ /* No ALERT on this port, return early. */
+ return;
+ }
- /* Process normal TCPC ALERT event and clear status */
+ /* Process normal TCPC ALERT event and clear status. */
tcpci_tcpc_alert(port);
/*
- * If IO expander feature is defined, check the Vendor Define bit to
- * handle the IOEX IO's interrupt event
+ * If the IO expander feature is enabled, use the ALERT register
+ * value read before it was cleared by calling
+ * tcpci_tcpc_alert(). Check the Vendor Defined Alert bit to
+ * handle the IOEX IO's interrupt event.
*/
if (IS_ENABLED(CONFIG_IO_EXPANDER_NCT38XX))
- if (!rv && (alert & TCPC_REG_ALERT_VENDOR_DEF))
+ if (rv == EC_SUCCESS && (alert & TCPC_REG_ALERT_VENDOR_DEF))
nct38xx_ioex_event_handler(port);
-
}
static int nct3807_handle_fault(int port, int fault)