1 /*
2 * Copyright (c) 2020 Eric Holland
3 *
4 * Use of this source code is governed by a MIT-style
5 * license that can be found in the LICENSE file or at
6 * https://opensource.org/licenses/MIT
7 */
8
9 #include <sys/types.h>
10 #include <lk/err.h>
11 #include <kernel/event.h>
12 #include <nrfx.h>
13 #include <nrfx_clock.h>
14 #include <hal/nrf_clock.h>
15 #include <platform/clock.h>
16
17
18 event_t hf_clk_evt = EVENT_INITIAL_VALUE(hf_clk_evt, false, 0);
19 event_t lf_clk_evt = EVENT_INITIAL_VALUE(lf_clk_evt, false, 0);
20
nrf52_POWER_CLOCK_IRQ(void)21 void nrf52_POWER_CLOCK_IRQ(void) {
22 arm_cm_irq_entry();
23 nrfx_clock_irq_handler();
24 arm_cm_irq_exit(true);
25 }
26
27 // Handler runs in interrupt context
nrf52_clock_handler(nrfx_clock_evt_type_t event)28 void nrf52_clock_handler(nrfx_clock_evt_type_t event) {
29 switch (event) {
30 case NRFX_CLOCK_EVT_HFCLK_STARTED :
31 event_signal(&hf_clk_evt, false);
32 break;
33 case NRFX_CLOCK_EVT_LFCLK_STARTED :
34 event_signal(&lf_clk_evt, false);
35 break;
36 default:
37 break;
38 }
39 }
40
nrf52_clock_init(void)41 status_t nrf52_clock_init(void) {
42 status_t status = nrfx_clock_init(nrf52_clock_handler);
43 if (status == NO_ERROR) {
44 nrfx_clock_enable();
45 }
46 return status;
47 }
48
nrf52_clock_hf_use_xtal_source(void)49 status_t nrf52_clock_hf_use_xtal_source(void) {
50 // Check if already running on hfclk xtal
51 if (nrfx_clock_hfclk_is_running()) {
52 return NO_ERROR;
53 }
54 event_unsignal(&hf_clk_evt);
55 nrfx_clock_hfclk_start();
56 if (event_wait_timeout(&hf_clk_evt, 100) != NO_ERROR) {
57 dprintf(CRITICAL, "Timeout waiting for hf source\n");
58 return ERR_TIMED_OUT;
59 }
60 return NO_ERROR;
61 }
62
63 // Switch to using the internal 64MHz oscillator for HF clock
nrf52_clock_hf_use_internal_source(void)64 void nrf52_clock_hf_use_internal_source(void) {
65 //The clock controller will automatically switch to the internal
66 // oscillator as the source when the external xtal is stopped.
67 // this nrfx function is poorly named as it does not stop the hf clock
68 // but only stops the external xtal oscillator.
69 nrfx_clock_hfclk_stop();
70 }
71
nrf52_clock_lfclk_enable(nrf_clock_lfclk_t src)72 status_t nrf52_clock_lfclk_enable(nrf_clock_lfclk_t src) {
73 if (nrfx_clock_lfclk_is_running()) {
74 nrf_clock_lfclk_t current_src = nrf_clock_lf_actv_src_get(NRF_CLOCK);
75 if (current_src == src) {
76 //Already running on the requested source, do nothing.
77 return NO_ERROR;
78 }
79 // If we make it here, it is running, but not right source, so shut it down to change
80 nrfx_clock_lfclk_stop();
81 }
82 nrf_clock_lf_src_set(NRF_CLOCK, src);
83 event_unsignal(&lf_clk_evt);
84 nrfx_clock_lfclk_start();
85 if (event_wait_timeout(&lf_clk_evt, 100) != NO_ERROR) {
86 dprintf(CRITICAL, "Timeout waiting for lf clock start\n");
87 return ERR_TIMED_OUT;
88 }
89 return NO_ERROR;
90 }
91
92