summaryrefslogtreecommitdiff
path: root/chip/stm32/i2c-stm32f0.c
diff options
context:
space:
mode:
authorAlec Berg <alecaberg@chromium.org>2015-05-21 13:29:03 -0700
committerChromeOS Commit Bot <chromeos-commit-bot@chromium.org>2015-05-22 18:11:58 +0000
commit608fa5efd868325ce85fca1f777a89c0909ea032 (patch)
tree1e9d64d38b4b7d0ea38199c1e8d7afa8e0e51c28 /chip/stm32/i2c-stm32f0.c
parent6fcd1c0481292b9df96f26bbb248248c697e2641 (diff)
downloadchrome-ec-608fa5efd868325ce85fca1f777a89c0909ea032.tar.gz
stm32f0: i2c: fix master i2c sending partial transfers
Fix master i2c when sending partial transfers using I2C_XFER_START and I2C_XFER_STOP. BUG=none BRANCH=none TEST=Tested i2c transfers on oak. tested transfers with I2C_XFER_SINGLE (I2C_XFER_START | I2C_XFER_STOP) and tested partial transfers with just one flag. For partial transfers I tested two different types: - i2c_xfer START only transmitting, then another i2c_xfer with more trasnmitting followed by a STOP. verified with logic analyzer that there is not restart in the middle. - i2c_xfer START with transmitting and receiving, then another i2c_xfer with more receiving followed by a STOP. verified with logic analyzer that there is one restart in between transmitting and receving and no restart in between the two calls to i2c_xfer. Change-Id: Ie4146d1cf7d39f7dc56fd02e65add6bf02772e67 Signed-off-by: Alec Berg <alecaberg@chromium.org> Reviewed-on: https://chromium-review.googlesource.com/272690 Reviewed-by: Vincent Palatin <vpalatin@chromium.org>
Diffstat (limited to 'chip/stm32/i2c-stm32f0.c')
-rw-r--r--chip/stm32/i2c-stm32f0.c34
1 files changed, 27 insertions, 7 deletions
diff --git a/chip/stm32/i2c-stm32f0.c b/chip/stm32/i2c-stm32f0.c
index 9d43f9cb27..4e599efa9a 100644
--- a/chip/stm32/i2c-stm32f0.c
+++ b/chip/stm32/i2c-stm32f0.c
@@ -340,13 +340,19 @@ int i2c_xfer(int port, int slave_addr, const uint8_t *out, int out_bytes,
}
if (out_bytes || !in_bytes) {
- /* Configure the write transfer */
+ /*
+ * Configure the write transfer: if we are stopping then set
+ * AUTOEND bit to automatically set STOP bit after NBYTES.
+ * if we are not stopping, set RELOAD bit so that we can load
+ * NBYTES again. if we are starting, then set START bit.
+ */
STM32_I2C_CR2(port) = ((out_bytes & 0xFF) << 16)
| slave_addr
| ((in_bytes == 0 && xfer_stop) ?
- STM32_I2C_CR2_AUTOEND : 0);
- /* let's go ... */
- STM32_I2C_CR2(port) |= STM32_I2C_CR2_START;
+ STM32_I2C_CR2_AUTOEND : 0)
+ | ((in_bytes == 0 && !xfer_stop) ?
+ STM32_I2C_CR2_RELOAD : 0)
+ | (xfer_start ? STM32_I2C_CR2_START : 0);
for (i = 0; i < out_bytes; i++) {
rv = wait_isr(port, STM32_I2C_ISR_TXIS);
@@ -362,11 +368,18 @@ int i2c_xfer(int port, int slave_addr, const uint8_t *out, int out_bytes,
if (rv)
goto xfer_exit;
}
- /* Configure the read transfer and (re)start */
+ /*
+ * Configure the read transfer: if we are stopping then set
+ * AUTOEND bit to automatically set STOP bit after NBYTES.
+ * if we are not stopping, set RELOAD bit so that we can load
+ * NBYTES again. if we were just transmitting, we need to
+ * set START bit to send (re)start and begin read transaction.
+ */
STM32_I2C_CR2(port) = ((in_bytes & 0xFF) << 16)
| STM32_I2C_CR2_RD_WRN | slave_addr
| (xfer_stop ? STM32_I2C_CR2_AUTOEND : 0)
- | STM32_I2C_CR2_START;
+ | (!xfer_stop ? STM32_I2C_CR2_RELOAD : 0)
+ | (out_bytes ? STM32_I2C_CR2_START : 0);
for (i = 0; i < in_bytes; i++) {
/* Wait for receive buffer not empty */
@@ -377,7 +390,14 @@ int i2c_xfer(int port, int slave_addr, const uint8_t *out, int out_bytes,
in[i] = STM32_I2C_RXDR(port);
}
}
- rv = wait_isr(port, xfer_stop ? STM32_I2C_ISR_STOP : STM32_I2C_ISR_TC);
+
+ /*
+ * If we are stopping, then we already set AUTOEND and we should
+ * wait for the stop bit to be transmitted. Otherwise, we set
+ * the RELOAD bit and we should wait for transfer complete
+ * reload (TCR).
+ */
+ rv = wait_isr(port, xfer_stop ? STM32_I2C_ISR_STOP : STM32_I2C_ISR_TCR);
if (rv)
goto xfer_exit;