1 /*
2  * Copyright (c) 2015, Freescale Semiconductor, Inc.
3  * Copyright 2016-2019, 2023 NXP
4  * All rights reserved.
5  *
6  * SPDX-License-Identifier: BSD-3-Clause
7  */
8 
9 #include "fsl_cmp.h"
10 
11 /* Component ID definition, used by tools. */
12 #ifndef FSL_COMPONENT_ID
13 #define FSL_COMPONENT_ID "platform.drivers.cmp"
14 #endif
15 
16 /*******************************************************************************
17  * Prototypes
18  ******************************************************************************/
19 /*!
20  * @brief Get instance number for CMP module.
21  *
22  * @param base CMP peripheral base address
23  */
24 static uint32_t CMP_GetInstance(CMP_Type *base);
25 
26 /*******************************************************************************
27  * Variables
28  ******************************************************************************/
29 /*! @brief Pointers to CMP bases for each instance. */
30 static CMP_Type *const s_cmpBases[] = CMP_BASE_PTRS;
31 #if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
32 /*! @brief Pointers to CMP clocks for each instance. */
33 static const clock_ip_name_t s_cmpClocks[] = CMP_CLOCKS;
34 #endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
35 
36 /*******************************************************************************
37  * Codes
38  ******************************************************************************/
CMP_GetInstance(CMP_Type * base)39 static uint32_t CMP_GetInstance(CMP_Type *base)
40 {
41     uint32_t instance;
42 
43     /* Find the instance index from base address mappings. */
44     for (instance = 0; instance < ARRAY_SIZE(s_cmpBases); instance++)
45     {
46         if (s_cmpBases[instance] == base)
47         {
48             break;
49         }
50     }
51 
52     assert(instance < ARRAY_SIZE(s_cmpBases));
53 
54     return instance;
55 }
56 
57 /*!
58  * brief Initializes the CMP.
59  *
60  * This function initializes the CMP module. The operations included are as follows.
61  * - Enabling the clock for CMP module.
62  * - Configuring the comparator.
63  * - Enabling the CMP module.
64  * Note that for some devices, multiple CMP instances share the same clock gate. In this case, to enable the clock for
65  * any instance enables all CMPs. See the appropriate MCU reference manual for the clock assignment of the CMP.
66  *
67  * param base   CMP peripheral base address.
68  * param config Pointer to the configuration structure.
69  */
CMP_Init(CMP_Type * base,const cmp_config_t * config)70 void CMP_Init(CMP_Type *base, const cmp_config_t *config)
71 {
72     assert(NULL != config);
73 
74     uint8_t tmp8;
75 
76 #if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
77     /* Enable the clock. */
78     CLOCK_EnableClock(s_cmpClocks[CMP_GetInstance(base)]);
79 #endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
80 
81     /* Configure. */
82     CMP_Enable(base, false); /* Disable the CMP module during configuring. */
83     /* CMPx_CR1. */
84     tmp8 = (uint8_t)(base->CR1 & ~(CMP_CR1_PMODE_MASK | CMP_CR1_INV_MASK | CMP_CR1_COS_MASK | CMP_CR1_OPE_MASK));
85     if (true == config->enableHighSpeed)
86     {
87         tmp8 |= CMP_CR1_PMODE_MASK;
88     }
89     if (true == config->enableInvertOutput)
90     {
91         tmp8 |= CMP_CR1_INV_MASK;
92     }
93     if (true == config->useUnfilteredOutput)
94     {
95         tmp8 |= CMP_CR1_COS_MASK;
96     }
97     if (true == config->enablePinOut)
98     {
99         tmp8 |= CMP_CR1_OPE_MASK;
100     }
101 #if defined(FSL_FEATURE_CMP_HAS_TRIGGER_MODE) && FSL_FEATURE_CMP_HAS_TRIGGER_MODE
102     if (true == config->enableTriggerMode)
103     {
104         tmp8 |= CMP_CR1_TRIGM_MASK;
105     }
106     else
107     {
108         tmp8 &= ~(uint8_t)CMP_CR1_TRIGM_MASK;
109     }
110 #endif /* FSL_FEATURE_CMP_HAS_TRIGGER_MODE */
111     base->CR1 = tmp8;
112 
113     /* CMPx_CR0. */
114     tmp8 = base->CR0 & ~(uint8_t)CMP_CR0_HYSTCTR_MASK;
115     tmp8 |= CMP_CR0_HYSTCTR(config->hysteresisMode);
116     base->CR0 = tmp8;
117 
118     CMP_Enable(base, config->enableCmp); /* Enable the CMP module after configured or not. */
119 }
120 
121 /*!
122  * brief De-initializes the CMP module.
123  *
124  * This function de-initializes the CMP module. The operations included are as follows.
125  * - Disabling the CMP module.
126  * - Disabling the clock for CMP module.
127  *
128  * This function disables the clock for the CMP.
129  * Note that for some devices, multiple CMP instances share the same clock gate. In this case, before disabling the
130  * clock for the CMP, ensure that all the CMP instances are not used.
131  *
132  * param base CMP peripheral base address.
133  */
CMP_Deinit(CMP_Type * base)134 void CMP_Deinit(CMP_Type *base)
135 {
136     // Disable the CMP module.
137     base->CR0 = 0U;
138     base->CR1 = 0U;
139 
140 #if !(defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL)
141     /* Disable the clock. */
142     CLOCK_DisableClock(s_cmpClocks[CMP_GetInstance(base)]);
143 #endif /* FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL */
144 }
145 
146 /*!
147  * brief Initializes the CMP user configuration structure.
148  *
149  * This function initializes the user configuration structure to these default values.
150  * code
151  *   config->enableCmp           = true;
152  *   config->hysteresisMode      = kCMP_HysteresisLevel0;
153  *   config->enableHighSpeed     = false;
154  *   config->enableInvertOutput  = false;
155  *   config->useUnfilteredOutput = false;
156  *   config->enablePinOut        = false;
157  *   config->enableTriggerMode   = false;
158  * endcode
159  * param config Pointer to the configuration structure.
160  */
CMP_GetDefaultConfig(cmp_config_t * config)161 void CMP_GetDefaultConfig(cmp_config_t *config)
162 {
163     assert(NULL != config);
164 
165     /* Initializes the configure structure to zero. */
166     (void)memset(config, 0, sizeof(*config));
167 
168     config->enableCmp           = true; /* Enable the CMP module after initialization. */
169     config->hysteresisMode      = kCMP_HysteresisLevel0;
170     config->enableHighSpeed     = false;
171     config->enableInvertOutput  = false;
172     config->useUnfilteredOutput = false;
173     config->enablePinOut        = false;
174 #if defined(FSL_FEATURE_CMP_HAS_TRIGGER_MODE) && FSL_FEATURE_CMP_HAS_TRIGGER_MODE
175     config->enableTriggerMode = false;
176 #endif /* FSL_FEATURE_CMP_HAS_TRIGGER_MODE */
177 }
178 
179 /*!
180  * brief  Sets the input channels for the comparator.
181  *
182  * This function sets the input channels for the comparator.
183  * Note that two input channels cannot be set the same way in the application. When the user selects the same input
184  * from the analog mux to the positive and negative port, the comparator is disabled automatically.
185  *
186  * param  base            CMP peripheral base address.
187  * param  positiveChannel Positive side input channel number. Available range is 0-7.
188  * param  negativeChannel Negative side input channel number. Available range is 0-7.
189  */
CMP_SetInputChannels(CMP_Type * base,uint8_t positiveChannel,uint8_t negativeChannel)190 void CMP_SetInputChannels(CMP_Type *base, uint8_t positiveChannel, uint8_t negativeChannel)
191 {
192     uint8_t tmp8 = base->MUXCR;
193 
194     tmp8 &= ~(uint8_t)(CMP_MUXCR_PSEL_MASK | CMP_MUXCR_MSEL_MASK);
195     tmp8 |= CMP_MUXCR_PSEL(positiveChannel) | CMP_MUXCR_MSEL(negativeChannel);
196     base->MUXCR = tmp8;
197 }
198 
199 #if defined(FSL_FEATURE_CMP_HAS_DMA) && FSL_FEATURE_CMP_HAS_DMA
200 /*!
201  * brief Enables/disables the DMA request for rising/falling events.
202  *
203  * This function enables/disables the DMA request for rising/falling events. Either event triggers the generation of
204  * the DMA request from CMP if the DMA feature is enabled. Both events are ignored for generating the DMA request from
205  * the CMP
206  * if the DMA is disabled.
207  *
208  * param base CMP peripheral base address.
209  * param enable Enables or disables the feature.
210  */
CMP_EnableDMA(CMP_Type * base,bool enable)211 void CMP_EnableDMA(CMP_Type *base, bool enable)
212 {
213     uint8_t tmp8 = (uint8_t)(base->SCR & ~(CMP_SCR_CFR_MASK | CMP_SCR_CFF_MASK)); /* To avoid change the w1c bits. */
214 
215     if (enable)
216     {
217         tmp8 |= CMP_SCR_DMAEN_MASK;
218     }
219     else
220     {
221         tmp8 &= ~(uint8_t)CMP_SCR_DMAEN_MASK;
222     }
223     base->SCR = tmp8;
224 }
225 #endif /* FSL_FEATURE_CMP_HAS_DMA */
226 
227 /*!
228  * brief  Configures the filter.
229  *
230  * param  base   CMP peripheral base address.
231  * param  config Pointer to the configuration structure.
232  */
CMP_SetFilterConfig(CMP_Type * base,const cmp_filter_config_t * config)233 void CMP_SetFilterConfig(CMP_Type *base, const cmp_filter_config_t *config)
234 {
235     assert(NULL != config);
236 
237     uint8_t tmp8;
238 
239 #if defined(FSL_FEATURE_CMP_HAS_EXTERNAL_SAMPLE_SUPPORT) && FSL_FEATURE_CMP_HAS_EXTERNAL_SAMPLE_SUPPORT
240     /* Choose the clock source for sampling. */
241     if (config->enableSample)
242     {
243         base->CR1 |= CMP_CR1_SE_MASK; /* Choose the external SAMPLE clock. */
244     }
245     else
246     {
247         base->CR1 &= (uint8_t)(~CMP_CR1_SE_MASK); /* Choose the internal divided bus clock. */
248     }
249 #endif /* FSL_FEATURE_CMP_HAS_EXTERNAL_SAMPLE_SUPPORT */
250     /* Set the filter count. */
251     tmp8 = (uint8_t)(base->CR0 & ~CMP_CR0_FILTER_CNT_MASK);
252     tmp8 |= CMP_CR0_FILTER_CNT(config->filterCount);
253     base->CR0 = tmp8;
254     /* Set the filter period. It is used as the divider to bus clock. */
255     base->FPR = CMP_FPR_FILT_PER(config->filterPeriod);
256 }
257 
258 /*!
259  * brief Configures the internal DAC.
260  *
261  * param base   CMP peripheral base address.
262  * param config Pointer to the configuration structure. "NULL" disables the feature.
263  */
CMP_SetDACConfig(CMP_Type * base,const cmp_dac_config_t * config)264 void CMP_SetDACConfig(CMP_Type *base, const cmp_dac_config_t *config)
265 {
266     uint8_t tmp8 = 0U;
267 
268     if (NULL == config)
269     {
270         /* Passing "NULL" as input parameter means no available configuration. So the DAC feature is disabled.*/
271         base->DACCR = 0U;
272         return;
273     }
274     /* CMPx_DACCR. */
275     tmp8 |= CMP_DACCR_DACEN_MASK; /* Enable the internal DAC. */
276     if (kCMP_VrefSourceVin2 == config->referenceVoltageSource)
277     {
278         tmp8 |= CMP_DACCR_VRSEL_MASK;
279     }
280     tmp8 |= CMP_DACCR_VOSEL(config->DACValue);
281 
282     base->DACCR = tmp8;
283 }
284 
285 /*!
286  * brief Enables the interrupts.
287  *
288  * param base    CMP peripheral base address.
289  * param mask    Mask value for interrupts. See "_cmp_interrupt_enable".
290  */
CMP_EnableInterrupts(CMP_Type * base,uint32_t mask)291 void CMP_EnableInterrupts(CMP_Type *base, uint32_t mask)
292 {
293     uint8_t tmp8 = (uint8_t)(base->SCR & ~(CMP_SCR_CFR_MASK | CMP_SCR_CFF_MASK)); /* To avoid change the w1c bits. */
294 
295     if (0U != ((uint32_t)kCMP_OutputRisingInterruptEnable & mask))
296     {
297         tmp8 |= CMP_SCR_IER_MASK;
298     }
299     if (0U != ((uint32_t)kCMP_OutputFallingInterruptEnable & mask))
300     {
301         tmp8 |= CMP_SCR_IEF_MASK;
302     }
303     base->SCR = tmp8;
304 }
305 
306 /*!
307  * brief Disables the interrupts.
308  *
309  * param base    CMP peripheral base address.
310  * param mask    Mask value for interrupts. See "_cmp_interrupt_enable".
311  */
CMP_DisableInterrupts(CMP_Type * base,uint32_t mask)312 void CMP_DisableInterrupts(CMP_Type *base, uint32_t mask)
313 {
314     uint8_t tmp8 = (uint8_t)(base->SCR & ~(CMP_SCR_CFR_MASK | CMP_SCR_CFF_MASK)); /* To avoid change the w1c bits. */
315 
316     if (0U != ((uint32_t)kCMP_OutputRisingInterruptEnable & mask))
317     {
318         tmp8 &= ~(uint8_t)CMP_SCR_IER_MASK;
319     }
320     if (0U != ((uint32_t)kCMP_OutputFallingInterruptEnable & mask))
321     {
322         tmp8 &= ~(uint8_t)CMP_SCR_IEF_MASK;
323     }
324     base->SCR = tmp8;
325 }
326 
327 /*!
328  * brief  Gets the status flags.
329  *
330  * param  base     CMP peripheral base address.
331  *
332  * return          Mask value for the asserted flags. See "_cmp_status_flags".
333  */
CMP_GetStatusFlags(CMP_Type * base)334 uint32_t CMP_GetStatusFlags(CMP_Type *base)
335 {
336     uint32_t ret32 = 0U;
337 
338     if (0U != (CMP_SCR_CFR_MASK & base->SCR))
339     {
340         ret32 |= (uint32_t)kCMP_OutputRisingEventFlag;
341     }
342     if (0U != (CMP_SCR_CFF_MASK & base->SCR))
343     {
344         ret32 |= (uint32_t)kCMP_OutputFallingEventFlag;
345     }
346     if (0U != (CMP_SCR_COUT_MASK & base->SCR))
347     {
348         ret32 |= (uint32_t)kCMP_OutputAssertEventFlag;
349     }
350     return ret32;
351 }
352 
353 /*!
354  * brief Clears the status flags.
355  *
356  * param base     CMP peripheral base address.
357  * param mask     Mask value for the flags. See "_cmp_status_flags".
358  */
CMP_ClearStatusFlags(CMP_Type * base,uint32_t mask)359 void CMP_ClearStatusFlags(CMP_Type *base, uint32_t mask)
360 {
361     uint8_t tmp8 = (uint8_t)(base->SCR & ~(CMP_SCR_CFR_MASK | CMP_SCR_CFF_MASK)); /* To avoid change the w1c bits. */
362 
363     if (0U != ((uint32_t)kCMP_OutputRisingEventFlag & mask))
364     {
365         tmp8 |= CMP_SCR_CFR_MASK;
366     }
367     if (0U != ((uint32_t)kCMP_OutputFallingEventFlag & mask))
368     {
369         tmp8 |= CMP_SCR_CFF_MASK;
370     }
371     base->SCR = tmp8;
372 }
373