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