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