Skip to content

Commit 066bb5f

Browse files
erian747jhedberg
authored andcommitted
drivers: i2c_stm32_v2: Add DMA helpers
To prepare for further patches and separation of interrupt/DMA modes from polled, this commit introduces two helpers for starting and stopping DMA transfers Finsishing DMA transfers are also moved from interrupt handlers to thread after beeing wokenen by semaphore Signed-off-by: Erik Andersson <[email protected]>
1 parent cf3dddf commit 066bb5f

File tree

1 file changed

+70
-67
lines changed

1 file changed

+70
-67
lines changed

drivers/i2c/i2c_ll_stm32_v2.c

Lines changed: 70 additions & 67 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@
2020
#include <zephyr/drivers/i2c.h>
2121
#include <zephyr/pm/device.h>
2222
#include <zephyr/pm/device_runtime.h>
23-
23+
#include <stm32_cache.h>
2424
#include <zephyr/cache.h>
2525
#include <zephyr/linker/linker-defs.h>
2626
#include <zephyr/mem_mgmt/mem_attr.h>
@@ -149,6 +149,68 @@ static int configure_dma(struct stream const *dma, struct dma_config *dma_cfg,
149149

150150
return 0;
151151
}
152+
153+
static void dma_xfer_start(const struct device *dev, struct i2c_msg *msg)
154+
{
155+
const struct i2c_stm32_config *cfg = dev->config;
156+
struct i2c_stm32_data *data = dev->data;
157+
I2C_TypeDef *i2c = cfg->i2c;
158+
159+
if ((msg->flags & I2C_MSG_READ) != 0U) {
160+
/* Configure RX DMA */
161+
data->dma_blk_cfg.source_address = LL_I2C_DMA_GetRegAddr(
162+
cfg->i2c, LL_I2C_DMA_REG_DATA_RECEIVE);
163+
data->dma_blk_cfg.source_addr_adj = DMA_ADDR_ADJ_NO_CHANGE;
164+
data->dma_blk_cfg.dest_address = (uint32_t)data->current.buf;
165+
data->dma_blk_cfg.dest_addr_adj = DMA_ADDR_ADJ_INCREMENT;
166+
data->dma_blk_cfg.block_size = data->current.len;
167+
168+
if (configure_dma(&cfg->rx_dma, &data->dma_rx_cfg,
169+
&data->dma_blk_cfg) != 0) {
170+
LOG_ERR("Problem setting up RX DMA");
171+
return;
172+
}
173+
data->current.buf += msg->len;
174+
data->current.len -= msg->len;
175+
LL_I2C_EnableDMAReq_RX(i2c);
176+
} else {
177+
if (data->current.len != 0U) {
178+
/* Configure TX DMA */
179+
data->dma_blk_cfg.source_address = (uint32_t)data->current.buf;
180+
data->dma_blk_cfg.source_addr_adj = DMA_ADDR_ADJ_INCREMENT;
181+
data->dma_blk_cfg.dest_address = LL_I2C_DMA_GetRegAddr(
182+
cfg->i2c, LL_I2C_DMA_REG_DATA_TRANSMIT);
183+
data->dma_blk_cfg.dest_addr_adj = DMA_ADDR_ADJ_NO_CHANGE;
184+
data->dma_blk_cfg.block_size = data->current.len;
185+
186+
if (configure_dma(&cfg->tx_dma, &data->dma_tx_cfg,
187+
&data->dma_blk_cfg) != 0) {
188+
LOG_ERR("Problem setting up TX DMA");
189+
return;
190+
}
191+
data->current.buf += data->current.len;
192+
data->current.len -= data->current.len;
193+
LL_I2C_EnableDMAReq_TX(i2c);
194+
}
195+
}
196+
}
197+
198+
static void dma_finish(const struct device *dev, struct i2c_msg *msg)
199+
{
200+
const struct i2c_stm32_config *cfg = dev->config;
201+
202+
if ((msg->flags & I2C_MSG_READ) != 0U) {
203+
dma_stop(cfg->rx_dma.dev_dma, cfg->rx_dma.dma_channel);
204+
LL_I2C_DisableDMAReq_RX(cfg->i2c);
205+
if (!stm32_buf_in_nocache((uintptr_t)msg->buf, msg->len)) {
206+
sys_cache_data_invd_range(msg->buf, msg->len);
207+
}
208+
} else {
209+
dma_stop(cfg->tx_dma.dev_dma, cfg->tx_dma.dma_channel);
210+
LL_I2C_DisableDMAReq_TX(cfg->i2c);
211+
}
212+
}
213+
152214
#endif /* CONFIG_I2C_STM32_V2_DMA */
153215

154216
static inline void msg_init(const struct device *dev, struct i2c_msg *msg,
@@ -188,44 +250,7 @@ static inline void msg_init(const struct device *dev, struct i2c_msg *msg,
188250

189251
#ifdef CONFIG_I2C_STM32_V2_DMA
190252
if (msg->len) {
191-
if (msg->flags & I2C_MSG_READ) {
192-
/* Configure RX DMA */
193-
data->dma_blk_cfg.source_address = LL_I2C_DMA_GetRegAddr(
194-
cfg->i2c, LL_I2C_DMA_REG_DATA_RECEIVE);
195-
data->dma_blk_cfg.source_addr_adj = DMA_ADDR_ADJ_NO_CHANGE;
196-
data->dma_blk_cfg.dest_address = (uint32_t)msg->buf;
197-
data->dma_blk_cfg.dest_addr_adj = DMA_ADDR_ADJ_INCREMENT;
198-
data->dma_blk_cfg.block_size = msg->len;
199-
200-
if (configure_dma(&cfg->rx_dma, &data->dma_rx_cfg,
201-
&data->dma_blk_cfg) != 0) {
202-
LOG_ERR("Problem setting up RX DMA");
203-
return;
204-
}
205-
data->current.buf += msg->len;
206-
data->current.len -= msg->len;
207-
LL_I2C_EnableDMAReq_RX(i2c);
208-
} else {
209-
if (data->current.len) {
210-
/* Configure TX DMA */
211-
data->dma_blk_cfg.source_address =
212-
(uint32_t)data->current.buf;
213-
data->dma_blk_cfg.source_addr_adj = DMA_ADDR_ADJ_INCREMENT;
214-
data->dma_blk_cfg.dest_address = LL_I2C_DMA_GetRegAddr(
215-
cfg->i2c, LL_I2C_DMA_REG_DATA_TRANSMIT);
216-
data->dma_blk_cfg.dest_addr_adj = DMA_ADDR_ADJ_NO_CHANGE;
217-
data->dma_blk_cfg.block_size = msg->len;
218-
219-
if (configure_dma(&cfg->tx_dma, &data->dma_tx_cfg,
220-
&data->dma_blk_cfg) != 0) {
221-
LOG_ERR("Problem setting up TX DMA");
222-
return;
223-
}
224-
data->current.buf += data->current.len;
225-
data->current.len -= data->current.len;
226-
LL_I2C_EnableDMAReq_TX(i2c);
227-
}
228-
}
253+
dma_xfer_start(dev, msg);
229254
}
230255
#endif /* CONFIG_I2C_STM32_V2_DMA */
231256

@@ -288,16 +313,6 @@ static void i2c_stm32_master_mode_end(const struct device *dev)
288313
}
289314
#endif
290315

291-
#ifdef CONFIG_I2C_STM32_V2_DMA
292-
if (data->current.msg->flags & I2C_MSG_READ) {
293-
dma_stop(cfg->rx_dma.dev_dma, cfg->rx_dma.dma_channel);
294-
LL_I2C_DisableDMAReq_RX(i2c);
295-
} else {
296-
dma_stop(cfg->tx_dma.dev_dma, cfg->tx_dma.dma_channel);
297-
LL_I2C_DisableDMAReq_TX(i2c);
298-
}
299-
#endif /* CONFIG_I2C_STM32_V2_DMA */
300-
301316
k_sem_give(&data->device_sync_sem);
302317
}
303318

@@ -599,17 +614,6 @@ void i2c_stm32_event(const struct device *dev)
599614
LL_I2C_GenerateStopCondition(i2c);
600615
} else {
601616
i2c_stm32_disable_transfer_interrupts(dev);
602-
603-
#ifdef CONFIG_I2C_STM32_V2_DMA
604-
if (data->current.msg->flags & I2C_MSG_READ) {
605-
dma_stop(cfg->rx_dma.dev_dma, cfg->rx_dma.dma_channel);
606-
LL_I2C_DisableDMAReq_RX(i2c);
607-
} else {
608-
dma_stop(cfg->tx_dma.dev_dma, cfg->tx_dma.dma_channel);
609-
LL_I2C_DisableDMAReq_TX(i2c);
610-
}
611-
#endif /* CONFIG_I2C_STM32_V2_DMA */
612-
613617
k_sem_give(&data->device_sync_sem);
614618
}
615619
}
@@ -694,6 +698,9 @@ static int i2c_stm32_msg_write(const struct device *dev, struct i2c_msg *msg,
694698
k_sem_take(&data->device_sync_sem, K_FOREVER);
695699
is_timeout = true;
696700
}
701+
#ifdef CONFIG_I2C_STM32_V2_DMA
702+
dma_finish(dev, msg);
703+
#endif
697704

698705
if (data->current.is_nack || data->current.is_err ||
699706
data->current.is_arlo || is_timeout) {
@@ -753,13 +760,9 @@ static int i2c_stm32_msg_read(const struct device *dev, struct i2c_msg *msg,
753760
k_sem_take(&data->device_sync_sem, K_FOREVER);
754761
is_timeout = true;
755762
}
756-
#if defined(CONFIG_I2C_STM32_V2_DMA)
757-
if (!stm32_buf_in_nocache((uintptr_t)msg->buf, msg->len)) {
758-
LOG_DBG("Rx buffer at %p (len %zu) is in cached memory; invalidating cache",
759-
msg->buf, msg->len);
760-
sys_cache_data_invd_range((void *)msg->buf, msg->len);
761-
}
762-
#endif /* CONFIG_I2C_STM32_V2_DMA */
763+
#ifdef CONFIG_I2C_STM32_V2_DMA
764+
dma_finish(dev, msg);
765+
#endif
763766

764767
if (data->current.is_nack || data->current.is_err ||
765768
data->current.is_arlo || is_timeout) {

0 commit comments

Comments
 (0)