diff options
author | Alec Berg <alecaberg@chromium.org> | 2015-05-21 13:29:03 -0700 |
---|---|---|
committer | ChromeOS Commit Bot <chromeos-commit-bot@chromium.org> | 2015-05-22 18:11:58 +0000 |
commit | 608fa5efd868325ce85fca1f777a89c0909ea032 (patch) | |
tree | 1e9d64d38b4b7d0ea38199c1e8d7afa8e0e51c28 | |
parent | 6fcd1c0481292b9df96f26bbb248248c697e2641 (diff) | |
download | chrome-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>
-rw-r--r-- | chip/stm32/i2c-stm32f0.c | 34 | ||||
-rw-r--r-- | chip/stm32/registers.h | 1 |
2 files changed, 28 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; diff --git a/chip/stm32/registers.h b/chip/stm32/registers.h index 52c74ef64f..f9ff3d1c69 100644 --- a/chip/stm32/registers.h +++ b/chip/stm32/registers.h @@ -474,6 +474,7 @@ typedef volatile struct timer_ctlr timer_ctlr_t; #define STM32_I2C_ISR_NACK (1 << 4) #define STM32_I2C_ISR_STOP (1 << 5) #define STM32_I2C_ISR_TC (1 << 6) +#define STM32_I2C_ISR_TCR (1 << 7) #define STM32_I2C_ISR_BERR (1 << 8) #define STM32_I2C_ISR_ARLO (1 << 9) #define STM32_I2C_ISR_OVR (1 << 10) |