1 /*!
2     \file    gd32vf103_rcu.c
3     \brief   RCU driver
4 
5     \version 2019-06-05, V1.0.0, firmware for GD32VF103
6     \version 2020-08-04, V1.1.0, firmware for GD32VF103
7 */
8 
9 /*
10     Copyright (c) 2020, GigaDevice Semiconductor Inc.
11 
12     Redistribution and use in source and binary forms, with or without modification,
13 are permitted provided that the following conditions are met:
14 
15     1. Redistributions of source code must retain the above copyright notice, this
16        list of conditions and the following disclaimer.
17     2. Redistributions in binary form must reproduce the above copyright notice,
18        this list of conditions and the following disclaimer in the documentation
19        and/or other materials provided with the distribution.
20     3. Neither the name of the copyright holder nor the names of its contributors
21        may be used to endorse or promote products derived from this software without
22        specific prior written permission.
23 
24     THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
25 AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
26 WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
27 IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
28 INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
29 NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
30 PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
31 WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
32 ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
33 OF SUCH DAMAGE.
34 */
35 
36 #include "gd32vf103_rcu.h"
37 
38 /* define clock source */
39 #define SEL_IRC8M                   ((uint16_t)0U)
40 #define SEL_HXTAL                   ((uint16_t)1U)
41 #define SEL_PLL                     ((uint16_t)2U)
42 
43 /* define startup timeout count */
44 #define OSC_STARTUP_TIMEOUT         ((uint32_t)0xFFFFFU)
45 #define LXTAL_STARTUP_TIMEOUT       ((uint32_t)0x3FFFFFFU)
46 
47 /*!
48     \brief      deinitialize the RCU
49     \param[in]  none
50     \param[out] none
51     \retval     none
52 */
rcu_deinit(void)53 void rcu_deinit(void)
54 {
55     /* enable IRC8M */
56     RCU_CTL |= RCU_CTL_IRC8MEN;
57     rcu_osci_stab_wait(RCU_IRC8M);
58     /* reset CTL register */
59     RCU_CTL &= ~(RCU_CTL_HXTALEN | RCU_CTL_CKMEN | RCU_CTL_PLLEN);
60     RCU_CTL &= ~RCU_CTL_HXTALBPS;
61     RCU_CTL &= ~(RCU_CTL_PLL1EN | RCU_CTL_PLL2EN);
62     /* reset CFG0 register */
63     RCU_CFG0 &= ~(RCU_CFG0_SCS | RCU_CFG0_AHBPSC | RCU_CFG0_APB1PSC | RCU_CFG0_APB2PSC |
64                   RCU_CFG0_ADCPSC | RCU_CFG0_PLLSEL | RCU_CFG0_PREDV0_LSB | RCU_CFG0_PLLMF |
65                   RCU_CFG0_USBFSPSC | RCU_CFG0_CKOUT0SEL | RCU_CFG0_ADCPSC_2 | RCU_CFG0_PLLMF_4);
66     /* reset INT and CFG1 register */
67     RCU_INT = 0x00ff0000U;
68     RCU_CFG1 &= ~(RCU_CFG1_PREDV0 | RCU_CFG1_PREDV1 | RCU_CFG1_PLL1MF | RCU_CFG1_PLL2MF |
69                   RCU_CFG1_PREDV0SEL | RCU_CFG1_I2S1SEL | RCU_CFG1_I2S2SEL);
70 }
71 
72 /*!
73     \brief      enable the peripherals clock
74     \param[in]  periph: RCU peripherals, refer to rcu_periph_enum
75                 only one parameter can be selected which is shown as below:
76       \arg        RCU_GPIOx (x=A,B,C,D,E): GPIO ports clock
77       \arg        RCU_AF : alternate function clock
78       \arg        RCU_CRC: CRC clock
79       \arg        RCU_DMAx (x=0,1): DMA clock
80       \arg        RCU_USBFS: USBFS clock
81       \arg        RCU_EXMC: EXMC clock
82       \arg        RCU_TIMERx (x=0,1,2,3,4,5,6): TIMER clock
83       \arg        RCU_WWDGT: WWDGT clock
84       \arg        RCU_SPIx (x=0,1,2): SPI clock
85       \arg        RCU_USARTx (x=0,1,2): USART clock
86       \arg        RCU_UARTx (x=3,4): UART clock
87       \arg        RCU_I2Cx (x=0,1): I2C clock
88       \arg        RCU_CANx (x=0,1): CAN clock
89       \arg        RCU_PMU: PMU clock
90       \arg        RCU_DAC: DAC clock
91       \arg        RCU_RTC: RTC clock
92       \arg        RCU_ADCx (x=0,1): ADC clock
93       \arg        RCU_BKPI: BKP interface clock
94     \param[out] none
95     \retval     none
96 */
rcu_periph_clock_enable(rcu_periph_enum periph)97 void rcu_periph_clock_enable(rcu_periph_enum periph)
98 {
99     RCU_REG_VAL(periph) |= BIT(RCU_BIT_POS(periph));
100 }
101 
102 /*!
103     \brief      disable the peripherals clock
104     \param[in]  periph: RCU peripherals, refer to rcu_periph_enum
105                 only one parameter can be selected which is shown as below:
106       \arg        RCU_GPIOx (x=A,B,C,D,E): GPIO ports clock
107       \arg        RCU_AF: alternate function clock
108       \arg        RCU_CRC: CRC clock
109       \arg        RCU_DMAx (x=0,1): DMA clock
110       \arg        RCU_USBFS: USBFS clock
111       \arg        RCU_EXMC: EXMC clock
112       \arg        RCU_TIMERx (x=0,1,2,3,4,5,6): TIMER clock
113       \arg        RCU_WWDGT: WWDGT clock
114       \arg        RCU_SPIx (x=0,1,2): SPI clock
115       \arg        RCU_USARTx (x=0,1,2): USART clock
116       \arg        RCU_UARTx (x=3,4): UART clock
117       \arg        RCU_I2Cx (x=0,1): I2C clock
118       \arg        RCU_CANx (x=0,1): CAN clock
119       \arg        RCU_PMU: PMU clock
120       \arg        RCU_DAC: DAC clock
121       \arg        RCU_RTC: RTC clock
122       \arg        RCU_ADCx (x=0,1): ADC clock
123       \arg        RCU_BKPI: BKP interface clock
124     \param[out] none
125     \retval     none
126 */
rcu_periph_clock_disable(rcu_periph_enum periph)127 void rcu_periph_clock_disable(rcu_periph_enum periph)
128 {
129     RCU_REG_VAL(periph) &= ~BIT(RCU_BIT_POS(periph));
130 }
131 
132 /*!
133     \brief      enable the peripherals clock when sleep mode
134     \param[in]  periph: RCU peripherals, refer to rcu_periph_sleep_enum
135                 only one parameter can be selected which is shown as below:
136       \arg        RCU_FMC_SLP: FMC clock
137       \arg        RCU_SRAM_SLP: SRAM clock
138     \param[out] none
139     \retval     none
140 */
rcu_periph_clock_sleep_enable(rcu_periph_sleep_enum periph)141 void rcu_periph_clock_sleep_enable(rcu_periph_sleep_enum periph)
142 {
143     RCU_REG_VAL(periph) |= BIT(RCU_BIT_POS(periph));
144 }
145 
146 /*!
147     \brief      disable the peripherals clock when sleep mode
148     \param[in]  periph: RCU peripherals, refer to rcu_periph_sleep_enum
149                 only one parameter can be selected which is shown as below:
150       \arg        RCU_FMC_SLP: FMC clock
151       \arg        RCU_SRAM_SLP: SRAM clock
152     \param[out] none
153     \retval     none
154 */
rcu_periph_clock_sleep_disable(rcu_periph_sleep_enum periph)155 void rcu_periph_clock_sleep_disable(rcu_periph_sleep_enum periph)
156 {
157     RCU_REG_VAL(periph) &= ~BIT(RCU_BIT_POS(periph));
158 }
159 
160 /*!
161     \brief      reset the peripherals
162     \param[in]  periph_reset: RCU peripherals reset, refer to rcu_periph_reset_enum
163                 only one parameter can be selected which is shown as below:
164       \arg        RCU_GPIOxRST (x=A,B,C,D,E): reset GPIO ports
165       \arg        RCU_AFRST : reset alternate function clock
166       \arg        RCU_USBFSRST: reset USBFS
167       \arg        RCU_TIMERxRST (x=0,1,2,3,4,5,6): reset TIMER
168       \arg        RCU_WWDGTRST: reset WWDGT
169       \arg        RCU_SPIxRST (x=0,1,2): reset SPI
170       \arg        RCU_USARTxRST (x=0,1,2): reset USART
171       \arg        RCU_UARTxRST (x=3,4): reset UART
172       \arg        RCU_I2CxRST (x=0,1): reset I2C
173       \arg        RCU_CANxRST (x=0,1): reset CAN
174       \arg        RCU_PMURST: reset PMU
175       \arg        RCU_DACRST: reset DAC
176       \arg        RCU_ADCxRST (x=0,1): reset ADC
177       \arg        RCU_BKPIRST: reset BKPI
178     \param[out] none
179     \retval     none
180 */
rcu_periph_reset_enable(rcu_periph_reset_enum periph_reset)181 void rcu_periph_reset_enable(rcu_periph_reset_enum periph_reset)
182 {
183     RCU_REG_VAL(periph_reset) |= BIT(RCU_BIT_POS(periph_reset));
184 }
185 
186 /*!
187     \brief      disable reset the peripheral
188     \param[in]  periph_reset: RCU peripherals reset, refer to rcu_periph_reset_enum
189                 only one parameter can be selected which is shown as below:
190       \arg        RCU_GPIOxRST (x=A,B,C,D,E): reset GPIO ports
191       \arg        RCU_AFRST : reset alternate function clock
192       \arg        RCU_USBFSRST: reset USBFS
193       \arg        RCU_TIMERxRST (x=0,1,2,3,4,5,6): reset TIMER
194       \arg        RCU_WWDGTRST: reset WWDGT
195       \arg        RCU_SPIxRST (x=0,1,2): reset SPI
196       \arg        RCU_USARTxRST (x=0,1,2): reset USART
197       \arg        RCU_UARTxRST (x=3,4): reset UART
198       \arg        RCU_I2CxRST (x=0,1): reset I2C
199       \arg        RCU_CANxRST (x=0,1): reset CAN
200       \arg        RCU_PMURST: reset PMU
201       \arg        RCU_DACRST: reset DAC
202       \arg        RCU_ADCxRST (x=0,1): reset ADC
203       \arg        RCU_BKPIRST: reset BKPI
204     \param[out] none
205     \retval     none
206 */
rcu_periph_reset_disable(rcu_periph_reset_enum periph_reset)207 void rcu_periph_reset_disable(rcu_periph_reset_enum periph_reset)
208 {
209     RCU_REG_VAL(periph_reset) &= ~BIT(RCU_BIT_POS(periph_reset));
210 }
211 
212 /*!
213     \brief      reset the BKP domain
214     \param[in]  none
215     \param[out] none
216     \retval     none
217 */
rcu_bkp_reset_enable(void)218 void rcu_bkp_reset_enable(void)
219 {
220     RCU_BDCTL |= RCU_BDCTL_BKPRST;
221 }
222 
223 /*!
224     \brief      disable the BKP domain reset
225     \param[in]  none
226     \param[out] none
227     \retval     none
228 */
rcu_bkp_reset_disable(void)229 void rcu_bkp_reset_disable(void)
230 {
231     RCU_BDCTL &= ~RCU_BDCTL_BKPRST;
232 }
233 
234 /*!
235     \brief      configure the system clock source
236     \param[in]  ck_sys: system clock source select
237                 only one parameter can be selected which is shown as below:
238       \arg        RCU_CKSYSSRC_IRC8M: select CK_IRC8M as the CK_SYS source
239       \arg        RCU_CKSYSSRC_HXTAL: select CK_HXTAL as the CK_SYS source
240       \arg        RCU_CKSYSSRC_PLL: select CK_PLL as the CK_SYS source
241     \param[out] none
242     \retval     none
243 */
rcu_system_clock_source_config(uint32_t ck_sys)244 void rcu_system_clock_source_config(uint32_t ck_sys)
245 {
246     uint32_t reg;
247 
248     reg = RCU_CFG0;
249     /* reset the SCS bits and set according to ck_sys */
250     reg &= ~RCU_CFG0_SCS;
251     RCU_CFG0 = (reg | ck_sys);
252 }
253 
254 /*!
255     \brief      get the system clock source
256     \param[in]  none
257     \param[out] none
258     \retval     which clock is selected as CK_SYS source
259       \arg        RCU_SCSS_IRC8M: CK_IRC8M is selected as the CK_SYS source
260       \arg        RCU_SCSS_HXTAL: CK_HXTAL is selected as the CK_SYS source
261       \arg        RCU_SCSS_PLL: CK_PLL is selected as the CK_SYS source
262 */
rcu_system_clock_source_get(void)263 uint32_t rcu_system_clock_source_get(void)
264 {
265     return (RCU_CFG0 & RCU_CFG0_SCSS);
266 }
267 
268 /*!
269     \brief      configure the AHB clock prescaler selection
270     \param[in]  ck_ahb: AHB clock prescaler selection
271                 only one parameter can be selected which is shown as below:
272       \arg        RCU_AHB_CKSYS_DIVx, x=1, 2, 4, 8, 16, 64, 128, 256, 512
273     \param[out] none
274     \retval     none
275 */
rcu_ahb_clock_config(uint32_t ck_ahb)276 void rcu_ahb_clock_config(uint32_t ck_ahb)
277 {
278     uint32_t reg;
279 
280     reg = RCU_CFG0;
281 
282     /* reset the AHBPSC bits and set according to ck_ahb */
283     reg &= ~RCU_CFG0_AHBPSC;
284     RCU_CFG0 = (reg | ck_ahb);
285 }
286 
287 /*!
288     \brief      configure the APB1 clock prescaler selection
289     \param[in]  ck_apb1: APB1 clock prescaler selection
290                 only one parameter can be selected which is shown as below:
291       \arg        RCU_APB1_CKAHB_DIV1: select CK_AHB as CK_APB1
292       \arg        RCU_APB1_CKAHB_DIV2: select CK_AHB/2 as CK_APB1
293       \arg        RCU_APB1_CKAHB_DIV4: select CK_AHB/4 as CK_APB1
294       \arg        RCU_APB1_CKAHB_DIV8: select CK_AHB/8 as CK_APB1
295       \arg        RCU_APB1_CKAHB_DIV16: select CK_AHB/16 as CK_APB1
296     \param[out] none
297     \retval     none
298 */
rcu_apb1_clock_config(uint32_t ck_apb1)299 void rcu_apb1_clock_config(uint32_t ck_apb1)
300 {
301     uint32_t reg;
302 
303     reg = RCU_CFG0;
304 
305     /* reset the APB1PSC and set according to ck_apb1 */
306     reg &= ~RCU_CFG0_APB1PSC;
307     RCU_CFG0 = (reg | ck_apb1);
308 }
309 
310 /*!
311     \brief      configure the APB2 clock prescaler selection
312     \param[in]  ck_apb2: APB2 clock prescaler selection
313                 only one parameter can be selected which is shown as below:
314       \arg        RCU_APB2_CKAHB_DIV1: select CK_AHB as CK_APB2
315       \arg        RCU_APB2_CKAHB_DIV2: select CK_AHB/2 as CK_APB2
316       \arg        RCU_APB2_CKAHB_DIV4: select CK_AHB/4 as CK_APB2
317       \arg        RCU_APB2_CKAHB_DIV8: select CK_AHB/8 as CK_APB2
318       \arg        RCU_APB2_CKAHB_DIV16: select CK_AHB/16 as CK_APB2
319     \param[out] none
320     \retval     none
321 */
rcu_apb2_clock_config(uint32_t ck_apb2)322 void rcu_apb2_clock_config(uint32_t ck_apb2)
323 {
324     uint32_t reg;
325 
326     reg = RCU_CFG0;
327 
328     /* reset the APB2PSC and set according to ck_apb2 */
329     reg &= ~RCU_CFG0_APB2PSC;
330     RCU_CFG0 = (reg | ck_apb2);
331 }
332 
333 /*!
334     \brief      configure the CK_OUT0 clock source
335     \param[in]  ckout0_src: CK_OUT0 clock source selection
336                 only one parameter can be selected which is shown as below:
337       \arg        RCU_CKOUT0SRC_NONE: no clock selected
338       \arg        RCU_CKOUT0SRC_CKSYS: system clock selected
339       \arg        RCU_CKOUT0SRC_IRC8M: high speed 8M internal oscillator clock selected
340       \arg        RCU_CKOUT0SRC_HXTAL: HXTAL selected
341       \arg        RCU_CKOUT0SRC_CKPLL_DIV2: CK_PLL/2 selected
342       \arg        RCU_CKOUT0SRC_CKPLL1: CK_PLL1 selected
343       \arg        RCU_CKOUT0SRC_CKPLL2_DIV2: CK_PLL2/2 selected
344       \arg        RCU_CKOUT0SRC_EXT1: EXT1 selected
345       \arg        RCU_CKOUT0SRC_CKPLL2: PLL2 selected
346     \param[out] none
347     \retval     none
348 */
rcu_ckout0_config(uint32_t ckout0_src)349 void rcu_ckout0_config(uint32_t ckout0_src)
350 {
351     uint32_t reg;
352 
353     reg = RCU_CFG0;
354 
355     /* reset the CKOUT0SRC, set according to ckout0_src */
356     reg &= ~RCU_CFG0_CKOUT0SEL;
357     RCU_CFG0 = (reg | ckout0_src);
358 }
359 
360 /*!
361     \brief      configure the main PLL clock
362     \param[in]  pll_src: PLL clock source selection
363                 only one parameter can be selected which is shown as below:
364       \arg        RCU_PLLSRC_IRC8M_DIV2: IRC8M/2 clock selected as source clock of PLL
365       \arg        RCU_PLLSRC_HXTAL: HXTAL selected as source clock of PLL
366     \param[in]  pll_mul: PLL clock multiplication factor
367                 only one parameter can be selected which is shown as below:
368       \arg        RCU_PLL_MULx (x = 2..14, 6.5, 16..32)
369     \param[out] none
370     \retval     none
371 */
rcu_pll_config(uint32_t pll_src,uint32_t pll_mul)372 void rcu_pll_config(uint32_t pll_src, uint32_t pll_mul)
373 {
374     uint32_t reg = 0U;
375 
376     reg = RCU_CFG0;
377 
378     /* PLL clock source and multiplication factor configuration */
379     reg &= ~(RCU_CFG0_PLLSEL | RCU_CFG0_PLLMF | RCU_CFG0_PLLMF_4);
380     reg |= (pll_src | pll_mul);
381 
382     RCU_CFG0 = reg;
383 }
384 
385 /*!
386     \brief      configure the PREDV0 division factor and clock source
387     \param[in]  predv0_source: PREDV0 input clock source selection
388                 only one parameter can be selected which is shown as below:
389       \arg        RCU_PREDV0SRC_HXTAL: HXTAL selected as PREDV0 input source clock
390       \arg        RCU_PREDV0SRC_CKPLL1: CK_PLL1 selected as PREDV0 input source clock
391     \param[in]  predv0_div: PREDV0 division factor
392                 only one parameter can be selected which is shown as below:
393       \arg        RCU_PREDV0_DIVx, x = 1..16
394     \param[out] none
395     \retval     none
396 */
rcu_predv0_config(uint32_t predv0_source,uint32_t predv0_div)397 void rcu_predv0_config(uint32_t predv0_source, uint32_t predv0_div)
398 {
399     uint32_t reg = 0U;
400 
401     reg = RCU_CFG1;
402     /* reset PREDV0SEL and PREDV0 bits */
403     reg &= ~(RCU_CFG1_PREDV0SEL | RCU_CFG1_PREDV0);
404     /* set the PREDV0SEL and PREDV0 division factor */
405     reg |= (predv0_source | predv0_div);
406 
407     RCU_CFG1 = reg;
408 }
409 
410 /*!
411     \brief      configure the PREDV1 division factor
412     \param[in]  predv1_div: PREDV1 division factor
413                 only one parameter can be selected which is shown as below:
414       \arg        RCU_PREDV1_DIVx, x = 1..16
415     \param[out] none
416     \retval     none
417 */
rcu_predv1_config(uint32_t predv1_div)418 void rcu_predv1_config(uint32_t predv1_div)
419 {
420     uint32_t reg = 0U;
421 
422     reg = RCU_CFG1;
423     /* reset the PREDV1 bits */
424     reg &= ~RCU_CFG1_PREDV1;
425     /* set the PREDV1 division factor */
426     reg |= predv1_div;
427 
428     RCU_CFG1 = reg;
429 }
430 
431 /*!
432     \brief      configure the PLL1 clock
433     \param[in]  pll_mul: PLL clock multiplication factor
434                 only one parameter can be selected which is shown as below:
435       \arg        RCU_PLL1_MULx (x = 8..16, 20)
436     \param[out] none
437     \retval     none
438 */
rcu_pll1_config(uint32_t pll_mul)439 void rcu_pll1_config(uint32_t pll_mul)
440 {
441     RCU_CFG1 &= ~RCU_CFG1_PLL1MF;
442     RCU_CFG1 |= pll_mul;
443 }
444 
445 /*!
446     \brief      configure the PLL2 clock
447     \param[in]  pll_mul: PLL clock multiplication factor
448                 only one parameter can be selected which is shown as below:
449       \arg        RCU_PLL2_MULx (x = 8..16, 20)
450     \param[out] none
451     \retval     none
452 */
rcu_pll2_config(uint32_t pll_mul)453 void rcu_pll2_config(uint32_t pll_mul)
454 {
455     RCU_CFG1 &= ~RCU_CFG1_PLL2MF;
456     RCU_CFG1 |= pll_mul;
457 }
458 
459 /*!
460     \brief      configure the ADC prescaler factor
461     \param[in]  adc_psc: ADC prescaler factor
462                 only one parameter can be selected which is shown as below:
463       \arg        RCU_CKADC_CKAPB2_DIV2: ADC prescaler select CK_APB2/2
464       \arg        RCU_CKADC_CKAPB2_DIV4: ADC prescaler select CK_APB2/4
465       \arg        RCU_CKADC_CKAPB2_DIV6: ADC prescaler select CK_APB2/6
466       \arg        RCU_CKADC_CKAPB2_DIV8: ADC prescaler select CK_APB2/8
467       \arg        RCU_CKADC_CKAPB2_DIV12: ADC prescaler select CK_APB2/12
468       \arg        RCU_CKADC_CKAPB2_DIV16: ADC prescaler select CK_APB2/16
469     \param[out] none
470     \retval     none
471 */
rcu_adc_clock_config(uint32_t adc_psc)472 void rcu_adc_clock_config(uint32_t adc_psc)
473 {
474     uint32_t reg0;
475 
476     /* reset the ADCPSC bits */
477     reg0 = RCU_CFG0;
478     reg0 &= ~(RCU_CFG0_ADCPSC_2 | RCU_CFG0_ADCPSC);
479 
480     /* set the ADC prescaler factor */
481     switch(adc_psc){
482         case RCU_CKADC_CKAPB2_DIV2:
483         case RCU_CKADC_CKAPB2_DIV4:
484         case RCU_CKADC_CKAPB2_DIV6:
485         case RCU_CKADC_CKAPB2_DIV8:
486             reg0 |= (adc_psc << 14);
487             break;
488 
489         case RCU_CKADC_CKAPB2_DIV12:
490         case RCU_CKADC_CKAPB2_DIV16:
491             adc_psc &= ~BIT(2);
492             reg0 |= (adc_psc << 14 | RCU_CFG0_ADCPSC_2);
493             break;
494 
495         default:
496             break;
497     }
498 
499     /* set the register */
500     RCU_CFG0 = reg0;
501 }
502 
503 /*!
504     \brief      configure the USBFS prescaler factor
505     \param[in]  usb_psc: USB prescaler factor
506                 only one parameter can be selected which is shown as below:
507       \arg        RCU_CKUSB_CKPLL_DIV1_5: USBFS prescaler select CK_PLL/1.5
508       \arg        RCU_CKUSB_CKPLL_DIV1: USBFS prescaler select CK_PLL/1
509       \arg        RCU_CKUSB_CKPLL_DIV2_5: USBFS prescaler select CK_PLL/2.5
510       \arg        RCU_CKUSB_CKPLL_DIV2: USBFS prescaler select CK_PLL/2
511     \param[out] none
512     \retval     none
513 */
rcu_usb_clock_config(uint32_t usb_psc)514 void rcu_usb_clock_config(uint32_t usb_psc)
515 {
516     uint32_t reg;
517 
518     reg = RCU_CFG0;
519 
520     /* configure the USBFS prescaler factor */
521     reg &= ~RCU_CFG0_USBFSPSC;
522     RCU_CFG0 = (reg | usb_psc);
523 }
524 
525 /*!
526     \brief      configure the RTC clock source selection
527     \param[in]  rtc_clock_source: RTC clock source selection
528                 only one parameter can be selected which is shown as below:
529       \arg        RCU_RTCSRC_NONE: no clock selected
530       \arg        RCU_RTCSRC_LXTAL: CK_LXTAL selected as RTC source clock
531       \arg        RCU_RTCSRC_IRC40K: CK_IRC40K selected as RTC source clock
532       \arg        RCU_RTCSRC_HXTAL_DIV_128: CK_HXTAL/128 selected as RTC source clock
533     \param[out] none
534     \retval     none
535 */
rcu_rtc_clock_config(uint32_t rtc_clock_source)536 void rcu_rtc_clock_config(uint32_t rtc_clock_source)
537 {
538     uint32_t reg;
539 
540     reg = RCU_BDCTL;
541     /* reset the RTCSRC bits and set according to rtc_clock_source */
542     reg &= ~RCU_BDCTL_RTCSRC;
543     RCU_BDCTL = (reg | rtc_clock_source);
544 }
545 
546 /*!
547     \brief      configure the I2S1 clock source selection
548     \param[in]  i2s_clock_source: I2S1 clock source selection
549                 only one parameter can be selected which is shown as below:
550       \arg        RCU_I2S1SRC_CKSYS: System clock selected as I2S1 source clock
551       \arg        RCU_I2S1SRC_CKPLL2_MUL2: CK_PLL2x2 selected as I2S1 source clock
552     \param[out] none
553     \retval     none
554 */
rcu_i2s1_clock_config(uint32_t i2s_clock_source)555 void rcu_i2s1_clock_config(uint32_t i2s_clock_source)
556 {
557     uint32_t reg;
558 
559     reg = RCU_CFG1;
560     /* reset the I2S1SEL bit and set according to i2s_clock_source */
561     reg &= ~RCU_CFG1_I2S1SEL;
562     RCU_CFG1 = (reg | i2s_clock_source);
563 }
564 
565 /*!
566     \brief      configure the I2S2 clock source selection
567     \param[in]  i2s_clock_source: I2S2 clock source selection
568                 only one parameter can be selected which is shown as below:
569       \arg        RCU_I2S2SRC_CKSYS: system clock selected as I2S2 source clock
570       \arg        RCU_I2S2SRC_CKPLL2_MUL2: CK_PLL2x2 selected as I2S2 source clock
571     \param[out] none
572     \retval     none
573 */
rcu_i2s2_clock_config(uint32_t i2s_clock_source)574 void rcu_i2s2_clock_config(uint32_t i2s_clock_source)
575 {
576     uint32_t reg;
577 
578     reg = RCU_CFG1;
579     /* reset the I2S2SEL bit and set according to i2s_clock_source */
580     reg &= ~RCU_CFG1_I2S2SEL;
581     RCU_CFG1 = (reg | i2s_clock_source);
582 }
583 
584 /*!
585     \brief      get the clock stabilization and periphral reset flags
586     \param[in]  flag: the clock stabilization and periphral reset flags, refer to rcu_flag_enum
587                 only one parameter can be selected which is shown as below:
588       \arg        RCU_FLAG_IRC8MSTB: IRC8M stabilization flag
589       \arg        RCU_FLAG_HXTALSTB: HXTAL stabilization flag
590       \arg        RCU_FLAG_PLLSTB: PLL stabilization flag
591       \arg        RCU_FLAG_PLL1STB: PLL1 stabilization flag
592       \arg        RCU_FLAG_PLL2STB: PLL2 stabilization flag
593       \arg        RCU_FLAG_LXTALSTB: LXTAL stabilization flag
594       \arg        RCU_FLAG_IRC40KSTB: IRC40K stabilization flag
595       \arg        RCU_FLAG_EPRST: external PIN reset flag
596       \arg        RCU_FLAG_PORRST: power reset flag
597       \arg        RCU_FLAG_SWRST: software reset flag
598       \arg        RCU_FLAG_FWDGTRST: free watchdog timer reset flag
599       \arg        RCU_FLAG_WWDGTRST: window watchdog timer reset flag
600       \arg        RCU_FLAG_LPRST: low-power reset flag
601     \param[out] none
602     \retval     FlagStatus: SET or RESET
603 */
rcu_flag_get(rcu_flag_enum flag)604 FlagStatus rcu_flag_get(rcu_flag_enum flag)
605 {
606     /* get the rcu flag */
607     if(RESET != (RCU_REG_VAL(flag) & BIT(RCU_BIT_POS(flag)))){
608         return SET;
609     }else{
610         return RESET;
611     }
612 }
613 
614 /*!
615     \brief      clear all the reset flag
616     \param[in]  none
617     \param[out] none
618     \retval     none
619 */
rcu_all_reset_flag_clear(void)620 void rcu_all_reset_flag_clear(void)
621 {
622     RCU_RSTSCK |= RCU_RSTSCK_RSTFC;
623 }
624 
625 /*!
626     \brief      get the clock stabilization interrupt and ckm flags
627     \param[in]  int_flag: interrupt and ckm flags, refer to rcu_int_flag_enum
628                 only one parameter can be selected which is shown as below:
629       \arg        RCU_INT_FLAG_IRC40KSTB: IRC40K stabilization interrupt flag
630       \arg        RCU_INT_FLAG_LXTALSTB: LXTAL stabilization interrupt flag
631       \arg        RCU_INT_FLAG_IRC8MSTB: IRC8M stabilization interrupt flag
632       \arg        RCU_INT_FLAG_HXTALSTB: HXTAL stabilization interrupt flag
633       \arg        RCU_INT_FLAG_PLLSTB: PLL stabilization interrupt flag
634       \arg        RCU_INT_FLAG_PLL1STB: PLL1 stabilization interrupt flag
635       \arg        RCU_INT_FLAG_PLL2STB: PLL2 stabilization interrupt flag
636       \arg        RCU_INT_FLAG_CKM: HXTAL clock stuck interrupt flag
637     \param[out] none
638     \retval     FlagStatus: SET or RESET
639 */
rcu_interrupt_flag_get(rcu_int_flag_enum int_flag)640 FlagStatus rcu_interrupt_flag_get(rcu_int_flag_enum int_flag)
641 {
642     /* get the rcu interrupt flag */
643     if(RESET != (RCU_REG_VAL(int_flag) & BIT(RCU_BIT_POS(int_flag)))){
644         return SET;
645     }else{
646         return RESET;
647     }
648 }
649 
650 /*!
651     \brief      clear the interrupt flags
652     \param[in]  int_flag_clear: clock stabilization and stuck interrupt flags clear, refer to rcu_int_flag_clear_enum
653                 only one parameter can be selected which is shown as below:
654       \arg        RCU_INT_FLAG_IRC40KSTB_CLR: IRC40K stabilization interrupt flag clear
655       \arg        RCU_INT_FLAG_LXTALSTB_CLR: LXTAL stabilization interrupt flag clear
656       \arg        RCU_INT_FLAG_IRC8MSTB_CLR: IRC8M stabilization interrupt flag clear
657       \arg        RCU_INT_FLAG_HXTALSTB_CLR: HXTAL stabilization interrupt flag clear
658       \arg        RCU_INT_FLAG_PLLSTB_CLR: PLL stabilization interrupt flag clear
659       \arg        RCU_INT_FLAG_PLL1STB_CLR: PLL1 stabilization interrupt flag clear
660       \arg        RCU_INT_FLAG_PLL2STB_CLR: PLL2 stabilization interrupt flag clear
661       \arg        RCU_INT_FLAG_CKM_CLR: clock stuck interrupt flag clear
662     \param[out] none
663     \retval     none
664 */
rcu_interrupt_flag_clear(rcu_int_flag_clear_enum int_flag_clear)665 void rcu_interrupt_flag_clear(rcu_int_flag_clear_enum int_flag_clear)
666 {
667     RCU_REG_VAL(int_flag_clear) |= BIT(RCU_BIT_POS(int_flag_clear));
668 }
669 
670 /*!
671     \brief      enable the stabilization interrupt
672     \param[in]  stab_int: clock stabilization interrupt, refer to rcu_int_enum
673                 Only one parameter can be selected which is shown as below:
674       \arg        RCU_INT_IRC40KSTB: IRC40K stabilization interrupt enable
675       \arg        RCU_INT_LXTALSTB: LXTAL stabilization interrupt enable
676       \arg        RCU_INT_IRC8MSTB: IRC8M stabilization interrupt enable
677       \arg        RCU_INT_HXTALSTB: HXTAL stabilization interrupt enable
678       \arg        RCU_INT_PLLSTB: PLL stabilization interrupt enable
679       \arg        RCU_INT_PLL1STB: PLL1 stabilization interrupt enable
680       \arg        RCU_INT_PLL2STB: PLL2 stabilization interrupt enable
681     \param[out] none
682     \retval     none
683 */
rcu_interrupt_enable(rcu_int_enum stab_int)684 void rcu_interrupt_enable(rcu_int_enum stab_int)
685 {
686     RCU_REG_VAL(stab_int) |= BIT(RCU_BIT_POS(stab_int));
687 }
688 
689 /*!
690     \brief      disable the stabilization interrupt
691     \param[in]  stab_int: clock stabilization interrupt, refer to rcu_int_enum
692                 only one parameter can be selected which is shown as below:
693       \arg        RCU_INT_IRC40KSTB: IRC40K stabilization interrupt enable
694       \arg        RCU_INT_LXTALSTB: LXTAL stabilization interrupt enable
695       \arg        RCU_INT_IRC8MSTB: IRC8M stabilization interrupt enable
696       \arg        RCU_INT_HXTALSTB: HXTAL stabilization interrupt enable
697       \arg        RCU_INT_PLLSTB: PLL stabilization interrupt enable
698       \arg        RCU_INT_PLL1STB: PLL1 stabilization interrupt enable
699       \arg        RCU_INT_PLL2STB: PLL2 stabilization interrupt enable
700     \param[out] none
701     \retval     none
702 */
rcu_interrupt_disable(rcu_int_enum stab_int)703 void rcu_interrupt_disable(rcu_int_enum stab_int)
704 {
705     RCU_REG_VAL(stab_int) &= ~BIT(RCU_BIT_POS(stab_int));
706 }
707 
708 /*!
709     \brief      wait for oscillator stabilization flags is SET or oscillator startup is timeout
710     \param[in]  osci: oscillator types, refer to rcu_osci_type_enum
711                 only one parameter can be selected which is shown as below:
712       \arg        RCU_HXTAL: high speed crystal oscillator(HXTAL)
713       \arg        RCU_LXTAL: low speed crystal oscillator(LXTAL)
714       \arg        RCU_IRC8M: internal 8M RC oscillators(IRC8M)
715       \arg        RCU_IRC40K: internal 40K RC oscillator(IRC40K)
716       \arg        RCU_PLL_CK: phase locked loop(PLL)
717       \arg        RCU_PLL1_CK: phase locked loop 1
718       \arg        RCU_PLL2_CK: phase locked loop 2
719     \param[out] none
720     \retval     ErrStatus: SUCCESS or ERROR
721 */
rcu_osci_stab_wait(rcu_osci_type_enum osci)722 ErrStatus rcu_osci_stab_wait(rcu_osci_type_enum osci)
723 {
724     uint32_t stb_cnt = 0U;
725     ErrStatus reval = ERROR;
726     FlagStatus osci_stat = RESET;
727 
728     switch(osci){
729     /* wait HXTAL stable */
730     case RCU_HXTAL:
731         while((RESET == osci_stat) && (HXTAL_STARTUP_TIMEOUT != stb_cnt)){
732             osci_stat = rcu_flag_get(RCU_FLAG_HXTALSTB);
733             stb_cnt++;
734         }
735 
736         /* check whether flag is set or not */
737         if(RESET != rcu_flag_get(RCU_FLAG_HXTALSTB)){
738             reval = SUCCESS;
739         }
740         break;
741 
742     /* wait LXTAL stable */
743     case RCU_LXTAL:
744         while((RESET == osci_stat) && (LXTAL_STARTUP_TIMEOUT != stb_cnt)){
745             osci_stat = rcu_flag_get(RCU_FLAG_LXTALSTB);
746             stb_cnt++;
747         }
748 
749         /* check whether flag is set or not */
750         if(RESET != rcu_flag_get(RCU_FLAG_LXTALSTB)){
751             reval = SUCCESS;
752         }
753         break;
754 
755     /* wait IRC8M stable */
756     case RCU_IRC8M:
757         while((RESET == osci_stat) && (IRC8M_STARTUP_TIMEOUT != stb_cnt)){
758             osci_stat = rcu_flag_get(RCU_FLAG_IRC8MSTB);
759             stb_cnt++;
760         }
761 
762         /* check whether flag is set or not */
763         if(RESET != rcu_flag_get(RCU_FLAG_IRC8MSTB)){
764             reval = SUCCESS;
765         }
766         break;
767 
768     /* wait IRC40K stable */
769     case RCU_IRC40K:
770         while((RESET == osci_stat) && (OSC_STARTUP_TIMEOUT != stb_cnt)){
771             osci_stat = rcu_flag_get(RCU_FLAG_IRC40KSTB);
772             stb_cnt++;
773         }
774 
775         /* check whether flag is set or not */
776         if(RESET != rcu_flag_get(RCU_FLAG_IRC40KSTB)){
777             reval = SUCCESS;
778         }
779         break;
780 
781     /* wait PLL stable */
782     case RCU_PLL_CK:
783         while((RESET == osci_stat) && (OSC_STARTUP_TIMEOUT != stb_cnt)){
784             osci_stat = rcu_flag_get(RCU_FLAG_PLLSTB);
785             stb_cnt++;
786         }
787 
788         /* check whether flag is set or not */
789         if(RESET != rcu_flag_get(RCU_FLAG_PLLSTB)){
790             reval = SUCCESS;
791         }
792         break;
793     /* wait PLL1 stable */
794     case RCU_PLL1_CK:
795         while((RESET == osci_stat) && (OSC_STARTUP_TIMEOUT != stb_cnt)){
796             osci_stat = rcu_flag_get(RCU_FLAG_PLL1STB);
797             stb_cnt++;
798         }
799 
800         /* check whether flag is set or not */
801         if(RESET != rcu_flag_get(RCU_FLAG_PLL1STB)){
802             reval = SUCCESS;
803         }
804         break;
805     /* wait PLL2 stable */
806     case RCU_PLL2_CK:
807         while((RESET == osci_stat) && (OSC_STARTUP_TIMEOUT != stb_cnt)){
808             osci_stat = rcu_flag_get(RCU_FLAG_PLL2STB);
809             stb_cnt++;
810         }
811 
812         /* check whether flag is set or not */
813         if(RESET != rcu_flag_get(RCU_FLAG_PLL2STB)){
814             reval = SUCCESS;
815         }
816         break;
817 
818     default:
819         break;
820     }
821 
822     /* return value */
823     return reval;
824 }
825 
826 /*!
827     \brief      turn on the oscillator
828     \param[in]  osci: oscillator types, refer to rcu_osci_type_enum
829                 only one parameter can be selected which is shown as below:
830       \arg        RCU_HXTAL: high speed crystal oscillator(HXTAL)
831       \arg        RCU_LXTAL: low speed crystal oscillator(LXTAL)
832       \arg        RCU_IRC8M: internal 8M RC oscillators(IRC8M)
833       \arg        RCU_IRC40K: internal 40K RC oscillator(IRC40K)
834       \arg        RCU_PLL_CK: phase locked loop(PLL)
835       \arg        RCU_PLL1_CK: phase locked loop 1
836       \arg        RCU_PLL2_CK: phase locked loop 2
837     \param[out] none
838     \retval     none
839 */
rcu_osci_on(rcu_osci_type_enum osci)840 void rcu_osci_on(rcu_osci_type_enum osci)
841 {
842     RCU_REG_VAL(osci) |= BIT(RCU_BIT_POS(osci));
843 }
844 
845 /*!
846     \brief      turn off the oscillator
847     \param[in]  osci: oscillator types, refer to rcu_osci_type_enum
848                 only one parameter can be selected which is shown as below:
849       \arg        RCU_HXTAL: high speed crystal oscillator(HXTAL)
850       \arg        RCU_LXTAL: low speed crystal oscillator(LXTAL)
851       \arg        RCU_IRC8M: internal 8M RC oscillators(IRC8M)
852       \arg        RCU_IRC40K: internal 40K RC oscillator(IRC40K)
853       \arg        RCU_PLL_CK: phase locked loop(PLL)
854       \arg        RCU_PLL1_CK: phase locked loop 1
855       \arg        RCU_PLL2_CK: phase locked loop 2
856     \param[out] none
857     \retval     none
858 */
rcu_osci_off(rcu_osci_type_enum osci)859 void rcu_osci_off(rcu_osci_type_enum osci)
860 {
861     RCU_REG_VAL(osci) &= ~BIT(RCU_BIT_POS(osci));
862 }
863 
864 /*!
865     \brief      enable the oscillator bypass mode, HXTALEN or LXTALEN must be reset before it
866     \param[in]  osci: oscillator types, refer to rcu_osci_type_enum
867                 only one parameter can be selected which is shown as below:
868       \arg        RCU_HXTAL: high speed crystal oscillator(HXTAL)
869       \arg        RCU_LXTAL: low speed crystal oscillator(LXTAL)
870     \param[out] none
871     \retval     none
872 */
rcu_osci_bypass_mode_enable(rcu_osci_type_enum osci)873 void rcu_osci_bypass_mode_enable(rcu_osci_type_enum osci)
874 {
875     uint32_t reg;
876 
877     switch(osci){
878     /* enable HXTAL to bypass mode */
879     case RCU_HXTAL:
880         reg = RCU_CTL;
881         RCU_CTL &= ~RCU_CTL_HXTALEN;
882         RCU_CTL = (reg | RCU_CTL_HXTALBPS);
883         break;
884     /* enable LXTAL to bypass mode */
885     case RCU_LXTAL:
886         reg = RCU_BDCTL;
887         RCU_BDCTL &= ~RCU_BDCTL_LXTALEN;
888         RCU_BDCTL = (reg | RCU_BDCTL_LXTALBPS);
889         break;
890     case RCU_IRC8M:
891     case RCU_IRC40K:
892     case RCU_PLL_CK:
893     case RCU_PLL1_CK:
894     case RCU_PLL2_CK:
895         break;
896     default:
897         break;
898     }
899 }
900 
901 /*!
902     \brief      disable the oscillator bypass mode, HXTALEN or LXTALEN must be reset before it
903     \param[in]  osci: oscillator types, refer to rcu_osci_type_enum
904                 only one parameter can be selected which is shown as below:
905       \arg        RCU_HXTAL: high speed crystal oscillator(HXTAL)
906       \arg        RCU_LXTAL: low speed crystal oscillator(LXTAL)
907     \param[out] none
908     \retval     none
909 */
rcu_osci_bypass_mode_disable(rcu_osci_type_enum osci)910 void rcu_osci_bypass_mode_disable(rcu_osci_type_enum osci)
911 {
912     uint32_t reg;
913 
914     switch(osci){
915     /* disable HXTAL to bypass mode */
916     case RCU_HXTAL:
917         reg = RCU_CTL;
918         RCU_CTL &= ~RCU_CTL_HXTALEN;
919         RCU_CTL = (reg & ~RCU_CTL_HXTALBPS);
920         break;
921     /* disable LXTAL to bypass mode */
922     case RCU_LXTAL:
923         reg = RCU_BDCTL;
924         RCU_BDCTL &= ~RCU_BDCTL_LXTALEN;
925         RCU_BDCTL = (reg & ~RCU_BDCTL_LXTALBPS);
926         break;
927     case RCU_IRC8M:
928     case RCU_IRC40K:
929     case RCU_PLL_CK:
930     case RCU_PLL1_CK:
931     case RCU_PLL2_CK:
932         break;
933     default:
934         break;
935     }
936 }
937 
938 /*!
939     \brief      enable the HXTAL clock monitor
940     \param[in]  none
941     \param[out] none
942     \retval     none
943 */
944 
rcu_hxtal_clock_monitor_enable(void)945 void rcu_hxtal_clock_monitor_enable(void)
946 {
947     RCU_CTL |= RCU_CTL_CKMEN;
948 }
949 
950 /*!
951     \brief      disable the HXTAL clock monitor
952     \param[in]  none
953     \param[out] none
954     \retval     none
955 */
rcu_hxtal_clock_monitor_disable(void)956 void rcu_hxtal_clock_monitor_disable(void)
957 {
958     RCU_CTL &= ~RCU_CTL_CKMEN;
959 }
960 
961 /*!
962     \brief      set the IRC8M adjust value
963     \param[in]  irc8m_adjval: IRC8M adjust value, must be between 0 and 0x1F
964     \param[out] none
965     \retval     none
966 */
rcu_irc8m_adjust_value_set(uint32_t irc8m_adjval)967 void rcu_irc8m_adjust_value_set(uint32_t irc8m_adjval)
968 {
969     uint32_t reg;
970 
971     reg = RCU_CTL;
972     /* reset the IRC8MADJ bits and set according to irc8m_adjval */
973     reg &= ~RCU_CTL_IRC8MADJ;
974     RCU_CTL = (reg | ((irc8m_adjval & 0x1FU) << 3));
975 }
976 
977 /*!
978     \brief      deep-sleep mode voltage select
979     \param[in]  dsvol: deep sleep mode voltage
980                 only one parameter can be selected which is shown as below:
981       \arg        RCU_DEEPSLEEP_V_1_2: the core voltage is 1.2V
982       \arg        RCU_DEEPSLEEP_V_1_1: the core voltage is 1.1V
983       \arg        RCU_DEEPSLEEP_V_1_0: the core voltage is 1.0V
984       \arg        RCU_DEEPSLEEP_V_0_9: the core voltage is 0.9V
985     \param[out] none
986     \retval     none
987 */
rcu_deepsleep_voltage_set(uint32_t dsvol)988 void rcu_deepsleep_voltage_set(uint32_t dsvol)
989 {
990     dsvol &= RCU_DSV_DSLPVS;
991     RCU_DSV = dsvol;
992 }
993 
994 /*!
995     \brief      get the system clock, bus and peripheral clock frequency
996     \param[in]  clock: the clock frequency which to get
997                 only one parameter can be selected which is shown as below:
998       \arg        CK_SYS: system clock frequency
999       \arg        CK_AHB: AHB clock frequency
1000       \arg        CK_APB1: APB1 clock frequency
1001       \arg        CK_APB2: APB2 clock frequency
1002     \param[out] none
1003     \retval     clock frequency of system, AHB, APB1, APB2
1004 */
rcu_clock_freq_get(rcu_clock_freq_enum clock)1005 uint32_t rcu_clock_freq_get(rcu_clock_freq_enum clock)
1006 {
1007     uint32_t sws, ck_freq = 0U;
1008     uint32_t cksys_freq, ahb_freq, apb1_freq, apb2_freq;
1009     uint32_t pllsel, predv0sel, pllmf,ck_src, idx, clk_exp;
1010     uint32_t predv0, predv1, pll1mf;
1011 
1012     /* exponent of AHB, APB1 and APB2 clock divider */
1013     uint8_t ahb_exp[16] = {0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 4, 6, 7, 8, 9};
1014     uint8_t apb1_exp[8] = {0, 0, 0, 0, 1, 2, 3, 4};
1015     uint8_t apb2_exp[8] = {0, 0, 0, 0, 1, 2, 3, 4};
1016 
1017     sws = GET_BITS(RCU_CFG0, 2, 3);
1018     switch(sws){
1019     /* IRC8M is selected as CK_SYS */
1020     case SEL_IRC8M:
1021         cksys_freq = IRC8M_VALUE;
1022         break;
1023     /* HXTAL is selected as CK_SYS */
1024     case SEL_HXTAL:
1025         cksys_freq = HXTAL_VALUE;
1026         break;
1027     /* PLL is selected as CK_SYS */
1028     case SEL_PLL:
1029         /* PLL clock source selection, HXTAL or IRC8M/2 */
1030         pllsel = (RCU_CFG0 & RCU_CFG0_PLLSEL);
1031 
1032         if(RCU_PLLSRC_HXTAL == pllsel) {
1033             /* PLL clock source is HXTAL */
1034             ck_src = HXTAL_VALUE;
1035 
1036             predv0sel = (RCU_CFG1 & RCU_CFG1_PREDV0SEL);
1037             /* source clock use PLL1 */
1038             if(RCU_PREDV0SRC_CKPLL1 == predv0sel){
1039                 predv1 = (uint32_t)((RCU_CFG1 & RCU_CFG1_PREDV1) >> 4) + 1U;
1040                 pll1mf = (uint32_t)((RCU_CFG1 & RCU_CFG1_PLL1MF) >> 8) + 2U;
1041                 if(17U == pll1mf){
1042                     pll1mf = 20U;
1043                 }
1044                 ck_src = (ck_src / predv1) * pll1mf;
1045             }
1046             predv0 = (RCU_CFG1 & RCU_CFG1_PREDV0) + 1U;
1047             ck_src /= predv0;
1048         }else{
1049             /* PLL clock source is IRC8M/2 */
1050             ck_src = IRC8M_VALUE/2U;
1051         }
1052 
1053         /* PLL multiplication factor */
1054         pllmf = GET_BITS(RCU_CFG0, 18, 21);
1055         if((RCU_CFG0 & RCU_CFG0_PLLMF_4)){
1056             pllmf |= 0x10U;
1057         }
1058         if(pllmf < 15U){
1059             pllmf += 2U;
1060         }else{
1061             pllmf += 1U;
1062         }
1063 
1064         cksys_freq = ck_src * pllmf;
1065 
1066         if(15U == pllmf){
1067             /* PLL source clock multiply by 6.5 */
1068             cksys_freq = ck_src * 6U + ck_src / 2U;
1069         }
1070 
1071         break;
1072     /* IRC8M is selected as CK_SYS */
1073     default:
1074         cksys_freq = IRC8M_VALUE;
1075         break;
1076     }
1077 
1078     /* calculate AHB clock frequency */
1079     idx = GET_BITS(RCU_CFG0, 4, 7);
1080     clk_exp = ahb_exp[idx];
1081     ahb_freq = cksys_freq >> clk_exp;
1082 
1083     /* calculate APB1 clock frequency */
1084     idx = GET_BITS(RCU_CFG0, 8, 10);
1085     clk_exp = apb1_exp[idx];
1086     apb1_freq = ahb_freq >> clk_exp;
1087 
1088     /* calculate APB2 clock frequency */
1089     idx = GET_BITS(RCU_CFG0, 11, 13);
1090     clk_exp = apb2_exp[idx];
1091     apb2_freq = ahb_freq >> clk_exp;
1092 
1093     /* return the clocks frequency */
1094     switch(clock){
1095     case CK_SYS:
1096         ck_freq = cksys_freq;
1097         break;
1098     case CK_AHB:
1099         ck_freq = ahb_freq;
1100         break;
1101     case CK_APB1:
1102         ck_freq = apb1_freq;
1103         break;
1104     case CK_APB2:
1105         ck_freq = apb2_freq;
1106         break;
1107     default:
1108         break;
1109     }
1110     return ck_freq;
1111 }
1112