summaryrefslogtreecommitdiff
path: root/chip/stm32/usb_pd_phy.c
diff options
context:
space:
mode:
Diffstat (limited to 'chip/stm32/usb_pd_phy.c')
-rw-r--r--chip/stm32/usb_pd_phy.c67
1 files changed, 56 insertions, 11 deletions
diff --git a/chip/stm32/usb_pd_phy.c b/chip/stm32/usb_pd_phy.c
index 7079709e99..55c465986d 100644
--- a/chip/stm32/usb_pd_phy.c
+++ b/chip/stm32/usb_pd_phy.c
@@ -13,6 +13,7 @@
#include "hwtimer.h"
#include "hooks.h"
#include "registers.h"
+#include "system.h"
#include "task.h"
#include "timer.h"
#include "util.h"
@@ -71,6 +72,10 @@ static struct pd_physical {
timer_ctlr_t *tim_rx;
} pd_phy[PD_PORT_COUNT];
+/* keep track of RX edge timing in order to trigger receive */
+static timestamp_t rx_edge_ts[PD_PORT_COUNT][PD_RX_TRANSITION_COUNT];
+static int rx_edge_ts_idx[PD_PORT_COUNT];
+
void pd_init_dequeue(int port)
{
/* preamble ends with 1 */
@@ -295,10 +300,17 @@ void pd_tx_set_circular_mode(int port)
pd_phy[port].dma_tx_option.flags |= STM32_DMA_CCR_CIRC;
}
-void pd_start_tx(int port, int polarity, int bit_len)
+int pd_start_tx(int port, int polarity, int bit_len)
{
stm32_dma_chan_t *tx = dma_get_channel(DMAC_SPI_TX(port));
+ /* disable RX detection interrupt */
+ pd_rx_disable_monitoring(port);
+
+ /* Check that we are not receiving a frame to avoid collisions */
+ if (pd_rx_started(port))
+ return -5;
+
/* Initialize spi peripheral to prepare for transmission. */
pd_tx_spi_init(port);
@@ -315,9 +327,6 @@ void pd_start_tx(int port, int polarity, int bit_len)
/* Flush data in write buffer so that DMA can get the latest data */
asm volatile("dmb;");
- /* disable RX detection interrupt */
- pd_rx_disable_monitoring(port);
-
/* Kick off the DMA to send the data */
dma_clear_isr(DMAC_SPI_TX(port));
#ifdef CONFIG_COMMON_RUNTIME
@@ -338,6 +347,8 @@ void pd_start_tx(int port, int polarity, int bit_len)
/* Start counting at 300Khz*/
pd_phy[port].tim_tx->cr1 |= 1;
#endif
+
+ return bit_len;
}
void pd_tx_done(int port, int polarity)
@@ -436,23 +447,57 @@ void pd_rx_disable_monitoring(int port)
STM32_EXTI_PR = EXTI_COMP_MASK(port);
}
+uint64_t get_time_since_last_edge(int port)
+{
+ int prev_idx = (rx_edge_ts_idx[port] == 0) ?
+ PD_RX_TRANSITION_COUNT - 1 :
+ rx_edge_ts_idx[port] - 1;
+ return get_time().val - rx_edge_ts[port][prev_idx].val;
+}
+
/* detect an edge on the PD RX pin */
void pd_rx_handler(void)
{
int pending, i;
+ int next_idx;
pending = STM32_EXTI_PR;
for (i = 0; i < PD_PORT_COUNT; i++) {
if (pending & EXTI_COMP_MASK(i)) {
- /* start sampling */
- pd_rx_start(i);
+ rx_edge_ts[i][rx_edge_ts_idx[i]].val = get_time().val;
+ next_idx = (rx_edge_ts_idx[i] ==
+ PD_RX_TRANSITION_COUNT - 1) ?
+ 0 : rx_edge_ts_idx[i] + 1;
+
/*
- * ignore the comparator IRQ until we are done with
- * current message
+ * Do not deep sleep while waiting for more edges. For
+ * most boards, sleep is already disabled due to being
+ * in PD connected state, but other boards can sleep
+ * while connected.
*/
- pd_rx_disable_monitoring(i);
- /* trigger the analysis in the task */
- pd_rx_event(i);
+ disable_sleep(SLEEP_MASK_USB_PD);
+
+ /*
+ * If we have seen enough edges in a certain amount of
+ * time, then trigger RX start.
+ */
+ if ((rx_edge_ts[i][rx_edge_ts_idx[i]].val -
+ rx_edge_ts[i][next_idx].val)
+ < PD_RX_TRANSITION_WINDOW) {
+ /* start sampling */
+ pd_rx_start(i);
+ /*
+ * ignore the comparator IRQ until we are done
+ * with current message
+ */
+ pd_rx_disable_monitoring(i);
+ /* trigger the analysis in the task */
+ pd_rx_event(i);
+ } else {
+ /* do not trigger RX start, just clear int */
+ STM32_EXTI_PR = EXTI_COMP_MASK(i);
+ }
+ rx_edge_ts_idx[i] = next_idx;
}
}
}