summaryrefslogtreecommitdiff
path: root/chip/stm32/i2c-stm32f0.c
diff options
context:
space:
mode:
authorNicolas Boichat <drinkcat@chromium.org>2016-05-23 15:23:38 +0800
committerchrome-bot <chrome-bot@chromium.org>2016-06-02 14:06:52 -0700
commit4f600b32bbcdd1f870f8389b8666101d3a8513ed (patch)
treed60ca034718fd19e0a13411825b1eaef25901072 /chip/stm32/i2c-stm32f0.c
parentf6a53e9917b474e95afb42e2522fb88c61998c9a (diff)
downloadchrome-ec-4f600b32bbcdd1f870f8389b8666101d3a8513ed.tar.gz
stm32: i2c: Busy loop for a while waiting for interrupt
I2C is not necessarily _that_ slow, especially when using 1Mhz clock speed, and, looking at traces from userspace, there are large gaps (150us) between bytes (while the bytes themselves only take ~10us). At 400kHz and higher bus speed, busy-loop for the duration of 2 bytes, before sleeping (and yielding to other tasks) for 100us between each attempt. BRANCH=None BUG=chrome-os-partner:50381 TEST=i2cget, look at Logic 16 traces: no gaps between address and bytes Change-Id: If47f0f8e55be37002361800d35f71c945863d42d Signed-off-by: Nicolas Boichat <drinkcat@chromium.org> Reviewed-on: https://chromium-review.googlesource.com/346670 Reviewed-by: Vincent Palatin <vpalatin@chromium.org>
Diffstat (limited to 'chip/stm32/i2c-stm32f0.c')
-rw-r--r--chip/stm32/i2c-stm32f0.c28
1 files changed, 23 insertions, 5 deletions
diff --git a/chip/stm32/i2c-stm32f0.c b/chip/stm32/i2c-stm32f0.c
index 4bc371a3dc..8710d73be5 100644
--- a/chip/stm32/i2c-stm32f0.c
+++ b/chip/stm32/i2c-stm32f0.c
@@ -10,6 +10,7 @@
#include "gpio.h"
#include "hooks.h"
#include "host_command.h"
+#include "hwtimer.h"
#include "i2c.h"
#include "registers.h"
#include "system.h"
@@ -44,6 +45,7 @@
/* I2C port state data */
struct i2c_port_data {
uint32_t timeout_us; /* Transaction timeout, or 0 to use default */
+ enum i2c_freq freq; /* Port clock speed */
};
static struct i2c_port_data pdata[I2C_PORT_COUNT];
@@ -52,6 +54,13 @@ void i2c_set_timeout(int port, uint32_t timeout)
pdata[port].timeout_us = timeout ? timeout : I2C_TX_TIMEOUT_MASTER;
}
+/* timingr register values for supported input clks / i2c clk rates */
+static const uint32_t busyloop_us[I2C_FREQ_COUNT] = {
+ [I2C_FREQ_1000KHZ] = 16, /* Enough for 2 bytes */
+ [I2C_FREQ_400KHZ] = 40, /* Enough for 2 bytes */
+ [I2C_FREQ_100KHZ] = 0, /* No busy looping at 100kHz (bus is slow) */
+};
+
/**
* Wait for ISR register to contain the specified mask.
*
@@ -60,9 +69,10 @@ void i2c_set_timeout(int port, uint32_t timeout)
*/
static int wait_isr(int port, int mask)
{
- uint64_t timeout = get_time().val + pdata[port].timeout_us;
+ uint32_t start = __hw_clock_source_read();
+ uint32_t delta = 0;
- while (get_time().val < timeout) {
+ do {
int isr = STM32_I2C_ISR(port);
/* Check for errors */
@@ -74,9 +84,15 @@ static int wait_isr(int port, int mask)
if ((isr & mask) == mask)
return EC_SUCCESS;
- /* I2C is slow, so let other things run while we wait */
- usleep(100);
- }
+ delta = __hw_clock_source_read() - start;
+
+ /**
+ * Depending on the bus speed, busy loop for a while before
+ * sleeping and letting other things run.
+ */
+ if (delta >= busyloop_us[pdata[port].freq])
+ usleep(100);
+ } while (delta < pdata[port].timeout_us);
return EC_ERROR_TIMEOUT;
}
@@ -116,6 +132,8 @@ static void i2c_set_freq_port(const struct i2c_port_t *p,
STM32_I2C_TIMINGR(port) = regs[freq];
/* Enable port */
STM32_I2C_CR1(port) = STM32_I2C_CR1_PE;
+
+ pdata[port].freq = freq;
}
/**