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