summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorVincent Palatin <vpalatin@chromium.org>2012-10-11 16:12:28 -0700
committerGerrit <chrome-bot@google.com>2012-10-11 23:32:26 -0700
commit94063c0f35d18cdfab0b678ee965220284a80f4d (patch)
tree5ad002be1edece2421642c8f80238a02e4fb89d2
parent1edad9de1196496f1844b8819b1ab8f9789712d7 (diff)
downloadchrome-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.c28
-rw-r--r--chip/stm32/dma.h8
-rw-r--r--chip/stm32/i2c.c48
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);