]> git.sur5r.net Git - freertos/blob - FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1_FreedomStudio/freedom-metal/metal/clock.h
Update RISCC-V-RV32-SiFive_HiFive1_FreedomStudio project to latest tools and metal...
[freertos] / FreeRTOS / Demo / RISC-V_RV32_SiFive_HiFive1_FreedomStudio / freedom-metal / metal / clock.h
1 /* Copyright 2018 SiFive, Inc */
2 /* SPDX-License-Identifier: Apache-2.0 */
3
4 #ifndef METAL__CLOCK_H
5 #define METAL__CLOCK_H
6
7 /*! 
8  * @file clock.h
9  * @brief API for manipulating clock sources
10  *
11  * The clock interface allows for controlling the rate of various clocks in the system.
12  */
13
14 struct metal_clock;
15
16 #include <stddef.h>
17
18 /* The generic interface to all clocks. */
19 struct __metal_clock_vtable {
20     long (*get_rate_hz)(const struct metal_clock *clk);
21     long (*set_rate_hz)(struct metal_clock *clk, long hz);
22 };
23
24 /*!
25  * @brief Function signature of clock rate change callbacks
26  */
27 typedef void (*metal_clock_rate_change_callback)(void *priv);
28
29 struct _metal_clock_callback_t;
30 struct _metal_clock_callback_t {
31     /* The callback function */
32     metal_clock_rate_change_callback callback;
33
34     /* Private data for the callback function */
35     void *priv;
36
37     struct _metal_clock_callback_t *_next;
38 };
39
40 /*!
41  * @brief Type for the linked list of callbacks for clock rate changes
42  */
43 typedef struct _metal_clock_callback_t metal_clock_callback;
44
45 /*!
46  * @brief Call all callbacks in the linked list, if any are registered
47  */
48 __inline__ void _metal_clock_call_all_callbacks(const metal_clock_callback *const list) {
49     const metal_clock_callback *current = list;
50     while (current) {
51         current->callback(current->priv);
52         current = current->_next;
53     }
54 }
55
56 /*!
57  * @brief Append a callback to the linked list and return the head of the list
58  */
59 __inline__ metal_clock_callback *_metal_clock_append_to_callbacks(metal_clock_callback *list, metal_clock_callback *const cb) {
60     cb->_next = NULL;
61
62     if (!list) {
63         return cb;
64     }
65
66     metal_clock_callback *current = list;
67
68     while ((current->_next) != NULL) {
69         current = current->_next;
70     }
71
72     current->_next = cb;
73
74     return list;
75 }
76
77 /*!
78  * @struct metal_clock
79  * @brief The handle for a clock
80  *
81  * Clocks are defined as a pointer to a `struct metal_clock`, the contents of which
82  * are implementation defined. Users of the clock interface must call functions
83  * which accept a `struct metal_clock *` as an argument to interract with the clock.
84  *
85  * Note that no mechanism for obtaining a pointer to a `struct metal_clock` has been
86  * defined, making it impossible to call any of these functions without invoking
87  * implementation-defined behavior.
88  */
89 struct metal_clock {
90     const struct __metal_clock_vtable *vtable;
91
92     /* Pre-rate change callback linked list */
93     metal_clock_callback *_pre_rate_change_callback;
94
95     /* Post-rate change callback linked list */
96     metal_clock_callback *_post_rate_change_callback;
97 };
98
99 /*!
100  * @brief Returns the current rate of the given clock
101  *
102  * @param clk The handle for the clock
103  * @return The current rate of the clock in Hz
104  */
105 __inline__ long metal_clock_get_rate_hz(const struct metal_clock *clk) { return clk->vtable->get_rate_hz(clk); }
106
107 /*!
108  * @brief Set the current rate of a clock
109  *
110  * @param clk The handle for the clock
111  * @param hz The desired rate in Hz
112  * @return The new rate of the clock in Hz.
113  *
114  * Attempts to set the current rate of the given clock to as close as possible
115  * to the given rate in Hz. Returns the actual value that's been selected, which
116  * could be anything!
117  *
118  * Prior to and after the rate change of the clock, this will call the registered
119  * pre- and post-rate change callbacks.
120  */
121 __inline__ long metal_clock_set_rate_hz(struct metal_clock *clk, long hz)
122 {
123     _metal_clock_call_all_callbacks(clk->_pre_rate_change_callback);
124
125     long out = clk->vtable->set_rate_hz(clk, hz);
126
127     _metal_clock_call_all_callbacks(clk->_post_rate_change_callback);
128
129     return out;
130 }
131
132 /*!
133  * @brief Register a callback that must be called before a rate change
134  *
135  * @param clk The handle for the clock
136  * @param cb The callback to be registered
137  */
138 __inline__ void metal_clock_register_pre_rate_change_callback(struct metal_clock *clk, metal_clock_callback *cb)
139 {
140     clk->_pre_rate_change_callback = _metal_clock_append_to_callbacks(clk->_pre_rate_change_callback, cb);
141 }
142
143 /*!
144  * @brief Registers a callback that must be called after a rate change
145  *
146  * @param clk The handle for the clock
147  * @param cb The callback to be registered
148  */
149 __inline__ void metal_clock_register_post_rate_change_callback(struct metal_clock *clk, metal_clock_callback *cb)
150 {
151     clk->_post_rate_change_callback = _metal_clock_append_to_callbacks(clk->_post_rate_change_callback, cb);
152 }
153
154 #endif