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