1 /* Copyright 2018 SiFive, Inc */
2 /* SPDX-License-Identifier: Apache-2.0 */
9 * @brief API for manipulating clock sources
11 * The clock interface allows for controlling the rate of various clocks in the system.
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);
25 * @brief Function signature of clock rate change callbacks
27 typedef void (*metal_clock_rate_change_callback)(void *priv);
29 struct _metal_clock_callback_t;
30 struct _metal_clock_callback_t {
31 /* The callback function */
32 metal_clock_rate_change_callback callback;
34 /* Private data for the callback function */
37 struct _metal_clock_callback_t *_next;
41 * @brief Type for the linked list of callbacks for clock rate changes
43 typedef struct _metal_clock_callback_t metal_clock_callback;
46 * @brief Call all callbacks in the linked list, if any are registered
48 __inline__ void _metal_clock_call_all_callbacks(const metal_clock_callback *const list) {
49 const metal_clock_callback *current = list;
51 current->callback(current->priv);
52 current = current->_next;
57 * @brief Append a callback to the linked list and return the head of the list
59 __inline__ metal_clock_callback *_metal_clock_append_to_callbacks(metal_clock_callback *list, metal_clock_callback *const cb) {
66 metal_clock_callback *current = list;
68 while ((current->_next) != NULL) {
69 current = current->_next;
79 * @brief The handle for a clock
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.
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.
90 const struct __metal_clock_vtable *vtable;
92 /* Pre-rate change callback linked list */
93 metal_clock_callback *_pre_rate_change_callback;
95 /* Post-rate change callback linked list */
96 metal_clock_callback *_post_rate_change_callback;
100 * @brief Returns the current rate of the given clock
102 * @param clk The handle for the clock
103 * @return The current rate of the clock in Hz
105 __inline__ long metal_clock_get_rate_hz(const struct metal_clock *clk) { return clk->vtable->get_rate_hz(clk); }
108 * @brief Set the current rate of a clock
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.
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
118 * Prior to and after the rate change of the clock, this will call the registered
119 * pre- and post-rate change callbacks.
121 __inline__ long metal_clock_set_rate_hz(struct metal_clock *clk, long hz)
123 _metal_clock_call_all_callbacks(clk->_pre_rate_change_callback);
125 long out = clk->vtable->set_rate_hz(clk, hz);
127 _metal_clock_call_all_callbacks(clk->_post_rate_change_callback);
133 * @brief Register a callback that must be called before a rate change
135 * @param clk The handle for the clock
136 * @param cb The callback to be registered
138 __inline__ void metal_clock_register_pre_rate_change_callback(struct metal_clock *clk, metal_clock_callback *cb)
140 clk->_pre_rate_change_callback = _metal_clock_append_to_callbacks(clk->_pre_rate_change_callback, cb);
144 * @brief Registers a callback that must be called after a rate change
146 * @param clk The handle for the clock
147 * @param cb The callback to be registered
149 __inline__ void metal_clock_register_post_rate_change_callback(struct metal_clock *clk, metal_clock_callback *cb)
151 clk->_post_rate_change_callback = _metal_clock_append_to_callbacks(clk->_post_rate_change_callback, cb);