stm32: try to be more robust against malformed commands

Timeout properly when the AP doesn't want our bytes.

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

BUG=chrome-os-partner:8865
TEST=On Snow, boot with an old kernel.

Change-Id: Iac4fa5c3606f2e8731927326fad291dae26a615c
This commit is contained in:
Vincent Palatin
2012-05-22 23:13:29 +00:00
parent 8b468a8a26
commit d9954b304a

View File

@@ -13,6 +13,7 @@
#include "i2c.h"
#include "registers.h"
#include "task.h"
#include "timer.h"
#include "util.h"
/* Console output macros */
@@ -28,6 +29,9 @@
/* Clock divider for I2C controller */
#define I2C_CCR (CPU_CLOCK/(2 * I2C_FREQ))
/* Transmit timeout in microseconds */
#define I2C_TX_TIMEOUT 10000 /* us */
#define NUM_PORTS 2
#define I2C1 STM32_I2C1_PORT
#define I2C2 STM32_I2C2_PORT
@@ -41,12 +45,19 @@ static uint8_t host_buffer[EC_PARAM_SIZE + 2];
/* current position in host buffer for reception */
static int rx_index;
/* indicates if a wait loop should abort */
static volatile int abort_transaction;
static void wait_tx(int port)
static int wait_tx(int port)
{
/* TODO: Add timeouts and error checking for safety */
while (!(STM32_I2C_SR1(port) & (1 << 7)))
static timestamp_t deadline;
deadline.val = get_time().val + I2C_TX_TIMEOUT;
/* 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(int port, void *buf, int len)
@@ -54,9 +65,13 @@ static int i2c_write_raw(int port, void *buf, int len)
int i;
uint8_t *data = buf;
abort_transaction = 0;
for (i = 0; i < len; i++) {
STM32_I2C_DR(port) = data[i];
wait_tx(port);
if (wait_tx(port)) {
CPRINTF("TX failed\n");
break;
}
}
return len;
@@ -117,6 +132,7 @@ static void i2c_event_handler(int port)
STM32_I2C_SR1(port);
STM32_I2C_SR2(port);
} else if (i2c_sr1[port] & (1 << 4)) {
abort_transaction = 1;
/* clear STOPF bit by reading SR1 and then writing CR1 */
STM32_I2C_SR1(port);
STM32_I2C_CR1(port) = STM32_I2C_CR1(port);
@@ -154,17 +170,16 @@ static void i2c_error_handler(int port)
{
i2c_sr1[port] = STM32_I2C_SR1(port);
#ifdef CONFIG_DEBUG
if (i2c_sr1[port] & 1 << 10) {
/* 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",
__func__, port, STM32_I2C_SR2(port));
}
#endif
STM32_I2C_SR1(port) &= ~0xdf00;
}