xref: /nrf52832-nimble/nordic/nrfx/drivers/src/nrfx_clock.c (revision 150812a83cab50279bd772ef6db1bfaf255f2c5b)
1 /*
2  * Copyright (c) 2016 - 2018, 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 
38 #define NRFX_LOG_MODULE CLOCK
39 #include <nrfx_log.h>
40 
41 #if NRFX_CHECK(NRFX_POWER_ENABLED)
42 extern bool nrfx_power_irq_enabled;
43 #endif
44 
45 #define EVT_TO_STR(event)                                                     \
46     (event == NRF_CLOCK_EVENT_HFCLKSTARTED ? "NRF_CLOCK_EVENT_HFCLKSTARTED" : \
47     (event == NRF_CLOCK_EVENT_LFCLKSTARTED ? "NRF_CLOCK_EVENT_LFCLKSTARTED" : \
48     (event == NRF_CLOCK_EVENT_DONE         ? "NRF_CLOCK_EVENT_DONE"         : \
49     (event == NRF_CLOCK_EVENT_CTTO         ? "NRF_CLOCK_EVENT_CTTO"         : \
50                                              "UNKNOWN EVENT"))))
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 != CLOCK_LFCLKSRC_SRC_RC)
57         #error "Calibration can be performed only for the RC Oscillator."
58     #endif
59 #endif
60 
61 #if defined(NRF52810_XXAA) || \
62     defined(NRF52832_XXAA) || defined(NRF52832_XXAB) || \
63     defined(NRF52840_XXAA)
64 // Enable workaround for nRF52 anomaly 192 (LFRC oscillator frequency is wrong
65 // after calibration, exceeding 500 ppm).
66 #define USE_WORKAROUND_FOR_ANOMALY_192
67 
68 // Enable workaround for nRF52 anomaly 201 (EVENTS_HFCLKSTARTED might be generated twice).
69 #define USE_WORKAROUND_FOR_ANOMALY_201
70 #endif
71 
72 #if NRFX_CHECK(NRFX_CLOCK_CONFIG_LF_CAL_ENABLED)
73 typedef enum
74 {
75     CAL_STATE_IDLE,
76     CAL_STATE_CAL
77 } nrfx_clock_cal_state_t;
78 #endif
79 
80 /**@brief CLOCK control block. */
81 typedef struct
82 {
83     nrfx_clock_event_handler_t      event_handler;
84     bool                            module_initialized; /*< Indicate the state of module */
85 #if defined(USE_WORKAROUND_FOR_ANOMALY_201)
86     bool                            hfclk_started;      /*< Anomaly 201 workaround. */
87 #endif
88 
89 #if NRFX_CHECK(NRFX_CLOCK_CONFIG_LF_CAL_ENABLED)
90     volatile nrfx_clock_cal_state_t cal_state;
91 #endif
92 } nrfx_clock_cb_t;
93 
94 static nrfx_clock_cb_t m_clock_cb;
95 
96 /**
97  * This variable is used to check whether common POWER_CLOCK common interrupt
98  * should be disabled or not if @ref nrfx_power tries to disable the interrupt.
99  */
100 #if NRFX_CHECK(NRFX_POWER_ENABLED)
101 bool nrfx_clock_irq_enabled;
102 #endif
103 
104 #if defined(NRF52832_XXAA) || defined(NRF52832_XXAB)
105 
106 // ANOMALY 132 - LFCLK needs to avoid frame from 66us to 138us after LFCLK stop. This solution
107 //               applies delay of 138us before starting LFCLK.
108 #define ANOMALY_132_REQ_DELAY_US 138UL
109 
110 // nRF52832 is clocked with 64MHz.
111 #define ANOMALY_132_NRF52832_FREQ_MHZ 64UL
112 
113 // Convert time to cycles.
114 #define ANOMALY_132_DELAY_CYCLES (ANOMALY_132_REQ_DELAY_US * ANOMALY_132_NRF52832_FREQ_MHZ)
115 
116 /**
117  * @brief Function for applying delay of 138us before starting LFCLK.
118  */
nrfx_clock_anomaly_132(void)119 static void nrfx_clock_anomaly_132(void)
120 {
121     uint32_t cyccnt_inital;
122     uint32_t core_debug;
123     uint32_t dwt_ctrl;
124 
125     // Preserve DEMCR register to do not influence into its configuration. Enable the trace and
126     // debug blocks. It is required to read and write data to DWT block.
127     core_debug = CoreDebug->DEMCR;
128     CoreDebug->DEMCR = core_debug | CoreDebug_DEMCR_TRCENA_Msk;
129 
130     // Preserve CTRL register in DWT block to do not influence into its configuration. Make sure
131     // that cycle counter is enabled.
132     dwt_ctrl = DWT->CTRL;
133     DWT->CTRL = dwt_ctrl | DWT_CTRL_CYCCNTENA_Msk;
134 
135     // Store start value of cycle counter.
136     cyccnt_inital = DWT->CYCCNT;
137 
138     // Delay required time.
139     while ((DWT->CYCCNT - cyccnt_inital) < ANOMALY_132_DELAY_CYCLES)
140     {}
141 
142     // Restore preserved registers.
143     DWT->CTRL = dwt_ctrl;
144     CoreDebug->DEMCR = core_debug;
145 }
146 
147 #endif // defined(NRF52832_XXAA) || defined(NRF52832_XXAB)
148 
nrfx_clock_init(nrfx_clock_event_handler_t event_handler)149 nrfx_err_t nrfx_clock_init(nrfx_clock_event_handler_t event_handler)
150 {
151     NRFX_ASSERT(event_handler);
152 
153     nrfx_err_t err_code = NRFX_SUCCESS;
154     if (m_clock_cb.module_initialized)
155     {
156         err_code = NRFX_ERROR_ALREADY_INITIALIZED;
157     }
158     else
159     {
160 #if NRFX_CHECK(NRFX_CLOCK_CONFIG_LF_CAL_ENABLED)
161         m_clock_cb.cal_state = CAL_STATE_IDLE;
162 #endif
163         m_clock_cb.event_handler = event_handler;
164         m_clock_cb.module_initialized = true;
165 #if defined(USE_WORKAROUND_FOR_ANOMALY_201)
166         m_clock_cb.hfclk_started = false;
167 #endif
168     }
169 
170     NRFX_LOG_INFO("Function: %s, error code: %s.", __func__, NRFX_LOG_ERROR_STRING_GET(err_code));
171     return err_code;
172 }
173 
nrfx_clock_enable(void)174 void nrfx_clock_enable(void)
175 {
176     NRFX_ASSERT(m_clock_cb.module_initialized);
177     nrfx_power_clock_irq_init();
178     nrf_clock_lf_src_set((nrf_clock_lfclk_t)NRFX_CLOCK_CONFIG_LF_SRC);
179 
180 #if NRFX_CHECK(NRFX_POWER_ENABLED)
181     nrfx_clock_irq_enabled = true;
182 #endif
183 
184     NRFX_LOG_INFO("Module enabled.");
185 }
186 
nrfx_clock_disable(void)187 void nrfx_clock_disable(void)
188 {
189     NRFX_ASSERT(m_clock_cb.module_initialized);
190 #if NRFX_CHECK(NRFX_POWER_ENABLED)
191     NRFX_ASSERT(nrfx_clock_irq_enabled);
192     if (!nrfx_power_irq_enabled)
193 #endif
194     {
195         NRFX_IRQ_DISABLE(nrfx_get_irq_number(NRF_CLOCK));
196     }
197     nrf_clock_int_disable(CLOCK_INTENSET_HFCLKSTARTED_Msk |
198                           CLOCK_INTENSET_LFCLKSTARTED_Msk |
199 #if NRFX_CHECK(NRFX_CLOCK_CONFIG_LF_CAL_ENABLED)
200                           CLOCK_INTENSET_DONE_Msk |
201                           CLOCK_INTENSET_CTTO_Msk |
202 #endif
203                           0);
204 #if NRFX_CHECK(NRFX_POWER_ENABLED)
205     nrfx_clock_irq_enabled = false;
206 #endif
207     NRFX_LOG_INFO("Module disabled.");
208 }
209 
nrfx_clock_uninit(void)210 void nrfx_clock_uninit(void)
211 {
212     NRFX_ASSERT(m_clock_cb.module_initialized);
213     nrfx_clock_lfclk_stop();
214     nrfx_clock_hfclk_stop();
215     m_clock_cb.module_initialized = false;
216     NRFX_LOG_INFO("Uninitialized.");
217 }
218 
nrfx_clock_lfclk_start(void)219 void nrfx_clock_lfclk_start(void)
220 {
221     NRFX_ASSERT(m_clock_cb.module_initialized);
222     nrf_clock_event_clear(NRF_CLOCK_EVENT_LFCLKSTARTED);
223     nrf_clock_int_enable(NRF_CLOCK_INT_LF_STARTED_MASK);
224 
225 #if defined(NRF52832_XXAA) || defined(NRF52832_XXAB)
226     nrfx_clock_anomaly_132();
227 #endif
228 
229     nrf_clock_task_trigger(NRF_CLOCK_TASK_LFCLKSTART);
230 }
231 
nrfx_clock_lfclk_stop(void)232 void nrfx_clock_lfclk_stop(void)
233 {
234     NRFX_ASSERT(m_clock_cb.module_initialized);
235     nrf_clock_task_trigger(NRF_CLOCK_TASK_LFCLKSTOP);
236     while (nrf_clock_lf_is_running())
237     {}
238 }
239 
nrfx_clock_hfclk_start(void)240 void nrfx_clock_hfclk_start(void)
241 {
242     NRFX_ASSERT(m_clock_cb.module_initialized);
243     nrf_clock_event_clear(NRF_CLOCK_EVENT_HFCLKSTARTED);
244     nrf_clock_int_enable(NRF_CLOCK_INT_HF_STARTED_MASK);
245     nrf_clock_task_trigger(NRF_CLOCK_TASK_HFCLKSTART);
246 }
247 
nrfx_clock_hfclk_stop(void)248 void nrfx_clock_hfclk_stop(void)
249 {
250     NRFX_ASSERT(m_clock_cb.module_initialized);
251     nrf_clock_task_trigger(NRF_CLOCK_TASK_HFCLKSTOP);
252     while (nrf_clock_hf_is_running(NRF_CLOCK_HFCLK_HIGH_ACCURACY))
253     {}
254 #if defined(USE_WORKAROUND_FOR_ANOMALY_201)
255     m_clock_cb.hfclk_started = false;
256 #endif
257 }
258 
nrfx_clock_calibration_start(void)259 nrfx_err_t nrfx_clock_calibration_start(void)
260 {
261     nrfx_err_t err_code = NRFX_SUCCESS;
262 
263 #if NRFX_CHECK(NRFX_CLOCK_CONFIG_LF_CAL_ENABLED)
264     if (nrfx_clock_hfclk_is_running() == false)
265     {
266         return NRFX_ERROR_INVALID_STATE;
267     }
268 
269     if (nrfx_clock_lfclk_is_running() == false)
270     {
271         return NRFX_ERROR_INVALID_STATE;
272     }
273 
274     if (m_clock_cb.cal_state == CAL_STATE_IDLE)
275     {
276         nrf_clock_event_clear(NRF_CLOCK_EVENT_DONE);
277         nrf_clock_int_enable(NRF_CLOCK_INT_DONE_MASK);
278         m_clock_cb.cal_state = CAL_STATE_CAL;
279 #if defined(USE_WORKAROUND_FOR_ANOMALY_192)
280         *(volatile uint32_t *)0x40000C34 = 0x00000002;
281 #endif
282         nrf_clock_task_trigger(NRF_CLOCK_TASK_CAL);
283     }
284     else
285     {
286         err_code = NRFX_ERROR_BUSY;
287     }
288 #endif // NRFX_CHECK(NRFX_CLOCK_CONFIG_LF_CAL_ENABLED)
289 
290     NRFX_LOG_WARNING("Function: %s, error code: %s.",
291                      __func__,
292                      NRFX_LOG_ERROR_STRING_GET(err_code));
293     return err_code;
294 }
295 
nrfx_clock_is_calibrating(void)296 nrfx_err_t nrfx_clock_is_calibrating(void)
297 {
298 #if NRFX_CHECK(NRFX_CLOCK_CONFIG_LF_CAL_ENABLED)
299     if (m_clock_cb.cal_state == CAL_STATE_CAL)
300     {
301         return NRFX_ERROR_BUSY;
302     }
303 #endif
304     return NRFX_SUCCESS;
305 }
306 
nrfx_clock_calibration_timer_start(uint8_t interval)307 void nrfx_clock_calibration_timer_start(uint8_t interval)
308 {
309 #if NRFX_CHECK(NRFX_CLOCK_CONFIG_LF_CAL_ENABLED)
310     nrf_clock_cal_timer_timeout_set(interval);
311     nrf_clock_event_clear(NRF_CLOCK_EVENT_CTTO);
312     nrf_clock_int_enable(NRF_CLOCK_INT_CTTO_MASK);
313     nrf_clock_task_trigger(NRF_CLOCK_TASK_CTSTART);
314 #endif
315 }
316 
nrfx_clock_calibration_timer_stop(void)317 void nrfx_clock_calibration_timer_stop(void)
318 {
319 #if NRFX_CHECK(NRFX_CLOCK_CONFIG_LF_CAL_ENABLED)
320     nrf_clock_int_disable(NRF_CLOCK_INT_CTTO_MASK);
321     nrf_clock_task_trigger(NRF_CLOCK_TASK_CTSTOP);
322 #endif
323 }
324 
nrfx_clock_irq_handler(void)325 void nrfx_clock_irq_handler(void)
326 {
327     if (nrf_clock_event_check(NRF_CLOCK_EVENT_HFCLKSTARTED))
328     {
329         nrf_clock_event_clear(NRF_CLOCK_EVENT_HFCLKSTARTED);
330         NRFX_LOG_DEBUG("Event: %s.", EVT_TO_STR(NRF_CLOCK_EVENT_HFCLKSTARTED));
331         nrf_clock_int_disable(NRF_CLOCK_INT_HF_STARTED_MASK);
332 
333 #if defined(USE_WORKAROUND_FOR_ANOMALY_201)
334         if (!m_clock_cb.hfclk_started)
335         {
336             m_clock_cb.hfclk_started = true;
337             m_clock_cb.event_handler(NRFX_CLOCK_EVT_HFCLK_STARTED);
338         }
339 #else
340         m_clock_cb.event_handler(NRFX_CLOCK_EVT_HFCLK_STARTED);
341 #endif
342     }
343     if (nrf_clock_event_check(NRF_CLOCK_EVENT_LFCLKSTARTED))
344     {
345         nrf_clock_event_clear(NRF_CLOCK_EVENT_LFCLKSTARTED);
346         NRFX_LOG_DEBUG("Event: %s.", EVT_TO_STR(NRF_CLOCK_EVENT_LFCLKSTARTED));
347         nrf_clock_int_disable(NRF_CLOCK_INT_LF_STARTED_MASK);
348 
349         m_clock_cb.event_handler(NRFX_CLOCK_EVT_LFCLK_STARTED);
350     }
351 
352 #if NRFX_CHECK(NRFX_CLOCK_CONFIG_LF_CAL_ENABLED)
353     if (nrf_clock_event_check(NRF_CLOCK_EVENT_CTTO))
354     {
355         nrf_clock_event_clear(NRF_CLOCK_EVENT_CTTO);
356         NRFX_LOG_DEBUG("Event: %s.", EVT_TO_STR(NRF_CLOCK_EVENT_CTTO));
357         nrf_clock_int_disable(NRF_CLOCK_INT_CTTO_MASK);
358 
359         m_clock_cb.event_handler(NRFX_CLOCK_EVT_CTTO);
360     }
361 
362     if (nrf_clock_event_check(NRF_CLOCK_EVENT_DONE))
363     {
364 #if defined(USE_WORKAROUND_FOR_ANOMALY_192)
365         *(volatile uint32_t *)0x40000C34 = 0x00000000;
366 #endif
367         nrf_clock_event_clear(NRF_CLOCK_EVENT_DONE);
368         NRFX_LOG_DEBUG("Event: %s.", EVT_TO_STR(NRF_CLOCK_EVENT_DONE));
369         nrf_clock_int_disable(NRF_CLOCK_INT_DONE_MASK);
370         m_clock_cb.cal_state = CAL_STATE_IDLE;
371         m_clock_cb.event_handler(NRFX_CLOCK_EVT_CAL_DONE);
372     }
373 #endif //  NRFX_CHECK(NRFX_CLOCK_CONFIG_LF_CAL_ENABLED)
374 }
375 
376 #endif // NRFX_CHECK(NRFX_CLOCK_ENABLED)
377