1 /*
2  * Copyright 2020-2023 NXP
3  * All rights reserved.
4  *
5  * SPDX-License-Identifier: BSD-3-Clause
6  */
7 
8 #include "fsl_ccm32k.h"
9 
10 /*******************************************************************************
11  * Definitions
12  ******************************************************************************/
13 
14 /* Component ID definition, used by tools. */
15 #ifndef FSL_COMPONENT_ID
16 #define FSL_COMPONENT_ID "platform.drivers.ccm32k"
17 #endif
18 
19 /*******************************************************************************
20  * Prototypes
21  ******************************************************************************/
22 
23 /*******************************************************************************
24  * Variables
25  ******************************************************************************/
26 
27 /*******************************************************************************
28  * Code
29  ******************************************************************************/
30 
31 /*!
32  * brief Enable/Disable 32kHz free-running oscillator.
33  *
34  * note There is a start up time before clocks are output from the FRO.
35  *
36  * @code
37  *          CCM32K_Enable32kFro(base, true);        //Enable FRO analog oscillator.
38  *          CCM32K_DisableCLKOutToPeripherals(base, mask); //Disable clock out.
39  *          CCM32K_SelectClockSource(base, kCCM32K_ClockSourceSelectFro32k); //Select FRO32k as clock source.
40  *          while(CCM32K_GetStatus(base) != kCCM32K_32kFroActiveStatusFlag); //Check FOR32k is active and in used.
41  *          CCM32K_EnableCLKOutToPeripherals(base, mask); //Enable clock out if needed.
42  * @endcode
43  *
44  * param base CCM32K peripheral base address.
45  * param enable   Boolean value to enable or disable the 32kHz free-running oscillator.
46  *                  true    --    Enable 32kHz free-running oscillator.
47  *                  false   --    Disable 32kHz free-running oscillator.
48  */
CCM32K_Enable32kFro(CCM32K_Type * base,bool enable)49 void CCM32K_Enable32kFro(CCM32K_Type *base, bool enable)
50 {
51     if (enable)
52     {
53         if ((base->FRO32K_CTRL & CCM32K_FRO32K_CTRL_FRO_EN_MASK) != 0UL)
54         {
55             return;
56         }
57 
58         base->FRO32K_CTRL |= CCM32K_FRO32K_CTRL_FRO_EN_MASK;
59     }
60     else
61     {
62         base->FRO32K_CTRL &= ~CCM32K_FRO32K_CTRL_FRO_EN_MASK;
63     }
64 }
65 
66 /*!
67  * brief Set the frequency trim value of 32kHz free-running oscillator by software.
68  *
69  * param base CCM32K peripheral base address.
70  * param trimValue The frequency trim value.
71  */
CCM32K_Set32kFroTrimValue(CCM32K_Type * base,uint16_t trimValue)72 void CCM32K_Set32kFroTrimValue(CCM32K_Type *base, uint16_t trimValue)
73 {
74     uint32_t tmp32;
75     bool froEnabled;
76 
77     froEnabled = ((base->FRO32K_CTRL & CCM32K_FRO32K_CTRL_FRO_EN_MASK) != 0UL) ? true : false;
78     if (froEnabled)
79     {
80         /* If the free-running oscillator is enabled, disable it temporarily. */
81         CCM32K_Enable32kFro(base, false);
82     }
83 
84     tmp32 = base->FRO32K_TRIM;
85     tmp32 &= ~CCM32K_FRO32K_TRIM_FREQ_TRIM_MASK;
86     tmp32 |= CCM32K_FRO32K_TRIM_FREQ_TRIM(trimValue);
87     base->FRO32K_TRIM = tmp32;
88 
89     if (froEnabled)
90     {
91         /* If the free-running oscillator is enabled previously, remember to enable it again. */
92         CCM32K_Enable32kFro(base, true);
93     }
94 }
95 
96 /*!
97  * brief Config 32k Crystal Oscillator.
98  *
99  * note When the mode selected as \ref kCCM32K_Disable32kHzCrystalOsc or \ref kCCM32K_Bypass32kHzCrystalOsc
100  *       the parameter config is useless, so it can be set as "NULL".
101  *
102  *  @code
103  *   CCM32K_Set32kOscConfig(base, kCCM32K_Enable32kHzCrystalOsc, config); //Enable OSC32k and set config.
104  *   while((CCM32K_GetStatus(base) & kCCM32K_32kOscReadyStatusFlag) == 0UL); //Check if OSC32K is stable.
105  *   CCM32K_DisableCLKOutToPeripherals(base, mask); //Disable clock out.
106  *   CCM32K_SelectClockSource(base, kCCM32K_ClockSourceSelectOsc32k); //Select OSC32k as clock source.
107  *   while((CCM32K_GetStatus(base) & kCCM32K_32kOscActiveStatusFlag) == 0UL); //Check if OSC32K is used as clock source.
108  *   CCM32K_EnableCLKOutToPeripherals(base, mask); //Enable clock out.
109  *  @endcode
110  *
111  * param base CCM32K peripheral base address.
112  * param mode The mode of 32k crystal oscillator.
113  * param config The pointer to the structure \ref ccm32k_osc_config_t.
114  */
CCM32K_Set32kOscConfig(CCM32K_Type * base,ccm32k_osc_mode_t mode,const ccm32k_osc_config_t * config)115 void CCM32K_Set32kOscConfig(CCM32K_Type *base, ccm32k_osc_mode_t mode, const ccm32k_osc_config_t *config)
116 {
117     uint32_t tmp32;
118 
119     if (mode == kCCM32K_Disable32kHzCrystalOsc)
120     {
121         /* OSC32k should not be disabled if it is used as clock source of 32 kHz. */
122         assert(CCM32K_GetClockSource(base) != kCCM32K_ClockSource32kOsc);
123         base->OSC32K_CTRL &= ~(CCM32K_OSC32K_CTRL_OSC_MODE_MASK | CCM32K_OSC32K_CTRL_SOX_EN_MASK);
124     }
125     else if (mode == kCCM32K_Bypass32kHzCrystalOsc)
126     {
127         base->OSC32K_CTRL |= CCM32K_OSC32K_CTRL_OSC_MODE_MASK;
128     }
129     else
130     {
131         tmp32 = base->OSC32K_CTRL;
132 
133         /*
134          * $Branch Coverage Justification$
135          * (config == NULL) not covered. The conifg memory space value cannot set to null.
136          */
137         if (config != NULL)
138         {
139             if (config->enableInternalCapBank)
140             {
141                 tmp32 &= ~(CCM32K_OSC32K_CTRL_EXTAL_CAP_SEL_MASK | CCM32K_OSC32K_CTRL_XTAL_CAP_SEL_MASK);
142                 tmp32 |= CCM32K_OSC32K_CTRL_EXTAL_CAP_SEL(config->extalCap) |
143                          CCM32K_OSC32K_CTRL_XTAL_CAP_SEL(config->xtalCap);
144                 tmp32 |= CCM32K_OSC32K_CTRL_CAP_SEL_EN_MASK;
145             }
146             else
147             {
148                 /* Disable the internal capacitance bank. */
149                 tmp32 &= ~CCM32K_OSC32K_CTRL_CAP_SEL_EN_MASK;
150             }
151 
152             tmp32 &= ~(CCM32K_OSC32K_CTRL_COARSE_AMP_GAIN_MASK);
153             tmp32 |= CCM32K_OSC32K_CTRL_COARSE_AMP_GAIN(config->coarseAdjustment);
154 #if (defined(FSL_FEATURE_CCM32K_HAS_FINE_AMP_GAIN) && FSL_FEATURE_CCM32K_HAS_FINE_AMP_GAIN)
155             tmp32 &= ~(CCM32K_OSC32K_CTRL_FINE_AMP_GAIN_MASK);
156             tmp32 |= CCM32K_OSC32K_CTRL_FINE_AMP_GAIN(config->fineAdjustment);
157 #endif /* FSL_FEATURE_CCM32K_HAS_FINE_AMP_GAIN */
158         }
159 
160         tmp32 |= CCM32K_OSC32K_CTRL_OSC_MODE(mode) | CCM32K_OSC32K_CTRL_SOX_EN_MASK;
161         base->OSC32K_CTRL = tmp32;
162     }
163 }
164 
165 #if (defined(FSL_FEATURE_CCM32K_HAS_CLKMON_CTRL) && FSL_FEATURE_CCM32K_HAS_CLKMON_CTRL)
166 
167 /*!
168  * brief Enable/disable clock monitor.
169  *
170  * param base CCM32K peripheral base address.
171  * param enable Used to enable/disable clock monitor.
172  *          - \b turn Enable clock monitor.
173  *          - \b false Disable clock monitor.
174  */
CCM32K_EnableClockMonitor(CCM32K_Type * base,bool enable)175 void CCM32K_EnableClockMonitor(CCM32K_Type *base, bool enable)
176 {
177     if (enable)
178     {
179         /* To enable monitor, one of 32k Hz clock source must be enabled. */
180         assert(CCM32K_GetClockSource(base) != kCCM32K_ClockSourceNone);
181         base->CLKMON_CTRL |= CCM32K_CLKMON_CTRL_MON_EN_MASK;
182     }
183     else
184     {
185         base->CLKMON_CTRL &= ~CCM32K_CLKMON_CTRL_MON_EN_MASK;
186     }
187 }
188 
189 /*!
190  * brief Config clock monitor one time, including frequency trim value, divide trim value.
191  *
192  * param base CCM32K peripheral base address.
193  * param config Pointer to @ref ccm32k_clock_monitor_config_t structure.
194  */
CCM32K_SetClockMonitorConfig(CCM32K_Type * base,const ccm32k_clock_monitor_config_t * config)195 void CCM32K_SetClockMonitorConfig(CCM32K_Type *base, const ccm32k_clock_monitor_config_t *config)
196 {
197     assert(config);
198 
199     if (config->enableClockMonitor)
200     {
201         CCM32K_EnableClockMonitor(base, false);
202     }
203 
204     CCM32K_SetClockMonitorFreqTrimValue(base, config->freqTrimValue);
205     CCM32K_SetClockMonitorDivideTrimValue(base, config->divideTrimValue);
206     CCM32K_EnableClockMonitor(base, config->enableClockMonitor);
207 }
208 #endif /* FSL_FEATURE_CCM32K_HAS_CLKMON_CTRL */
209 
210 /*!
211  * brief Get current state.
212  *
213  * param base CCM32K peripheral base address.
214  * return The CCM32K's current state, please refer to \ref ccm32k_state_t for details.
215  */
CCM32K_GetCurrentState(CCM32K_Type * base)216 ccm32k_state_t CCM32K_GetCurrentState(CCM32K_Type *base)
217 {
218     uint8_t state = 0U;
219 
220     if ((base->FRO32K_CTRL & CCM32K_FRO32K_CTRL_FRO_EN_MASK) != 0UL)
221     {
222         state |= (uint8_t)kCCM32K_Only32kFroEnabled;
223     }
224 
225     if ((base->OSC32K_CTRL & CCM32K_OSC32K_CTRL_OSC_EN_MASK) != 0UL)
226     {
227         state |= (uint8_t)kCCM32K_Only32kOscEnabled;
228     }
229 
230     return (ccm32k_state_t)state;
231 }
232 
233 /*!
234  * brief Return current clock source.
235  *
236  * param base CCM32K peripheral base address.
237  * retval kCCM32K_ClockSourceNone The none clock source is selected.
238  * retval kCCM32K_ClockSource32kFro 32kHz free-running oscillator is selected as clock source.
239  * retval kCCM32K_ClockSource32kOsc 32kHz crystal oscillator is selected as clock source..
240  */
CCM32K_GetClockSource(CCM32K_Type * base)241 ccm32k_clock_source_t CCM32K_GetClockSource(CCM32K_Type *base)
242 {
243     uint32_t statusFlag;
244     ccm32k_clock_source_t clockSource = kCCM32K_ClockSourceNone;
245 
246     statusFlag = CCM32K_GetStatusFlag(base);
247 
248     if (statusFlag == ((uint32_t)kCCM32K_32kOscActiveStatusFlag | (uint32_t)kCCM32K_32kOscReadyStatusFlag))
249     {
250         clockSource = kCCM32K_ClockSource32kOsc;
251     }
252     else if ((statusFlag & (uint32_t)kCCM32K_32kFroActiveStatusFlag) != 0UL)
253     {
254         clockSource = kCCM32K_ClockSource32kFro;
255     }
256     /*
257      * $Branch Coverage Justification$
258      * (statusFlag != 0UL) not covered. All status are covered above.
259      */
260     else
261     {
262         clockSource = kCCM32K_ClockSourceNone;
263     }
264 
265     return clockSource;
266 }
267