summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--chip/stm32/dma.c19
-rw-r--r--chip/stm32/dma.h8
-rw-r--r--chip/stm32/i2c.c20
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);