1 /*
2  * Copyright (c) 2019 - 2024, Nordic Semiconductor ASA
3  * All rights reserved.
4  *
5  * SPDX-License-Identifier: BSD-3-Clause
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions are met:
9  *
10  * 1. Redistributions of source code must retain the above copyright notice, this
11  *    list of conditions and the following disclaimer.
12  *
13  * 2. Redistributions in binary form must reproduce the above copyright
14  *    notice, this list of conditions and the following disclaimer in the
15  *    documentation and/or other materials provided with the distribution.
16  *
17  * 3. Neither the name of the copyright holder nor the names of its
18  *    contributors may be used to endorse or promote products derived from this
19  *    software without specific prior written permission.
20  *
21  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
22  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
25  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
26  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
27  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
28  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
29  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
30  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
31  * POSSIBILITY OF SUCH DAMAGE.
32  */
33 
34 #ifndef NRF_OSCILLATORS_H__
35 #define NRF_OSCILLATORS_H__
36 
37 #include <nrfx.h>
38 
39 #ifdef __cplusplus
40 extern "C" {
41 #endif
42 
43 /**
44  * @defgroup nrf_oscillators_hal OSCILLATORS HAL
45  * @{
46  * @ingroup nrf_clock
47  * @brief   Hardware access layer for managing the OSCILLATORS peripheral.
48  */
49 
50 #if defined(OSCILLATORS_PLL_FREQ_FREQ_Msk) || defined(__NRFX_DOXYGEN__)
51 /** @brief Symbol indicating whether PLL is present. */
52 #define NRF_OSCILLATORS_HAS_PLL 1
53 #else
54 #define NRF_OSCILLATORS_HAS_PLL 0
55 #endif
56 
57 #if defined(OSCILLATORS_XOSC32M_CLOCKQUALITY_INDICATOR_Msk) || defined(__NRFX_DOXYGEN__)
58 /** @brief Symbol indicating whether clock quality indicator is present. */
59 #define NRF_OSCILLATORS_HAS_CLOCK_QUALITY_IND 1
60 #else
61 #define NRF_OSCILLATORS_HAS_CLOCK_QUALITY_IND 0
62 #endif
63 
64 #if defined(OSCILLATORS_XOSC32KI_INTCAP_VAL_Msk) || defined(__NRFX_DOXYGEN__)
65 /** @brief Symbol indicating whether configuration of internal capacitor using integer value is present. */
66 #define NRF_OSCILLATORS_HAS_LFXO_CAP_AS_INT_VALUE 1
67 #else
68 #define NRF_OSCILLATORS_HAS_LFXO_CAP_AS_INT_VALUE 0
69 #endif
70 
71 #if defined(OSCILLATORS_XOSC32KI_Type) || defined(__NRFX_DOXYGEN__)
72 /** @brief Symbol indicating whether LFXO bypass is present. */
73 #define NRF_OSCILLATORS_HAS_LFXO_BYPASS 1
74 #else
75 #define NRF_OSCILLATORS_HAS_LFXO_BYPASS 0
76 #endif
77 
78 #if defined(NRF5340_XXAA_APPLICATION) || defined(__NRFX_DOXYGEN__)
79 /**
80  * @brief Macro for calculating HFXO internal capacitor value.
81  *
82  * Depending on the SoC used, a range of capacitance of internal capacitors is as follows:
83  * - From 7 pF to 20 pF in 0.5 pF steps for nRF5340.
84  * - From 4 pF to 17 pF in 0.25 pF steps for other SoCs.
85  * This macro should be used to calculate argument's value for @ref nrf_oscillators_hfxo_cap_set function.
86 */
87 #define OSCILLATORS_HFXO_CAP_CALCULATE(p_ficr_reg, cap_val)   \
88     ((((p_ficr_reg->XOSC32MTRIM & FICR_XOSC32MTRIM_SLOPE_Msk) \
89        << FICR_XOSC32MTRIM_SLOPE_Pos) / 16 + 1) *             \
90      (cap_val * 2 - 14) +                                     \
91      ((p_ficr_reg->XOSC32MTRIM & FICR_XOSC32MTRIM_OFFSET_Msk) \
92        << FICR_XOSC32MTRIM_OFFSET_Pos))
93 #else
94 #define OSCILLATORS_HFXO_CAP_CALCULATE(p_ficr_reg, cap_val)       \
95     (((cap_val - 5.5) *                                           \
96       (((p_ficr_reg->XOSC32MTRIM & FICR_XOSC32MTRIM_SLOPE_Msk)    \
97                           << FICR_XOSC32MTRIM_SLOPE_Pos) + 791) + \
98       (((p_ficr_reg->XOSC32MTRIM & FICR_XOSC32MTRIM_OFFSET_Msk)   \
99          << FICR_XOSC32MTRIM_OFFSET_Pos) << 2)) >> 8)
100 #endif
101 
102 #if NRF_OSCILLATORS_HAS_LFXO_CAP_AS_INT_VALUE
103 /**
104  * @brief Macro for calculating LFXO internal capacitor value.
105  *
106  * The capacitance of internal capacitors ranges from 4 pF to 18 pF in 0.5 pF steps.
107  * This macro should be used to calculate argument's value for @ref nrf_oscillators_lfxo_cap_set function.
108 */
109 #define OSCILLATORS_LFXO_CAP_CALCULATE(p_ficr_reg, cap_val)                     \
110     ((((cap_val - 4) * (((p_ficr_reg->XOSC32KTRIM & FICR_XOSC32KTRIM_SLOPE_Msk) \
111                           << FICR_XOSC32KTRIM_SLOPE_Pos)) + 392) >> 3 +         \
112       ((p_ficr_reg->XOSC32KTRIM & FICR_XOSC32KTRIM_OFFSET_Msk)                  \
113        << FICR_XOSC32KTRIM_OFFSET_Pos)) >> 6)
114 #endif
115 
116 #if NRF_OSCILLATORS_HAS_CLOCK_QUALITY_IND
117 /** @brief HFXO clock quality indicator. */
118 typedef enum
119 {
120     NRF_OSCILLATORS_HFXO_CLOCK_QUALITY_NONE     = OSCILLATORS_XOSC32M_CLOCKQUALITY_INDICATOR_NoStatus, ///< Clock XOSC32M status is not defined.
121     NRF_OSCILLATORS_HFXO_CLOCK_QUALITY_STARTING = OSCILLATORS_XOSC32M_CLOCKQUALITY_INDICATOR_Starting, ///< Clock XOSC32M has started but has not yet reached the specified frequency tolerance requirement fTOL_HFXO.
122     NRF_OSCILLATORS_HFXO_CLOCK_QUALITY_STARTED  = OSCILLATORS_XOSC32M_CLOCKQUALITY_INDICATOR_Started   ///< Clock XOSC32M has started and is operating with the specified frequency tolerance requirement fTOL_HFXO.
123 } nrf_oscillators_hfxo_clock_quality_t;
124 #endif
125 
126 #if NRF_OSCILLATORS_HAS_PLL
127 /** @brief PLL frequencies. */
128 typedef enum
129 {
130     NRF_OSCILLATORS_PLL_FREQ_64M  = OSCILLATORS_PLL_FREQ_FREQ_CK64M,  ///< PLL 64 MHz frequency.
131     NRF_OSCILLATORS_PLL_FREQ_128M = OSCILLATORS_PLL_FREQ_FREQ_CK128M, ///< PLL 128 MHz frequency.
132 } nrf_oscillators_pll_freq_t;
133 #endif
134 
135 #if NRF_OSCILLATORS_HAS_LFXO_CAP_AS_INT_VALUE
136 /** @brief LFXO capacitance type. */
137 typedef uint32_t nrf_oscillators_lfxo_cap_t;
138 
139 /** @brief Symbol specifying usage of external capacitors. */
140 #define NRF_OSCILLATORS_LFXO_CAP_EXTERNAL ((nrf_oscillators_lfxo_cap_t)0)
141 #else
142 /** @brief Capacitors configuration for LFXO. */
143 typedef enum
144 {
145     NRF_OSCILLATORS_LFXO_CAP_EXTERNAL = OSCILLATORS_XOSC32KI_INTCAP_INTCAP_External, ///< Use external capacitors.
146     NRF_OSCILLATORS_LFXO_CAP_6PF      = OSCILLATORS_XOSC32KI_INTCAP_INTCAP_C6PF,     ///< Use 6 pF internal capacitors.
147     NRF_OSCILLATORS_LFXO_CAP_7PF      = OSCILLATORS_XOSC32KI_INTCAP_INTCAP_C7PF,     ///< Use 7 pF internal capacitors.
148     NRF_OSCILLATORS_LFXO_CAP_9PF      = OSCILLATORS_XOSC32KI_INTCAP_INTCAP_C9PF,     ///< Use 9 pF internal capacitors.
149 #if defined(OSCILLATORS_XOSC32KI_INTCAP_INTCAP_C11PF) || defined(__NRFX_DOXYGEN__)
150     NRF_OSCILLATORS_LFXO_CAP_11PF     = OSCILLATORS_XOSC32KI_INTCAP_INTCAP_C11PF,    ///< Use 11 pF internal capacitors.
151 #endif
152 } nrf_oscillators_lfxo_cap_t;
153 #endif
154 
155 #if NRF_OSCILLATORS_HAS_CLOCK_QUALITY_IND
156 /**
157  * @brief Function for reading HFXO clock quality indicator.
158  *
159  * @param[in] p_reg Pointer to the structure of registers of the peripheral.
160  *
161  * @return Clock quality indicator value.
162  */
163 NRF_STATIC_INLINE nrf_oscillators_hfxo_clock_quality_t
164 nrf_oscillators_hfxo_clock_quality_get(NRF_OSCILLATORS_Type * p_reg);
165 #endif
166 
167 #if NRF_OSCILLATORS_HAS_PLL
168 /**
169  * @brief Function for setting PLL frequency.
170  *
171  * @param[in] p_reg Pointer to the structure of registers of the peripheral.
172  * @param[in] freq  New PLL frequency.
173  */
174 NRF_STATIC_INLINE void nrf_oscillators_pll_freq_set(NRF_OSCILLATORS_Type *     p_reg,
175                                                     nrf_oscillators_pll_freq_t freq);
176 
177 /**
178  * @brief Function for getting PLL frequency.
179  *
180  * @param[in] p_reg Pointer to the structure of registers of the peripheral.
181  *
182  * @return Current PLL frequency value.
183  */
184 NRF_STATIC_INLINE
185 nrf_oscillators_pll_freq_t nrf_oscillators_pll_freq_get(NRF_OSCILLATORS_Type * p_reg);
186 #endif
187 
188 #if NRF_OSCILLATORS_HAS_LFXO_BYPASS
189 /**
190  * @brief Function for enabling or disabling the bypass of LFXO with external clock source.
191  *
192  * @param[in] p_reg  Pointer to the structure of registers of the peripheral.
193  * @param[in] enable True if bypass is to be enabled (use with rail-to-rail external source).
194  *                   False if bypass is to be disabled (use with xtal or low-swing external source).
195  */
196 NRF_STATIC_INLINE void nrf_oscillators_lfxo_bypass_set(NRF_OSCILLATORS_Type * p_reg, bool enable);
197 #endif
198 
199 /**
200  * @brief Function for configuring the internal capacitors of LFXO.
201  *
202  * For SoCs other than nRF5340, to calculate the correct @p cap_value, use @ref OSCILLATORS_LFXO_CAP_CALCULATE macro.
203  *
204  * @param[in] p_reg Pointer to the structure of registers of the peripheral.
205  * @param[in] cap   Capacitors configuration.
206  */
207 NRF_STATIC_INLINE void nrf_oscillators_lfxo_cap_set(NRF_OSCILLATORS_Type *     p_reg,
208                                                     nrf_oscillators_lfxo_cap_t cap);
209 
210 /**
211  * @brief Function for configuring the internal capacitors of HFXO.
212  *
213  * To calculate the correct @p cap_value, use @ref OSCILLATORS_HFXO_CAP_CALCULATE macro.
214  *
215  * @param[in] p_reg     Pointer to the structure of registers of the peripheral.
216  * @param[in] enable    True if internal capacitors are to be enabled, false otherwise.
217  * @param[in] cap_value Value representing capacitance, calculated using provided equation.
218  *                      Ignored when internal capacitors are disabled.
219  */
220 NRF_STATIC_INLINE void nrf_oscillators_hfxo_cap_set(NRF_OSCILLATORS_Type * p_reg,
221                                                     bool                   enable,
222                                                     uint32_t               cap_value);
223 
224 #ifndef NRF_DECLARE_ONLY
225 
226 #if NRF_OSCILLATORS_HAS_CLOCK_QUALITY_IND
227 NRF_STATIC_INLINE nrf_oscillators_hfxo_clock_quality_t
nrf_oscillators_hfxo_clock_quality_get(NRF_OSCILLATORS_Type * p_reg)228 nrf_oscillators_hfxo_clock_quality_get(NRF_OSCILLATORS_Type * p_reg)
229 {
230     return (nrf_oscillators_hfxo_clock_quality_t)(p_reg->XOSC32M.CLOCKQUALITY);
231 }
232 #endif
233 
234 #if NRF_OSCILLATORS_HAS_PLL
nrf_oscillators_pll_freq_set(NRF_OSCILLATORS_Type * p_reg,nrf_oscillators_pll_freq_t freq)235 NRF_STATIC_INLINE void nrf_oscillators_pll_freq_set(NRF_OSCILLATORS_Type *     p_reg,
236                                                     nrf_oscillators_pll_freq_t freq)
237 {
238     p_reg->PLL.FREQ = (uint32_t)freq;
239 }
240 
241 NRF_STATIC_INLINE
nrf_oscillators_pll_freq_get(NRF_OSCILLATORS_Type * p_reg)242 nrf_oscillators_pll_freq_t nrf_oscillators_pll_freq_get(NRF_OSCILLATORS_Type * p_reg)
243 {
244     return (nrf_oscillators_pll_freq_t)(p_reg->PLL.CURRENTFREQ);
245 }
246 #endif
247 
248 #if NRF_OSCILLATORS_HAS_LFXO_BYPASS
nrf_oscillators_lfxo_bypass_set(NRF_OSCILLATORS_Type * p_reg,bool enable)249 NRF_STATIC_INLINE void nrf_oscillators_lfxo_bypass_set(NRF_OSCILLATORS_Type * p_reg, bool enable)
250 {
251     p_reg->XOSC32KI.BYPASS = (enable ? OSCILLATORS_XOSC32KI_BYPASS_BYPASS_Enabled :
252                                        OSCILLATORS_XOSC32KI_BYPASS_BYPASS_Disabled);
253 }
254 #endif
255 
nrf_oscillators_lfxo_cap_set(NRF_OSCILLATORS_Type * p_reg,nrf_oscillators_lfxo_cap_t cap)256 NRF_STATIC_INLINE void nrf_oscillators_lfxo_cap_set(NRF_OSCILLATORS_Type *     p_reg,
257                                                     nrf_oscillators_lfxo_cap_t cap)
258 {
259     p_reg->XOSC32KI.INTCAP = (uint32_t)cap;
260 }
261 
nrf_oscillators_hfxo_cap_set(NRF_OSCILLATORS_Type * p_reg,bool enable,uint32_t cap_value)262 NRF_STATIC_INLINE void nrf_oscillators_hfxo_cap_set(NRF_OSCILLATORS_Type * p_reg,
263                                                     bool                   enable,
264                                                     uint32_t               cap_value)
265 {
266 #if defined(OSCILLATORS_XOSC32MCAPS_CAPVALUE_Msk)
267     p_reg->XOSC32MCAPS =
268         (enable ? ((OSCILLATORS_XOSC32MCAPS_ENABLE_Enabled << OSCILLATORS_XOSC32MCAPS_ENABLE_Pos) |
269                    (cap_value << OSCILLATORS_XOSC32MCAPS_CAPVALUE_Pos))
270                 : (OSCILLATORS_XOSC32MCAPS_ENABLE_Disabled << OSCILLATORS_XOSC32MCAPS_ENABLE_Pos));
271 #else
272     p_reg->XOSC32M.CONFIG.INTCAP = enable ? cap_value : 0;
273 #endif
274 }
275 #endif // NRF_DECLARE_ONLY
276 
277 /** @} */
278 
279 #ifdef __cplusplus
280 }
281 #endif
282 
283 #endif // NRF_OSCILLATORS_H__
284