summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRong Chang <rongchang@chromium.org>2012-07-31 21:27:32 +0800
committerGerrit <chrome-bot@google.com>2012-07-31 22:13:50 -0700
commit776374b028c3fe4708d8a1458c73805edb6895b1 (patch)
tree53eb78156f1412daa94fecb5863705098b7cc158
parentae8e24acb764be386e06a9720c828ec5ce2353c3 (diff)
downloadchrome-ec-776374b028c3fe4708d8a1458c73805edb6895b1.tar.gz
Wait STM I2C stop bit sent
This CL prevents the risk of CR1 write access causes duplicate STOP. Signed-off-by: Rong Chang <rongchang@chromium.org> BUG=chrome-os-partner:11974 TEST=manual console command "pmu 200" Change-Id: I717336d87230139a1a17e6f39e70502c0e0c7a18 (cherry picked from https://gerrit.chromium.org/gerrit/#/c/26832) Reviewed-on: https://gerrit.chromium.org/gerrit/28811 Commit-Ready: Rong Chang <rongchang@chromium.org> Tested-by: Rong Chang <rongchang@chromium.org> Reviewed-by: Vincent Palatin <vpalatin@chromium.org> Reviewed-by: Simon Glass <sjg@chromium.org>
-rw-r--r--chip/stm32/i2c.c27
1 files changed, 26 insertions, 1 deletions
diff --git a/chip/stm32/i2c.c b/chip/stm32/i2c.c
index 7e7bafefc6..c2acb293e7 100644
--- a/chip/stm32/i2c.c
+++ b/chip/stm32/i2c.c
@@ -27,6 +27,9 @@
/* I2C bus frequency */
#define I2C_FREQ 100000 /* Hz */
+/* I2C bit period in microseconds */
+#define I2C_PERIOD_US (1000000 / I2C_FREQ)
+
/* Clock divider for I2C controller */
#define I2C_CCR (CPU_CLOCK/(2 * I2C_FREQ))
@@ -37,6 +40,10 @@
#define I2C1 STM32_I2C1_PORT
#define I2C2 STM32_I2C2_PORT
+enum {
+ /* A stop condition should take 2 clocks, so allow 8 */
+ TIMEOUT_STOP_SENT_US = I2C_PERIOD_US * 8,
+};
static uint16_t i2c_sr1[NUM_PORTS];
static struct mutex i2c_mutex;
@@ -439,6 +446,24 @@ static void master_stop(int port)
STM32_I2C_CR1(port) |= (1 << 9);
}
+static int wait_until_stop_sent(int port)
+{
+ timestamp_t deadline;
+
+ deadline = get_time();
+ deadline.val += TIMEOUT_STOP_SENT_US;
+
+ while (STM32_I2C_CR1(port) & (1 << 9)) {
+ if (timestamp_expired(deadline, NULL)) {
+ ccprintf("Stop event deadline passed: CR1=%016b\n",
+ STM32_I2C_CR1(port));
+ return EC_ERROR_TIMEOUT;
+ }
+ }
+
+ return EC_SUCCESS;
+}
+
static void handle_i2c_error(int port, int rv)
{
timestamp_t t1, t2;
@@ -581,7 +606,7 @@ static int i2c_master_receive(int port, int slave_addr, uint8_t *data,
data[0] = STM32_I2C_DR(port);
}
- return EC_SUCCESS;
+ return wait_until_stop_sent(port);
}
/**