diff options
author | Vincent Palatin <vpalatin@chromium.org> | 2012-10-11 16:12:28 -0700 |
---|---|---|
committer | Gerrit <chrome-bot@google.com> | 2012-10-11 23:32:26 -0700 |
commit | 94063c0f35d18cdfab0b678ee965220284a80f4d (patch) | |
tree | 5ad002be1edece2421642c8f80238a02e4fb89d2 | |
parent | 1edad9de1196496f1844b8819b1ab8f9789712d7 (diff) | |
download | chrome-ec-94063c0f35d18cdfab0b678ee965220284a80f4d.tar.gz |
stm32: support DMA on I2C1
Each I2C controller needs to use a fixed pair of DMA channels.
The former code was hardcoded for I2C2. We now use the board
configuration to decide between I2C1 and I2C2 DMA channels.
Signed-off-by: Vincent Palatin <vpalatin@chromium.org>
BRANCH=none
BUG=chrome-os-partner:15185
TEST=make BOARD=snow && make BOARD=spring && make BOARD=daisy
run on Spring and Snow and see we can communicate both with the PMU
(using "pmu" EC console command) and the AP (answering U-Boot host command)
Change-Id: Ifd6806205b443c623e3db09fb1a2d5804bb94214
Reviewed-on: https://gerrit.chromium.org/gerrit/35355
Reviewed-by: Charlie Mooney <charliemooney@chromium.org>
Reviewed-by: Simon Glass <sjg@chromium.org>
Commit-Ready: Vincent Palatin <vpalatin@chromium.org>
Tested-by: Vincent Palatin <vpalatin@chromium.org>
-rw-r--r-- | chip/stm32/dma.c | 28 | ||||
-rw-r--r-- | chip/stm32/dma.h | 8 | ||||
-rw-r--r-- | chip/stm32/i2c.c | 48 |
3 files changed, 54 insertions, 30 deletions
diff --git a/chip/stm32/dma.c b/chip/stm32/dma.c index ab8e8f2d58..c5d1c5e493 100644 --- a/chip/stm32/dma.c +++ b/chip/stm32/dma.c @@ -278,16 +278,32 @@ struct dma_ctlr *dma_get_ctlr(int channel) static void dma_event_interrupt_channel_4(void) { - dma_clear_isr(DMAC_I2C_TX); - if (id[DMAC_I2C_TX] != TASK_ID_INVALID) - task_wake(id[DMAC_I2C_TX]); + dma_clear_isr(DMAC_I2C2_TX); + if (id[DMAC_I2C2_TX] != TASK_ID_INVALID) + task_wake(id[DMAC_I2C2_TX]); } DECLARE_IRQ(STM32_IRQ_DMA_CHANNEL_4, dma_event_interrupt_channel_4, 3); static void dma_event_interrupt_channel_5(void) { - dma_clear_isr(DMAC_I2C_RX); - if (id[DMAC_I2C_RX] != TASK_ID_INVALID) - task_wake(id[DMAC_I2C_RX]); + dma_clear_isr(DMAC_I2C2_RX); + if (id[DMAC_I2C2_RX] != TASK_ID_INVALID) + task_wake(id[DMAC_I2C2_RX]); } DECLARE_IRQ(STM32_IRQ_DMA_CHANNEL_5, dma_event_interrupt_channel_5, 3); + +static void dma_event_interrupt_channel_6(void) +{ + dma_clear_isr(DMAC_I2C1_TX); + if (id[DMAC_I2C1_TX] != TASK_ID_INVALID) + task_wake(id[DMAC_I2C1_TX]); +} +DECLARE_IRQ(STM32_IRQ_DMA_CHANNEL_6, dma_event_interrupt_channel_6, 3); + +static void dma_event_interrupt_channel_7(void) +{ + dma_clear_isr(DMAC_I2C1_RX); + if (id[DMAC_I2C1_RX] != TASK_ID_INVALID) + task_wake(id[DMAC_I2C1_RX]); +} +DECLARE_IRQ(STM32_IRQ_DMA_CHANNEL_7, dma_event_interrupt_channel_7, 3); diff --git a/chip/stm32/dma.h b/chip/stm32/dma.h index 76380de6f7..c9832fcfe3 100644 --- a/chip/stm32/dma.h +++ b/chip/stm32/dma.h @@ -26,11 +26,13 @@ enum { DMAC_SPI2_TX, /* - * The same channels are used for i2c and spi, you can't use them at + * The same channels are used for i2c2 and spi, you can't use them at * the same time or it will cause dma to not work */ - DMAC_I2C_RX = 4, - DMAC_I2C_TX = 3, + DMAC_I2C2_TX = 3, + DMAC_I2C2_RX = 4, + DMAC_I2C1_TX = 5, + DMAC_I2C1_RX = 6, /* DMA1 has 7 channels, DMA2 has 5 */ DMA1_NUM_CHANNELS = 7, diff --git a/chip/stm32/i2c.c b/chip/stm32/i2c.c index 6a4da26158..5acd5c40f9 100644 --- a/chip/stm32/i2c.c +++ b/chip/stm32/i2c.c @@ -59,6 +59,12 @@ #define I2C1 STM32_I2C1_PORT #define I2C2 STM32_I2C2_PORT +/* select the DMA channels matching the board configuration */ +#define DMAC_SLAVE_TX ((I2C_PORT_SLAVE) ? DMAC_I2C2_TX : DMAC_I2C1_TX) +#define DMAC_SLAVE_RX ((I2C_PORT_SLAVE) ? DMAC_I2C2_RX : DMAC_I2C1_RX) +#define DMAC_HOST_TX ((I2C_PORT_HOST) ? DMAC_I2C2_TX : DMAC_I2C1_TX) +#define DMAC_HOST_RX ((I2C_PORT_HOST) ? DMAC_I2C2_RX : DMAC_I2C1_RX) + enum { /* * A stop condition should take 2 clocks, but the process may need more @@ -73,16 +79,16 @@ enum { }; static const struct dma_option dma_tx_option[NUM_PORTS] = { - {DMAC_I2C_TX, (void *)&STM32_I2C_DR(I2C1), + {DMAC_I2C1_TX, (void *)&STM32_I2C_DR(I2C1), DMA_MSIZE_BYTE | DMA_PSIZE_HALF_WORD}, - {DMAC_I2C_TX, (void *)&STM32_I2C_DR(I2C2), + {DMAC_I2C2_TX, (void *)&STM32_I2C_DR(I2C2), DMA_MSIZE_BYTE | DMA_PSIZE_HALF_WORD}, }; static const struct dma_option dma_rx_option[NUM_PORTS] = { - {DMAC_I2C_RX, (void *)&STM32_I2C_DR(I2C1), + {DMAC_I2C1_RX, (void *)&STM32_I2C_DR(I2C1), DMA_MSIZE_BYTE | DMA_PSIZE_HALF_WORD}, - {DMAC_I2C_RX, (void *)&STM32_I2C_DR(I2C2), + {DMAC_I2C2_RX, (void *)&STM32_I2C_DR(I2C2), DMA_MSIZE_BYTE | DMA_PSIZE_HALF_WORD}, }; @@ -142,26 +148,26 @@ static int i2c_write_raw_slave(int port, void *buf, int len) /* we don't want to race with TxE interrupt event */ disable_i2c_interrupt(port); - /* Configuring DMA1 channel DMAC_I2X_TX */ + /* Configuring DMA1 channel DMAC_SLAVE_TX */ enable_ack(port); - chan = dma_get_channel(DMAC_I2C_TX); + chan = dma_get_channel(DMAC_SLAVE_TX); dma_prepare_tx(dma_tx_option + port, len, buf); /* Start the DMA */ dma_go(chan); - /* Configuring i2c2 to use DMA */ + /* Configuring i2c to use DMA */ STM32_I2C_CR2(port) |= (1 << 11); if (in_interrupt_context()) { /* Poll for the transmission complete flag */ - dma_wait(DMAC_I2C_TX); - dma_clear_isr(DMAC_I2C_TX); + dma_wait(DMAC_SLAVE_TX); + dma_clear_isr(DMAC_SLAVE_TX); } else { /* Wait for the transmission complete Interrupt */ - dma_enable_tc_interrupt(DMAC_I2C_TX); + dma_enable_tc_interrupt(DMAC_SLAVE_TX); rv = task_wait_event(DMA_TRANSFER_TIMEOUT_US); - dma_disable_tc_interrupt(DMAC_I2C_TX); + dma_disable_tc_interrupt(DMAC_SLAVE_TX); if (!(rv & TASK_EVENT_WAKE)) { CPRINTF("[%T Slave timeout, resetting i2c]\n"); @@ -169,7 +175,7 @@ static int i2c_write_raw_slave(int port, void *buf, int len) } } - dma_disable(DMAC_I2C_TX); + dma_disable(DMAC_SLAVE_TX); STM32_I2C_CR2(port) &= ~(1 << 11); enable_i2c_interrupt(port); @@ -273,8 +279,8 @@ static void i2c_event_handler(int port) /* If it's a receiver slave */ if (!(STM32_I2C_SR2(port) & (1 << 2))) { /* Disable, and clear the DMA transfer complete flag */ - dma_disable(DMAC_I2C_RX); - dma_clear_isr(DMAC_I2C_RX); + dma_disable(DMAC_SLAVE_RX); + dma_clear_isr(DMAC_SLAVE_RX); /* Turn off i2c's DMA flag */ STM32_I2C_CR2(port) &= ~(1 << 11); @@ -741,10 +747,10 @@ static int i2c_master_transmit(int port, int slave_addr, uint8_t *data, /* Configuring DMA1 channel DMAC_I2X_TX */ dma_prepare_tx(dma_tx_option + port, size, data); - dma_enable_tc_interrupt(DMAC_I2C_TX); + dma_enable_tc_interrupt(DMAC_HOST_TX); /* Start the DMA */ - dma_go(dma_get_channel(DMAC_I2C_TX)); + dma_go(dma_get_channel(DMAC_HOST_TX)); /* Configuring i2c2 to use DMA */ STM32_I2C_CR2(port) |= CR2_DMAEN; @@ -756,8 +762,8 @@ static int i2c_master_transmit(int port, int slave_addr, uint8_t *data, if (!rv_start) rv = task_wait_event(DMA_TRANSFER_TIMEOUT_US); - dma_disable(DMAC_I2C_TX); - dma_disable_tc_interrupt(DMAC_I2C_TX); + dma_disable(DMAC_HOST_TX); + dma_disable_tc_interrupt(DMAC_HOST_TX); STM32_I2C_CR2(port) &= ~CR2_DMAEN; if (rv_start) @@ -790,7 +796,7 @@ static int i2c_master_receive(int port, int slave_addr, uint8_t *data, enable_ack(port); dma_start_rx(dma_rx_option + port, size, data); - dma_enable_tc_interrupt(DMAC_I2C_RX); + dma_enable_tc_interrupt(DMAC_HOST_RX); STM32_I2C_CR2(port) |= CR2_DMAEN; STM32_I2C_CR2(port) |= CR2_LAST; @@ -799,8 +805,8 @@ static int i2c_master_receive(int port, int slave_addr, uint8_t *data, if (!rv_start) rv = task_wait_event(DMA_TRANSFER_TIMEOUT_US); - dma_disable(DMAC_I2C_RX); - dma_disable_tc_interrupt(DMAC_I2C_RX); + dma_disable(DMAC_HOST_RX); + dma_disable_tc_interrupt(DMAC_HOST_RX); STM32_I2C_CR2(port) &= ~CR2_DMAEN; disable_ack(port); |