diff options
-rw-r--r-- | chip/stm32/i2c.c | 27 |
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); } /** |