From 8d187addc8ca7f8379185b33171995e1b113e55f Mon Sep 17 00:00:00 2001 From: Doug Anderson Date: Wed, 10 Oct 2012 11:05:57 -0700 Subject: [PATCH] snow: i2c: Reset i2c if we get a timeout in slave mode This is important to do because if we don't reset we could leave the i2c bus in a wedged state (it's possible that whoever was mastering us could have reset halfway through a transaction). BUG=chrome-os-partner:14430 BRANCH=snow TEST=From vt2 type: "echo bug > /proc/breakme" several times and see good reboots. Check scope trace and see that reset of i2c bus helped (SDA low for 100ms and then fixed). TEST=Run hacky "repro" script from bug see that i2c doesn't get wedged. Change-Id: I57010dcc5f4baa63278b6a025d44f10f00eb9e9d Signed-off-by: Doug Anderson Reviewed-on: https://gerrit.chromium.org/gerrit/35115 Reviewed-by: Simon Glass Reviewed-by: Vincent Palatin Reviewed-by: Charlie Mooney --- chip/stm32/i2c.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/chip/stm32/i2c.c b/chip/stm32/i2c.c index a591e82709..6a4da26158 100644 --- a/chip/stm32/i2c.c +++ b/chip/stm32/i2c.c @@ -132,9 +132,12 @@ void __board_i2c_release(int port) void board_i2c_release(int port) __attribute__((weak, alias("__board_i2c_release"))); +static int i2c_init_port(unsigned int port); + static int i2c_write_raw_slave(int port, void *buf, int len) { struct dma_channel *chan; + int rv; /* we don't want to race with TxE interrupt event */ disable_i2c_interrupt(port); @@ -157,8 +160,13 @@ static int i2c_write_raw_slave(int port, void *buf, int len) } else { /* Wait for the transmission complete Interrupt */ dma_enable_tc_interrupt(DMAC_I2C_TX); - task_wait_event(DMA_TRANSFER_TIMEOUT_US); + rv = task_wait_event(DMA_TRANSFER_TIMEOUT_US); dma_disable_tc_interrupt(DMAC_I2C_TX); + + if (!(rv & TASK_EVENT_WAKE)) { + CPRINTF("[%T Slave timeout, resetting i2c]\n"); + i2c_init_port(port); + } } dma_disable(DMAC_I2C_TX);