Branch data Line data Source code
1 : : /*
2 : : * Copyright (c) 2016 - 2022, 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 : : #include <nrfx.h>
35 : :
36 : : #if NRFX_CHECK(NRFX_CLOCK_ENABLED)
37 : :
38 : : #include <nrfx_clock.h>
39 : : #include <nrf_erratas.h>
40 : :
41 : : #define NRFX_LOG_MODULE CLOCK
42 : : #include <nrfx_log.h>
43 : :
44 : : #if NRFX_CHECK(NRFX_POWER_ENABLED)
45 : : extern bool nrfx_power_irq_enabled;
46 : : #endif
47 : :
48 : : #if defined(CLOCK_LFCLKSRC_SRC_RC) || defined(__NRFX_DOXYGEN__)
49 : : #define LF_SRC_RC CLOCK_LFCLKSRC_SRC_RC
50 : : #else
51 : : #define LF_SRC_RC CLOCK_LFCLKSRC_SRC_LFRC
52 : : #endif
53 : :
54 : : #if NRFX_CHECK(NRFX_CLOCK_CONFIG_LF_CAL_ENABLED)
55 : : #if (NRF_CLOCK_HAS_CALIBRATION == 0)
56 : : #error "Calibration is not available in the SoC that is used."
57 : : #endif
58 : : #if (NRFX_CLOCK_CONFIG_LF_SRC != LF_SRC_RC)
59 : : #error "Calibration can be performed only for the RC Oscillator."
60 : : #endif
61 : : #endif
62 : :
63 : : #if !defined(USE_WORKAROUND_FOR_ANOMALY_132) && \
64 : : (defined(NRF52832_XXAA) || defined(NRF52832_XXAB))
65 : : // ANOMALY 132 - LFCLK needs to avoid frame from 66us to 138us after LFCLK stop. This solution
66 : : // applies delay of 138us before starting LFCLK.
67 : : #define USE_WORKAROUND_FOR_ANOMALY_132 1
68 : :
69 : : // Convert time to cycles (nRF52832 is clocked with 64 MHz, use delay of 138 us).
70 : : #define ANOMALY_132_DELAY_CYCLES (64UL * 138)
71 : : #endif
72 : :
73 : : #if !defined(USE_WORKAROUND_FOR_ANOMALY_192) && \
74 : : (defined(NRF52810_XXAA) || \
75 : : defined(NRF52832_XXAA) || defined(NRF52832_XXAB) || \
76 : : defined(NRF52840_XXAA))
77 : : // Enable workaround for nRF52 anomaly 192 (LFRC oscillator frequency is wrong
78 : : // after calibration, exceeding 500 ppm).
79 : : #define USE_WORKAROUND_FOR_ANOMALY_192 1
80 : : #endif
81 : :
82 : : #if !defined(USE_WORKAROUND_FOR_ANOMALY_201) && \
83 : : (defined(NRF52810_XXAA) || \
84 : : defined(NRF52832_XXAA) || defined(NRF52832_XXAB) || \
85 : : defined(NRF52840_XXAA))
86 : : // Enable workaround for nRF52 anomaly 201 (EVENTS_HFCLKSTARTED might be generated twice).
87 : : #define USE_WORKAROUND_FOR_ANOMALY_201 1
88 : : #endif
89 : :
90 : : #if defined(CLOCK_LFCLKSRC_SRC_Xtal)
91 : : #define LF_SRC_LFXO CLOCK_LFCLKSRC_SRC_Xtal
92 : : #else
93 : : #define LF_SRC_LFXO CLOCK_LFCLKSRC_SRC_LFXO
94 : : #endif
95 : :
96 : : #if defined(NRF_CLOCK_USE_EXTERNAL_LFCLK_SOURCES)
97 : : #define LF_SRC_XTAL_LOW (CLOCK_LFCLKSRC_SRC_Xtal | \
98 : : (CLOCK_LFCLKSRC_EXTERNAL_Enabled << CLOCK_LFCLKSRC_EXTERNAL_Pos))
99 : : #define LF_SRC_XTAL_FULL (CLOCK_LFCLKSRC_SRC_Xtal | \
100 : : (CLOCK_LFCLKSRC_BYPASS_Enabled << CLOCK_LFCLKSRC_BYPASS_Pos) | \
101 : : (CLOCK_LFCLKSRC_EXTERNAL_Enabled << CLOCK_LFCLKSRC_EXTERNAL_Pos))
102 : : #else
103 : : #define LF_SRC_XTAL_LOW LF_SRC_LFXO
104 : : #define LF_SRC_XTAL_FULL LF_SRC_LFXO
105 : : #endif
106 : :
107 : : #if NRFX_CHECK(NRFX_CLOCK_CONFIG_LFXO_TWO_STAGE_ENABLED) && \
108 : : NRFX_CLOCK_CONFIG_LF_SRC != LF_SRC_LFXO && \
109 : : NRFX_CLOCK_CONFIG_LF_SRC != LF_SRC_XTAL_LOW && \
110 : : NRFX_CLOCK_CONFIG_LF_SRC != LF_SRC_XTAL_FULL
111 : : #error "Two-stage LFXO start procedure enabled but LFCLK source is not set to LFXO!"
112 : : #endif
113 : :
114 : : #if !defined(NRFX_CLOCK_CONFIG_CT_ENABLED) && NRF_CLOCK_HAS_CALIBRATION_TIMER
115 : : #define NRFX_CLOCK_CONFIG_CT_ENABLED 1
116 : : #endif
117 : :
118 : : #if NRFX_CHECK(NRFX_CLOCK_CONFIG_CT_ENABLED) && !NRF_CLOCK_HAS_CALIBRATION_TIMER
119 : : #error "Calibration timer is not available in the SoC that is used."
120 : : #endif
121 : :
122 : : #if NRFX_CHECK(NRFX_CLOCK_CONFIG_LF_CAL_ENABLED)
123 : : typedef enum
124 : : {
125 : : CAL_STATE_IDLE,
126 : : CAL_STATE_CAL
127 : : } nrfx_clock_cal_state_t;
128 : : #endif
129 : :
130 : : /**@brief CLOCK control block. */
131 : : typedef struct
132 : : {
133 : : nrfx_clock_event_handler_t event_handler;
134 : : bool module_initialized; /*< Indicate the state of module */
135 : : #if NRFX_CHECK(USE_WORKAROUND_FOR_ANOMALY_201)
136 : : bool hfclk_started; /*< Anomaly 201 workaround. */
137 : : #endif
138 : :
139 : : #if NRFX_CHECK(NRFX_CLOCK_CONFIG_LF_CAL_ENABLED)
140 : : volatile nrfx_clock_cal_state_t cal_state;
141 : : #endif
142 : : } nrfx_clock_cb_t;
143 : :
144 : : static nrfx_clock_cb_t m_clock_cb;
145 : :
146 : : /**
147 : : * This variable is used to check whether common POWER_CLOCK common interrupt
148 : : * should be disabled or not if @ref nrfx_power tries to disable the interrupt.
149 : : */
150 : : #if NRFX_CHECK(NRFX_POWER_ENABLED)
151 : : bool nrfx_clock_irq_enabled;
152 : : #endif
153 : :
154 : : #if NRFX_CHECK(USE_WORKAROUND_FOR_ANOMALY_132)
155 : : /**
156 : : * @brief Function for applying delay of 138us before starting LFCLK.
157 : : */
158 : : static void nrfx_clock_anomaly_132(void)
159 : : {
160 : : uint32_t cyccnt_inital;
161 : : uint32_t core_debug;
162 : : uint32_t dwt_ctrl;
163 : :
164 : : // Preserve DEMCR register to do not influence into its configuration. Enable the trace and
165 : : // debug blocks. It is required to read and write data to DWT block.
166 : : core_debug = CoreDebug->DEMCR;
167 : : CoreDebug->DEMCR = core_debug | CoreDebug_DEMCR_TRCENA_Msk;
168 : :
169 : : // Preserve CTRL register in DWT block to do not influence into its configuration. Make sure
170 : : // that cycle counter is enabled.
171 : : dwt_ctrl = DWT->CTRL;
172 : : DWT->CTRL = dwt_ctrl | DWT_CTRL_CYCCNTENA_Msk;
173 : :
174 : : // Store start value of cycle counter.
175 : : cyccnt_inital = DWT->CYCCNT;
176 : :
177 : : // Delay required time.
178 : : while ((DWT->CYCCNT - cyccnt_inital) < ANOMALY_132_DELAY_CYCLES)
179 : : {}
180 : :
181 : : // Restore preserved registers.
182 : : DWT->CTRL = dwt_ctrl;
183 : : CoreDebug->DEMCR = core_debug;
184 : : }
185 : : #endif // NRFX_CHECK(USE_WORKAROUND_FOR_ANOMALY_132)
186 : :
187 : 0 : static void clock_stop(nrf_clock_domain_t domain)
188 : : {
189 [ # # # # : 0 : switch (domain)
# ]
190 : : {
191 : 0 : case NRF_CLOCK_DOMAIN_LFCLK:
192 : 0 : nrf_clock_int_disable(NRF_CLOCK, NRF_CLOCK_INT_LF_STARTED_MASK);
193 : 0 : nrf_clock_event_clear(NRF_CLOCK, NRF_CLOCK_EVENT_LFCLKSTARTED);
194 : 0 : nrf_clock_task_trigger(NRF_CLOCK, NRF_CLOCK_TASK_LFCLKSTOP);
195 : 0 : break;
196 : 0 : case NRF_CLOCK_DOMAIN_HFCLK:
197 : 0 : nrf_clock_int_disable(NRF_CLOCK, NRF_CLOCK_INT_HF_STARTED_MASK);
198 : 0 : nrf_clock_event_clear(NRF_CLOCK, NRF_CLOCK_EVENT_HFCLKSTARTED);
199 : 0 : nrf_clock_task_trigger(NRF_CLOCK, NRF_CLOCK_TASK_HFCLKSTOP);
200 : 0 : break;
201 : : #if NRF_CLOCK_HAS_HFCLK192M
202 : 0 : case NRF_CLOCK_DOMAIN_HFCLK192M:
203 : 0 : nrf_clock_int_disable(NRF_CLOCK, NRF_CLOCK_INT_HF192M_STARTED_MASK);
204 : 0 : nrf_clock_event_clear(NRF_CLOCK, NRF_CLOCK_EVENT_HFCLK192MSTARTED);
205 : 0 : nrf_clock_task_trigger(NRF_CLOCK, NRF_CLOCK_TASK_HFCLK192MSTOP);
206 : 0 : break;
207 : : #endif
208 : : #if NRF_CLOCK_HAS_HFCLKAUDIO
209 : 0 : case NRF_CLOCK_DOMAIN_HFCLKAUDIO:
210 : 0 : nrf_clock_int_disable(NRF_CLOCK, NRF_CLOCK_INT_HFAUDIO_STARTED_MASK);
211 : 0 : nrf_clock_event_clear(NRF_CLOCK, NRF_CLOCK_EVENT_HFCLKAUDIOSTARTED);
212 : 0 : nrf_clock_task_trigger(NRF_CLOCK, NRF_CLOCK_TASK_HFCLKAUDIOSTOP);
213 : 0 : break;
214 : : #endif
215 : 0 : default:
216 : 0 : NRFX_ASSERT(0);
217 : 0 : return;
218 : : }
219 : :
220 : : bool stopped;
221 : 0 : nrf_clock_hfclk_t clk_src = NRF_CLOCK_HFCLK_HIGH_ACCURACY;
222 [ # # ]: 0 : nrf_clock_hfclk_t *p_clk_src = (domain == NRF_CLOCK_DOMAIN_HFCLK) ? &clk_src : NULL;
223 [ # # # # : 0 : NRFX_WAIT_FOR((!nrfx_clock_is_running(domain, p_clk_src) ||
# # # # ]
224 : : (p_clk_src && clk_src != NRF_CLOCK_HFCLK_HIGH_ACCURACY)), 10000, 1, stopped);
225 [ # # ]: 0 : if (!stopped)
226 : : {
227 [ # # ]: 0 : NRFX_LOG_ERROR("Failed to stop clock domain: %d.", domain);
228 : : }
229 : :
230 : : #if NRFX_CHECK(USE_WORKAROUND_FOR_ANOMALY_201)
231 : : if (domain == NRF_CLOCK_DOMAIN_HFCLK)
232 : : {
233 : : m_clock_cb.hfclk_started = false;
234 : : }
235 : : #endif
236 : : }
237 : :
238 : 2 : static nrf_clock_lfclk_t clock_initial_lfclksrc_get(void)
239 : : {
240 : : #if NRFX_CHECK(NRFX_CLOCK_CONFIG_LFXO_TWO_STAGE_ENABLED)
241 : 2 : return NRF_CLOCK_LFCLK_RC;
242 : : #else
243 : : return (nrf_clock_lfclk_t)NRFX_CLOCK_CONFIG_LF_SRC;
244 : : #endif
245 : : }
246 : :
247 : : /**
248 : : * @brief Function for tweaking the specified low-frequency clock source given current driver state.
249 : : *
250 : : * @warning This function may stop currently running low-frequency clock source.
251 : : *
252 : : * @param[in,out] p_lfclksrc Pointer to the variable containing low-frequency clock source.
253 : : * It is set to adequate value in case of being inappropriate
254 : : * for current driver configuration.
255 : : *
256 : : * @return True if the specified clock source was correct, false otherwise.
257 : : */
258 : 0 : static bool clock_lfclksrc_tweak(nrf_clock_lfclk_t * p_lfclksrc)
259 : : {
260 : 0 : bool is_correct_clk = (*p_lfclksrc == NRFX_CLOCK_CONFIG_LF_SRC);
261 : : #if NRFX_CHECK(NRFX_CLOCK_CONFIG_LFXO_TWO_STAGE_ENABLED)
262 : : // In case of two-stage LFXO start procedure RC source is valid as well.
263 [ # # # # ]: 0 : is_correct_clk = is_correct_clk || (*p_lfclksrc == NRF_CLOCK_LFCLK_RC);
264 : : #endif
265 [ # # ]: 0 : if (!is_correct_clk)
266 : : {
267 : : // Inappropriate LF clock source is chosen.
268 : : // Stop currently active LF clock source and choose the correct one to start.
269 : 0 : clock_stop(NRF_CLOCK_DOMAIN_LFCLK);
270 : 0 : *p_lfclksrc = clock_initial_lfclksrc_get();
271 : : }
272 : 0 : return is_correct_clk;
273 : : }
274 : :
275 : 1 : nrfx_err_t nrfx_clock_init(nrfx_clock_event_handler_t event_handler)
276 : : {
277 [ - + ]: 1 : NRFX_ASSERT(event_handler);
278 : :
279 : 1 : nrfx_err_t err_code = NRFX_SUCCESS;
280 [ - + ]: 1 : if (m_clock_cb.module_initialized)
281 : : {
282 : 0 : err_code = NRFX_ERROR_ALREADY_INITIALIZED;
283 : : }
284 : : else
285 : : {
286 : : #if NRFX_CHECK(NRFX_CLOCK_CONFIG_LF_CAL_ENABLED)
287 : : m_clock_cb.cal_state = CAL_STATE_IDLE;
288 : : #endif
289 : 1 : m_clock_cb.event_handler = event_handler;
290 : 1 : m_clock_cb.module_initialized = true;
291 : : #if NRFX_CHECK(USE_WORKAROUND_FOR_ANOMALY_201)
292 : : m_clock_cb.hfclk_started = false;
293 : : #endif
294 : : }
295 : :
296 [ + - ]: 1 : NRFX_LOG_INFO("Function: %s, error code: %s.", __func__, NRFX_LOG_ERROR_STRING_GET(err_code));
297 : 1 : return err_code;
298 : : }
299 : :
300 : 1 : void nrfx_clock_enable(void)
301 : : {
302 [ - + ]: 1 : NRFX_ASSERT(m_clock_cb.module_initialized);
303 : 1 : nrfx_power_clock_irq_init();
304 : 1 : nrf_clock_lf_src_set(NRF_CLOCK, clock_initial_lfclksrc_get());
305 : : #if NRF_CLOCK_HAS_HFCLKSRC
306 : 1 : nrf_clock_hf_src_set(NRF_CLOCK, NRF_CLOCK_HFCLK_HIGH_ACCURACY);
307 : : #endif
308 : : #if NRF_CLOCK_HAS_HFCLK192M
309 : 1 : nrf_clock_hfclk192m_src_set(NRF_CLOCK, (nrf_clock_hfclk_t)NRFX_CLOCK_CONFIG_HFCLK192M_SRC);
310 : : #endif
311 : : #if NRFX_CHECK(NRFX_POWER_ENABLED)
312 : : nrfx_clock_irq_enabled = true;
313 : : #endif
314 : :
315 [ + - ]: 1 : NRFX_LOG_INFO("Module enabled.");
316 : 1 : }
317 : :
318 : 0 : void nrfx_clock_disable(void)
319 : : {
320 [ # # ]: 0 : NRFX_ASSERT(m_clock_cb.module_initialized);
321 : : #if NRFX_CHECK(NRFX_POWER_ENABLED)
322 : : NRFX_ASSERT(nrfx_clock_irq_enabled);
323 : : if (!nrfx_power_irq_enabled)
324 : : #endif
325 : : {
326 : 0 : NRFX_IRQ_DISABLE(nrfx_get_irq_number(NRF_CLOCK));
327 : : }
328 : 0 : nrf_clock_int_disable(NRF_CLOCK, CLOCK_INTENSET_HFCLKSTARTED_Msk |
329 : : CLOCK_INTENSET_LFCLKSTARTED_Msk |
330 : : #if NRFX_CHECK(NRFX_CLOCK_CONFIG_LF_CAL_ENABLED)
331 : : CLOCK_INTENSET_DONE_Msk |
332 : : #if NRF_HAS_CALIBRATION_TIMER
333 : : CLOCK_INTENSET_CTTO_Msk |
334 : : #endif
335 : : #endif // NRFX_CHECK(NRFX_CLOCK_CONFIG_LF_CAL_ENABLED)
336 : : 0);
337 : : #if NRFX_CHECK(NRFX_POWER_ENABLED)
338 : : nrfx_clock_irq_enabled = false;
339 : : #endif
340 [ # # ]: 0 : NRFX_LOG_INFO("Module disabled.");
341 : 0 : }
342 : :
343 : 0 : void nrfx_clock_uninit(void)
344 : : {
345 [ # # ]: 0 : NRFX_ASSERT(m_clock_cb.module_initialized);
346 : 0 : clock_stop(NRF_CLOCK_DOMAIN_LFCLK);
347 : 0 : clock_stop(NRF_CLOCK_DOMAIN_HFCLK);
348 : : #if NRF_CLOCK_HAS_HFCLK192M
349 : 0 : clock_stop(NRF_CLOCK_DOMAIN_HFCLK192M);
350 : : #endif
351 : : #if NRF_CLOCK_HAS_HFCLKAUDIO
352 : 0 : clock_stop(NRF_CLOCK_DOMAIN_HFCLKAUDIO);
353 : : #endif
354 : 0 : m_clock_cb.module_initialized = false;
355 [ # # ]: 0 : NRFX_LOG_INFO("Uninitialized.");
356 : 0 : }
357 : :
358 : 1 : void nrfx_clock_start(nrf_clock_domain_t domain)
359 : : {
360 [ - + ]: 1 : NRFX_ASSERT(m_clock_cb.module_initialized);
361 [ + - - - : 1 : switch (domain)
- ]
362 : : {
363 : 1 : case NRF_CLOCK_DOMAIN_LFCLK:
364 : : {
365 : : nrf_clock_lfclk_t lfclksrc;
366 [ - + ]: 1 : if (nrf_clock_is_running(NRF_CLOCK, NRF_CLOCK_DOMAIN_LFCLK, &lfclksrc))
367 : : {
368 : : // LF clock is already running. Inspect its source.
369 : : // If LF clock source is inappropriate then it will be stopped and modified.
370 : : // Ignore return value as LF clock will be started again regardless of the result.
371 : 0 : (void)clock_lfclksrc_tweak(&lfclksrc);
372 : : }
373 [ - + ]: 1 : else if (nrf_clock_start_task_check(NRF_CLOCK, NRF_CLOCK_DOMAIN_LFCLK))
374 : : {
375 : : // LF clock is not active yet but was started already. Inspect its source.
376 : 0 : lfclksrc = nrf_clock_lf_srccopy_get(NRF_CLOCK);
377 [ # # ]: 0 : if (clock_lfclksrc_tweak(&lfclksrc))
378 : : {
379 : : // LF clock was started already and the configured source
380 : : // corresponds to the user configuration.
381 : : // No action is needed as the chosen LF clock source will become active soon.
382 : 0 : nrf_clock_int_enable(NRF_CLOCK, NRF_CLOCK_INT_LF_STARTED_MASK);
383 : 0 : break;
384 : : }
385 : : // Otherwise LF clock was started already but with inappropriate source.
386 : : // LF clock was stopped and modified. Now it will be restarted.
387 : : }
388 : : else
389 : : {
390 : : // LF clock not active and not started.
391 : 1 : lfclksrc = clock_initial_lfclksrc_get();
392 : : }
393 : 1 : nrf_clock_lf_src_set(NRF_CLOCK, lfclksrc);
394 : : }
395 : 1 : nrf_clock_event_clear(NRF_CLOCK, NRF_CLOCK_EVENT_LFCLKSTARTED);
396 : 1 : nrf_clock_int_enable(NRF_CLOCK, NRF_CLOCK_INT_LF_STARTED_MASK);
397 : : #if NRFX_CHECK(USE_WORKAROUND_FOR_ANOMALY_132)
398 : : nrfx_clock_anomaly_132();
399 : : #endif
400 : 1 : nrf_clock_task_trigger(NRF_CLOCK, NRF_CLOCK_TASK_LFCLKSTART);
401 : 1 : break;
402 : 0 : case NRF_CLOCK_DOMAIN_HFCLK:
403 : 0 : nrf_clock_event_clear(NRF_CLOCK, NRF_CLOCK_EVENT_HFCLKSTARTED);
404 : 0 : nrf_clock_int_enable(NRF_CLOCK, NRF_CLOCK_INT_HF_STARTED_MASK);
405 : 0 : nrf_clock_task_trigger(NRF_CLOCK, NRF_CLOCK_TASK_HFCLKSTART);
406 : 0 : break;
407 : : #if NRF_CLOCK_HAS_HFCLK192M
408 : 0 : case NRF_CLOCK_DOMAIN_HFCLK192M:
409 : 0 : nrf_clock_event_clear(NRF_CLOCK, NRF_CLOCK_EVENT_HFCLK192MSTARTED);
410 : 0 : nrf_clock_int_enable(NRF_CLOCK, NRF_CLOCK_INT_HF192M_STARTED_MASK);
411 : 0 : nrf_clock_task_trigger(NRF_CLOCK, NRF_CLOCK_TASK_HFCLK192MSTART);
412 : 0 : break;
413 : : #endif
414 : : #if NRF_CLOCK_HAS_HFCLKAUDIO
415 : 0 : case NRF_CLOCK_DOMAIN_HFCLKAUDIO:
416 : 0 : nrf_clock_event_clear(NRF_CLOCK, NRF_CLOCK_EVENT_HFCLKAUDIOSTARTED);
417 : 0 : nrf_clock_int_enable(NRF_CLOCK, NRF_CLOCK_INT_HFAUDIO_STARTED_MASK);
418 : 0 : nrf_clock_task_trigger(NRF_CLOCK, NRF_CLOCK_TASK_HFCLKAUDIOSTART);
419 : 0 : break;
420 : : #endif
421 : 0 : default:
422 : 0 : NRFX_ASSERT(0);
423 : 0 : break;
424 : : }
425 : 1 : }
426 : :
427 : 0 : void nrfx_clock_stop(nrf_clock_domain_t domain)
428 : : {
429 [ # # ]: 0 : NRFX_ASSERT(m_clock_cb.module_initialized);
430 : 0 : clock_stop(domain);
431 : 0 : }
432 : :
433 : 0 : nrfx_err_t nrfx_clock_calibration_start(void)
434 : : {
435 : 0 : nrfx_err_t err_code = NRFX_SUCCESS;
436 : :
437 : : #if NRFX_CHECK(NRFX_CLOCK_CONFIG_LF_CAL_ENABLED)
438 : : nrf_clock_hfclk_t clk_src;
439 : : if (!nrfx_clock_is_running(NRF_CLOCK_DOMAIN_HFCLK, &clk_src))
440 : : {
441 : : return NRFX_ERROR_INVALID_STATE;
442 : : }
443 : :
444 : : if (clk_src != NRF_CLOCK_HFCLK_HIGH_ACCURACY)
445 : : {
446 : : return NRFX_ERROR_INVALID_STATE;
447 : : }
448 : :
449 : : if (!nrfx_clock_is_running(NRF_CLOCK_DOMAIN_LFCLK, NULL))
450 : : {
451 : : return NRFX_ERROR_INVALID_STATE;
452 : : }
453 : :
454 : : if (m_clock_cb.cal_state == CAL_STATE_IDLE)
455 : : {
456 : : nrf_clock_event_clear(NRF_CLOCK, NRF_CLOCK_EVENT_DONE);
457 : : nrf_clock_int_enable(NRF_CLOCK, NRF_CLOCK_INT_DONE_MASK);
458 : : m_clock_cb.cal_state = CAL_STATE_CAL;
459 : : #if NRFX_CHECK(USE_WORKAROUND_FOR_ANOMALY_192)
460 : : *(volatile uint32_t *)0x40000C34 = 0x00000002;
461 : : #endif
462 : : nrf_clock_task_trigger(NRF_CLOCK, NRF_CLOCK_TASK_CAL);
463 : : }
464 : : else
465 : : {
466 : : err_code = NRFX_ERROR_BUSY;
467 : : }
468 : : #endif // NRFX_CHECK(NRFX_CLOCK_CONFIG_LF_CAL_ENABLED)
469 : :
470 [ # # ]: 0 : NRFX_LOG_WARNING("Function: %s, error code: %s.",
471 : : __func__,
472 : : NRFX_LOG_ERROR_STRING_GET(err_code));
473 : 0 : return err_code;
474 : : }
475 : :
476 : 0 : nrfx_err_t nrfx_clock_is_calibrating(void)
477 : : {
478 : : #if NRFX_CHECK(NRFX_CLOCK_CONFIG_LF_CAL_ENABLED)
479 : : if (m_clock_cb.cal_state == CAL_STATE_CAL)
480 : : {
481 : : return NRFX_ERROR_BUSY;
482 : : }
483 : : #endif
484 : 0 : return NRFX_SUCCESS;
485 : : }
486 : :
487 : 0 : void nrfx_clock_calibration_timer_start(uint8_t interval)
488 : : {
489 : : #if NRFX_CHECK(NRFX_CLOCK_CONFIG_LF_CAL_ENABLED) && \
490 : : NRFX_CHECK(NRFX_CLOCK_CONFIG_CT_ENABLED) && NRF_CLOCK_HAS_CALIBRATION_TIMER
491 : : nrf_clock_cal_timer_timeout_set(NRF_CLOCK, interval);
492 : : nrf_clock_event_clear(NRF_CLOCK, NRF_CLOCK_EVENT_CTTO);
493 : : nrf_clock_int_enable(NRF_CLOCK, NRF_CLOCK_INT_CTTO_MASK);
494 : : nrf_clock_task_trigger(NRF_CLOCK, NRF_CLOCK_TASK_CTSTART);
495 : : #else
496 : : (void)interval;
497 : : #endif
498 : 0 : }
499 : :
500 : 0 : void nrfx_clock_calibration_timer_stop(void)
501 : : {
502 : : #if NRFX_CHECK(NRFX_CLOCK_CONFIG_LF_CAL_ENABLED) && \
503 : : NRFX_CHECK(NRFX_CLOCK_CONFIG_CT_ENABLED) && NRF_CLOCK_HAS_CALIBRATION_TIMER
504 : : nrf_clock_int_disable(NRF_CLOCK, NRF_CLOCK_INT_CTTO_MASK);
505 : : nrf_clock_task_trigger(NRF_CLOCK, NRF_CLOCK_TASK_CTSTOP);
506 : : #endif
507 : 0 : }
508 : :
509 : : #if defined(CLOCK_FEATURE_HFCLK_DIVIDE_PRESENT) || NRF_CLOCK_HAS_HFCLK192M
510 : 0 : nrfx_err_t nrfx_clock_divider_set(nrf_clock_domain_t domain,
511 : : nrf_clock_hfclk_div_t div)
512 : : {
513 [ # # # ]: 0 : switch(domain)
514 : : {
515 : : #if defined(CLOCK_FEATURE_HFCLK_DIVIDE_PRESENT)
516 : 0 : case NRF_CLOCK_DOMAIN_HFCLK:
517 [ # # # ]: 0 : switch (div)
518 : : {
519 : 0 : case NRF_CLOCK_HFCLK_DIV_2:
520 : : #if !defined(NRF_TRUSTZONE_NONSECURE)
521 [ # # ]: 0 : if (nrf53_errata_4())
522 : : {
523 : 0 : NRFX_CRITICAL_SECTION_ENTER();
524 : : __DSB();
525 : :
526 : 0 : nrf_clock_hfclk_div_set(NRF_CLOCK, div);
527 : :
528 : 0 : *(volatile uint32_t *)0x5084450C = 0x0;
529 : 0 : *(volatile uint32_t *)0x50026548 = 0x0;
530 : 0 : *(volatile uint32_t *)0x50081EE4 = 0x0D;
531 : :
532 : 0 : NRFX_CRITICAL_SECTION_EXIT();
533 : : }
534 : : else
535 : : #endif
536 : : {
537 : 0 : nrf_clock_hfclk_div_set(NRF_CLOCK, div);
538 : : }
539 : 0 : break;
540 : 0 : case NRF_CLOCK_HFCLK_DIV_1:
541 : : #if !defined(NRF_TRUSTZONE_NONSECURE)
542 [ # # ]: 0 : if (nrf53_errata_4())
543 : : {
544 : 0 : NRFX_CRITICAL_SECTION_ENTER();
545 : : __DSB();
546 : :
547 : 0 : *(volatile uint32_t *)0x5084450C = 0x4040;
548 : 0 : *(volatile uint32_t *)0x50026548 = 0x40;
549 : 0 : *(volatile uint32_t *)0x50081EE4 = 0x4D;
550 : :
551 : 0 : nrf_clock_hfclk_div_set(NRF_CLOCK, div);
552 : :
553 : 0 : NRFX_CRITICAL_SECTION_EXIT();
554 : : }
555 : : else
556 : : #endif
557 : : {
558 : 0 : nrf_clock_hfclk_div_set(NRF_CLOCK, div);
559 : : }
560 : 0 : break;
561 : 0 : default:
562 : 0 : return NRFX_ERROR_INVALID_PARAM;
563 : : }
564 : 0 : SystemCoreClockUpdate();
565 : 0 : return NRFX_SUCCESS;
566 : : #endif
567 : : #if NRF_CLOCK_HAS_HFCLK192M
568 : 0 : case NRF_CLOCK_DOMAIN_HFCLK192M:
569 [ # # ]: 0 : if (div > NRF_CLOCK_HFCLK_DIV_4)
570 : : {
571 : 0 : return NRFX_ERROR_INVALID_PARAM;
572 : : }
573 : : else
574 : : {
575 : 0 : nrf_clock_hfclk192m_div_set(NRF_CLOCK, div);
576 : : }
577 : 0 : return NRFX_SUCCESS;
578 : : #endif
579 : 0 : default:
580 : 0 : NRFX_ASSERT(0);
581 : 0 : return NRFX_ERROR_NOT_SUPPORTED;
582 : : }
583 : : }
584 : : #endif
585 : :
586 : 1 : void nrfx_clock_irq_handler(void)
587 : : {
588 [ - + ]: 1 : if (nrf_clock_event_check(NRF_CLOCK, NRF_CLOCK_EVENT_HFCLKSTARTED))
589 : : {
590 : 0 : nrf_clock_event_clear(NRF_CLOCK, NRF_CLOCK_EVENT_HFCLKSTARTED);
591 [ # # ]: 0 : NRFX_LOG_DEBUG("Event: NRF_CLOCK_EVENT_HFCLKSTARTED");
592 : 0 : nrf_clock_int_disable(NRF_CLOCK, NRF_CLOCK_INT_HF_STARTED_MASK);
593 : :
594 : : #if NRFX_CHECK(USE_WORKAROUND_FOR_ANOMALY_201)
595 : : if (!m_clock_cb.hfclk_started)
596 : : {
597 : : m_clock_cb.hfclk_started = true;
598 : : m_clock_cb.event_handler(NRFX_CLOCK_EVT_HFCLK_STARTED);
599 : : }
600 : : #else
601 : 0 : m_clock_cb.event_handler(NRFX_CLOCK_EVT_HFCLK_STARTED);
602 : : #endif
603 : : }
604 [ + - ]: 1 : if (nrf_clock_event_check(NRF_CLOCK, NRF_CLOCK_EVENT_LFCLKSTARTED))
605 : : {
606 : 1 : nrf_clock_event_clear(NRF_CLOCK, NRF_CLOCK_EVENT_LFCLKSTARTED);
607 [ + - ]: 1 : NRFX_LOG_DEBUG("Event: NRF_CLOCK_EVENT_LFCLKSTARTED");
608 : :
609 : : #if NRFX_CHECK(NRFX_CLOCK_CONFIG_LFXO_TWO_STAGE_ENABLED)
610 : : nrf_clock_lfclk_t lfclksrc;
611 : 1 : (void)nrf_clock_is_running(NRF_CLOCK, NRF_CLOCK_DOMAIN_LFCLK, &lfclksrc);
612 [ - + ]: 1 : if (lfclksrc == NRF_CLOCK_LFCLK_RC)
613 : : {
614 : : // After the LFRC oscillator start switch to external source.
615 : 0 : nrf_clock_lf_src_set(NRF_CLOCK, (nrf_clock_lfclk_t)NRFX_CLOCK_CONFIG_LF_SRC);
616 : 0 : nrf_clock_task_trigger(NRF_CLOCK, NRF_CLOCK_TASK_LFCLKSTART);
617 : : }
618 : : else
619 : : #endif
620 : : {
621 : : // After the LF clock external source start invoke user callback.
622 : 1 : nrf_clock_int_disable(NRF_CLOCK, NRF_CLOCK_INT_LF_STARTED_MASK);
623 : 1 : m_clock_cb.event_handler(NRFX_CLOCK_EVT_LFCLK_STARTED);
624 : : }
625 : : }
626 : :
627 : : #if NRFX_CHECK(NRFX_CLOCK_CONFIG_LF_CAL_ENABLED)
628 : : #if NRF_CLOCK_HAS_CALIBRATION_TIMER && NRFX_CHECK(NRFX_CLOCK_CONFIG_CT_ENABLED)
629 : : if (nrf_clock_event_check(NRF_CLOCK, NRF_CLOCK_EVENT_CTTO) &&
630 : : nrf_clock_int_enable_check(NRF_CLOCK, NRF_CLOCK_INT_CTTO_MASK))
631 : : {
632 : : nrf_clock_event_clear(NRF_CLOCK, NRF_CLOCK_EVENT_CTTO);
633 : : NRFX_LOG_DEBUG("Event: NRF_CLOCK_EVENT_CTTO");
634 : : nrf_clock_int_disable(NRF_CLOCK, NRF_CLOCK_INT_CTTO_MASK);
635 : :
636 : : m_clock_cb.event_handler(NRFX_CLOCK_EVT_CTTO);
637 : : }
638 : : #endif // NRF_CLOCK_HAS_CALIBRATION_TIMER && NRFX_CHECK(NRFX_CLOCK_CONFIG_CT_ENABLED)
639 : :
640 : : if (nrf_clock_event_check(NRF_CLOCK, NRF_CLOCK_EVENT_DONE) &&
641 : : nrf_clock_int_enable_check(NRF_CLOCK, NRF_CLOCK_INT_DONE_MASK))
642 : : {
643 : : #if NRFX_CHECK(USE_WORKAROUND_FOR_ANOMALY_192)
644 : : *(volatile uint32_t *)0x40000C34 = 0x00000000;
645 : : #endif
646 : : nrf_clock_event_clear(NRF_CLOCK, NRF_CLOCK_EVENT_DONE);
647 : : NRFX_LOG_DEBUG("Event: NRF_CLOCK_EVENT_DONE");
648 : : nrf_clock_int_disable(NRF_CLOCK, NRF_CLOCK_INT_DONE_MASK);
649 : : m_clock_cb.cal_state = CAL_STATE_IDLE;
650 : : m_clock_cb.event_handler(NRFX_CLOCK_EVT_CAL_DONE);
651 : : }
652 : : #endif // NRFX_CHECK(NRFX_CLOCK_CONFIG_LF_CAL_ENABLED)
653 : :
654 : : #if NRF_CLOCK_HAS_HFCLKAUDIO
655 [ - + ]: 1 : if (nrf_clock_event_check(NRF_CLOCK, NRF_CLOCK_EVENT_HFCLKAUDIOSTARTED))
656 : : {
657 : 0 : nrf_clock_event_clear(NRF_CLOCK, NRF_CLOCK_EVENT_HFCLKAUDIOSTARTED);
658 [ # # ]: 0 : NRFX_LOG_DEBUG("Event: NRF_CLOCK_EVENT_HFCLKAUDIOSTARTED");
659 : 0 : nrf_clock_int_disable(NRF_CLOCK, NRF_CLOCK_INT_HFAUDIO_STARTED_MASK);
660 : :
661 : 0 : m_clock_cb.event_handler(NRFX_CLOCK_EVT_HFCLKAUDIO_STARTED);
662 : : }
663 : : #endif
664 : :
665 : : #if NRF_CLOCK_HAS_HFCLK192M
666 [ - + ]: 1 : if (nrf_clock_event_check(NRF_CLOCK, NRF_CLOCK_EVENT_HFCLK192MSTARTED))
667 : : {
668 : 0 : nrf_clock_event_clear(NRF_CLOCK, NRF_CLOCK_EVENT_HFCLK192MSTARTED);
669 [ # # ]: 0 : NRFX_LOG_DEBUG("Event: NRF_CLOCK_EVENT_HFCLK192MSTARTED");
670 : 0 : nrf_clock_int_disable(NRF_CLOCK, NRF_CLOCK_INT_HF192M_STARTED_MASK);
671 : :
672 : 0 : m_clock_cb.event_handler(NRFX_CLOCK_EVT_HFCLK192M_STARTED);
673 : : }
674 : : #endif
675 : 1 : }
676 : :
677 : : #endif // NRFX_CHECK(NRFX_CLOCK_ENABLED)
|