Skip to content

Commit 04e8570

Browse files
ttmutnashif
authored andcommitted
drivers: i2c: i2c_max32: Add DMA support for controller mode
MAX32 I2C peripheral can benefit from DMA transfers. This patch adds DMA support for transactions made in controller mode. Signed-off-by: Tahsin Mutlugun <[email protected]>
1 parent b4278bf commit 04e8570

File tree

2 files changed

+227
-2
lines changed

2 files changed

+227
-2
lines changed

drivers/i2c/Kconfig.max32

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,4 +17,11 @@ config I2C_MAX32_INTERRUPT
1717
Enable interrupt support for MAX32 I2C controller mode
1818
transfers.
1919

20+
config I2C_MAX32_DMA
21+
bool "DMA support for MAX32 MCU I2C driver"
22+
depends on I2C_MAX32_INTERRUPT
23+
select DMA
24+
help
25+
Use DMA for MAX32 MCU I2C controller mode transfers.
26+
2027
endif # I2C_MAX32

drivers/i2c/i2c_max32.c

Lines changed: 220 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,10 @@
1212
#include <zephyr/drivers/clock_control/adi_max32_clock_control.h>
1313
#include <zephyr/irq.h>
1414

15+
#if defined(CONFIG_I2C_MAX32_DMA)
16+
#include <zephyr/drivers/dma.h>
17+
#endif /* CONFIG_I2C_MAX32_DMA */
18+
1519
#include <wrap_max32_i2c.h>
1620

1721
#define ADI_MAX32_I2C_INT_FL0_MASK 0x00FFFFFF
@@ -21,6 +25,14 @@
2125

2226
#define I2C_RECOVER_MAX_RETRIES 3
2327

28+
#ifdef CONFIG_I2C_MAX32_DMA
29+
struct max32_i2c_dma_config {
30+
const struct device *dev;
31+
const uint32_t channel;
32+
const uint32_t slot;
33+
};
34+
#endif /* CONFIG_I2C_MAX32_DMA */
35+
2436
/* Driver config */
2537
struct max32_i2c_config {
2638
mxc_i2c_regs_t *regs;
@@ -32,6 +44,10 @@ struct max32_i2c_config {
3244
uint8_t irqn;
3345
void (*irq_config_func)(const struct device *dev);
3446
#endif
47+
#ifdef CONFIG_I2C_MAX32_DMA
48+
struct max32_i2c_dma_config tx_dma;
49+
struct max32_i2c_dma_config rx_dma;
50+
#endif /* CONFIG_I2C_MAX32_DMA */
3551
};
3652

3753
struct max32_i2c_data {
@@ -46,7 +62,7 @@ struct max32_i2c_data {
4662
#endif /* CONFIG_I2C_TARGET */
4763
uint32_t readb;
4864
uint32_t written;
49-
#if defined(CONFIG_I2C_MAX32_INTERRUPT)
65+
#if defined(CONFIG_I2C_MAX32_INTERRUPT) || defined(CONFIG_I2C_MAX32_DMA)
5066
struct k_sem xfer;
5167
int err;
5268
#endif
@@ -266,6 +282,149 @@ static int i2c_max32_transfer_sync(mxc_i2c_regs_t *i2c, struct max32_i2c_data *d
266282
}
267283
#endif /* CONFIG_I2C_MAX32_INTERRUPT */
268284

285+
#if defined(CONFIG_I2C_MAX32_DMA)
286+
static void i2c_max32_dma_callback(const struct device *dev, void *arg, uint32_t channel,
287+
int status)
288+
{
289+
struct max32_i2c_data *data = arg;
290+
const struct device *i2c_dev = data->dev;
291+
const struct max32_i2c_config *const cfg = i2c_dev->config;
292+
293+
if (status < 0) {
294+
data->err = -EIO;
295+
} else {
296+
if (data->req.restart) {
297+
Wrap_MXC_I2C_Restart(cfg->regs);
298+
} else {
299+
Wrap_MXC_I2C_Stop(cfg->regs);
300+
}
301+
}
302+
}
303+
304+
static int i2c_max32_tx_dma_load(const struct device *dev, struct i2c_msg *msg)
305+
{
306+
int ret;
307+
const struct max32_i2c_config *config = dev->config;
308+
struct max32_i2c_data *data = dev->data;
309+
struct dma_config dma_cfg = {0};
310+
struct dma_block_config dma_blk = {0};
311+
312+
dma_cfg.channel_direction = MEMORY_TO_PERIPHERAL;
313+
dma_cfg.dma_callback = i2c_max32_dma_callback;
314+
dma_cfg.user_data = (void *)data;
315+
dma_cfg.dma_slot = config->tx_dma.slot;
316+
dma_cfg.block_count = 1;
317+
dma_cfg.source_data_size = 1U;
318+
dma_cfg.source_burst_length = 1U;
319+
dma_cfg.dest_data_size = 1U;
320+
dma_cfg.head_block = &dma_blk;
321+
dma_blk.block_size = msg->len;
322+
dma_blk.source_addr_adj = DMA_ADDR_ADJ_INCREMENT;
323+
dma_blk.source_address = (uint32_t)msg->buf;
324+
325+
ret = dma_config(config->tx_dma.dev, config->tx_dma.channel, &dma_cfg);
326+
if (ret < 0) {
327+
return ret;
328+
}
329+
330+
return dma_start(config->tx_dma.dev, config->tx_dma.channel);
331+
}
332+
333+
static int i2c_max32_rx_dma_load(const struct device *dev, struct i2c_msg *msg)
334+
{
335+
int ret;
336+
const struct max32_i2c_config *config = dev->config;
337+
struct max32_i2c_data *data = dev->data;
338+
struct dma_config dma_cfg = {0};
339+
struct dma_block_config dma_blk = {0};
340+
341+
dma_cfg.channel_direction = PERIPHERAL_TO_MEMORY;
342+
dma_cfg.dma_callback = i2c_max32_dma_callback;
343+
dma_cfg.user_data = (void *)data;
344+
dma_cfg.dma_slot = config->rx_dma.slot;
345+
dma_cfg.block_count = 1;
346+
dma_cfg.source_data_size = 1U;
347+
dma_cfg.source_burst_length = 1U;
348+
dma_cfg.dest_data_size = 1U;
349+
dma_cfg.head_block = &dma_blk;
350+
dma_blk.block_size = msg->len;
351+
dma_blk.dest_addr_adj = DMA_ADDR_ADJ_INCREMENT;
352+
dma_blk.dest_address = (uint32_t)msg->buf;
353+
354+
ret = dma_config(config->rx_dma.dev, config->rx_dma.channel, &dma_cfg);
355+
if (ret < 0) {
356+
return ret;
357+
}
358+
359+
return dma_start(config->rx_dma.dev, config->rx_dma.channel);
360+
}
361+
362+
static int i2c_max32_transfer_dma(const struct device *dev, struct i2c_msg *msgs, uint8_t num_msgs,
363+
uint16_t target_address)
364+
{
365+
int ret = 0;
366+
const struct max32_i2c_config *const cfg = dev->config;
367+
struct max32_i2c_data *data = dev->data;
368+
mxc_i2c_regs_t *i2c = cfg->regs;
369+
uint8_t target_rw;
370+
unsigned int i = 0;
371+
372+
k_sem_take(&data->lock, K_FOREVER);
373+
374+
MXC_I2C_SetRXThreshold(i2c, 1);
375+
MXC_I2C_SetTXThreshold(i2c, 2);
376+
MXC_I2C_ClearTXFIFO(i2c);
377+
MXC_I2C_ClearRXFIFO(i2c);
378+
379+
for (i = 0; i < num_msgs; i++) {
380+
data->req.restart = !(msgs[i].flags & I2C_MSG_STOP);
381+
if (msgs[i].flags & I2C_MSG_READ) {
382+
target_rw = (target_address << 1) | 0x1;
383+
MXC_I2C_WriteTXFIFO(i2c, &target_rw, 1);
384+
Wrap_MXC_I2C_SetRxCount(i2c, msgs[i].len);
385+
ret = i2c_max32_rx_dma_load(dev, &msgs[i]);
386+
if (ret < 0) {
387+
break;
388+
}
389+
390+
MXC_I2C_EnableInt(
391+
i2c, ADI_MAX32_I2C_INT_EN0_DONE | ADI_MAX32_I2C_INT_EN0_ERR, 0);
392+
i2c->dma |= ADI_MAX32_I2C_DMA_RX_EN;
393+
} else {
394+
target_rw = (target_address << 1) & ~0x1;
395+
MXC_I2C_WriteTXFIFO(i2c, &target_rw, 1);
396+
ret = i2c_max32_tx_dma_load(dev, &msgs[i]);
397+
if (ret < 0) {
398+
break;
399+
}
400+
401+
MXC_I2C_EnableInt(
402+
i2c, ADI_MAX32_I2C_INT_EN0_DONE | ADI_MAX32_I2C_INT_EN0_ERR, 0);
403+
i2c->dma |= ADI_MAX32_I2C_DMA_TX_EN;
404+
}
405+
data->err = 0;
406+
407+
Wrap_MXC_I2C_Start(i2c);
408+
ret = k_sem_take(&data->xfer, K_FOREVER);
409+
Wrap_MXC_I2C_SetIntEn(i2c, 0, 0);
410+
i2c->dma &= ~(ADI_MAX32_I2C_DMA_TX_EN | ADI_MAX32_I2C_DMA_RX_EN);
411+
412+
if (data->err) {
413+
ret = data->err;
414+
}
415+
if (ret) {
416+
MXC_I2C_Stop(i2c);
417+
dma_stop(cfg->tx_dma.dev, cfg->tx_dma.channel);
418+
dma_stop(cfg->rx_dma.dev, cfg->rx_dma.channel);
419+
}
420+
}
421+
422+
k_sem_give(&data->lock);
423+
424+
return ret;
425+
}
426+
#endif /* CONFIG_I2C_MAX32_DMA */
427+
269428
#ifdef CONFIG_I2C_MAX32_INTERRUPT
270429
static int i2c_max32_transfer(const struct device *dev, struct i2c_msg *msgs, uint8_t num_msgs,
271430
uint16_t target_address)
@@ -434,6 +593,13 @@ static int i2c_max32_transfer(const struct device *dev, struct i2c_msg *msgs, ui
434593
static int api_transfer(const struct device *dev, struct i2c_msg *msgs, uint8_t num_msgs,
435594
uint16_t target_address)
436595
{
596+
#if CONFIG_I2C_MAX32_DMA
597+
const struct max32_i2c_config *cfg = dev->config;
598+
599+
if ((cfg->tx_dma.channel != 0xFF) && (cfg->rx_dma.channel != 0xFF)) {
600+
return i2c_max32_transfer_dma(dev, msgs, num_msgs, target_address);
601+
}
602+
#endif
437603
return i2c_max32_transfer(dev, msgs, num_msgs, target_address);
438604
}
439605

@@ -615,6 +781,29 @@ static void i2c_max32_isr_controller(const struct device *dev, mxc_i2c_regs_t *i
615781
}
616782
#endif /* CONFIG_I2C_MAX32_INTERRUPT */
617783

784+
#ifdef CONFIG_I2C_MAX32_DMA
785+
static void i2c_max32_isr_controller_dma(const struct device *dev, mxc_i2c_regs_t *i2c)
786+
{
787+
struct max32_i2c_data *data = dev->data;
788+
uint32_t int_fl0, int_fl1;
789+
uint32_t int_en0, int_en1;
790+
791+
Wrap_MXC_I2C_GetIntEn(i2c, &int_en0, &int_en1);
792+
MXC_I2C_GetFlags(i2c, &int_fl0, &int_fl1);
793+
MXC_I2C_ClearFlags(i2c, ADI_MAX32_I2C_INT_FL0_MASK, ADI_MAX32_I2C_INT_FL1_MASK);
794+
795+
if (int_fl0 & ADI_MAX32_I2C_INT_FL0_ERR) {
796+
data->err = -EIO;
797+
Wrap_MXC_I2C_SetIntEn(i2c, 0, 0);
798+
k_sem_give(&data->xfer);
799+
} else {
800+
if (!data->err && (int_en0 & ADI_MAX32_I2C_INT_EN0_DONE)) {
801+
k_sem_give(&data->xfer);
802+
}
803+
}
804+
}
805+
#endif /* CONFIG_I2C_MAX32_DMA */
806+
618807
#if defined(CONFIG_I2C_TARGET) || defined(CONFIG_I2C_MAX32_INTERRUPT)
619808
static void i2c_max32_isr(const struct device *dev)
620809
{
@@ -624,6 +813,12 @@ static void i2c_max32_isr(const struct device *dev)
624813

625814
#ifdef CONFIG_I2C_MAX32_INTERRUPT
626815
if (data->target_mode == 0) {
816+
#ifdef CONFIG_I2C_MAX32_DMA
817+
if ((cfg->tx_dma.channel != 0xFF) && (cfg->rx_dma.channel != 0xFF)) {
818+
i2c_max32_isr_controller_dma(dev, i2c);
819+
return;
820+
}
821+
#endif
627822
i2c_max32_isr_controller(dev, i2c);
628823
return;
629824
}
@@ -713,6 +908,28 @@ static int i2c_max32_init(const struct device *dev)
713908
#define I2C_MAX32_IRQ_CONFIG_FUNC(n)
714909
#endif
715910

911+
#if CONFIG_I2C_MAX32_DMA
912+
#define MAX32_DT_INST_DMA_CTLR(n, name) \
913+
COND_CODE_1(DT_INST_NODE_HAS_PROP(n, dmas), \
914+
(DEVICE_DT_GET(DT_INST_DMAS_CTLR_BY_NAME(n, name))), (NULL))
915+
916+
#define MAX32_DT_INST_DMA_CELL(n, name, cell) \
917+
COND_CODE_1(DT_INST_NODE_HAS_PROP(n, dmas), (DT_INST_DMAS_CELL_BY_NAME(n, name, cell)), \
918+
(0xff))
919+
920+
#define MAX32_I2C_TX_DMA_INIT(n) \
921+
.tx_dma.dev = MAX32_DT_INST_DMA_CTLR(n, tx), \
922+
.tx_dma.channel = MAX32_DT_INST_DMA_CELL(n, tx, channel), \
923+
.tx_dma.slot = MAX32_DT_INST_DMA_CELL(n, tx, slot),
924+
#define MAX32_I2C_RX_DMA_INIT(n) \
925+
.rx_dma.dev = MAX32_DT_INST_DMA_CTLR(n, rx), \
926+
.rx_dma.channel = MAX32_DT_INST_DMA_CELL(n, rx, channel), \
927+
.rx_dma.slot = MAX32_DT_INST_DMA_CELL(n, rx, slot),
928+
#else
929+
#define MAX32_I2C_TX_DMA_INIT(n)
930+
#define MAX32_I2C_RX_DMA_INIT(n)
931+
#endif
932+
716933
#define DEFINE_I2C_MAX32(_num) \
717934
PINCTRL_DT_INST_DEFINE(_num); \
718935
I2C_MAX32_IRQ_CONFIG_FUNC(_num) \
@@ -723,7 +940,8 @@ static int i2c_max32_init(const struct device *dev)
723940
.perclk.bus = DT_INST_CLOCKS_CELL(_num, offset), \
724941
.perclk.bit = DT_INST_CLOCKS_CELL(_num, bit), \
725942
.bitrate = DT_INST_PROP(_num, clock_frequency), \
726-
I2C_MAX32_CONFIG_IRQ_FUNC(_num)}; \
943+
I2C_MAX32_CONFIG_IRQ_FUNC(_num) MAX32_I2C_TX_DMA_INIT(_num) \
944+
MAX32_I2C_RX_DMA_INIT(_num)}; \
727945
static struct max32_i2c_data max32_i2c_data_##_num; \
728946
I2C_DEVICE_DT_INST_DEFINE(_num, i2c_max32_init, NULL, &max32_i2c_data_##_num, \
729947
&max32_i2c_dev_cfg_##_num, PRE_KERNEL_2, \

0 commit comments

Comments
 (0)