summaryrefslogtreecommitdiff
path: root/FreeRTOS/Demo/RISC-V_RV32_SiFive_HiFive1_FreedomStudio/freedom-metal/metal/clock.h
blob: 277841e0125712ef72f8508dbc31bebdbe1bac0a (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
/* Copyright 2018 SiFive, Inc */
/* SPDX-License-Identifier: Apache-2.0 */

#ifndef METAL__CLOCK_H
#define METAL__CLOCK_H

/*! 
 * @file clock.h
 * @brief API for manipulating clock sources
 *
 * The clock interface allows for controlling the rate of various clocks in the system.
 */

struct metal_clock;

#include <stddef.h>

/* The generic interface to all clocks. */
struct __metal_clock_vtable {
    long (*get_rate_hz)(const struct metal_clock *clk);
    long (*set_rate_hz)(struct metal_clock *clk, long hz);
};

/*!
 * @brief Function signature of clock pre-rate change callbacks
 */
typedef void (*metal_clock_pre_rate_change_callback)(void *priv);

/*!
 * @brief Function signature of clock post-rate change callbacks
 */
typedef void (*metal_clock_post_rate_change_callback)(void *priv);

/*!
 * @struct metal_clock
 * @brief The handle for a clock
 *
 * Clocks are defined as a pointer to a `struct metal_clock`, the contents of which
 * are implementation defined. Users of the clock interface must call functions
 * which accept a `struct metal_clock *` as an argument to interract with the clock.
 *
 * Note that no mechanism for obtaining a pointer to a `struct metal_clock` has been
 * defined, making it impossible to call any of these functions without invoking
 * implementation-defined behavior.
 */
struct metal_clock {
    const struct __metal_clock_vtable *vtable;

    /* Pre-rate change callback */
    metal_clock_pre_rate_change_callback _pre_rate_change_callback;
    void *_pre_rate_change_callback_priv;

    /* Post-rate change callback */
    metal_clock_post_rate_change_callback _post_rate_change_callback;
    void *_post_rate_change_callback_priv;
};

/*!
 * @brief Returns the current rate of the given clock
 *
 * @param clk The handle for the clock
 * @return The current rate of the clock in Hz
 */
inline long metal_clock_get_rate_hz(const struct metal_clock *clk) { return clk->vtable->get_rate_hz(clk); }

/*!
 * @brief Set the current rate of a clock
 *
 * @param clk The handle for the clock
 * @param hz The desired rate in Hz
 * @return The new rate of the clock in Hz.
 *
 * Attempts to set the current rate of the given clock to as close as possible
 * to the given rate in Hz. Returns the actual value that's been selected, which
 * could be anything!
 *
 * Prior to and after the rate change of the clock, this will call the registered
 * pre- and post-rate change callbacks.
 */
inline long metal_clock_set_rate_hz(struct metal_clock *clk, long hz)
{
    if(clk->_pre_rate_change_callback != NULL)
        clk->_pre_rate_change_callback(clk->_pre_rate_change_callback_priv);

    long out = clk->vtable->set_rate_hz(clk, hz);

    if (clk->_post_rate_change_callback != NULL)
        clk->_post_rate_change_callback(clk->_post_rate_change_callback_priv);

    return out;
}

/*!
 * @brief Register a callback that must be called before a rate change
 *
 * @param clk The handle for the clock
 * @param cb The callback to be registered
 * @param priv Private data for the callback handler
 */
inline void metal_clock_register_pre_rate_change_callback(struct metal_clock *clk, metal_clock_pre_rate_change_callback cb, void *priv)
{
    clk->_pre_rate_change_callback = cb;
    clk->_pre_rate_change_callback_priv = priv;
}

/*!
 * @brief Registers a callback that must be called after a rate change
 *
 * @param clk The handle for the clock
 * @param cb The callback to be registered
 * @param priv Private data for the callback handler
 */
inline void metal_clock_register_post_rate_change_callback(struct metal_clock *clk, metal_clock_post_rate_change_callback cb, void *priv)
{
    clk->_post_rate_change_callback = cb;
    clk->_post_rate_change_callback_priv = priv;
}

#endif