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 ;
@@ -120,6 +131,104 @@ static void iadc_configure_scan_table_entry(sl_hal_iadc_scan_table_entry_t *entr
120
131
};
121
132
}
122
133
134
+ #ifdef CONFIG_ADC_SILABS_IADC_DMA
135
+ static int iadc_dma_init (const struct device * dev )
136
+ {
137
+ const struct iadc_config * config = dev -> config ;
138
+ struct iadc_data * data = dev -> data ;
139
+ struct iadc_dma_channel * dma = & data -> dma ;
140
+
141
+ if (!dma -> dma_dev ) {
142
+ return 0 ;
143
+ }
144
+
145
+ if (!device_is_ready (dma -> dma_dev )) {
146
+ LOG_ERR ("DMA device not ready" );
147
+ return - ENODEV ;
148
+ }
149
+
150
+ dma -> dma_channel = dma_request_channel (dma -> dma_dev , NULL );
151
+ if (dma -> dma_channel < 0 ) {
152
+ LOG_ERR ("Failed to request DMA channel" );
153
+ return - ENODEV ;
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
+
220
+ if (status < 0 ) {
221
+ LOG_ERR ("DMA transfer error: %d" , status );
222
+ adc_context_complete (& data -> ctx , status );
223
+ return ;
224
+ }
225
+
226
+ iadc_dma_stop (dev );
227
+
228
+ adc_context_on_sampling_done (& data -> ctx , dev );
229
+ }
230
+ #endif /* CONFIG_ADC_SILABS_IADC_DMA */
231
+
123
232
/* Oversampling and resolution are common for both ADC configs
124
233
* because they are not configurable per channel inside a ADC
125
234
* sequence and are common for a sequence.
@@ -150,8 +259,28 @@ static int iadc_set_config(const struct device *dev)
150
259
uint32_t channels ;
151
260
int res ;
152
261
262
+ if (data -> dma .dma_dev ) {
263
+ scan_init .data_valid_level = _IADC_SCANFIFOCFG_DVL_VALID1 ;
264
+ /* Only needed to wake up DMA if EM is 2/3 */
265
+ scan_init .fifo_dma_wakeup = true;
266
+ }
267
+
153
268
data -> adc_config_count = 0 ;
154
269
270
+ if (data -> dma .dma_dev ) {
271
+ if (data -> alignment == _IADC_SCANFIFOCFG_ALIGNMENT_RIGHT20 ) {
272
+ data -> dma .dma_cfg .source_data_size = 4 ;
273
+ data -> dma .dma_cfg .dest_data_size = 4 ;
274
+ data -> dma .dma_cfg .source_burst_length = 4 ;
275
+ data -> dma .dma_cfg .dest_burst_length = 4 ;
276
+ } else {
277
+ data -> dma .dma_cfg .source_data_size = 2 ;
278
+ data -> dma .dma_cfg .dest_data_size = 2 ;
279
+ data -> dma .dma_cfg .source_burst_length = 2 ;
280
+ data -> dma .dma_cfg .dest_burst_length = 2 ;
281
+ }
282
+ }
283
+
155
284
channels = data -> channels ;
156
285
157
286
/*
@@ -377,6 +506,11 @@ static int start_read(const struct device *dev, const struct adc_sequence *seque
377
506
data -> buffer = sequence -> buffer ;
378
507
data -> active_channels = channel_count ;
379
508
509
+ if (data -> dma .dma_dev ) {
510
+ data -> dma .blk_cfg .dest_address = (uintptr_t )data -> buffer ;
511
+ data -> dma .blk_cfg .block_size = channel_count * data -> data_size ;
512
+ }
513
+
380
514
data -> channels = sequence -> channels ;
381
515
382
516
res = iadc_set_config (data -> dev );
@@ -394,9 +528,19 @@ static int start_read(const struct device *dev, const struct adc_sequence *seque
394
528
static void iadc_start_scan (const struct device * dev )
395
529
{
396
530
const struct iadc_config * config = dev -> config ;
531
+ __maybe_unused struct iadc_data * data = dev -> data ;
397
532
IADC_TypeDef * iadc = (IADC_TypeDef * )config -> base ;
398
533
534
+ #ifdef CONFIG_ADC_SILABS_IADC_DMA
535
+ if (data -> dma .dma_dev ) {
536
+ data -> dma .blk_cfg .dest_address = (uintptr_t )data -> buffer ;
537
+ iadc_dma_start (dev );
538
+ } else {
539
+ sl_hal_iadc_enable_interrupts (iadc , IADC_IEN_SCANTABLEDONE );
540
+ }
541
+ #else
399
542
sl_hal_iadc_enable_interrupts (iadc , IADC_IEN_SCANTABLEDONE );
543
+ #endif
400
544
401
545
sl_hal_iadc_start_scan (iadc );
402
546
}
@@ -606,6 +750,13 @@ static int iadc_init(const struct device *dev)
606
750
return ret ;
607
751
}
608
752
753
+ #ifdef CONFIG_ADC_SILABS_IADC_DMA
754
+ ret = iadc_dma_init (dev );
755
+ if (ret < 0 ) {
756
+ data -> dma .dma_dev = NULL ;
757
+ }
758
+ #endif
759
+
609
760
config -> irq_cfg_func ();
610
761
611
762
adc_context_unlock_unconditionally (& data -> ctx );
@@ -622,6 +773,17 @@ static DEVICE_API(adc, iadc_api) = {
622
773
.ref_internal = SL_HAL_IADC_DEFAULT_VREF ,
623
774
};
624
775
776
+ #ifdef CONFIG_ADC_SILABS_IADC_DMA
777
+ #define IADC_DMA_CHANNEL_INIT (n ) \
778
+ .dma.dma_dev = DEVICE_DT_GET(DT_INST_DMAS_CTLR(n)), \
779
+ .dma.dma_cfg.dma_slot = SILABS_LDMA_REQSEL_TO_SLOT(DT_INST_DMAS_CELL_BY_IDX(n, 0, slot)), \
780
+ .dma.dma_cfg.dma_callback = iadc_dma_cb,
781
+ #define IADC_DMA_CHANNEL (n ) \
782
+ COND_CODE_1(DT_INST_NODE_HAS_PROP(n, dmas), (IADC_DMA_CHANNEL_INIT(n)), ())
783
+ #else
784
+ #define IADC_DMA_CHANNEL (n )
785
+ #endif
786
+
625
787
#define IADC_INIT (n ) \
626
788
PINCTRL_DT_INST_DEFINE(n); \
627
789
PM_DEVICE_DT_INST_DEFINE(n, iadc_pm_action); \
@@ -640,6 +802,7 @@ static DEVICE_API(adc, iadc_api) = {
640
802
ADC_CONTEXT_INIT_TIMER(iadc_data_##n, ctx), \
641
803
ADC_CONTEXT_INIT_LOCK(iadc_data_##n, ctx), \
642
804
ADC_CONTEXT_INIT_SYNC(iadc_data_##n, ctx), \
805
+ IADC_DMA_CHANNEL(n) \
643
806
}; \
644
807
\
645
808
static void iadc_config_func_##n(void) \
0 commit comments