9
9
#include <zephyr/drivers/adc.h>
10
10
#include <zephyr/drivers/clock_control.h>
11
11
#include <zephyr/drivers/clock_control/clock_control_silabs.h>
12
+ #include <zephyr/drivers/dma.h>
13
+ #include <zephyr/drivers/dma/dma_silabs_ldma.h>
12
14
#include <zephyr/drivers/pinctrl.h>
13
15
#include <zephyr/logging/log.h>
14
16
#include <zephyr/pm/device.h>
@@ -24,6 +26,15 @@ LOG_MODULE_REGISTER(iadc, CONFIG_ADC_LOG_LEVEL);
24
26
#define IADC_PORT_MASK 0xF0
25
27
#define IADC_PIN_MASK 0x0F
26
28
29
+ struct iadc_dma_channel {
30
+ const struct device * dma_dev ;
31
+ int dma_channel ;
32
+ struct dma_block_config blk_cfg ;
33
+ struct dma_config dma_cfg ;
34
+ uint32_t offset ;
35
+ bool enabled ;
36
+ };
37
+
27
38
struct iadc_chan_conf {
28
39
sl_hal_iadc_analog_gain_t gain ;
29
40
sl_hal_iadc_voltage_reference_t reference ;
@@ -44,6 +55,7 @@ struct iadc_data {
44
55
uint32_t channels ;
45
56
uint8_t adc_config_count ; /* Number of ADC configs created (max 2) */
46
57
struct iadc_chan_conf chan_conf [SL_HAL_IADC_CHANNEL_ID_MAX - 1 ];
58
+ struct iadc_dma_channel dma ;
47
59
};
48
60
49
61
struct iadc_config {
@@ -97,6 +109,115 @@ static void iadc_configure_scan_table_entry(sl_hal_iadc_scan_table_entry_t *entr
97
109
};
98
110
}
99
111
112
+ #ifdef CONFIG_ADC_SILABS_IADC_DMA
113
+ static int iadc_dma_init (const struct device * dev )
114
+ {
115
+ const struct iadc_config * config = dev -> config ;
116
+ struct iadc_data * data = dev -> data ;
117
+ struct iadc_dma_channel * dma = & data -> dma ;
118
+
119
+ if (dma -> dma_dev ) {
120
+ if (!device_is_ready (dma -> dma_dev )) {
121
+ LOG_ERR ("DMA device not ready" );
122
+ return - ENODEV ;
123
+ }
124
+
125
+ dma -> dma_channel = dma_request_channel (dma -> dma_dev , NULL );
126
+ if (dma -> dma_channel < 0 ) {
127
+ LOG_ERR ("Failed to request DMA channel" );
128
+ return - ENODEV ;
129
+ }
130
+ }
131
+
132
+ /* Configure DMA block */
133
+ memset (& dma -> blk_cfg , 0 , sizeof (dma -> blk_cfg ));
134
+ dma -> blk_cfg .source_address = (uintptr_t )& ((IADC_TypeDef * )config -> base )-> SCANFIFODATA ;
135
+ dma -> blk_cfg .dest_address = 0 ;
136
+ dma -> blk_cfg .source_addr_adj = DMA_ADDR_ADJ_NO_CHANGE ;
137
+ dma -> blk_cfg .dest_addr_adj = DMA_ADDR_ADJ_INCREMENT ;
138
+ dma -> blk_cfg .block_size = 0 ;
139
+ dma -> dma_cfg .complete_callback_en = 1 ;
140
+ dma -> dma_cfg .channel_priority = 3 ;
141
+ dma -> dma_cfg .channel_direction = PERIPHERAL_TO_MEMORY ;
142
+ dma -> dma_cfg .head_block = & dma -> blk_cfg ;
143
+ dma -> dma_cfg .user_data = data ;
144
+
145
+ return 0 ;
146
+ }
147
+
148
+ static int iadc_dma_start (const struct device * dev )
149
+ {
150
+ struct iadc_data * data = dev -> data ;
151
+ struct iadc_dma_channel * dma = & data -> dma ;
152
+ int ret ;
153
+
154
+ if (!dma -> dma_dev ) {
155
+ return - ENODEV ;
156
+ }
157
+
158
+ if (dma -> enabled ) {
159
+ LOG_WRN ("DMA was already enabled for IADC" );
160
+ return - EBUSY ;
161
+ }
162
+
163
+ /* Configure DMA channel */
164
+ ret = dma_config (dma -> dma_dev , dma -> dma_channel , & dma -> dma_cfg );
165
+ if (ret ) {
166
+ LOG_ERR ("DMA config error: %d" , ret );
167
+ return ret ;
168
+ }
169
+
170
+ dma -> enabled = true;
171
+
172
+ /* Start DMA transfer */
173
+ ret = dma_start (dma -> dma_dev , dma -> dma_channel );
174
+ if (ret ) {
175
+ LOG_ERR ("DMA start error: %d" , ret );
176
+ dma -> enabled = false;
177
+ return ret ;
178
+ }
179
+
180
+ LOG_DBG ("DMA transfer started" );
181
+
182
+ return 0 ;
183
+ }
184
+
185
+ static void iadc_dma_stop (const struct device * dev )
186
+ {
187
+ struct iadc_data * data = dev -> data ;
188
+ struct iadc_dma_channel * dma = & data -> dma ;
189
+
190
+ if (!dma -> enabled ) {
191
+ return ;
192
+ }
193
+
194
+ /* Stop DMA transfer */
195
+ dma_stop (dma -> dma_dev , dma -> dma_channel );
196
+
197
+ dma -> enabled = false;
198
+
199
+ LOG_DBG ("DMA transfer stopped" );
200
+ }
201
+
202
+ static void iadc_dma_cb (const struct device * dma_dev , void * user_data , uint32_t channel , int status )
203
+ {
204
+ struct iadc_data * data = user_data ;
205
+ const struct device * dev = data -> dev ;
206
+
207
+ if (status < 0 ) {
208
+ LOG_ERR ("DMA transfer error: %d" , status );
209
+ adc_context_complete (& data -> ctx , status );
210
+ return ;
211
+ }
212
+
213
+ iadc_dma_stop (dev );
214
+
215
+ adc_context_on_sampling_done (& data -> ctx , dev );
216
+
217
+ LOG_DBG ("DMA transfer completed" );
218
+ }
219
+ #endif
220
+
100
221
static void iadc_set_config (const struct device * dev )
101
222
{
102
223
sl_hal_iadc_scan_table_t scanTable = SL_HAL_IADC_SCANTABLE_DEFAULT ;
@@ -107,6 +228,12 @@ static void iadc_set_config(const struct device *dev)
107
228
struct iadc_data * data = dev -> data ;
108
229
struct iadc_chan_conf * chan_conf ;
109
230
231
+ if (data -> dma .dma_dev ) {
232
+ scanInit .data_valid_level = SL_HAL_IADC_DATA_VALID_1 ;
233
+ /* Only needed to wake up DMA if EM is 2/3 */
234
+ scanInit .fifo_dma_wakeup = true;
235
+ }
236
+
110
237
data -> adc_config_count = 0 ;
111
238
112
239
/*
@@ -221,6 +348,14 @@ static int start_read(const struct device *dev, const struct adc_sequence *seque
221
348
222
349
data -> buffer = sequence -> buffer ;
223
350
351
+ if (data -> dma .dma_dev ) {
352
+ /* Need to take care that it will copy 16 bit data and not only 12 bit of the result
353
+ */
354
+ data -> dma .blk_cfg .dest_address = (uintptr_t )data -> buffer ;
355
+ data -> dma .blk_cfg .block_size = channel_count * sizeof (uint16_t );
356
+ data -> dma .offset = 0 ;
357
+ }
358
+
224
359
adc_context_start_read (& data -> ctx , sequence );
225
360
226
361
res = adc_context_wait_for_completion (& data -> ctx );
@@ -238,7 +373,16 @@ static void iadc_start_channel(const struct device *dev)
238
373
239
374
iadc_set_config (data -> dev );
240
375
376
+ #ifdef CONFIG_ADC_SILABS_IADC_DMA
377
+ if (data -> dma .dma_dev ) {
378
+ data -> dma .blk_cfg .dest_address = (uintptr_t )data -> buffer + data -> dma .offset ;
379
+ iadc_dma_start (dev );
380
+ } else {
381
+ sl_hal_iadc_enable_interrupts (iadc , IADC_IEN_SCANTABLEDONE );
382
+ }
383
+ #else
241
384
sl_hal_iadc_enable_interrupts (iadc , IADC_IEN_SCANTABLEDONE );
385
+ #endif
242
386
243
387
sl_hal_iadc_start_scan (iadc );
244
388
}
@@ -259,6 +403,9 @@ static void adc_context_update_buffer_pointer(struct adc_context *ctx, bool repe
259
403
260
404
if (repeat_sampling ) {
261
405
data -> buffer = data -> repeat_buffer ;
406
+ data -> dma .offset = 0 ;
407
+ } else {
408
+ data -> dma .offset = data -> dma .blk_cfg .block_size * (data -> ctx .sampling_index );
262
409
}
263
410
}
264
411
@@ -445,11 +592,18 @@ static int iadc_init(const struct device *dev)
445
592
}
446
593
447
594
ret = clock_control_get_rate (config -> clock_dev , (clock_control_subsys_t )& config -> clock_cfg ,
448
- & data -> clock_rate );
595
+ & data -> clock_rate );
449
596
if (ret < 0 ) {
450
597
return ret ;
451
598
}
452
599
600
+ #ifdef CONFIG_ADC_SILABS_IADC_DMA
601
+ ret = iadc_dma_init (dev );
602
+ if (ret < 0 ) {
603
+ data -> dma .dma_dev = NULL ;
604
+ }
605
+ #endif
606
+
453
607
config -> irq_cfg_func ();
454
608
455
609
adc_context_unlock_unconditionally (& data -> ctx );
@@ -466,6 +620,24 @@ static DEVICE_API(adc, iadc_api) = {
466
620
.ref_internal = SL_HAL_IADC_DEFAULT_VREF ,
467
621
};
468
622
623
+ #ifdef CONFIG_ADC_SILABS_IADC_DMA
624
+ #define IADC_DMA_CHANNEL_INIT (n ) \
625
+ .dma = {.dma_dev = DEVICE_DT_GET(DT_INST_DMAS_CTLR(n)), \
626
+ .dma_cfg = { \
627
+ .dma_slot = \
628
+ SILABS_LDMA_REQSEL_TO_SLOT(DT_INST_DMAS_CELL_BY_IDX(n, 0, slot)), \
629
+ .source_data_size = 2, \
630
+ .dest_data_size = 2, \
631
+ .source_burst_length = 2, \
632
+ .dest_burst_length = 2, \
633
+ .dma_callback = iadc_dma_cb, \
634
+ }},
635
+ #define IADC_DMA_CHANNEL (n ) COND_CODE_1(DT_INST_NODE_HAS_PROP(n, dmas), \
636
+ (IADC_DMA_CHANNEL_INIT(n)), ())
637
+ #else
638
+ #define IADC_DMA_CHANNEL (n )
639
+ #endif
640
+
469
641
#define IADC_INIT (n ) \
470
642
PINCTRL_DT_INST_DEFINE(n); \
471
643
PM_DEVICE_DT_INST_DEFINE(n, iadc_pm_action); \
@@ -483,7 +655,7 @@ static DEVICE_API(adc, iadc_api) = {
483
655
static struct iadc_data iadc_data_##n = {ADC_CONTEXT_INIT_TIMER(iadc_data_##n, ctx), \
484
656
ADC_CONTEXT_INIT_LOCK(iadc_data_##n, ctx), \
485
657
ADC_CONTEXT_INIT_SYNC(iadc_data_##n, ctx), \
486
- }; \
658
+ IADC_DMA_CHANNEL(n)}; \
487
659
\
488
660
static void iadc_config_func_##n(void) \
489
661
{ \
0 commit comments