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