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>
@@ -45,6 +47,14 @@ LOG_MODULE_REGISTER(iadc, CONFIG_ADC_LOG_LEVEL);
45
47
#define IADC_PORT_MASK 0xF0
46
48
#define IADC_PIN_MASK 0x0F
47
49
50
+ struct iadc_dma_channel {
51
+ const struct device * dma_dev ;
52
+ struct dma_block_config blk_cfg ;
53
+ struct dma_config dma_cfg ;
54
+ int dma_channel ;
55
+ bool enabled ;
56
+ };
57
+
48
58
struct iadc_chan_conf {
49
59
sl_hal_iadc_analog_gain_t gain ;
50
60
sl_hal_iadc_voltage_reference_t reference ;
@@ -60,6 +70,7 @@ struct iadc_data {
60
70
const struct device * dev ;
61
71
struct adc_context ctx ;
62
72
struct iadc_chan_conf chan_conf [SL_HAL_IADC_CHANNEL_ID_MAX ];
73
+ struct iadc_dma_channel dma ;
63
74
uint8_t adc_config_count ; /* Number of ADC configs created (max 2) */
64
75
uint32_t clock_rate ;
65
76
uint32_t channels ;
@@ -122,6 +133,212 @@ static void iadc_configure_scan_table_entry(sl_hal_iadc_scan_table_entry_t *entr
122
133
};
123
134
}
124
135
136
+ #ifdef CONFIG_ADC_SILABS_IADC_DMA
137
+ static int iadc_dma_init (const struct device * dev )
138
+ {
139
+ const struct iadc_config * config = dev -> config ;
140
+ struct iadc_data * data = dev -> data ;
141
+ struct iadc_dma_channel * dma = & data -> dma ;
142
+
143
+ if (dma -> dma_dev ) {
144
+ if (!device_is_ready (dma -> dma_dev )) {
145
+ LOG_ERR ("DMA device not ready" );
146
+ return - ENODEV ;
147
+ }
148
+
149
+ dma -> dma_channel = dma_request_channel (dma -> dma_dev , NULL );
150
+ if (dma -> dma_channel < 0 ) {
151
+ LOG_ERR ("Failed to request DMA channel" );
152
+ return - ENODEV ;
153
+ }
154
+ }
155
+
156
+ memset (& dma -> blk_cfg , 0 , sizeof (dma -> blk_cfg ));
157
+ dma -> blk_cfg .source_address = (uintptr_t )& (config -> base )-> SCANFIFODATA ;
158
+ dma -> blk_cfg .source_addr_adj = DMA_ADDR_ADJ_NO_CHANGE ;
159
+ dma -> blk_cfg .dest_addr_adj = DMA_ADDR_ADJ_INCREMENT ;
160
+ dma -> dma_cfg .complete_callback_en = 1 ;
161
+ dma -> dma_cfg .channel_priority = 3 ;
162
+ dma -> dma_cfg .channel_direction = PERIPHERAL_TO_MEMORY ;
163
+ dma -> dma_cfg .head_block = & dma -> blk_cfg ;
164
+ dma -> dma_cfg .user_data = data ;
165
+
166
+ return 0 ;
167
+ }
168
+
169
+ static int iadc_dma_start (const struct device * dev )
170
+ {
171
+ struct iadc_data * data = dev -> data ;
172
+ struct iadc_dma_channel * dma = & data -> dma ;
173
+ int ret ;
174
+
175
+ if (!dma -> dma_dev ) {
176
+ return - ENODEV ;
177
+ }
178
+
179
+ if (dma -> enabled ) {
180
+ return - EBUSY ;
181
+ }
182
+
183
+ ret = dma_config (dma -> dma_dev , dma -> dma_channel , & dma -> dma_cfg );
184
+ if (ret ) {
185
+ LOG_ERR ("DMA config error: %d" , ret );
186
+ return ret ;
187
+ }
188
+
189
+ dma -> enabled = true;
190
+
191
+ ret = dma_start (dma -> dma_dev , dma -> dma_channel );
192
+ if (ret ) {
193
+ LOG_ERR ("DMA start error: %d" , ret );
194
+ dma -> enabled = false;
195
+ return ret ;
196
+ }
197
+
198
+ return 0 ;
199
+ }
200
+
201
+ static void iadc_dma_stop (const struct device * dev )
202
+ {
203
+ struct iadc_data * data = dev -> data ;
204
+ struct iadc_dma_channel * dma = & data -> dma ;
205
+
206
+ if (!dma -> enabled ) {
207
+ return ;
208
+ }
209
+
210
+ dma_stop (dma -> dma_dev , dma -> dma_channel );
211
+
212
+ dma -> enabled = false;
213
+ }
214
+
215
+ static void iadc_dma_cb (const struct device * dma_dev , void * user_data , uint32_t channel , int status )
216
+ {
217
+ struct iadc_data * data = user_data ;
218
+ const struct device * dev = data -> dev ;
219
+ uint8_t * sample_ptr ;
220
+
221
+ if (status < 0 ) {
222
+ LOG_ERR ("DMA transfer error: %d" , status );
223
+ adc_context_complete (& data -> ctx , status );
224
+ return ;
225
+ }
226
+
227
+ /* Apply data mask */
228
+ for (int i = 0 ; i < data -> active_channels ; i ++ ) {
229
+ sample_ptr = data -> buffer + (i * data -> data_size );
230
+
231
+ if (data -> data_size == sizeof (uint32_t )) {
232
+ uint32_t * sample_32 = (uint32_t * )sample_ptr ;
233
+ * sample_32 = * sample_32 & data -> data_mask ;
234
+ } else {
235
+ uint16_t * sample_16 = (uint16_t * )sample_ptr ;
236
+ * sample_16 = * sample_16 & data -> data_mask ;
237
+ }
238
+ }
239
+
240
+ iadc_dma_stop (dev );
241
+
242
+ adc_context_on_sampling_done (& data -> ctx , dev );
243
+ }
244
+ #endif
245
+
246
+ #ifdef CONFIG_ADC_SILABS_IADC_DMA
247
+ static int iadc_dma_init (const struct device * dev )
248
+ {
249
+ const struct iadc_config * config = dev -> config ;
250
+ struct iadc_data * data = dev -> data ;
251
+ struct iadc_dma_channel * dma = & data -> dma ;
252
+
253
+ if (dma -> dma_dev ) {
254
+ if (!device_is_ready (dma -> dma_dev )) {
255
+ LOG_ERR ("DMA device not ready" );
256
+ return - ENODEV ;
257
+ }
258
+
259
+ dma -> dma_channel = dma_request_channel (dma -> dma_dev , NULL );
260
+ if (dma -> dma_channel < 0 ) {
261
+ LOG_ERR ("Failed to request DMA channel" );
262
+ return - ENODEV ;
263
+ }
264
+ }
265
+
266
+ memset (& dma -> blk_cfg , 0 , sizeof (dma -> blk_cfg ));
267
+ dma -> blk_cfg .source_address = (uintptr_t )& ((IADC_TypeDef * )config -> base )-> SCANFIFODATA ;
268
+ dma -> blk_cfg .source_addr_adj = DMA_ADDR_ADJ_NO_CHANGE ;
269
+ dma -> blk_cfg .dest_addr_adj = DMA_ADDR_ADJ_INCREMENT ;
270
+ dma -> dma_cfg .complete_callback_en = 1 ;
271
+ dma -> dma_cfg .channel_priority = 3 ;
272
+ dma -> dma_cfg .channel_direction = PERIPHERAL_TO_MEMORY ;
273
+ dma -> dma_cfg .head_block = & dma -> blk_cfg ;
274
+ dma -> dma_cfg .user_data = data ;
275
+
276
+ return 0 ;
277
+ }
278
+
279
+ static int iadc_dma_start (const struct device * dev )
280
+ {
281
+ struct iadc_data * data = dev -> data ;
282
+ struct iadc_dma_channel * dma = & data -> dma ;
283
+ int ret ;
284
+
285
+ if (!dma -> dma_dev ) {
286
+ return - ENODEV ;
287
+ }
288
+
289
+ if (dma -> enabled ) {
290
+ return - EBUSY ;
291
+ }
292
+
293
+ ret = dma_config (dma -> dma_dev , dma -> dma_channel , & dma -> dma_cfg );
294
+ if (ret ) {
295
+ LOG_ERR ("DMA config error: %d" , ret );
296
+ return ret ;
297
+ }
298
+
299
+ dma -> enabled = true;
300
+
301
+ ret = dma_start (dma -> dma_dev , dma -> dma_channel );
302
+ if (ret ) {
303
+ LOG_ERR ("DMA start error: %d" , ret );
304
+ dma -> enabled = false;
305
+ return ret ;
306
+ }
307
+
308
+ return 0 ;
309
+ }
310
+
311
+ static void iadc_dma_stop (const struct device * dev )
312
+ {
313
+ struct iadc_data * data = dev -> data ;
314
+ struct iadc_dma_channel * dma = & data -> dma ;
315
+
316
+ if (!dma -> enabled ) {
317
+ return ;
318
+ }
319
+
320
+ dma_stop (dma -> dma_dev , dma -> dma_channel );
321
+
322
+ dma -> enabled = false;
323
+ }
324
+
325
+ static void iadc_dma_cb (const struct device * dma_dev , void * user_data , uint32_t channel , int status )
326
+ {
327
+ struct iadc_data * data = user_data ;
328
+ const struct device * dev = data -> dev ;
329
+
330
+ if (status < 0 ) {
331
+ LOG_ERR ("DMA transfer error: %d" , status );
332
+ adc_context_complete (& data -> ctx , status );
333
+ return ;
334
+ }
335
+
336
+ iadc_dma_stop (dev );
337
+
338
+ adc_context_on_sampling_done (& data -> ctx , dev );
339
+ }
340
+ #endif
341
+
125
342
/* Oversampling and resolution are common for both ADC configs
126
343
* because they are not configurable per channel inside a ADC
127
344
* sequence and are common for a sequence.
@@ -152,8 +369,28 @@ static int iadc_set_config(const struct device *dev)
152
369
uint32_t channels ;
153
370
int res ;
154
371
372
+ if (data -> dma .dma_dev ) {
373
+ scan_init .data_valid_level = _IADC_SCANFIFOCFG_DVL_VALID1 ;
374
+ /* Only needed to wake up DMA if EM is 2/3 */
375
+ scan_init .fifo_dma_wakeup = true;
376
+ }
377
+
155
378
data -> adc_config_count = 0 ;
156
379
380
+ if (data -> dma .dma_dev ) {
381
+ if (data -> alignment == _IADC_SCANFIFOCFG_ALIGNMENT_RIGHT20 ) {
382
+ data -> dma .dma_cfg .source_data_size = 4 ;
383
+ data -> dma .dma_cfg .dest_data_size = 4 ;
384
+ data -> dma .dma_cfg .source_burst_length = 4 ;
385
+ data -> dma .dma_cfg .dest_burst_length = 4 ;
386
+ } else {
387
+ data -> dma .dma_cfg .source_data_size = 2 ;
388
+ data -> dma .dma_cfg .dest_data_size = 2 ;
389
+ data -> dma .dma_cfg .source_burst_length = 2 ;
390
+ data -> dma .dma_cfg .dest_burst_length = 2 ;
391
+ }
392
+ }
393
+
157
394
channels = data -> channels ;
158
395
159
396
/*
@@ -415,6 +652,12 @@ static int start_read(const struct device *dev, const struct adc_sequence *seque
415
652
data -> buffer = sequence -> buffer ;
416
653
data -> active_channels = channel_count ;
417
654
655
+
656
+ if (data -> dma .dma_dev ) {
657
+ data -> dma .blk_cfg .dest_address = (uintptr_t )data -> buffer ;
658
+ data -> dma .blk_cfg .block_size = channel_count * data -> data_size ;
659
+ }
660
+
418
661
data -> channels = sequence -> channels ;
419
662
420
663
res = iadc_set_config (data -> dev );
@@ -432,9 +675,19 @@ static int start_read(const struct device *dev, const struct adc_sequence *seque
432
675
static void iadc_start_scan (const struct device * dev )
433
676
{
434
677
const struct iadc_config * config = dev -> config ;
678
+ __maybe_unused struct iadc_data * data = dev -> data ;
435
679
IADC_TypeDef * iadc = (IADC_TypeDef * )config -> base ;
436
680
681
+ #ifdef CONFIG_ADC_SILABS_IADC_DMA
682
+ if (data -> dma .dma_dev ) {
683
+ data -> dma .blk_cfg .dest_address = (uintptr_t )data -> buffer ;
684
+ iadc_dma_start (dev );
685
+ } else {
686
+ sl_hal_iadc_enable_interrupts (iadc , IADC_IEN_SCANTABLEDONE );
687
+ }
688
+ #else
437
689
sl_hal_iadc_enable_interrupts (iadc , IADC_IEN_SCANTABLEDONE );
690
+ #endif
438
691
439
692
sl_hal_iadc_start_scan (iadc );
440
693
}
@@ -648,6 +901,13 @@ static int iadc_init(const struct device *dev)
648
901
return ret ;
649
902
}
650
903
904
+ #ifdef CONFIG_ADC_SILABS_IADC_DMA
905
+ ret = iadc_dma_init (dev );
906
+ if (ret < 0 ) {
907
+ data -> dma .dma_dev = NULL ;
908
+ }
909
+ #endif
910
+
651
911
config -> irq_cfg_func ();
652
912
653
913
adc_context_unlock_unconditionally (& data -> ctx );
@@ -664,6 +924,20 @@ static DEVICE_API(adc, iadc_api) = {
664
924
.ref_internal = SL_HAL_IADC_DEFAULT_VREF ,
665
925
};
666
926
927
+ #ifdef CONFIG_ADC_SILABS_IADC_DMA
928
+ #define IADC_DMA_CHANNEL_INIT (n ) \
929
+ .dma = {.dma_dev = DEVICE_DT_GET(DT_INST_DMAS_CTLR(n)), \
930
+ .dma_cfg = { \
931
+ .dma_slot = \
932
+ SILABS_LDMA_REQSEL_TO_SLOT(DT_INST_DMAS_CELL_BY_IDX(n, 0, slot)), \
933
+ .dma_callback = iadc_dma_cb, \
934
+ }},
935
+ #define IADC_DMA_CHANNEL (n ) COND_CODE_1(DT_INST_NODE_HAS_PROP(n, dmas), \
936
+ (IADC_DMA_CHANNEL_INIT(n)), ())
937
+ #else
938
+ #define IADC_DMA_CHANNEL (n )
939
+ #endif
940
+
667
941
#define IADC_INIT (n ) \
668
942
PINCTRL_DT_INST_DEFINE(n); \
669
943
PM_DEVICE_DT_INST_DEFINE(n, iadc_pm_action); \
@@ -681,7 +955,7 @@ static DEVICE_API(adc, iadc_api) = {
681
955
static struct iadc_data iadc_data_##n = {ADC_CONTEXT_INIT_TIMER(iadc_data_##n, ctx), \
682
956
ADC_CONTEXT_INIT_LOCK(iadc_data_##n, ctx), \
683
957
ADC_CONTEXT_INIT_SYNC(iadc_data_##n, ctx), \
684
- }; \
958
+ IADC_DMA_CHANNEL(n)}; \
685
959
\
686
960
static void iadc_config_func_##n(void) \
687
961
{ \
0 commit comments