Skip to content

Commit c1080f3

Browse files
hakehuanggalak
authored andcommitted
adc: adc dma driver
add dma support to adc driver add HW trigger dma support using new dma api to request dma channel tested on frdm_k82f and frdm_k64f Signed-off-by: Hake Huang <[email protected]>
1 parent d7edd37 commit c1080f3

File tree

2 files changed

+230
-15
lines changed

2 files changed

+230
-15
lines changed

drivers/adc/Kconfig.mcux

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,28 @@ config ADC_MCUX_ADC16_VREF_ALTERNATE
5353

5454
endchoice
5555

56+
config ADC_MCUX_ADC16_ENABLE_EDMA
57+
bool "Enable EDMA for adc driver"
58+
depends on HAS_MCUX_ADC16 && HAS_MCUX_EDMA
59+
help
60+
Enable the MCUX ADC16 driver.
61+
62+
if ADC_MCUX_ADC16_ENABLE_EDMA
63+
64+
config ADC_MCUX_ADC16_INIT_PRIORITY
65+
int "Init priority"
66+
default 70
67+
help
68+
Device driver initialization priority.
69+
70+
config ADC_MCUX_ADC16_HW_TRIGGER
71+
bool "ADC HW TRIGGER"
72+
default y
73+
help
74+
Support HW Trigger ADC
75+
76+
endif # ADC_MCUX_ADC16_ENABLE_EDMA
77+
5678
endif # ADC_MCUX_ADC16
5779

5880

drivers/adc/adc_mcux_adc16.c

Lines changed: 208 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2017-2018, NXP
2+
* Copyright (c) 2017-2018, 2020, NXP
33
*
44
* SPDX-License-Identifier: Apache-2.0
55
*/
@@ -8,6 +8,11 @@
88

99
#include <errno.h>
1010
#include <drivers/adc.h>
11+
#ifdef CONFIG_ADC_MCUX_ADC16_ENABLE_EDMA
12+
#include <drivers/dma.h>
13+
#include <fsl_sim.h>
14+
#endif
15+
1116
#include <fsl_adc16.h>
1217

1318
#define LOG_LEVEL CONFIG_ADC_LOG_LEVEL
@@ -19,19 +24,82 @@ LOG_MODULE_REGISTER(adc_mcux_adc16);
1924

2025
struct mcux_adc16_config {
2126
ADC_Type *base;
27+
#ifndef CONFIG_ADC_MCUX_ADC16_ENABLE_EDMA
2228
void (*irq_config_func)(const struct device *dev);
29+
#endif
30+
uint32_t clk_source; /* ADC clock source selection */
31+
uint32_t long_sample; /* ADC long sample mode selection */
32+
uint32_t hw_trigger_src; /* ADC hardware trigger source */
33+
/* defined in SIM module SOPT7 */
34+
#ifdef CONFIG_ADC_MCUX_ADC16_ENABLE_EDMA
35+
uint32_t dma_slot; /* ADC DMA MUX slot */
36+
#endif
37+
uint32_t trg_offset;
38+
uint32_t trg_bits;
39+
uint32_t alt_offset;
40+
uint32_t alt_bits;
41+
bool periodic_trigger; /* ADC enable periodic trigger */
2342
bool channel_mux_b;
43+
bool high_speed; /* ADC enable high speed mode*/
44+
bool continuous_convert; /* ADC enable continuous convert*/
2445
};
2546

47+
#ifdef CONFIG_ADC_MCUX_ADC16_ENABLE_EDMA
48+
struct adc_edma_config {
49+
int32_t state;
50+
uint32_t dma_channel;
51+
void (*irq_call_back)(void);
52+
struct dma_config dma_cfg;
53+
struct dma_block_config dma_block;
54+
};
55+
#endif
56+
2657
struct mcux_adc16_data {
2758
const struct device *dev;
2859
struct adc_context ctx;
60+
#ifdef CONFIG_ADC_MCUX_ADC16_ENABLE_EDMA
61+
const struct device *dev_dma;
62+
struct adc_edma_config adc_dma_config;
63+
#endif
2964
uint16_t *buffer;
3065
uint16_t *repeat_buffer;
3166
uint32_t channels;
3267
uint8_t channel_id;
3368
};
3469

70+
#define DEV_CFG(dev) ((const struct mcux_adc16_config *const)dev->config)
71+
#define DEV_DATA(dev) ((struct mcux_adc16_data *)dev->data)
72+
#define DEV_BASE(dev) ((ADC_Type *)DEV_CFG(dev)->base)
73+
74+
#ifdef CONFIG_ADC_MCUX_ADC16_HW_TRIGGER
75+
#define SIM_SOPT7_ADCSET(x, shifts, mask) \
76+
(((uint32_t)(((uint32_t)(x)) << shifts)) & mask)
77+
#endif
78+
79+
#ifdef CONFIG_ADC_MCUX_ADC16_ENABLE_EDMA
80+
static void adc_dma_callback(const struct device *dma_dev, void *callback_arg,
81+
uint32_t channel, int error_code)
82+
{
83+
struct device *dev = (struct device *)callback_arg;
84+
struct mcux_adc16_data *data = DEV_DATA(dev);
85+
86+
LOG_DBG("DMA done");
87+
adc_context_on_sampling_done(&data->ctx, dev);
88+
}
89+
#endif
90+
91+
#ifdef CONFIG_ADC_MCUX_ADC16_HW_TRIGGER
92+
static void adc_hw_trigger_enable(const struct device *dev)
93+
{
94+
const struct mcux_adc16_config *config = dev->config;
95+
96+
/* enable ADC trigger channel */
97+
SIM->SOPT7 |= SIM_SOPT7_ADCSET(config->hw_trigger_src,
98+
config->trg_offset, config->trg_bits) |
99+
SIM_SOPT7_ADCSET(1, config->alt_offset, config->alt_bits);
100+
}
101+
#endif
102+
35103
static int mcux_adc16_channel_setup(const struct device *dev,
36104
const struct adc_channel_cfg *channel_cfg)
37105
{
@@ -62,6 +130,10 @@ static int mcux_adc16_channel_setup(const struct device *dev,
62130
return -EINVAL;
63131
}
64132

133+
#ifdef CONFIG_ADC_MCUX_ADC16_HW_TRIGGER
134+
adc_hw_trigger_enable(dev);
135+
#endif
136+
65137
return 0;
66138
}
67139

@@ -89,7 +161,8 @@ static int start_read(const struct device *dev,
89161
case 13:
90162
resolution = kADC16_Resolution12or13Bit;
91163
break;
92-
#if defined(FSL_FEATURE_ADC16_MAX_RESOLUTION) && (FSL_FEATURE_ADC16_MAX_RESOLUTION >= 16U)
164+
#if defined(FSL_FEATURE_ADC16_MAX_RESOLUTION) && \
165+
(FSL_FEATURE_ADC16_MAX_RESOLUTION >= 16U)
93166
case 16:
94167
resolution = kADC16_Resolution16Bit;
95168
break;
@@ -130,6 +203,9 @@ static int start_read(const struct device *dev,
130203
adc_context_start_read(&data->ctx, sequence);
131204

132205
error = adc_context_wait_for_completion(&data->ctx);
206+
#ifdef CONFIG_ADC_MCUX_ADC16_ENABLE_EDMA
207+
dma_stop(data->dev_dma, data->adc_dma_config.dma_channel);
208+
#endif
133209
return error;
134210
}
135211

@@ -180,6 +256,11 @@ static void mcux_adc16_start_channel(const struct device *dev)
180256
channel_config.enableInterruptOnConversionCompleted = true;
181257
channel_config.channelNumber = data->channel_id;
182258
ADC16_SetChannelConfig(config->base, channel_group, &channel_config);
259+
#ifdef CONFIG_ADC_MCUX_ADC16_ENABLE_EDMA
260+
LOG_DBG("Starting EDMA");
261+
dma_start(data->dev_dma, data->adc_dma_config.dma_channel);
262+
#endif
263+
LOG_DBG("Starting channel done");
183264
}
184265

185266
static void adc_context_start_sampling(struct adc_context *ctx)
@@ -190,6 +271,17 @@ static void adc_context_start_sampling(struct adc_context *ctx)
190271
data->channels = ctx->sequence.channels;
191272
data->repeat_buffer = data->buffer;
192273

274+
#ifdef CONFIG_ADC_MCUX_ADC16_ENABLE_EDMA
275+
LOG_DBG("config dma");
276+
data->buffer = ctx->sequence.buffer;
277+
data->adc_dma_config.dma_block.block_size = ctx->sequence.buffer_size;
278+
data->adc_dma_config.dma_block.dest_address = (uint32_t)data->buffer;
279+
data->adc_dma_config.dma_cfg.head_block =
280+
&(data->adc_dma_config.dma_block);
281+
dma_config(data->dev_dma, data->adc_dma_config.dma_channel,
282+
&data->adc_dma_config.dma_cfg);
283+
#endif
284+
193285
mcux_adc16_start_channel(data->dev);
194286
}
195287

@@ -204,6 +296,7 @@ static void adc_context_update_buffer_pointer(struct adc_context *ctx,
204296
}
205297
}
206298

299+
#ifndef CONFIG_ADC_MCUX_ADC16_ENABLE_EDMA
207300
static void mcux_adc16_isr(const struct device *dev)
208301
{
209302
const struct mcux_adc16_config *config = dev->config;
@@ -213,8 +306,8 @@ static void mcux_adc16_isr(const struct device *dev)
213306
uint16_t result;
214307

215308
result = ADC16_GetChannelConversionValue(base, channel_group);
216-
LOG_DBG("Finished channel %d. Result is 0x%04x",
217-
data->channel_id, result);
309+
LOG_DBG("Finished channel %d. Result is 0x%04x", data->channel_id,
310+
result);
218311

219312
*data->buffer++ = result;
220313
data->channels &= ~BIT(data->channel_id);
@@ -225,6 +318,7 @@ static void mcux_adc16_isr(const struct device *dev)
225318
adc_context_on_sampling_done(&data->ctx, dev);
226319
}
227320
}
321+
#endif
228322

229323
static int mcux_adc16_init(const struct device *dev)
230324
{
@@ -233,8 +327,17 @@ static int mcux_adc16_init(const struct device *dev)
233327
ADC_Type *base = config->base;
234328
adc16_config_t adc_config;
235329

330+
LOG_DBG("init adc");
236331
ADC16_GetDefaultConfig(&adc_config);
237332

333+
#ifdef CONFIG_ADC_MCUX_ADC16_ENABLE_EDMA
334+
adc_config.clockSource = (adc16_clock_source_t)config->clk_source;
335+
adc_config.longSampleMode =
336+
(adc16_long_sample_mode_t)config->long_sample;
337+
adc_config.enableHighSpeed = config->high_speed;
338+
adc_config.enableContinuousConversion = config->continuous_convert;
339+
#endif
340+
238341
#if CONFIG_ADC_MCUX_ADC16_VREF_DEFAULT
239342
adc_config.referenceVoltageSource = kADC16_ReferenceVoltageSourceVref;
240343
#else /* CONFIG_ADC_MCUX_ADC16_VREF_ALTERNATE */
@@ -260,11 +363,60 @@ static int mcux_adc16_init(const struct device *dev)
260363
if (config->channel_mux_b) {
261364
ADC16_SetChannelMuxMode(base, kADC16_ChannelMuxB);
262365
}
263-
ADC16_EnableHardwareTrigger(base, false);
264366

265-
config->irq_config_func(dev);
367+
if (IS_ENABLED(CONFIG_ADC_MCUX_ADC16_HW_TRIGGER)) {
368+
ADC16_EnableHardwareTrigger(base, true);
369+
} else {
370+
ADC16_EnableHardwareTrigger(base, false);
371+
}
372+
266373
data->dev = dev;
267374

375+
/* dma related init */
376+
#ifdef CONFIG_ADC_MCUX_ADC16_ENABLE_EDMA
377+
/* Enable DMA. */
378+
ADC16_EnableDMA(base, true);
379+
380+
data->adc_dma_config.dma_cfg.block_count = 1U;
381+
data->adc_dma_config.dma_cfg.dma_slot = config->dma_slot;
382+
data->adc_dma_config.dma_cfg.channel_direction = PERIPHERAL_TO_MEMORY;
383+
data->adc_dma_config.dma_cfg.source_burst_length = 4U;
384+
data->adc_dma_config.dma_cfg.dest_burst_length = 4U;
385+
data->adc_dma_config.dma_cfg.channel_priority = 0U;
386+
data->adc_dma_config.dma_cfg.dma_callback = adc_dma_callback;
387+
data->adc_dma_config.dma_cfg.user_data = (void *)dev;
388+
389+
data->adc_dma_config.dma_cfg.source_data_size = 4U;
390+
data->adc_dma_config.dma_cfg.dest_data_size = 4U;
391+
data->adc_dma_config.dma_block.source_address = (uint32_t)&base->R[0];
392+
393+
394+
if (data->dev_dma == NULL || !device_is_ready(data->dev_dma)) {
395+
LOG_ERR("dma binding fail");
396+
return -EINVAL;
397+
}
398+
399+
if (config->periodic_trigger) {
400+
enum dma_channel_filter adc_filter = DMA_CHANNEL_PERIODIC;
401+
402+
data->adc_dma_config.dma_channel =
403+
dma_request_channel(data->dev_dma, (void *)&adc_filter);
404+
} else {
405+
enum dma_channel_filter adc_filter = DMA_CHANNEL_NORMAL;
406+
407+
data->adc_dma_config.dma_channel =
408+
dma_request_channel(data->dev_dma, (void *)&adc_filter);
409+
}
410+
if (data->adc_dma_config.dma_channel == -EINVAL) {
411+
LOG_ERR("can not allocate dma channel");
412+
return -EINVAL;
413+
}
414+
LOG_DBG("dma allocated channel %d", data->adc_dma_config.dma_channel);
415+
#else
416+
config->irq_config_func(dev);
417+
#endif
418+
LOG_INF("adc init done");
419+
268420
adc_context_unlock_unconditionally(&data->ctx);
269421

270422
return 0;
@@ -278,26 +430,66 @@ static const struct adc_driver_api mcux_adc16_driver_api = {
278430
#endif
279431
};
280432

281-
#define ACD16_MCUX_INIT(n) \
282-
static void mcux_adc16_config_func_##n(const struct device *dev); \
283-
\
433+
#ifdef CONFIG_ADC_MCUX_ADC16_ENABLE_EDMA
434+
#define ACD16_MCUX_INIT(n) \
284435
static const struct mcux_adc16_config mcux_adc16_config_##n = { \
285436
.base = (ADC_Type *)DT_INST_REG_ADDR(n), \
286-
.irq_config_func = mcux_adc16_config_func_##n, \
287437
.channel_mux_b = DT_INST_PROP(n, channel_mux_b), \
438+
.clk_source = DT_INST_PROP_OR(n, clk_source, 0), \
439+
.long_sample = DT_INST_PROP_OR(n, long_sample, 0), \
440+
.high_speed = DT_INST_PROP(n, high_speed), \
441+
.periodic_trigger = DT_INST_PROP(n, periodic_trigger), \
442+
.continuous_convert = \
443+
DT_INST_PROP(n, continuous_convert), \
444+
.hw_trigger_src = \
445+
DT_INST_PROP_OR(n, hw_trigger_src, 0), \
446+
.dma_slot = DT_INST_DMAS_CELL_BY_IDX(n, 0, source), \
447+
.trg_offset = DT_INST_CLOCKS_CELL_BY_IDX(n, 0, offset), \
448+
.trg_bits = DT_INST_CLOCKS_CELL_BY_IDX(n, 0, bits), \
449+
.alt_offset = DT_INST_CLOCKS_CELL_BY_IDX(n, 1, offset), \
450+
.alt_bits = DT_INST_CLOCKS_CELL_BY_IDX(n, 1, bits), \
288451
}; \
289452
\
290453
static struct mcux_adc16_data mcux_adc16_data_##n = { \
291454
ADC_CONTEXT_INIT_TIMER(mcux_adc16_data_##n, ctx), \
292455
ADC_CONTEXT_INIT_LOCK(mcux_adc16_data_##n, ctx), \
293456
ADC_CONTEXT_INIT_SYNC(mcux_adc16_data_##n, ctx), \
457+
.dev_dma = DEVICE_DT_GET(DT_INST_DMAS_CTLR_BY_NAME(n, adc##n)), \
458+
}; \
459+
\
460+
DEVICE_DT_INST_DEFINE(n, &mcux_adc16_init, \
461+
NULL, \
462+
&mcux_adc16_data_##n, \
463+
&mcux_adc16_config_##n, \
464+
POST_KERNEL, \
465+
CONFIG_ADC_MCUX_ADC16_INIT_PRIORITY, \
466+
&mcux_adc16_driver_api);
467+
#else
468+
#define ACD16_MCUX_INIT(n) \
469+
static void mcux_adc16_config_func_##n(const struct device *dev); \
470+
static const struct mcux_adc16_config mcux_adc16_config_##n = { \
471+
.base = (ADC_Type *)DT_INST_REG_ADDR(n), \
472+
.irq_config_func = mcux_adc16_config_func_##n, \
473+
.channel_mux_b = DT_INST_PROP(n, channel_mux_b), \
474+
.clk_source = DT_INST_PROP_OR(n, clk_source, 0), \
475+
.long_sample = DT_INST_PROP_OR(n, long_sample, 0), \
476+
.high_speed = DT_INST_PROP(n, high_speed), \
477+
.continuous_convert = \
478+
DT_INST_PROP(n, continuous_convert), \
479+
}; \
480+
static struct mcux_adc16_data mcux_adc16_data_##n = { \
481+
ADC_CONTEXT_INIT_TIMER(mcux_adc16_data_##n, ctx), \
482+
ADC_CONTEXT_INIT_LOCK(mcux_adc16_data_##n, ctx), \
483+
ADC_CONTEXT_INIT_SYNC(mcux_adc16_data_##n, ctx), \
294484
}; \
295485
\
296-
DEVICE_DT_INST_DEFINE(n, &mcux_adc16_init, \
297-
NULL, &mcux_adc16_data_##n, \
298-
&mcux_adc16_config_##n, POST_KERNEL, \
299-
CONFIG_KERNEL_INIT_PRIORITY_DEVICE, \
300-
&mcux_adc16_driver_api); \
486+
DEVICE_DT_INST_DEFINE(n, &mcux_adc16_init, \
487+
NULL, \
488+
&mcux_adc16_data_##n, \
489+
&mcux_adc16_config_##n, \
490+
POST_KERNEL, \
491+
CONFIG_KERNEL_INIT_PRIORITY_DEVICE, \
492+
&mcux_adc16_driver_api); \
301493
\
302494
static void mcux_adc16_config_func_##n(const struct device *dev) \
303495
{ \
@@ -307,5 +499,6 @@ static const struct adc_driver_api mcux_adc16_driver_api = {
307499
\
308500
irq_enable(DT_INST_IRQN(n)); \
309501
}
502+
#endif
310503

311504
DT_INST_FOREACH_STATUS_OKAY(ACD16_MCUX_INIT)

0 commit comments

Comments
 (0)