1 /*
2  * Copyright (c) 2015, Freescale Semiconductor, Inc.
3  * Copyright 2016-2017 NXP
4  *
5  * Redistribution and use in source and binary forms, with or without modification,
6  * are permitted provided that the following conditions are met:
7  *
8  * o Redistributions of source code must retain the above copyright notice, this list
9  *   of conditions and the following disclaimer.
10  *
11  * o Redistributions in binary form must reproduce the above copyright notice, this
12  *   list of conditions and the following disclaimer in the documentation and/or
13  *   other materials provided with the distribution.
14  *
15  * o Neither the name of the copyright holder nor the names of its
16  *   contributors may be used to endorse or promote products derived from this
17  *   software without specific prior written permission.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
20  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
21  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
22  * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
23  * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
24  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
25  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
26  * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
28  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29  */
30 
31 #include "fsl_adc16.h"
32 
33 /*******************************************************************************
34  * Prototypes
35  ******************************************************************************/
36 /*!
37  * @brief Get instance number for ADC16 module.
38  *
39  * @param base ADC16 peripheral base address
40  */
41 static uint32_t ADC16_GetInstance(ADC_Type *base);
42 
43 /*******************************************************************************
44  * Variables
45  ******************************************************************************/
46 /*! @brief Pointers to ADC16 bases for each instance. */
47 static ADC_Type *const s_adc16Bases[] = ADC_BASE_PTRS;
48 
49 #if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
50 /*! @brief Pointers to ADC16 clocks for each instance. */
51 static const clock_ip_name_t s_adc16Clocks[] = ADC16_CLOCKS;
52 #endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
53 
54 /*******************************************************************************
55  * Code
56  ******************************************************************************/
ADC16_GetInstance(ADC_Type * base)57 static uint32_t ADC16_GetInstance(ADC_Type *base)
58 {
59     uint32_t instance;
60 
61     /* Find the instance index from base address mappings. */
62     for (instance = 0; instance < ARRAY_SIZE(s_adc16Bases); instance++)
63     {
64         if (s_adc16Bases[instance] == base)
65         {
66             break;
67         }
68     }
69 
70     assert(instance < ARRAY_SIZE(s_adc16Bases));
71 
72     return instance;
73 }
74 
ADC16_Init(ADC_Type * base,const adc16_config_t * config)75 void ADC16_Init(ADC_Type *base, const adc16_config_t *config)
76 {
77     assert(NULL != config);
78 
79     uint32_t tmp32;
80 
81 #if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
82     /* Enable the clock. */
83     CLOCK_EnableClock(s_adc16Clocks[ADC16_GetInstance(base)]);
84 #endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
85 
86     /* ADCx_CFG1. */
87     tmp32 = ADC_CFG1_ADICLK(config->clockSource) | ADC_CFG1_MODE(config->resolution);
88     if (kADC16_LongSampleDisabled != config->longSampleMode)
89     {
90         tmp32 |= ADC_CFG1_ADLSMP_MASK;
91     }
92     tmp32 |= ADC_CFG1_ADIV(config->clockDivider);
93     if (config->enableLowPower)
94     {
95         tmp32 |= ADC_CFG1_ADLPC_MASK;
96     }
97     base->CFG1 = tmp32;
98 
99     /* ADCx_CFG2. */
100     tmp32 = base->CFG2 & ~(ADC_CFG2_ADACKEN_MASK | ADC_CFG2_ADHSC_MASK | ADC_CFG2_ADLSTS_MASK);
101     if (kADC16_LongSampleDisabled != config->longSampleMode)
102     {
103         tmp32 |= ADC_CFG2_ADLSTS(config->longSampleMode);
104     }
105     if (config->enableHighSpeed)
106     {
107         tmp32 |= ADC_CFG2_ADHSC_MASK;
108     }
109     if (config->enableAsynchronousClock)
110     {
111         tmp32 |= ADC_CFG2_ADACKEN_MASK;
112     }
113     base->CFG2 = tmp32;
114 
115     /* ADCx_SC2. */
116     tmp32 = base->SC2 & ~(ADC_SC2_REFSEL_MASK);
117     tmp32 |= ADC_SC2_REFSEL(config->referenceVoltageSource);
118     base->SC2 = tmp32;
119 
120     /* ADCx_SC3. */
121     if (config->enableContinuousConversion)
122     {
123         base->SC3 |= ADC_SC3_ADCO_MASK;
124     }
125     else
126     {
127         base->SC3 &= ~ADC_SC3_ADCO_MASK;
128     }
129 }
130 
ADC16_Deinit(ADC_Type * base)131 void ADC16_Deinit(ADC_Type *base)
132 {
133 #if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
134     /* Disable the clock. */
135     CLOCK_DisableClock(s_adc16Clocks[ADC16_GetInstance(base)]);
136 #endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
137 }
138 
ADC16_GetDefaultConfig(adc16_config_t * config)139 void ADC16_GetDefaultConfig(adc16_config_t *config)
140 {
141     assert(NULL != config);
142 
143     config->referenceVoltageSource = kADC16_ReferenceVoltageSourceVref;
144     config->clockSource = kADC16_ClockSourceAsynchronousClock;
145     config->enableAsynchronousClock = true;
146     config->clockDivider = kADC16_ClockDivider8;
147     config->resolution = kADC16_ResolutionSE12Bit;
148     config->longSampleMode = kADC16_LongSampleDisabled;
149     config->enableHighSpeed = false;
150     config->enableLowPower = false;
151     config->enableContinuousConversion = false;
152 }
153 
154 #if defined(FSL_FEATURE_ADC16_HAS_CALIBRATION) && FSL_FEATURE_ADC16_HAS_CALIBRATION
ADC16_DoAutoCalibration(ADC_Type * base)155 status_t ADC16_DoAutoCalibration(ADC_Type *base)
156 {
157     bool bHWTrigger = false;
158     volatile uint32_t tmp32; /* 'volatile' here is for the dummy read of ADCx_R[0] register. */
159     status_t status = kStatus_Success;
160 
161     /* The calibration would be failed when in hardwar mode.
162      * Remember the hardware trigger state here and restore it later if the hardware trigger is enabled.*/
163     if (0U != (ADC_SC2_ADTRG_MASK & base->SC2))
164     {
165         bHWTrigger = true;
166         base->SC2 &= ~ADC_SC2_ADTRG_MASK;
167     }
168 
169     /* Clear the CALF and launch the calibration. */
170     base->SC3 |= ADC_SC3_CAL_MASK | ADC_SC3_CALF_MASK;
171     while (0U == (kADC16_ChannelConversionDoneFlag & ADC16_GetChannelStatusFlags(base, 0U)))
172     {
173         /* Check the CALF when the calibration is active. */
174         if (0U != (kADC16_CalibrationFailedFlag & ADC16_GetStatusFlags(base)))
175         {
176             status = kStatus_Fail;
177             break;
178         }
179     }
180     tmp32 = base->R[0]; /* Dummy read to clear COCO caused by calibration. */
181 
182     /* Restore the hardware trigger setting if it was enabled before. */
183     if (bHWTrigger)
184     {
185         base->SC2 |= ADC_SC2_ADTRG_MASK;
186     }
187     /* Check the CALF at the end of calibration. */
188     if (0U != (kADC16_CalibrationFailedFlag & ADC16_GetStatusFlags(base)))
189     {
190         status = kStatus_Fail;
191     }
192     if (kStatus_Success != status) /* Check if the calibration process is succeed. */
193     {
194         return status;
195     }
196 
197     /* Calculate the calibration values. */
198     tmp32 = base->CLP0 + base->CLP1 + base->CLP2 + base->CLP3 + base->CLP4 + base->CLPS;
199     tmp32 = 0x8000U | (tmp32 >> 1U);
200     base->PG = tmp32;
201 
202 #if defined(FSL_FEATURE_ADC16_HAS_DIFF_MODE) && FSL_FEATURE_ADC16_HAS_DIFF_MODE
203     tmp32 = base->CLM0 + base->CLM1 + base->CLM2 + base->CLM3 + base->CLM4 + base->CLMS;
204     tmp32 = 0x8000U | (tmp32 >> 1U);
205     base->MG = tmp32;
206 #endif /* FSL_FEATURE_ADC16_HAS_DIFF_MODE */
207 
208     return kStatus_Success;
209 }
210 #endif /* FSL_FEATURE_ADC16_HAS_CALIBRATION */
211 
212 #if defined(FSL_FEATURE_ADC16_HAS_MUX_SELECT) && FSL_FEATURE_ADC16_HAS_MUX_SELECT
ADC16_SetChannelMuxMode(ADC_Type * base,adc16_channel_mux_mode_t mode)213 void ADC16_SetChannelMuxMode(ADC_Type *base, adc16_channel_mux_mode_t mode)
214 {
215     if (kADC16_ChannelMuxA == mode)
216     {
217         base->CFG2 &= ~ADC_CFG2_MUXSEL_MASK;
218     }
219     else /* kADC16_ChannelMuxB. */
220     {
221         base->CFG2 |= ADC_CFG2_MUXSEL_MASK;
222     }
223 }
224 #endif /* FSL_FEATURE_ADC16_HAS_MUX_SELECT */
225 
ADC16_SetHardwareCompareConfig(ADC_Type * base,const adc16_hardware_compare_config_t * config)226 void ADC16_SetHardwareCompareConfig(ADC_Type *base, const adc16_hardware_compare_config_t *config)
227 {
228     uint32_t tmp32 = base->SC2 & ~(ADC_SC2_ACFE_MASK | ADC_SC2_ACFGT_MASK | ADC_SC2_ACREN_MASK);
229 
230     if (!config) /* Pass "NULL" to disable the feature. */
231     {
232         base->SC2 = tmp32;
233         return;
234     }
235     /* Enable the feature. */
236     tmp32 |= ADC_SC2_ACFE_MASK;
237 
238     /* Select the hardware compare working mode. */
239     switch (config->hardwareCompareMode)
240     {
241         case kADC16_HardwareCompareMode0:
242             break;
243         case kADC16_HardwareCompareMode1:
244             tmp32 |= ADC_SC2_ACFGT_MASK;
245             break;
246         case kADC16_HardwareCompareMode2:
247             tmp32 |= ADC_SC2_ACREN_MASK;
248             break;
249         case kADC16_HardwareCompareMode3:
250             tmp32 |= ADC_SC2_ACFGT_MASK | ADC_SC2_ACREN_MASK;
251             break;
252         default:
253             break;
254     }
255     base->SC2 = tmp32;
256 
257     /* Load the compare values. */
258     base->CV1 = ADC_CV1_CV(config->value1);
259     base->CV2 = ADC_CV2_CV(config->value2);
260 }
261 
262 #if defined(FSL_FEATURE_ADC16_HAS_HW_AVERAGE) && FSL_FEATURE_ADC16_HAS_HW_AVERAGE
ADC16_SetHardwareAverage(ADC_Type * base,adc16_hardware_average_mode_t mode)263 void ADC16_SetHardwareAverage(ADC_Type *base, adc16_hardware_average_mode_t mode)
264 {
265     uint32_t tmp32 = base->SC3 & ~(ADC_SC3_AVGE_MASK | ADC_SC3_AVGS_MASK);
266 
267     if (kADC16_HardwareAverageDisabled != mode)
268     {
269         tmp32 |= ADC_SC3_AVGE_MASK | ADC_SC3_AVGS(mode);
270     }
271     base->SC3 = tmp32;
272 }
273 #endif /* FSL_FEATURE_ADC16_HAS_HW_AVERAGE */
274 
275 #if defined(FSL_FEATURE_ADC16_HAS_PGA) && FSL_FEATURE_ADC16_HAS_PGA
ADC16_SetPGAConfig(ADC_Type * base,const adc16_pga_config_t * config)276 void ADC16_SetPGAConfig(ADC_Type *base, const adc16_pga_config_t *config)
277 {
278     uint32_t tmp32;
279 
280     if (!config) /* Passing "NULL" is to disable the feature. */
281     {
282         base->PGA = 0U;
283         return;
284     }
285 
286     /* Enable the PGA and set the gain value. */
287     tmp32 = ADC_PGA_PGAEN_MASK | ADC_PGA_PGAG(config->pgaGain);
288 
289     /* Configure the misc features for PGA. */
290     if (config->enableRunInNormalMode)
291     {
292         tmp32 |= ADC_PGA_PGALPb_MASK;
293     }
294 #if defined(FSL_FEATURE_ADC16_HAS_PGA_CHOPPING) && FSL_FEATURE_ADC16_HAS_PGA_CHOPPING
295     if (config->disablePgaChopping)
296     {
297         tmp32 |= ADC_PGA_PGACHPb_MASK;
298     }
299 #endif /* FSL_FEATURE_ADC16_HAS_PGA_CHOPPING */
300 #if defined(FSL_FEATURE_ADC16_HAS_PGA_OFFSET_MEASUREMENT) && FSL_FEATURE_ADC16_HAS_PGA_OFFSET_MEASUREMENT
301     if (config->enableRunInOffsetMeasurement)
302     {
303         tmp32 |= ADC_PGA_PGAOFSM_MASK;
304     }
305 #endif /* FSL_FEATURE_ADC16_HAS_PGA_OFFSET_MEASUREMENT */
306     base->PGA = tmp32;
307 }
308 #endif /* FSL_FEATURE_ADC16_HAS_PGA */
309 
ADC16_GetStatusFlags(ADC_Type * base)310 uint32_t ADC16_GetStatusFlags(ADC_Type *base)
311 {
312     uint32_t ret = 0;
313 
314     if (0U != (base->SC2 & ADC_SC2_ADACT_MASK))
315     {
316         ret |= kADC16_ActiveFlag;
317     }
318 #if defined(FSL_FEATURE_ADC16_HAS_CALIBRATION) && FSL_FEATURE_ADC16_HAS_CALIBRATION
319     if (0U != (base->SC3 & ADC_SC3_CALF_MASK))
320     {
321         ret |= kADC16_CalibrationFailedFlag;
322     }
323 #endif /* FSL_FEATURE_ADC16_HAS_CALIBRATION */
324     return ret;
325 }
326 
ADC16_ClearStatusFlags(ADC_Type * base,uint32_t mask)327 void ADC16_ClearStatusFlags(ADC_Type *base, uint32_t mask)
328 {
329 #if defined(FSL_FEATURE_ADC16_HAS_CALIBRATION) && FSL_FEATURE_ADC16_HAS_CALIBRATION
330     if (0U != (mask & kADC16_CalibrationFailedFlag))
331     {
332         base->SC3 |= ADC_SC3_CALF_MASK;
333     }
334 #endif /* FSL_FEATURE_ADC16_HAS_CALIBRATION */
335 }
336 
ADC16_SetChannelConfig(ADC_Type * base,uint32_t channelGroup,const adc16_channel_config_t * config)337 void ADC16_SetChannelConfig(ADC_Type *base, uint32_t channelGroup, const adc16_channel_config_t *config)
338 {
339     assert(channelGroup < ADC_SC1_COUNT);
340     assert(NULL != config);
341 
342     uint32_t sc1 = ADC_SC1_ADCH(config->channelNumber); /* Set the channel number. */
343 
344 #if defined(FSL_FEATURE_ADC16_HAS_DIFF_MODE) && FSL_FEATURE_ADC16_HAS_DIFF_MODE
345     /* Enable the differential conversion. */
346     if (config->enableDifferentialConversion)
347     {
348         sc1 |= ADC_SC1_DIFF_MASK;
349     }
350 #endif /* FSL_FEATURE_ADC16_HAS_DIFF_MODE */
351     /* Enable the interrupt when the conversion is done. */
352     if (config->enableInterruptOnConversionCompleted)
353     {
354         sc1 |= ADC_SC1_AIEN_MASK;
355     }
356     base->SC1[channelGroup] = sc1;
357 }
358 
ADC16_GetChannelStatusFlags(ADC_Type * base,uint32_t channelGroup)359 uint32_t ADC16_GetChannelStatusFlags(ADC_Type *base, uint32_t channelGroup)
360 {
361     assert(channelGroup < ADC_SC1_COUNT);
362 
363     uint32_t ret = 0U;
364 
365     if (0U != (base->SC1[channelGroup] & ADC_SC1_COCO_MASK))
366     {
367         ret |= kADC16_ChannelConversionDoneFlag;
368     }
369     return ret;
370 }
371