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 <dianders@chromium.org>
Reviewed-on: https://gerrit.chromium.org/gerrit/35115
Reviewed-by: Simon Glass <sjg@chromium.org>
Reviewed-by: Vincent Palatin <vpalatin@chromium.org>
Reviewed-by: Charlie Mooney <charliemooney@chromium.org>
This commit is contained in:
Doug Anderson
2012-10-10 11:05:57 -07:00
committed by Gerrit
parent e679d8504d
commit 8d187addc8

View File

@@ -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);