1 /*
2  * Copyright 2020-2021 NXP
3  * All rights reserved.
4  *
5  * SPDX-License-Identifier: BSD-3-Clause
6  */
7 #include "fsl_audiomix.h"
8 
9 /*******************************************************************************
10  * Definitions
11  ******************************************************************************/
12 /* Component ID definition, used by tools. */
13 #ifndef FSL_COMPONENT_ID
14 #define FSL_COMPONENT_ID "platform.drivers.audiomix"
15 #endif
16 
17 /*******************************************************************************
18  * Prototypes
19  ******************************************************************************/
20 
21 /*******************************************************************************
22  * Variables
23  ******************************************************************************/
24 
25 /*******************************************************************************
26  * Code
27  ******************************************************************************/
28 /*!
29  * brief audiomix attach clock.
30  *
31  * param base audiomix base address.
32  * param id attach clock id.
33  */
AUDIOMIX_AttachClk(AUDIOMIX_Type * base,audiomix_attch_clk_t id)34 void AUDIOMIX_AttachClk(AUDIOMIX_Type *base, audiomix_attch_clk_t id)
35 {
36     /* extract offset, mask, value */
37     uint32_t offset             = GET_AUDIOMIX_ATTACH_ID_OFFSET(id);
38     uint32_t mask               = GET_AUDIOMIX_ATTACH_ID_MASK(id);
39     uint32_t value              = GET_AUDIOMIX_ATTACH_ID_value(id);
40     volatile uint32_t *baseAddr = (volatile uint32_t *)((uintptr_t)base + offset);
41     /* load to register */
42     *baseAddr = (*baseAddr & ~mask) | value;
43 }
44 
45 /*!
46  * brief Initializes the SAI PLL.
47  * note This function can't detect whether the AUDIO PLL has been enabled and
48  * used by some IPs.
49  *
50  * param config Pointer to the configuration structure(see ref ccm_analog_frac_pll_config_t enumeration).
51  *
52  */
AUDIOMIX_InitAudioPll(AUDIOMIX_Type * base,const ccm_analog_frac_pll_config_t * config)53 void AUDIOMIX_InitAudioPll(AUDIOMIX_Type *base, const ccm_analog_frac_pll_config_t *config)
54 {
55     assert(config != NULL);
56 
57     uint32_t fracCfg1 = base->SAI_PLL_FDIV_CTL0;
58     uint32_t fracCfg2 = base->SAI_PLL_FDIV_CTL1;
59 
60     /* PLL power down and no bypass */
61     base->SAI_PLL_GNRL_CTL =
62         base->SAI_PLL_GNRL_CTL & (~(AUDIOMIX_SAI_PLL_GNRL_CTL_RESETB_MASK | AUDIOMIX_SAI_PLL_GNRL_CTL_BYPASS_MASK));
63     base->SAI_PLL_FDIV_CTL0 =
64         (fracCfg1 & (~(AUDIOMIX_SAI_PLL_FDIV_CTL0_MAIN_DIV_MASK | AUDIOMIX_SAI_PLL_FDIV_CTL0_PRE_DIV_MASK |
65                        AUDIOMIX_SAI_PLL_FDIV_CTL0_POST_DIV_MASK))) |
66         AUDIOMIX_SAI_PLL_FDIV_CTL0_MAIN_DIV(config->mainDiv) | AUDIOMIX_SAI_PLL_FDIV_CTL0_PRE_DIV(config->preDiv) |
67         AUDIOMIX_SAI_PLL_FDIV_CTL0_POST_DIV(config->postDiv);
68 
69     base->SAI_PLL_FDIV_CTL1 =
70         (fracCfg2 & (~(AUDIOMIX_SAI_PLL_FDIV_CTL1_DSM_MASK))) | AUDIOMIX_SAI_PLL_FDIV_CTL1_DSM(config->dsm);
71 
72     base->SAI_PLL_GNRL_CTL |=
73         AUDIOMIX_SAI_PLL_GNRL_CTL_RESETB_MASK | AUDIOMIX_SAI_PLL_GNRL_CTL_CKE_MASK; /* Enable and power up PLL clock. */
74 
75     /* Wait for PLL to be locked. */
76     while ((base->SAI_PLL_GNRL_CTL & AUDIOMIX_SAI_PLL_GNRL_CTL_LOCK_MASK) == 0U)
77     {
78     }
79 }
80 
81 /*!
82  * brief De-initialize the SAI PLL.
83  */
AUDIOMIX_DeinitAudioPll1(AUDIOMIX_Type * base)84 void AUDIOMIX_DeinitAudioPll1(AUDIOMIX_Type *base)
85 {
86     base->SAI_PLL_GNRL_CTL &= ~AUDIOMIX_SAI_PLL_GNRL_CTL_RESETB_MASK;
87 }
88 
89 /*!
90  * brief Get the sai PLL output freq.
91  *
92  * retval sai pll output freq.
93  */
AUDIOMIX_GetAudioPllFreq(AUDIOMIX_Type * base)94 uint32_t AUDIOMIX_GetAudioPllFreq(AUDIOMIX_Type *base)
95 {
96     uint32_t fracCfg1 = base->SAI_PLL_FDIV_CTL0;
97     uint32_t fracCfg2 = base->SAI_PLL_FDIV_CTL1;
98     uint64_t fracClk  = 0U;
99     /* get reference clock freq */
100     uint32_t refClkFreq =
101         (base->SAI_PLL_GNRL_CTL & AUDIOMIX_SAI_PLL_GNRL_CTL_REF_CLK_SEL_MASK) != 0U ? CLKPAD_FREQ : OSC24M_CLK_FREQ;
102     /* main divider */
103     uint32_t mainDiv =
104         (fracCfg1 & AUDIOMIX_SAI_PLL_FDIV_CTL0_MAIN_DIV_MASK) >> AUDIOMIX_SAI_PLL_FDIV_CTL0_MAIN_DIV_SHIFT;
105     /* pre divider */
106     uint32_t preDiv = (fracCfg1 & AUDIOMIX_SAI_PLL_FDIV_CTL0_PRE_DIV_MASK) >> AUDIOMIX_SAI_PLL_FDIV_CTL0_PRE_DIV_SHIFT;
107     /* post divider */
108     uint32_t postDiv =
109         ((fracCfg1 & AUDIOMIX_SAI_PLL_FDIV_CTL0_POST_DIV_MASK) >> AUDIOMIX_SAI_PLL_FDIV_CTL0_POST_DIV_SHIFT);
110     uint32_t dsm = (fracCfg2 & AUDIOMIX_SAI_PLL_FDIV_CTL1_DSM_MASK) >> AUDIOMIX_SAI_PLL_FDIV_CTL1_DSM_SHIFT;
111 
112     /* calculate the audio pll frequ */
113     fracClk = (uint64_t)refClkFreq * ((uint64_t)mainDiv * 65536UL + dsm) / (65536UL * preDiv * (1UL << postDiv));
114 
115     return (uint32_t)fracClk;
116 }
117