1 /* clock_control.h - public clock controller driver API */
2
3 /*
4 * Copyright (c) 2015 Intel Corporation
5 *
6 * SPDX-License-Identifier: Apache-2.0
7 */
8
9 /**
10 * @file
11 * @brief Public Clock Control APIs
12 */
13
14 #ifndef ZEPHYR_INCLUDE_DRIVERS_CLOCK_CONTROL_H_
15 #define ZEPHYR_INCLUDE_DRIVERS_CLOCK_CONTROL_H_
16
17 /**
18 * @brief Clock Control Interface
19 * @defgroup clock_control_interface Clock Control Interface
20 * @ingroup io_interfaces
21 * @{
22 */
23
24 #include <errno.h>
25 #include <stddef.h>
26
27 #include <zephyr/types.h>
28 #include <zephyr/device.h>
29 #include <zephyr/sys/__assert.h>
30 #include <zephyr/sys/slist.h>
31
32 #ifdef __cplusplus
33 extern "C" {
34 #endif
35
36 /* Clock control API */
37
38 /* Used to select all subsystem of a clock controller */
39 #define CLOCK_CONTROL_SUBSYS_ALL NULL
40
41 /**
42 * @brief Current clock status.
43 */
44 enum clock_control_status {
45 CLOCK_CONTROL_STATUS_STARTING,
46 CLOCK_CONTROL_STATUS_OFF,
47 CLOCK_CONTROL_STATUS_ON,
48 CLOCK_CONTROL_STATUS_UNKNOWN
49 };
50
51 /**
52 * clock_control_subsys_t is a type to identify a clock controller sub-system.
53 * Such data pointed is opaque and relevant only to the clock controller
54 * driver instance being used.
55 */
56 typedef void *clock_control_subsys_t;
57
58 /**
59 * clock_control_subsys_rate_t is a type to identify a clock
60 * controller sub-system rate. Such data pointed is opaque and
61 * relevant only to set the clock controller rate of the driver
62 * instance being used.
63 */
64 typedef void *clock_control_subsys_rate_t;
65
66 /** @brief Callback called on clock started.
67 *
68 * @param dev Device structure whose driver controls the clock.
69 * @param subsys Opaque data representing the clock.
70 * @param user_data User data.
71 */
72 typedef void (*clock_control_cb_t)(const struct device *dev,
73 clock_control_subsys_t subsys,
74 void *user_data);
75
76 typedef int (*clock_control)(const struct device *dev,
77 clock_control_subsys_t sys);
78
79 typedef int (*clock_control_get)(const struct device *dev,
80 clock_control_subsys_t sys,
81 uint32_t *rate);
82
83 typedef int (*clock_control_async_on_fn)(const struct device *dev,
84 clock_control_subsys_t sys,
85 clock_control_cb_t cb,
86 void *user_data);
87
88 typedef enum clock_control_status (*clock_control_get_status_fn)(
89 const struct device *dev,
90 clock_control_subsys_t sys);
91
92 typedef int (*clock_control_set)(const struct device *dev,
93 clock_control_subsys_t sys,
94 clock_control_subsys_rate_t rate);
95
96 typedef int (*clock_control_configure_fn)(const struct device *dev,
97 clock_control_subsys_t sys,
98 void *data);
99
100 struct clock_control_driver_api {
101 clock_control on;
102 clock_control off;
103 clock_control_async_on_fn async_on;
104 clock_control_get get_rate;
105 clock_control_get_status_fn get_status;
106 clock_control_set set_rate;
107 clock_control_configure_fn configure;
108 };
109
110 /**
111 * @brief Enable a clock controlled by the device
112 *
113 * On success, the clock is enabled and ready when this function
114 * returns. This function may sleep, and thus can only be called from
115 * thread context.
116 *
117 * Use @ref clock_control_async_on() for non-blocking operation.
118 *
119 * @param dev Device structure whose driver controls the clock.
120 * @param sys Opaque data representing the clock.
121 * @return 0 on success, negative errno on failure.
122 */
clock_control_on(const struct device * dev,clock_control_subsys_t sys)123 static inline int clock_control_on(const struct device *dev,
124 clock_control_subsys_t sys)
125 {
126 const struct clock_control_driver_api *api =
127 (const struct clock_control_driver_api *)dev->api;
128
129 return api->on(dev, sys);
130 }
131
132 /**
133 * @brief Disable a clock controlled by the device
134 *
135 * This function is non-blocking and can be called from any context.
136 * On success, the clock is disabled when this function returns.
137 *
138 * @param dev Device structure whose driver controls the clock
139 * @param sys Opaque data representing the clock
140 * @return 0 on success, negative errno on failure.
141 */
clock_control_off(const struct device * dev,clock_control_subsys_t sys)142 static inline int clock_control_off(const struct device *dev,
143 clock_control_subsys_t sys)
144 {
145 const struct clock_control_driver_api *api =
146 (const struct clock_control_driver_api *)dev->api;
147
148 return api->off(dev, sys);
149 }
150
151 /**
152 * @brief Request clock to start with notification when clock has been started.
153 *
154 * Function is non-blocking and can be called from any context. User callback is
155 * called when clock is started.
156 *
157 * @param dev Device.
158 * @param sys A pointer to an opaque data representing the sub-system.
159 * @param cb Callback.
160 * @param user_data User context passed to the callback.
161 *
162 * @retval 0 if start is successfully initiated.
163 * @retval -EALREADY if clock was already started and is starting or running.
164 * @retval -ENOTSUP If the requested mode of operation is not supported.
165 * @retval -ENOSYS if the interface is not implemented.
166 * @retval other negative errno on vendor specific error.
167 */
clock_control_async_on(const struct device * dev,clock_control_subsys_t sys,clock_control_cb_t cb,void * user_data)168 static inline int clock_control_async_on(const struct device *dev,
169 clock_control_subsys_t sys,
170 clock_control_cb_t cb,
171 void *user_data)
172 {
173 const struct clock_control_driver_api *api =
174 (const struct clock_control_driver_api *)dev->api;
175
176 if (api->async_on == NULL) {
177 return -ENOSYS;
178 }
179
180 return api->async_on(dev, sys, cb, user_data);
181 }
182
183 /**
184 * @brief Get clock status.
185 *
186 * @param dev Device.
187 * @param sys A pointer to an opaque data representing the sub-system.
188 *
189 * @return Status.
190 */
clock_control_get_status(const struct device * dev,clock_control_subsys_t sys)191 static inline enum clock_control_status clock_control_get_status(const struct device *dev,
192 clock_control_subsys_t sys)
193 {
194 const struct clock_control_driver_api *api =
195 (const struct clock_control_driver_api *)dev->api;
196
197 if (!api->get_status) {
198 return CLOCK_CONTROL_STATUS_UNKNOWN;
199 }
200
201 return api->get_status(dev, sys);
202 }
203
204 /**
205 * @brief Obtain the clock rate of given sub-system
206 * @param dev Pointer to the device structure for the clock controller driver
207 * instance
208 * @param sys A pointer to an opaque data representing the sub-system
209 * @param[out] rate Subsystem clock rate
210 * @retval 0 on successful rate reading.
211 * @retval -EAGAIN if rate cannot be read. Some drivers do not support returning the rate when the
212 * clock is off.
213 * @retval -ENOTSUP if reading the clock rate is not supported for the given sub-system.
214 * @retval -ENOSYS if the interface is not implemented.
215 */
clock_control_get_rate(const struct device * dev,clock_control_subsys_t sys,uint32_t * rate)216 static inline int clock_control_get_rate(const struct device *dev,
217 clock_control_subsys_t sys,
218 uint32_t *rate)
219 {
220 const struct clock_control_driver_api *api =
221 (const struct clock_control_driver_api *)dev->api;
222
223 if (api->get_rate == NULL) {
224 return -ENOSYS;
225 }
226
227 return api->get_rate(dev, sys, rate);
228 }
229
230 /**
231 * @brief Set the rate of the clock controlled by the device.
232 *
233 * On success, the new clock rate is set and ready when this function
234 * returns. This function may sleep, and thus can only be called from
235 * thread context.
236 *
237 * @param dev Device structure whose driver controls the clock.
238 * @param sys Opaque data representing the clock.
239 * @param rate Opaque data representing the clock rate to be used.
240 *
241 * @retval -EALREADY if clock was already in the given rate.
242 * @retval -ENOTSUP If the requested mode of operation is not supported.
243 * @retval -ENOSYS if the interface is not implemented.
244 * @retval other negative errno on vendor specific error.
245 */
clock_control_set_rate(const struct device * dev,clock_control_subsys_t sys,clock_control_subsys_rate_t rate)246 static inline int clock_control_set_rate(const struct device *dev,
247 clock_control_subsys_t sys,
248 clock_control_subsys_rate_t rate)
249 {
250 const struct clock_control_driver_api *api =
251 (const struct clock_control_driver_api *)dev->api;
252
253 if (api->set_rate == NULL) {
254 return -ENOSYS;
255 }
256
257 return api->set_rate(dev, sys, rate);
258 }
259
260 /**
261 * @brief Configure a source clock
262 *
263 * This function is non-blocking and can be called from any context.
264 * On success, the selected clock is configured as per caller's request.
265 *
266 * It is caller's responsibility to ensure that subsequent calls to the API
267 * provide the right information to allows clock_control driver to perform
268 * the right action (such as using the right clock source on clock_control_get_rate
269 * call).
270 *
271 * @p data is implementation specific and could be used to convey
272 * supplementary information required for expected clock configuration.
273 *
274 * @param dev Device structure whose driver controls the clock
275 * @param sys Opaque data representing the clock
276 * @param data Opaque data providing additional input for clock configuration
277 *
278 * @retval 0 On success
279 * @retval -ENOSYS If the device driver does not implement this call
280 * @retval -errno Other negative errno on failure.
281 */
clock_control_configure(const struct device * dev,clock_control_subsys_t sys,void * data)282 static inline int clock_control_configure(const struct device *dev,
283 clock_control_subsys_t sys,
284 void *data)
285 {
286 const struct clock_control_driver_api *api =
287 (const struct clock_control_driver_api *)dev->api;
288
289 if (api->configure == NULL) {
290 return -ENOSYS;
291 }
292
293 return api->configure(dev, sys, data);
294 }
295
296 #ifdef __cplusplus
297 }
298 #endif
299
300 /**
301 * @}
302 */
303
304 #endif /* ZEPHYR_INCLUDE_DRIVERS_CLOCK_CONTROL_H_ */
305