1 /*
2  * Copyright (c) 2024 Nordic Semiconductor ASA
3  * SPDX-License-Identifier: Apache-2.0
4  */
5 
6 #define DT_DRV_COMPAT nordic_nrf54h_hfxo
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 <zephyr/logging/log.h>
12 LOG_MODULE_DECLARE(clock_control_nrf2, CONFIG_CLOCK_CONTROL_LOG_LEVEL);
13 
14 #include <soc_lrcconf.h>
15 #include <hal/nrf_bicr.h>
16 
17 BUILD_ASSERT(DT_NUM_INST_STATUS_OKAY(DT_DRV_COMPAT) == 1,
18 	     "multiple instances not supported");
19 
20 struct dev_data_hfxo {
21 	struct onoff_manager mgr;
22 	onoff_notify_fn notify;
23 	struct k_timer timer;
24 	sys_snode_t hfxo_node;
25 #if defined(CONFIG_ZERO_LATENCY_IRQS)
26 	uint16_t request_count;
27 #endif /* CONFIG_ZERO_LATENCY_IRQS */
28 	k_timeout_t start_up_time;
29 };
30 
31 struct dev_config_hfxo {
32 	uint32_t fixed_frequency;
33 	uint16_t fixed_accuracy;
34 };
35 
36 #define BICR (NRF_BICR_Type *)DT_REG_ADDR(DT_NODELABEL(bicr))
37 
38 #if defined(CONFIG_ZERO_LATENCY_IRQS)
full_irq_lock(void)39 static uint32_t full_irq_lock(void)
40 {
41 	uint32_t mcu_critical_state;
42 
43 	mcu_critical_state = __get_PRIMASK();
44 	__disable_irq();
45 
46 	return mcu_critical_state;
47 }
48 
full_irq_unlock(uint32_t mcu_critical_state)49 static void full_irq_unlock(uint32_t mcu_critical_state)
50 {
51 	__set_PRIMASK(mcu_critical_state);
52 }
53 #endif /* CONFIG_ZERO_LATENCY_IRQS */
54 
hfxo_start_up_timer_handler(struct k_timer * timer)55 static void hfxo_start_up_timer_handler(struct k_timer *timer)
56 {
57 	struct dev_data_hfxo *dev_data =
58 		CONTAINER_OF(timer, struct dev_data_hfxo, timer);
59 
60 	/* In specific cases, the HFXOSTARTED event might not be set even
61 	 * though the HFXO has started (this is a hardware issue that will
62 	 * be fixed). For now, the HFXO is simply assumed to be started
63 	 * after its configured start-up time expires.
64 	 */
65 	LOG_DBG("HFXOSTARTED: %u",
66 		nrf_lrcconf_event_check(NRF_LRCCONF010,
67 					NRF_LRCCONF_EVENT_HFXOSTARTED));
68 
69 	if (dev_data->notify) {
70 		dev_data->notify(&dev_data->mgr, 0);
71 	}
72 }
73 
start_hfxo(struct dev_data_hfxo * dev_data)74 static void start_hfxo(struct dev_data_hfxo *dev_data)
75 {
76 	nrf_lrcconf_event_clear(NRF_LRCCONF010, NRF_LRCCONF_EVENT_HFXOSTARTED);
77 	soc_lrcconf_poweron_request(&dev_data->hfxo_node, NRF_LRCCONF_POWER_MAIN);
78 	nrf_lrcconf_task_trigger(NRF_LRCCONF010, NRF_LRCCONF_TASK_REQHFXO);
79 }
80 
request_hfxo(struct dev_data_hfxo * dev_data)81 static void request_hfxo(struct dev_data_hfxo *dev_data)
82 {
83 #if defined(CONFIG_ZERO_LATENCY_IRQS)
84 	unsigned int key;
85 
86 	key = full_irq_lock();
87 	if (dev_data->request_count == 0) {
88 		start_hfxo(dev_data);
89 	}
90 
91 	dev_data->request_count++;
92 	full_irq_unlock(key);
93 #else
94 	start_hfxo(dev_data);
95 #endif /* CONFIG_ZERO_LATENCY_IRQS */
96 }
97 
98 #if IS_ENABLED(CONFIG_ZERO_LATENCY_IRQS)
nrf_clock_control_hfxo_request(void)99 void nrf_clock_control_hfxo_request(void)
100 {
101 	const struct device *dev = DEVICE_DT_INST_GET(0);
102 	struct dev_data_hfxo *dev_data = dev->data;
103 
104 	request_hfxo(dev_data);
105 }
106 #endif /* CONFIG_ZERO_LATENCY_IRQS */
107 
onoff_start_hfxo(struct onoff_manager * mgr,onoff_notify_fn notify)108 static void onoff_start_hfxo(struct onoff_manager *mgr, onoff_notify_fn notify)
109 {
110 	struct dev_data_hfxo *dev_data =
111 		CONTAINER_OF(mgr, struct dev_data_hfxo, mgr);
112 
113 	dev_data->notify = notify;
114 	request_hfxo(dev_data);
115 
116 	/* Due to a hardware issue, the HFXOSTARTED event is currently
117 	 * unreliable. Hence the timer is used to simply wait the expected
118 	 * start-up time. To be removed once the hardware is fixed.
119 	 */
120 	k_timer_start(&dev_data->timer, dev_data->start_up_time, K_NO_WAIT);
121 }
122 
stop_hfxo(struct dev_data_hfxo * dev_data)123 static void stop_hfxo(struct dev_data_hfxo *dev_data)
124 {
125 	nrf_lrcconf_task_trigger(NRF_LRCCONF010, NRF_LRCCONF_TASK_STOPREQHFXO);
126 	soc_lrcconf_poweron_release(&dev_data->hfxo_node, NRF_LRCCONF_POWER_MAIN);
127 }
128 
release_hfxo(struct dev_data_hfxo * dev_data)129 static void release_hfxo(struct dev_data_hfxo *dev_data)
130 {
131 #if IS_ENABLED(CONFIG_ZERO_LATENCY_IRQS)
132 	unsigned int key;
133 
134 	key = full_irq_lock();
135 	if (dev_data->request_count < 1) {
136 		full_irq_unlock(key);
137 		/* Misuse of the API, release without request? */
138 		__ASSERT_NO_MSG(false);
139 		/* In case asserts are disabled early return due to no requests pending */
140 		return;
141 	}
142 
143 	dev_data->request_count--;
144 	if (dev_data->request_count < 1) {
145 		stop_hfxo(dev_data);
146 	}
147 
148 	full_irq_unlock(key);
149 #else
150 	stop_hfxo(dev_data);
151 #endif /* CONFIG_ZERO_LATENCY_IRQS */
152 }
153 
154 #if IS_ENABLED(CONFIG_ZERO_LATENCY_IRQS)
nrf_clock_control_hfxo_release(void)155 void nrf_clock_control_hfxo_release(void)
156 {
157 	const struct device *dev = DEVICE_DT_INST_GET(0);
158 	struct dev_data_hfxo *dev_data = dev->data;
159 
160 	release_hfxo(dev_data);
161 }
162 #endif /* IS_ENABLED(CONFIG_ZERO_LATENCY_IRQS) */
163 
onoff_stop_hfxo(struct onoff_manager * mgr,onoff_notify_fn notify)164 static void onoff_stop_hfxo(struct onoff_manager *mgr, onoff_notify_fn notify)
165 {
166 	struct dev_data_hfxo *dev_data =
167 		CONTAINER_OF(mgr, struct dev_data_hfxo, mgr);
168 
169 	release_hfxo(dev_data);
170 	notify(mgr, 0);
171 }
172 
is_clock_spec_valid(const struct device * dev,const struct nrf_clock_spec * spec)173 static bool is_clock_spec_valid(const struct device *dev,
174 				const struct nrf_clock_spec *spec)
175 {
176 	const struct dev_config_hfxo *dev_config = dev->config;
177 
178 	if (spec->frequency > dev_config->fixed_frequency) {
179 		LOG_ERR("invalid frequency");
180 		return false;
181 	}
182 
183 	/* Signal an error if an accuracy better than available is requested. */
184 	if (spec->accuracy &&
185 	    spec->accuracy != NRF_CLOCK_CONTROL_ACCURACY_MAX &&
186 	    spec->accuracy < dev_config->fixed_accuracy) {
187 		LOG_ERR("invalid accuracy");
188 		return false;
189 	}
190 
191 	/* Consider HFXO precision high, skip checking what is requested. */
192 
193 	return true;
194 }
195 
api_request_hfxo(const struct device * dev,const struct nrf_clock_spec * spec,struct onoff_client * cli)196 static int api_request_hfxo(const struct device *dev,
197 			    const struct nrf_clock_spec *spec,
198 			    struct onoff_client *cli)
199 {
200 	struct dev_data_hfxo *dev_data = dev->data;
201 
202 	if (spec && !is_clock_spec_valid(dev, spec)) {
203 		return -EINVAL;
204 	}
205 
206 	return onoff_request(&dev_data->mgr, cli);
207 }
208 
api_release_hfxo(const struct device * dev,const struct nrf_clock_spec * spec)209 static int api_release_hfxo(const struct device *dev,
210 			    const struct nrf_clock_spec *spec)
211 {
212 	struct dev_data_hfxo *dev_data = dev->data;
213 
214 	if (spec && !is_clock_spec_valid(dev, spec)) {
215 		return -EINVAL;
216 	}
217 
218 	return onoff_release(&dev_data->mgr);
219 }
220 
api_cancel_or_release_hfxo(const struct device * dev,const struct nrf_clock_spec * spec,struct onoff_client * cli)221 static int api_cancel_or_release_hfxo(const struct device *dev,
222 				      const struct nrf_clock_spec *spec,
223 				      struct onoff_client *cli)
224 {
225 	struct dev_data_hfxo *dev_data = dev->data;
226 
227 	if (spec && !is_clock_spec_valid(dev, spec)) {
228 		return -EINVAL;
229 	}
230 
231 	return onoff_cancel_or_release(&dev_data->mgr, cli);
232 }
233 
api_get_rate_hfxo(const struct device * dev,clock_control_subsys_t sys,uint32_t * rate)234 static int api_get_rate_hfxo(const struct device *dev,
235 			     clock_control_subsys_t sys,
236 			     uint32_t *rate)
237 {
238 	ARG_UNUSED(sys);
239 
240 	const struct dev_config_hfxo *dev_config = dev->config;
241 
242 	*rate = dev_config->fixed_frequency;
243 
244 	return 0;
245 }
246 
init_hfxo(const struct device * dev)247 static int init_hfxo(const struct device *dev)
248 {
249 	struct dev_data_hfxo *dev_data = dev->data;
250 	static const struct onoff_transitions transitions = {
251 		.start = onoff_start_hfxo,
252 		.stop = onoff_stop_hfxo
253 	};
254 	uint32_t start_up_time;
255 	int rc;
256 
257 	rc = onoff_manager_init(&dev_data->mgr, &transitions);
258 	if (rc < 0) {
259 		return rc;
260 	}
261 
262 	start_up_time = nrf_bicr_hfxo_startup_time_us_get(BICR);
263 	if (start_up_time == NRF_BICR_HFXO_STARTUP_TIME_UNCONFIGURED) {
264 		return -EINVAL;
265 	}
266 
267 	dev_data->start_up_time = K_USEC(start_up_time);
268 
269 	k_timer_init(&dev_data->timer, hfxo_start_up_timer_handler, NULL);
270 
271 	return 0;
272 }
273 
274 static DEVICE_API(nrf_clock_control, drv_api_hfxo) = {
275 	.std_api = {
276 		.on = api_nosys_on_off,
277 		.off = api_nosys_on_off,
278 		.get_rate = api_get_rate_hfxo,
279 	},
280 	.request = api_request_hfxo,
281 	.release = api_release_hfxo,
282 	.cancel_or_release = api_cancel_or_release_hfxo,
283 };
284 
285 static struct dev_data_hfxo data_hfxo;
286 
287 static const struct dev_config_hfxo config_hfxo = {
288 	.fixed_frequency = DT_INST_PROP(0, clock_frequency),
289 	.fixed_accuracy = DT_INST_PROP(0, accuracy_ppm),
290 };
291 
292 DEVICE_DT_INST_DEFINE(0, init_hfxo, NULL,
293 		      &data_hfxo, &config_hfxo,
294 		      PRE_KERNEL_1, CONFIG_CLOCK_CONTROL_INIT_PRIORITY,
295 		      &drv_api_hfxo);
296