1 /*
2  * Copyright (c) 2016, Freescale Semiconductor, Inc.
3  * Copyright 2016-2019, 2023 NXP
4  * All rights reserved.
5  *
6  *
7  * SPDX-License-Identifier: BSD-3-Clause
8  */
9 
10 #include "fsl_lpcmp.h"
11 
12 /*******************************************************************************
13  * Definitions
14  ******************************************************************************/
15 /* Component ID definition, used by tools. */
16 #ifndef FSL_COMPONENT_ID
17 #define FSL_COMPONENT_ID "platform.drivers.lpcmp"
18 #endif
19 
20 #if defined(LPCMP_RSTS)
21 #define LPCMP_RESETS_ARRAY LPCMP_RSTS
22 #endif
23 
24 /*******************************************************************************
25  * Prototypes
26  ******************************************************************************/
27 #if defined(LPCMP_CLOCKS)
28 /*!
29  * @brief Get instance number for LPCMP module.
30  *
31  * @param base LPCMP peripheral base address
32  */
33 static uint32_t LPCMP_GetInstance(LPCMP_Type *base);
34 #endif /* LPCMP_CLOCKS */
35 
36 /*******************************************************************************
37  * Variables
38  ******************************************************************************/
39 #if defined(LPCMP_CLOCKS)
40 /*! @brief Pointers to LPCMP bases for each instance. */
41 static LPCMP_Type *const s_lpcmpBases[] = LPCMP_BASE_PTRS;
42 
43 #if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
44 /*! @brief Pointers to LPCMP clocks for each instance. */
45 static const clock_ip_name_t s_lpcmpClocks[] = LPCMP_CLOCKS;
46 #endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
47 #endif /* LPCMP_CLOCKS */
48 
49 #if defined(LPCMP_RESETS_ARRAY)
50 /* Reset array */
51 static const reset_ip_name_t s_lpcmpResets[] = LPCMP_RESETS_ARRAY;
52 #endif
53 
54 /*******************************************************************************
55  * Codes
56  ******************************************************************************/
57 #if defined(LPCMP_CLOCKS)
LPCMP_GetInstance(LPCMP_Type * base)58 static uint32_t LPCMP_GetInstance(LPCMP_Type *base)
59 {
60     uint32_t instance;
61 
62     /* Find the instance index from base address mappings. */
63     /*
64      * $Branch Coverage Justification$
65      * (instance >= ARRAY_SIZE(s_lpcmpBases)) not covered. The peripheral base
66      * address is always valid and checked by assert.
67      */
68     for (instance = 0; instance < ARRAY_SIZE(s_lpcmpBases); instance++)
69     {
70         /*
71          * $Branch Coverage Justification$
72          * (s_lpcmpBases[instance] != base) not covered. The peripheral base
73          * address is always valid and checked by assert.
74          */
75         if (s_lpcmpBases[instance] == base)
76         {
77             break;
78         }
79     }
80 
81     assert(instance < ARRAY_SIZE(s_lpcmpBases));
82 
83     return instance;
84 }
85 #endif /* LPCMP_CLOCKS */
86 
87 /*!
88  * brief Initialize the LPCMP
89  *
90  * This function initializes the LPCMP module. The operations included are:
91  * - Enabling the clock for LPCMP module.
92  * - Configuring the comparator.
93  * - Enabling the LPCMP module.
94  * Note: For some devices, multiple LPCMP instance share the same clock gate. In this case, to enable the clock for
95  * any instance enables all the LPCMPs. Check the chip reference manual for the clock assignment of the LPCMP.
96  *
97  * param base LPCMP peripheral base address.
98  * param config Pointer to "lpcmp_config_t" structure.
99  */
LPCMP_Init(LPCMP_Type * base,const lpcmp_config_t * config)100 void LPCMP_Init(LPCMP_Type *base, const lpcmp_config_t *config)
101 {
102     assert(config != NULL);
103 
104     uint32_t tmp32;
105 
106 #if defined(LPCMP_CLOCKS)
107 #if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
108     /* Enable the clock. */
109     CLOCK_EnableClock(s_lpcmpClocks[LPCMP_GetInstance(base)]);
110 #endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
111 #endif /* LPCMP_CLOCKS */
112 
113 #if defined(LPCMP_RESETS_ARRAY)
114     RESET_ReleasePeripheralReset(s_lpcmpResets[LPCMP_GetInstance(base)]);
115 #endif
116 
117     /* Configure. */
118     LPCMP_Enable(base, false);
119 
120 #if !(defined(FSL_FEATURE_LPCMP_HAS_NO_CCR0_CMP_STOP_EN) && FSL_FEATURE_LPCMP_HAS_NO_CCR0_CMP_STOP_EN)
121     /* CCR0 register. */
122 #if defined(FSL_FEATURE_LPCMP_INSTANCE_SUPPORT_CCR0_CMP_STOP_ENn)
123     if (1U == FSL_FEATURE_LPCMP_INSTANCE_SUPPORT_CCR0_CMP_STOP_ENn(base))
124 #endif /* FSL_FEATURE_LPCMP_INSTANCE_SUPPORT_CCR0_CMP_STOP_ENn */
125     {
126         if (config->enableStopMode)
127         {
128             base->CCR0 |= LPCMP_CCR0_CMP_STOP_EN_MASK;
129         }
130         else
131         {
132             base->CCR0 &= ~LPCMP_CCR0_CMP_STOP_EN_MASK;
133         }
134     }
135 #endif /* !(defined(FSL_FEATURE_LPCMP_HAS_NO_CCR0_CMP_STOP_EN) && FSL_FEATURE_LPCMP_HAS_NO_CCR0_CMP_STOP_EN) */
136 
137     /* CCR1 register. */
138     tmp32 = (base->CCR1 & (~(LPCMP_CCR1_COUT_PEN_MASK | LPCMP_CCR1_COUT_SEL_MASK | LPCMP_CCR1_COUT_INV_MASK
139 #if defined(FSL_FEATURE_LPCMP_HAS_CCR1_FUNC_CLK_SEL) && FSL_FEATURE_LPCMP_HAS_CCR1_FUNC_CLK_SEL
140                              | LPCMP_CCR1_FUNC_CLK_SEL_MASK
141 #endif /* FSL_FEATURE_LPCMP_HAS_CCR1_FUNC_CLK_SEL */
142                              )));
143 
144     if (config->enableOutputPin)
145     {
146         tmp32 |= LPCMP_CCR1_COUT_PEN_MASK;
147     }
148     if (config->useUnfilteredOutput)
149     {
150         tmp32 |= LPCMP_CCR1_COUT_SEL_MASK;
151     }
152     if (config->enableInvertOutput)
153     {
154         tmp32 |= LPCMP_CCR1_COUT_INV_MASK;
155     }
156 #if defined(FSL_FEATURE_LPCMP_HAS_CCR1_FUNC_CLK_SEL) && FSL_FEATURE_LPCMP_HAS_CCR1_FUNC_CLK_SEL
157     tmp32 |= LPCMP_CCR1_FUNC_CLK_SEL(config->functionalSourceClock);
158 #endif /* FSL_FEATURE_LPCMP_HAS_CCR1_FUNC_CLK_SEL */
159     base->CCR1 = tmp32;
160     /* CCR2 register. */
161     tmp32 = base->CCR2 & ~(LPCMP_CCR2_HYSTCTR_MASK | LPCMP_CCR2_CMP_NPMD_MASK | LPCMP_CCR2_CMP_HPMD_MASK);
162     tmp32 |= LPCMP_CCR2_HYSTCTR(config->hysteresisMode);
163     tmp32 |= ((uint32_t)(config->powerMode) << LPCMP_CCR2_CMP_HPMD_SHIFT);
164     base->CCR2 = tmp32;
165 
166     LPCMP_Enable(base, true); /* Enable the LPCMP module. */
167 }
168 
169 /*!
170  * brief De-initializes the LPCMP module.
171  *
172  * This function de-initializes the LPCMP module. The operations included are:
173  * - Disabling the LPCMP module.
174  * - Disabling the clock for LPCMP module.
175  *
176  * This function disables the clock for the LPCMP.
177  * Note: For some devices, multiple LPCMP instance shares the same clock gate. In this case, before disabling the
178  * clock for the LPCMP, ensure that all the LPCMP instances are not used.
179  *
180  * param base LPCMP peripheral base address.
181  */
LPCMP_Deinit(LPCMP_Type * base)182 void LPCMP_Deinit(LPCMP_Type *base)
183 {
184     /* Disable the LPCMP module. */
185     LPCMP_Enable(base, false);
186 #if defined(LPCMP_CLOCKS)
187 #if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
188     /* Disable the clock. */
189     CLOCK_DisableClock(s_lpcmpClocks[LPCMP_GetInstance(base)]);
190 #endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
191 #endif /* LPCMP_CLOCKS */
192 }
193 
194 /*!
195  * brief Gets an available pre-defined settings for the comparator's configuration.
196  *
197  * This function initializes the comparator configuration structure to these default values:
198  * code
199  *   config->enableStopMode      = false;
200  *   config->enableOutputPin     = false;
201  *   config->useUnfilteredOutput = false;
202  *   config->enableInvertOutput  = false;
203  *   config->hysteresisMode      = kLPCMP_HysteresisLevel0;
204  *   config->powerMode           = kLPCMP_LowSpeedPowerMode;
205  *   config->functionalSourceClock = kLPCMP_FunctionalClockSource0;
206  * endcode
207  * param config Pointer to "lpcmp_config_t" structure.
208  */
LPCMP_GetDefaultConfig(lpcmp_config_t * config)209 void LPCMP_GetDefaultConfig(lpcmp_config_t *config)
210 {
211     /* Initializes the configure structure to zero. */
212     (void)memset(config, 0, sizeof(*config));
213 #if !(defined(FSL_FEATURE_LPCMP_HAS_NO_CCR0_CMP_STOP_EN) && FSL_FEATURE_LPCMP_HAS_NO_CCR0_CMP_STOP_EN)
214     config->enableStopMode = false;
215 #endif /* !(defined(FSL_FEATURE_LPCMP_HAS_NO_CCR0_CMP_STOP_EN) && FSL_FEATURE_LPCMP_HAS_NO_CCR0_CMP_STOP_EN) */
216     config->enableOutputPin     = false;
217     config->useUnfilteredOutput = false;
218     config->enableInvertOutput  = false;
219     config->hysteresisMode      = kLPCMP_HysteresisLevel0;
220     config->powerMode           = kLPCMP_LowSpeedPowerMode;
221 #if defined(FSL_FEATURE_LPCMP_HAS_CCR1_FUNC_CLK_SEL) && FSL_FEATURE_LPCMP_HAS_CCR1_FUNC_CLK_SEL
222     config->functionalSourceClock = kLPCMP_FunctionalClockSource0;
223 #endif /* FSL_FEATURE_LPCMP_HAS_CCR1_FUNC_CLK_SEL */
224 }
225 
226 /*!
227  * brief Select the input channels for LPCMP. This function determines which input
228  *        is selected for the negative and positive mux.
229  *
230  * param base LPCMP peripheral base address.
231  * param positiveChannel Positive side input channel number.
232  * param negativeChannel Negative side input channel number.
233  */
LPCMP_SetInputChannels(LPCMP_Type * base,uint32_t positiveChannel,uint32_t negativeChannel)234 void LPCMP_SetInputChannels(LPCMP_Type *base, uint32_t positiveChannel, uint32_t negativeChannel)
235 {
236     uint32_t tmp32;
237 
238     tmp32 = base->CCR2 & ~(LPCMP_CCR2_PSEL_MASK | LPCMP_CCR2_MSEL_MASK);
239     tmp32 |= LPCMP_CCR2_PSEL(positiveChannel) | LPCMP_CCR2_MSEL(negativeChannel);
240     base->CCR2 = tmp32;
241 }
242 
243 /*!
244  * brief Configures the filter.
245  *
246  * param base LPCMP peripheral base address.
247  * param config Pointer to "lpcmp_filter_config_t" structure.
248  */
LPCMP_SetFilterConfig(LPCMP_Type * base,const lpcmp_filter_config_t * config)249 void LPCMP_SetFilterConfig(LPCMP_Type *base, const lpcmp_filter_config_t *config)
250 {
251     assert(config != NULL);
252 
253     uint32_t tmp32;
254 
255     tmp32 = base->CCR1 & ~(LPCMP_CCR1_FILT_PER_MASK | LPCMP_CCR1_FILT_CNT_MASK | LPCMP_CCR1_SAMPLE_EN_MASK);
256     if (config->enableSample)
257     {
258         tmp32 |= LPCMP_CCR1_SAMPLE_EN_MASK;
259     }
260     tmp32 |= LPCMP_CCR1_FILT_PER(config->filterSamplePeriod) | LPCMP_CCR1_FILT_CNT(config->filterSampleCount);
261     base->CCR1 = tmp32;
262 }
263 
264 /*!
265  * brief Configure the internal DAC module.
266  *
267  * param base LPCMP peripheral base address.
268  * param config Pointer to "lpcmp_dac_config_t" structure. If config is "NULL", disable internal DAC.
269  */
LPCMP_SetDACConfig(LPCMP_Type * base,const lpcmp_dac_config_t * config)270 void LPCMP_SetDACConfig(LPCMP_Type *base, const lpcmp_dac_config_t *config)
271 {
272     uint32_t tmp32;
273     if (config == NULL)
274     {
275         tmp32 = 0U; /* Disable internal DAC. */
276     }
277     else
278     {
279         tmp32 = LPCMP_DCR_VRSEL(config->referenceVoltageSource) | LPCMP_DCR_DAC_DATA(config->DACValue);
280         if (config->enableLowPowerMode)
281         {
282             tmp32 |= LPCMP_DCR_DAC_HPMD_MASK;
283         }
284         tmp32 |= LPCMP_DCR_DAC_EN_MASK;
285     }
286     base->DCR = tmp32;
287 }
288 
289 #if defined(FSL_FEATURE_LPCMP_HAS_WINDOW_CONTROL) && FSL_FEATURE_LPCMP_HAS_WINDOW_CONTROL
290 /*!
291  * @brief Configure the window control, users can use this API to implement operations on the window,
292  * such as inverting the window signal, setting the window closing event(only valid in windowing mode),
293  * and setting the COUTA signal after the window is closed(only valid in windowing mode).
294  *
295  * @param base LPCMP peripheral base address.
296  * @param config Pointer "lpcmp_window_control_config_t" structure.
297  */
LPCMP_SetWindowControl(LPCMP_Type * base,const lpcmp_window_control_config_t * config)298 void LPCMP_SetWindowControl(LPCMP_Type *base, const lpcmp_window_control_config_t *config)
299 {
300     assert(config != NULL);
301 
302     uint32_t tmp32 = 0UL;
303 
304     tmp32 = (base->CCR1 & (~(LPCMP_CCR1_COUTA_CFG_MASK | LPCMP_CCR1_EVT_SEL_CFG_MASK | LPCMP_CCR1_WINDOW_INV_MASK)));
305 
306     if (config->enableInvertWindowSignal)
307     {
308         tmp32 |= LPCMP_CCR1_WINDOW_INV_MASK;
309     }
310 
311     /* Set COUT event, which can close the active window in window mode. */
312     tmp32 |= LPCMP_CCR1_EVT_SEL_CFG(config->closeWindowEvent);
313 
314     /* Set the COUTA signal value when the window is closed. */
315     tmp32 |= LPCMP_CCR1_COUTA_CFG(config->COUTASignal);
316 
317     base->CCR1 = tmp32;
318 }
319 #endif /* FSL_FEATURE_LPCMP_HAS_WINDOW_CONTROL */
320 
321 #if defined(FSL_FEATURE_LPCMP_HAS_ROUNDROBIN_MODE) && FSL_FEATURE_LPCMP_HAS_ROUNDROBIN_MODE
322 /*!
323  * @brief Configure the roundrobin mode.
324  *
325  * @param base LPCMP peripheral base address.
326  * @param config Pointer "lpcmp_roundrobin_config_t" structure.
327  */
LPCMP_SetRoundRobinConfig(LPCMP_Type * base,const lpcmp_roundrobin_config_t * config)328 void LPCMP_SetRoundRobinConfig(LPCMP_Type *base, const lpcmp_roundrobin_config_t *config)
329 {
330     assert(config != NULL);
331 
332     uint32_t tmp32 = 0UL;
333 
334     /* LPCMPx_RRCR0 register, Configuration options for the round-robin operation. */
335     tmp32 = (base->RRCR0 &
336              (~(LPCMP_RRCR0_RR_TRG_SEL_MASK | LPCMP_RRCR0_RR_NSAM_MASK | LPCMP_RRCR0_RR_CLK_SEL_MASK |
337                 LPCMP_RRCR0_RR_INITMOD_MASK | LPCMP_RRCR0_RR_SAMPLE_CNT_MASK | LPCMP_RRCR0_RR_SAMPLE_THRESHOLD_MASK)));
338 
339     tmp32 |=
340         (LPCMP_RRCR0_RR_TRG_SEL(config->roundrobinTriggerSource) | LPCMP_RRCR0_RR_NSAM(config->sampleClockNumbers) |
341          LPCMP_RRCR0_RR_CLK_SEL(config->roundrobinClockSource) | LPCMP_RRCR0_RR_INITMOD(config->initDelayModules) |
342          LPCMP_RRCR0_RR_SAMPLE_CNT(config->channelSampleNumbers) |
343          LPCMP_RRCR0_RR_SAMPLE_THRESHOLD(config->sampleTimeThreshhold));
344 
345     base->RRCR0 = tmp32;
346 
347     /* LPCMPx_RRCR1 register, Configure the fix port, fix channel and checker channel. */
348     tmp32 =
349         (base->RRCR1 & (~(LPCMP_RRCR1_FIXP_MASK | LPCMP_RRCR1_FIXCH_MASK | (0xFFUL << LPCMP_RRCR1_RR_CH0EN_SHIFT))));
350     tmp32 |= (LPCMP_RRCR1_FIXP(config->fixedMuxPort) | LPCMP_RRCR1_FIXCH(config->fixedChannel) |
351               ((uint32_t)(config->checkerChannelMask) << LPCMP_RRCR1_RR_CH0EN_SHIFT));
352 
353     base->RRCR1 = tmp32;
354 }
355 
356 /*!
357  * brief Configure the roundrobin internal timer reload value.
358  *
359  * param base LPCMP peripheral base address.
360  * param value RoundRobin internal timer reload value, allowed range:0x0UL-0xFFFFFFFUL.
361  */
LPCMP_SetRoundRobinInternalTimer(LPCMP_Type * base,uint32_t value)362 void LPCMP_SetRoundRobinInternalTimer(LPCMP_Type *base, uint32_t value)
363 {
364     uint32_t tmp32 = 0UL;
365 
366     tmp32 = (base->RRCR2 & (~LPCMP_RRCR2_RR_TIMER_RELOAD_MASK));
367     tmp32 |= LPCMP_RRCR2_RR_TIMER_RELOAD(value);
368 
369     base->RRCR2 = tmp32;
370 }
371 
372 #endif /* FSL_FEATURE_LPCMP_HAS_ROUNDROBIN_MODE */
373