1 /*
2  * Arm SCP/MCP Software
3  * Copyright (c) 2017-2023, Arm Limited and Contributors. All rights reserved.
4  *
5  * SPDX-License-Identifier: BSD-3-Clause
6  *
7  * Description:
8  *    Implementation of Timer module
9  */
10 
11 #include <mod_timer.h>
12 
13 #include <fwk_assert.h>
14 #include <fwk_dlist.h>
15 #include <fwk_id.h>
16 #include <fwk_interrupt.h>
17 #include <fwk_list.h>
18 #include <fwk_log.h>
19 #include <fwk_macros.h>
20 #include <fwk_mm.h>
21 #include <fwk_module.h>
22 #include <fwk_module_idx.h>
23 #include <fwk_status.h>
24 
25 #include <stdbool.h>
26 #include <stdint.h>
27 #include <string.h>
28 
29 /* Timer device context (element) */
30 struct timer_dev_ctx {
31     /* Pointer to the device's configuration */
32     const struct mod_timer_dev_config *config;
33     /* Pointer to an API provided by the driver that controls the device */
34     struct mod_timer_driver_api *driver;
35     /* Identifier of the driver that controls the device */
36     fwk_id_t driver_dev_id;
37     /* Storage for all alarms */
38     struct alarm_sub_element_ctx *alarm_pool;
39     /* Queue of active alarms */
40     struct fwk_dlist alarms_active;
41 };
42 
43 /* Alarm item context (sub-element) */
44 struct alarm_sub_element_ctx {
45     /* List node */
46     struct fwk_dlist_node node;
47     /* Time between starting this alarm and it triggering */
48     uint32_t microseconds;
49     /* Timestamp of the time this alarm will trigger */
50     uint64_t timestamp;
51     /* Pointer to the callback function */
52     void (*callback)(uintptr_t param);
53     /* Parameter of the callback function */
54     uintptr_t param;
55     /* Flag indicating if this alarm if periodic */
56     bool periodic;
57     /* Flag indicating if this alarm is in the active queue */
58     bool activated;
59     /* Flag indicating if this alarm has been bound to */
60     bool bound;
61     /* Flag indicating if this alarm is started */
62     bool started;
63 };
64 
65 /* Table of timer device context structures */
66 static struct timer_dev_ctx *ctx_table;
67 
68 /*
69  * Forward declarations
70  */
71 
72 static void timer_isr(uintptr_t ctx_ptr);
73 
74 /*
75  * Internal functions
76  */
77 
_time_to_timestamp(struct timer_dev_ctx * ctx,uint32_t microseconds,uint64_t * timestamp)78 static int _time_to_timestamp(
79     struct timer_dev_ctx *ctx,
80     uint32_t microseconds,
81     uint64_t *timestamp)
82 {
83     int status;
84     uint32_t frequency;
85 
86     fwk_assert(ctx != NULL);
87     fwk_assert(timestamp != NULL);
88 
89     status = ctx->driver->get_frequency(ctx->driver_dev_id, &frequency);
90     if (status != FWK_SUCCESS) {
91         return status;
92     }
93 
94     *timestamp = ((uint64_t)frequency * microseconds) / 1000000;
95 
96     return FWK_SUCCESS;
97 }
98 
_timestamp_from_now(struct timer_dev_ctx * ctx,uint32_t microseconds,uint64_t * timestamp)99 static int _timestamp_from_now(
100     struct timer_dev_ctx *ctx,
101     uint32_t microseconds,
102     uint64_t *timestamp)
103 {
104     int status;
105     uint64_t counter;
106 
107     fwk_assert(ctx != NULL);
108     fwk_assert(timestamp != NULL);
109 
110     status = _time_to_timestamp(ctx, microseconds, timestamp);
111     if (status != FWK_SUCCESS) {
112         return status;
113     }
114 
115     status = ctx->driver->get_counter(ctx->driver_dev_id, &counter);
116     if (status != FWK_SUCCESS) {
117         return status;
118     }
119 
120     *timestamp += counter;
121 
122     return FWK_SUCCESS;
123 }
124 
_remaining(const struct timer_dev_ctx * ctx,uint64_t timestamp,uint64_t * remaining_ticks)125 static int _remaining(
126     const struct timer_dev_ctx *ctx,
127     uint64_t timestamp,
128     uint64_t *remaining_ticks)
129 {
130     int status;
131     uint64_t counter;
132 
133     fwk_assert(ctx != NULL);
134     fwk_assert(remaining_ticks != NULL);
135 
136     status = ctx->driver->get_counter(ctx->driver_dev_id, &counter);
137     if (!fwk_expect(status == FWK_SUCCESS)) {
138         return status;
139     }
140 
141     /* If timestamp is in the past, remaining_ticks is set to zero. */
142     if (timestamp < counter) {
143         *remaining_ticks = 0;
144     } else {
145         *remaining_ticks = timestamp - counter;
146     }
147 
148     return FWK_SUCCESS;
149 }
150 
_configure_timer_with_next_alarm(struct timer_dev_ctx * ctx)151 static void _configure_timer_with_next_alarm(struct timer_dev_ctx *ctx)
152 {
153     int status;
154     struct alarm_sub_element_ctx *alarm_head;
155 
156     fwk_assert(ctx != NULL);
157 
158     alarm_head =
159         (struct alarm_sub_element_ctx *)fwk_list_head(&ctx->alarms_active);
160     if (alarm_head != NULL) {
161         /* Configure timer device */
162         status =
163             ctx->driver->set_timer(ctx->driver_dev_id, alarm_head->timestamp);
164         if (status != FWK_SUCCESS) {
165             FWK_LOG_DEBUG("[Timer] %s @%d", __func__, __LINE__);
166         }
167 
168         status = ctx->driver->enable(ctx->driver_dev_id);
169         if (status != FWK_SUCCESS) {
170             FWK_LOG_DEBUG("[Timer] %s @%d", __func__, __LINE__);
171         }
172     }
173 }
174 
_insert_alarm_ctx_into_active_queue(struct timer_dev_ctx * ctx,struct alarm_sub_element_ctx * alarm_new)175 static void _insert_alarm_ctx_into_active_queue(
176     struct timer_dev_ctx *ctx,
177     struct alarm_sub_element_ctx *alarm_new)
178 {
179     struct fwk_dlist_node *alarm_node;
180     struct alarm_sub_element_ctx *alarm;
181 
182     fwk_assert(ctx != NULL);
183     fwk_assert(alarm_new != NULL);
184 
185     /*
186      * Search though the active queue to find the correct place to insert the
187      * new alarm item
188      */
189     alarm_node = fwk_list_head(&ctx->alarms_active);
190     alarm = FWK_LIST_GET(alarm_node, struct alarm_sub_element_ctx, node);
191 
192     while ((alarm_node != NULL) && (alarm_new->timestamp > alarm->timestamp)) {
193         alarm_node = fwk_list_next(&ctx->alarms_active, alarm_node);
194         alarm = FWK_LIST_GET(alarm_node, struct alarm_sub_element_ctx, node);
195     }
196 
197     /* Insert alarm_new just BEFORE the alarm that was found */
198     fwk_list_insert(&ctx->alarms_active,
199                     &(alarm_new->node),
200                     alarm_node);
201 
202     alarm_new->activated = true;
203 }
204 
205 
206 /*
207  * Functions fulfilling the timer API
208  */
209 
get_frequency(fwk_id_t dev_id,uint32_t * frequency)210 static int get_frequency(fwk_id_t dev_id, uint32_t *frequency)
211 {
212     struct timer_dev_ctx *ctx;
213 
214     ctx = &ctx_table[fwk_id_get_element_idx(dev_id)];
215 
216     if (frequency == NULL) {
217         return FWK_E_PARAM;
218     }
219 
220     return ctx->driver->get_frequency(ctx->driver_dev_id, frequency);
221 }
222 
time_to_timestamp(fwk_id_t dev_id,uint32_t microseconds,uint64_t * timestamp)223 static int time_to_timestamp(fwk_id_t dev_id,
224                              uint32_t microseconds,
225                              uint64_t *timestamp)
226 {
227     struct timer_dev_ctx *ctx;
228 
229     if (timestamp == NULL) {
230         return FWK_E_PARAM;
231     }
232 
233     ctx = &ctx_table[fwk_id_get_element_idx(dev_id)];
234 
235     return _time_to_timestamp(ctx, microseconds, timestamp);
236 }
237 
get_counter(fwk_id_t dev_id,uint64_t * counter)238 static int get_counter(fwk_id_t dev_id, uint64_t *counter)
239 {
240     struct timer_dev_ctx *ctx;
241 
242     ctx = &ctx_table[fwk_id_get_element_idx(dev_id)];
243 
244     if (counter == NULL) {
245         return FWK_E_PARAM;
246     }
247 
248     /* Read counter */
249     return ctx->driver->get_counter(ctx->driver_dev_id, counter);
250 }
251 
delay(fwk_id_t dev_id,uint32_t microseconds)252 static int delay(fwk_id_t dev_id, uint32_t microseconds)
253 {
254     int status;
255     struct timer_dev_ctx *ctx;
256     uint64_t counter, counter_limit;
257 
258     ctx = &ctx_table[fwk_id_get_element_idx(dev_id)];
259 
260     status = _timestamp_from_now(ctx, microseconds, &counter_limit);
261     if (status != FWK_SUCCESS) {
262         return status;
263     }
264 
265     do {
266         status = ctx->driver->get_counter(ctx->driver_dev_id, &counter);
267         if (status != FWK_SUCCESS) {
268             return status;
269         }
270     } while (counter < counter_limit);
271 
272     return FWK_SUCCESS;
273 }
274 
wait(fwk_id_t dev_id,uint32_t microseconds,bool (* cond)(void *),void * data)275 static int wait(fwk_id_t dev_id,
276                 uint32_t microseconds,
277                 bool (*cond)(void*),
278                 void *data)
279 {
280     struct timer_dev_ctx *ctx;
281     int status;
282     uint64_t counter, counter_limit;
283 
284     ctx = &ctx_table[fwk_id_get_element_idx(dev_id)];
285 
286     status = _timestamp_from_now(ctx, microseconds, &counter_limit);
287     if (status != FWK_SUCCESS) {
288         return status;
289     }
290 
291     while (true) {
292         if (cond(data)) {
293             return FWK_SUCCESS;
294         }
295 
296         status = ctx->driver->get_counter(ctx->driver_dev_id, &counter);
297         if (status != FWK_SUCCESS) {
298             return FWK_E_DEVICE;
299         }
300 
301         /*
302          * If the time to wait is over, check condition one last time.
303          */
304         if (counter > counter_limit) {
305             if (cond(data)) {
306                 return FWK_SUCCESS;
307             } else {
308                 return FWK_E_TIMEOUT;
309             }
310         }
311     }
312 }
313 
remaining(fwk_id_t dev_id,uint64_t timestamp,uint64_t * remaining_ticks)314 static int remaining(fwk_id_t dev_id,
315                      uint64_t timestamp,
316                      uint64_t *remaining_ticks)
317 {
318     struct timer_dev_ctx *ctx;
319 
320     ctx = &ctx_table[fwk_id_get_element_idx(dev_id)];
321 
322     if (remaining_ticks == NULL) {
323         return FWK_E_PARAM;
324     }
325 
326     return _remaining(ctx, timestamp, remaining_ticks);
327 }
328 
get_next_alarm_remaining(fwk_id_t dev_id,bool * has_alarm,uint64_t * remaining_ticks)329 static int get_next_alarm_remaining(fwk_id_t dev_id,
330                                     bool *has_alarm,
331                                     uint64_t *remaining_ticks)
332 {
333     int status, exit_status;
334     const struct timer_dev_ctx *ctx;
335     const struct alarm_sub_element_ctx *alarm_ctx;
336     const struct fwk_dlist_node *alarm_ctx_node;
337     if (has_alarm == NULL) {
338         return FWK_E_PARAM;
339     }
340 
341     if (remaining_ticks == NULL) {
342         return FWK_E_PARAM;
343     }
344 
345     ctx = &ctx_table[fwk_id_get_element_idx(dev_id)];
346 
347     /*
348      * The timer interrupt is disabled to ensure that the alarm list is not
349      * modified while we are trying to read it below.
350      */
351     status = ctx->driver->disable(ctx->driver_dev_id);
352     if (status != FWK_SUCCESS) {
353         return FWK_E_DEVICE;
354     }
355 
356     *has_alarm = !fwk_list_is_empty(&ctx->alarms_active);
357 
358     if (*has_alarm) {
359         alarm_ctx_node = fwk_list_head(&ctx->alarms_active);
360         alarm_ctx =
361             FWK_LIST_GET(alarm_ctx_node, struct alarm_sub_element_ctx, node);
362 
363         exit_status = _remaining(ctx, alarm_ctx->timestamp, remaining_ticks);
364     } else {
365         exit_status = FWK_E_PARAM;
366     }
367 
368     status = ctx->driver->enable(ctx->driver_dev_id);
369     if (status != FWK_SUCCESS) {
370         return FWK_E_DEVICE;
371     }
372 
373     return exit_status;
374 }
375 
376 static const struct mod_timer_api timer_api = {
377     .get_frequency = get_frequency,
378     .time_to_timestamp = time_to_timestamp,
379     .get_counter = get_counter,
380     .delay = delay,
381     .wait = wait,
382     .remaining = remaining,
383     .get_next_alarm_remaining = get_next_alarm_remaining,
384 };
385 
386 /*
387  * Functions fulfilling the alarm API
388  */
389 
alarm_stop(fwk_id_t alarm_id)390 static int alarm_stop(fwk_id_t alarm_id)
391 {
392     int status;
393     struct timer_dev_ctx *ctx;
394     struct alarm_sub_element_ctx *alarm;
395     unsigned int interrupt;
396 
397     fwk_assert(fwk_module_is_valid_sub_element_id(alarm_id));
398 
399     ctx = &ctx_table[fwk_id_get_element_idx(alarm_id)];
400 
401     status = fwk_interrupt_get_current(&interrupt);
402     switch (status) {
403     case FWK_E_STATE:
404         /* Not within an ISR */
405         break;
406 
407     case FWK_SUCCESS:
408         /* Within an ISR */
409 
410         if (interrupt == ctx->config->timer_irq) {
411             /*
412              * The interrupt handler is the interrupt handler for the alarm's
413              * timer
414              */
415             break;
416         }
417         /* Fall-through */
418 
419     default:
420         return FWK_E_ACCESS;
421     }
422 
423     alarm = &ctx->alarm_pool[fwk_id_get_sub_element_idx(alarm_id)];
424 
425     /* Prevent possible data races with the timer interrupt */
426     status = ctx->driver->disable(ctx->driver_dev_id);
427     if (status != FWK_SUCCESS) {
428         return FWK_E_DEVICE;
429     }
430 
431     if (!alarm->started) {
432         status = ctx->driver->enable(ctx->driver_dev_id);
433         if (status != FWK_SUCCESS) {
434             return FWK_E_DEVICE;
435         } else {
436             return FWK_E_STATE;
437         }
438     }
439 
440     alarm->started = false;
441 
442     if (!alarm->activated) {
443         return FWK_SUCCESS;
444     }
445 
446     /*
447      * If the alarm is stopped while the interrupts are globally disabled, an
448      * interrupt may be pending because the alarm being stopped here has
449      * triggered. If the interrupt is not cleared then when the interrupts are
450      * re-enabled, the timer ISR will be executed but the alarm, cause of the
451      * interrupt, will have disappeared. To avoid that, the timer interrupt is
452      * cleared here. If the interrupt was triggered by another alarm, it will be
453      * re-triggered when the timer interrupt is re-enabled.
454      */
455     status = fwk_interrupt_clear_pending(ctx->config->timer_irq);
456     if (status != FWK_SUCCESS) {
457         return status;
458     }
459 
460     fwk_list_remove(&ctx->alarms_active, (struct fwk_dlist_node *)alarm);
461     alarm->activated = false;
462 
463     _configure_timer_with_next_alarm(ctx);
464 
465     return FWK_SUCCESS;
466 }
467 
alarm_start(fwk_id_t alarm_id,unsigned int milliseconds,enum mod_timer_alarm_type type,void (* callback)(uintptr_t param),uintptr_t param)468 static int alarm_start(fwk_id_t alarm_id,
469                        unsigned int milliseconds,
470                        enum mod_timer_alarm_type type,
471                        void (*callback)(uintptr_t param),
472                        uintptr_t param)
473 {
474     int status;
475     struct timer_dev_ctx *ctx;
476     struct alarm_sub_element_ctx *alarm;
477     unsigned int interrupt;
478 
479     fwk_assert(fwk_module_is_valid_sub_element_id(alarm_id));
480 
481     status = fwk_interrupt_get_current(&interrupt);
482     if (status != FWK_E_STATE) {
483         /*
484          * Could not attain call context OR this function is called from an
485          * interrupt handler.
486          */
487         return FWK_E_ACCESS;
488     }
489 
490     ctx = ctx_table + fwk_id_get_element_idx(alarm_id);
491     alarm = &ctx->alarm_pool[fwk_id_get_sub_element_idx(alarm_id)];
492 
493     if (alarm->started) {
494         status = alarm_stop(alarm_id);
495         if (status != FWK_SUCCESS) {
496             return status;
497         }
498     }
499 
500     alarm->started = true;
501 
502     /* Cap to ensure value will not overflow when stored as microseconds */
503     milliseconds = FWK_MIN(milliseconds, UINT32_MAX / 1000);
504 
505     /* Populate alarm item */
506     alarm->callback = callback;
507     alarm->param = param;
508     alarm->periodic =
509         (type == MOD_TIMER_ALARM_TYPE_PERIODIC ? true : false);
510     alarm->microseconds = milliseconds * 1000;
511     status = _timestamp_from_now(ctx,
512                                  alarm->microseconds,
513                                  &alarm->timestamp);
514     if (status != FWK_SUCCESS) {
515         return status;
516     }
517 
518     /* Disable timer interrupts to work with the active queue */
519     status = ctx->driver->disable(ctx->driver_dev_id);
520     if (status != FWK_SUCCESS) {
521         return FWK_E_DEVICE;
522     }
523 
524     _insert_alarm_ctx_into_active_queue(ctx, alarm);
525 
526     _configure_timer_with_next_alarm(ctx);
527 
528     return FWK_SUCCESS;
529 }
530 
531 static const struct mod_timer_alarm_api alarm_api = {
532     .start = alarm_start,
533     .stop = alarm_stop,
534 };
535 
timer_isr(uintptr_t ctx_ptr)536 static void timer_isr(uintptr_t ctx_ptr)
537 {
538     int status;
539     struct alarm_sub_element_ctx *alarm;
540     struct timer_dev_ctx *ctx = (struct timer_dev_ctx *)ctx_ptr;
541     uint64_t timestamp = 0;
542 
543     fwk_assert(ctx != NULL);
544 
545     /* Disable timer interrupts to work with the active queue */
546     status = ctx->driver->disable(ctx->driver_dev_id);
547     if (status != FWK_SUCCESS) {
548         FWK_LOG_DEBUG("[Timer] %s @%d", __func__, __LINE__);
549     }
550 
551     status = fwk_interrupt_clear_pending(ctx->config->timer_irq);
552     if (status != FWK_SUCCESS) {
553         FWK_LOG_DEBUG("[Timer] %s @%d", __func__, __LINE__);
554     }
555 
556     alarm =
557         (struct alarm_sub_element_ctx *)fwk_list_pop_head(&ctx->alarms_active);
558 
559     if (alarm == NULL) {
560         /* Timer interrupt triggered without any alarm in the active queue */
561         fwk_unexpected();
562         return;
563     }
564 
565     alarm->activated = false;
566 
567     /* Execute the callback function */
568     alarm->callback(alarm->param);
569 
570     if (alarm->periodic && alarm->started) {
571         /* Put this alarm back into the active queue */
572         status = _time_to_timestamp(ctx, alarm->microseconds, &timestamp);
573 
574         if (status == FWK_SUCCESS) {
575             alarm->timestamp += timestamp;
576             _insert_alarm_ctx_into_active_queue(ctx, alarm);
577         } else {
578             FWK_LOG_ERR(
579                 "[Timer] Error: Periodic alarm could not be added "
580                 "back into queue.");
581         }
582     }
583 
584     _configure_timer_with_next_alarm(ctx);
585 }
586 
587 /*
588  * Functions fulfilling the framework's module interface
589  */
590 
timer_init(fwk_id_t module_id,unsigned int element_count,const void * data)591 static int timer_init(fwk_id_t module_id,
592                       unsigned int element_count,
593                       const void *data)
594 {
595     ctx_table = fwk_mm_calloc(element_count, sizeof(struct timer_dev_ctx));
596 
597     return FWK_SUCCESS;
598 }
599 
timer_device_init(fwk_id_t element_id,unsigned int alarm_count,const void * data)600 static int timer_device_init(fwk_id_t element_id, unsigned int alarm_count,
601                              const void *data)
602 {
603     struct timer_dev_ctx *ctx;
604 
605     fwk_assert(data != NULL);
606 
607     ctx = ctx_table + fwk_id_get_element_idx(element_id);
608     ctx->config = data;
609 
610     if (alarm_count > 0) {
611         ctx->alarm_pool =
612             fwk_mm_calloc(alarm_count, sizeof(struct alarm_sub_element_ctx));
613     }
614 
615     return FWK_SUCCESS;
616 }
617 
timer_bind(fwk_id_t id,unsigned int round)618 static int timer_bind(fwk_id_t id, unsigned int round)
619 {
620     int status;
621     struct timer_dev_ctx *ctx;
622     struct mod_timer_driver_api *driver = NULL;
623     unsigned int driver_module_idx;
624 
625     /* Nothing to do after the initial round. */
626     if (round > 0) {
627         return FWK_SUCCESS;
628     }
629 
630     if (fwk_id_is_type(id, FWK_ID_TYPE_MODULE)) {
631         return FWK_SUCCESS;
632     }
633 
634     ctx = ctx_table + fwk_id_get_element_idx(id);
635     ctx->driver_dev_id = ctx->config->id;
636 
637     /* Bind to the driver API for the current device */
638     driver_module_idx = fwk_id_get_module_idx(ctx->driver_dev_id);
639     status = fwk_module_bind(ctx->driver_dev_id,
640                              FWK_ID_API(driver_module_idx, 0),
641                              &driver);
642     if (status != FWK_SUCCESS) {
643         return status;
644     }
645 
646     /* Check that the driver API is completely fulfilled */
647     if (driver->enable == NULL || driver->disable == NULL ||
648         driver->get_counter == NULL || driver->get_frequency == NULL) {
649         return FWK_E_DEVICE;
650     }
651 
652     ctx->driver = driver;
653 
654     return FWK_SUCCESS;
655 }
656 
timer_process_bind_request(fwk_id_t requester_id,fwk_id_t id,fwk_id_t api_id,const void ** api)657 static int timer_process_bind_request(fwk_id_t requester_id,
658                                       fwk_id_t id,
659                                       fwk_id_t api_id,
660                                       const void **api)
661 {
662     struct timer_dev_ctx *ctx;
663     struct alarm_sub_element_ctx *alarm_ctx;
664 
665     if (fwk_id_is_equal(api_id, MOD_TIMER_API_ID_TIMER)) {
666         if (!fwk_module_is_valid_element_id(id)) {
667             fwk_unexpected();
668             return FWK_E_PARAM;
669         }
670 
671         *api = &timer_api;
672         return FWK_SUCCESS;
673     }
674 
675     /* Alarm API requested */
676 
677     if (!fwk_module_is_valid_sub_element_id(id)) {
678         fwk_unexpected();
679         return FWK_E_PARAM;
680     }
681 
682     ctx = ctx_table + fwk_id_get_element_idx(id);
683     alarm_ctx = &ctx->alarm_pool[fwk_id_get_sub_element_idx(id)];
684 
685     if (alarm_ctx->bound) {
686         fwk_unexpected();
687         return FWK_E_STATE;
688     }
689 
690     alarm_ctx->bound = true;
691 
692     *api = &alarm_api;
693     return FWK_SUCCESS;
694 }
695 
timer_start(fwk_id_t id)696 static int timer_start(fwk_id_t id)
697 {
698     int status;
699     struct timer_dev_ctx *ctx;
700 
701     if (!fwk_module_is_valid_element_id(id)) {
702         return FWK_SUCCESS;
703     }
704 
705     ctx = ctx_table + fwk_id_get_element_idx(id);
706 
707     fwk_list_init(&ctx->alarms_active);
708 
709     status = fwk_interrupt_set_isr_param(
710         ctx->config->timer_irq, timer_isr, (uintptr_t)ctx);
711     if (status != FWK_SUCCESS) {
712         return status;
713     }
714 
715     return fwk_interrupt_enable(ctx->config->timer_irq);
716 }
717 
718 /* Module descriptor */
719 const struct fwk_module module_timer = {
720     .api_count = (unsigned int)MOD_TIMER_API_COUNT,
721     .type = FWK_MODULE_TYPE_HAL,
722     .init = timer_init,
723     .element_init = timer_device_init,
724     .bind = timer_bind,
725     .process_bind_request = timer_process_bind_request,
726     .start = timer_start,
727 };
728