1 /*
2  * Copyright (c) 2024 Nordic Semiconductor ASA
3  * SPDX-License-Identifier: Apache-2.0
4  */
5 
6 #define DT_DRV_COMPAT nordic_nrf_lfclk
7 
8 #include "clock_control_nrf2_common.h"
9 #include <zephyr/devicetree.h>
10 #include <zephyr/drivers/clock_control/nrf_clock_control.h>
11 #include <hal/nrf_bicr.h>
12 #include <nrfs_clock.h>
13 
14 #include <zephyr/logging/log.h>
15 LOG_MODULE_DECLARE(clock_control_nrf2, CONFIG_CLOCK_CONTROL_LOG_LEVEL);
16 
17 BUILD_ASSERT(DT_NUM_INST_STATUS_OKAY(DT_DRV_COMPAT) == 1,
18 	     "multiple instances not supported");
19 
20 #define LFCLK_HFXO_NODE DT_INST_PHANDLE_BY_NAME(0, clocks, hfxo)
21 
22 #define LFCLK_LFLPRC_ACCURACY DT_INST_PROP(0, lflprc_accuracy_ppm)
23 #define LFCLK_LFRC_ACCURACY DT_INST_PROP(0, lfrc_accuracy_ppm)
24 #define LFCLK_HFXO_ACCURACY DT_PROP(LFCLK_HFXO_NODE, accuracy_ppm)
25 
26 #define LFCLK_MAX_OPTS 5
27 #define LFCLK_DEF_OPTS 3
28 
29 #define NRFS_CLOCK_TIMEOUT K_MSEC(CONFIG_CLOCK_CONTROL_NRF2_NRFS_CLOCK_TIMEOUT_MS)
30 
31 #define BICR (NRF_BICR_Type *)DT_REG_ADDR(DT_NODELABEL(bicr))
32 
33 /* Clock options sorted from lowest to highest accuracy/precision */
34 static struct clock_options {
35 	uint16_t accuracy : 15;
36 	uint16_t precision : 1;
37 	nrfs_clock_src_t src;
38 } clock_options[LFCLK_MAX_OPTS] = {
39 	{
40 		.accuracy = LFCLK_LFLPRC_ACCURACY,
41 		.precision = 0,
42 		.src = NRFS_CLOCK_SRC_LFCLK_LFLPRC,
43 	},
44 	{
45 		.accuracy = LFCLK_LFRC_ACCURACY,
46 		.precision = 0,
47 		.src = NRFS_CLOCK_SRC_LFCLK_LFRC,
48 	},
49 	{
50 		/* NRFS will request FLL16M use HFXO in bypass mode if SYNTH src is used */
51 		.accuracy = LFCLK_HFXO_ACCURACY,
52 		.precision = 1,
53 		.src = NRFS_CLOCK_SRC_LFCLK_SYNTH,
54 	},
55 };
56 
57 struct lfclk_dev_data {
58 	STRUCT_CLOCK_CONFIG(lfclk, ARRAY_SIZE(clock_options)) clk_cfg;
59 	struct k_timer timer;
60 	uint16_t max_accuracy;
61 	uint8_t clock_options_cnt;
62 };
63 
64 struct lfclk_dev_config {
65 	uint32_t fixed_frequency;
66 };
67 
clock_evt_handler(nrfs_clock_evt_t const * p_evt,void * context)68 static void clock_evt_handler(nrfs_clock_evt_t const *p_evt, void *context)
69 {
70 	struct lfclk_dev_data *dev_data = context;
71 	int status = 0;
72 
73 	k_timer_stop(&dev_data->timer);
74 
75 	if (p_evt->type == NRFS_CLOCK_EVT_REJECT) {
76 		status = -ENXIO;
77 	}
78 
79 	clock_config_update_end(&dev_data->clk_cfg, status);
80 }
81 
lfclk_update_timeout_handler(struct k_timer * timer)82 static void lfclk_update_timeout_handler(struct k_timer *timer)
83 {
84 	struct lfclk_dev_data *dev_data =
85 		CONTAINER_OF(timer, struct lfclk_dev_data, timer);
86 
87 	clock_config_update_end(&dev_data->clk_cfg, -ETIMEDOUT);
88 }
89 
lfclk_work_handler(struct k_work * work)90 static void lfclk_work_handler(struct k_work *work)
91 {
92 	struct lfclk_dev_data *dev_data =
93 		CONTAINER_OF(work, struct lfclk_dev_data, clk_cfg.work);
94 	uint8_t to_activate_idx;
95 	nrfs_err_t err;
96 
97 	to_activate_idx = clock_config_update_begin(work);
98 
99 	err = nrfs_clock_lfclk_src_set(clock_options[to_activate_idx].src,
100 				       dev_data);
101 	if (err != NRFS_SUCCESS) {
102 		clock_config_update_end(&dev_data->clk_cfg, -EIO);
103 	} else {
104 		k_timer_start(&dev_data->timer, NRFS_CLOCK_TIMEOUT, K_NO_WAIT);
105 	}
106 }
107 
lfclk_find_mgr(const struct device * dev,const struct nrf_clock_spec * spec)108 static struct onoff_manager *lfclk_find_mgr(const struct device *dev,
109 					    const struct nrf_clock_spec *spec)
110 {
111 	struct lfclk_dev_data *dev_data = dev->data;
112 	const struct lfclk_dev_config *dev_config = dev->config;
113 	uint16_t accuracy;
114 
115 	if (!spec) {
116 		return &dev_data->clk_cfg.onoff[0].mgr;
117 	}
118 
119 	if (spec->frequency > dev_config->fixed_frequency) {
120 		LOG_ERR("invalid frequency");
121 		return NULL;
122 	}
123 
124 	accuracy = spec->accuracy == NRF_CLOCK_CONTROL_ACCURACY_MAX
125 		 ? dev_data->max_accuracy
126 		 : spec->accuracy;
127 
128 	for (int i = 0; i < dev_data->clock_options_cnt; ++i) {
129 		if ((accuracy &&
130 		     accuracy < clock_options[i].accuracy) ||
131 		    spec->precision > clock_options[i].precision) {
132 			continue;
133 		}
134 
135 		return &dev_data->clk_cfg.onoff[i].mgr;
136 	}
137 
138 	LOG_ERR("invalid accuracy or precision");
139 	return NULL;
140 }
141 
api_request_lfclk(const struct device * dev,const struct nrf_clock_spec * spec,struct onoff_client * cli)142 static int api_request_lfclk(const struct device *dev,
143 			     const struct nrf_clock_spec *spec,
144 			     struct onoff_client *cli)
145 {
146 	struct onoff_manager *mgr = lfclk_find_mgr(dev, spec);
147 
148 	if (mgr) {
149 		return onoff_request(mgr, cli);
150 	}
151 
152 	return -EINVAL;
153 }
154 
api_release_lfclk(const struct device * dev,const struct nrf_clock_spec * spec)155 static int api_release_lfclk(const struct device *dev,
156 			     const struct nrf_clock_spec *spec)
157 {
158 	struct onoff_manager *mgr = lfclk_find_mgr(dev, spec);
159 
160 	if (mgr) {
161 		return onoff_release(mgr);
162 	}
163 
164 	return -EINVAL;
165 }
166 
api_cancel_or_release_lfclk(const struct device * dev,const struct nrf_clock_spec * spec,struct onoff_client * cli)167 static int api_cancel_or_release_lfclk(const struct device *dev,
168 				       const struct nrf_clock_spec *spec,
169 				       struct onoff_client *cli)
170 {
171 	struct onoff_manager *mgr = lfclk_find_mgr(dev, spec);
172 
173 	if (mgr) {
174 		return onoff_cancel_or_release(mgr, cli);
175 	}
176 
177 	return -EINVAL;
178 }
179 
api_get_rate_lfclk(const struct device * dev,clock_control_subsys_t sys,uint32_t * rate)180 static int api_get_rate_lfclk(const struct device *dev,
181 			      clock_control_subsys_t sys,
182 			      uint32_t *rate)
183 {
184 	ARG_UNUSED(sys);
185 
186 	const struct lfclk_dev_config *dev_config = dev->config;
187 
188 	*rate = dev_config->fixed_frequency;
189 
190 	return 0;
191 }
192 
lfclk_init(const struct device * dev)193 static int lfclk_init(const struct device *dev)
194 {
195 	struct lfclk_dev_data *dev_data = dev->data;
196 	nrf_bicr_lfosc_mode_t lfosc_mode;
197 	nrfs_err_t res;
198 
199 	res = nrfs_clock_init(clock_evt_handler);
200 	if (res != NRFS_SUCCESS) {
201 		return -EIO;
202 	}
203 
204 	dev_data->clock_options_cnt = LFCLK_DEF_OPTS;
205 
206 	lfosc_mode = nrf_bicr_lfosc_mode_get(BICR);
207 
208 	if (lfosc_mode == NRF_BICR_LFOSC_MODE_UNCONFIGURED ||
209 	    lfosc_mode == NRF_BICR_LFOSC_MODE_DISABLED) {
210 		dev_data->max_accuracy = LFCLK_HFXO_ACCURACY;
211 	} else {
212 		int ret;
213 
214 		ret = lfosc_get_accuracy(&dev_data->max_accuracy);
215 		if (ret < 0) {
216 			LOG_ERR("LFOSC enabled with invalid accuracy");
217 			return ret;
218 		}
219 
220 		switch (lfosc_mode) {
221 		case NRF_BICR_LFOSC_MODE_CRYSTAL:
222 			clock_options[LFCLK_MAX_OPTS - 2].accuracy = dev_data->max_accuracy;
223 			clock_options[LFCLK_MAX_OPTS - 2].precision = 0;
224 			clock_options[LFCLK_MAX_OPTS - 2].src = NRFS_CLOCK_SRC_LFCLK_XO_PIERCE;
225 
226 			clock_options[LFCLK_MAX_OPTS - 1].accuracy = dev_data->max_accuracy;
227 			clock_options[LFCLK_MAX_OPTS - 1].precision = 1;
228 			clock_options[LFCLK_MAX_OPTS - 1].src = NRFS_CLOCK_SRC_LFCLK_XO_PIERCE_HP;
229 
230 			dev_data->clock_options_cnt += 2;
231 			break;
232 		case NRF_BICR_LFOSC_MODE_EXTSINE:
233 			clock_options[LFCLK_MAX_OPTS - 2].accuracy = dev_data->max_accuracy;
234 			clock_options[LFCLK_MAX_OPTS - 2].precision = 0;
235 			clock_options[LFCLK_MAX_OPTS - 2].src = NRFS_CLOCK_SRC_LFCLK_XO_EXT_SINE;
236 
237 			clock_options[LFCLK_MAX_OPTS - 1].accuracy = dev_data->max_accuracy;
238 			clock_options[LFCLK_MAX_OPTS - 1].precision = 1;
239 			clock_options[LFCLK_MAX_OPTS - 1].src = NRFS_CLOCK_SRC_LFCLK_XO_EXT_SINE_HP;
240 
241 			dev_data->clock_options_cnt += 2;
242 			break;
243 		case NRF_BICR_LFOSC_MODE_EXTSQUARE:
244 			clock_options[LFCLK_MAX_OPTS - 2].accuracy = dev_data->max_accuracy;
245 			clock_options[LFCLK_MAX_OPTS - 2].precision = 0;
246 			clock_options[LFCLK_MAX_OPTS - 2].src = NRFS_CLOCK_SRC_LFCLK_XO_EXT_SQUARE;
247 
248 			dev_data->clock_options_cnt += 1;
249 			break;
250 		default:
251 			LOG_ERR("Unexpected LFOSC mode");
252 			return -EINVAL;
253 		}
254 	}
255 
256 	k_timer_init(&dev_data->timer, lfclk_update_timeout_handler, NULL);
257 
258 	return clock_config_init(&dev_data->clk_cfg,
259 				 ARRAY_SIZE(dev_data->clk_cfg.onoff),
260 				 lfclk_work_handler);
261 }
262 
263 static DEVICE_API(nrf_clock_control, lfclk_drv_api) = {
264 	.std_api = {
265 		.on = api_nosys_on_off,
266 		.off = api_nosys_on_off,
267 		.get_rate = api_get_rate_lfclk,
268 	},
269 	.request = api_request_lfclk,
270 	.release = api_release_lfclk,
271 	.cancel_or_release = api_cancel_or_release_lfclk,
272 };
273 
274 static struct lfclk_dev_data lfclk_data;
275 
276 static const struct lfclk_dev_config lfclk_config = {
277 	.fixed_frequency = DT_INST_PROP(0, clock_frequency),
278 };
279 
280 DEVICE_DT_INST_DEFINE(0, lfclk_init, NULL,
281 		      &lfclk_data, &lfclk_config,
282 		      PRE_KERNEL_1, CONFIG_CLOCK_CONTROL_INIT_PRIORITY,
283 		      &lfclk_drv_api);
284