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