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