summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorCharlie Mooney <charliemooney@chromium.org>2012-08-13 13:10:55 -0700
committerGerrit <chrome-bot@google.com>2012-08-13 15:35:16 -0700
commit847a3feca69932e1ea8168a8fab630ff82f95a15 (patch)
tree402f5233c09a19dea4370f26c448042a8f8f20fa
parent3b8b1bd586f13d8137d2830210c64e12dab1adc6 (diff)
downloadchrome-ec-847a3feca69932e1ea8168a8fab630ff82f95a15.tar.gz
Lucas: Switching i2c slave-mode over to dma
There was an errata issued for the i2c on STMF100xx. It specified that not all guarantees apply to i2c on these chips if you are not using DMA to load the data. To prevent problems, I am converting the i2c code on the EC for Lucas over to DMA. The master functionality was already converted over in change I2fb80dcb, this change switches over the slave-mode i2c code to also use dma now, instead of polling, as per the errata. BUG=chrome-os-partner:10901 TEST=The slave mode i2c code is used heavily during normal use of the Chromebook, including boot up and using the keyboard. Start up the cpu uart console, and boot the system. Then once it's fulling started, make sure that pressing keys does not cause any errors and that the key presses are working. Change-Id: I8d665054bccbd3ca9b8dcc5e0fa74b2fbe49f52d Signed-off-by: Charlie Mooney <charliemooney@chromium.org> Reviewed-on: https://gerrit.chromium.org/gerrit/30024 Reviewed-by: Simon Glass <sjg@chromium.org> Reviewed-by: David Hendricks <dhendrix@chromium.org>
-rw-r--r--chip/stm32/i2c.c84
1 files changed, 42 insertions, 42 deletions
diff --git a/chip/stm32/i2c.c b/chip/stm32/i2c.c
index fe3f03db5f..8cd684be93 100644
--- a/chip/stm32/i2c.c
+++ b/chip/stm32/i2c.c
@@ -62,11 +62,8 @@ static struct mutex i2c_mutex;
static uint8_t host_buffer[EC_HOST_PARAM_SIZE + 4];
static struct host_cmd_handler_args host_cmd_args;
-/* current position in host buffer for reception */
-static int rx_index;
-
-/* indicates if a wait loop should abort */
-static volatile int abort_transaction;
+/* Flag indicating if a command is currently in the buffer*/
+static uint8_t rx_pending;
static inline void disable_i2c_interrupt(int port)
{
@@ -104,35 +101,32 @@ void __board_i2c_release(int port)
void board_i2c_release(int port)
__attribute__((weak, alias("__board_i2c_release")));
-
-static int wait_tx_slave(int port)
-{
- static timestamp_t deadline;
-
- deadline.val = get_time().val + I2C_TX_TIMEOUT_SLAVE;
- /* wait for TxE or errors (Timeout, STOP, BERR, AF) */
- while (!(STM32_I2C_SR1(port) & (1<<7)) && !abort_transaction &&
- (get_time().val < deadline.val))
- ;
- return !(STM32_I2C_SR1(port) & (1 << 7));
-}
-
static int i2c_write_raw_slave(int port, void *buf, int len)
{
- int i;
- uint8_t *data = buf;
+ struct dma_channel *chan;
/* we don't want to race with TxE interrupt event */
disable_i2c_interrupt(port);
- abort_transaction = 0;
- for (i = 0; i < len; i++) {
- STM32_I2C_DR(port) = data[i];
- if (wait_tx_slave(port)) {
- CPRINTF("TX failed\n");
- break;
- }
- }
+ enable_ack(port);
+
+ /* Configuring DMA1 channel DMAC_I2X_TX */
+ chan = dma_get_channel(DMAC_I2C_TX);
+ dma_prepare_tx(chan, len, (void *)&STM32_I2C_DR(port), buf);
+ dma_go(chan);
+
+ /* Configuring i2c2 */
+ STM32_I2C_CR2(port) |= (1 << 11);
+
+ /* Wait for the dma to transfer all the data */
+ dma_wait(DMAC_I2C_TX);
+
+ /* Disable, and clear the DMA transfer complete flag */
+ dma_disable(DMAC_I2C_TX);
+ dma_clear_isr(DMAC_I2C_TX);
+
+ /* Turn off i2c's DMA flag */
+ STM32_I2C_CR2(port) &= ~(1 << 11);
enable_i2c_interrupt(port);
@@ -213,33 +207,40 @@ static void i2c_event_handler(int port)
/* transfer matched our slave address */
if (i2c_sr1[port] & (1 << 1)) {
+ /* If it's a receiver slave */
+ if (!(STM32_I2C_SR2(port) & (1 << 2))) {
+ dma_start_rx(DMAC_I2C_RX, sizeof(host_buffer),
+ (void *)&STM32_I2C_DR(port), host_buffer);
+
+ STM32_I2C_CR2(port) |= (1 << 11);
+ rx_pending = 1;
+ }
+
/* cleared by reading SR1 followed by reading SR2 */
STM32_I2C_SR1(port);
STM32_I2C_SR2(port);
} else if (i2c_sr1[port] & (1 << 4)) {
- abort_transaction = 1;
+ /* 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);
+
+ /* Turn off i2c's DMA flag */
+ STM32_I2C_CR2(port) &= ~(1 << 11);
+ }
/* clear STOPF bit by reading SR1 and then writing CR1 */
STM32_I2C_SR1(port);
STM32_I2C_CR1(port) = STM32_I2C_CR1(port);
}
- /* RxNE event */
- if (i2c_sr1[port] & (1 << 6)) {
- if (port == I2C2) { /* AP issued write command */
- if (rx_index >= sizeof(host_buffer) - 1) {
- rx_index = 0;
- CPRINTF("I2C message too large\n");
- }
- host_buffer[rx_index++] = STM32_I2C_DR(I2C2);
- }
- }
/* TxE event */
if (i2c_sr1[port] & (1 << 7)) {
if (port == I2C2) { /* AP is waiting for EC response */
- if (rx_index) {
+ if (rx_pending) {
i2c_process_command();
/* reset host buffer after end of transfer */
- rx_index = 0;
+ rx_pending = 0;
} else {
/* spurious read : return dummy value */
STM32_I2C_DR(port) = 0xec;
@@ -258,7 +259,6 @@ static void i2c_error_handler(int port)
/* ACK failed (NACK); expected when AP reads final byte.
* Software must clear AF bit. */
} else {
- abort_transaction = 1;
CPRINTF("%s: I2C_SR1(%s): 0x%04x\n",
__func__, port, i2c_sr1[port]);
CPRINTF("%s: I2C_SR2(%s): 0x%04x\n",