Skip to content

Commit 4d1ccb1

Browse files
committed
drivers: dma: sam: implement finite state machine for DMA channel
Add state machine for config/start/stop/resume/suspend for DMA channels. Signed-off-by: Tony Han <[email protected]>
1 parent dbd8425 commit 4d1ccb1

File tree

1 file changed

+56
-0
lines changed

1 file changed

+56
-0
lines changed

drivers/dma/dma_sam_xdmac.c

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,11 +28,19 @@ LOG_MODULE_REGISTER(dma_sam_xdmac);
2828
#define XDMAC_INT_ERR (XDMAC_CIE_RBIE | XDMAC_CIE_WBIE | XDMAC_CIE_ROIE)
2929
#define DMA_CHANNELS_MAX 31
3030

31+
enum dma_state {
32+
DMA_STATE_INIT = 0,
33+
DMA_STATE_CONFIGURED,
34+
DMA_STATE_RUNNING,
35+
DMA_STATE_SUSPENDED,
36+
};
37+
3138
/* DMA channel configuration */
3239
struct sam_xdmac_channel_cfg {
3340
void *user_data;
3441
dma_callback_t callback;
3542
uint32_t data_size;
43+
enum dma_state state;
3644
};
3745

3846
/* Device constant configuration parameters */
@@ -68,6 +76,7 @@ static void sam_xdmac_isr(const struct device *dev)
6876
continue;
6977
}
7078

79+
dev_data->dma_channels[channel].state = DMA_STATE_CONFIGURED;
7180
channel_cfg = &dev_data->dma_channels[channel];
7281

7382
/* Get channel errors */
@@ -180,6 +189,8 @@ int sam_xdmac_transfer_configure(const struct device *dev, uint32_t channel,
180189
/* Set next descriptor configuration */
181190
xdmac->XDMAC_CHID[channel].XDMAC_CNDC = param->ndc;
182191

192+
dev_data->dma_channels[channel].state = DMA_STATE_CONFIGURED;
193+
183194
return 0;
184195
}
185196

@@ -199,6 +210,12 @@ static int sam_xdmac_config(const struct device *dev, uint32_t channel,
199210
return -EINVAL;
200211
}
201212

213+
if (dev_data->dma_channels[channel].state != DMA_STATE_INIT &&
214+
dev_data->dma_channels[channel].state != DMA_STATE_CONFIGURED) {
215+
LOG_ERR("Config Channel %d at invalidate state", channel);
216+
return -EINVAL;
217+
}
218+
202219
__ASSERT_NO_MSG(cfg->source_data_size == cfg->dest_data_size);
203220
__ASSERT_NO_MSG(cfg->source_burst_length == cfg->dest_burst_length);
204221

@@ -327,6 +344,12 @@ int sam_xdmac_transfer_start(const struct device *dev, uint32_t channel)
327344
return -EINVAL;
328345
}
329346

347+
if (dev_data->dma_channels[channel].state != DMA_STATE_CONFIGURED &&
348+
dev_data->dma_channels[channel].state != DMA_STATE_RUNNING) {
349+
LOG_ERR("Start Channel %d at invalidate state", channel);
350+
return -EINVAL;
351+
}
352+
330353
/* Check if the channel is enabled */
331354
if (xdmac->XDMAC_GS & (XDMAC_GS_ST0 << channel)) {
332355
LOG_DBG("Channel %d already enabled", channel);
@@ -338,6 +361,8 @@ int sam_xdmac_transfer_start(const struct device *dev, uint32_t channel)
338361
/* Enable channel */
339362
xdmac->XDMAC_GE = XDMAC_GE_EN0 << channel;
340363

364+
dev_data->dma_channels[channel].state = DMA_STATE_RUNNING;
365+
341366
return 0;
342367
}
343368

@@ -354,6 +379,11 @@ int sam_xdmac_transfer_stop(const struct device *dev, uint32_t channel)
354379
return -EINVAL;
355380
}
356381

382+
if (dev_data->dma_channels[channel].state == DMA_STATE_INIT) {
383+
LOG_ERR("Channel %d not configured", channel);
384+
return -EINVAL;
385+
}
386+
357387
/* Check if the channel is enabled */
358388
if (!(xdmac->XDMAC_GS & (XDMAC_GS_ST0 << channel))) {
359389
return 0;
@@ -368,6 +398,8 @@ int sam_xdmac_transfer_stop(const struct device *dev, uint32_t channel)
368398
/* Clear the pending Interrupt Status bit(s) */
369399
(void)xdmac->XDMAC_CHID[channel].XDMAC_CIS;
370400

401+
dev_data->dma_channels[channel].state = DMA_STATE_CONFIGURED;
402+
371403
return 0;
372404
}
373405

@@ -417,6 +449,16 @@ static int xdmac_suspend(const struct device *dev, uint32_t channel)
417449
return -EINVAL;
418450
}
419451

452+
switch (dev_data->dma_channels[channel].state) {
453+
case DMA_STATE_RUNNING:
454+
break;
455+
case DMA_STATE_SUSPENDED:
456+
return 0;
457+
default:
458+
LOG_ERR("Suspend Channel %d at invalidate state", channel);
459+
return -EINVAL;
460+
}
461+
420462
if (!(xdmac->XDMAC_GS & BIT(channel))) {
421463
LOG_DBG("Channel %d not enabled", channel);
422464
return -EINVAL;
@@ -435,6 +477,8 @@ static int xdmac_suspend(const struct device *dev, uint32_t channel)
435477

436478
xdmac->XDMAC_GRWS |= BIT(channel);
437479

480+
dev_data->dma_channels[channel].state = DMA_STATE_SUSPENDED;
481+
438482
return 0;
439483
}
440484

@@ -451,6 +495,16 @@ static int xdmac_resume(const struct device *dev, uint32_t channel)
451495
return -EINVAL;
452496
}
453497

498+
switch (dev_data->dma_channels[channel].state) {
499+
case DMA_STATE_SUSPENDED:
500+
break;
501+
case DMA_STATE_RUNNING:
502+
return 0;
503+
default:
504+
LOG_ERR("Resume Channel %d at invalidate state", channel);
505+
return -EINVAL;
506+
}
507+
454508
if (!(xdmac->XDMAC_GS & BIT(channel))) {
455509
LOG_DBG("Channel %d not enabled", channel);
456510
return -EINVAL;
@@ -469,6 +523,8 @@ static int xdmac_resume(const struct device *dev, uint32_t channel)
469523

470524
xdmac->XDMAC_GRWR |= BIT(channel);
471525

526+
dev_data->dma_channels[channel].state = DMA_STATE_RUNNING;
527+
472528
return 0;
473529
}
474530

0 commit comments

Comments
 (0)