soc: atmel_sam0: Implement fixup.h for ADC driver

The ADC driver now supports three different implementations. To maintain
readability, this patch implements an adc_fixup.h that permits more
generic access to relevant registers.

This patch also introduces support for a new third shape ADC - as found
in the SAML21 for example.

Signed-off-by: Attie Grande <attie.grande@argentum-systems.co.uk>
This commit is contained in:
Attie Grande 2022-01-05 00:08:52 +00:00 committed by Carles Cufí
parent ec1ab6d104
commit e4d4eaca03
9 changed files with 163 additions and 74 deletions

View file

@ -60,13 +60,8 @@ struct adc_sam0_cfg {
static void wait_synchronization(Adc *const adc)
{
#if defined(ADC_SYNCBUSY_MASK)
while ((adc->SYNCBUSY.reg & ADC_SYNCBUSY_MASK) != 0) {
while ((ADC_SYNC(adc) & ADC_SYNC_MASK) != 0) {
}
#else
while ((adc->STATUS.reg & ADC_STATUS_SYNCBUSY) != 0) {
}
#endif
}
static int adc_sam0_acquisition_to_clocks(const struct device *dev,
@ -141,26 +136,16 @@ static int adc_sam0_channel_setup(const struct device *dev,
switch (channel_cfg->reference) {
case ADC_REF_INTERNAL:
#ifdef ADC_REFCTRL_REFSEL_INTREF
REFCTRL = ADC_REFCTRL_REFSEL_INTREF | ADC_REFCTRL_REFCOMP;
/* Enable the internal reference, defaulting to 1V */
SUPC->VREF.bit.VREFOE = 1;
#else
REFCTRL = ADC_REFCTRL_REFSEL_INT1V | ADC_REFCTRL_REFCOMP;
REFCTRL = ADC_REFCTRL_REFSEL_INTERNAL | ADC_REFCTRL_REFCOMP;
/* Enable the internal bandgap reference */
SYSCTRL->VREF.bit.BGOUTEN = 1;
#endif
ADC_BGEN = 1;
break;
case ADC_REF_VDD_1_2:
#ifdef ADC_REFCTRL_REFSEL_INTVCC0
REFCTRL = ADC_REFCTRL_REFSEL_INTVCC0 | ADC_REFCTRL_REFCOMP;
#else
REFCTRL = ADC_REFCTRL_REFSEL_INTVCC1 | ADC_REFCTRL_REFCOMP;
#endif
REFCTRL = ADC_REFCTRL_REFSEL_VDD_1_2 | ADC_REFCTRL_REFCOMP;
break;
#ifdef ADC_REFCTRL_REFSEL_INTVCC1
#ifdef ADC_REFCTRL_REFSEL_VDD_1
case ADC_REF_VDD_1:
REFCTRL = ADC_REFCTRL_REFSEL_INTVCC1 | ADC_REFCTRL_REFCOMP;
REFCTRL = ADC_REFCTRL_REFSEL_VDD_1 | ADC_REFCTRL_REFCOMP;
break;
#endif
case ADC_REF_EXTERNAL0:
@ -226,20 +211,13 @@ static int adc_sam0_channel_setup(const struct device *dev,
if (channel_cfg->differential) {
INPUTCTRL |= ADC_INPUTCTRL_MUXNEG(channel_cfg->input_negative);
#ifdef ADC_INPUTCTRL_DIFFMODE
INPUTCTRL |= ADC_INPUTCTRL_DIFFMODE;
#else
adc->CTRLB.bit.DIFFMODE = 1;
wait_synchronization(adc);
#endif
ADC_DIFF(adc) |= ADC_DIFF_MASK;
} else {
INPUTCTRL |= ADC_INPUTCTRL_MUXNEG_GND;
#ifndef ADC_INPUTCTRL_DIFFMODE
adc->CTRLB.bit.DIFFMODE = 0;
wait_synchronization(adc);
#endif
ADC_DIFF(adc) &= ~ADC_DIFF_MASK;
}
wait_synchronization(adc);
adc->INPUTCTRL.reg = INPUTCTRL;
wait_synchronization(adc);
@ -248,25 +226,21 @@ static int adc_sam0_channel_setup(const struct device *dev,
switch (channel_cfg->input_positive) {
#ifdef ADC_INPUTCTRL_MUXPOS_TEMP_Val
case ADC_INPUTCTRL_MUXPOS_TEMP_Val:
SYSCTRL->VREF.bit.TSEN = 1;
ADC_TSEN = 1;
break;
#endif
#ifdef ADC_INPUTCTRL_MUXPOS_PTAT_Val
case ADC_INPUTCTRL_MUXPOS_PTAT_Val:
SUPC->VREF.bit.TSEN = 1;
ADC_TSEN = 1;
break;
#endif
#ifdef ADC_INPUTCTRL_MUXPOS_CTAT_Val
case ADC_INPUTCTRL_MUXPOS_CTAT_Val:
SUPC->VREF.bit.TSEN = 1;
ADC_TSEN = 1;
break;
#endif
case ADC_INPUTCTRL_MUXPOS_BANDGAP_Val:
#ifdef ADC_REFCTRL_REFSEL_INTREF
SUPC->VREF.bit.VREFOE = 1;
#else
SYSCTRL->VREF.bit.BGOUTEN = 1;
#endif
ADC_BGEN = 1;
break;
default:
break;
@ -361,7 +335,7 @@ static int start_read(const struct device *dev,
return -EINVAL;
}
adc->CTRLB.bit.RESSEL = ADC_CTRLB_RESSEL_8BIT_Val;
ADC_RESSEL(adc) = ADC_RESSEL_8BIT;
break;
case 10:
if (sequence->oversampling) {
@ -369,15 +343,14 @@ static int start_read(const struct device *dev,
return -EINVAL;
}
adc->CTRLB.bit.RESSEL = ADC_CTRLB_RESSEL_10BIT_Val;
ADC_RESSEL(adc) = ADC_RESSEL_10BIT;
break;
case 12:
if (sequence->oversampling) {
adc->CTRLB.bit.RESSEL = ADC_CTRLB_RESSEL_16BIT_Val;
ADC_RESSEL(adc) = ADC_RESSEL_16BIT;
} else {
adc->CTRLB.bit.RESSEL = ADC_CTRLB_RESSEL_12BIT_Val;
ADC_RESSEL(adc) = ADC_RESSEL_12BIT;
}
break;
default:
LOG_ERR("ADC resolution value %d is not valid",
@ -473,11 +446,7 @@ static int adc_sam0_init(const struct device *dev)
GCLK->CLKCTRL.reg = cfg->gclk | GCLK_CLKCTRL_CLKEN;
#endif
#ifdef ADC_CTRLA_PRESCALER_Pos
adc->CTRLA.reg = cfg->prescaler;
#else
adc->CTRLB.reg = cfg->prescaler;
#endif
ADC_PRESCALER(adc) = cfg->prescaler;
wait_synchronization(adc);
adc->INTENCLR.reg = ADC_INTENCLR_MASK;
@ -532,34 +501,16 @@ static const struct adc_driver_api adc_sam0_api = {
.gclk_mask = UTIL_CAT(GCLK_PCHCTRL_GEN_GCLK, \
DT_INST_PROP(n, gclk)), \
.gclk_id = DT_INST_CLOCKS_CELL_BY_NAME(n, gclk, periph_ch), \
.prescaler = UTIL_CAT(ADC_CTRLA_PRESCALER_DIV, \
DT_INST_PROP(n, prescaler)),
#define ADC_SAM0_BIASCOMP_SHIFT(n) \
(ADC0_FUSES_BIASCOMP_Pos + DT_INST_PROP(n, calib_offset))
#define ADC_SAM0_BIASCOMP(n) \
(((*(uint32_t *)NVMCTRL_SW0) >> ADC_SAM0_BIASCOMP_SHIFT(n)) & 0x7)
#define ADC_SAM0_BIASR2R_SHIFT(n) \
(ADC0_FUSES_BIASR2R_Pos + DT_INST_PROP(n, calib_offset))
#define ADC_SAM0_BIASR2R(n) \
(((*(uint32_t *)NVMCTRL_SW0) >> ADC_SAM0_BIASR2R_SHIFT(n)) & 0x7)
#define ADC_SAM0_BIASREFBUF_SHIFT(n) \
(ADC0_FUSES_BIASREFBUF_Pos + DT_INST_PROP(n, calib_offset))
#define ADC_SAM0_BIASREFBUF(n) \
(((*(uint32_t *)NVMCTRL_SW0) >> ADC_SAM0_BIASREFBUF_SHIFT(n)) & 0x7)
.prescaler = UTIL_CAT(ADC_CTRLx_PRESCALER_DIV, \
UTIL_CAT(DT_INST_PROP(n, prescaler), _Val)),
#define ADC_SAM0_CONFIGURE(n) \
do { \
const struct adc_sam0_cfg *const cfg = dev->config; \
Adc * const adc = cfg->regs; \
uint32_t comp = ADC_SAM0_BIASCOMP(n); \
uint32_t r2r = ADC_SAM0_BIASR2R(n); \
uint32_t rbuf = ADC_SAM0_BIASREFBUF(n); \
adc->CALIB.reg = ADC_CALIB_BIASCOMP(comp) | \
ADC_CALIB_BIASR2R(r2r) | \
ADC_CALIB_BIASREFBUF(rbuf); \
adc->CALIB.reg = ADC_SAM0_BIASCOMP(n) \
| ADC_SAM0_BIASR2R(n) \
| ADC_SAM0_BIASREFBUF(n); \
} while (0)
#else
@ -567,8 +518,8 @@ do { \
#define ADC_SAM0_CLOCK_CONTROL(n) \
.gclk = UTIL_CAT(GCLK_CLKCTRL_GEN_GCLK, DT_INST_PROP(n, gclk)) |\
GCLK_CLKCTRL_ID_ADC, \
.prescaler = UTIL_CAT(ADC_CTRLB_PRESCALER_DIV, \
DT_INST_PROP(n, prescaler)), \
.prescaler = UTIL_CAT(ADC_CTRLx_PRESCALER_DIV, \
UTIL_CAT(DT_INST_PROP(n, prescaler), _Val)),
#define ADC_SAM0_CONFIGURE(n) \
do { \

View file

@ -0,0 +1,131 @@
/*
* Copyright (c) 2021 Argentum Systems Ltd.
*
* SPDX-License-Identifier: Apache-2.0
*/
#ifndef _ATMEL_SAM_ADC_FIXUP_H_
#define _ATMEL_SAM_ADC_FIXUP_H_
#if defined(ADC_SYNCBUSY_MASK)
#define ADC_SYNC(adc) ((adc)->SYNCBUSY.reg)
#define ADC_SYNC_MASK (ADC_SYNCBUSY_MASK)
#elif defined(ADC_STATUS_SYNCBUSY)
#define ADC_SYNC(adc) ((adc)->STATUS.reg)
#define ADC_SYNC_MASK (ADC_STATUS_SYNCBUSY)
#else
#error ADC not supported...
#endif
#if defined(ADC_INPUTCTRL_DIFFMODE)
#define ADC_DIFF(adc) (INPUTCTRL)
#define ADC_DIFF_MASK (ADC_INPUTCTRL_DIFFMODE)
#elif defined(ADC_CTRLB_DIFFMODE)
#define ADC_DIFF(adc) ((adc)->CTRLB.reg)
#define ADC_DIFF_MASK (ADC_CTRLB_DIFFMODE)
#elif defined(ADC_CTRLC_DIFFMODE)
#define ADC_DIFF(adc) ((adc)->CTRLC.reg)
#define ADC_DIFF_MASK (ADC_CTRLC_DIFFMODE)
#else
#error ADC not supported...
#endif
#if defined(ADC_CTRLB_RESSEL)
#define ADC_RESSEL(adc) ((adc)->CTRLB.bit.RESSEL)
#define ADC_RESSEL_8BIT ADC_CTRLB_RESSEL_8BIT_Val
#define ADC_RESSEL_10BIT ADC_CTRLB_RESSEL_10BIT_Val
#define ADC_RESSEL_12BIT ADC_CTRLB_RESSEL_12BIT_Val
#define ADC_RESSEL_16BIT ADC_CTRLB_RESSEL_16BIT_Val
#elif defined(ADC_CTRLC_RESSEL)
#define ADC_RESSEL(adc) ((adc)->CTRLC.bit.RESSEL)
#define ADC_RESSEL_8BIT ADC_CTRLC_RESSEL_8BIT_Val
#define ADC_RESSEL_10BIT ADC_CTRLC_RESSEL_10BIT_Val
#define ADC_RESSEL_12BIT ADC_CTRLC_RESSEL_12BIT_Val
#define ADC_RESSEL_16BIT ADC_CTRLC_RESSEL_16BIT_Val
#else
#error ADC not supported...
#endif
#if defined(ADC_CTRLA_PRESCALER)
#define ADC_PRESCALER(adc) ((adc)->CTRLA.bit.PRESCALER)
#define ADC_CTRLx_PRESCALER_DIV ADC_CTRLA_PRESCALER_DIV
#elif defined(ADC_CTRLB_PRESCALER)
#define ADC_PRESCALER(adc) ((adc)->CTRLB.bit.PRESCALER)
#define ADC_CTRLx_PRESCALER_DIV ADC_CTRLB_PRESCALER_DIV
#else
#error ADC not supported...
#endif
#if defined(SYSCTRL_VREF_TSEN)
#define ADC_TSEN (SYSCTRL->VREF.bit.TSEN)
#elif defined(SUPC_VREF_TSEN)
#define ADC_TSEN (SUPC->VREF.bit.TSEN)
#else
#error ADC not supported...
#endif
#if defined(SYSCTRL_VREF_BGOUTEN)
#define ADC_BGEN (SYSCTRL->VREF.bit.BGOUTEN)
#elif defined(SUPC_VREF_VREFOE)
#define ADC_BGEN (SUPC->VREF.bit.VREFOE)
#else
#error ADC not supported...
#endif
#if defined(MCLK)
/* a trailing underscore and/or lumpy concatenation is used to prevent expansion */
#define ADC_SAM0_CALIB(prefix, val) \
UTIL_CAT(ADC_CALIB_, val)( \
(((*(uint32_t *)UTIL_CAT(UTIL_CAT(UTIL_CAT(prefix, FUSES_), val), _ADDR)) \
>> UTIL_CAT(UTIL_CAT(UTIL_CAT(prefix, FUSES_), val), _Pos)) \
& UTIL_CAT(UTIL_CAT(UTIL_CAT(prefix, FUSES_), val), _Msk)) \
)
#if ADC_INST_NUM == 1
# define ADC_FUSES_PREFIX(n) ADC_
#else
# define ADC_FUSES_PREFIX(n) UTIL_CAT(AD, UTIL_CAT(C, UTIL_CAT(n, _)))
#endif
#if defined(ADC_FUSES_BIASCOMP) || defined(ADC0_FUSES_BIASCOMP)
# define ADC_SAM0_BIASCOMP(n) ADC_SAM0_CALIB(ADC_FUSES_PREFIX(n), BIASCOMP)
#else
# define ADC_SAM0_BIASCOMP(n) 0
#endif
#if defined(ADC_FUSES_BIASR2R) || defined(ADC0_FUSES_BIASR2R)
# define ADC_SAM0_BIASR2R(n) ADC_SAM0_CALIB(ADC_FUSES_PREFIX(n), BIASR2R)
#else
# define ADC_SAM0_BIASR2R(n) 0
#endif
#if defined(ADC_FUSES_BIASREFBUF) || defined(ADC0_FUSES_BIASREFBUF)
# define ADC_SAM0_BIASREFBUF(n) ADC_SAM0_CALIB(ADC_FUSES_PREFIX(n), BIASREFBUF)
#else
# define ADC_SAM0_BIASREFBUF(n) 0
#endif
#endif /* MCLK */
#ifndef ADC_REFCTRL_REFSEL_INTERNAL
# ifdef ADC_REFCTRL_REFSEL_INTREF
# define ADC_REFCTRL_REFSEL_INTERNAL ADC_REFCTRL_REFSEL_INTREF
# else
# define ADC_REFCTRL_REFSEL_INTERNAL ADC_REFCTRL_REFSEL_INT1V
# endif
#endif
#ifndef ADC_REFCTRL_REFSEL_VDD_1_2
# ifdef ADC_REFCTRL_REFSEL_INTVCC0
# define ADC_REFCTRL_REFSEL_VDD_1_2 ADC_REFCTRL_REFSEL_INTVCC0
# else
# define ADC_REFCTRL_REFSEL_VDD_1_2 ADC_REFCTRL_REFSEL_INTVCC1
# endif
#endif
#ifndef ADC_REFCTRL_REFSEL_VDD_1
# ifdef ADC_REFCTRL_REFSEL_INTVCC1
# define ADC_REFCTRL_REFSEL_VDD_1 ADC_REFCTRL_REFSEL_INTVCC1
# endif
#endif
#endif /* _ATMEL_SAM0_ADC_FIXUP_H_ */

View file

@ -54,6 +54,7 @@
#endif /* _ASMLANGUAGE */
#include "adc_fixup_sam0.h"
#include "../common/soc_port.h"
#include "../common/atmel_sam0_dt.h"

View file

@ -48,6 +48,7 @@
#endif /* _ASMLANGUAGE */
#include "adc_fixup_sam0.h"
#include "../common/soc_port.h"
#include "../common/atmel_sam0_dt.h"

View file

@ -40,6 +40,7 @@
#include "sercom_fixup_samd5x.h"
#include "tc_fixup_samd5x.h"
#include "adc_fixup_sam0.h"
#include "../common/soc_port.h"
#include "../common/atmel_sam0_dt.h"

View file

@ -32,6 +32,7 @@
#include "sercom_fixup_samd5x.h"
#include "tc_fixup_samd5x.h"
#include "adc_fixup_sam0.h"
#include "../common/soc_port.h"
#include "../common/atmel_sam0_dt.h"

View file

@ -33,6 +33,7 @@
#include "sercom_fixup_samd5x.h"
#include "tc_fixup_samd5x.h"
#include "gmac_fixup_samd5x.h"
#include "adc_fixup_sam0.h"
#include "../common/soc_port.h"
#include "../common/atmel_sam0_dt.h"

View file

@ -31,6 +31,7 @@
#include "sercom_fixup_samd5x.h"
#include "tc_fixup_samd5x.h"
#include "gmac_fixup_samd5x.h"
#include "adc_fixup_sam0.h"
#include "../common/soc_port.h"
#include "../common/atmel_sam0_dt.h"

View file

@ -34,6 +34,7 @@
#endif /* _ASMLANGUAGE */
#include "adc_fixup_sam0.h"
#include "../common/soc_port.h"
#include "../common/atmel_sam0_dt.h"