1 /*
2 * Copyright (c) 2022 HPMicro
3 *
4 * SPDX-License-Identifier: BSD-3-Clause
5 *
6 */
7
8 #include "hpm_pllctlv2_drv.h"
9
10 #define PLLCTLV2_PLL_MFI_MIN (16U)
11 #define PLLCTLV2_PLL_MFI_MAX (42U)
12 #define PLLCTLV2_PLL_XTAL_FREQ (24000000UL)
13
14 #define PLLCTLV2_PLL_FREQ_MIN (PLLCTLV2_PLL_MFI_MIN * PLLCTLV2_PLL_XTAL_FREQ)
15 #define PLLCTLV2_PLL_FREQ_MAX ((PLLCTLV2_PLL_MFI_MAX + 1U) * PLLCTLV2_PLL_XTAL_FREQ)
16
pllctlv2_init_pll_with_freq(PLLCTLV2_Type * ptr,uint8_t pll,uint32_t freq_in_hz)17 hpm_stat_t pllctlv2_init_pll_with_freq(PLLCTLV2_Type *ptr, uint8_t pll, uint32_t freq_in_hz)
18 {
19 if ((ptr == NULL) || (freq_in_hz < PLLCTLV2_PLL_FREQ_MIN) || (freq_in_hz > PLLCTLV2_PLL_FREQ_MAX) ||
20 (pll >= PLLCTL_SOC_PLL_MAX_COUNT)) {
21 return status_invalid_argument;
22 }
23
24 uint32_t mfn = freq_in_hz % PLLCTLV2_PLL_XTAL_FREQ;
25 uint32_t mfi = freq_in_hz / PLLCTLV2_PLL_XTAL_FREQ;
26
27 ptr->PLL[pll].MFI = mfi;
28 ptr->PLL[pll].MFN = mfn * 10UL;
29
30 while (!pllctlv2_pll_is_stable(ptr, pll)) {
31 }
32 return status_success;
33 }
34
pllctlv2_enable_spread_spectrum(PLLCTLV2_Type * ptr,uint8_t pll,uint32_t step,uint32_t stop)35 void pllctlv2_enable_spread_spectrum(PLLCTLV2_Type *ptr, uint8_t pll, uint32_t step, uint32_t stop)
36 {
37 /*
38 * NOTE: The spread spectrum related registers cannot be configured under below conditions:
39 * 1. PLL is enabled
40 * 2. spread spectrum is enabled
41 */
42 if ((ptr != NULL) && (pll < PLLCTL_SOC_PLL_MAX_COUNT)) {
43
44 ptr->PLL[pll].CONFIG &= ~PLLCTLV2_PLL_CONFIG_SPREAD_MASK;
45
46 ptr->PLL[pll].SS_STEP = step;
47 ptr->PLL[pll].SS_STOP = stop;
48
49 ptr->PLL[pll].CONFIG |= PLLCTLV2_PLL_CONFIG_SPREAD_MASK;
50 }
51 }
52
pllctlv2_set_postdiv(PLLCTLV2_Type * ptr,uint8_t pll,uint8_t div_index,uint8_t div_value)53 void pllctlv2_set_postdiv(PLLCTLV2_Type *ptr, uint8_t pll, uint8_t div_index, uint8_t div_value)
54 {
55 if ((ptr != NULL) && (pll < PLLCTL_SOC_PLL_MAX_COUNT)) {
56 ptr->PLL[pll].DIV[div_index] =
57 (ptr->PLL[pll].DIV[div_index] & PLLCTLV2_DIV_DIV_MASK) | PLLCTLV2_DIV_DIV_SET(div_value) |
58 PLLCTLV2_DIV_ENABLE_MASK;
59 }
60 }
61
pllctlv2_get_pll_freq_in_hz(PLLCTLV2_Type * ptr,uint8_t pll)62 uint32_t pllctlv2_get_pll_freq_in_hz(PLLCTLV2_Type *ptr, uint8_t pll)
63 {
64 uint32_t freq = 0;
65 if ((ptr != NULL) && (pll < PLLCTL_SOC_PLL_MAX_COUNT)) {
66 uint32_t mfi = PLLCTLV2_PLL_MFI_MFI_GET(ptr->PLL[pll].MFI);
67 uint32_t mfn = PLLCTLV2_PLL_MFN_MFN_GET(ptr->PLL[pll].MFN);
68 uint32_t mfd = PLLCTLV2_PLL_MFD_MFD_GET(ptr->PLL[pll].MFD);
69 freq = (uint32_t) (PLLCTLV2_PLL_XTAL_FREQ * (mfi + 1.0 * mfn / mfd));
70 }
71 return freq;
72 }
73
pllctlv2_get_pll_postdiv_freq_in_hz(PLLCTLV2_Type * ptr,uint8_t pll,uint8_t div_index)74 uint32_t pllctlv2_get_pll_postdiv_freq_in_hz(PLLCTLV2_Type *ptr, uint8_t pll, uint8_t div_index)
75 {
76 uint32_t postdiv_freq = 0;
77 if ((ptr != NULL) && (pll < PLLCTL_SOC_PLL_MAX_COUNT)) {
78 uint32_t postdiv = PLLCTLV2_DIV_DIV_GET(ptr->PLL[pll].DIV[div_index]);
79 uint32_t pll_freq = pllctlv2_get_pll_freq_in_hz(ptr, pll);
80 postdiv_freq = (uint32_t) (pll_freq / (1 + postdiv * 1.0 / 5));
81 }
82
83 return postdiv_freq;
84 }
85