1 /*
2 * Copyright (c) 2018, Nordic Semiconductor ASA
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6 #include <zephyr/drivers/counter.h>
7 #include <hal/nrf_rtc.h>
8 #ifdef CONFIG_CLOCK_CONTROL_NRF
9 #include <zephyr/drivers/clock_control.h>
10 #include <zephyr/drivers/clock_control/nrf_clock_control.h>
11 #endif
12 #include <haly/nrfy_rtc.h>
13 #include <zephyr/sys/atomic.h>
14 #ifdef DPPI_PRESENT
15 #include <nrfx_dppi.h>
16 #else
17 #include <nrfx_ppi.h>
18 #endif
19
20 #define LOG_MODULE_NAME counter_rtc
21 #include <zephyr/logging/log.h>
22 #include <zephyr/irq.h>
23 LOG_MODULE_REGISTER(LOG_MODULE_NAME, CONFIG_COUNTER_LOG_LEVEL);
24
25 #define ERR(...) LOG_INST_ERR( \
26 ((const struct counter_nrfx_config *)dev->config)->log, __VA_ARGS__)
27 #define WRN(...) LOG_INST_WRN( \
28 ((const struct counter_nrfx_config *)dev->config)->log, __VA_ARGS__)
29 #define INF(...) LOG_INST_INF( \
30 ((const struct counter_nrfx_config *)dev->config)->log, __VA_ARGS__)
31 #define DBG(...) LOG_INST_DBG( \
32 ((const struct counter_nrfx_config *)dev->config)->log, __VA_ARGS__)
33
34 #define DT_DRV_COMPAT nordic_nrf_rtc
35
36 #define COUNTER_GET_TOP_CH(dev) counter_get_num_of_channels(dev)
37
38 #define IS_FIXED_TOP(dev) COND_CODE_1(CONFIG_COUNTER_RTC_CUSTOM_TOP_SUPPORT, \
39 (((const struct counter_nrfx_config *)dev->config)->fixed_top), (true))
40
41 #define IS_PPI_WRAP(dev) COND_CODE_1(CONFIG_COUNTER_RTC_WITH_PPI_WRAP, \
42 (((const struct counter_nrfx_config *)dev->config)->use_ppi), (false))
43
44 #define CC_ADJUSTED_OFFSET 16
45 #define CC_ADJ_MASK(chan) (BIT(chan + CC_ADJUSTED_OFFSET))
46
47 #if defined(CONFIG_SOC_SERIES_BSIM_NRFXX)
48 #define MAYBE_CONST_CONFIG
49 #else
50 #define MAYBE_CONST_CONFIG const
51 #endif
52
53 struct counter_nrfx_data {
54 counter_top_callback_t top_cb;
55 void *top_user_data;
56 uint32_t top;
57 uint32_t guard_period;
58 /* Store channel interrupt pending and CC adjusted flags. */
59 atomic_t ipend_adj;
60 #if CONFIG_COUNTER_RTC_WITH_PPI_WRAP
61 uint8_t ppi_ch;
62 #endif
63 };
64
65 struct counter_nrfx_ch_data {
66 counter_alarm_callback_t callback;
67 void *user_data;
68 };
69
70 struct counter_nrfx_config {
71 struct counter_config_info info;
72 struct counter_nrfx_ch_data *ch_data;
73 NRF_RTC_Type *rtc;
74 #if CONFIG_COUNTER_RTC_WITH_PPI_WRAP
75 bool use_ppi;
76 #endif
77 #if CONFIG_COUNTER_RTC_CUSTOM_TOP_SUPPORT
78 bool fixed_top;
79 #endif
80 LOG_INSTANCE_PTR_DECLARE(log);
81 };
82
start(const struct device * dev)83 static int start(const struct device *dev)
84 {
85 const struct counter_nrfx_config *config = dev->config;
86
87 nrfy_rtc_task_trigger(config->rtc, NRF_RTC_TASK_START);
88
89 return 0;
90 }
91
stop(const struct device * dev)92 static int stop(const struct device *dev)
93 {
94 const struct counter_nrfx_config *config = dev->config;
95
96 nrfy_rtc_task_trigger(config->rtc, NRF_RTC_TASK_STOP);
97
98 return 0;
99 }
100
read(const struct device * dev)101 static uint32_t read(const struct device *dev)
102 {
103 const struct counter_nrfx_config *config = dev->config;
104
105 return nrfy_rtc_counter_get(config->rtc);
106 }
107
get_value(const struct device * dev,uint32_t * ticks)108 static int get_value(const struct device *dev, uint32_t *ticks)
109 {
110 *ticks = read(dev);
111 return 0;
112 }
113
114 /* Function calculates distance between to values assuming that one first
115 * argument is in front and that values wrap.
116 */
ticks_sub(const struct device * dev,uint32_t val,uint32_t old,uint32_t top)117 static uint32_t ticks_sub(const struct device *dev, uint32_t val,
118 uint32_t old, uint32_t top)
119 {
120 if (IS_FIXED_TOP(dev)) {
121 return (val - old) & NRF_RTC_COUNTER_MAX;
122 } else if (likely(IS_BIT_MASK(top))) {
123 return (val - old) & top;
124 }
125
126 /* if top is not 2^n-1 */
127 return (val >= old) ? (val - old) : val + top + 1 - old;
128
129 }
130
skip_zero_on_custom_top(uint32_t val,uint32_t top)131 static uint32_t skip_zero_on_custom_top(uint32_t val, uint32_t top)
132 {
133 /* From Product Specification: If a CC register value is 0 when
134 * a CLEAR task is set, this will not trigger a COMPARE event.
135 */
136 if (unlikely(val == 0) && (top != NRF_RTC_COUNTER_MAX)) {
137 val++;
138 }
139
140 return val;
141 }
142
ticks_add(const struct device * dev,uint32_t val1,uint32_t val2,uint32_t top)143 static uint32_t ticks_add(const struct device *dev, uint32_t val1,
144 uint32_t val2, uint32_t top)
145 {
146 uint32_t sum = val1 + val2;
147
148 if (IS_FIXED_TOP(dev)) {
149 ARG_UNUSED(top);
150 return sum & NRF_RTC_COUNTER_MAX;
151 }
152 if (likely(IS_BIT_MASK(top))) {
153 sum = sum & top;
154 } else {
155 sum = sum > top ? sum - (top + 1) : sum;
156 }
157
158 return skip_zero_on_custom_top(sum, top);
159 }
160
set_cc_int_pending(const struct device * dev,uint8_t chan)161 static void set_cc_int_pending(const struct device *dev, uint8_t chan)
162 {
163 const struct counter_nrfx_config *config = dev->config;
164 struct counter_nrfx_data *data = dev->data;
165
166 atomic_or(&data->ipend_adj, BIT(chan));
167 NRFY_IRQ_PENDING_SET(NRFX_IRQ_NUMBER_GET(config->rtc));
168 }
169
170 /** @brief Handle case when CC value equals COUNTER+1.
171 *
172 * RTC will not generate event if CC value equals COUNTER+1. If such CC is
173 * about to be set then special algorithm is applied. Since counter must not
174 * expire before expected value, CC is set to COUNTER+2. If COUNTER progressed
175 * during that time it means that target value is reached and interrupt is
176 * manually triggered. If not then interrupt is enabled since it is expected
177 * that CC value will generate event.
178 *
179 * Additionally, an information about CC adjustment is stored. This information
180 * is used in the callback to return original CC value which was requested by
181 * the user.
182 */
handle_next_tick_case(const struct device * dev,uint8_t chan,uint32_t now,uint32_t val)183 static void handle_next_tick_case(const struct device *dev, uint8_t chan,
184 uint32_t now, uint32_t val)
185 {
186 const struct counter_nrfx_config *config = dev->config;
187 struct counter_nrfx_data *data = dev->data;
188
189 val = ticks_add(dev, val, 1, data->top);
190 nrfy_rtc_cc_set(config->rtc, chan, val);
191 atomic_or(&data->ipend_adj, CC_ADJ_MASK(chan));
192 if (nrfy_rtc_counter_get(config->rtc) != now) {
193 set_cc_int_pending(dev, chan);
194 } else {
195 nrfy_rtc_int_enable(config->rtc, NRF_RTC_CHANNEL_INT_MASK(chan));
196 }
197 }
198
199 /*
200 * @brief Set COMPARE value with optional too late setting detection.
201 *
202 * Setting CC algorithm takes into account:
203 * - Current COMPARE value written to the register may be close to the current
204 * COUNTER value thus COMPARE event may be generated at any moment
205 * - Next COMPARE value may be soon in the future. Taking into account potential
206 * preemption COMPARE value may be set too late.
207 * - RTC registers are clocked with LF clock (32kHz) and sampled between two
208 * LF ticks.
209 * - Setting COMPARE register to COUNTER+1 does not generate COMPARE event if
210 * done half tick before tick boundary.
211 *
212 * Algorithm assumes that:
213 * - COMPARE interrupt is disabled
214 * - absolute value is taking into account guard period. It means that
215 * it won't be further in future than <top> - <guard_period> from now.
216 *
217 * @param dev Device.
218 * @param chan COMPARE channel.
219 * @param val Value (absolute or relative).
220 * @param flags Alarm flags.
221 *
222 * @retval 0 if COMPARE value was set on time and COMPARE interrupt is expected.
223 * @retval -ETIME if absolute alarm was set too late and error reporting is
224 * enabled.
225 *
226 */
set_cc(const struct device * dev,uint8_t chan,uint32_t val,uint32_t flags)227 static int set_cc(const struct device *dev, uint8_t chan, uint32_t val,
228 uint32_t flags)
229 {
230 const struct counter_nrfx_config *config = dev->config;
231 struct counter_nrfx_data *data = dev->data;
232
233 __ASSERT_NO_MSG(data->guard_period < data->top);
234 NRF_RTC_Type *rtc = config->rtc;
235 nrf_rtc_event_t evt;
236 uint32_t prev_val;
237 uint32_t top;
238 uint32_t now;
239 uint32_t diff;
240 uint32_t int_mask = NRF_RTC_CHANNEL_INT_MASK(chan);
241 int err = 0;
242 uint32_t max_rel_val;
243 bool absolute = flags & COUNTER_ALARM_CFG_ABSOLUTE;
244 bool irq_on_late;
245
246 __ASSERT(nrf_rtc_int_enable_check(rtc, int_mask) == 0,
247 "Expected that CC interrupt is disabled.");
248
249 evt = NRF_RTC_CHANNEL_EVENT_ADDR(chan);
250 top = data->top;
251 now = nrfy_rtc_counter_get(rtc);
252
253 /* First take care of a risk of an event coming from CC being set to
254 * next tick. Reconfigure CC to future (now tick is the furthest
255 * future). If CC was set to next tick we need to wait for up to 15us
256 * (half of 32k tick) and clean potential event. After that time there
257 * is no risk of unwanted event.
258 */
259 prev_val = nrfy_rtc_cc_get(rtc, chan);
260 nrfy_rtc_event_clear(rtc, evt);
261 nrfy_rtc_cc_set(rtc, chan, now);
262 nrfy_rtc_event_enable(rtc, int_mask);
263
264 if (ticks_sub(dev, prev_val, now, top) == 1) {
265 NRFX_DELAY_US(15);
266 nrfy_rtc_event_clear(rtc, evt);
267 }
268
269 now = nrfy_rtc_counter_get(rtc);
270
271 if (absolute) {
272 val = skip_zero_on_custom_top(val, top);
273 irq_on_late = flags & COUNTER_ALARM_CFG_EXPIRE_WHEN_LATE;
274 max_rel_val = top - data->guard_period;
275 } else {
276 /* If relative value is smaller than half of the counter range
277 * it is assumed that there is a risk of setting value too late
278 * and late detection algorithm must be applied. When late
279 * setting is detected, interrupt shall be triggered for
280 * immediate expiration of the timer. Detection is performed
281 * by limiting relative distance between CC and counter.
282 *
283 * Note that half of counter range is an arbitrary value.
284 */
285 irq_on_late = val < (top / 2);
286 /* limit max to detect short relative being set too late. */
287 max_rel_val = irq_on_late ? top / 2 : top;
288 val = ticks_add(dev, now, val, top);
289 }
290
291 diff = ticks_sub(dev, val, now, top);
292 if (diff == 1) {
293 /* CC cannot be set to COUNTER+1 because that will not
294 * generate an event. In that case, special handling is
295 * performed (attempt to set CC to COUNTER+2).
296 */
297 handle_next_tick_case(dev, chan, now, val);
298 } else {
299 nrfy_rtc_cc_set(rtc, chan, val);
300 now = nrfy_rtc_counter_get(rtc);
301
302 /* decrement value to detect also case when val == read(dev).
303 * Otherwise, condition would need to include comparing diff
304 * against 0.
305 */
306 diff = ticks_sub(dev, val - 1, now, top);
307 if (diff > max_rel_val) {
308 if (absolute) {
309 err = -ETIME;
310 }
311
312 /* Interrupt is triggered always for relative alarm and
313 * for absolute depending on the flag.
314 */
315 if (irq_on_late) {
316 set_cc_int_pending(dev, chan);
317 } else {
318 config->ch_data[chan].callback = NULL;
319 }
320 } else if (diff == 0) {
321 /* It is possible that setting CC was interrupted and
322 * CC might be set to COUNTER+1 value which will not
323 * generate an event. In that case, special handling
324 * is performed (attempt to set CC to COUNTER+2).
325 */
326 handle_next_tick_case(dev, chan, now, val);
327 } else {
328 nrfy_rtc_int_enable(rtc, int_mask);
329 }
330 }
331
332 return err;
333 }
334
set_channel_alarm(const struct device * dev,uint8_t chan,const struct counter_alarm_cfg * alarm_cfg)335 static int set_channel_alarm(const struct device *dev, uint8_t chan,
336 const struct counter_alarm_cfg *alarm_cfg)
337 {
338 const struct counter_nrfx_config *nrfx_config = dev->config;
339 struct counter_nrfx_data *data = dev->data;
340 struct counter_nrfx_ch_data *chdata = &nrfx_config->ch_data[chan];
341
342 if (alarm_cfg->ticks > data->top) {
343 return -EINVAL;
344 }
345
346 if (chdata->callback) {
347 return -EBUSY;
348 }
349
350 chdata->callback = alarm_cfg->callback;
351 chdata->user_data = alarm_cfg->user_data;
352 atomic_and(&data->ipend_adj, ~CC_ADJ_MASK(chan));
353
354 return set_cc(dev, chan, alarm_cfg->ticks, alarm_cfg->flags);
355 }
356
disable(const struct device * dev,uint8_t chan)357 static void disable(const struct device *dev, uint8_t chan)
358 {
359 const struct counter_nrfx_config *config = dev->config;
360 NRF_RTC_Type *rtc = config->rtc;
361 nrf_rtc_event_t evt = NRF_RTC_CHANNEL_EVENT_ADDR(chan);
362
363 nrfy_rtc_event_int_disable(rtc, NRF_RTC_CHANNEL_INT_MASK(chan));
364 nrfy_rtc_event_clear(rtc, evt);
365 config->ch_data[chan].callback = NULL;
366 }
367
cancel_alarm(const struct device * dev,uint8_t chan_id)368 static int cancel_alarm(const struct device *dev, uint8_t chan_id)
369 {
370 disable(dev, chan_id);
371
372 return 0;
373 }
374
ppi_setup(const struct device * dev,uint8_t chan)375 static int ppi_setup(const struct device *dev, uint8_t chan)
376 {
377 #if CONFIG_COUNTER_RTC_WITH_PPI_WRAP
378 const struct counter_nrfx_config *nrfx_config = dev->config;
379 struct counter_nrfx_data *data = dev->data;
380 NRF_RTC_Type *rtc = nrfx_config->rtc;
381 nrf_rtc_event_t evt = NRF_RTC_CHANNEL_EVENT_ADDR(chan);
382 nrfx_err_t result;
383
384 if (!nrfx_config->use_ppi) {
385 return 0;
386 }
387
388 nrfy_rtc_event_enable(rtc, NRF_RTC_CHANNEL_INT_MASK(chan));
389 #ifdef DPPI_PRESENT
390 nrfx_dppi_t dppi = NRFX_DPPI_INSTANCE(0);
391
392 result = nrfx_dppi_channel_alloc(&dppi, &data->ppi_ch);
393 if (result != NRFX_SUCCESS) {
394 ERR("Failed to allocate PPI channel.");
395 return -ENODEV;
396 }
397
398 nrfy_rtc_subscribe_set(rtc, NRF_RTC_TASK_CLEAR, data->ppi_ch);
399 nrfy_rtc_publish_set(rtc, evt, data->ppi_ch);
400 (void)nrfx_dppi_channel_enable(&dppi, data->ppi_ch);
401 #else /* DPPI_PRESENT */
402 uint32_t evt_addr;
403 uint32_t task_addr;
404
405 evt_addr = nrfy_rtc_event_address_get(rtc, evt);
406 task_addr = nrfy_rtc_task_address_get(rtc, NRF_RTC_TASK_CLEAR);
407
408 result = nrfx_ppi_channel_alloc(&data->ppi_ch);
409 if (result != NRFX_SUCCESS) {
410 ERR("Failed to allocate PPI channel.");
411 return -ENODEV;
412 }
413 (void)nrfx_ppi_channel_assign(data->ppi_ch, evt_addr, task_addr);
414 (void)nrfx_ppi_channel_enable(data->ppi_ch);
415 #endif
416 #endif /* CONFIG_COUNTER_RTC_WITH_PPI_WRAP */
417 return 0;
418 }
419
ppi_free(const struct device * dev,uint8_t chan)420 static void ppi_free(const struct device *dev, uint8_t chan)
421 {
422 #if CONFIG_COUNTER_RTC_WITH_PPI_WRAP
423 const struct counter_nrfx_config *nrfx_config = dev->config;
424 struct counter_nrfx_data *data = dev->data;
425 uint8_t ppi_ch = data->ppi_ch;
426 NRF_RTC_Type *rtc = nrfx_config->rtc;
427
428 if (!nrfx_config->use_ppi) {
429 return;
430 }
431 nrfy_rtc_event_disable(rtc, NRF_RTC_CHANNEL_INT_MASK(chan));
432 #ifdef DPPI_PRESENT
433 nrf_rtc_event_t evt = NRF_RTC_CHANNEL_EVENT_ADDR(chan);
434 nrfx_dppi_t dppi = NRFX_DPPI_INSTANCE(0);
435
436 (void)nrfx_dppi_channel_disable(&dppi, ppi_ch);
437 nrfy_rtc_subscribe_clear(rtc, NRF_RTC_TASK_CLEAR);
438 nrfy_rtc_publish_clear(rtc, evt);
439 (void)nrfx_dppi_channel_free(&dppi, ppi_ch);
440 #else /* DPPI_PRESENT */
441 (void)nrfx_ppi_channel_disable(ppi_ch);
442 (void)nrfx_ppi_channel_free(ppi_ch);
443 #endif
444 #endif
445 }
446
447 /* Return true if counter must be cleared by the CPU. It is cleared
448 * automatically in case of max top value or PPI usage.
449 */
sw_wrap_required(const struct device * dev)450 static bool sw_wrap_required(const struct device *dev)
451 {
452 struct counter_nrfx_data *data = dev->data;
453
454 return (data->top != NRF_RTC_COUNTER_MAX) && !IS_PPI_WRAP(dev);
455 }
456
set_fixed_top_value(const struct device * dev,const struct counter_top_cfg * cfg)457 static int set_fixed_top_value(const struct device *dev,
458 const struct counter_top_cfg *cfg)
459 {
460 const struct counter_nrfx_config *config = dev->config;
461 struct counter_nrfx_data *data = dev->data;
462
463 NRF_RTC_Type *rtc = config->rtc;
464
465 if (cfg->ticks != NRF_RTC_COUNTER_MAX) {
466 return -EINVAL;
467 }
468
469 nrfy_rtc_int_disable(rtc, NRF_RTC_INT_OVERFLOW_MASK);
470 data->top_cb = cfg->callback;
471 data->top_user_data = cfg->user_data;
472
473 if (!(cfg->flags & COUNTER_TOP_CFG_DONT_RESET)) {
474 nrfy_rtc_task_trigger(rtc, NRF_RTC_TASK_CLEAR);
475 }
476
477 if (cfg->callback) {
478 nrfy_rtc_int_enable(rtc, NRF_RTC_INT_OVERFLOW_MASK);
479 }
480
481 return 0;
482 }
483
set_top_value(const struct device * dev,const struct counter_top_cfg * cfg)484 static int set_top_value(const struct device *dev,
485 const struct counter_top_cfg *cfg)
486 {
487 const struct counter_nrfx_config *nrfx_config = dev->config;
488 NRF_RTC_Type *rtc = nrfx_config->rtc;
489 struct counter_nrfx_data *dev_data = dev->data;
490 uint32_t top_ch = COUNTER_GET_TOP_CH(dev);
491 int err = 0;
492
493 if (IS_FIXED_TOP(dev)) {
494 return set_fixed_top_value(dev, cfg);
495 }
496
497 for (int i = 0; i < counter_get_num_of_channels(dev); i++) {
498 /* Overflow can be changed only when all alarms are
499 * disables.
500 */
501 if (nrfx_config->ch_data[i].callback) {
502 return -EBUSY;
503 }
504 }
505
506 nrfy_rtc_int_disable(rtc, NRF_RTC_CHANNEL_INT_MASK(top_ch));
507
508 if (IS_PPI_WRAP(dev)) {
509 if ((dev_data->top == NRF_RTC_COUNTER_MAX) &&
510 cfg->ticks != NRF_RTC_COUNTER_MAX) {
511 err = ppi_setup(dev, top_ch);
512 } else if (((dev_data->top != NRF_RTC_COUNTER_MAX) &&
513 cfg->ticks == NRF_RTC_COUNTER_MAX)) {
514 ppi_free(dev, top_ch);
515 }
516 }
517
518 dev_data->top_cb = cfg->callback;
519 dev_data->top_user_data = cfg->user_data;
520 dev_data->top = cfg->ticks;
521 nrfy_rtc_cc_set(rtc, top_ch, cfg->ticks);
522
523 if (!(cfg->flags & COUNTER_TOP_CFG_DONT_RESET)) {
524 nrfy_rtc_task_trigger(rtc, NRF_RTC_TASK_CLEAR);
525 } else if (read(dev) >= cfg->ticks) {
526 err = -ETIME;
527 if (cfg->flags & COUNTER_TOP_CFG_RESET_WHEN_LATE) {
528 nrfy_rtc_task_trigger(rtc, NRF_RTC_TASK_CLEAR);
529 }
530 }
531
532 if (cfg->callback || sw_wrap_required(dev)) {
533 nrfy_rtc_int_enable(rtc, NRF_RTC_CHANNEL_INT_MASK(top_ch));
534 }
535
536 return err;
537 }
538
get_pending_int(const struct device * dev)539 static uint32_t get_pending_int(const struct device *dev)
540 {
541 return 0;
542 }
543
init_rtc(const struct device * dev,uint32_t prescaler)544 static int init_rtc(const struct device *dev, uint32_t prescaler)
545 {
546 MAYBE_CONST_CONFIG struct counter_nrfx_config *nrfx_config =
547 (MAYBE_CONST_CONFIG struct counter_nrfx_config *) dev->config;
548 struct counter_nrfx_data *data = dev->data;
549 struct counter_top_cfg top_cfg = {
550 .ticks = NRF_RTC_COUNTER_MAX
551 };
552
553 #if defined(CONFIG_SOC_SERIES_BSIM_NRFXX)
554 /* For simulated devices we need to convert the hardcoded DT address from the real
555 * peripheral into the correct one for simulation
556 */
557 nrfx_config->rtc = nhw_convert_periph_base_addr(nrfx_config->rtc);
558 #endif
559
560 NRF_RTC_Type *rtc = nrfx_config->rtc;
561 int err;
562
563 #ifdef CONFIG_CLOCK_CONTROL_NRF
564 z_nrf_clock_control_lf_on(CLOCK_CONTROL_NRF_LF_START_NOWAIT);
565 #endif
566
567 nrfy_rtc_prescaler_set(rtc, prescaler);
568
569 NRFY_IRQ_ENABLE(NRFX_IRQ_NUMBER_GET(rtc));
570
571 data->top = NRF_RTC_COUNTER_MAX;
572 err = set_top_value(dev, &top_cfg);
573 DBG("Initialized");
574
575 return err;
576 }
577
get_top_value(const struct device * dev)578 static uint32_t get_top_value(const struct device *dev)
579 {
580 struct counter_nrfx_data *data = dev->data;
581
582 return data->top;
583 }
584
get_guard_period(const struct device * dev,uint32_t flags)585 static uint32_t get_guard_period(const struct device *dev, uint32_t flags)
586 {
587 struct counter_nrfx_data *data = dev->data;
588
589 return data->guard_period;
590 }
591
set_guard_period(const struct device * dev,uint32_t guard,uint32_t flags)592 static int set_guard_period(const struct device *dev, uint32_t guard,
593 uint32_t flags)
594 {
595 struct counter_nrfx_data *data = dev->data;
596
597 data->guard_period = guard;
598 return 0;
599 }
600
top_irq_handle(const struct device * dev)601 static void top_irq_handle(const struct device *dev)
602 {
603 const struct counter_nrfx_config *config = dev->config;
604 struct counter_nrfx_data *data = dev->data;
605
606 NRF_RTC_Type *rtc = config->rtc;
607 counter_top_callback_t cb = data->top_cb;
608 nrf_rtc_event_t top_evt;
609
610 top_evt = IS_FIXED_TOP(dev) ?
611 NRF_RTC_EVENT_OVERFLOW :
612 NRF_RTC_CHANNEL_EVENT_ADDR(counter_get_num_of_channels(dev));
613
614 uint32_t event_mask = nrfy_rtc_events_process(rtc, NRFY_EVENT_TO_INT_BITMASK(top_evt));
615
616 if (event_mask & NRFY_EVENT_TO_INT_BITMASK(top_evt)) {
617 /* Perform manual clear if custom top value is used and PPI
618 * clearing is not used.
619 */
620 if (!IS_FIXED_TOP(dev) && !IS_PPI_WRAP(dev)) {
621 nrfy_rtc_task_trigger(rtc, NRF_RTC_TASK_CLEAR);
622 }
623
624 if (cb) {
625 cb(dev, data->top_user_data);
626 }
627 }
628 }
629
alarm_irq_handle(const struct device * dev,uint32_t chan)630 static void alarm_irq_handle(const struct device *dev, uint32_t chan)
631 {
632 const struct counter_nrfx_config *config = dev->config;
633 struct counter_nrfx_data *data = dev->data;
634
635 NRF_RTC_Type *rtc = config->rtc;
636 nrf_rtc_event_t evt = NRF_RTC_CHANNEL_EVENT_ADDR(chan);
637 uint32_t int_mask = NRF_RTC_CHANNEL_INT_MASK(chan);
638
639 bool hw_irq_pending = nrfy_rtc_events_process(rtc, NRFY_EVENT_TO_INT_BITMASK(evt)) &
640 nrfy_rtc_int_enable_check(rtc, NRFY_EVENT_TO_INT_BITMASK(evt));
641 bool sw_irq_pending = data->ipend_adj & BIT(chan);
642
643 if (hw_irq_pending || sw_irq_pending) {
644 struct counter_nrfx_ch_data *chdata;
645 counter_alarm_callback_t cb;
646
647 atomic_and(&data->ipend_adj, ~BIT(chan));
648 nrfy_rtc_int_disable(rtc, int_mask);
649
650 chdata = &config->ch_data[chan];
651 cb = chdata->callback;
652 chdata->callback = NULL;
653
654 if (cb) {
655 uint32_t cc = nrfy_rtc_cc_get(rtc, chan);
656
657 if (data->ipend_adj & CC_ADJ_MASK(chan)) {
658 cc = ticks_sub(dev, cc, 1, data->top);
659 }
660
661 cb(dev, chan, cc, chdata->user_data);
662 }
663 }
664 }
665
irq_handler(const void * arg)666 static void irq_handler(const void *arg)
667 {
668 const struct device *dev = arg;
669
670 top_irq_handle(dev);
671
672 for (uint32_t i = 0; i < counter_get_num_of_channels(dev); i++) {
673 alarm_irq_handle(dev, i);
674 }
675 }
676
677 static DEVICE_API(counter, counter_nrfx_driver_api) = {
678 .start = start,
679 .stop = stop,
680 .get_value = get_value,
681 .set_alarm = set_channel_alarm,
682 .cancel_alarm = cancel_alarm,
683 .set_top_value = set_top_value,
684 .get_pending_int = get_pending_int,
685 .get_top_value = get_top_value,
686 .get_guard_period = get_guard_period,
687 .set_guard_period = set_guard_period,
688 };
689
690 /*
691 * Devicetree access is done with node labels due to HAL API
692 * requirements. In particular, RTCx_CC_NUM values from HALs
693 * are indexed by peripheral number, so DT_INST APIs won't work.
694 */
695
696 #define RTC_IRQ_CONNECT(idx) \
697 COND_CODE_1(DT_INST_PROP(idx, zli), \
698 (IRQ_DIRECT_CONNECT(DT_INST_IRQN(idx), \
699 DT_INST_IRQ(idx, priority), \
700 counter_rtc##idx##_isr_wrapper, \
701 IRQ_ZERO_LATENCY)), \
702 (IRQ_CONNECT(DT_INST_IRQN(idx), DT_INST_IRQ(idx, priority), \
703 irq_handler, DEVICE_DT_INST_GET(idx), 0)) \
704 )
705
706 #define COUNTER_NRF_RTC_DEVICE(idx) \
707 BUILD_ASSERT((DT_INST_PROP(idx, prescaler) - 1) <= \
708 RTC_PRESCALER_PRESCALER_Msk, \
709 "RTC prescaler out of range"); \
710 COND_CODE_1(DT_INST_PROP(idx, zli), ( \
711 ISR_DIRECT_DECLARE(counter_rtc##idx##_isr_wrapper) \
712 { \
713 irq_handler(DEVICE_DT_INST_GET(idx)); \
714 /* No rescheduling, it shall not access zephyr primitives. */ \
715 return 0; \
716 }), ()) \
717 static int counter_##idx##_init(const struct device *dev) \
718 { \
719 RTC_IRQ_CONNECT(idx); \
720 return init_rtc(dev, DT_INST_PROP(idx, prescaler) - 1); \
721 } \
722 static struct counter_nrfx_data counter_##idx##_data; \
723 static struct counter_nrfx_ch_data \
724 counter##idx##_ch_data[DT_INST_PROP(idx, cc_num)]; \
725 LOG_INSTANCE_REGISTER(LOG_MODULE_NAME, idx, CONFIG_COUNTER_LOG_LEVEL); \
726 static MAYBE_CONST_CONFIG \
727 struct counter_nrfx_config nrfx_counter_##idx##_config = { \
728 .info = { \
729 .max_top_value = NRF_RTC_COUNTER_MAX, \
730 .freq = DT_INST_PROP(idx, clock_frequency) / \
731 DT_INST_PROP(idx, prescaler), \
732 .flags = COUNTER_CONFIG_INFO_COUNT_UP, \
733 .channels = DT_INST_PROP(idx, fixed_top) \
734 ? DT_INST_PROP(idx, cc_num) \
735 : DT_INST_PROP(idx, cc_num) - 1 \
736 }, \
737 .ch_data = counter##idx##_ch_data, \
738 .rtc = (NRF_RTC_Type *)DT_INST_REG_ADDR(idx), \
739 IF_ENABLED(CONFIG_COUNTER_RTC_WITH_PPI_WRAP, \
740 (.use_ppi = DT_INST_PROP(idx, ppi_wrap),)) \
741 IF_ENABLED(CONFIG_COUNTER_RTC_CUSTOM_TOP_SUPPORT, \
742 (.fixed_top = DT_INST_PROP(idx, fixed_top),)) \
743 LOG_INSTANCE_PTR_INIT(log, LOG_MODULE_NAME, idx) \
744 }; \
745 DEVICE_DT_INST_DEFINE(idx, \
746 counter_##idx##_init, \
747 NULL, \
748 &counter_##idx##_data, \
749 &nrfx_counter_##idx##_config.info, \
750 PRE_KERNEL_1, CONFIG_COUNTER_INIT_PRIORITY, \
751 &counter_nrfx_driver_api);
752
753 DT_INST_FOREACH_STATUS_OKAY(COUNTER_NRF_RTC_DEVICE)
754