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 	if (api->on == NULL) {
132 		return -ENOSYS;
133 	}
134 
135 	return api->on(dev, sys);
136 }
137 
138 /**
139  * @brief Disable a clock controlled by the device
140  *
141  * This function is non-blocking and can be called from any context.
142  * On success, the clock is disabled when this function returns.
143  *
144  * @param dev Device structure whose driver controls the clock
145  * @param sys Opaque data representing the clock
146  * @return 0 on success, negative errno on failure.
147  */
clock_control_off(const struct device * dev,clock_control_subsys_t sys)148 static inline int clock_control_off(const struct device *dev,
149 				    clock_control_subsys_t sys)
150 {
151 	const struct clock_control_driver_api *api =
152 		(const struct clock_control_driver_api *)dev->api;
153 
154 	if (api->off == NULL) {
155 		return -ENOSYS;
156 	}
157 
158 	return api->off(dev, sys);
159 }
160 
161 /**
162  * @brief Request clock to start with notification when clock has been started.
163  *
164  * Function is non-blocking and can be called from any context. User callback is
165  * called when clock is started.
166  *
167  * @param dev	    Device.
168  * @param sys	    A pointer to an opaque data representing the sub-system.
169  * @param cb	    Callback.
170  * @param user_data User context passed to the callback.
171  *
172  * @retval 0 if start is successfully initiated.
173  * @retval -EALREADY if clock was already started and is starting or running.
174  * @retval -ENOTSUP If the requested mode of operation is not supported.
175  * @retval -ENOSYS if the interface is not implemented.
176  * @retval other negative errno on vendor specific error.
177  */
clock_control_async_on(const struct device * dev,clock_control_subsys_t sys,clock_control_cb_t cb,void * user_data)178 static inline int clock_control_async_on(const struct device *dev,
179 					 clock_control_subsys_t sys,
180 					 clock_control_cb_t cb,
181 					 void *user_data)
182 {
183 	const struct clock_control_driver_api *api =
184 		(const struct clock_control_driver_api *)dev->api;
185 
186 	if (api->async_on == NULL) {
187 		return -ENOSYS;
188 	}
189 
190 	return api->async_on(dev, sys, cb, user_data);
191 }
192 
193 /**
194  * @brief Get clock status.
195  *
196  * @param dev Device.
197  * @param sys A pointer to an opaque data representing the sub-system.
198  *
199  * @return Status.
200  */
clock_control_get_status(const struct device * dev,clock_control_subsys_t sys)201 static inline enum clock_control_status clock_control_get_status(const struct device *dev,
202 								 clock_control_subsys_t sys)
203 {
204 	const struct clock_control_driver_api *api =
205 		(const struct clock_control_driver_api *)dev->api;
206 
207 	if (!api->get_status) {
208 		return CLOCK_CONTROL_STATUS_UNKNOWN;
209 	}
210 
211 	return api->get_status(dev, sys);
212 }
213 
214 /**
215  * @brief Obtain the clock rate of given sub-system
216  * @param dev Pointer to the device structure for the clock controller driver
217  *        instance
218  * @param sys A pointer to an opaque data representing the sub-system
219  * @param[out] rate Subsystem clock rate
220  * @retval 0 on successful rate reading.
221  * @retval -EAGAIN if rate cannot be read. Some drivers do not support returning the rate when the
222  *         clock is off.
223  * @retval -ENOTSUP if reading the clock rate is not supported for the given sub-system.
224  * @retval -ENOSYS if the interface is not implemented.
225  */
clock_control_get_rate(const struct device * dev,clock_control_subsys_t sys,uint32_t * rate)226 static inline int clock_control_get_rate(const struct device *dev,
227 					 clock_control_subsys_t sys,
228 					 uint32_t *rate)
229 {
230 	const struct clock_control_driver_api *api =
231 		(const struct clock_control_driver_api *)dev->api;
232 
233 	if (api->get_rate == NULL) {
234 		return -ENOSYS;
235 	}
236 
237 	return api->get_rate(dev, sys, rate);
238 }
239 
240 /**
241  * @brief Set the rate of the clock controlled by the device.
242  *
243  * On success, the new clock rate is set and ready when this function
244  * returns. This function may sleep, and thus can only be called from
245  * thread context.
246  *
247  * @param dev Device structure whose driver controls the clock.
248  * @param sys Opaque data representing the clock.
249  * @param rate Opaque data representing the clock rate to be used.
250  *
251  * @retval -EALREADY if clock was already in the given rate.
252  * @retval -ENOTSUP If the requested mode of operation is not supported.
253  * @retval -ENOSYS if the interface is not implemented.
254  * @retval other negative errno on vendor specific error.
255  */
clock_control_set_rate(const struct device * dev,clock_control_subsys_t sys,clock_control_subsys_rate_t rate)256 static inline int clock_control_set_rate(const struct device *dev,
257 		clock_control_subsys_t sys,
258 		clock_control_subsys_rate_t rate)
259 {
260 	const struct clock_control_driver_api *api =
261 		(const struct clock_control_driver_api *)dev->api;
262 
263 	if (api->set_rate == NULL) {
264 		return -ENOSYS;
265 	}
266 
267 	return api->set_rate(dev, sys, rate);
268 }
269 
270 /**
271  * @brief Configure a source clock
272  *
273  * This function is non-blocking and can be called from any context.
274  * On success, the selected clock is configured as per caller's request.
275  *
276  * It is caller's responsibility to ensure that subsequent calls to the API
277  * provide the right information to allows clock_control driver to perform
278  * the right action (such as using the right clock source on clock_control_get_rate
279  * call).
280  *
281  * @p data is implementation specific and could be used to convey
282  * supplementary information required for expected clock configuration.
283  *
284  * @param dev Device structure whose driver controls the clock
285  * @param sys Opaque data representing the clock
286  * @param data Opaque data providing additional input for clock configuration
287  *
288  * @retval 0 On success
289  * @retval -ENOSYS If the device driver does not implement this call
290  * @retval -errno Other negative errno on failure.
291  */
clock_control_configure(const struct device * dev,clock_control_subsys_t sys,void * data)292 static inline int clock_control_configure(const struct device *dev,
293 					  clock_control_subsys_t sys,
294 					  void *data)
295 {
296 	const struct clock_control_driver_api *api =
297 		(const struct clock_control_driver_api *)dev->api;
298 
299 	if (api->configure == NULL) {
300 		return -ENOSYS;
301 	}
302 
303 	return api->configure(dev, sys, data);
304 }
305 
306 #ifdef __cplusplus
307 }
308 #endif
309 
310 /**
311  * @}
312  */
313 
314 #endif /* ZEPHYR_INCLUDE_DRIVERS_CLOCK_CONTROL_H_ */
315