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