1 /*
2 * Copyright (c) 2019 Derek Hageman <hageman@inthat.cloud>
3 * Copyright (c) 2024 Gerson Fernando Budke <nandojve@gmail.com>
4 *
5 * SPDX-License-Identifier: Apache-2.0
6 */
7
8 #define DT_DRV_COMPAT atmel_sam0_adc
9
10 #include <soc.h>
11 #include <zephyr/drivers/adc.h>
12 #include <zephyr/drivers/pinctrl.h>
13
14 #include <zephyr/logging/log.h>
15 #include <zephyr/irq.h>
16 LOG_MODULE_REGISTER(adc_sam0, CONFIG_ADC_LOG_LEVEL);
17
18 /* clang-format off */
19
20 #define ADC_CONTEXT_USES_KERNEL_TIMER
21 #include "adc_context.h"
22
23 #if defined(CONFIG_SOC_SERIES_SAMD21) || defined(CONFIG_SOC_SERIES_SAMR21) || \
24 defined(CONFIG_SOC_SERIES_SAMD20)
25 /*
26 * SAMD21 Manual 33.6.2.1: The first conversion after changing the reference
27 * is invalid, so we have to discard it.
28 */
29 #define ADC_SAM0_REFERENCE_GLITCH 1
30 #endif
31
32 struct adc_sam0_data {
33 struct adc_context ctx;
34 const struct device *dev;
35
36 uint16_t *buffer;
37
38 /*
39 * Saved initial start, so we can reset the advances we've done
40 * if required
41 */
42 uint16_t *repeat_buffer;
43
44 #ifdef ADC_SAM0_REFERENCE_GLITCH
45 uint8_t reference_changed;
46 #endif
47 };
48
49 struct adc_sam0_cfg {
50 Adc *regs;
51 const struct pinctrl_dev_config *pcfg;
52 volatile uint32_t *mclk;
53 uint32_t mclk_mask;
54 uint32_t gclk_gen;
55 uint16_t gclk_id;
56 uint32_t freq;
57 uint16_t prescaler;
58 void (*config_func)(const struct device *dev);
59 };
60
wait_synchronization(Adc * const adc)61 static void wait_synchronization(Adc *const adc)
62 {
63 while ((ADC_SYNC(adc) & ADC_SYNC_MASK) != 0) {
64 }
65 }
66
adc_sam0_acquisition_to_clocks(const struct device * dev,uint16_t acquisition_time)67 static int adc_sam0_acquisition_to_clocks(const struct device *dev,
68 uint16_t acquisition_time)
69 {
70 const struct adc_sam0_cfg *const cfg = dev->config;
71 uint64_t scaled_acq;
72
73 switch (ADC_ACQ_TIME_UNIT(acquisition_time)) {
74 case ADC_ACQ_TIME_TICKS:
75 if (ADC_ACQ_TIME_VALUE(acquisition_time) > 64U) {
76 return -EINVAL;
77 }
78
79 return (int)ADC_ACQ_TIME_VALUE(acquisition_time) - 1;
80 case ADC_ACQ_TIME_MICROSECONDS:
81 scaled_acq = (uint64_t)ADC_ACQ_TIME_VALUE(acquisition_time) *
82 1000000U;
83 break;
84 case ADC_ACQ_TIME_NANOSECONDS:
85 scaled_acq = (uint64_t)ADC_ACQ_TIME_VALUE(acquisition_time) *
86 1000U;
87 break;
88 default:
89 return -EINVAL;
90 }
91
92 /*
93 * sample_time = (sample_length+1) * (clk_adc / 2)
94 * sample_length = sample_time * (2/clk_adc) - 1,
95 */
96
97 scaled_acq *= 2U;
98 scaled_acq += cfg->freq / 2U;
99 scaled_acq /= cfg->freq;
100 if (scaled_acq <= 1U) {
101 return 0;
102 }
103
104 scaled_acq -= 1U;
105 if (scaled_acq >= 64U) {
106 return -EINVAL;
107 }
108
109 return (int)scaled_acq;
110 }
111
adc_sam0_channel_setup(const struct device * dev,const struct adc_channel_cfg * channel_cfg)112 static int adc_sam0_channel_setup(const struct device *dev,
113 const struct adc_channel_cfg *channel_cfg)
114 {
115 const struct adc_sam0_cfg *const cfg = dev->config;
116 Adc *const adc = cfg->regs;
117 int retval;
118 uint8_t sampctrl = 0;
119
120 if (channel_cfg->acquisition_time != ADC_ACQ_TIME_DEFAULT) {
121 retval = adc_sam0_acquisition_to_clocks(dev,
122 channel_cfg->acquisition_time);
123 if (retval < 0) {
124 LOG_ERR("Selected ADC acquisition time is not valid");
125 return retval;
126 }
127
128 sampctrl |= ADC_SAMPCTRL_SAMPLEN(retval);
129 }
130
131 adc->SAMPCTRL.reg = sampctrl;
132 wait_synchronization(adc);
133
134 uint8_t refctrl;
135
136 switch (channel_cfg->reference) {
137 case ADC_REF_INTERNAL:
138 refctrl = ADC_REFCTRL_REFSEL_INTERNAL | ADC_REFCTRL_REFCOMP;
139 /* Enable the internal bandgap reference */
140 ADC_BGEN = 1;
141 break;
142 #ifdef ADC_REFCTRL_REFSEL_VDD_1
143 case ADC_REF_VDD_1:
144 refctrl = ADC_REFCTRL_REFSEL_VDD_1 | ADC_REFCTRL_REFCOMP;
145 break;
146 #endif
147 case ADC_REF_VDD_1_2:
148 refctrl = ADC_REFCTRL_REFSEL_VDD_1_2 | ADC_REFCTRL_REFCOMP;
149 break;
150 case ADC_REF_EXTERNAL0:
151 refctrl = ADC_REFCTRL_REFSEL_AREFA;
152 break;
153 #ifdef ADC_REFCTRL_REFSEL_AREFB
154 case ADC_REF_EXTERNAL1:
155 refctrl = ADC_REFCTRL_REFSEL_AREFB;
156 break;
157 #endif
158 default:
159 LOG_ERR("Selected reference is not valid");
160 return -EINVAL;
161 }
162 if (adc->REFCTRL.reg != refctrl) {
163 #ifdef ADC_SAM0_REFERENCE_ENABLE_PROTECTED
164 adc->CTRLA.bit.ENABLE = 0;
165 wait_synchronization(adc);
166 #endif
167 adc->REFCTRL.reg = refctrl;
168 wait_synchronization(adc);
169 #ifdef ADC_SAM0_REFERENCE_ENABLE_PROTECTED
170 adc->CTRLA.bit.ENABLE = 1;
171 wait_synchronization(adc);
172 #endif
173 #ifdef ADC_SAM0_REFERENCE_GLITCH
174 struct adc_sam0_data *data = dev->data;
175
176 data->reference_changed = 1;
177 #endif
178 }
179
180 uint32_t inputctrl = 0;
181
182 switch (channel_cfg->gain) {
183 case ADC_GAIN_1:
184 #ifdef ADC_INPUTCTRL_GAIN_1X
185 inputctrl = ADC_INPUTCTRL_GAIN_1X;
186 #endif
187 break;
188 #ifdef ADC_INPUTCTRL_GAIN_DIV2
189 case ADC_GAIN_1_2:
190 inputctrl = ADC_INPUTCTRL_GAIN_DIV2;
191 break;
192 #endif
193 #ifdef ADC_INPUTCTRL_GAIN_2X
194 case ADC_GAIN_2:
195 inputctrl = ADC_INPUTCTRL_GAIN_2X;
196 break;
197 #endif
198 #ifdef ADC_INPUTCTRL_GAIN_4X
199 case ADC_GAIN_4:
200 inputctrl = ADC_INPUTCTRL_GAIN_4X;
201 break;
202 #endif
203 #ifdef ADC_INPUTCTRL_GAIN_8X
204 case ADC_GAIN_8:
205 inputctrl = ADC_INPUTCTRL_GAIN_8X;
206 break;
207 #endif
208 #ifdef ADC_INPUTCTRL_GAIN_16X
209 case ADC_GAIN_16:
210 inputctrl = ADC_INPUTCTRL_GAIN_16X;
211 break;
212 #endif
213 default:
214 LOG_ERR("Selected ADC gain is not valid");
215 return -EINVAL;
216 }
217
218 inputctrl |= ADC_INPUTCTRL_MUXPOS(channel_cfg->input_positive);
219 if (channel_cfg->differential) {
220 inputctrl |= ADC_INPUTCTRL_MUXNEG(channel_cfg->input_negative);
221
222 ADC_DIFF(adc) |= ADC_DIFF_MASK;
223 } else {
224 inputctrl |= ADC_INPUTCTRL_MUXNEG_GND;
225
226 ADC_DIFF(adc) &= ~ADC_DIFF_MASK;
227 }
228 wait_synchronization(adc);
229
230 adc->INPUTCTRL.reg = inputctrl;
231 wait_synchronization(adc);
232
233 /* Enable references if they're selected */
234 switch (channel_cfg->input_positive) {
235 #ifdef ADC_INPUTCTRL_MUXPOS_TEMP_Val
236 case ADC_INPUTCTRL_MUXPOS_TEMP_Val:
237 ADC_TSEN = 1;
238 break;
239 #endif
240 #ifdef ADC_INPUTCTRL_MUXPOS_PTAT_Val
241 case ADC_INPUTCTRL_MUXPOS_PTAT_Val:
242 ADC_TSEN = 1;
243 break;
244 #endif
245 #ifdef ADC_INPUTCTRL_MUXPOS_CTAT_Val
246 case ADC_INPUTCTRL_MUXPOS_CTAT_Val:
247 ADC_TSEN = 1;
248 break;
249 #endif
250 case ADC_INPUTCTRL_MUXPOS_BANDGAP_Val:
251 ADC_BGEN = 1;
252 break;
253 default:
254 break;
255 }
256
257 return 0;
258 }
259
adc_sam0_start_conversion(const struct device * dev)260 static void adc_sam0_start_conversion(const struct device *dev)
261 {
262 const struct adc_sam0_cfg *const cfg = dev->config;
263 Adc *const adc = cfg->regs;
264
265 LOG_DBG("Starting conversion");
266
267 adc->SWTRIG.reg = ADC_SWTRIG_START;
268 /*
269 * Should be safe to not synchronize here because the only things
270 * that might access the ADC after this will wait for it to complete
271 * (synchronize finished implicitly)
272 */
273 }
274
adc_context_start_sampling(struct adc_context * ctx)275 static void adc_context_start_sampling(struct adc_context *ctx)
276 {
277 struct adc_sam0_data *data =
278 CONTAINER_OF(ctx, struct adc_sam0_data, ctx);
279
280 adc_sam0_start_conversion(data->dev);
281 }
282
adc_context_update_buffer_pointer(struct adc_context * ctx,bool repeat_sampling)283 static void adc_context_update_buffer_pointer(struct adc_context *ctx,
284 bool repeat_sampling)
285 {
286 struct adc_sam0_data *data =
287 CONTAINER_OF(ctx, struct adc_sam0_data, ctx);
288
289 if (repeat_sampling) {
290 data->buffer = data->repeat_buffer;
291 }
292 }
293
check_buffer_size(const struct adc_sequence * sequence,uint8_t active_channels)294 static int check_buffer_size(const struct adc_sequence *sequence,
295 uint8_t active_channels)
296 {
297 size_t needed_buffer_size;
298
299 needed_buffer_size = active_channels * sizeof(uint16_t);
300 if (sequence->options) {
301 needed_buffer_size *= (1U + sequence->options->extra_samplings);
302 }
303
304 if (sequence->buffer_size < needed_buffer_size) {
305 LOG_ERR("Provided buffer is too small (%u/%u)",
306 sequence->buffer_size, needed_buffer_size);
307 return -ENOMEM;
308 }
309 return 0;
310 }
311
start_read(const struct device * dev,const struct adc_sequence * sequence)312 static int start_read(const struct device *dev,
313 const struct adc_sequence *sequence)
314 {
315 const struct adc_sam0_cfg *const cfg = dev->config;
316 struct adc_sam0_data *data = dev->data;
317 Adc *const adc = cfg->regs;
318 int error;
319
320 if (sequence->oversampling > 10U) {
321 LOG_ERR("Invalid oversampling");
322 return -EINVAL;
323 }
324
325 adc->AVGCTRL.reg = ADC_AVGCTRL_SAMPLENUM(sequence->oversampling);
326 if (sequence->oversampling < 4) {
327 adc->AVGCTRL.reg |= ADC_AVGCTRL_ADJRES(sequence->oversampling);
328 } else {
329 adc->AVGCTRL.reg |= ADC_AVGCTRL_ADJRES(4);
330 }
331
332 /* AVGCTRL is not synchronized */
333
334 #ifdef CONFIG_SOC_SERIES_SAMD20
335 /*
336 * Errata: silicon revisions B and C do not perform the automatic right
337 * shifts in accumulation
338 */
339 if (sequence->oversampling > 4U && DSU->DID.bit.REVISION < 3) {
340 adc->AVGCTRL.bit.ADJRES = sequence->oversampling - 4U;
341 }
342 #endif
343
344 switch (sequence->resolution) {
345 case 8:
346 if (sequence->oversampling) {
347 LOG_ERR("Oversampling requires 12 bit resolution");
348 return -EINVAL;
349 }
350
351 ADC_RESSEL(adc) = ADC_RESSEL_8BIT;
352 break;
353 case 10:
354 if (sequence->oversampling) {
355 LOG_ERR("Oversampling requires 12 bit resolution");
356 return -EINVAL;
357 }
358
359 ADC_RESSEL(adc) = ADC_RESSEL_10BIT;
360 break;
361 case 12:
362 if (sequence->oversampling) {
363 ADC_RESSEL(adc) = ADC_RESSEL_16BIT;
364 } else {
365 ADC_RESSEL(adc) = ADC_RESSEL_12BIT;
366 }
367 break;
368 default:
369 LOG_ERR("ADC resolution value %d is not valid",
370 sequence->resolution);
371 return -EINVAL;
372 }
373
374 wait_synchronization(adc);
375
376 if ((sequence->channels == 0)
377 || ((sequence->channels & (sequence->channels - 1)) != 0)) {
378 /* The caller is expected to identify a single input channel, which will
379 * typically be the positive input, though no check is made for this...
380 *
381 * While ensuring that the channels bitfield matches the positive input
382 * might be sensible, this will likely break users before this revision
383 * was put in place.
384 */
385 LOG_ERR("Channel scanning is not supported");
386 return -ENOTSUP;
387 }
388
389 error = check_buffer_size(sequence, 1);
390 if (error) {
391 return error;
392 }
393
394 data->buffer = sequence->buffer;
395 data->repeat_buffer = sequence->buffer;
396
397 /* At this point we allow the scheduler to do other things while
398 * we wait for the conversions to complete. This is provided by the
399 * adc_context functions. However, the caller of this function is
400 * blocked until the results are in.
401 */
402 adc_context_start_read(&data->ctx, sequence);
403
404 error = adc_context_wait_for_completion(&data->ctx);
405 return error;
406 }
407
adc_sam0_read(const struct device * dev,const struct adc_sequence * sequence)408 static int adc_sam0_read(const struct device *dev,
409 const struct adc_sequence *sequence)
410 {
411 struct adc_sam0_data *data = dev->data;
412 int error;
413
414 adc_context_lock(&data->ctx, false, NULL);
415 error = start_read(dev, sequence);
416 adc_context_release(&data->ctx, error);
417
418 return error;
419 }
420
adc_sam0_isr(const struct device * dev)421 static void adc_sam0_isr(const struct device *dev)
422 {
423 struct adc_sam0_data *data = dev->data;
424 const struct adc_sam0_cfg *const cfg = dev->config;
425 Adc *const adc = cfg->regs;
426 uint16_t result;
427
428 adc->INTFLAG.reg = ADC_INTFLAG_MASK;
429
430 result = (uint16_t)(adc->RESULT.reg);
431
432 #ifdef ADC_SAM0_REFERENCE_GLITCH
433 if (data->reference_changed) {
434 data->reference_changed = 0;
435 LOG_DBG("Discarded initial conversion due to reference change");
436
437 adc_sam0_start_conversion(dev);
438 return;
439 }
440 #endif
441
442 *data->buffer++ = result;
443 adc_context_on_sampling_done(&data->ctx, dev);
444 }
445
adc_sam0_init(const struct device * dev)446 static int adc_sam0_init(const struct device *dev)
447 {
448 const struct adc_sam0_cfg *const cfg = dev->config;
449 struct adc_sam0_data *data = dev->data;
450 Adc *const adc = cfg->regs;
451 int retval;
452
453 *cfg->mclk |= cfg->mclk_mask;
454
455 #ifdef MCLK
456 GCLK->PCHCTRL[cfg->gclk_id].reg = GCLK_PCHCTRL_CHEN
457 | GCLK_PCHCTRL_GEN(cfg->gclk_gen);
458 #else
459 GCLK->CLKCTRL.reg = GCLK_CLKCTRL_CLKEN
460 | GCLK_CLKCTRL_GEN(cfg->gclk_gen)
461 | GCLK_CLKCTRL_ID(cfg->gclk_id);
462 #endif
463
464 retval = pinctrl_apply_state(cfg->pcfg, PINCTRL_STATE_DEFAULT);
465 if (retval < 0) {
466 return retval;
467 }
468
469 ADC_PRESCALER(adc) = cfg->prescaler;
470 wait_synchronization(adc);
471
472 adc->INTENCLR.reg = ADC_INTENCLR_MASK;
473 adc->INTFLAG.reg = ADC_INTFLAG_MASK;
474
475 cfg->config_func(dev);
476
477 adc->INTENSET.reg = ADC_INTENSET_RESRDY;
478
479 data->dev = dev;
480 #ifdef ADC_SAM0_REFERENCE_GLITCH
481 data->reference_changed = 1;
482 #endif
483
484 adc->CTRLA.bit.ENABLE = 1;
485 wait_synchronization(adc);
486
487 adc_context_unlock_unconditionally(&data->ctx);
488
489 return 0;
490 }
491
492 #ifdef CONFIG_ADC_ASYNC
adc_sam0_read_async(const struct device * dev,const struct adc_sequence * sequence,struct k_poll_signal * async)493 static int adc_sam0_read_async(const struct device *dev,
494 const struct adc_sequence *sequence,
495 struct k_poll_signal *async)
496 {
497 struct adc_sam0_data *data = dev->data;
498 int error;
499
500 adc_context_lock(&data->ctx, true, async);
501 error = start_read(dev, sequence);
502 adc_context_release(&data->ctx, error);
503
504 return error;
505 }
506 #endif
507
508 static DEVICE_API(adc, adc_sam0_api) = {
509 .channel_setup = adc_sam0_channel_setup,
510 .read = adc_sam0_read,
511 .ref_internal = 1000U, /* Fixed 1.0 V reference */
512 #ifdef CONFIG_ADC_ASYNC
513 .read_async = adc_sam0_read_async,
514 #endif
515 };
516
517
518 #ifdef MCLK
519
520 #define ADC_SAM0_CONFIGURE(n) \
521 do { \
522 const struct adc_sam0_cfg *const cfg = dev->config; \
523 Adc * const adc = cfg->regs; \
524 adc->CALIB.reg = ADC_SAM0_BIASCOMP(n) \
525 | ADC_SAM0_BIASR2R(n) \
526 | ADC_SAM0_BIASREFBUF(n); \
527 } while (false)
528
529 #else
530
531 #define ADC_SAM0_CONFIGURE(n) \
532 do { \
533 const struct adc_sam0_cfg *const cfg = dev->config; \
534 Adc * const adc = cfg->regs; \
535 /* Linearity is split across two words */ \
536 uint32_t lin = ((*(uint32_t *)ADC_FUSES_LINEARITY_0_ADDR) & \
537 ADC_FUSES_LINEARITY_0_Msk) >> \
538 ADC_FUSES_LINEARITY_0_Pos; \
539 lin |= (((*(uint32_t *)ADC_FUSES_LINEARITY_1_ADDR) & \
540 ADC_FUSES_LINEARITY_1_Msk) >> \
541 ADC_FUSES_LINEARITY_1_Pos) << 4; \
542 uint32_t bias = ((*(uint32_t *)ADC_FUSES_BIASCAL_ADDR) & \
543 ADC_FUSES_BIASCAL_Msk) >> ADC_FUSES_BIASCAL_Pos; \
544 adc->CALIB.reg = ADC_CALIB_BIAS_CAL(bias) | \
545 ADC_CALIB_LINEARITY_CAL(lin); \
546 } while (false)
547
548 #endif
549
550 #define ASSIGNED_CLOCKS_CELL_BY_NAME \
551 ATMEL_SAM0_DT_INST_ASSIGNED_CLOCKS_CELL_BY_NAME
552
553 #define ADC_SAM0_GCLK_FREQ(n) \
554 UTIL_CAT(UTIL_CAT(SOC_ATMEL_SAM0_GCLK, \
555 ASSIGNED_CLOCKS_CELL_BY_NAME(n, gclk, gen)), \
556 _FREQ_HZ)
557
558 #define ADC_SAM0_FREQ(n) \
559 .prescaler = UTIL_CAT(ADC_CTRLx_PRESCALER_DIV, \
560 UTIL_CAT(DT_INST_PROP(n, prescaler), _Val)), \
561 .freq = ADC_SAM0_GCLK_FREQ(n) / DT_INST_PROP(n, prescaler)
562
563 #define ADC_SAM0_DEVICE(n) \
564 PINCTRL_DT_INST_DEFINE(n); \
565 static void adc_sam0_config_##n(const struct device *dev); \
566 static const struct adc_sam0_cfg adc_sam_cfg_##n = { \
567 .regs = (Adc *)DT_INST_REG_ADDR(n), \
568 .gclk_gen = ASSIGNED_CLOCKS_CELL_BY_NAME(n, gclk, gen), \
569 .gclk_id = DT_INST_CLOCKS_CELL_BY_NAME(n, gclk, id), \
570 .mclk = ATMEL_SAM0_DT_INST_MCLK_PM_REG_ADDR_OFFSET(n), \
571 .mclk_mask = ATMEL_SAM0_DT_INST_MCLK_PM_PERIPH_MASK(n, bit), \
572 ADC_SAM0_FREQ(n), \
573 .config_func = &adc_sam0_config_##n, \
574 .pcfg = PINCTRL_DT_INST_DEV_CONFIG_GET(n), \
575 }; \
576 static struct adc_sam0_data adc_sam_data_##n = { \
577 ADC_CONTEXT_INIT_TIMER(adc_sam_data_##n, ctx), \
578 ADC_CONTEXT_INIT_LOCK(adc_sam_data_##n, ctx), \
579 ADC_CONTEXT_INIT_SYNC(adc_sam_data_##n, ctx), \
580 }; \
581 DEVICE_DT_INST_DEFINE(n, adc_sam0_init, NULL, \
582 &adc_sam_data_##n, \
583 &adc_sam_cfg_##n, POST_KERNEL, \
584 CONFIG_ADC_INIT_PRIORITY, \
585 &adc_sam0_api); \
586 static void adc_sam0_config_##n(const struct device *dev) \
587 { \
588 IRQ_CONNECT(DT_INST_IRQ_BY_NAME(n, resrdy, irq), \
589 DT_INST_IRQ_BY_NAME(n, resrdy, priority), \
590 adc_sam0_isr, \
591 DEVICE_DT_INST_GET(n), 0); \
592 irq_enable(DT_INST_IRQ_BY_NAME(n, resrdy, irq)); \
593 ADC_SAM0_CONFIGURE(n); \
594 }
595
596 DT_INST_FOREACH_STATUS_OKAY(ADC_SAM0_DEVICE)
597
598 /* clang-format on */
599