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