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