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 <zephyr/types.h>
25 #include <stddef.h>
26 #include <device.h>
27 #include <sys/__assert.h>
28 #include <sys/slist.h>
29 
30 #ifdef __cplusplus
31 extern "C" {
32 #endif
33 
34 /* Clock control API */
35 
36 /* Used to select all subsystem of a clock controller */
37 #define CLOCK_CONTROL_SUBSYS_ALL	NULL
38 
39 /**
40  * @brief Current clock status.
41  */
42 enum clock_control_status {
43 	CLOCK_CONTROL_STATUS_STARTING,
44 	CLOCK_CONTROL_STATUS_OFF,
45 	CLOCK_CONTROL_STATUS_ON,
46 	CLOCK_CONTROL_STATUS_UNAVAILABLE,
47 	CLOCK_CONTROL_STATUS_UNKNOWN
48 };
49 
50 /**
51  * clock_control_subsys_t is a type to identify a clock controller sub-system.
52  * Such data pointed is opaque and relevant only to the clock controller
53  * driver instance being used.
54  */
55 typedef void *clock_control_subsys_t;
56 
57 /** @brief Callback called on clock started.
58  *
59  * @param dev		Device structure whose driver controls the clock.
60  * @param subsys	Opaque data representing the clock.
61  * @param user_data	User data.
62  */
63 typedef void (*clock_control_cb_t)(const struct device *dev,
64 				   clock_control_subsys_t subsys,
65 				   void *user_data);
66 
67 typedef int (*clock_control)(const struct device *dev,
68 			     clock_control_subsys_t sys);
69 
70 typedef int (*clock_control_get)(const struct device *dev,
71 				 clock_control_subsys_t sys,
72 				 uint32_t *rate);
73 
74 typedef int (*clock_control_async_on_fn)(const struct device *dev,
75 					 clock_control_subsys_t sys,
76 					 clock_control_cb_t cb,
77 					 void *user_data);
78 
79 typedef enum clock_control_status (*clock_control_get_status_fn)(
80 						    const struct device *dev,
81 						    clock_control_subsys_t sys);
82 
83 struct clock_control_driver_api {
84 	clock_control			on;
85 	clock_control			off;
86 	clock_control_async_on_fn	async_on;
87 	clock_control_get		get_rate;
88 	clock_control_get_status_fn	get_status;
89 };
90 
91 /**
92  * @brief Enable a clock controlled by the device
93  *
94  * On success, the clock is enabled and ready when this function
95  * returns. This function may sleep, and thus can only be called from
96  * thread context.
97  *
98  * Use @ref clock_control_async_on() for non-blocking operation.
99  *
100  * @param dev Device structure whose driver controls the clock.
101  * @param sys Opaque data representing the clock.
102  * @return 0 on success, negative errno on failure.
103  */
clock_control_on(const struct device * dev,clock_control_subsys_t sys)104 static inline int clock_control_on(const struct device *dev,
105 				   clock_control_subsys_t sys)
106 {
107 	int ret = device_usable_check(dev);
108 
109 	if (ret != 0) {
110 		return ret;
111 	}
112 
113 	const struct clock_control_driver_api *api =
114 		(const struct clock_control_driver_api *)dev->api;
115 
116 	return api->on(dev, sys);
117 }
118 
119 /**
120  * @brief Disable a clock controlled by the device
121  *
122  * This function is non-blocking and can be called from any context.
123  * On success, the clock is disabled when this function returns.
124  *
125  * @param dev Device structure whose driver controls the clock
126  * @param sys Opaque data representing the clock
127  * @return 0 on success, negative errno on failure.
128  */
clock_control_off(const struct device * dev,clock_control_subsys_t sys)129 static inline int clock_control_off(const struct device *dev,
130 				    clock_control_subsys_t sys)
131 {
132 	int ret = device_usable_check(dev);
133 
134 	if (ret != 0) {
135 		return ret;
136 	}
137 
138 	const struct clock_control_driver_api *api =
139 		(const struct clock_control_driver_api *)dev->api;
140 
141 	return api->off(dev, sys);
142 }
143 
144 /**
145  * @brief Request clock to start with notification when clock has been started.
146  *
147  * Function is non-blocking and can be called from any context. User callback is
148  * called when clock is started.
149  *
150  * @param dev	    Device.
151  * @param sys	    A pointer to an opaque data representing the sub-system.
152  * @param cb	    Callback.
153  * @param user_data User context passed to the callback.
154  *
155  * @retval 0 if start is successfully initiated.
156  * @retval -EALREADY if clock was already started and is starting or running.
157  * @retval -ENOTSUP If the requested mode of operation is not supported.
158  * @retval -ENOSYS if the interface is not implemented.
159  * @retval other negative errno on vendor specific error.
160  */
clock_control_async_on(const struct device * dev,clock_control_subsys_t sys,clock_control_cb_t cb,void * user_data)161 static inline int clock_control_async_on(const struct device *dev,
162 					 clock_control_subsys_t sys,
163 					 clock_control_cb_t cb,
164 					 void *user_data)
165 {
166 	const struct clock_control_driver_api *api =
167 		(const struct clock_control_driver_api *)dev->api;
168 
169 	if (api->async_on == NULL) {
170 		return -ENOSYS;
171 	}
172 
173 	int ret = device_usable_check(dev);
174 
175 	if (ret != 0) {
176 		return ret;
177 	}
178 
179 	return api->async_on(dev, sys, cb, user_data);
180 }
181 
182 /**
183  * @brief Get clock status.
184  *
185  * @param dev Device.
186  * @param sys A pointer to an opaque data representing the sub-system.
187  *
188  * @return Status.
189  */
clock_control_get_status(const struct device * dev,clock_control_subsys_t sys)190 static inline enum clock_control_status clock_control_get_status(const struct device *dev,
191 								 clock_control_subsys_t sys)
192 {
193 	const struct clock_control_driver_api *api =
194 		(const struct clock_control_driver_api *)dev->api;
195 
196 	if (!api->get_status) {
197 		return CLOCK_CONTROL_STATUS_UNKNOWN;
198 	}
199 
200 	if (!device_is_ready(dev)) {
201 		return CLOCK_CONTROL_STATUS_UNAVAILABLE;
202 	}
203 
204 	return api->get_status(dev, sys);
205 }
206 
207 /**
208  * @brief Obtain the clock rate of given sub-system
209  * @param dev Pointer to the device structure for the clock controller driver
210  *        instance
211  * @param sys A pointer to an opaque data representing the sub-system
212  * @param[out] rate Subsystem clock rate
213  */
clock_control_get_rate(const struct device * dev,clock_control_subsys_t sys,uint32_t * rate)214 static inline int clock_control_get_rate(const struct device *dev,
215 					 clock_control_subsys_t sys,
216 					 uint32_t *rate)
217 {
218 	int ret = device_usable_check(dev);
219 
220 	if (ret != 0) {
221 		return ret;
222 	}
223 
224 	const struct clock_control_driver_api *api =
225 		(const struct clock_control_driver_api *)dev->api;
226 
227 	if (api->get_rate == NULL) {
228 		return -ENOSYS;
229 	}
230 
231 	return api->get_rate(dev, sys, rate);
232 }
233 
234 #ifdef __cplusplus
235 }
236 #endif
237 
238 /**
239  * @}
240  */
241 
242 #endif /* ZEPHYR_INCLUDE_DRIVERS_CLOCK_CONTROL_H_ */
243