1 /*
2 * Copyright 2017-2019 NXP
3 * All rights reserved.
4 *
5 * SPDX-License-Identifier: BSD-3-Clause
6 */
7
8 #include "fsl_clock.h"
9 #include "rom_api.h"
10 /*******************************************************************************
11 * Definitions
12 ******************************************************************************/
13 /* Component ID definition, used by tools. */
14 #ifndef FSL_COMPONENT_ID
15 #define FSL_COMPONENT_ID "platform.drivers.clock"
16 #endif
17 #define SYSPLL_MIN_INPUT_FREQ_HZ (10000000U) /*!< Minimum PLL input rate */
18 #define SYSPLL_MAX_INPUT_FREQ_HZ (25000000U) /*!< Maximum PLL input rate */
19 #define SYSPLL_MAX_OUTPUT_FREQ_HZ (100000000U) /*!< Maximum PLL output rate */
20 #define SYSOSC_BOUNDARY_FREQ_HZ (15000000U) /*!< boundary frequency value */
21
22 /* External clock rate.
23 * Either external clk in rate or system oscillator frequency.
24 */
25 volatile uint32_t g_Ext_Clk_Freq = 0U;
26 /** watch dog oscillator rate in Hz.*/
27 volatile uint32_t g_Wdt_Osc_Freq = 0U;
28 /** For oscillator rate in Hz */
29 volatile uint32_t g_Fro_Osc_Freq = 0U;
30
31 /*******************************************************************************
32 * Variables
33 ******************************************************************************/
34
35 /*******************************************************************************
36 * Prototypes
37 ******************************************************************************/
38
39 /*
40 * @brief Get
41 input clock frequency.
42 * @param fractional clock register base address.
43 * @return input clock frequency.
44 */
45 static uint32_t CLOCK_GetFRGInputClkFreq(uint32_t *base);
46
47 /*
48 * @brief Update clock source.
49 * @param base clock register base address.
50 * @param mask clock source update enable bit mask value.
51 */
52 static void CLOCK_UpdateClkSrc(volatile uint32_t *base, uint32_t mask);
53
54 /*******************************************************************************
55 * Code
56 ******************************************************************************/
CLOCK_GetFRGInputClkFreq(uint32_t * base)57 static uint32_t CLOCK_GetFRGInputClkFreq(uint32_t *base)
58 {
59 uint32_t sel = CLK_FRG_SEL_REG_MAP(base) & SYSCON_FRG_FRGCLKSEL_SEL_MASK;
60 uint32_t freq;
61
62 if (sel == 0U)
63 {
64 freq = CLOCK_GetFroFreq();
65 }
66 else
67 {
68 freq = CLOCK_GetMainClkFreq();
69 }
70 return freq;
71 }
72
73 /*! brief Set FRG0 output frequency.
74 * param freq, target output frequency,freq < input and (input / freq) < 2 should be satisfy.
75 * retval true - successfully, false - input argument is invalid.
76 *
77 */
CLOCK_SetFRGClkFreq(uint32_t freq)78 bool CLOCK_SetFRGClkFreq(uint32_t freq)
79 {
80 assert(freq);
81
82 uint32_t *base = (uint32_t *)(&SYSCON->FRG);
83 uint32_t input = CLOCK_GetFRGInputClkFreq(base);
84 uint32_t mul;
85
86 if ((freq > input) || (input / freq >= 2U))
87 {
88 return false;
89 }
90
91 mul = (uint32_t)(((uint64_t)((uint64_t)input - freq) << 8U) / ((uint64_t)freq));
92
93 CLK_FRG_DIV_REG_MAP(base) = SYSCON_FRG_FRGDIV_DIV_MASK;
94 CLK_FRG_MUL_REG_MAP(base) = SYSCON_FRG_FRGMULT_MULT(mul);
95
96 return true;
97 }
98
CLOCK_UpdateClkSrc(volatile uint32_t * base,uint32_t mask)99 static void CLOCK_UpdateClkSrc(volatile uint32_t *base, uint32_t mask)
100 {
101 assert(base);
102
103 *base &= ~mask;
104 *base |= mask;
105 while ((*base & mask) == 0U)
106 {
107 }
108 }
109
110 /*! brief Return Frequency of FRG0 Clock.
111 * return Frequency of FRG0 Clock.
112 */
CLOCK_GetFRGClkFreq(void)113 uint32_t CLOCK_GetFRGClkFreq(void)
114 {
115 uint32_t temp;
116
117 temp = CLOCK_GetFRGInputClkFreq((uint32_t *)(&SYSCON->FRG)) << 8U;
118 return (uint32_t)(((uint64_t)(temp)) / (((uint64_t)SYSCON->FRG->FRGMULT & SYSCON_FRG_FRGMULT_MULT_MASK) + 256ULL));
119 }
120
121 /*! brief Return Frequency of Main Clock.
122 * return Frequency of Main Clock.
123 */
CLOCK_GetMainClkFreq(void)124 uint32_t CLOCK_GetMainClkFreq(void)
125 {
126 uint32_t freq = 0U;
127
128 switch (SYSCON->MAINCLKSEL)
129 {
130 case 0U:
131 freq = CLOCK_GetFroFreq();
132 break;
133
134 case 1U:
135 freq = CLOCK_GetExtClkFreq();
136 break;
137
138 case 2U:
139 freq = CLOCK_GetLPOscFreq();
140 break;
141
142 case 3U:
143 freq = CLOCK_GetFroFreq() >> 1U;
144 break;
145 default:
146 assert(false);
147 break;
148 }
149
150 return freq;
151 }
152
153 /*! brief Return Frequency of FRO.
154 * return Frequency of FRO.
155 */
CLOCK_GetFroFreq(void)156 uint32_t CLOCK_GetFroFreq(void)
157 {
158 return g_Fro_Osc_Freq / 2U;
159 }
160
161 /*! brief Return Frequency of ClockOut
162 * return Frequency of ClockOut
163 */
CLOCK_GetClockOutClkFreq(void)164 uint32_t CLOCK_GetClockOutClkFreq(void)
165 {
166 uint32_t div = SYSCON->CLKOUTDIV & 0xffU, freq = 0U;
167
168 switch (SYSCON->CLKOUTSEL)
169 {
170 case 0U:
171 freq = CLOCK_GetFroFreq();
172 break;
173
174 case 1U:
175 freq = CLOCK_GetMainClkFreq();
176 break;
177
178 case 3U:
179 freq = CLOCK_GetExtClkFreq();
180 break;
181
182 case 4U:
183 freq = CLOCK_GetLPOscFreq();
184 break;
185
186 default:
187 assert(false);
188 break;
189 }
190
191 return div == 0U ? 0U : (freq / div);
192 }
193
194 /*! brief Return Frequency of UART0
195 * return Frequency of UART0
196 */
CLOCK_GetUart0ClkFreq(void)197 uint32_t CLOCK_GetUart0ClkFreq(void)
198 {
199 uint32_t freq = 0U;
200
201 switch (SYSCON->UART0CLKSEL)
202 {
203 case 0U:
204 freq = CLOCK_GetFroFreq();
205 break;
206 case 1U:
207 freq = CLOCK_GetMainClkFreq();
208 break;
209 case 2U:
210 freq = CLOCK_GetFRGClkFreq();
211 break;
212 case 4U:
213 freq = CLOCK_GetFroFreq() >> 1U;
214 break;
215
216 default:
217 assert(false);
218 break;
219 }
220
221 return freq;
222 }
223
224 /*! brief Return Frequency of UART1
225 * return Frequency of UART1
226 */
CLOCK_GetUart1ClkFreq(void)227 uint32_t CLOCK_GetUart1ClkFreq(void)
228 {
229 uint32_t freq = 0U;
230
231 switch (SYSCON->UART1CLKSEL)
232 {
233 case 0U:
234 freq = CLOCK_GetFroFreq();
235 break;
236 case 1U:
237 freq = CLOCK_GetMainClkFreq();
238 break;
239 case 2U:
240 freq = CLOCK_GetFRGClkFreq();
241 break;
242 case 4U:
243 freq = CLOCK_GetFroFreq() >> 1U;
244 break;
245
246 default:
247 assert(false);
248 break;
249 }
250
251 return freq;
252 }
253
254 /*! brief Return Frequency of selected clock
255 * return Frequency of selected clock
256 */
CLOCK_GetFreq(clock_name_t clockName)257 uint32_t CLOCK_GetFreq(clock_name_t clockName)
258 {
259 uint32_t freq;
260
261 switch (clockName)
262 {
263 case kCLOCK_CoreSysClk:
264 freq = CLOCK_GetCoreSysClkFreq();
265 break;
266 case kCLOCK_MainClk:
267 freq = CLOCK_GetMainClkFreq();
268 break;
269 case kCLOCK_Fro:
270 freq = CLOCK_GetFroFreq();
271 break;
272 case kCLOCK_FroDiv:
273 freq = CLOCK_GetFroFreq() >> 1U;
274 break;
275 case kCLOCK_ExtClk:
276 freq = CLOCK_GetExtClkFreq();
277 break;
278 case kCLOCK_LPOsc:
279 freq = CLOCK_GetLPOscFreq();
280 break;
281 case kCLOCK_Frg:
282 freq = CLOCK_GetFRGClkFreq();
283 break;
284
285 default:
286 freq = 0U;
287 break;
288 }
289
290 return freq;
291 }
292
293 /*! brief Init external CLK IN, select the CLKIN as the external clock source.
294 * param clkInFreq external clock in frequency.
295 */
CLOCK_InitExtClkin(uint32_t clkInFreq)296 void CLOCK_InitExtClkin(uint32_t clkInFreq)
297 {
298 /* remove the pull up and pull down resistors in the IOCON */
299 IOCON->PIO[IOCON_INDEX_PIO0_1] &= ~IOCON_PIO_MODE_MASK;
300 /* enable the 1 bit functions for CLKIN */
301 SWM0->PINENABLE0 &= ~SWM_PINENABLE0_CLKIN_MASK;
302 /* record the external clock rate */
303 g_Ext_Clk_Freq = clkInFreq;
304 }
305
306 /*! brief Set main clock reference source.
307 * param src, reference clock_main_clk_src_t to set the main clock source.
308 */
CLOCK_SetMainClkSrc(clock_main_clk_src_t src)309 void CLOCK_SetMainClkSrc(clock_main_clk_src_t src)
310 {
311 uint32_t mainMux = CLK_MAIN_CLK_MUX_GET_MUX(src), mainPreMux = CLK_MAIN_CLK_MUX_GET_PRE_MUX(src);
312
313 if (((SYSCON->MAINCLKSEL & SYSCON_MAINCLKSEL_SEL_MASK) != mainPreMux) && (mainMux == 0U))
314 {
315 SYSCON->MAINCLKSEL = (SYSCON->MAINCLKSEL & (~SYSCON_MAINCLKSEL_SEL_MASK)) | SYSCON_MAINCLKSEL_SEL(mainPreMux);
316 CLOCK_UpdateClkSrc((volatile uint32_t *)(&(SYSCON->MAINCLKUEN)), SYSCON_MAINCLKUEN_ENA_MASK);
317 }
318 }
319
320 /*! brief Set FRO oscillator output frequency.
321 * Initialize the FRO clock to given frequency (18, 24 or 30 MHz).
322 * param freq, please reference clock_fro_osc_freq_t definition, frequency must be one of 18000, 24000 or 30000 KHz.
323 *
324 */
CLOCK_SetFroOscFreq(clock_fro_osc_freq_t freq)325 void CLOCK_SetFroOscFreq(clock_fro_osc_freq_t freq)
326 {
327 g_Fro_Osc_Freq = ((uint32_t)freq) * 1000U;
328 LPC_PWRD_API->set_fro_frequency((uint32_t)freq);
329 }
330