summaryrefslogtreecommitdiff
path: root/common/usb_pd_protocol.c
diff options
context:
space:
mode:
Diffstat (limited to 'common/usb_pd_protocol.c')
-rw-r--r--common/usb_pd_protocol.c60
1 files changed, 40 insertions, 20 deletions
diff --git a/common/usb_pd_protocol.c b/common/usb_pd_protocol.c
index 33730fb9cd..ff8f5610cd 100644
--- a/common/usb_pd_protocol.c
+++ b/common/usb_pd_protocol.c
@@ -401,25 +401,7 @@ static void handle_device_access(int port)
}
}
-/*
- * This can be called from any task. If we are in the PD task, we can handle
- * immediately. Otherwise, we need to notify the PD task via event.
- */
-void pd_device_accessed(int port)
-{
- if (port == TASK_ID_TO_PD_PORT(task_get_current())) {
- /* Ignore any access to device while it is waking up */
- if (pd[port].flags & PD_FLAGS_LPM_TRANSITION)
- return;
-
- handle_device_access(port);
- }
- else
- task_set_event(PD_PORT_TO_TASK_ID(port),
- PD_EVENT_DEVICE_ACCESSED, 0);
-}
-
-int pd_device_in_low_power(int port)
+static int pd_device_in_low_power(int port)
{
/*
* If we are actively waking the device up in the PD task, do not
@@ -449,6 +431,20 @@ static int reset_device_and_notify(int port)
else
CPRINTS("TCPC p%d init failed!", port);
+ /*
+ * Before getting the other tasks that are waiting, clear the reset
+ * event from this PD task to prevent multiple reset/init events
+ * occurring.
+ *
+ * The double reset event happens when the higher priority PD interrupt
+ * task gets an interrupt during the above tcpm_init function. When that
+ * occurs, the higher priority task waits correctly for us to finish
+ * waking the TCPC, but it has also set PD_EVENT_TCPC_RESET again, which
+ * would result in a second, unnecessary init.
+ */
+ atomic_clear(task_get_event_bitmap(task_get_current()),
+ PD_EVENT_TCPC_RESET);
+
waiting_tasks = atomic_read_clear(&pd[port].tasks_waiting_on_reset);
/*
@@ -470,7 +466,7 @@ static int reset_device_and_notify(int port)
return rv;
}
-void pd_wait_for_wakeup(int port)
+static void pd_wait_for_wakeup(int port)
{
if (port == TASK_ID_TO_PD_PORT(task_get_current())) {
/* If we are in the PD task, we can directly reset */
@@ -493,6 +489,30 @@ void pd_wait_for_wakeup(int port)
}
}
+void pd_wait_exit_low_power(int port)
+{
+ if (pd_device_in_low_power(port))
+ pd_wait_for_wakeup(port);
+}
+
+/*
+ * This can be called from any task. If we are in the PD task, we can handle
+ * immediately. Otherwise, we need to notify the PD task via event.
+ */
+void pd_device_accessed(int port)
+{
+ if (port == TASK_ID_TO_PD_PORT(task_get_current())) {
+ /* Ignore any access to device while it is waking up */
+ if (pd[port].flags & PD_FLAGS_LPM_TRANSITION)
+ return;
+
+ handle_device_access(port);
+ } else {
+ task_set_event(PD_PORT_TO_TASK_ID(port),
+ PD_EVENT_DEVICE_ACCESSED, 0);
+ }
+}
+
void pd_prevent_low_power_mode(int port, int prevent)
{
const int current_task_mask = (1 << task_get_current());