diff options
author | Etienne Carriere <etienne.carriere@st.com> | 2019-05-03 10:20:21 +0200 |
---|---|---|
committer | Jérôme Forissier <jerome@forissier.org> | 2019-05-22 13:38:49 +0200 |
commit | 834ce4c65a544eab592f8f339a77d6b7ace4165d (patch) | |
tree | d3ee2acefb31145ef9e078c5219dcb0c9862bcbd | |
parent | 41e5aa8f18c4d48083341ff3df9e75f0c77cf703 (diff) |
stm32_i2c: optimized I2C 1 byte memory transfer
Introduce stm32_i2c_read_write_membyte() to operate a single byte
data transfer in memory mode. This function will be used by the
power management sequence in order to relax pager resident memory
footprint when I2C need to execute in an unpaged context.
Signed-off-by: Etienne Carriere <etienne.carriere@st.com>
Acked-by: Jerome Forissier <jerome.forissier@linaro.org>
-rw-r--r-- | core/drivers/stm32_i2c.c | 82 | ||||
-rw-r--r-- | core/include/drivers/stm32_i2c.h | 9 |
2 files changed, 88 insertions, 3 deletions
diff --git a/core/drivers/stm32_i2c.c b/core/drivers/stm32_i2c.c index 0dc418a8..5895e4a9 100644 --- a/core/drivers/stm32_i2c.c +++ b/core/drivers/stm32_i2c.c @@ -151,10 +151,11 @@ #define I2C_ICR_ALERTCF BIT(13) /* Max data size for a single I2C transfer */ -#define MAX_NBYTE_SIZE 255U +#define MAX_NBYTE_SIZE 255U -#define I2C_NSEC_PER_SEC 1000000000L -#define I2C_TIMEOUT_BUSY_MS 25U +#define I2C_NSEC_PER_SEC 1000000000L +#define I2C_TIMEOUT_BUSY_MS 25 +#define I2C_TIMEOUT_BUSY_US (I2C_TIMEOUT_BUSY_MS * 1000) #define CR2_RESET_MASK (I2C_CR2_SADD | I2C_CR2_HEAD10R | \ I2C_CR2_NBYTES | I2C_CR2_RELOAD | \ @@ -1151,6 +1152,81 @@ int stm32_i2c_master_transmit(struct i2c_handle_s *hi2c, uint32_t dev_addr, return i2c_write(hi2c, &request, p_data, size); } +int stm32_i2c_read_write_membyte(struct i2c_handle_s *hi2c, uint16_t dev_addr, + unsigned int mem_addr, uint8_t *p_data, + bool write) +{ + uint64_t timeout_ref = 0; + uintptr_t base = get_base(hi2c); + int rc = -1; + uint8_t *p_buff = p_data; + uint32_t event_mask = 0; + + if (hi2c->i2c_state != I2C_STATE_READY || !p_data) + return -1; + + stm32_clock_enable(hi2c->clock); + + timeout_ref = timeout_init_us(I2C_TIMEOUT_BUSY_US); + if (wait_isr_event(hi2c, I2C_ISR_BUSY, 0, timeout_ref)) + goto bail; + + hi2c->i2c_state = write ? I2C_STATE_BUSY_TX : I2C_STATE_BUSY_RX; + hi2c->i2c_err = I2C_ERROR_NONE; + + i2c_transfer_config(hi2c, dev_addr, I2C_MEMADD_SIZE_8BIT, + write ? I2C_RELOAD_MODE : I2C_SOFTEND_MODE, + I2C_GENERATE_START_WRITE); + + timeout_ref = timeout_init_us(I2C_TIMEOUT_BUSY_US); + if (i2c_wait_txis(hi2c, timeout_ref)) + goto bail; + + io_write8(base + I2C_TXDR, mem_addr); + + if (write) + event_mask = I2C_ISR_TCR; + else + event_mask = I2C_ISR_TC; + + timeout_ref = timeout_init_us(I2C_TIMEOUT_BUSY_US); + if (wait_isr_event(hi2c, event_mask, 1, timeout_ref)) + goto bail; + + i2c_transfer_config(hi2c, dev_addr, I2C_MEMADD_SIZE_8BIT, + I2C_AUTOEND_MODE, + write ? I2C_NO_STARTSTOP : I2C_GENERATE_START_READ); + + timeout_ref = timeout_init_us(I2C_TIMEOUT_BUSY_US); + if (write) { + if (i2c_wait_txis(hi2c, timeout_ref)) + goto bail; + + io_write8(base + I2C_TXDR, *p_buff); + } else { + if (wait_isr_event(hi2c, I2C_ISR_RXNE, 1, timeout_ref)) + goto bail; + + *p_buff = io_read8(base + I2C_RXDR); + } + + timeout_ref = timeout_init_us(I2C_TIMEOUT_BUSY_US); + if (i2c_wait_stop(hi2c, timeout_ref)) + goto bail; + + io_write32(base + I2C_ICR, I2C_ISR_STOPF); + io_clrbits32(base + I2C_CR2, CR2_RESET_MASK); + + hi2c->i2c_state = I2C_STATE_READY; + + rc = 0; + +bail: + stm32_clock_disable(hi2c->clock); + + return rc; +} + /* * Read an amount of data in blocking mode * diff --git a/core/include/drivers/stm32_i2c.h b/core/include/drivers/stm32_i2c.h index 6efcf00e..470fb2be 100644 --- a/core/include/drivers/stm32_i2c.h +++ b/core/include/drivers/stm32_i2c.h @@ -214,6 +214,15 @@ int stm32_i2c_master_receive(struct i2c_handle_s *hi2c, uint32_t dev_addr, unsigned int timeout_ms); /* + * Optimized 1 byte read/write function for unpaged sequences. + * 8-bit addressing mode / single byte transferred / use default I2C timeout. + * Return 0 on success else a negative value + */ +int stm32_i2c_read_write_membyte(struct i2c_handle_s *hi2c, uint16_t dev_addr, + unsigned int mem_addr, uint8_t *p_data, + bool write); + +/* * Check link with the I2C device * * @hi2c: Reference to I2C bus handle structure |