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  * @ingroup io_interfaces
19  * @{
20  */
21 
22 #include <errno.h>
23 
24 #include <zephyr/types.h>
25 #include <zephyr/device.h>
26 
27 #ifdef __cplusplus
28 extern "C" {
29 #endif
30 
31 /** Reset controller device configuration. */
32 struct reset_dt_spec {
33 	/** Reset controller device. */
34 	const struct device *dev;
35 	/** Reset line. */
36 	uint32_t id;
37 };
38 
39 /**
40  * @brief Static initializer for a @p reset_dt_spec
41  *
42  * This returns a static initializer for a @p reset_dt_spec structure given a
43  * devicetree node identifier, a property specifying a Reset Controller and an index.
44  *
45  * Example devicetree fragment:
46  *
47  *	n: node {
48  *		resets = <&reset 10>;
49  *	}
50  *
51  * Example usage:
52  *
53  *	const struct reset_dt_spec spec = RESET_DT_SPEC_GET_BY_IDX(DT_NODELABEL(n), 0);
54  *	// Initializes 'spec' to:
55  *	// {
56  *	//         .dev = DEVICE_DT_GET(DT_NODELABEL(reset)),
57  *	//         .id = 10
58  *	// }
59  *
60  * The 'reset' field must still be checked for readiness, e.g. using
61  * device_is_ready(). It is an error to use this macro unless the node
62  * exists, has the given property, and that property specifies a reset
63  * controller reset line id as shown above.
64  *
65  * @param node_id devicetree node identifier
66  * @param idx logical index into "resets"
67  * @return static initializer for a struct reset_dt_spec for the property
68  */
69 #define RESET_DT_SPEC_GET_BY_IDX(node_id, idx)					\
70 	{									\
71 		.dev = DEVICE_DT_GET(DT_RESET_CTLR_BY_IDX(node_id, idx)),	\
72 		.id = DT_RESET_ID_BY_IDX(node_id, idx)				\
73 	}
74 
75 /**
76  * @brief Equivalent to RESET_DT_SPEC_GET_BY_IDX(node_id, 0).
77  *
78  * @param node_id devicetree node identifier
79  * @return static initializer for a struct reset_dt_spec for the property
80  * @see RESET_DT_SPEC_GET_BY_IDX()
81  */
82 #define RESET_DT_SPEC_GET(node_id) \
83 	RESET_DT_SPEC_GET_BY_IDX(node_id, 0)
84 
85 /**
86  * @brief Static initializer for a @p reset_dt_spec from a DT_DRV_COMPAT
87  * instance's Reset Controller property at an index.
88  *
89  * @param inst DT_DRV_COMPAT instance number
90  * @param idx logical index into "resets"
91  * @return static initializer for a struct reset_dt_spec for the property
92  * @see RESET_DT_SPEC_GET_BY_IDX()
93  */
94 #define RESET_DT_SPEC_INST_GET_BY_IDX(inst, idx) \
95 	RESET_DT_SPEC_GET_BY_IDX(DT_DRV_INST(inst), idx)
96 
97 /**
98  * @brief Equivalent to RESET_DT_SPEC_INST_GET_BY_IDX(inst, 0).
99  *
100  * @param inst DT_DRV_COMPAT instance number
101  * @return static initializer for a struct reset_dt_spec for the property
102  * @see RESET_DT_SPEC_INST_GET_BY_IDX()
103  */
104 #define RESET_DT_SPEC_INST_GET(inst) \
105 	RESET_DT_SPEC_INST_GET_BY_IDX(inst, 0)
106 
107 /** @cond INTERNAL_HIDDEN */
108 
109 /**
110  * API template to get the reset status of the device.
111  *
112  * @see reset_status
113  */
114 typedef int (*reset_api_status)(const struct device *dev, uint32_t id, uint8_t *status);
115 
116 /**
117  * API template to put the device in reset state.
118  *
119  * @see reset_line_assert
120  */
121 typedef int (*reset_api_line_assert)(const struct device *dev, uint32_t id);
122 
123 /**
124  * API template to take out the device from reset state.
125  *
126  * @see reset_line_deassert
127  */
128 typedef int (*reset_api_line_deassert)(const struct device *dev, uint32_t id);
129 
130 /**
131  * API template to reset the device.
132  *
133  * @see reset_line_toggle
134  */
135 typedef int (*reset_api_line_toggle)(const struct device *dev, uint32_t id);
136 
137 /**
138  * @brief Reset Controller driver API
139  */
140 __subsystem struct reset_driver_api {
141 	reset_api_status status;
142 	reset_api_line_assert line_assert;
143 	reset_api_line_deassert line_deassert;
144 	reset_api_line_toggle line_toggle;
145 };
146 
147 /** @endcond */
148 
149 /**
150  * @brief Get the reset status
151  *
152  * This function returns the reset status of the device.
153  *
154  * @param dev Reset controller device.
155  * @param id Reset line.
156  * @param status Where to write the reset status.
157  *
158  * @retval 0 On success.
159  * @retval -ENOSYS If the functionality is not implemented by the driver.
160  * @retval -errno Other negative errno in case of failure.
161  */
162 __syscall int reset_status(const struct device *dev, uint32_t id, uint8_t *status);
163 
z_impl_reset_status(const struct device * dev,uint32_t id,uint8_t * status)164 static inline int z_impl_reset_status(const struct device *dev, uint32_t id, uint8_t *status)
165 {
166 	const struct reset_driver_api *api = (const struct reset_driver_api *)dev->api;
167 
168 	if (api->status == NULL) {
169 		return -ENOSYS;
170 	}
171 
172 	return api->status(dev, id, status);
173 }
174 
175 /**
176  * @brief Get the reset status from a @p reset_dt_spec.
177  *
178  * This is equivalent to:
179  *
180  *    reset_status(spec->dev, spec->id, status);
181  *
182  * @param spec Reset controller specification from devicetree
183  * @param status Where to write the reset status.
184  *
185  * @return a value from reset_status()
186  */
reset_status_dt(const struct reset_dt_spec * spec,uint8_t * status)187 static inline int reset_status_dt(const struct reset_dt_spec *spec, uint8_t *status)
188 {
189 	return reset_status(spec->dev, spec->id, status);
190 }
191 
192 /**
193  * @brief Put the device in reset state
194  *
195  * This function sets/clears the reset bits of the device,
196  * depending on the logic level (active-high/active-low).
197  *
198  * @param dev Reset controller device.
199  * @param id Reset line.
200  *
201  * @retval 0 On success.
202  * @retval -ENOSYS If the functionality is not implemented by the driver.
203  * @retval -errno Other negative errno in case of failure.
204  */
205 __syscall int reset_line_assert(const struct device *dev, uint32_t id);
206 
z_impl_reset_line_assert(const struct device * dev,uint32_t id)207 static inline int z_impl_reset_line_assert(const struct device *dev, uint32_t id)
208 {
209 	const struct reset_driver_api *api = (const struct reset_driver_api *)dev->api;
210 
211 	if (api->line_assert == NULL) {
212 		return -ENOSYS;
213 	}
214 
215 	return api->line_assert(dev, id);
216 }
217 
218 /**
219  * @brief Assert the reset state from a @p reset_dt_spec.
220  *
221  * This is equivalent to:
222  *
223  *     reset_line_assert(spec->dev, spec->id);
224  *
225  * @param spec Reset controller specification from devicetree
226  *
227  * @return a value from reset_line_assert()
228  */
reset_line_assert_dt(const struct reset_dt_spec * spec)229 static inline int reset_line_assert_dt(const struct reset_dt_spec *spec)
230 {
231 	return reset_line_assert(spec->dev, spec->id);
232 }
233 
234 /**
235  * @brief Take out the device from reset state.
236  *
237  * This function sets/clears the reset bits of the device,
238  * depending on the logic level (active-low/active-high).
239  *
240  * @param dev Reset controller device.
241  * @param id Reset line.
242  *
243  * @retval 0 On success.
244  * @retval -ENOSYS If the functionality is not implemented by the driver.
245  * @retval -errno Other negative errno in case of failure.
246  */
247 __syscall int reset_line_deassert(const struct device *dev, uint32_t id);
248 
z_impl_reset_line_deassert(const struct device * dev,uint32_t id)249 static inline int z_impl_reset_line_deassert(const struct device *dev, uint32_t id)
250 {
251 	const struct reset_driver_api *api = (const struct reset_driver_api *)dev->api;
252 
253 	if (api->line_deassert == NULL) {
254 		return -ENOSYS;
255 	}
256 
257 	return api->line_deassert(dev, id);
258 }
259 
260 /**
261  * @brief Deassert the reset state from a @p reset_dt_spec.
262  *
263  * This is equivalent to:
264  *
265  *     reset_line_deassert(spec->dev, spec->id)
266  *
267  * @param spec Reset controller specification from devicetree
268  *
269  * @return a value from reset_line_deassert()
270  */
reset_line_deassert_dt(const struct reset_dt_spec * spec)271 static inline int reset_line_deassert_dt(const struct reset_dt_spec *spec)
272 {
273 	return reset_line_deassert(spec->dev, spec->id);
274 }
275 
276 /**
277  * @brief Reset the device.
278  *
279  * This function performs reset for a device (assert + deassert).
280  *
281  * @param dev Reset controller device.
282  * @param id Reset line.
283  *
284  * @retval 0 On success.
285  * @retval -ENOSYS If the functionality is not implemented by the driver.
286  * @retval -errno Other negative errno in case of failure.
287  */
288 __syscall int reset_line_toggle(const struct device *dev, uint32_t id);
289 
z_impl_reset_line_toggle(const struct device * dev,uint32_t id)290 static inline int z_impl_reset_line_toggle(const struct device *dev, uint32_t id)
291 {
292 	const struct reset_driver_api *api = (const struct reset_driver_api *)dev->api;
293 
294 	if (api->line_toggle == NULL) {
295 		return -ENOSYS;
296 	}
297 
298 	return api->line_toggle(dev, id);
299 }
300 
301 /**
302  * @brief Reset the device from a @p reset_dt_spec.
303  *
304  * This is equivalent to:
305  *
306  *     reset_line_toggle(spec->dev, spec->id)
307  *
308  * @param spec Reset controller specification from devicetree
309  *
310  * @return a value from reset_line_toggle()
311  */
reset_line_toggle_dt(const struct reset_dt_spec * spec)312 static inline int reset_line_toggle_dt(const struct reset_dt_spec *spec)
313 {
314 	return reset_line_toggle(spec->dev, spec->id);
315 }
316 
317 /**
318  * @}
319  */
320 
321 #ifdef __cplusplus
322 }
323 #endif
324 
325 #include <syscalls/reset.h>
326 
327 #endif /* ZEPHYR_INCLUDE_DRIVERS_RESET_H_ */
328