1 /*
2 * Copyright (c) 2016 - 2025, 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 #elif defined(CLOCK_LFCLKSRC_SRC_LFRC)
51 #define LF_SRC_RC CLOCK_LFCLKSRC_SRC_LFRC
52 #else
53 #define LF_SRC_RC CLOCK_LFCLK_SRC_SRC_LFRC
54 #endif
55
56 #if NRFX_CHECK(NRFX_CLOCK_CONFIG_LF_CAL_ENABLED)
57 #if (NRF_CLOCK_HAS_CALIBRATION == 0)
58 #error "Calibration is not available in the SoC that is used."
59 #endif
60 #if (NRFX_CLOCK_CONFIG_LF_SRC != LF_SRC_RC)
61 #error "Calibration can be performed only for the RC Oscillator."
62 #endif
63 #endif
64
65 #if !defined(USE_WORKAROUND_FOR_ANOMALY_132) && \
66 (defined(NRF52832_XXAA) || defined(NRF52832_XXAB))
67 // ANOMALY 132 - LFCLK needs to avoid frame from 66us to 138us after LFCLK stop. This solution
68 // applies delay of 138us before starting LFCLK.
69 #define USE_WORKAROUND_FOR_ANOMALY_132 1
70
71 // Convert time to cycles (nRF52832 is clocked with 64 MHz, use delay of 138 us).
72 #define ANOMALY_132_DELAY_CYCLES (64UL * 138)
73 #endif
74
75 #if !defined(USE_WORKAROUND_FOR_ANOMALY_192) && \
76 (defined(NRF52810_XXAA) || \
77 defined(NRF52832_XXAA) || defined(NRF52832_XXAB) || \
78 defined(NRF52840_XXAA))
79 // Enable workaround for nRF52 anomaly 192 (LFRC oscillator frequency is wrong
80 // after calibration, exceeding 500 ppm).
81 #define USE_WORKAROUND_FOR_ANOMALY_192 1
82 #endif
83
84 #if !defined(USE_WORKAROUND_FOR_ANOMALY_201) && \
85 (defined(NRF52810_XXAA) || \
86 defined(NRF52832_XXAA) || defined(NRF52832_XXAB) || \
87 defined(NRF52840_XXAA))
88 // Enable workaround for nRF52 anomaly 201 (EVENTS_HFCLKSTARTED might be generated twice).
89 #define USE_WORKAROUND_FOR_ANOMALY_201 1
90 #endif
91
92 #if defined(CLOCK_LFCLKSRC_SRC_Xtal)
93 #define LF_SRC_LFXO CLOCK_LFCLKSRC_SRC_Xtal
94 #elif NRF_CLOCK_HAS_LFCLK_TYPE
95 #define LF_SRC_LFXO CLOCK_LFCLK_SRC_SRC_LFXO
96 #else
97 #define LF_SRC_LFXO CLOCK_LFCLKSRC_SRC_LFXO
98 #endif
99
100 #if defined(NRF_CLOCK_USE_EXTERNAL_LFCLK_SOURCES)
101 #define LF_SRC_XTAL_LOW (CLOCK_LFCLKSRC_SRC_Xtal | \
102 (CLOCK_LFCLKSRC_EXTERNAL_Enabled << CLOCK_LFCLKSRC_EXTERNAL_Pos))
103 #define LF_SRC_XTAL_FULL (CLOCK_LFCLKSRC_SRC_Xtal | \
104 (CLOCK_LFCLKSRC_BYPASS_Enabled << CLOCK_LFCLKSRC_BYPASS_Pos) | \
105 (CLOCK_LFCLKSRC_EXTERNAL_Enabled << CLOCK_LFCLKSRC_EXTERNAL_Pos))
106 #else
107 #define LF_SRC_XTAL_LOW LF_SRC_LFXO
108 #define LF_SRC_XTAL_FULL LF_SRC_LFXO
109 #endif
110
111 #if NRFX_CHECK(NRFX_CLOCK_CONFIG_LFXO_TWO_STAGE_ENABLED) && \
112 NRFX_CLOCK_CONFIG_LF_SRC != LF_SRC_LFXO && \
113 NRFX_CLOCK_CONFIG_LF_SRC != LF_SRC_XTAL_LOW && \
114 NRFX_CLOCK_CONFIG_LF_SRC != LF_SRC_XTAL_FULL
115 #error "Two-stage LFXO start procedure enabled but LFCLK source is not set to LFXO!"
116 #endif
117
118 #if !defined(NRFX_CLOCK_CONFIG_CT_ENABLED) && NRF_CLOCK_HAS_CALIBRATION_TIMER
119 #define NRFX_CLOCK_CONFIG_CT_ENABLED 1
120 #endif
121
122 #if NRFX_CHECK(NRFX_CLOCK_CONFIG_CT_ENABLED) && !NRF_CLOCK_HAS_CALIBRATION_TIMER
123 #error "Calibration timer is not available in the SoC that is used."
124 #endif
125
126 #if NRFX_CHECK(NRFX_CLOCK_CONFIG_LF_CAL_ENABLED)
127 typedef enum
128 {
129 CAL_STATE_IDLE,
130 CAL_STATE_CAL
131 } nrfx_clock_cal_state_t;
132 #endif
133
134 /** @brief CLOCK control block. */
135 typedef struct
136 {
137 nrfx_clock_event_handler_t event_handler;
138 bool module_initialized; /*< Indicate the state of module */
139 #if NRFX_CHECK(USE_WORKAROUND_FOR_ANOMALY_201)
140 bool hfclk_started; /*< Anomaly 201 workaround. */
141 #endif
142
143 #if NRFX_CHECK(NRFX_CLOCK_CONFIG_LF_CAL_ENABLED)
144 volatile nrfx_clock_cal_state_t cal_state;
145 #endif
146
147 #if NRFX_CHECK(NRF_CLOCK_HAS_XO_TUNE)
148 volatile bool xo_tune_in_progress;
149 #endif
150 } nrfx_clock_cb_t;
151
152 static nrfx_clock_cb_t m_clock_cb;
153
154 /**
155 * This variable is used to check whether common POWER_CLOCK common interrupt
156 * should be disabled or not if @ref nrfx_power tries to disable the interrupt.
157 */
158 #if NRFX_CHECK(NRFX_POWER_ENABLED)
159 bool nrfx_clock_irq_enabled;
160 #endif
161
162 #if NRFX_CHECK(USE_WORKAROUND_FOR_ANOMALY_132)
163 /**
164 * @brief Function for applying delay of 138us before starting LFCLK.
165 */
nrfx_clock_anomaly_132(void)166 static void nrfx_clock_anomaly_132(void)
167 {
168 uint32_t cyccnt_inital;
169 uint32_t core_debug;
170 uint32_t dwt_ctrl;
171
172 // Preserve DEMCR register to do not influence into its configuration. Enable the trace and
173 // debug blocks. It is required to read and write data to DWT block.
174 core_debug = CoreDebug->DEMCR;
175 CoreDebug->DEMCR = core_debug | CoreDebug_DEMCR_TRCENA_Msk;
176
177 // Preserve CTRL register in DWT block to do not influence into its configuration. Make sure
178 // that cycle counter is enabled.
179 dwt_ctrl = DWT->CTRL;
180 DWT->CTRL = dwt_ctrl | DWT_CTRL_CYCCNTENA_Msk;
181
182 // Store start value of cycle counter.
183 cyccnt_inital = DWT->CYCCNT;
184
185 // Delay required time.
186 while ((DWT->CYCCNT - cyccnt_inital) < ANOMALY_132_DELAY_CYCLES)
187 {}
188
189 // Restore preserved registers.
190 DWT->CTRL = dwt_ctrl;
191 CoreDebug->DEMCR = core_debug;
192 }
193 #endif // NRFX_CHECK(USE_WORKAROUND_FOR_ANOMALY_132)
194
clock_stop(nrf_clock_domain_t domain)195 static void clock_stop(nrf_clock_domain_t domain)
196 {
197 uint32_t int_mask;
198 nrf_clock_event_t event;
199 nrf_clock_task_t task;
200 switch (domain)
201 {
202 case NRF_CLOCK_DOMAIN_LFCLK:
203 int_mask = NRF_CLOCK_INT_LF_STARTED_MASK;
204 task = NRF_CLOCK_TASK_LFCLKSTOP;
205 event = NRF_CLOCK_EVENT_LFCLKSTARTED;
206 break;
207 case NRF_CLOCK_DOMAIN_HFCLK:
208 int_mask = NRF_CLOCK_INT_HF_STARTED_MASK |
209 #if NRF_CLOCK_HAS_XO_TUNE
210 NRF_CLOCK_INT_XOTUNED_MASK |
211 NRF_CLOCK_INT_XOTUNEFAILED_MASK |
212 NRF_CLOCK_INT_XOTUNEERROR_MASK |
213 #endif
214 0;
215 task = NRF_CLOCK_TASK_HFCLKSTOP;
216 event = NRF_CLOCK_EVENT_HFCLKSTARTED;
217 break;
218 #if NRF_CLOCK_HAS_HFCLK192M
219 case NRF_CLOCK_DOMAIN_HFCLK192M:
220 int_mask = NRF_CLOCK_INT_HF192M_STARTED_MASK;
221 task = NRF_CLOCK_TASK_HFCLK192MSTOP;
222 event = NRF_CLOCK_EVENT_HFCLK192MSTARTED;
223 break;
224 #endif
225 #if NRF_CLOCK_HAS_HFCLKAUDIO
226 case NRF_CLOCK_DOMAIN_HFCLKAUDIO:
227 int_mask = NRF_CLOCK_INT_HFAUDIO_STARTED_MASK;
228 task = NRF_CLOCK_TASK_HFCLKAUDIOSTOP;
229 event = NRF_CLOCK_EVENT_HFCLKAUDIOSTARTED;
230 break;
231 #endif
232 default:
233 NRFX_ASSERT(0);
234 return;
235 }
236
237 nrf_clock_int_disable(NRF_CLOCK, int_mask);
238 nrf_clock_task_trigger(NRF_CLOCK, task);
239 nrf_clock_event_clear(NRF_CLOCK, event);
240
241 bool stopped;
242 nrf_clock_hfclk_t clk_src = NRF_CLOCK_HFCLK_HIGH_ACCURACY;
243 nrf_clock_hfclk_t *p_clk_src = (domain == NRF_CLOCK_DOMAIN_HFCLK) ? &clk_src : NULL;
244 NRFX_WAIT_FOR((!nrfx_clock_is_running(domain, p_clk_src) ||
245 (p_clk_src && clk_src != NRF_CLOCK_HFCLK_HIGH_ACCURACY)), 10000, 1, stopped);
246 if (!stopped)
247 {
248 NRFX_LOG_ERROR("Failed to stop clock domain: %d.", domain);
249 }
250
251 #if NRFX_CHECK(USE_WORKAROUND_FOR_ANOMALY_201)
252 if (domain == NRF_CLOCK_DOMAIN_HFCLK)
253 {
254 m_clock_cb.hfclk_started = false;
255 }
256 #endif
257 }
258
clock_initial_lfclksrc_get(void)259 static nrf_clock_lfclk_t clock_initial_lfclksrc_get(void)
260 {
261 #if NRFX_CHECK(NRFX_CLOCK_CONFIG_LFXO_TWO_STAGE_ENABLED)
262 return NRF_CLOCK_LFCLK_RC;
263 #else
264 return (nrf_clock_lfclk_t)NRFX_CLOCK_CONFIG_LF_SRC;
265 #endif
266 }
267
268 /**
269 * @brief Function for tweaking the specified low-frequency clock source given current driver state.
270 *
271 * @warning This function may stop currently running low-frequency clock source.
272 *
273 * @param[in,out] p_lfclksrc Pointer to the variable containing low-frequency clock source.
274 * It is set to adequate value in case of being inappropriate
275 * for current driver configuration.
276 *
277 * @return True if the specified clock source was correct, false otherwise.
278 */
clock_lfclksrc_tweak(nrf_clock_lfclk_t * p_lfclksrc)279 static bool clock_lfclksrc_tweak(nrf_clock_lfclk_t * p_lfclksrc)
280 {
281 bool is_correct_clk = (*p_lfclksrc == NRFX_CLOCK_CONFIG_LF_SRC);
282 #if NRFX_CHECK(NRFX_CLOCK_CONFIG_LFXO_TWO_STAGE_ENABLED)
283 // In case of two-stage LFXO start procedure RC source is valid as well.
284 is_correct_clk = is_correct_clk || (*p_lfclksrc == NRF_CLOCK_LFCLK_RC);
285 #endif
286 if (!is_correct_clk)
287 {
288 // Inappropriate LF clock source is chosen.
289 // Stop currently active LF clock source and choose the correct one to start.
290 clock_stop(NRF_CLOCK_DOMAIN_LFCLK);
291 *p_lfclksrc = clock_initial_lfclksrc_get();
292 }
293 return is_correct_clk;
294 }
295
nrfx_clock_init(nrfx_clock_event_handler_t event_handler)296 nrfx_err_t nrfx_clock_init(nrfx_clock_event_handler_t event_handler)
297 {
298 nrfx_err_t err_code = NRFX_SUCCESS;
299 if (m_clock_cb.module_initialized)
300 {
301 err_code = NRFX_ERROR_ALREADY;
302 }
303 else
304 {
305 #if NRFX_CHECK(NRFX_CLOCK_CONFIG_LF_CAL_ENABLED)
306 m_clock_cb.cal_state = CAL_STATE_IDLE;
307 #endif
308 m_clock_cb.event_handler = event_handler;
309 m_clock_cb.module_initialized = true;
310 #if NRFX_CHECK(USE_WORKAROUND_FOR_ANOMALY_201)
311 m_clock_cb.hfclk_started = false;
312 #endif
313 }
314
315 NRFX_LOG_INFO("Function: %s, error code: %s.", __func__, NRFX_LOG_ERROR_STRING_GET(err_code));
316 return err_code;
317 }
318
nrfx_clock_enable(void)319 void nrfx_clock_enable(void)
320 {
321 NRFX_ASSERT(m_clock_cb.module_initialized);
322 if (m_clock_cb.event_handler)
323 {
324 nrfx_power_clock_irq_init();
325 }
326 nrf_clock_lf_src_set(NRF_CLOCK, clock_initial_lfclksrc_get());
327 #if NRF_CLOCK_HAS_HFCLKSRC
328 nrf_clock_hf_src_set(NRF_CLOCK, NRF_CLOCK_HFCLK_HIGH_ACCURACY);
329 #endif
330 #if NRF_CLOCK_HAS_HFCLK192M
331 nrf_clock_hfclk192m_src_set(NRF_CLOCK, (nrf_clock_hfclk_t)NRFX_CLOCK_CONFIG_HFCLK192M_SRC);
332 #endif
333 #if NRFX_CHECK(NRFX_POWER_ENABLED)
334 nrfx_clock_irq_enabled = true;
335 #endif
336
337 NRFX_LOG_INFO("Module enabled.");
338 }
339
nrfx_clock_disable(void)340 void nrfx_clock_disable(void)
341 {
342 NRFX_ASSERT(m_clock_cb.module_initialized);
343
344 if (m_clock_cb.event_handler)
345 {
346 #if NRFX_CHECK(NRFX_POWER_ENABLED)
347 NRFX_ASSERT(nrfx_clock_irq_enabled);
348 if (!nrfx_power_irq_enabled)
349 #endif
350 {
351 #if defined(NRF54L05_XXAA) || defined(NRF54L10_XXAA) || defined(NRF54L15_XXAA)
352 IRQn_Type irqn = CLOCK_POWER_IRQn;
353 #else
354 IRQn_Type irqn = nrfx_get_irq_number(NRF_CLOCK);
355 #endif
356 NRFX_IRQ_DISABLE(irqn);
357 }
358 }
359 nrf_clock_int_disable(NRF_CLOCK, NRF_CLOCK_INT_HF_STARTED_MASK |
360 NRF_CLOCK_INT_LF_STARTED_MASK |
361 #if NRFX_CHECK(NRFX_CLOCK_CONFIG_LF_CAL_ENABLED)
362 NRF_CLOCK_INT_DONE_MASK |
363 #if NRF_CLOCK_HAS_CALIBRATION_TIMER
364 NRF_CLOCK_INT_CTTO_MASK |
365 #endif
366 #endif // NRFX_CHECK(NRFX_CLOCK_CONFIG_LF_CAL_ENABLED)
367 0);
368 #if NRFX_CHECK(NRFX_POWER_ENABLED)
369 nrfx_clock_irq_enabled = false;
370 #endif
371 NRFX_LOG_INFO("Module disabled.");
372 }
373
nrfx_clock_uninit(void)374 void nrfx_clock_uninit(void)
375 {
376 NRFX_ASSERT(m_clock_cb.module_initialized);
377 clock_stop(NRF_CLOCK_DOMAIN_LFCLK);
378 clock_stop(NRF_CLOCK_DOMAIN_HFCLK);
379 #if NRF_CLOCK_HAS_HFCLK192M
380 clock_stop(NRF_CLOCK_DOMAIN_HFCLK192M);
381 #endif
382 #if NRF_CLOCK_HAS_HFCLKAUDIO
383 clock_stop(NRF_CLOCK_DOMAIN_HFCLKAUDIO);
384 #endif
385 m_clock_cb.module_initialized = false;
386 NRFX_LOG_INFO("Uninitialized.");
387 }
388
nrfx_clock_init_check(void)389 bool nrfx_clock_init_check(void)
390 {
391 return m_clock_cb.module_initialized;
392 }
393
nrfx_clock_start(nrf_clock_domain_t domain)394 void nrfx_clock_start(nrf_clock_domain_t domain)
395 {
396 uint32_t int_mask;
397 nrf_clock_event_t event;
398 nrf_clock_task_t task;
399
400 NRFX_ASSERT(m_clock_cb.module_initialized);
401 switch (domain)
402 {
403 case NRF_CLOCK_DOMAIN_LFCLK:
404 {
405 nrf_clock_lfclk_t lfclksrc;
406 if (nrf_clock_is_running(NRF_CLOCK, NRF_CLOCK_DOMAIN_LFCLK, &lfclksrc))
407 {
408 // LF clock is already running. Inspect its source.
409 // If LF clock source is inappropriate then it will be stopped and modified.
410 // Ignore return value as LF clock will be started again regardless of the result.
411 (void)clock_lfclksrc_tweak(&lfclksrc);
412 }
413 else if (nrf_clock_start_task_check(NRF_CLOCK, NRF_CLOCK_DOMAIN_LFCLK))
414 {
415 // LF clock is not active yet but was started already. Inspect its source.
416 lfclksrc = nrf_clock_lf_srccopy_get(NRF_CLOCK);
417 if (clock_lfclksrc_tweak(&lfclksrc))
418 {
419 // LF clock was started already and the configured source
420 // corresponds to the user configuration.
421 // No action is needed as the chosen LF clock source will become active soon.
422 if (m_clock_cb.event_handler)
423 {
424 nrf_clock_int_enable(NRF_CLOCK, NRF_CLOCK_INT_LF_STARTED_MASK);
425 }
426 else
427 {
428 while (!nrf_clock_event_check(NRF_CLOCK, NRF_CLOCK_EVENT_LFCLKSTARTED))
429 {}
430 nrf_clock_event_clear(NRF_CLOCK, NRF_CLOCK_EVENT_LFCLKSTARTED);
431 }
432 return;
433 }
434 // Otherwise LF clock was started already but with inappropriate source.
435 // LF clock was stopped and modified. Now it will be restarted.
436 }
437 else
438 {
439 // LF clock not active and not started.
440 lfclksrc = clock_initial_lfclksrc_get();
441 }
442 nrf_clock_lf_src_set(NRF_CLOCK, lfclksrc);
443 }
444 event = NRF_CLOCK_EVENT_LFCLKSTARTED;
445 int_mask = NRF_CLOCK_INT_LF_STARTED_MASK;
446 task = NRF_CLOCK_TASK_LFCLKSTART;
447 break;
448 case NRF_CLOCK_DOMAIN_HFCLK:
449 event = NRF_CLOCK_EVENT_HFCLKSTARTED;
450 int_mask = NRF_CLOCK_INT_HF_STARTED_MASK |
451 #if NRF_CLOCK_HAS_XO_TUNE
452 NRF_CLOCK_INT_XOTUNED_MASK |
453 NRF_CLOCK_INT_XOTUNEERROR_MASK |
454 NRF_CLOCK_INT_XOTUNEFAILED_MASK |
455 #endif
456 0;
457 task = NRF_CLOCK_TASK_HFCLKSTART;
458 break;
459 #if NRF_CLOCK_HAS_HFCLK192M
460 case NRF_CLOCK_DOMAIN_HFCLK192M:
461 event = NRF_CLOCK_EVENT_HFCLK192MSTARTED;
462 int_mask = NRF_CLOCK_INT_HF192M_STARTED_MASK;
463 task = NRF_CLOCK_TASK_HFCLK192MSTART;
464 break;
465 #endif
466 #if NRF_CLOCK_HAS_HFCLKAUDIO
467 case NRF_CLOCK_DOMAIN_HFCLKAUDIO:
468 event = NRF_CLOCK_EVENT_HFCLKAUDIOSTARTED;
469 int_mask = NRF_CLOCK_INT_HFAUDIO_STARTED_MASK;
470 task = NRF_CLOCK_TASK_HFCLKAUDIOSTART;
471 break;
472 #endif
473 default:
474 NRFX_ASSERT(0);
475 return;
476 }
477
478 nrf_clock_event_clear(NRF_CLOCK, event);
479 #if NRFX_CHECK(USE_WORKAROUND_FOR_ANOMALY_132)
480 if (event == NRF_CLOCK_EVENT_LFCLKSTARTED)
481 {
482 nrfx_clock_anomaly_132();
483 }
484 #endif
485 nrf_clock_task_trigger(NRF_CLOCK, task);
486 if (m_clock_cb.event_handler)
487 {
488 nrf_clock_int_enable(NRF_CLOCK, int_mask);
489 }
490 else
491 {
492 while (!nrf_clock_event_check(NRF_CLOCK, event))
493 {}
494 nrf_clock_event_clear(NRF_CLOCK, event);
495 }
496 }
497
nrfx_clock_stop(nrf_clock_domain_t domain)498 void nrfx_clock_stop(nrf_clock_domain_t domain)
499 {
500 NRFX_ASSERT(m_clock_cb.module_initialized);
501 clock_stop(domain);
502 }
503
504 #if NRF_CLOCK_HAS_CALIBRATION && NRFX_CHECK(NRFX_CLOCK_CONFIG_LF_CAL_ENABLED)
nrfx_clock_calibration_start(void)505 nrfx_err_t nrfx_clock_calibration_start(void)
506 {
507 nrfx_err_t err_code = NRFX_SUCCESS;
508
509 nrf_clock_hfclk_t clk_src;
510 if (!nrfx_clock_is_running(NRF_CLOCK_DOMAIN_HFCLK, &clk_src))
511 {
512 err_code = NRFX_ERROR_INVALID_STATE;
513 }
514 else if (clk_src != NRF_CLOCK_HFCLK_HIGH_ACCURACY)
515 {
516 err_code = NRFX_ERROR_INVALID_STATE;
517 }
518 else if (!nrfx_clock_is_running(NRF_CLOCK_DOMAIN_LFCLK, NULL))
519 {
520 err_code = NRFX_ERROR_INVALID_STATE;
521 }
522
523 if (err_code != NRFX_SUCCESS)
524 {
525 NRFX_LOG_WARNING("Function: %s, error code: %s.",
526 __func__,
527 NRFX_LOG_ERROR_STRING_GET(err_code));
528 return err_code;
529 }
530
531 if (m_clock_cb.cal_state == CAL_STATE_IDLE)
532 {
533 nrf_clock_event_clear(NRF_CLOCK, NRF_CLOCK_EVENT_DONE);
534
535 m_clock_cb.cal_state = CAL_STATE_CAL;
536 #if NRFX_CHECK(USE_WORKAROUND_FOR_ANOMALY_192)
537 *(volatile uint32_t *)0x40000C34 = 0x00000002;
538 #endif
539 nrf_clock_task_trigger(NRF_CLOCK, NRF_CLOCK_TASK_CAL);
540 if (m_clock_cb.event_handler)
541 {
542 nrf_clock_int_enable(NRF_CLOCK, NRF_CLOCK_INT_DONE_MASK);
543 }
544 else
545 {
546 while (!nrf_clock_event_check(NRF_CLOCK, NRF_CLOCK_EVENT_DONE))
547 {}
548 nrf_clock_event_clear(NRF_CLOCK, NRF_CLOCK_EVENT_DONE);
549 }
550 }
551 else
552 {
553 err_code = NRFX_ERROR_BUSY;
554 NRFX_LOG_WARNING("Function: %s, error code: %s.",
555 __func__,
556 NRFX_LOG_ERROR_STRING_GET(err_code));
557 return err_code;
558 }
559
560 NRFX_LOG_INFO("Initialized.");
561 return err_code;
562 }
563
nrfx_clock_is_calibrating(void)564 nrfx_err_t nrfx_clock_is_calibrating(void)
565 {
566 if (m_clock_cb.cal_state == CAL_STATE_CAL)
567 {
568 return NRFX_ERROR_BUSY;
569 }
570 return NRFX_SUCCESS;
571 }
572
573 #if NRF_CLOCK_HAS_XO_TUNE
nrfx_clock_xo_tune_start(void)574 nrfx_err_t nrfx_clock_xo_tune_start(void)
575 {
576 nrf_clock_hfclk_t hfclksrc = nrf_clock_hf_src_get(NRF_CLOCK);
577 if ((hfclksrc != NRF_CLOCK_HFCLK_HIGH_ACCURACY) || (m_clock_cb.xo_tune_in_progress))
578 {
579 return NRFX_ERROR_INVALID_STATE;
580 }
581
582 nrf_clock_event_clear(NRF_CLOCK, NRF_CLOCK_EVENT_XOTUNED);
583 nrf_clock_event_clear(NRF_CLOCK, NRF_CLOCK_EVENT_XOTUNEFAILED);
584
585 if (m_clock_cb.event_handler)
586 {
587 uint32_t int_mask = NRF_CLOCK_INT_XOTUNED_MASK | NRF_CLOCK_INT_XOTUNEFAILED_MASK;
588 nrf_clock_int_enable(NRF_CLOCK, int_mask);
589 }
590
591 // XOTUNEERROR can occur at any moment and it is not related to this operation
592 m_clock_cb.xo_tune_in_progress = true;
593 nrf_clock_task_trigger(NRF_CLOCK, NRF_CLOCK_TASK_XOTUNE);
594
595 if (!m_clock_cb.event_handler)
596 {
597 bool evt_xotuned;
598 bool evt_xotunefailed;
599 do
600 {
601 evt_xotuned = nrf_clock_event_check(NRF_CLOCK, NRF_CLOCK_EVENT_XOTUNED);
602 evt_xotunefailed = nrf_clock_event_check(NRF_CLOCK, NRF_CLOCK_EVENT_XOTUNEFAILED);
603 } while (!(evt_xotuned | evt_xotunefailed));
604 m_clock_cb.xo_tune_in_progress = false;
605
606 nrf_clock_event_clear(NRF_CLOCK, NRF_CLOCK_EVENT_XOTUNED);
607 nrf_clock_event_clear(NRF_CLOCK, NRF_CLOCK_EVENT_XOTUNEFAILED);
608
609 if (evt_xotunefailed)
610 {
611 return NRFX_ERROR_INTERNAL;
612 }
613 }
614
615 return NRFX_SUCCESS;
616 }
617
nrfx_clock_xo_tune_abort(void)618 nrfx_err_t nrfx_clock_xo_tune_abort(void)
619 {
620 nrf_clock_hfclk_t hfclksrc = nrf_clock_hf_src_get(NRF_CLOCK);
621 if ((hfclksrc != NRF_CLOCK_HFCLK_HIGH_ACCURACY) || (!m_clock_cb.xo_tune_in_progress))
622 {
623 return NRFX_ERROR_FORBIDDEN;
624 }
625
626 nrf_clock_task_trigger(NRF_CLOCK, NRF_CLOCK_TASK_XOTUNEABORT);
627 m_clock_cb.xo_tune_in_progress = false;
628
629 if (m_clock_cb.event_handler)
630 {
631 uint32_t int_mask = NRF_CLOCK_INT_XOTUNED_MASK | NRF_CLOCK_INT_XOTUNEFAILED_MASK;
632 nrf_clock_int_disable(NRF_CLOCK, int_mask);
633 }
634
635 return NRFX_SUCCESS;
636 }
637
nrfx_clock_xo_tune_error_check(void)638 bool nrfx_clock_xo_tune_error_check(void)
639 {
640 NRFX_ASSERT(!m_clock_cb.event_handler);
641
642 bool quality_issue = nrf_clock_event_check(NRF_CLOCK, NRF_CLOCK_EVENT_XOTUNEERROR);
643 if (quality_issue)
644 {
645 nrf_clock_event_clear(NRF_CLOCK, NRF_CLOCK_EVENT_XOTUNEERROR);
646 }
647 return quality_issue;
648 }
649
650 #endif // NRF_CLOCK_HAS_XO
651
652 #if NRF_CLOCK_HAS_CALIBRATION_TIMER && NRFX_CHECK(NRFX_CLOCK_CONFIG_CT_ENABLED)
nrfx_clock_calibration_timer_start(uint8_t interval)653 void nrfx_clock_calibration_timer_start(uint8_t interval)
654 {
655 nrf_clock_cal_timer_timeout_set(NRF_CLOCK, interval);
656 nrf_clock_event_clear(NRF_CLOCK, NRF_CLOCK_EVENT_CTTO);
657
658 nrf_clock_task_trigger(NRF_CLOCK, NRF_CLOCK_TASK_CTSTART);
659 if (m_clock_cb.event_handler)
660 {
661 nrf_clock_int_enable(NRF_CLOCK, NRF_CLOCK_INT_CTTO_MASK);
662 }
663 else
664 {
665 while (!nrf_clock_event_check(NRF_CLOCK, NRF_CLOCK_EVENT_CTTO))
666 {}
667 nrf_clock_event_clear(NRF_CLOCK, NRF_CLOCK_EVENT_CTTO);
668 }
669 }
670
nrfx_clock_calibration_timer_stop(void)671 void nrfx_clock_calibration_timer_stop(void)
672 {
673 nrf_clock_int_disable(NRF_CLOCK, NRF_CLOCK_INT_CTTO_MASK);
674 nrf_clock_task_trigger(NRF_CLOCK, NRF_CLOCK_TASK_CTSTOP);
675 }
676 #endif // NRF_CLOCK_HAS_CALIBRATION_TIMER && NRFX_CHECK(NRFX_CLOCK_CONFIG_CT_ENABLED)
677 #endif // NRF_CLOCK_HAS_CALIBRATION && NRFX_CHECK(NRFX_CLOCK_CONFIG_LF_CAL_ENABLED)
678
679 #if defined(CLOCK_FEATURE_HFCLK_DIVIDE_PRESENT) || NRF_CLOCK_HAS_HFCLK192M
nrfx_clock_divider_set(nrf_clock_domain_t domain,nrf_clock_hfclk_div_t div)680 nrfx_err_t nrfx_clock_divider_set(nrf_clock_domain_t domain,
681 nrf_clock_hfclk_div_t div)
682 {
683 switch(domain)
684 {
685 #if defined(CLOCK_FEATURE_HFCLK_DIVIDE_PRESENT)
686 case NRF_CLOCK_DOMAIN_HFCLK:
687 switch (div)
688 {
689 case NRF_CLOCK_HFCLK_DIV_2:
690 #if !defined(NRF_TRUSTZONE_NONSECURE)
691 if (nrf53_errata_4())
692 {
693 NRFX_CRITICAL_SECTION_ENTER();
694 __DSB();
695
696 nrf_clock_hfclk_div_set(NRF_CLOCK, div);
697
698 *(volatile uint32_t *)0x5084450C = 0x0;
699 *(volatile uint32_t *)0x50026548 = 0x0;
700 *(volatile uint32_t *)0x50081EE4 = 0x0D;
701
702 NRFX_CRITICAL_SECTION_EXIT();
703 }
704 else
705 #endif
706 {
707 nrf_clock_hfclk_div_set(NRF_CLOCK, div);
708 }
709 break;
710 case NRF_CLOCK_HFCLK_DIV_1:
711 #if !defined(NRF_TRUSTZONE_NONSECURE)
712 if (nrf53_errata_4())
713 {
714 NRFX_CRITICAL_SECTION_ENTER();
715 __DSB();
716
717 *(volatile uint32_t *)0x5084450C = 0x4040;
718 *(volatile uint32_t *)0x50026548 = 0x40;
719 *(volatile uint32_t *)0x50081EE4 = 0x4D;
720
721 nrf_clock_hfclk_div_set(NRF_CLOCK, div);
722
723 NRFX_CRITICAL_SECTION_EXIT();
724 }
725 else
726 #endif
727 {
728 nrf_clock_hfclk_div_set(NRF_CLOCK, div);
729 }
730 break;
731 default:
732 return NRFX_ERROR_INVALID_PARAM;
733 }
734 SystemCoreClockUpdate();
735 return NRFX_SUCCESS;
736 #endif
737 #if NRF_CLOCK_HAS_HFCLK192M
738 case NRF_CLOCK_DOMAIN_HFCLK192M:
739 if (div > NRF_CLOCK_HFCLK_DIV_4)
740 {
741 return NRFX_ERROR_INVALID_PARAM;
742 }
743 else
744 {
745 nrf_clock_hfclk192m_div_set(NRF_CLOCK, div);
746 }
747 return NRFX_SUCCESS;
748 #endif
749 default:
750 NRFX_ASSERT(0);
751 return NRFX_ERROR_NOT_SUPPORTED;
752 }
753 }
754 #endif
755
nrfx_clock_irq_handler(void)756 void nrfx_clock_irq_handler(void)
757 {
758 if (nrf_clock_event_check(NRF_CLOCK, NRF_CLOCK_EVENT_HFCLKSTARTED))
759 {
760 nrf_clock_event_clear(NRF_CLOCK, NRF_CLOCK_EVENT_HFCLKSTARTED);
761 NRFX_LOG_DEBUG("Event: NRF_CLOCK_EVENT_HFCLKSTARTED");
762 nrf_clock_int_disable(NRF_CLOCK, NRF_CLOCK_INT_HF_STARTED_MASK);
763
764 #if NRFX_CHECK(USE_WORKAROUND_FOR_ANOMALY_201)
765 if (!m_clock_cb.hfclk_started)
766 {
767 m_clock_cb.hfclk_started = true;
768 m_clock_cb.event_handler(NRFX_CLOCK_EVT_HFCLK_STARTED);
769 }
770 #else
771 m_clock_cb.event_handler(NRFX_CLOCK_EVT_HFCLK_STARTED);
772 #endif
773 }
774 if (nrf_clock_event_check(NRF_CLOCK, NRF_CLOCK_EVENT_LFCLKSTARTED))
775 {
776 nrf_clock_event_clear(NRF_CLOCK, NRF_CLOCK_EVENT_LFCLKSTARTED);
777 NRFX_LOG_DEBUG("Event: NRF_CLOCK_EVENT_LFCLKSTARTED");
778
779 #if NRFX_CHECK(NRFX_CLOCK_CONFIG_LFXO_TWO_STAGE_ENABLED)
780 nrf_clock_lfclk_t lfclksrc;
781 (void)nrf_clock_is_running(NRF_CLOCK, NRF_CLOCK_DOMAIN_LFCLK, &lfclksrc);
782 if (lfclksrc == NRF_CLOCK_LFCLK_RC)
783 {
784 // After the LFRC oscillator start switch to external source.
785 nrf_clock_lf_src_set(NRF_CLOCK, (nrf_clock_lfclk_t)NRFX_CLOCK_CONFIG_LF_SRC);
786 nrf_clock_task_trigger(NRF_CLOCK, NRF_CLOCK_TASK_LFCLKSTART);
787 }
788 else
789 #endif
790 {
791 // After the LF clock external source start invoke user callback.
792 nrf_clock_int_disable(NRF_CLOCK, NRF_CLOCK_INT_LF_STARTED_MASK);
793 m_clock_cb.event_handler(NRFX_CLOCK_EVT_LFCLK_STARTED);
794 }
795 }
796
797 #if NRFX_CHECK(NRF_CLOCK_HAS_PLL)
798 if (nrf_clock_event_check(NRF_CLOCK, NRF_CLOCK_EVENT_PLLSTARTED))
799 {
800 nrf_clock_event_clear(NRF_CLOCK, NRF_CLOCK_EVENT_PLLSTARTED);
801 NRFX_LOG_DEBUG("Event: NRF_CLOCK_EVENT_PLLSTARTED");
802 nrf_clock_int_disable(NRF_CLOCK, NRFX_CLOCK_INT_PLL_STARTED_MASK);
803 m_clock_cb.event_handler(NRFX_CLOCK_EVT_PLL_STARTED);
804 }
805 #endif
806
807 #if NRFX_CHECK(NRFX_CLOCK_CONFIG_LF_CAL_ENABLED)
808 #if NRF_CLOCK_HAS_CALIBRATION_TIMER && NRFX_CHECK(NRFX_CLOCK_CONFIG_CT_ENABLED)
809 if (nrf_clock_event_check(NRF_CLOCK, NRF_CLOCK_EVENT_CTTO) &&
810 nrf_clock_int_enable_check(NRF_CLOCK, NRF_CLOCK_INT_CTTO_MASK))
811 {
812 nrf_clock_event_clear(NRF_CLOCK, NRF_CLOCK_EVENT_CTTO);
813 NRFX_LOG_DEBUG("Event: NRF_CLOCK_EVENT_CTTO");
814 nrf_clock_int_disable(NRF_CLOCK, NRF_CLOCK_INT_CTTO_MASK);
815
816 m_clock_cb.event_handler(NRFX_CLOCK_EVT_CTTO);
817 }
818 #endif // NRF_CLOCK_HAS_CALIBRATION_TIMER && NRFX_CHECK(NRFX_CLOCK_CONFIG_CT_ENABLED)
819
820 if (nrf_clock_event_check(NRF_CLOCK, NRF_CLOCK_EVENT_DONE) &&
821 nrf_clock_int_enable_check(NRF_CLOCK, NRF_CLOCK_INT_DONE_MASK))
822 {
823 #if NRFX_CHECK(USE_WORKAROUND_FOR_ANOMALY_192)
824 *(volatile uint32_t *)0x40000C34 = 0x00000000;
825 #endif
826 nrf_clock_event_clear(NRF_CLOCK, NRF_CLOCK_EVENT_DONE);
827 NRFX_LOG_DEBUG("Event: NRF_CLOCK_EVENT_DONE");
828 nrf_clock_int_disable(NRF_CLOCK, NRF_CLOCK_INT_DONE_MASK);
829 m_clock_cb.cal_state = CAL_STATE_IDLE;
830 m_clock_cb.event_handler(NRFX_CLOCK_EVT_CAL_DONE);
831 }
832 #endif // NRFX_CHECK(NRFX_CLOCK_CONFIG_LF_CAL_ENABLED)
833
834 #if NRF_CLOCK_HAS_HFCLKAUDIO
835 if (nrf_clock_event_check(NRF_CLOCK, NRF_CLOCK_EVENT_HFCLKAUDIOSTARTED))
836 {
837 nrf_clock_event_clear(NRF_CLOCK, NRF_CLOCK_EVENT_HFCLKAUDIOSTARTED);
838 NRFX_LOG_DEBUG("Event: NRF_CLOCK_EVENT_HFCLKAUDIOSTARTED");
839 nrf_clock_int_disable(NRF_CLOCK, NRF_CLOCK_INT_HFAUDIO_STARTED_MASK);
840
841 m_clock_cb.event_handler(NRFX_CLOCK_EVT_HFCLKAUDIO_STARTED);
842 }
843 #endif
844
845 #if NRF_CLOCK_HAS_HFCLK192M
846 if (nrf_clock_event_check(NRF_CLOCK, NRF_CLOCK_EVENT_HFCLK192MSTARTED))
847 {
848 nrf_clock_event_clear(NRF_CLOCK, NRF_CLOCK_EVENT_HFCLK192MSTARTED);
849 NRFX_LOG_DEBUG("Event: NRF_CLOCK_EVENT_HFCLK192MSTARTED");
850 nrf_clock_int_disable(NRF_CLOCK, NRF_CLOCK_INT_HF192M_STARTED_MASK);
851
852 m_clock_cb.event_handler(NRFX_CLOCK_EVT_HFCLK192M_STARTED);
853 }
854 #endif
855
856 #if NRF_CLOCK_HAS_XO_TUNE
857 if (nrf_clock_event_check(NRF_CLOCK, NRF_CLOCK_EVENT_XOTUNED))
858 {
859 m_clock_cb.xo_tune_in_progress = false;
860 nrf_clock_event_clear(NRF_CLOCK, NRF_CLOCK_EVENT_XOTUNED);
861 NRFX_LOG_DEBUG("Event: NRF_CLOCK_EVENT_XOTUNED");
862 nrf_clock_int_disable(NRF_CLOCK, NRF_CLOCK_EVENT_XOTUNED);
863 // Enable XOTUNEERROR interrupt to handle situation when XO is out of tune.
864 nrf_clock_event_clear(NRF_CLOCK, NRF_CLOCK_EVENT_XOTUNEERROR);
865 nrf_clock_int_enable(NRF_CLOCK, NRF_CLOCK_INT_XOTUNEERROR_MASK);
866
867 m_clock_cb.event_handler(NRFX_CLOCK_EVT_XO_TUNED);
868 }
869
870 if (nrf_clock_event_check(NRF_CLOCK, NRF_CLOCK_EVENT_XOTUNEERROR) &&
871 nrf_clock_int_enable_check(NRF_CLOCK, NRF_CLOCK_INT_XOTUNEERROR_MASK))
872 {
873 nrf_clock_event_clear(NRF_CLOCK, NRF_CLOCK_EVENT_XOTUNEERROR);
874 NRFX_LOG_DEBUG("Event: NRF_CLOCK_EVENT_XOTUNEERROR");
875 nrf_clock_int_disable(NRF_CLOCK, NRF_CLOCK_INT_XOTUNEERROR_MASK);
876
877 m_clock_cb.event_handler(NRFX_CLOCK_EVT_XO_TUNE_ERROR);
878 }
879
880 if (nrf_clock_event_check(NRF_CLOCK, NRF_CLOCK_EVENT_XOTUNEFAILED))
881 {
882 m_clock_cb.xo_tune_in_progress = false;
883 nrf_clock_event_clear(NRF_CLOCK, NRF_CLOCK_EVENT_XOTUNEFAILED);
884 NRFX_LOG_DEBUG("Event: NRF_CLOCK_EVENT_XOTUNEFAILED");
885 nrf_clock_int_disable(NRF_CLOCK, NRF_CLOCK_EVENT_XOTUNEFAILED);
886
887 m_clock_cb.event_handler(NRFX_CLOCK_EVT_XO_TUNE_FAILED);
888 }
889 #endif
890 }
891
892 #endif // NRFX_CHECK(NRFX_CLOCK_ENABLED)
893