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