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