clock.h 4.3 KB

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