summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorVincent Palatin <vpalatin@chromium.org>2012-05-22 23:13:29 +0000
committerVincent Palatin <vpalatin@chromium.org>2012-05-23 00:52:36 +0000
commitd9954b304a5146378e78003fb095c2842d6b2ad3 (patch)
tree8c3a957043ea8b416906af1798d6cddf6172f553
parent8b468a8a269a79b6af075c4872649524ff6841a0 (diff)
downloadchrome-ec-d9954b304a5146378e78003fb095c2842d6b2ad3.tar.gz
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
-rw-r--r--chip/stm32/i2c.c27
1 files changed, 21 insertions, 6 deletions
diff --git a/chip/stm32/i2c.c b/chip/stm32/i2c.c
index e1018ed31b..d4df0648ee 100644
--- a/chip/stm32/i2c.c
+++ b/chip/stm32/i2c.c
@@ -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;
}