1 /*
2  * Copyright (c) 2016, Freescale Semiconductor, Inc.
3  * Copyright 2016-2017 NXP
4  * All rights reserved.
5  *
6  * SPDX-License-Identifier: BSD-3-Clause
7  */
8 
9 #include "fsl_lpadc.h"
10 
11 /*******************************************************************************
12  * Prototypes
13  ******************************************************************************/
14 /*!
15  * @brief Get instance number for LPADC module.
16  *
17  * @param base LPADC peripheral base address
18  */
19 static uint32_t LPADC_GetInstance(ADC_Type *base);
20 
21 /*******************************************************************************
22  * Variables
23  ******************************************************************************/
24 /*! @brief Pointers to LPADC bases for each instance. */
25 static ADC_Type *const s_lpadcBases[] = ADC_BASE_PTRS;
26 #if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
27 /*! @brief Pointers to LPADC clocks for each instance. */
28 static const clock_ip_name_t s_lpadcClocks[] = LPADC_CLOCKS;
29 #endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
30 
31 /*******************************************************************************
32  * Code
33  ******************************************************************************/
LPADC_GetInstance(ADC_Type * base)34 static uint32_t LPADC_GetInstance(ADC_Type *base)
35 {
36     uint32_t instance;
37 
38     /* Find the instance index from base address mappings. */
39     for (instance = 0; instance < ARRAY_SIZE(s_lpadcBases); instance++)
40     {
41         if (s_lpadcBases[instance] == base)
42         {
43             break;
44         }
45     }
46 
47     assert(instance < ARRAY_SIZE(s_lpadcBases));
48 
49     return instance;
50 }
51 
LPADC_Init(ADC_Type * base,const lpadc_config_t * config)52 void LPADC_Init(ADC_Type *base, const lpadc_config_t *config)
53 {
54     /* Check if the pointer is available. */
55     assert(config != NULL);
56 
57     uint32_t tmp32 = 0U;
58 
59 #if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
60     /* Enable the clock for LPADC instance. */
61     CLOCK_EnableClock(s_lpadcClocks[LPADC_GetInstance(base)]);
62 #endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
63 
64     /* Reset the module. */
65     LPADC_DoResetConfig(base);
66     LPADC_DoResetFIFO(base);
67 
68     /* Disable the module before setting configuration. */
69     LPADC_Enable(base, false);
70 
71     /* Configure the module generally. */
72     if (config->enableInDozeMode)
73     {
74         base->CTRL &= ~ADC_CTRL_DOZEN_MASK;
75     }
76     else
77     {
78         base->CTRL |= ADC_CTRL_DOZEN_MASK;
79     }
80 
81 /* ADCx_CFG. */
82 #if defined(FSL_FEATURE_LPADC_HAS_CFG_ADCKEN) && FSL_FEATURE_LPADC_HAS_CFG_ADCKEN
83     if (config->enableInternalClock)
84     {
85         tmp32 |= ADC_CFG_ADCKEN_MASK;
86     }
87 #endif /* FSL_FEATURE_LPADC_HAS_CFG_ADCKEN */
88 #if defined(FSL_FEATURE_LPADC_HAS_CFG_VREF1RNG) && FSL_FEATURE_LPADC_HAS_CFG_VREF1RNG
89     if (config->enableVref1LowVoltage)
90     {
91         tmp32 |= ADC_CFG_VREF1RNG_MASK;
92     }
93 #endif /* FSL_FEATURE_LPADC_HAS_CFG_VREF1RNG */
94     if (config->enableAnalogPreliminary)
95     {
96         tmp32 |= ADC_CFG_PWREN_MASK;
97     }
98     tmp32 |= ADC_CFG_PUDLY(config->powerUpDelay)                /* Power up delay. */
99              | ADC_CFG_REFSEL(config->referenceVoltageSource)   /* Reference voltage. */
100              | ADC_CFG_TPRICTRL(config->triggerPrioirtyPolicy); /* Trigger priority policy. */
101     base->CFG = tmp32;
102 
103     /* ADCx_PAUSE. */
104     if (config->enableConvPause)
105     {
106         base->PAUSE = ADC_PAUSE_PAUSEEN_MASK | ADC_PAUSE_PAUSEDLY(config->convPauseDelay);
107     }
108     else
109     {
110         base->PAUSE = 0U;
111     }
112 
113     /* ADCx_FCTRL. */
114     base->FCTRL = ADC_FCTRL_FWMARK(config->FIFOWatermark);
115 
116     /* Enable the module after setting configuration. */
117     LPADC_Enable(base, true);
118 }
119 
LPADC_GetDefaultConfig(lpadc_config_t * config)120 void LPADC_GetDefaultConfig(lpadc_config_t *config)
121 {
122 #if defined(FSL_FEATURE_LPADC_HAS_CFG_ADCKEN) && FSL_FEATURE_LPADC_HAS_CFG_ADCKEN
123     config->enableInternalClock = false;
124 #endif /* FSL_FEATURE_LPADC_HAS_CFG_ADCKEN */
125 #if defined(FSL_FEATURE_LPADC_HAS_CFG_VREF1RNG) && FSL_FEATURE_LPADC_HAS_CFG_VREF1RNG
126     config->enableVref1LowVoltage = false;
127 #endif /* FSL_FEATURE_LPADC_HAS_CFG_VREF1RNG */
128     config->enableInDozeMode = true;
129     config->enableAnalogPreliminary = false;
130     config->powerUpDelay = 0x80;
131     config->referenceVoltageSource = kLPADC_ReferenceVoltageAlt1;
132     config->powerLevelMode = kLPADC_PowerLevelAlt1;
133     config->triggerPrioirtyPolicy = kLPADC_TriggerPriorityPreemptImmediately;
134     config->enableConvPause = false;
135     config->convPauseDelay = 0U;
136     config->FIFOWatermark = 0U;
137 }
138 
LPADC_Deinit(ADC_Type * base)139 void LPADC_Deinit(ADC_Type *base)
140 {
141     /* Disable the module. */
142     LPADC_Enable(base, false);
143 
144 #if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
145     /* Gate the clock. */
146     CLOCK_DisableClock(s_lpadcClocks[LPADC_GetInstance(base)]);
147 #endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
148 }
149 
LPADC_GetConvResult(ADC_Type * base,lpadc_conv_result_t * result)150 bool LPADC_GetConvResult(ADC_Type *base, lpadc_conv_result_t *result)
151 {
152     assert(result != NULL); /* Check if the input pointer is available. */
153 
154     uint32_t tmp32;
155 
156     tmp32 = base->RESFIFO;
157 
158     if (0U == (ADC_RESFIFO_VALID_MASK & tmp32))
159     {
160         return false; /* FIFO is empty. Discard any read from RESFIFO. */
161     }
162 
163     result->commandIdSource = (tmp32 & ADC_RESFIFO_CMDSRC_MASK) >> ADC_RESFIFO_CMDSRC_SHIFT;
164     result->loopCountIndex = (tmp32 & ADC_RESFIFO_LOOPCNT_MASK) >> ADC_RESFIFO_LOOPCNT_SHIFT;
165     result->triggerIdSource = (tmp32 & ADC_RESFIFO_TSRC_MASK) >> ADC_RESFIFO_TSRC_SHIFT;
166     result->convValue = (uint16_t)(tmp32 & ADC_RESFIFO_D_MASK);
167 
168     return true;
169 }
170 
LPADC_SetConvTriggerConfig(ADC_Type * base,uint32_t triggerId,const lpadc_conv_trigger_config_t * config)171 void LPADC_SetConvTriggerConfig(ADC_Type *base, uint32_t triggerId, const lpadc_conv_trigger_config_t *config)
172 {
173     assert(triggerId < ADC_TCTRL_COUNT); /* Check if the triggerId is available in this device. */
174     assert(config != NULL);              /* Check if the input pointer is available. */
175 
176     uint32_t tmp32;
177 
178     tmp32 = ADC_TCTRL_TCMD(config->targetCommandId) /* Trigger command select. */
179             | ADC_TCTRL_TDLY(config->delayPower)    /* Trigger delay select. */
180             | ADC_TCTRL_TPRI(config->priority);     /* Trigger priority setting. */
181     if (config->enableHardwareTrigger)
182     {
183         tmp32 |= ADC_TCTRL_HTEN_MASK;
184     }
185 
186     base->TCTRL[triggerId] = tmp32;
187 }
188 
LPADC_GetDefaultConvTriggerConfig(lpadc_conv_trigger_config_t * config)189 void LPADC_GetDefaultConvTriggerConfig(lpadc_conv_trigger_config_t *config)
190 {
191     assert(config != NULL); /* Check if the input pointer is available. */
192 
193     config->targetCommandId = 0U;
194     config->delayPower = 0U;
195     config->priority = 0U;
196     config->enableHardwareTrigger = false;
197 }
198 
LPADC_SetConvCommandConfig(ADC_Type * base,uint32_t commandId,const lpadc_conv_command_config_t * config)199 void LPADC_SetConvCommandConfig(ADC_Type *base, uint32_t commandId, const lpadc_conv_command_config_t *config)
200 {
201     assert(commandId < (ADC_CMDL_COUNT + 1U)); /* Check if the commandId is available on this device. */
202     assert(config != NULL);                    /* Check if the input pointer is available. */
203 
204     uint32_t tmp32;
205 
206     commandId--; /* The available command number are 1-15, while the index of register group are 0-14. */
207 
208     /* ADCx_CMDL. */
209     tmp32 = ADC_CMDL_ADCH(config->channelNumber); /* Channel number. */
210 #if defined(FSL_FEATURE_LPADC_HAS_CMDL_CSCALE) && FSL_FEATURE_LPADC_HAS_CMDL_CSCALE
211     tmp32 |= ADC_CMDL_CSCALE(config->sampleScaleMode); /* Full/Part scale input voltage. */
212 #endif                                                 /* FSL_FEATURE_LPADC_HAS_CMDL_CSCALE */
213     switch (config->sampleChannelMode)                 /* Sample input. */
214     {
215         case kLPADC_SampleChannelSingleEndSideB:
216             tmp32 |= ADC_CMDL_ABSEL_MASK;
217             break;
218 #if defined(FSL_FEATURE_LPADC_HAS_CMDL_DIFF) && FSL_FEATURE_LPADC_HAS_CMDL_DIFF
219         case kLPADC_SampleChannelDiffBothSideAB:
220             tmp32 |= ADC_CMDL_DIFF_MASK;
221             break;
222         case kLPADC_SampleChannelDiffBothSideBA:
223             tmp32 |= ADC_CMDL_ABSEL_MASK | ADC_CMDL_DIFF_MASK;
224             break;
225 #endif           /* FSL_FEATURE_LPADC_HAS_CMDL_DIFF */
226         default: /* kLPADC_SampleChannelSingleEndSideA. */
227             break;
228     }
229     base->CMD[commandId].CMDL = tmp32;
230 
231     /* ADCx_CMDH. */
232     tmp32 = ADC_CMDH_NEXT(config->chainedNextCommandNumber) /* Next Command Select. */
233             | ADC_CMDH_LOOP(config->loopCount)              /* Loop Count Select. */
234             | ADC_CMDH_AVGS(config->hardwareAverageMode)    /* Hardware Average Select. */
235             | ADC_CMDH_STS(config->sampleTimeMode)          /* Sample Time Select. */
236             | ADC_CMDH_CMPEN(config->hardwareCompareMode);  /* Hardware compare enable. */
237     if (config->enableAutoChannelIncrement)
238     {
239         tmp32 |= ADC_CMDH_LWI_MASK;
240     }
241     base->CMD[commandId].CMDH = tmp32;
242 
243     /* Hardware compare settings.
244     * Not all Command Buffers have an associated Compare Value register. The compare function is only available on
245     * Command Buffers that have a corresponding Compare Value register.
246     */
247     if (kLPADC_HardwareCompareDisabled != config->hardwareCompareMode)
248     {
249         /* Check if the hardware compare feature is available for indicated command buffer. */
250         assert(commandId < ADC_CV_COUNT);
251 
252         /* Set CV register. */
253         base->CV[commandId] = ADC_CV_CVH(config->hardwareCompareValueHigh)   /* Compare value high. */
254                               | ADC_CV_CVL(config->hardwareCompareValueLow); /* Compare value low. */
255     }
256 }
257 
LPADC_GetDefaultConvCommandConfig(lpadc_conv_command_config_t * config)258 void LPADC_GetDefaultConvCommandConfig(lpadc_conv_command_config_t *config)
259 {
260     assert(config != NULL); /* Check if the input pointer is available. */
261 
262 #if defined(FSL_FEATURE_LPADC_HAS_CMDL_CSCALE) && FSL_FEATURE_LPADC_HAS_CMDL_CSCALE
263     config->sampleScaleMode = kLPADC_SampleFullScale;
264 #endif /* FSL_FEATURE_LPADC_HAS_CMDL_CSCALE */
265     config->sampleChannelMode = kLPADC_SampleChannelSingleEndSideA;
266     config->channelNumber = 0U;
267     config->chainedNextCommandNumber = 0U; /* No next command defined. */
268     config->enableAutoChannelIncrement = false;
269     config->loopCount = 0U;
270     config->hardwareAverageMode = kLPADC_HardwareAverageCount1;
271     config->sampleTimeMode = kLPADC_SampleTimeADCK3;
272     config->hardwareCompareMode = kLPADC_HardwareCompareDisabled;
273     config->hardwareCompareValueHigh = 0U; /* No used. */
274     config->hardwareCompareValueLow = 0U;  /* No used. */
275 }
276 
277 #if defined(FSL_FEATURE_LPADC_HAS_CFG_CALOFS) && FSL_FEATURE_LPADC_HAS_CFG_CALOFS
LPADC_EnableCalibration(ADC_Type * base,bool enable)278 void LPADC_EnableCalibration(ADC_Type *base, bool enable)
279 {
280     LPADC_Enable(base, false);
281     if (enable)
282     {
283         base->CFG |= ADC_CFG_CALOFS_MASK;
284     }
285     else
286     {
287         base->CFG &= ~ADC_CFG_CALOFS_MASK;
288     }
289     LPADC_Enable(base, true);
290 }
291 
292 #if defined(FSL_FEATURE_LPADC_HAS_OFSTRIM) && FSL_FEATURE_LPADC_HAS_OFSTRIM
LPADC_DoAutoCalibration(ADC_Type * base)293 void LPADC_DoAutoCalibration(ADC_Type *base)
294 {
295     assert(0u == LPADC_GetConvResultCount(base));
296 
297     uint32_t mLpadcCMDL;
298     uint32_t mLpadcCMDH;
299     uint32_t mLpadcTrigger;
300     lpadc_conv_trigger_config_t mLpadcTriggerConfigStruct;
301     lpadc_conv_command_config_t mLpadcCommandConfigStruct;
302     lpadc_conv_result_t mLpadcResultConfigStruct;
303 
304     /* Enable the calibration function. */
305     LPADC_EnableCalibration(base, true);
306 
307     /* Keep the CMD and TRG state here and restore it later if the calibration completes.*/
308     mLpadcCMDL = base->CMD[0].CMDL; /* CMD1L. */
309     mLpadcCMDH = base->CMD[0].CMDH; /* CMD1H. */
310     mLpadcTrigger = base->TCTRL[0]; /* Trigger0. */
311 
312     /* Set trigger0 configuration - for software trigger. */
313     LPADC_GetDefaultConvTriggerConfig(&mLpadcTriggerConfigStruct);
314     mLpadcTriggerConfigStruct.targetCommandId = 1U;                   /* CMD1 is executed. */
315     LPADC_SetConvTriggerConfig(base, 0U, &mLpadcTriggerConfigStruct); /* Configurate the trigger0. */
316 
317     /* Set conversion CMD configuration. */
318     LPADC_GetDefaultConvCommandConfig(&mLpadcCommandConfigStruct);
319     mLpadcCommandConfigStruct.hardwareAverageMode = kLPADC_HardwareAverageCount128;
320     LPADC_SetConvCommandConfig(base, 1U, &mLpadcCommandConfigStruct); /* Set CMD1 configuration. */
321 
322     /* Do calibration. */
323     LPADC_DoSoftwareTrigger(base, 1U); /* 1U is trigger0 mask. */
324     while (!LPADC_GetConvResult(base, &mLpadcResultConfigStruct))
325     {
326     }
327     /* The valid bits of data are bits 14:3 in the RESFIFO register. */
328     LPADC_SetOffsetValue(base, (mLpadcResultConfigStruct.convValue) >> 3U);
329     /* Disable the calibration function. */
330     LPADC_EnableCalibration(base, false);
331 
332     /* restore CMD and TRG registers. */
333     base->CMD[0].CMDL = mLpadcCMDL; /* CMD1L. */
334     base->CMD[0].CMDH = mLpadcCMDH; /* CMD1H. */
335     base->TCTRL[0] = mLpadcTrigger; /* Trigger0. */
336 }
337 #endif /* FSL_FEATURE_LPADC_HAS_OFSTRIM */
338 #endif /* FSL_FEATURE_LPADC_HAS_CFG_CALOFS */
339