From f11169fa8d1ec6f6982306727f0bf0c8a7bd410b Mon Sep 17 00:00:00 2001 From: Scott Collyer Date: Tue, 1 May 2018 10:58:14 -0700 Subject: tcpci: Adjust pd task event/wake when processing alerts Processing of TCPC alerts takes place in the PDCMD task and the result of processing alerts is to wake the PD task. When the PD task runs, it's possible that it may attempt to put the TCPC into low power mode prior to the remainder of the alert processing function completing. So there may be pending TCPC accesses in the alert handler function which called subsequent to the PD task putting the TCPC into low power mode. The TCPC access in the PDCMD task will cause the TCPC to exit low power mode. With the ANX7447 TCPC, this process will repeat indefinitely. This CL replaces the calls to task_set_event and task_wake with indications stored in a local variable. Then at the end of the function the task_set_event is made if necessary. This change in order removes one guaranteed source of pending TCPC accesses from causing the TCPC to exit low power mode. BRANCH=none BUG=b:77544959 TEST=Was using Salea logic analyzer and testing in conjunction with low power mode. Verified that prior to this change I2C accesses were attempted and NAKd after the command I2CIDLE was sent on the bus. Also tested basic type C operation as both SNK/SRC. Change-Id: I8879c655a48a2b16e0445522497002482dc9ca33 Signed-off-by: Scott Collyer Reviewed-on: https://chromium-review.googlesource.com/1044868 Commit-Ready: Scott Collyer Tested-by: Scott Collyer Reviewed-by: Jett Rink --- driver/tcpm/tcpci.c | 22 ++++++++++++++++------ 1 file changed, 16 insertions(+), 6 deletions(-) diff --git a/driver/tcpm/tcpci.c b/driver/tcpm/tcpci.c index 76d01adeae..d4518ae608 100644 --- a/driver/tcpm/tcpci.c +++ b/driver/tcpm/tcpci.c @@ -309,6 +309,7 @@ static int register_mask_reset(int port) void tcpci_tcpc_alert(int port) { int status; + uint32_t pd_event = 0; /* Read the Alert register from the TCPC */ tcpm_alert_status(port, &status); @@ -317,8 +318,7 @@ void tcpci_tcpc_alert(int port) * so, perform tcpc_init inline. */ if (register_mask_reset(port)) - task_set_event(PD_PORT_TO_TASK_ID(port), - PD_EVENT_TCPC_RESET, 0); + pd_event |= PD_EVENT_TCPC_RESET; /* * Clear alert status for everything except RX_STATUS, which shouldn't @@ -330,7 +330,7 @@ void tcpci_tcpc_alert(int port) if (status & TCPC_REG_ALERT_CC_STATUS) { /* CC status changed, wake task */ - task_set_event(PD_PORT_TO_TASK_ID(port), PD_EVENT_CC, 0); + pd_event |= PD_EVENT_CC; } if (status & TCPC_REG_ALERT_POWER_STATUS) { int reg = 0; @@ -342,17 +342,17 @@ void tcpci_tcpc_alert(int port) #if defined(CONFIG_USB_PD_VBUS_DETECT_TCPC) && defined(CONFIG_USB_CHARGER) /* Update charge manager with new VBUS state */ usb_charger_vbus_change(port, tcpc_vbus[port]); - task_wake(PD_PORT_TO_TASK_ID(port)); + pd_event |= TASK_EVENT_WAKE; #endif /* CONFIG_USB_PD_VBUS_DETECT_TCPC && CONFIG_USB_CHARGER */ } if (status & TCPC_REG_ALERT_RX_STATUS) { /* message received */ - task_set_event(PD_PORT_TO_TASK_ID(port), PD_EVENT_RX, 0); + pd_event |= PD_EVENT_RX; } if (status & TCPC_REG_ALERT_RX_HARD_RST) { /* hard reset received */ pd_execute_hard_reset(port); - task_wake(PD_PORT_TO_TASK_ID(port)); + pd_event |= TASK_EVENT_WAKE; } if (status & TCPC_REG_ALERT_TX_COMPLETE) { /* transmit complete */ @@ -360,6 +360,16 @@ void tcpci_tcpc_alert(int port) TCPC_TX_COMPLETE_SUCCESS : TCPC_TX_COMPLETE_FAILED); } + + /* + * Wait until all possible TCPC accesses in this function are complete + * prior to setting events and/or waking the pd task. When the PD + * task is woken and runs (which will happen during I2C transactions in + * this function), the pd task may put the TCPC into low power mode and + * the next I2C transaction to the TCPC will cause it to wake again. + */ + if (pd_event) + task_set_event(PD_PORT_TO_TASK_ID(port), pd_event, 0); } /* -- cgit v1.2.1