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