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 ;
@@ -119,6 +130,104 @@ static void iadc_configure_scan_table_entry(sl_hal_iadc_scan_table_entry_t *entr
119
130
};
120
131
}
121
132
133
+ #ifdef CONFIG_ADC_SILABS_IADC_DMA
134
+ static int iadc_dma_init (const struct device * dev )
135
+ {
136
+ const struct iadc_config * config = dev -> config ;
137
+ struct iadc_data * data = dev -> data ;
138
+ struct iadc_dma_channel * dma = & data -> dma ;
139
+
140
+ if (!dma -> dma_dev ) {
141
+ return 0 ;
142
+ }
143
+
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
+ memset (& dma -> blk_cfg , 0 , sizeof (dma -> blk_cfg ));
156
+ dma -> blk_cfg .source_address = (uintptr_t )& (config -> base )-> SCANFIFODATA ;
157
+ dma -> blk_cfg .source_addr_adj = DMA_ADDR_ADJ_NO_CHANGE ;
158
+ dma -> blk_cfg .dest_addr_adj = DMA_ADDR_ADJ_INCREMENT ;
159
+ dma -> dma_cfg .complete_callback_en = 1 ;
160
+ dma -> dma_cfg .channel_priority = 3 ;
161
+ dma -> dma_cfg .channel_direction = PERIPHERAL_TO_MEMORY ;
162
+ dma -> dma_cfg .head_block = & dma -> blk_cfg ;
163
+ dma -> dma_cfg .user_data = data ;
164
+
165
+ return 0 ;
166
+ }
167
+
168
+ static int iadc_dma_start (const struct device * dev )
169
+ {
170
+ struct iadc_data * data = dev -> data ;
171
+ struct iadc_dma_channel * dma = & data -> dma ;
172
+ int ret ;
173
+
174
+ if (!dma -> dma_dev ) {
175
+ return - ENODEV ;
176
+ }
177
+
178
+ if (dma -> enabled ) {
179
+ return - EBUSY ;
180
+ }
181
+
182
+ ret = dma_config (dma -> dma_dev , dma -> dma_channel , & dma -> dma_cfg );
183
+ if (ret ) {
184
+ LOG_ERR ("DMA config error: %d" , ret );
185
+ return ret ;
186
+ }
187
+
188
+ dma -> enabled = true;
189
+
190
+ ret = dma_start (dma -> dma_dev , dma -> dma_channel );
191
+ if (ret ) {
192
+ LOG_ERR ("DMA start error: %d" , ret );
193
+ dma -> enabled = false;
194
+ return ret ;
195
+ }
196
+
197
+ return 0 ;
198
+ }
199
+
200
+ static void iadc_dma_stop (const struct device * dev )
201
+ {
202
+ struct iadc_data * data = dev -> data ;
203
+ struct iadc_dma_channel * dma = & data -> dma ;
204
+
205
+ if (!dma -> enabled ) {
206
+ return ;
207
+ }
208
+
209
+ dma_stop (dma -> dma_dev , dma -> dma_channel );
210
+
211
+ dma -> enabled = false;
212
+ }
213
+
214
+ static void iadc_dma_cb (const struct device * dma_dev , void * user_data , uint32_t channel , int status )
215
+ {
216
+ struct iadc_data * data = user_data ;
217
+ const struct device * dev = data -> dev ;
218
+
219
+ if (status < 0 ) {
220
+ LOG_ERR ("DMA transfer error: %d" , status );
221
+ adc_context_complete (& data -> ctx , status );
222
+ return ;
223
+ }
224
+
225
+ iadc_dma_stop (dev );
226
+
227
+ adc_context_on_sampling_done (& data -> ctx , dev );
228
+ }
229
+ #endif /* CONFIG_ADC_SILABS_IADC_DMA */
230
+
122
231
/* Oversampling and resolution are common for both ADC configs
123
232
* because they are not configurable per channel inside a ADC
124
233
* sequence and are common for a sequence.
@@ -149,8 +258,28 @@ static int iadc_set_config(const struct device *dev)
149
258
uint32_t channels ;
150
259
int res ;
151
260
261
+ if (data -> dma .dma_dev ) {
262
+ scan_init .data_valid_level = _IADC_SCANFIFOCFG_DVL_VALID1 ;
263
+ /* Only needed to wake up DMA if EM is 2/3 */
264
+ scan_init .fifo_dma_wakeup = true;
265
+ }
266
+
152
267
data -> adc_config_count = 0 ;
153
268
269
+ if (data -> dma .dma_dev ) {
270
+ if (data -> alignment == _IADC_SCANFIFOCFG_ALIGNMENT_RIGHT20 ) {
271
+ data -> dma .dma_cfg .source_data_size = 4 ;
272
+ data -> dma .dma_cfg .dest_data_size = 4 ;
273
+ data -> dma .dma_cfg .source_burst_length = 4 ;
274
+ data -> dma .dma_cfg .dest_burst_length = 4 ;
275
+ } else {
276
+ data -> dma .dma_cfg .source_data_size = 2 ;
277
+ data -> dma .dma_cfg .dest_data_size = 2 ;
278
+ data -> dma .dma_cfg .source_burst_length = 2 ;
279
+ data -> dma .dma_cfg .dest_burst_length = 2 ;
280
+ }
281
+ }
282
+
154
283
channels = data -> channels ;
155
284
156
285
/*
@@ -340,6 +469,11 @@ static int start_read(const struct device *dev, const struct adc_sequence *seque
340
469
data -> buffer = sequence -> buffer ;
341
470
data -> active_channels = channel_count ;
342
471
472
+ if (data -> dma .dma_dev ) {
473
+ data -> dma .blk_cfg .dest_address = (uintptr_t )data -> buffer ;
474
+ data -> dma .blk_cfg .block_size = channel_count * data -> data_size ;
475
+ }
476
+
343
477
data -> channels = sequence -> channels ;
344
478
345
479
res = iadc_set_config (data -> dev );
@@ -357,9 +491,19 @@ static int start_read(const struct device *dev, const struct adc_sequence *seque
357
491
static void iadc_start_scan (const struct device * dev )
358
492
{
359
493
const struct iadc_config * config = dev -> config ;
494
+ __maybe_unused struct iadc_data * data = dev -> data ;
360
495
IADC_TypeDef * iadc = (IADC_TypeDef * )config -> base ;
361
496
497
+ #ifdef CONFIG_ADC_SILABS_IADC_DMA
498
+ if (data -> dma .dma_dev ) {
499
+ data -> dma .blk_cfg .dest_address = (uintptr_t )data -> buffer ;
500
+ iadc_dma_start (dev );
501
+ } else {
502
+ sl_hal_iadc_enable_interrupts (iadc , IADC_IEN_SCANTABLEDONE );
503
+ }
504
+ #else
362
505
sl_hal_iadc_enable_interrupts (iadc , IADC_IEN_SCANTABLEDONE );
506
+ #endif
363
507
364
508
sl_hal_iadc_start_scan (iadc );
365
509
}
@@ -569,6 +713,13 @@ static int iadc_init(const struct device *dev)
569
713
return ret ;
570
714
}
571
715
716
+ #ifdef CONFIG_ADC_SILABS_IADC_DMA
717
+ ret = iadc_dma_init (dev );
718
+ if (ret < 0 ) {
719
+ data -> dma .dma_dev = NULL ;
720
+ }
721
+ #endif
722
+
572
723
config -> irq_cfg_func ();
573
724
574
725
adc_context_unlock_unconditionally (& data -> ctx );
@@ -585,6 +736,17 @@ static DEVICE_API(adc, iadc_api) = {
585
736
.ref_internal = SL_HAL_IADC_DEFAULT_VREF ,
586
737
};
587
738
739
+ #ifdef CONFIG_ADC_SILABS_IADC_DMA
740
+ #define IADC_DMA_CHANNEL_INIT (n ) \
741
+ .dma.dma_dev = DEVICE_DT_GET(DT_INST_DMAS_CTLR(n)), \
742
+ .dma.dma_cfg.dma_slot = SILABS_LDMA_REQSEL_TO_SLOT(DT_INST_DMAS_CELL_BY_IDX(n, 0, slot)), \
743
+ .dma.dma_cfg.dma_callback = iadc_dma_cb,
744
+ #define IADC_DMA_CHANNEL (n ) \
745
+ COND_CODE_1(DT_INST_NODE_HAS_PROP(n, dmas), (IADC_DMA_CHANNEL_INIT(n)), ())
746
+ #else
747
+ #define IADC_DMA_CHANNEL (n )
748
+ #endif
749
+
588
750
#define IADC_INIT (n ) \
589
751
PINCTRL_DT_INST_DEFINE(n); \
590
752
PM_DEVICE_DT_INST_DEFINE(n, iadc_pm_action); \
@@ -603,6 +765,7 @@ static DEVICE_API(adc, iadc_api) = {
603
765
ADC_CONTEXT_INIT_TIMER(iadc_data_##n, ctx), \
604
766
ADC_CONTEXT_INIT_LOCK(iadc_data_##n, ctx), \
605
767
ADC_CONTEXT_INIT_SYNC(iadc_data_##n, ctx), \
768
+ IADC_DMA_CHANNEL(n) \
606
769
}; \
607
770
\
608
771
static void iadc_config_func_##n(void) \
0 commit comments