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