1 /*
2 * Copyright (c) 2018-2020 Nordic Semiconductor ASA
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6
7 #include <soc.h>
8 #include <zephyr/device.h>
9
10 #include <zephyr/drivers/clock_control.h>
11 #include <zephyr/drivers/clock_control/nrf_clock_control.h>
12
13 #include "hal/debug.h"
14
15 /* Clock setup timeouts are unlikely, below values are experimental */
16 #define LFCLOCK_TIMEOUT_MS 500
17 #define HFCLOCK_TIMEOUT_MS 2
18
19 static uint16_t const sca_ppm_lut[] = {500, 250, 150, 100, 75, 50, 30, 20};
20
21 struct lll_clock_state {
22 struct onoff_client cli;
23 struct k_sem sem;
24 };
25
26 static struct onoff_client lf_cli;
27 static atomic_val_t hf_refcnt;
28
clock_ready(struct onoff_manager * mgr,struct onoff_client * cli,uint32_t state,int res)29 static void clock_ready(struct onoff_manager *mgr, struct onoff_client *cli,
30 uint32_t state, int res)
31 {
32 struct lll_clock_state *clk_state =
33 CONTAINER_OF(cli, struct lll_clock_state, cli);
34
35 k_sem_give(&clk_state->sem);
36 }
37
blocking_on(struct onoff_manager * mgr,uint32_t timeout)38 static int blocking_on(struct onoff_manager *mgr, uint32_t timeout)
39 {
40
41 struct lll_clock_state state;
42 int err;
43
44 k_sem_init(&state.sem, 0, 1);
45 sys_notify_init_callback(&state.cli.notify, clock_ready);
46 err = onoff_request(mgr, &state.cli);
47 if (err < 0) {
48 return err;
49 }
50
51 return k_sem_take(&state.sem, K_MSEC(timeout));
52 }
53
lll_clock_init(void)54 int lll_clock_init(void)
55 {
56 struct onoff_manager *mgr =
57 z_nrf_clock_control_get_onoff(CLOCK_CONTROL_NRF_SUBSYS_LF);
58
59 sys_notify_init_spinwait(&lf_cli.notify);
60
61 return onoff_request(mgr, &lf_cli);
62 }
63
lll_clock_deinit(void)64 int lll_clock_deinit(void)
65 {
66 struct onoff_manager *mgr =
67 z_nrf_clock_control_get_onoff(CLOCK_CONTROL_NRF_SUBSYS_LF);
68
69 /* Cancel any ongoing request */
70 (void)onoff_cancel(mgr, &lf_cli);
71
72 return onoff_release(mgr);
73 }
74
lll_clock_wait(void)75 int lll_clock_wait(void)
76 {
77 struct onoff_manager *mgr;
78 static bool done;
79 int err;
80
81 if (done) {
82 return 0;
83 }
84 done = true;
85
86 mgr = z_nrf_clock_control_get_onoff(CLOCK_CONTROL_NRF_SUBSYS_LF);
87 err = blocking_on(mgr, LFCLOCK_TIMEOUT_MS);
88 if (err) {
89 return err;
90 }
91
92 err = onoff_release(mgr);
93 if (err != ONOFF_STATE_ON) {
94 return -EIO;
95 }
96
97 return 0;
98 }
99
lll_hfclock_on(void)100 int lll_hfclock_on(void)
101 {
102 if (atomic_inc(&hf_refcnt) > 0) {
103 return 0;
104 }
105
106 z_nrf_clock_bt_ctlr_hf_request();
107 DEBUG_RADIO_XTAL(1);
108
109 return 0;
110 }
111
lll_hfclock_on_wait(void)112 int lll_hfclock_on_wait(void)
113 {
114 struct onoff_manager *mgr =
115 z_nrf_clock_control_get_onoff(CLOCK_CONTROL_NRF_SUBSYS_HF);
116 int err;
117
118 atomic_inc(&hf_refcnt);
119
120 err = blocking_on(mgr, HFCLOCK_TIMEOUT_MS);
121 if (err >= 0) {
122 DEBUG_RADIO_XTAL(1);
123 }
124
125 return err;
126 }
127
lll_hfclock_off(void)128 int lll_hfclock_off(void)
129 {
130 if (hf_refcnt < 1) {
131 return -EALREADY;
132 }
133
134 if (atomic_dec(&hf_refcnt) > 1) {
135 return 0;
136 }
137
138 z_nrf_clock_bt_ctlr_hf_release();
139 DEBUG_RADIO_XTAL(0);
140
141 return 0;
142 }
143
lll_clock_sca_local_get(void)144 uint8_t lll_clock_sca_local_get(void)
145 {
146 return CLOCK_CONTROL_NRF_K32SRC_ACCURACY;
147 }
148
lll_clock_ppm_local_get(void)149 uint32_t lll_clock_ppm_local_get(void)
150 {
151 return sca_ppm_lut[CLOCK_CONTROL_NRF_K32SRC_ACCURACY];
152 }
153
lll_clock_ppm_get(uint8_t sca)154 uint32_t lll_clock_ppm_get(uint8_t sca)
155 {
156 return sca_ppm_lut[sca];
157 }
158