aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEtienne Carriere <etienne.carriere@st.com>2019-05-03 10:20:21 +0200
committerJérôme Forissier <jerome@forissier.org>2019-05-22 13:38:49 +0200
commit834ce4c65a544eab592f8f339a77d6b7ace4165d (patch)
treed3ee2acefb31145ef9e078c5219dcb0c9862bcbd
parent41e5aa8f18c4d48083341ff3df9e75f0c77cf703 (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.c82
-rw-r--r--core/include/drivers/stm32_i2c.h9
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