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