1 /*
2  * Copyright (c) 2016 - 2020, Nordic Semiconductor ASA
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions are met:
7  *
8  * 1. Redistributions of source code must retain the above copyright notice, this
9  *    list of conditions and the following disclaimer.
10  *
11  * 2. Redistributions in binary form must reproduce the above copyright
12  *    notice, this list of conditions and the following disclaimer in the
13  *    documentation and/or other materials provided with the distribution.
14  *
15  * 3. Neither the name of the copyright holder nor the names of its
16  *    contributors may be used to endorse or promote products derived from this
17  *    software without specific prior written permission.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
20  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
23  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29  * POSSIBILITY OF SUCH DAMAGE.
30  */
31 
32 #include <nrfx.h>
33 
34 #if NRFX_CHECK(NRFX_CLOCK_ENABLED)
35 
36 #include <nrfx_clock.h>
37 #include <nrf_erratas.h>
38 
39 #define NRFX_LOG_MODULE CLOCK
40 #include <nrfx_log.h>
41 
42 #if NRFX_CHECK(NRFX_POWER_ENABLED)
43 extern bool nrfx_power_irq_enabled;
44 #endif
45 
46 #if defined(CLOCK_LFCLKSRC_SRC_RC) || defined(__NRFX_DOXYGEN__)
47     #define LF_SRC_RC CLOCK_LFCLKSRC_SRC_RC
48 #else
49     #define LF_SRC_RC CLOCK_LFCLKSRC_SRC_LFRC
50 #endif
51 
52 #if NRFX_CHECK(NRFX_CLOCK_CONFIG_LF_CAL_ENABLED)
53     #if (NRF_CLOCK_HAS_CALIBRATION == 0)
54         #error "Calibration is not available in the SoC that is used."
55     #endif
56     #if (NRFX_CLOCK_CONFIG_LF_SRC != LF_SRC_RC)
57         #error "Calibration can be performed only for the RC Oscillator."
58     #endif
59 #endif
60 
61 #if !defined(USE_WORKAROUND_FOR_ANOMALY_132) && \
62     (defined(NRF52832_XXAA) || defined(NRF52832_XXAB))
63     // ANOMALY 132 - LFCLK needs to avoid frame from 66us to 138us after LFCLK stop. This solution
64     //               applies delay of 138us before starting LFCLK.
65     #define USE_WORKAROUND_FOR_ANOMALY_132 1
66 
67     // Convert time to cycles (nRF52832 is clocked with 64 MHz, use delay of 138 us).
68     #define ANOMALY_132_DELAY_CYCLES (64UL * 138)
69 #endif
70 
71 #if !defined(USE_WORKAROUND_FOR_ANOMALY_192) && \
72     (defined(NRF52810_XXAA) || \
73      defined(NRF52832_XXAA) || defined(NRF52832_XXAB) || \
74      defined(NRF52840_XXAA))
75     // Enable workaround for nRF52 anomaly 192 (LFRC oscillator frequency is wrong
76     // after calibration, exceeding 500 ppm).
77     #define USE_WORKAROUND_FOR_ANOMALY_192 1
78 #endif
79 
80 #if !defined(USE_WORKAROUND_FOR_ANOMALY_201) && \
81     (defined(NRF52810_XXAA) || \
82      defined(NRF52832_XXAA) || defined(NRF52832_XXAB) || \
83      defined(NRF52840_XXAA))
84     // Enable workaround for nRF52 anomaly 201 (EVENTS_HFCLKSTARTED might be generated twice).
85     #define USE_WORKAROUND_FOR_ANOMALY_201 1
86 #endif
87 
88 #if defined(CLOCK_LFCLKSRC_SRC_Xtal)
89     #define LF_SRC_LFXO CLOCK_LFCLKSRC_SRC_Xtal
90 #else
91     #define LF_SRC_LFXO CLOCK_LFCLKSRC_SRC_LFXO
92 #endif
93 
94 #if defined(NRF_CLOCK_USE_EXTERNAL_LFCLK_SOURCES)
95     #define LF_SRC_XTAL_LOW  (CLOCK_LFCLKSRC_SRC_Xtal | \
96                              (CLOCK_LFCLKSRC_EXTERNAL_Enabled << CLOCK_LFCLKSRC_EXTERNAL_Pos))
97     #define LF_SRC_XTAL_FULL (CLOCK_LFCLKSRC_SRC_Xtal | \
98                              (CLOCK_LFCLKSRC_BYPASS_Enabled   << CLOCK_LFCLKSRC_BYPASS_Pos) | \
99                              (CLOCK_LFCLKSRC_EXTERNAL_Enabled << CLOCK_LFCLKSRC_EXTERNAL_Pos))
100 #else
101     #define LF_SRC_XTAL_LOW  LF_SRC_LFXO
102     #define LF_SRC_XTAL_FULL LF_SRC_LFXO
103 #endif
104 
105 #if NRFX_CHECK(NRFX_CLOCK_CONFIG_LFXO_TWO_STAGE_ENABLED) && \
106     NRFX_CLOCK_CONFIG_LF_SRC != LF_SRC_LFXO && \
107     NRFX_CLOCK_CONFIG_LF_SRC != LF_SRC_XTAL_LOW && \
108     NRFX_CLOCK_CONFIG_LF_SRC != LF_SRC_XTAL_FULL
109     #error "Two-stage LFXO start procedure enabled but LFCLK source is not set to LFXO!"
110 #endif
111 
112 #if NRFX_CHECK(NRFX_CLOCK_CONFIG_LF_CAL_ENABLED)
113 typedef enum
114 {
115     CAL_STATE_IDLE,
116     CAL_STATE_CAL
117 } nrfx_clock_cal_state_t;
118 #endif
119 
120 /**@brief CLOCK control block. */
121 typedef struct
122 {
123     nrfx_clock_event_handler_t      event_handler;
124     bool                            module_initialized; /*< Indicate the state of module */
125 #if NRFX_CHECK(USE_WORKAROUND_FOR_ANOMALY_201)
126     bool                            hfclk_started;      /*< Anomaly 201 workaround. */
127 #endif
128 
129 #if NRFX_CHECK(NRFX_CLOCK_CONFIG_LF_CAL_ENABLED)
130     volatile nrfx_clock_cal_state_t cal_state;
131 #endif
132 } nrfx_clock_cb_t;
133 
134 static nrfx_clock_cb_t m_clock_cb;
135 
136 /**
137  * This variable is used to check whether common POWER_CLOCK common interrupt
138  * should be disabled or not if @ref nrfx_power tries to disable the interrupt.
139  */
140 #if NRFX_CHECK(NRFX_POWER_ENABLED)
141 bool nrfx_clock_irq_enabled;
142 #endif
143 
144 #if NRFX_CHECK(USE_WORKAROUND_FOR_ANOMALY_132)
145 /**
146  * @brief Function for applying delay of 138us before starting LFCLK.
147  */
nrfx_clock_anomaly_132(void)148 static void nrfx_clock_anomaly_132(void)
149 {
150     uint32_t cyccnt_inital;
151     uint32_t core_debug;
152     uint32_t dwt_ctrl;
153 
154     // Preserve DEMCR register to do not influence into its configuration. Enable the trace and
155     // debug blocks. It is required to read and write data to DWT block.
156     core_debug = CoreDebug->DEMCR;
157     CoreDebug->DEMCR = core_debug | CoreDebug_DEMCR_TRCENA_Msk;
158 
159     // Preserve CTRL register in DWT block to do not influence into its configuration. Make sure
160     // that cycle counter is enabled.
161     dwt_ctrl = DWT->CTRL;
162     DWT->CTRL = dwt_ctrl | DWT_CTRL_CYCCNTENA_Msk;
163 
164     // Store start value of cycle counter.
165     cyccnt_inital = DWT->CYCCNT;
166 
167     // Delay required time.
168     while ((DWT->CYCCNT - cyccnt_inital) < ANOMALY_132_DELAY_CYCLES)
169     {}
170 
171     // Restore preserved registers.
172     DWT->CTRL = dwt_ctrl;
173     CoreDebug->DEMCR = core_debug;
174 }
175 #endif // NRFX_CHECK(USE_WORKAROUND_FOR_ANOMALY_132)
176 
nrfx_clock_init(nrfx_clock_event_handler_t event_handler)177 nrfx_err_t nrfx_clock_init(nrfx_clock_event_handler_t event_handler)
178 {
179     NRFX_ASSERT(event_handler);
180 
181     nrfx_err_t err_code = NRFX_SUCCESS;
182     if (m_clock_cb.module_initialized)
183     {
184         err_code = NRFX_ERROR_ALREADY_INITIALIZED;
185     }
186     else
187     {
188 #if NRFX_CHECK(NRFX_CLOCK_CONFIG_LF_CAL_ENABLED)
189         m_clock_cb.cal_state = CAL_STATE_IDLE;
190 #endif
191         m_clock_cb.event_handler = event_handler;
192         m_clock_cb.module_initialized = true;
193 #if NRFX_CHECK(USE_WORKAROUND_FOR_ANOMALY_201)
194         m_clock_cb.hfclk_started = false;
195 #endif
196     }
197 
198     NRFX_LOG_INFO("Function: %s, error code: %s.", __func__, NRFX_LOG_ERROR_STRING_GET(err_code));
199     return err_code;
200 }
201 
nrfx_clock_enable(void)202 void nrfx_clock_enable(void)
203 {
204     NRFX_ASSERT(m_clock_cb.module_initialized);
205     nrfx_power_clock_irq_init();
206 #if !NRFX_CHECK(NRFX_CLOCK_CONFIG_LFXO_TWO_STAGE_ENABLED)
207     nrf_clock_lf_src_set(NRF_CLOCK, (nrf_clock_lfclk_t)NRFX_CLOCK_CONFIG_LF_SRC);
208 #endif
209 #if NRF_CLOCK_HAS_HFCLKSRC
210     nrf_clock_hf_src_set(NRF_CLOCK, NRF_CLOCK_HFCLK_HIGH_ACCURACY);
211 #endif
212 #if NRF_CLOCK_HAS_HFCLK192M
213     nrf_clock_hfclk192m_src_set(NRF_CLOCK, (nrf_clock_hfclk_t)NRFX_CLOCK_CONFIG_HFCLK192M_SRC);
214 #endif
215 #if NRFX_CHECK(NRFX_POWER_ENABLED)
216     nrfx_clock_irq_enabled = true;
217 #endif
218 
219     NRFX_LOG_INFO("Module enabled.");
220 }
221 
nrfx_clock_disable(void)222 void nrfx_clock_disable(void)
223 {
224     NRFX_ASSERT(m_clock_cb.module_initialized);
225 #if NRFX_CHECK(NRFX_POWER_ENABLED)
226     NRFX_ASSERT(nrfx_clock_irq_enabled);
227     if (!nrfx_power_irq_enabled)
228 #endif
229     {
230         NRFX_IRQ_DISABLE(nrfx_get_irq_number(NRF_CLOCK));
231     }
232     nrf_clock_int_disable(NRF_CLOCK, CLOCK_INTENSET_HFCLKSTARTED_Msk |
233                                      CLOCK_INTENSET_LFCLKSTARTED_Msk |
234 #if NRFX_CHECK(NRFX_CLOCK_CONFIG_LF_CAL_ENABLED)
235                                      CLOCK_INTENSET_DONE_Msk |
236 #if NRF_HAS_CALIBRATION_TIMER
237                                      CLOCK_INTENSET_CTTO_Msk |
238 #endif
239 #endif // NRFX_CHECK(NRFX_CLOCK_CONFIG_LF_CAL_ENABLED)
240                           0);
241 #if NRFX_CHECK(NRFX_POWER_ENABLED)
242     nrfx_clock_irq_enabled = false;
243 #endif
244     NRFX_LOG_INFO("Module disabled.");
245 }
246 
nrfx_clock_uninit(void)247 void nrfx_clock_uninit(void)
248 {
249     NRFX_ASSERT(m_clock_cb.module_initialized);
250     nrfx_clock_stop(NRF_CLOCK_DOMAIN_LFCLK);
251     nrfx_clock_stop(NRF_CLOCK_DOMAIN_HFCLK);
252 #if NRF_CLOCK_HAS_HFCLK192M
253     nrfx_clock_stop(NRF_CLOCK_DOMAIN_HFCLK192M);
254 #endif
255 #if NRF_CLOCK_HAS_HFCLKAUDIO
256     nrfx_clock_stop(NRF_CLOCK_DOMAIN_HFCLKAUDIO);
257 #endif
258     m_clock_cb.module_initialized = false;
259     NRFX_LOG_INFO("Uninitialized.");
260 }
261 
nrfx_clock_start(nrf_clock_domain_t domain)262 void nrfx_clock_start(nrf_clock_domain_t domain)
263 {
264     NRFX_ASSERT(m_clock_cb.module_initialized);
265     switch (domain)
266     {
267         case NRF_CLOCK_DOMAIN_LFCLK:
268 #if NRFX_CHECK(NRFX_CLOCK_CONFIG_LFXO_TWO_STAGE_ENABLED)
269             {
270                 nrf_clock_lfclk_t lfclksrc;
271                 if (nrf_clock_is_running(NRF_CLOCK, NRF_CLOCK_DOMAIN_LFCLK, &lfclksrc) &&
272                     lfclksrc == NRFX_CLOCK_CONFIG_LF_SRC)
273                 {
274                     // If the two-stage LFXO procedure has finished already
275                     // use the configured LF clock source.
276                     nrf_clock_lf_src_set(NRF_CLOCK, (nrf_clock_lfclk_t)NRFX_CLOCK_CONFIG_LF_SRC);
277                 }
278                 else
279                 {
280                     // If the two-stage LFXO procedure hasn't started yet
281                     // or the RC stage is in progress,
282                     // use the RC oscillator as LF clock source.
283                     nrf_clock_lf_src_set(NRF_CLOCK, NRF_CLOCK_LFCLK_RC);
284                 }
285             }
286 #endif // NRFX_CHECK(NRFX_CLOCK_CONFIG_LFXO_TWO_STAGE_ENABLED)
287             nrf_clock_event_clear(NRF_CLOCK, NRF_CLOCK_EVENT_LFCLKSTARTED);
288             nrf_clock_int_enable(NRF_CLOCK, NRF_CLOCK_INT_LF_STARTED_MASK);
289 #if NRFX_CHECK(USE_WORKAROUND_FOR_ANOMALY_132)
290             nrfx_clock_anomaly_132();
291 #endif
292             nrf_clock_task_trigger(NRF_CLOCK, NRF_CLOCK_TASK_LFCLKSTART);
293             break;
294         case NRF_CLOCK_DOMAIN_HFCLK:
295             nrf_clock_event_clear(NRF_CLOCK, NRF_CLOCK_EVENT_HFCLKSTARTED);
296             nrf_clock_int_enable(NRF_CLOCK, NRF_CLOCK_INT_HF_STARTED_MASK);
297             nrf_clock_task_trigger(NRF_CLOCK, NRF_CLOCK_TASK_HFCLKSTART);
298             break;
299 #if NRF_CLOCK_HAS_HFCLK192M
300         case NRF_CLOCK_DOMAIN_HFCLK192M:
301             nrf_clock_event_clear(NRF_CLOCK, NRF_CLOCK_EVENT_HFCLK192MSTARTED);
302             nrf_clock_int_enable(NRF_CLOCK, NRF_CLOCK_INT_HF192M_STARTED_MASK);
303             nrf_clock_task_trigger(NRF_CLOCK, NRF_CLOCK_TASK_HFCLK192MSTART);
304             break;
305 #endif
306 #if NRF_CLOCK_HAS_HFCLKAUDIO
307         case NRF_CLOCK_DOMAIN_HFCLKAUDIO:
308             nrf_clock_event_clear(NRF_CLOCK, NRF_CLOCK_EVENT_HFCLKAUDIOSTARTED);
309             nrf_clock_int_enable(NRF_CLOCK, NRF_CLOCK_INT_HFAUDIO_STARTED_MASK);
310             nrf_clock_task_trigger(NRF_CLOCK, NRF_CLOCK_TASK_HFCLKAUDIOSTART);
311             break;
312 #endif
313         default:
314             NRFX_ASSERT(0);
315             break;
316     }
317 }
318 
nrfx_clock_stop(nrf_clock_domain_t domain)319 void nrfx_clock_stop(nrf_clock_domain_t domain)
320 {
321     NRFX_ASSERT(m_clock_cb.module_initialized);
322     switch (domain)
323     {
324         case NRF_CLOCK_DOMAIN_LFCLK:
325             nrf_clock_int_disable(NRF_CLOCK, NRF_CLOCK_INT_LF_STARTED_MASK);
326             nrf_clock_event_clear(NRF_CLOCK, NRF_CLOCK_EVENT_LFCLKSTARTED);
327             nrf_clock_task_trigger(NRF_CLOCK, NRF_CLOCK_TASK_LFCLKSTOP);
328             break;
329         case NRF_CLOCK_DOMAIN_HFCLK:
330             nrf_clock_int_disable(NRF_CLOCK, NRF_CLOCK_INT_HF_STARTED_MASK);
331             nrf_clock_event_clear(NRF_CLOCK, NRF_CLOCK_EVENT_HFCLKSTARTED);
332             nrf_clock_task_trigger(NRF_CLOCK, NRF_CLOCK_TASK_HFCLKSTOP);
333             break;
334 #if NRF_CLOCK_HAS_HFCLK192M
335         case NRF_CLOCK_DOMAIN_HFCLK192M:
336             nrf_clock_int_disable(NRF_CLOCK, NRF_CLOCK_INT_HF192M_STARTED_MASK);
337             nrf_clock_event_clear(NRF_CLOCK, NRF_CLOCK_EVENT_HFCLK192MSTARTED);
338             nrf_clock_task_trigger(NRF_CLOCK, NRF_CLOCK_TASK_HFCLK192MSTOP);
339             break;
340 #endif
341 #if NRF_CLOCK_HAS_HFCLKAUDIO
342         case NRF_CLOCK_DOMAIN_HFCLKAUDIO:
343             nrf_clock_int_disable(NRF_CLOCK, NRF_CLOCK_INT_HFAUDIO_STARTED_MASK);
344             nrf_clock_event_clear(NRF_CLOCK, NRF_CLOCK_EVENT_HFCLKAUDIOSTARTED);
345             nrf_clock_task_trigger(NRF_CLOCK, NRF_CLOCK_TASK_HFCLKAUDIOSTOP);
346             break;
347 #endif
348         default:
349             NRFX_ASSERT(0);
350             return;
351     }
352 
353     bool stopped;
354     if (domain == NRF_CLOCK_DOMAIN_HFCLK)
355     {
356         nrf_clock_hfclk_t clk_src = NRF_CLOCK_HFCLK_HIGH_ACCURACY;
357         NRFX_WAIT_FOR((!nrfx_clock_is_running(domain, &clk_src) ||
358                        (clk_src != NRF_CLOCK_HFCLK_HIGH_ACCURACY)), 10000, 1, stopped);
359     }
360     else
361     {
362         NRFX_WAIT_FOR(!nrfx_clock_is_running(domain, NULL), 10000, 1, stopped);
363     }
364 
365     if (!stopped)
366     {
367         NRFX_LOG_ERROR("Failed to stop clock domain: %d.", domain);
368     }
369 
370 #if NRFX_CHECK(USE_WORKAROUND_FOR_ANOMALY_201)
371     if (domain == NRF_CLOCK_DOMAIN_HFCLK)
372     {
373             m_clock_cb.hfclk_started = false;
374     }
375 #endif
376 }
377 
nrfx_clock_calibration_start(void)378 nrfx_err_t nrfx_clock_calibration_start(void)
379 {
380     nrfx_err_t err_code = NRFX_SUCCESS;
381 
382 #if NRFX_CHECK(NRFX_CLOCK_CONFIG_LF_CAL_ENABLED)
383     nrf_clock_hfclk_t clk_src;
384     if (!nrfx_clock_is_running(NRF_CLOCK_DOMAIN_HFCLK, &clk_src))
385     {
386         return NRFX_ERROR_INVALID_STATE;
387     }
388 
389     if (clk_src != NRF_CLOCK_HFCLK_HIGH_ACCURACY)
390     {
391         return NRFX_ERROR_INVALID_STATE;
392     }
393 
394     if (!nrfx_clock_is_running(NRF_CLOCK_DOMAIN_LFCLK, NULL))
395     {
396         return NRFX_ERROR_INVALID_STATE;
397     }
398 
399     if (m_clock_cb.cal_state == CAL_STATE_IDLE)
400     {
401         nrf_clock_event_clear(NRF_CLOCK, NRF_CLOCK_EVENT_DONE);
402         nrf_clock_int_enable(NRF_CLOCK, NRF_CLOCK_INT_DONE_MASK);
403         m_clock_cb.cal_state = CAL_STATE_CAL;
404 #if NRFX_CHECK(USE_WORKAROUND_FOR_ANOMALY_192)
405         *(volatile uint32_t *)0x40000C34 = 0x00000002;
406 #endif
407         nrf_clock_task_trigger(NRF_CLOCK, NRF_CLOCK_TASK_CAL);
408     }
409     else
410     {
411         err_code = NRFX_ERROR_BUSY;
412     }
413 #endif // NRFX_CHECK(NRFX_CLOCK_CONFIG_LF_CAL_ENABLED)
414 
415     NRFX_LOG_WARNING("Function: %s, error code: %s.",
416                      __func__,
417                      NRFX_LOG_ERROR_STRING_GET(err_code));
418     return err_code;
419 }
420 
nrfx_clock_is_calibrating(void)421 nrfx_err_t nrfx_clock_is_calibrating(void)
422 {
423 #if NRFX_CHECK(NRFX_CLOCK_CONFIG_LF_CAL_ENABLED)
424     if (m_clock_cb.cal_state == CAL_STATE_CAL)
425     {
426         return NRFX_ERROR_BUSY;
427     }
428 #endif
429     return NRFX_SUCCESS;
430 }
431 
nrfx_clock_calibration_timer_start(uint8_t interval)432 void nrfx_clock_calibration_timer_start(uint8_t interval)
433 {
434 #if NRFX_CHECK(NRFX_CLOCK_CONFIG_LF_CAL_ENABLED) && NRF_CLOCK_HAS_CALIBRATION_TIMER
435     nrf_clock_cal_timer_timeout_set(NRF_CLOCK, interval);
436     nrf_clock_event_clear(NRF_CLOCK, NRF_CLOCK_EVENT_CTTO);
437     nrf_clock_int_enable(NRF_CLOCK, NRF_CLOCK_INT_CTTO_MASK);
438     nrf_clock_task_trigger(NRF_CLOCK, NRF_CLOCK_TASK_CTSTART);
439 #endif
440 }
441 
nrfx_clock_calibration_timer_stop(void)442 void nrfx_clock_calibration_timer_stop(void)
443 {
444 #if NRFX_CHECK(NRFX_CLOCK_CONFIG_LF_CAL_ENABLED) && NRF_CLOCK_HAS_CALIBRATION_TIMER
445     nrf_clock_int_disable(NRF_CLOCK, NRF_CLOCK_INT_CTTO_MASK);
446     nrf_clock_task_trigger(NRF_CLOCK, NRF_CLOCK_TASK_CTSTOP);
447 #endif
448 }
449 
450 #if NRF_CLOCK_HAS_HFCLK_DIV || NRF_CLOCK_HAS_HFCLK192M
nrfx_clock_divider_set(nrf_clock_domain_t domain,nrf_clock_hfclk_div_t div)451 nrfx_err_t nrfx_clock_divider_set(nrf_clock_domain_t domain,
452                                   nrf_clock_hfclk_div_t div)
453 {
454     switch(domain)
455     {
456 #if NRF_CLOCK_HAS_HFCLK_DIV
457         case NRF_CLOCK_DOMAIN_HFCLK:
458             switch (div)
459             {
460                 case NRF_CLOCK_HFCLK_DIV_2:
461                     NRFX_CRITICAL_SECTION_ENTER();
462                     if (nrf53_errata_4())
463                     {
464                         __DSB();
465                     }
466                     nrf_clock_hfclk_div_set(NRF_CLOCK, div);
467                     if (nrf53_errata_4())
468                     {
469                         *(volatile uint32_t *)0x5084450C = 0x0;
470                         *(volatile uint32_t *)0x50026548 = 0x0;
471                         *(volatile uint32_t *)0x50081EE4 = 0x0D;
472                     }
473                     NRFX_CRITICAL_SECTION_EXIT();
474                     break;
475                 case NRF_CLOCK_HFCLK_DIV_1:
476                     NRFX_CRITICAL_SECTION_ENTER();
477                     if (nrf53_errata_4())
478                     {
479                         __DSB();
480                         *(volatile uint32_t *)0x5084450C = 0x4040;
481                         *(volatile uint32_t *)0x50026548 = 0x40;
482                         *(volatile uint32_t *)0x50081EE4 = 0x4D;
483                     }
484                     nrf_clock_hfclk_div_set(NRF_CLOCK, div);
485                     NRFX_CRITICAL_SECTION_EXIT();
486                     break;
487                 default:
488                     return NRFX_ERROR_INVALID_PARAM;
489             }
490             SystemCoreClockUpdate();
491             return NRFX_SUCCESS;
492 #endif
493 #if NRF_CLOCK_HAS_HFCLK192M
494         case NRF_CLOCK_DOMAIN_HFCLK192M:
495             if (div > NRF_CLOCK_HFCLK_DIV_4)
496             {
497                 return NRFX_ERROR_INVALID_PARAM;
498             }
499             else
500             {
501                 nrf_clock_hfclk192m_div_set(NRF_CLOCK, div);
502             }
503             return NRFX_SUCCESS;
504 #endif
505         default:
506             NRFX_ASSERT(0);
507             return NRFX_ERROR_NOT_SUPPORTED;
508     }
509 }
510 #endif
511 
nrfx_clock_irq_handler(void)512 void nrfx_clock_irq_handler(void)
513 {
514     if (nrf_clock_event_check(NRF_CLOCK, NRF_CLOCK_EVENT_HFCLKSTARTED))
515     {
516         nrf_clock_event_clear(NRF_CLOCK, NRF_CLOCK_EVENT_HFCLKSTARTED);
517         NRFX_LOG_DEBUG("Event: NRF_CLOCK_EVENT_HFCLKSTARTED");
518         nrf_clock_int_disable(NRF_CLOCK, NRF_CLOCK_INT_HF_STARTED_MASK);
519 
520 #if NRFX_CHECK(USE_WORKAROUND_FOR_ANOMALY_201)
521         if (!m_clock_cb.hfclk_started)
522         {
523             m_clock_cb.hfclk_started = true;
524             m_clock_cb.event_handler(NRFX_CLOCK_EVT_HFCLK_STARTED);
525         }
526 #else
527         m_clock_cb.event_handler(NRFX_CLOCK_EVT_HFCLK_STARTED);
528 #endif
529     }
530     if (nrf_clock_event_check(NRF_CLOCK, NRF_CLOCK_EVENT_LFCLKSTARTED))
531     {
532         nrf_clock_event_clear(NRF_CLOCK, NRF_CLOCK_EVENT_LFCLKSTARTED);
533         NRFX_LOG_DEBUG("Event: NRF_CLOCK_EVENT_LFCLKSTARTED");
534 
535 #if NRFX_CHECK(NRFX_CLOCK_CONFIG_LFXO_TWO_STAGE_ENABLED)
536         nrf_clock_lfclk_t lfclksrc;
537         (void)nrf_clock_is_running(NRF_CLOCK, NRF_CLOCK_DOMAIN_LFCLK, &lfclksrc);
538         if (lfclksrc == NRF_CLOCK_LFCLK_RC)
539         {
540             // After the LFRC oscillator start switch to external source.
541             nrf_clock_lf_src_set(NRF_CLOCK, (nrf_clock_lfclk_t)NRFX_CLOCK_CONFIG_LF_SRC);
542             nrf_clock_task_trigger(NRF_CLOCK, NRF_CLOCK_TASK_LFCLKSTART);
543         }
544         else
545 #endif
546         {
547             // After the LF clock external source start invoke user callback.
548             nrf_clock_int_disable(NRF_CLOCK, NRF_CLOCK_INT_LF_STARTED_MASK);
549             m_clock_cb.event_handler(NRFX_CLOCK_EVT_LFCLK_STARTED);
550         }
551     }
552 
553 #if NRFX_CHECK(NRFX_CLOCK_CONFIG_LF_CAL_ENABLED)
554 #if NRF_CLOCK_HAS_CALIBRATION_TIMER
555     if (nrf_clock_event_check(NRF_CLOCK, NRF_CLOCK_EVENT_CTTO))
556     {
557         nrf_clock_event_clear(NRF_CLOCK, NRF_CLOCK_EVENT_CTTO);
558         NRFX_LOG_DEBUG("Event: NRF_CLOCK_EVENT_CTTO");
559         nrf_clock_int_disable(NRF_CLOCK, NRF_CLOCK_INT_CTTO_MASK);
560 
561         m_clock_cb.event_handler(NRFX_CLOCK_EVT_CTTO);
562     }
563 #endif // NRF_CLOCK_HAS_CALIBRATION_TIMER
564 
565     if (nrf_clock_event_check(NRF_CLOCK, NRF_CLOCK_EVENT_DONE))
566     {
567 #if NRFX_CHECK(USE_WORKAROUND_FOR_ANOMALY_192)
568         *(volatile uint32_t *)0x40000C34 = 0x00000000;
569 #endif
570         nrf_clock_event_clear(NRF_CLOCK, NRF_CLOCK_EVENT_DONE);
571         NRFX_LOG_DEBUG("Event: NRF_CLOCK_EVENT_DONE");
572         nrf_clock_int_disable(NRF_CLOCK, NRF_CLOCK_INT_DONE_MASK);
573         m_clock_cb.cal_state = CAL_STATE_IDLE;
574         m_clock_cb.event_handler(NRFX_CLOCK_EVT_CAL_DONE);
575     }
576 #endif // NRFX_CHECK(NRFX_CLOCK_CONFIG_LF_CAL_ENABLED)
577 
578 #if NRF_CLOCK_HAS_HFCLKAUDIO
579     if (nrf_clock_event_check(NRF_CLOCK, NRF_CLOCK_EVENT_HFCLKAUDIOSTARTED))
580     {
581         nrf_clock_event_clear(NRF_CLOCK, NRF_CLOCK_EVENT_HFCLKAUDIOSTARTED);
582         NRFX_LOG_DEBUG("Event: NRF_CLOCK_EVENT_HFCLKAUDIOSTARTED");
583         nrf_clock_int_disable(NRF_CLOCK, NRF_CLOCK_INT_HFAUDIO_STARTED_MASK);
584 
585         m_clock_cb.event_handler(NRFX_CLOCK_EVT_HFCLKAUDIO_STARTED);
586     }
587 #endif
588 
589 #if NRF_CLOCK_HAS_HFCLK192M
590     if (nrf_clock_event_check(NRF_CLOCK, NRF_CLOCK_EVENT_HFCLK192MSTARTED))
591     {
592         nrf_clock_event_clear(NRF_CLOCK, NRF_CLOCK_EVENT_HFCLK192MSTARTED);
593         NRFX_LOG_DEBUG("Event: NRF_CLOCK_EVENT_HFCLK192MSTARTED");
594         nrf_clock_int_disable(NRF_CLOCK, NRF_CLOCK_INT_HF192M_STARTED_MASK);
595 
596         m_clock_cb.event_handler(NRFX_CLOCK_EVT_HFCLK192M_STARTED);
597     }
598 #endif
599 }
600 
601 #endif // NRFX_CHECK(NRFX_CLOCK_ENABLED)
602