1 /*
2  * Copyright (c) 2022 Andrei-Edward Popa <andrei.popa105@yahoo.com>
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 /**
8  * @file
9  * @brief Public Reset Controller driver APIs
10  */
11 
12 #ifndef ZEPHYR_INCLUDE_DRIVERS_RESET_H_
13 #define ZEPHYR_INCLUDE_DRIVERS_RESET_H_
14 
15 /**
16  * @brief Reset Controller Interface
17  * @defgroup reset_controller_interface Reset Controller Interface
18  * @since 3.1
19  * @version 0.2.0
20  * @ingroup io_interfaces
21  * @{
22  */
23 
24 #include <errno.h>
25 
26 #include <zephyr/types.h>
27 #include <zephyr/device.h>
28 
29 #ifdef __cplusplus
30 extern "C" {
31 #endif
32 
33 /** Reset controller device configuration. */
34 struct reset_dt_spec {
35 	/** Reset controller device. */
36 	const struct device *dev;
37 	/** Reset line. */
38 	uint32_t id;
39 };
40 
41 /**
42  * @brief Static initializer for a @p reset_dt_spec
43  *
44  * This returns a static initializer for a @p reset_dt_spec structure given a
45  * devicetree node identifier, a property specifying a Reset Controller and an index.
46  *
47  * Example devicetree fragment:
48  *
49  *	n: node {
50  *		resets = <&reset 10>;
51  *	}
52  *
53  * Example usage:
54  *
55  *	const struct reset_dt_spec spec = RESET_DT_SPEC_GET_BY_IDX(DT_NODELABEL(n), 0);
56  *	// Initializes 'spec' to:
57  *	// {
58  *	//         .dev = DEVICE_DT_GET(DT_NODELABEL(reset)),
59  *	//         .id = 10
60  *	// }
61  *
62  * The 'reset' field must still be checked for readiness, e.g. using
63  * device_is_ready(). It is an error to use this macro unless the node
64  * exists, has the given property, and that property specifies a reset
65  * controller reset line id as shown above.
66  *
67  * @param node_id devicetree node identifier
68  * @param idx logical index into "resets"
69  * @return static initializer for a struct reset_dt_spec for the property
70  */
71 #define RESET_DT_SPEC_GET_BY_IDX(node_id, idx)					\
72 	{									\
73 		.dev = DEVICE_DT_GET(DT_RESET_CTLR_BY_IDX(node_id, idx)),	\
74 		.id = DT_RESET_ID_BY_IDX(node_id, idx)				\
75 	}
76 
77 /**
78  * @brief Like RESET_DT_SPEC_GET_BY_IDX(), with a fallback to a default value
79  *
80  * If the devicetree node identifier 'node_id' refers to a node with a
81  * 'resets' property, this expands to
82  * <tt>RESET_DT_SPEC_GET_BY_IDX(node_id, idx)</tt>. The @p
83  * default_value parameter is not expanded in this case.
84  *
85  * Otherwise, this expands to @p default_value.
86  *
87  * @param node_id devicetree node identifier
88  * @param idx logical index into the 'resets' property
89  * @param default_value fallback value to expand to
90  * @return static initializer for a struct reset_dt_spec for the property,
91  *         or default_value if the node or property do not exist
92  */
93 #define RESET_DT_SPEC_GET_BY_IDX_OR(node_id, idx, default_value)	\
94 	COND_CODE_1(DT_NODE_HAS_PROP(node_id, resets),			\
95 		    (RESET_DT_SPEC_GET_BY_IDX(node_id, idx)),		\
96 		    (default_value))
97 
98 /**
99  * @brief Equivalent to RESET_DT_SPEC_GET_BY_IDX(node_id, 0).
100  *
101  * @param node_id devicetree node identifier
102  * @return static initializer for a struct reset_dt_spec for the property
103  * @see RESET_DT_SPEC_GET_BY_IDX()
104  */
105 #define RESET_DT_SPEC_GET(node_id) \
106 	RESET_DT_SPEC_GET_BY_IDX(node_id, 0)
107 
108 /**
109  * @brief Equivalent to
110  *	  RESET_DT_SPEC_GET_BY_IDX_OR(node_id, 0, default_value).
111  *
112  * @param node_id devicetree node identifier
113  * @param default_value fallback value to expand to
114  * @return static initializer for a struct reset_dt_spec for the property,
115  *         or default_value if the node or property do not exist
116  */
117 #define RESET_DT_SPEC_GET_OR(node_id, default_value)			\
118 	RESET_DT_SPEC_GET_BY_IDX_OR(node_id, 0, default_value)
119 
120 /**
121  * @brief Static initializer for a @p reset_dt_spec from a DT_DRV_COMPAT
122  * instance's Reset Controller property at an index.
123  *
124  * @param inst DT_DRV_COMPAT instance number
125  * @param idx logical index into "resets"
126  * @return static initializer for a struct reset_dt_spec for the property
127  * @see RESET_DT_SPEC_GET_BY_IDX()
128  */
129 #define RESET_DT_SPEC_INST_GET_BY_IDX(inst, idx) \
130 	RESET_DT_SPEC_GET_BY_IDX(DT_DRV_INST(inst), idx)
131 
132 /**
133  * @brief Static initializer for a @p reset_dt_spec from a DT_DRV_COMPAT
134  *	  instance's 'resets' property at an index, with fallback
135  *
136  * @param inst DT_DRV_COMPAT instance number
137  * @param idx logical index into the 'resets' property
138  * @param default_value fallback value to expand to
139  * @return static initializer for a struct reset_dt_spec for the property,
140  *         or default_value if the node or property do not exist
141  */
142 #define RESET_DT_SPEC_INST_GET_BY_IDX_OR(inst, idx, default_value)	\
143 	COND_CODE_1(DT_PROP_HAS_IDX(DT_DRV_INST(inst), resets, idx),	\
144 		    (RESET_DT_SPEC_GET_BY_IDX(DT_DRV_INST(inst), idx)),	\
145 		    (default_value))
146 
147 /**
148  * @brief Equivalent to RESET_DT_SPEC_INST_GET_BY_IDX(inst, 0).
149  *
150  * @param inst DT_DRV_COMPAT instance number
151  * @return static initializer for a struct reset_dt_spec for the property
152  * @see RESET_DT_SPEC_INST_GET_BY_IDX()
153  */
154 #define RESET_DT_SPEC_INST_GET(inst) \
155 	RESET_DT_SPEC_INST_GET_BY_IDX(inst, 0)
156 
157 /**
158  * @brief Equivalent to
159  *	  RESET_DT_SPEC_INST_GET_BY_IDX_OR(node_id, 0, default_value).
160  *
161  * @param inst DT_DRV_COMPAT instance number
162  * @param default_value fallback value to expand to
163  * @return static initializer for a struct reset_dt_spec for the property,
164  *         or default_value if the node or property do not exist
165  */
166 #define RESET_DT_SPEC_INST_GET_OR(inst, default_value)			\
167 	RESET_DT_SPEC_INST_GET_BY_IDX_OR(inst, 0, default_value)
168 
169 /** @cond INTERNAL_HIDDEN */
170 
171 /**
172  * API template to get the reset status of the device.
173  *
174  * @see reset_status
175  */
176 typedef int (*reset_api_status)(const struct device *dev, uint32_t id, uint8_t *status);
177 
178 /**
179  * API template to put the device in reset state.
180  *
181  * @see reset_line_assert
182  */
183 typedef int (*reset_api_line_assert)(const struct device *dev, uint32_t id);
184 
185 /**
186  * API template to take out the device from reset state.
187  *
188  * @see reset_line_deassert
189  */
190 typedef int (*reset_api_line_deassert)(const struct device *dev, uint32_t id);
191 
192 /**
193  * API template to reset the device.
194  *
195  * @see reset_line_toggle
196  */
197 typedef int (*reset_api_line_toggle)(const struct device *dev, uint32_t id);
198 
199 /**
200  * @brief Reset Controller driver API
201  */
202 __subsystem struct reset_driver_api {
203 	reset_api_status status;
204 	reset_api_line_assert line_assert;
205 	reset_api_line_deassert line_deassert;
206 	reset_api_line_toggle line_toggle;
207 };
208 
209 /** @endcond */
210 
211 /**
212  * @brief Get the reset status
213  *
214  * This function returns the reset status of the device.
215  *
216  * @param dev Reset controller device.
217  * @param id Reset line.
218  * @param status Where to write the reset status.
219  *
220  * @retval 0 On success.
221  * @retval -ENOSYS If the functionality is not implemented by the driver.
222  * @retval -errno Other negative errno in case of failure.
223  */
224 __syscall int reset_status(const struct device *dev, uint32_t id, uint8_t *status);
225 
z_impl_reset_status(const struct device * dev,uint32_t id,uint8_t * status)226 static inline int z_impl_reset_status(const struct device *dev, uint32_t id, uint8_t *status)
227 {
228 	const struct reset_driver_api *api = (const struct reset_driver_api *)dev->api;
229 
230 	if (api->status == NULL) {
231 		return -ENOSYS;
232 	}
233 
234 	return api->status(dev, id, status);
235 }
236 
237 /**
238  * @brief Get the reset status from a @p reset_dt_spec.
239  *
240  * This is equivalent to:
241  *
242  *    reset_status(spec->dev, spec->id, status);
243  *
244  * @param spec Reset controller specification from devicetree
245  * @param status Where to write the reset status.
246  *
247  * @return a value from reset_status()
248  */
reset_status_dt(const struct reset_dt_spec * spec,uint8_t * status)249 static inline int reset_status_dt(const struct reset_dt_spec *spec, uint8_t *status)
250 {
251 	return reset_status(spec->dev, spec->id, status);
252 }
253 
254 /**
255  * @brief Put the device in reset state
256  *
257  * This function sets/clears the reset bits of the device,
258  * depending on the logic level (active-high/active-low).
259  *
260  * @param dev Reset controller device.
261  * @param id Reset line.
262  *
263  * @retval 0 On success.
264  * @retval -ENOSYS If the functionality is not implemented by the driver.
265  * @retval -errno Other negative errno in case of failure.
266  */
267 __syscall int reset_line_assert(const struct device *dev, uint32_t id);
268 
z_impl_reset_line_assert(const struct device * dev,uint32_t id)269 static inline int z_impl_reset_line_assert(const struct device *dev, uint32_t id)
270 {
271 	const struct reset_driver_api *api = (const struct reset_driver_api *)dev->api;
272 
273 	if (api->line_assert == NULL) {
274 		return -ENOSYS;
275 	}
276 
277 	return api->line_assert(dev, id);
278 }
279 
280 /**
281  * @brief Assert the reset state from a @p reset_dt_spec.
282  *
283  * This is equivalent to:
284  *
285  *     reset_line_assert(spec->dev, spec->id);
286  *
287  * @param spec Reset controller specification from devicetree
288  *
289  * @return a value from reset_line_assert()
290  */
reset_line_assert_dt(const struct reset_dt_spec * spec)291 static inline int reset_line_assert_dt(const struct reset_dt_spec *spec)
292 {
293 	return reset_line_assert(spec->dev, spec->id);
294 }
295 
296 /**
297  * @brief Take out the device from reset state.
298  *
299  * This function sets/clears the reset bits of the device,
300  * depending on the logic level (active-low/active-high).
301  *
302  * @param dev Reset controller device.
303  * @param id Reset line.
304  *
305  * @retval 0 On success.
306  * @retval -ENOSYS If the functionality is not implemented by the driver.
307  * @retval -errno Other negative errno in case of failure.
308  */
309 __syscall int reset_line_deassert(const struct device *dev, uint32_t id);
310 
z_impl_reset_line_deassert(const struct device * dev,uint32_t id)311 static inline int z_impl_reset_line_deassert(const struct device *dev, uint32_t id)
312 {
313 	const struct reset_driver_api *api = (const struct reset_driver_api *)dev->api;
314 
315 	if (api->line_deassert == NULL) {
316 		return -ENOSYS;
317 	}
318 
319 	return api->line_deassert(dev, id);
320 }
321 
322 /**
323  * @brief Deassert the reset state from a @p reset_dt_spec.
324  *
325  * This is equivalent to:
326  *
327  *     reset_line_deassert(spec->dev, spec->id)
328  *
329  * @param spec Reset controller specification from devicetree
330  *
331  * @return a value from reset_line_deassert()
332  */
reset_line_deassert_dt(const struct reset_dt_spec * spec)333 static inline int reset_line_deassert_dt(const struct reset_dt_spec *spec)
334 {
335 	return reset_line_deassert(spec->dev, spec->id);
336 }
337 
338 /**
339  * @brief Reset the device.
340  *
341  * This function performs reset for a device (assert + deassert).
342  *
343  * @param dev Reset controller device.
344  * @param id Reset line.
345  *
346  * @retval 0 On success.
347  * @retval -ENOSYS If the functionality is not implemented by the driver.
348  * @retval -errno Other negative errno in case of failure.
349  */
350 __syscall int reset_line_toggle(const struct device *dev, uint32_t id);
351 
z_impl_reset_line_toggle(const struct device * dev,uint32_t id)352 static inline int z_impl_reset_line_toggle(const struct device *dev, uint32_t id)
353 {
354 	const struct reset_driver_api *api = (const struct reset_driver_api *)dev->api;
355 
356 	if (api->line_toggle == NULL) {
357 		return -ENOSYS;
358 	}
359 
360 	return api->line_toggle(dev, id);
361 }
362 
363 /**
364  * @brief Reset the device from a @p reset_dt_spec.
365  *
366  * This is equivalent to:
367  *
368  *     reset_line_toggle(spec->dev, spec->id)
369  *
370  * @param spec Reset controller specification from devicetree
371  *
372  * @return a value from reset_line_toggle()
373  */
reset_line_toggle_dt(const struct reset_dt_spec * spec)374 static inline int reset_line_toggle_dt(const struct reset_dt_spec *spec)
375 {
376 	return reset_line_toggle(spec->dev, spec->id);
377 }
378 
379 /**
380  * @}
381  */
382 
383 #ifdef __cplusplus
384 }
385 #endif
386 
387 #include <zephyr/syscalls/reset.h>
388 
389 #endif /* ZEPHYR_INCLUDE_DRIVERS_RESET_H_ */
390