diff options
-rw-r--r-- | chip/stm32/dma.c | 19 | ||||
-rw-r--r-- | chip/stm32/dma.h | 8 | ||||
-rw-r--r-- | chip/stm32/i2c.c | 20 |
3 files changed, 39 insertions, 8 deletions
diff --git a/chip/stm32/dma.c b/chip/stm32/dma.c index 8281422fa3..9d7f72df6f 100644 --- a/chip/stm32/dma.c +++ b/chip/stm32/dma.c @@ -197,6 +197,25 @@ void dma_init(void) STM32_RCC_AHBENR |= RCC_AHBENR_DMA1EN; } +int dma_wait(int channel) +{ + struct dma_ctlr *dma; + uint32_t mask; + timestamp_t deadline; + + dma = dma_get_ctlr(channel); + mask = DMA_TCIF(channel); + + deadline.val = get_time().val + DMA_TRANSFER_TIMEOUT_US; + while ((REG32(&dma->isr) & mask) != mask) { + if (deadline.val <= get_time().val) + return -1; + else + usleep(DMA_POLLING_INTERVAL_US); + } + return 0; +} + int dma_get_irq(int channel) { ASSERT(channel < DMA_NUM_CHANNELS); diff --git a/chip/stm32/dma.h b/chip/stm32/dma.h index 606bcf72cb..c1d69a7c07 100644 --- a/chip/stm32/dma.h +++ b/chip/stm32/dma.h @@ -206,4 +206,12 @@ void dma_disable_tc_interrupt(int channel); */ struct dma_ctlr *dma_get_ctlr(int channel); +/** + * Wait for the DMA transfer to complete by polling the transfer complete flag + * + * @param channelĀ» Channel number to wait on (DMAC_...) + * @return -1 for timeout, 0 for sucess + */ +int dma_wait(int channel); + #endif diff --git a/chip/stm32/i2c.c b/chip/stm32/i2c.c index 7139695b23..f74479310c 100644 --- a/chip/stm32/i2c.c +++ b/chip/stm32/i2c.c @@ -62,7 +62,7 @@ static struct mutex i2c_mutex; static uint8_t host_buffer[EC_HOST_PARAM_SIZE + 4]; static struct host_cmd_handler_args host_cmd_args; -/* Flag indicating if a command is currently in the buffer*/ +/* Flag indicating if a command is currently in the buffer */ static uint8_t rx_pending; static inline void disable_i2c_interrupt(int port) @@ -113,20 +113,24 @@ static int i2c_write_raw_slave(int port, void *buf, int len) chan = dma_get_channel(DMAC_I2C_TX); dma_prepare_tx(chan, len, (void *)&STM32_I2C_DR(port), buf); - /* set up DMA interrupts to signal when the transfer is over */ - dma_enable_tc_interrupt(DMAC_I2C_TX); - /* Start the DMA */ dma_go(chan); - /* Configuring i2c2 to use DMA*/ + /* Configuring i2c2 to use DMA */ STM32_I2C_CR2(port) |= (1 << 11); - /* Wait for the transmission complete Interrupt */ - task_wait_event(DMA_TRANSFER_TIMEOUT_US); + if (!in_interrupt_context()) { + /* Poll for the transmission complete flag */ + dma_wait(DMAC_I2C_TX); + dma_clear_isr(DMAC_I2C_TX); + } else { + /* Wait for the transmission complete Interrupt */ + dma_enable_tc_interrupt(DMAC_I2C_TX); + task_wait_event(DMA_TRANSFER_TIMEOUT_US); + dma_disable_tc_interrupt(DMAC_I2C_TX); + } dma_disable(DMAC_I2C_TX); - dma_disable_tc_interrupt(DMAC_I2C_TX); STM32_I2C_CR2(port) &= ~(1 << 11); enable_i2c_interrupt(port); |