1 /*
2  * Copyright 2020-2023 NXP
3  * All rights reserved.
4  *
5  * SPDX-License-Identifier: BSD-3-Clause
6  */
7 
8 #include "fsl_adc.h"
9 
10 /* Component ID definition, used by tools. */
11 #ifndef FSL_COMPONENT_ID
12 #define FSL_COMPONENT_ID "platform.drivers.cns_adc"
13 #endif
14 
15 /*******************************************************************************
16  * Prototypes
17  ******************************************************************************/
18 #if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
19 static uint32_t ADC_GetInstance(ADC_Type *base);
20 #endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
21 
22 /*******************************************************************************
23  * Variables
24  ******************************************************************************/
25 static ADC_Type *const s_adcBases[] = ADC_BASE_PTRS;
26 
27 #if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
28 /*! @brief Pointers to adc clocks for each instance. */
29 static const clock_ip_name_t s_adcClocks[] = ADC_CLOCKS;
30 #endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
31 
32 /*******************************************************************************
33  * Code
34  ******************************************************************************/
35 
36 #if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
37 /*!
38  * @brief Get the ADC peripheral instance
39  *
40  * @param base ADC peripheral base address.
41  * @return The instance of input ADC peripheral base address.
42  */
ADC_GetInstance(ADC_Type * base)43 static uint32_t ADC_GetInstance(ADC_Type *base)
44 {
45     uint32_t instance;
46     uint32_t adcArrayCount = (sizeof(s_adcBases) / sizeof(s_adcBases[0]));
47 
48     /* Find the instance index from base address mappings. */
49     for (instance = 0; instance < adcArrayCount; instance++)
50     {
51         if (s_adcBases[instance] == base)
52         {
53             break;
54         }
55     }
56 
57     assert(instance < adcArrayCount);
58 
59     return instance;
60 }
61 #endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
62 
63 /*!
64  * brief Initialize ADC module, including clock divider, power mode, and so on.
65  *
66  * param base ADC peripheral base address.
67  * param config The pointer to the structure adc_config_t.
68  */
ADC_Init(ADC_Type * base,const adc_config_t * config)69 void ADC_Init(ADC_Type *base, const adc_config_t *config)
70 {
71     assert(config != NULL);
72 
73 #if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
74     /* Ungate the ADC clock*/
75     (void)CLOCK_EnableClock(s_adcClocks[ADC_GetInstance(base)]);
76 #endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
77     uint32_t tmp32;
78 
79     ADC_DoSoftwareReset(base);
80 
81     base->ADC_REG_GENERAL = (base->ADC_REG_GENERAL & ~(ADC_ADC_REG_GENERAL_CLK_DIV_RATIO_MASK)) |
82                             ADC_ADC_REG_GENERAL_CLK_DIV_RATIO(config->clockDivider);
83 
84     tmp32 = base->ADC_REG_CONFIG;
85     tmp32 &=
86         ~(ADC_ADC_REG_CONFIG_TRIGGER_SEL_MASK | ADC_ADC_REG_CONFIG_TRIGGER_EN_MASK |
87           ADC_ADC_REG_CONFIG_CONT_CONV_EN_MASK | ADC_ADC_REG_CONFIG_AVG_SEL_MASK | ADC_ADC_REG_CONFIG_SCAN_LENGTH_MASK);
88     tmp32 |= ADC_ADC_REG_CONFIG_CONT_CONV_EN(config->conversionMode) |
89              ADC_ADC_REG_CONFIG_AVG_SEL(config->averageLength) | ADC_ADC_REG_CONFIG_SCAN_LENGTH(config->scanLength);
90     if (config->triggerSource != kADC_TriggerSourceSoftware)
91     {
92         tmp32 |= ADC_ADC_REG_CONFIG_TRIGGER_EN_MASK | ADC_ADC_REG_CONFIG_TRIGGER_SEL(config->triggerSource);
93     }
94     base->ADC_REG_CONFIG = tmp32;
95 
96     tmp32 = base->ADC_REG_INTERVAL;
97     if (config->warmupTime == kADC_WarmUpStateBypass)
98     {
99         tmp32 |= ADC_ADC_REG_INTERVAL_BYPASS_WARMUP_MASK;
100     }
101     else
102     {
103         tmp32 =
104             (tmp32 & ~(ADC_ADC_REG_INTERVAL_WARMUP_TIME_MASK)) | ADC_ADC_REG_INTERVAL_WARMUP_TIME(config->warmupTime);
105     }
106     base->ADC_REG_INTERVAL = tmp32;
107 
108     tmp32 = base->ADC_REG_ANA;
109     tmp32 &= ~(ADC_ADC_REG_ANA_VREF_SEL_MASK | ADC_ADC_REG_ANA_SINGLEDIFF_MASK | ADC_ADC_REG_ANA_INBUF_GAIN_MASK |
110                ADC_ADC_REG_ANA_INBUF_EN_MASK | ADC_ADC_REG_ANA_BIAS_SEL_MASK | ADC_ADC_REG_ANA_RES_SEL_MASK |
111                ADC_ADC_REG_ANA_INBUF_CHOP_EN_MASK | ADC_ADC_REG_ANA_CHOP_EN_MASK);
112     tmp32 |= ADC_ADC_REG_ANA_VREF_SEL(config->vrefSource) | ADC_ADC_REG_ANA_SINGLEDIFF(config->inputMode) |
113              ADC_ADC_REG_ANA_INBUF_GAIN(config->inputGain) | ADC_ADC_REG_ANA_INBUF_EN(config->enableInputGainBuffer) |
114              ADC_ADC_REG_ANA_BIAS_SEL(config->powerMode) | ADC_ADC_REG_ANA_RES_SEL(config->resolution) |
115              ADC_ADC_REG_ANA_INBUF_CHOP_EN(config->enableInputBufferChop) | ADC_ADC_REG_ANA_CHOP_EN(config->enableChop);
116     base->ADC_REG_ANA = tmp32;
117 
118     base->ADC_REG_RESULT_BUF = (base->ADC_REG_RESULT_BUF & ~(ADC_ADC_REG_RESULT_BUF_WIDTH_SEL_MASK)) |
119                                ADC_ADC_REG_RESULT_BUF_WIDTH_SEL(config->resultWidth);
120 
121     tmp32 = base->ADC_REG_DMAR;
122     tmp32 &= ~(ADC_ADC_REG_DMAR_DMA_EN_MASK | ADC_ADC_REG_DMAR_FIFO_THL_MASK);
123     tmp32 |= ADC_ADC_REG_DMAR_FIFO_THL(config->fifoThreshold) | ADC_ADC_REG_DMAR_DMA_EN(config->enableDMA);
124     base->ADC_REG_DMAR = tmp32;
125 
126     if (config->enableADC)
127     {
128         base->ADC_REG_GENERAL |= ADC_ADC_REG_GENERAL_GLOBAL_EN_MASK;
129     }
130 }
131 
132 /*!
133  * brief Get default configuration.
134  *
135  * code
136  *      config->clockDivider = kADC_ClockDivider1;
137  *      config->powerMode = kADC_PowerModeFullBiasingCurrent;
138  *      config->resolution = kADC_Resolution12Bit;
139  *      config->warmupTime = kADC_WarmUpTime16us;
140  *      config->vrefSource = kADC_Vref1P2V;
141  *      config->inputMode = kADC_InputSingleEnded;
142  *      config->conversionMode = kADC_ConversionContinuous;
143  *      config->scanLength = kADC_ScanLength_1;
144  *      config->averageLength = kADC_AverageNone;
145  *      config->triggerSource = kADC_TriggerSourceSoftware;
146  *      config->inputGain = kADC_InputGain1;
147  *      config->enableInputGainBuffer = false;
148  *      config->resultWidth = kADC_ResultWidth16;
149  *      config->fifoThreshold = kADC_FifoThresholdData1;
150  *      config->enableDMA = false;
151  *      config->enableADC = false;
152  * endcode
153  * param config Pointer to the structure adc_config_t.
154  */
ADC_GetDefaultConfig(adc_config_t * config)155 void ADC_GetDefaultConfig(adc_config_t *config)
156 {
157     assert(config != NULL);
158 
159     (void)memset(config, 0, sizeof(adc_config_t));
160 
161     config->clockDivider = kADC_ClockDivider1;
162     config->powerMode    = kADC_PowerModeFullBiasingCurrent;
163     config->resolution   = kADC_Resolution12Bit;
164     config->warmupTime   = kADC_WarmUpTime16us;
165 
166     config->vrefSource            = kADC_Vref1P2V;
167     config->inputMode             = kADC_InputSingleEnded;
168     config->conversionMode        = kADC_ConversionContinuous;
169     config->scanLength            = kADC_ScanLength_1;
170     config->averageLength         = kADC_AverageNone;
171     config->triggerSource         = kADC_TriggerSourceSoftware;
172     config->inputGain             = kADC_InputGain1;
173     config->enableInputGainBuffer = false;
174     config->enableInputBufferChop = true;
175 
176     config->resultWidth   = kADC_ResultWidth16;
177     config->fifoThreshold = kADC_FifoThresholdData1;
178     config->enableDMA     = false;
179     config->enableADC     = false;
180     config->enableChop    = true;
181 }
182 
183 /*!
184  * brief De-initialize the ADC module.
185  *
186  * param base ADC peripheral base address.
187  */
ADC_Deinit(ADC_Type * base)188 void ADC_Deinit(ADC_Type *base)
189 {
190     ADC_DoSoftwareReset(base);
191 
192 #if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
193     /* Ungate the ADC clock*/
194     (void)CLOCK_DisableClock(s_adcClocks[ADC_GetInstance(base)]);
195 #endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
196 }
197 
198 /*!
199  * brief Set scan channel mux source.
200  *
201  * param base ADC peripheral base address.
202  * param scanChannel The selected channel, please refer to adc_scan_channel_t for details.
203  * param channelSource The mux source to be set to the selected channel,
204  *                      please refer to adc_channel_source_t for details.
205  */
ADC_SetScanChannel(ADC_Type * base,adc_scan_channel_t scanChannel,adc_channel_source_t channelSource)206 void ADC_SetScanChannel(ADC_Type *base, adc_scan_channel_t scanChannel, adc_channel_source_t channelSource)
207 {
208     if (scanChannel < kADC_ScanChannel8)
209     {
210         base->ADC_REG_SCN1 = (base->ADC_REG_SCN1 & ~(0xFUL << (uint32_t)(4UL * (uint32_t)scanChannel))) |
211                              ((uint32_t)channelSource << (uint32_t)(4UL * (uint32_t)scanChannel));
212     }
213     else
214     {
215         base->ADC_REG_SCN2 = (base->ADC_REG_SCN2 & ~(0xFUL << (uint32_t)(4UL * ((uint32_t)scanChannel - 8UL)))) |
216                              ((uint32_t)channelSource << (uint32_t)(4UL * ((uint32_t)scanChannel - 8UL)));
217     }
218 }
219 
220 /*!
221  * brief Do automatic calibration measurement.
222  *
223  * note After auto calibrate successful, user can invoke ADC_GetAutoCalibrationData() to get self offset calibration
224  * value and self gain calibration value.
225  *
226  * param base ADC peripheral base address.
227  * param calVref The inpul reference channel for gain calibration,
228  *                please refer to adc_calibration_ref_t for details.
229  * retval kStatus_Success Auto calibrate successfully.
230  * retval kStatus_Fail Auto calibrate failure.
231  */
ADC_DoAutoCalibration(ADC_Type * base,adc_calibration_ref_t calVref)232 status_t ADC_DoAutoCalibration(ADC_Type *base, adc_calibration_ref_t calVref)
233 {
234     uint32_t tmp32;
235 
236     tmp32 = base->ADC_REG_CONFIG;
237     tmp32 &= ~(ADC_ADC_REG_CONFIG_CAL_VREF_SEL_MASK);
238     tmp32 |= ADC_ADC_REG_CONFIG_CAL_VREF_SEL(calVref);
239     base->ADC_REG_CONFIG = tmp32;
240 
241     base->ADC_REG_CMD &= ~ADC_ADC_REG_CMD_CONV_START_MASK;
242     base->ADC_REG_GENERAL |= ADC_ADC_REG_GENERAL_ADC_CAL_EN_MASK;
243     base->ADC_REG_CMD |= ADC_ADC_REG_CMD_CONV_START_MASK;
244 
245     /* Wait for self calibration done */
246     for (uint32_t i = 0UL; i < 1000000UL; i++)
247     {
248         if ((base->ADC_REG_GENERAL & ADC_ADC_REG_GENERAL_ADC_CAL_EN_MASK) == 0UL)
249         {
250             base->ADC_REG_CONFIG &= ~ADC_ADC_REG_CONFIG_CAL_DATA_SEL_MASK;
251             base->ADC_REG_CMD &= ~ADC_ADC_REG_CMD_CONV_START_MASK;
252             return kStatus_Success;
253         }
254     }
255 
256     return kStatus_Fail;
257 }
258 
259 /*!
260  * brief Configure audio voice level.
261  *
262  * param base ADC peripheral base address.
263  * param enableDetect Used  to enable/disable voice level detection.
264  *          - \b true Enable voice level detection.
265  *          - \b false Disable voice level detection.
266  * param voiceLevel Selected voice level, please refer to adc_audio_voice_level_t.
267  */
ADC_ConfigAudioVoiceLevel(ADC_Type * base,bool enableDetect,adc_audio_voice_level_t voiceLevel)268 void ADC_ConfigAudioVoiceLevel(ADC_Type *base, bool enableDetect, adc_audio_voice_level_t voiceLevel)
269 {
270     uint32_t tmp32;
271 
272     tmp32 = base->ADC_REG_VOICE_DET;
273     tmp32 &= ~(ADC_ADC_REG_VOICE_DET_DET_EN_MASK | ADC_ADC_REG_VOICE_DET_LEVEL_SEL_MASK);
274     tmp32 |= ADC_ADC_REG_VOICE_DET_DET_EN(enableDetect) | ADC_ADC_REG_VOICE_DET_LEVEL_SEL(voiceLevel);
275     base->ADC_REG_VOICE_DET = tmp32;
276 }
277 
278 /*!
279  * brief Get status flags, including interrupt flags, raw flags, and so on.
280  *
281  * param base ADC peripheral base address.
282  * return The OR'ed value of ADC status flags, please refer to _adc_status_flags for details.
283  */
ADC_GetStatusFlags(ADC_Type * base)284 uint32_t ADC_GetStatusFlags(ADC_Type *base)
285 {
286     uint32_t tmp32;
287 
288     tmp32 = base->ADC_REG_ISR;
289     tmp32 |= (base->ADC_REG_IRSR) << 7UL;
290     tmp32 |= (base->ADC_REG_STATUS) << 14UL;
291 
292     return tmp32;
293 }
294