stm32: fix race condition in I2C response

When we are transmitting a response to the EC, we don't want to race
with the TX empty interrupt handler. So just disable I2C interrupt
during the transmission.

Signed-off-by: Vincent Palatin <vpalatin@chromium.org>

BUG=None
TEST=on Lucas DVT, use the keyboard and see we are no longer getting
"bad checksum" in the kernel log.

Change-Id: Ic59532d1ac0a3eabb67ba0d498940986282bd87f
Reviewed-on: https://gerrit.chromium.org/gerrit/26162
Commit-Ready: Vincent Palatin <vpalatin@chromium.org>
Reviewed-by: Vincent Palatin <vpalatin@chromium.org>
Tested-by: Vincent Palatin <vpalatin@chromium.org>
This commit is contained in:
Vincent Palatin
2012-06-22 23:39:59 +00:00
committed by Gerrit
parent cbbaf428a9
commit 240470a54b

View File

@@ -50,6 +50,26 @@ static int rx_index;
/* indicates if a wait loop should abort */
static volatile int abort_transaction;
static inline void disable_i2c_interrupt(int port)
{
STM32_I2C_CR2(port) &= ~(3 << 8);
}
static inline void enable_i2c_interrupt(int port)
{
STM32_I2C_CR2(port) |= 3 << 8;
}
static inline void enable_ack(int port)
{
STM32_I2C_CR1(port) |= (1 << 10);
}
static inline void disable_ack(int port)
{
STM32_I2C_CR1(port) &= ~(1 << 10);
}
static int wait_tx(int port)
{
static timestamp_t deadline;
@@ -67,6 +87,9 @@ static int i2c_write_raw(int port, void *buf, int len)
int i;
uint8_t *data = buf;
/* 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];
@@ -76,6 +99,8 @@ static int i2c_write_raw(int port, void *buf, int len)
}
}
enable_i2c_interrupt(port);
return len;
}
@@ -281,26 +306,6 @@ DECLARE_HOOK(HOOK_INIT, i2c_init, HOOK_PRIO_DEFAULT);
#define SR1_PECERR (1 << 12) /* PEC err in reception */
#define SR1_TIMEOUT (1 << 14) /* Timeout : 25ms */
static inline void disable_i2c_interrupt(int port)
{
STM32_I2C_CR2(port) &= ~(3 << 8);
}
static inline void enable_i2c_interrupt(int port)
{
STM32_I2C_CR2(port) |= 3 << 8;
}
static inline void enable_ack(int port)
{
STM32_I2C_CR1(port) |= (1 << 10);
}
static inline void disable_ack(int port)
{
STM32_I2C_CR1(port) &= ~(1 << 10);
}
static inline void dump_i2c_reg(int port)
{
#ifdef CONFIG_DEBUG_I2C