Line data Source code
1 1 : /*
2 : * Copyright (c) 2016 Intel Corporation.
3 : * Copyright (c) 2020-2021 Vestas Wind Systems A/S
4 : *
5 : * SPDX-License-Identifier: Apache-2.0
6 : */
7 :
8 : /**
9 : * @file
10 : * @brief Public PWM Driver APIs
11 : */
12 :
13 : #ifndef ZEPHYR_INCLUDE_DRIVERS_PWM_H_
14 : #define ZEPHYR_INCLUDE_DRIVERS_PWM_H_
15 :
16 : /**
17 : * @brief PWM Interface
18 : * @defgroup pwm_interface PWM Interface
19 : * @since 1.0
20 : * @version 1.0.0
21 : * @ingroup io_interfaces
22 : * @{
23 : */
24 :
25 : #include <errno.h>
26 : #include <stdint.h>
27 :
28 : #include <zephyr/device.h>
29 : #include <zephyr/devicetree.h>
30 : #include <zephyr/sys_clock.h>
31 : #include <zephyr/sys/math_extras.h>
32 : #include <zephyr/toolchain.h>
33 :
34 : #include <zephyr/dt-bindings/pwm/pwm.h>
35 :
36 : #ifdef __cplusplus
37 : extern "C" {
38 : #endif
39 :
40 : /**
41 : * @name PWM capture configuration flags
42 : * @anchor PWM_CAPTURE_FLAGS
43 : * @{
44 : */
45 :
46 : /** @cond INTERNAL_HIDDEN */
47 : /* Bit 0 is used for PWM_POLARITY_NORMAL/PWM_POLARITY_INVERTED */
48 : #define PWM_CAPTURE_TYPE_SHIFT 1U
49 : #define PWM_CAPTURE_TYPE_MASK (3U << PWM_CAPTURE_TYPE_SHIFT)
50 : #define PWM_CAPTURE_MODE_SHIFT 3U
51 : #define PWM_CAPTURE_MODE_MASK (1U << PWM_CAPTURE_MODE_SHIFT)
52 : /** @endcond */
53 :
54 : /** PWM pin capture captures period. */
55 1 : #define PWM_CAPTURE_TYPE_PERIOD (1U << PWM_CAPTURE_TYPE_SHIFT)
56 :
57 : /** PWM pin capture captures pulse width. */
58 1 : #define PWM_CAPTURE_TYPE_PULSE (2U << PWM_CAPTURE_TYPE_SHIFT)
59 :
60 : /** PWM pin capture captures both period and pulse width. */
61 1 : #define PWM_CAPTURE_TYPE_BOTH (PWM_CAPTURE_TYPE_PERIOD | \
62 : PWM_CAPTURE_TYPE_PULSE)
63 :
64 : /** PWM pin capture captures a single period/pulse width. */
65 1 : #define PWM_CAPTURE_MODE_SINGLE (0U << PWM_CAPTURE_MODE_SHIFT)
66 :
67 : /** PWM pin capture captures period/pulse width continuously. */
68 1 : #define PWM_CAPTURE_MODE_CONTINUOUS (1U << PWM_CAPTURE_MODE_SHIFT)
69 :
70 : /** @} */
71 :
72 : /**
73 : * @brief Provides a type to hold PWM configuration flags.
74 : *
75 : * The lower 8 bits are used for standard flags.
76 : * The upper 8 bits are reserved for SoC specific flags.
77 : *
78 : * @see @ref PWM_CAPTURE_FLAGS.
79 : */
80 :
81 1 : typedef uint16_t pwm_flags_t;
82 :
83 : /**
84 : * @brief Container for PWM information specified in devicetree.
85 : *
86 : * This type contains a pointer to a PWM device, channel number (controlled by
87 : * the PWM device), the PWM signal period in nanoseconds and the flags
88 : * applicable to the channel. Note that not all PWM drivers support flags. In
89 : * such case, flags will be set to 0.
90 : *
91 : * @see PWM_DT_SPEC_GET_BY_NAME
92 : * @see PWM_DT_SPEC_GET_BY_NAME_OR
93 : * @see PWM_DT_SPEC_GET_BY_IDX
94 : * @see PWM_DT_SPEC_GET_BY_IDX_OR
95 : * @see PWM_DT_SPEC_GET
96 : * @see PWM_DT_SPEC_GET_OR
97 : */
98 1 : struct pwm_dt_spec {
99 : /** PWM device instance. */
100 1 : const struct device *dev;
101 : /** Channel number. */
102 1 : uint32_t channel;
103 : /** Period in nanoseconds. */
104 1 : uint32_t period;
105 : /** Flags. */
106 1 : pwm_flags_t flags;
107 : };
108 :
109 : /**
110 : * @brief Static initializer for a struct pwm_dt_spec
111 : *
112 : * This returns a static initializer for a struct pwm_dt_spec given a devicetree
113 : * node identifier and an index.
114 : *
115 : * Example devicetree fragment:
116 : *
117 : * @code{.dts}
118 : * n: node {
119 : * pwms = <&pwm1 1 1000 PWM_POLARITY_NORMAL>,
120 : * <&pwm2 3 2000 PWM_POLARITY_INVERTED>;
121 : * pwm-names = "alpha", "beta";
122 : * };
123 : * @endcode
124 : *
125 : * Example usage:
126 : *
127 : * @code{.c}
128 : * const struct pwm_dt_spec spec =
129 : * PWM_DT_SPEC_GET_BY_NAME(DT_NODELABEL(n), alpha);
130 : *
131 : * // Initializes 'spec' to:
132 : * // {
133 : * // .dev = DEVICE_DT_GET(DT_NODELABEL(pwm1)),
134 : * // .channel = 1,
135 : * // .period = 1000,
136 : * // .flags = PWM_POLARITY_NORMAL,
137 : * // }
138 : * @endcode
139 : *
140 : * The device (dev) must still be checked for readiness, e.g. using
141 : * device_is_ready(). It is an error to use this macro unless the node exists,
142 : * has the 'pwms' property, and that 'pwms' property specifies a PWM controller,
143 : * a channel, a period in nanoseconds and optionally flags.
144 : *
145 : * @param node_id Devicetree node identifier.
146 : * @param name Lowercase-and-underscores name of a pwms element as defined by
147 : * the node's pwm-names property.
148 : *
149 : * @return Static initializer for a struct pwm_dt_spec for the property.
150 : *
151 : * @see PWM_DT_SPEC_INST_GET_BY_NAME
152 : */
153 1 : #define PWM_DT_SPEC_GET_BY_NAME(node_id, name) \
154 : { \
155 : .dev = DEVICE_DT_GET(DT_PWMS_CTLR_BY_NAME(node_id, name)), \
156 : .channel = DT_PWMS_CHANNEL_BY_NAME(node_id, name), \
157 : .period = DT_PWMS_PERIOD_BY_NAME(node_id, name), \
158 : .flags = DT_PWMS_FLAGS_BY_NAME(node_id, name), \
159 : }
160 :
161 : /**
162 : * @brief Static initializer for a struct pwm_dt_spec from a DT_DRV_COMPAT
163 : * instance.
164 : *
165 : * @param inst DT_DRV_COMPAT instance number
166 : * @param name Lowercase-and-underscores name of a pwms element as defined by
167 : * the node's pwm-names property.
168 : *
169 : * @return Static initializer for a struct pwm_dt_spec for the property.
170 : *
171 : * @see PWM_DT_SPEC_GET_BY_NAME
172 : */
173 1 : #define PWM_DT_SPEC_INST_GET_BY_NAME(inst, name) \
174 : PWM_DT_SPEC_GET_BY_NAME(DT_DRV_INST(inst), name)
175 :
176 : /**
177 : * @brief Like PWM_DT_SPEC_GET_BY_NAME(), with a fallback to a default value.
178 : *
179 : * If the devicetree node identifier 'node_id' refers to a node with a property
180 : * 'pwms', this expands to <tt>PWM_DT_SPEC_GET_BY_NAME(node_id, name)</tt>. The
181 : * @p default_value parameter is not expanded in this case. Otherwise, this
182 : * expands to @p default_value.
183 : *
184 : * @param node_id Devicetree node identifier.
185 : * @param name Lowercase-and-underscores name of a pwms element as defined by
186 : * the node's pwm-names property
187 : * @param default_value Fallback value to expand to.
188 : *
189 : * @return Static initializer for a struct pwm_dt_spec for the property,
190 : * or @p default_value if the node or property do not exist.
191 : *
192 : * @see PWM_DT_SPEC_INST_GET_BY_NAME_OR
193 : */
194 1 : #define PWM_DT_SPEC_GET_BY_NAME_OR(node_id, name, default_value) \
195 : COND_CODE_1(DT_NODE_HAS_PROP(node_id, pwms), \
196 : (PWM_DT_SPEC_GET_BY_NAME(node_id, name)), \
197 : (default_value))
198 :
199 : /**
200 : * @brief Like PWM_DT_SPEC_INST_GET_BY_NAME(), with a fallback to a default
201 : * value.
202 : *
203 : * @param inst DT_DRV_COMPAT instance number
204 : * @param name Lowercase-and-underscores name of a pwms element as defined by
205 : * the node's pwm-names property.
206 : * @param default_value Fallback value to expand to.
207 : *
208 : * @return Static initializer for a struct pwm_dt_spec for the property,
209 : * or @p default_value if the node or property do not exist.
210 : *
211 : * @see PWM_DT_SPEC_GET_BY_NAME_OR
212 : */
213 1 : #define PWM_DT_SPEC_INST_GET_BY_NAME_OR(inst, name, default_value) \
214 : PWM_DT_SPEC_GET_BY_NAME_OR(DT_DRV_INST(inst), name, default_value)
215 :
216 : /**
217 : * @brief Static initializer for a struct pwm_dt_spec
218 : *
219 : * This returns a static initializer for a struct pwm_dt_spec given a devicetree
220 : * node identifier and an index.
221 : *
222 : * Example devicetree fragment:
223 : *
224 : * @code{.dts}
225 : * n: node {
226 : * pwms = <&pwm1 1 1000 PWM_POLARITY_NORMAL>,
227 : * <&pwm2 3 2000 PWM_POLARITY_INVERTED>;
228 : * };
229 : * @endcode
230 : *
231 : * Example usage:
232 : *
233 : * @code{.c}
234 : * const struct pwm_dt_spec spec =
235 : * PWM_DT_SPEC_GET_BY_IDX(DT_NODELABEL(n), 1);
236 : *
237 : * // Initializes 'spec' to:
238 : * // {
239 : * // .dev = DEVICE_DT_GET(DT_NODELABEL(pwm2)),
240 : * // .channel = 3,
241 : * // .period = 2000,
242 : * // .flags = PWM_POLARITY_INVERTED,
243 : * // }
244 : * @endcode
245 : *
246 : * The device (dev) must still be checked for readiness, e.g. using
247 : * device_is_ready(). It is an error to use this macro unless the node exists,
248 : * has the 'pwms' property, and that 'pwms' property specifies a PWM controller,
249 : * a channel, a period in nanoseconds and optionally flags.
250 : *
251 : * @param node_id Devicetree node identifier.
252 : * @param idx Logical index into 'pwms' property.
253 : *
254 : * @return Static initializer for a struct pwm_dt_spec for the property.
255 : *
256 : * @see PWM_DT_SPEC_INST_GET_BY_IDX
257 : */
258 1 : #define PWM_DT_SPEC_GET_BY_IDX(node_id, idx) \
259 : { \
260 : .dev = DEVICE_DT_GET(DT_PWMS_CTLR_BY_IDX(node_id, idx)), \
261 : .channel = DT_PWMS_CHANNEL_BY_IDX(node_id, idx), \
262 : .period = DT_PWMS_PERIOD_BY_IDX(node_id, idx), \
263 : .flags = DT_PWMS_FLAGS_BY_IDX(node_id, idx), \
264 : }
265 :
266 : /**
267 : * @brief Static initializer for a struct pwm_dt_spec from a DT_DRV_COMPAT
268 : * instance.
269 : *
270 : * @param inst DT_DRV_COMPAT instance number
271 : * @param idx Logical index into 'pwms' property.
272 : *
273 : * @return Static initializer for a struct pwm_dt_spec for the property.
274 : *
275 : * @see PWM_DT_SPEC_GET_BY_IDX
276 : */
277 1 : #define PWM_DT_SPEC_INST_GET_BY_IDX(inst, idx) \
278 : PWM_DT_SPEC_GET_BY_IDX(DT_DRV_INST(inst), idx)
279 :
280 : /**
281 : * @brief Like PWM_DT_SPEC_GET_BY_IDX(), with a fallback to a default value.
282 : *
283 : * If the devicetree node identifier 'node_id' refers to a node with a property
284 : * 'pwms', this expands to <tt>PWM_DT_SPEC_GET_BY_IDX(node_id, idx)</tt>. The
285 : * @p default_value parameter is not expanded in this case. Otherwise, this
286 : * expands to @p default_value.
287 : *
288 : * @param node_id Devicetree node identifier.
289 : * @param idx Logical index into 'pwms' property.
290 : * @param default_value Fallback value to expand to.
291 : *
292 : * @return Static initializer for a struct pwm_dt_spec for the property,
293 : * or @p default_value if the node or property do not exist.
294 : *
295 : * @see PWM_DT_SPEC_INST_GET_BY_IDX_OR
296 : */
297 1 : #define PWM_DT_SPEC_GET_BY_IDX_OR(node_id, idx, default_value) \
298 : COND_CODE_1(DT_NODE_HAS_PROP(node_id, pwms), \
299 : (PWM_DT_SPEC_GET_BY_IDX(node_id, idx)), \
300 : (default_value))
301 :
302 : /**
303 : * @brief Like PWM_DT_SPEC_INST_GET_BY_IDX(), with a fallback to a default
304 : * value.
305 : *
306 : * @param inst DT_DRV_COMPAT instance number
307 : * @param idx Logical index into 'pwms' property.
308 : * @param default_value Fallback value to expand to.
309 : *
310 : * @return Static initializer for a struct pwm_dt_spec for the property,
311 : * or @p default_value if the node or property do not exist.
312 : *
313 : * @see PWM_DT_SPEC_GET_BY_IDX_OR
314 : */
315 1 : #define PWM_DT_SPEC_INST_GET_BY_IDX_OR(inst, idx, default_value) \
316 : PWM_DT_SPEC_GET_BY_IDX_OR(DT_DRV_INST(inst), idx, default_value)
317 :
318 : /**
319 : * @brief Equivalent to <tt>PWM_DT_SPEC_GET_BY_IDX(node_id, 0)</tt>.
320 : *
321 : * @param node_id Devicetree node identifier.
322 : *
323 : * @return Static initializer for a struct pwm_dt_spec for the property.
324 : *
325 : * @see PWM_DT_SPEC_GET_BY_IDX
326 : * @see PWM_DT_SPEC_INST_GET
327 : */
328 1 : #define PWM_DT_SPEC_GET(node_id) PWM_DT_SPEC_GET_BY_IDX(node_id, 0)
329 :
330 : /**
331 : * @brief Equivalent to <tt>PWM_DT_SPEC_INST_GET_BY_IDX(inst, 0)</tt>.
332 : *
333 : * @param inst DT_DRV_COMPAT instance number
334 : *
335 : * @return Static initializer for a struct pwm_dt_spec for the property.
336 : *
337 : * @see PWM_DT_SPEC_INST_GET_BY_IDX
338 : * @see PWM_DT_SPEC_GET
339 : */
340 1 : #define PWM_DT_SPEC_INST_GET(inst) PWM_DT_SPEC_GET(DT_DRV_INST(inst))
341 :
342 : /**
343 : * @brief Equivalent to
344 : * <tt>PWM_DT_SPEC_GET_BY_IDX_OR(node_id, 0, default_value)</tt>.
345 : *
346 : * @param node_id Devicetree node identifier.
347 : * @param default_value Fallback value to expand to.
348 : *
349 : * @return Static initializer for a struct pwm_dt_spec for the property.
350 : *
351 : * @see PWM_DT_SPEC_GET_BY_IDX_OR
352 : * @see PWM_DT_SPEC_INST_GET_OR
353 : */
354 1 : #define PWM_DT_SPEC_GET_OR(node_id, default_value) \
355 : PWM_DT_SPEC_GET_BY_IDX_OR(node_id, 0, default_value)
356 :
357 : /**
358 : * @brief Equivalent to
359 : * <tt>PWM_DT_SPEC_INST_GET_BY_IDX_OR(inst, 0, default_value)</tt>.
360 : *
361 : * @param inst DT_DRV_COMPAT instance number
362 : * @param default_value Fallback value to expand to.
363 : *
364 : * @return Static initializer for a struct pwm_dt_spec for the property.
365 : *
366 : * @see PWM_DT_SPEC_INST_GET_BY_IDX_OR
367 : * @see PWM_DT_SPEC_GET_OR
368 : */
369 1 : #define PWM_DT_SPEC_INST_GET_OR(inst, default_value) \
370 : PWM_DT_SPEC_GET_OR(DT_DRV_INST(inst), default_value)
371 :
372 : /**
373 : * @brief PWM capture callback handler function signature
374 : *
375 : * @note The callback handler will be called in interrupt context.
376 : *
377 : * @note @kconfig{CONFIG_PWM_CAPTURE} must be selected to enable PWM capture
378 : * support.
379 : *
380 : * @param[in] dev PWM device instance.
381 : * @param channel PWM channel.
382 :
383 : * @param period_cycles Captured PWM period width (in clock cycles). HW
384 : * specific.
385 : * @param pulse_cycles Captured PWM pulse width (in clock cycles). HW specific.
386 : * @param status Status for the PWM capture (0 if no error, negative errno
387 : * otherwise. See pwm_capture_cycles() return value
388 : * descriptions for details).
389 : * @param user_data User data passed to pwm_configure_capture()
390 : */
391 1 : typedef void (*pwm_capture_callback_handler_t)(const struct device *dev,
392 : uint32_t channel,
393 : uint32_t period_cycles,
394 : uint32_t pulse_cycles,
395 : int status, void *user_data);
396 :
397 : /** @cond INTERNAL_HIDDEN */
398 : /**
399 : * @brief PWM driver API call to configure PWM pin period and pulse width.
400 : * @see pwm_set_cycles() for argument description.
401 : */
402 : typedef int (*pwm_set_cycles_t)(const struct device *dev, uint32_t channel,
403 : uint32_t period_cycles, uint32_t pulse_cycles,
404 : pwm_flags_t flags);
405 :
406 : /**
407 : * @brief PWM driver API call to obtain the PWM cycles per second (frequency).
408 : * @see pwm_get_cycles_per_sec() for argument description
409 : */
410 : typedef int (*pwm_get_cycles_per_sec_t)(const struct device *dev,
411 : uint32_t channel, uint64_t *cycles);
412 :
413 : #ifdef CONFIG_PWM_CAPTURE
414 : /**
415 : * @brief PWM driver API call to configure PWM capture.
416 : * @see pwm_configure_capture() for argument description.
417 : */
418 : typedef int (*pwm_configure_capture_t)(const struct device *dev,
419 : uint32_t channel, pwm_flags_t flags,
420 : pwm_capture_callback_handler_t cb,
421 : void *user_data);
422 :
423 : /**
424 : * @brief PWM driver API call to enable PWM capture.
425 : * @see pwm_enable_capture() for argument description.
426 : */
427 : typedef int (*pwm_enable_capture_t)(const struct device *dev, uint32_t channel);
428 :
429 : /**
430 : * @brief PWM driver API call to disable PWM capture.
431 : * @see pwm_disable_capture() for argument description
432 : */
433 : typedef int (*pwm_disable_capture_t)(const struct device *dev,
434 : uint32_t channel);
435 : #endif /* CONFIG_PWM_CAPTURE */
436 :
437 : /** @brief PWM driver API definition. */
438 : __subsystem struct pwm_driver_api {
439 : pwm_set_cycles_t set_cycles;
440 : pwm_get_cycles_per_sec_t get_cycles_per_sec;
441 : #ifdef CONFIG_PWM_CAPTURE
442 : pwm_configure_capture_t configure_capture;
443 : pwm_enable_capture_t enable_capture;
444 : pwm_disable_capture_t disable_capture;
445 : #endif /* CONFIG_PWM_CAPTURE */
446 : };
447 : /** @endcond */
448 :
449 : /**
450 : * @brief Set the period and pulse width for a single PWM output.
451 : *
452 : * The PWM period and pulse width will synchronously be set to the new values
453 : * without glitches in the PWM signal, but the call will not block for the
454 : * change to take effect.
455 : *
456 : * @note Not all PWM controllers support synchronous, glitch-free updates of the
457 : * PWM period and pulse width. Depending on the hardware, changing the PWM
458 : * period and/or pulse width may cause a glitch in the generated PWM signal.
459 : *
460 : * @note Some multi-channel PWM controllers share the PWM period across all
461 : * channels. Depending on the hardware, changing the PWM period for one channel
462 : * may affect the PWM period for the other channels of the same PWM controller.
463 : *
464 : * Passing 0 as @p pulse will cause the pin to be driven to a constant
465 : * inactive level.
466 : * Passing a non-zero @p pulse equal to @p period will cause the pin
467 : * to be driven to a constant active level.
468 : *
469 : * @param[in] dev PWM device instance.
470 : * @param channel PWM channel.
471 : * @param period Period (in clock cycles) set to the PWM. HW specific.
472 : * @param pulse Pulse width (in clock cycles) set to the PWM. HW specific.
473 : * @param flags Flags for pin configuration.
474 : *
475 : * @retval 0 If successful.
476 : * @retval -EINVAL If pulse > period.
477 : * @retval -errno Negative errno code on failure.
478 : */
479 1 : __syscall int pwm_set_cycles(const struct device *dev, uint32_t channel,
480 : uint32_t period, uint32_t pulse,
481 : pwm_flags_t flags);
482 :
483 : static inline int z_impl_pwm_set_cycles(const struct device *dev,
484 : uint32_t channel, uint32_t period,
485 : uint32_t pulse, pwm_flags_t flags)
486 : {
487 : const struct pwm_driver_api *api =
488 : (const struct pwm_driver_api *)dev->api;
489 :
490 : if (pulse > period) {
491 : return -EINVAL;
492 : }
493 :
494 : return api->set_cycles(dev, channel, period, pulse, flags);
495 : }
496 :
497 : /**
498 : * @brief Get the clock rate (cycles per second) for a single PWM output.
499 : *
500 : * @param[in] dev PWM device instance.
501 : * @param channel PWM channel.
502 : * @param[out] cycles Pointer to the memory to store clock rate (cycles per
503 : * sec). HW specific.
504 : *
505 : * @retval 0 If successful.
506 : * @retval -errno Negative errno code on failure.
507 : */
508 1 : __syscall int pwm_get_cycles_per_sec(const struct device *dev, uint32_t channel,
509 : uint64_t *cycles);
510 :
511 : static inline int z_impl_pwm_get_cycles_per_sec(const struct device *dev,
512 : uint32_t channel,
513 : uint64_t *cycles)
514 : {
515 : const struct pwm_driver_api *api =
516 : (const struct pwm_driver_api *)dev->api;
517 :
518 : return api->get_cycles_per_sec(dev, channel, cycles);
519 : }
520 :
521 : /**
522 : * @brief Set the period and pulse width in nanoseconds for a single PWM output.
523 : *
524 : * @note Utility macros such as PWM_MSEC() can be used to convert from other
525 : * scales or units to nanoseconds, the units used by this function.
526 : *
527 : * @param[in] dev PWM device instance.
528 : * @param channel PWM channel.
529 : * @param period Period (in nanoseconds) set to the PWM.
530 : * @param pulse Pulse width (in nanoseconds) set to the PWM.
531 : * @param flags Flags for pin configuration (polarity).
532 : *
533 : * @retval 0 If successful.
534 : * @retval -ENOTSUP If requested period or pulse cycles are not supported.
535 : * @retval -errno Other negative errno code on failure.
536 : */
537 1 : static inline int pwm_set(const struct device *dev, uint32_t channel,
538 : uint32_t period, uint32_t pulse, pwm_flags_t flags)
539 : {
540 : int err;
541 : uint64_t pulse_cycles;
542 : uint64_t period_cycles;
543 : uint64_t cycles_per_sec;
544 :
545 : err = pwm_get_cycles_per_sec(dev, channel, &cycles_per_sec);
546 : if (err < 0) {
547 : return err;
548 : }
549 :
550 : period_cycles = (period * cycles_per_sec) / NSEC_PER_SEC;
551 : if (period_cycles > UINT32_MAX) {
552 : return -ENOTSUP;
553 : }
554 :
555 : pulse_cycles = (pulse * cycles_per_sec) / NSEC_PER_SEC;
556 : if (pulse_cycles > UINT32_MAX) {
557 : return -ENOTSUP;
558 : }
559 :
560 : return pwm_set_cycles(dev, channel, (uint32_t)period_cycles,
561 : (uint32_t)pulse_cycles, flags);
562 : }
563 :
564 : /**
565 : * @brief Set the period and pulse width in nanoseconds from a struct
566 : * pwm_dt_spec (with custom period).
567 : *
568 : * This is equivalent to:
569 : *
570 : * pwm_set(spec->dev, spec->channel, period, pulse, spec->flags)
571 : *
572 : * The period specified in @p spec is ignored. This API call can be used when
573 : * the period specified in Devicetree needs to be changed at runtime.
574 : *
575 : * @param[in] spec PWM specification from devicetree.
576 : * @param period Period (in nanoseconds) set to the PWM.
577 : * @param pulse Pulse width (in nanoseconds) set to the PWM.
578 : *
579 : * @return A value from pwm_set().
580 : *
581 : * @see pwm_set_pulse_dt()
582 : */
583 1 : static inline int pwm_set_dt(const struct pwm_dt_spec *spec, uint32_t period,
584 : uint32_t pulse)
585 : {
586 : return pwm_set(spec->dev, spec->channel, period, pulse, spec->flags);
587 : }
588 :
589 : /**
590 : * @brief Set the period and pulse width in nanoseconds from a struct
591 : * pwm_dt_spec.
592 : *
593 : * This is equivalent to:
594 : *
595 : * pwm_set(spec->dev, spec->channel, spec->period, pulse, spec->flags)
596 : *
597 : * @param[in] spec PWM specification from devicetree.
598 : * @param pulse Pulse width (in nanoseconds) set to the PWM.
599 : *
600 : * @return A value from pwm_set().
601 : *
602 : * @see pwm_set_pulse_dt()
603 : */
604 1 : static inline int pwm_set_pulse_dt(const struct pwm_dt_spec *spec,
605 : uint32_t pulse)
606 : {
607 : return pwm_set(spec->dev, spec->channel, spec->period, pulse,
608 : spec->flags);
609 : }
610 :
611 : /**
612 : * @brief Convert from PWM cycles to microseconds.
613 : *
614 : * @param[in] dev PWM device instance.
615 : * @param channel PWM channel.
616 : * @param cycles Cycles to be converted.
617 : * @param[out] usec Pointer to the memory to store calculated usec.
618 : *
619 : * @retval 0 If successful.
620 : * @retval -ERANGE If result is too large.
621 : * @retval -errno Other negative errno code on failure.
622 : */
623 1 : static inline int pwm_cycles_to_usec(const struct device *dev, uint32_t channel,
624 : uint32_t cycles, uint64_t *usec)
625 : {
626 : int err;
627 : uint64_t temp;
628 : uint64_t cycles_per_sec;
629 :
630 : err = pwm_get_cycles_per_sec(dev, channel, &cycles_per_sec);
631 : if (err < 0) {
632 : return err;
633 : }
634 :
635 : if (u64_mul_overflow(cycles, (uint64_t)USEC_PER_SEC, &temp)) {
636 : return -ERANGE;
637 : }
638 :
639 : *usec = temp / cycles_per_sec;
640 :
641 : return 0;
642 : }
643 :
644 : /**
645 : * @brief Convert from PWM cycles to nanoseconds.
646 : *
647 : * @param[in] dev PWM device instance.
648 : * @param channel PWM channel.
649 : * @param cycles Cycles to be converted.
650 : * @param[out] nsec Pointer to the memory to store the calculated nsec.
651 : *
652 : * @retval 0 If successful.
653 : * @retval -ERANGE If result is too large.
654 : * @retval -errno Other negative errno code on failure.
655 : */
656 1 : static inline int pwm_cycles_to_nsec(const struct device *dev, uint32_t channel,
657 : uint32_t cycles, uint64_t *nsec)
658 : {
659 : int err;
660 : uint64_t temp;
661 : uint64_t cycles_per_sec;
662 :
663 : err = pwm_get_cycles_per_sec(dev, channel, &cycles_per_sec);
664 : if (err < 0) {
665 : return err;
666 : }
667 :
668 : if (u64_mul_overflow(cycles, (uint64_t)NSEC_PER_SEC, &temp)) {
669 : return -ERANGE;
670 : }
671 :
672 : *nsec = temp / cycles_per_sec;
673 :
674 : return 0;
675 : }
676 :
677 : #if defined(CONFIG_PWM_CAPTURE) || defined(__DOXYGEN__)
678 : /**
679 : * @brief Configure PWM period/pulse width capture for a single PWM input.
680 : *
681 : * After configuring PWM capture using this function, the capture can be
682 : * enabled/disabled using pwm_enable_capture() and
683 : * pwm_disable_capture().
684 : *
685 : * @note This API function cannot be invoked from user space due to the use of a
686 : * function callback. In user space, one of the simpler API functions
687 : * (pwm_capture_cycles(), pwm_capture_usec(), or
688 : * pwm_capture_nsec()) can be used instead.
689 : *
690 : * @note @kconfig{CONFIG_PWM_CAPTURE} must be selected for this function to be
691 : * available.
692 : *
693 : * @param[in] dev PWM device instance.
694 : * @param channel PWM channel.
695 : * @param flags PWM capture flags
696 : * @param[in] cb Application callback handler function to be called upon capture
697 : * @param[in] user_data User data to pass to the application callback handler
698 : * function
699 : *
700 : * @retval -EINVAL if invalid function parameters were given
701 : * @retval -ENOSYS if PWM capture is not supported or the given flags are not
702 : * supported
703 : * @retval -EIO if IO error occurred while configuring
704 : * @retval -EBUSY if PWM capture is already in progress
705 : */
706 1 : static inline int pwm_configure_capture(const struct device *dev,
707 : uint32_t channel, pwm_flags_t flags,
708 : pwm_capture_callback_handler_t cb,
709 : void *user_data)
710 : {
711 : const struct pwm_driver_api *api =
712 : (const struct pwm_driver_api *)dev->api;
713 :
714 : if (api->configure_capture == NULL) {
715 : return -ENOSYS;
716 : }
717 :
718 : return api->configure_capture(dev, channel, flags, cb,
719 : user_data);
720 : }
721 : #endif /* CONFIG_PWM_CAPTURE */
722 :
723 : /**
724 : * @brief Enable PWM period/pulse width capture for a single PWM input.
725 : *
726 : * The PWM pin must be configured using pwm_configure_capture() prior to
727 : * calling this function.
728 : *
729 : * @note @kconfig{CONFIG_PWM_CAPTURE} must be selected for this function to be
730 : * available.
731 : *
732 : * @param[in] dev PWM device instance.
733 : * @param channel PWM channel.
734 : *
735 : * @retval 0 If successful.
736 : * @retval -EINVAL if invalid function parameters were given
737 : * @retval -ENOSYS if PWM capture is not supported
738 : * @retval -EIO if IO error occurred while enabling PWM capture
739 : * @retval -EBUSY if PWM capture is already in progress
740 : */
741 1 : __syscall int pwm_enable_capture(const struct device *dev, uint32_t channel);
742 :
743 : #ifdef CONFIG_PWM_CAPTURE
744 : static inline int z_impl_pwm_enable_capture(const struct device *dev,
745 : uint32_t channel)
746 : {
747 : const struct pwm_driver_api *api =
748 : (const struct pwm_driver_api *)dev->api;
749 :
750 : if (api->enable_capture == NULL) {
751 : return -ENOSYS;
752 : }
753 :
754 : return api->enable_capture(dev, channel);
755 : }
756 : #endif /* CONFIG_PWM_CAPTURE */
757 :
758 : /**
759 : * @brief Disable PWM period/pulse width capture for a single PWM input.
760 : *
761 : * @note @kconfig{CONFIG_PWM_CAPTURE} must be selected for this function to be
762 : * available.
763 : *
764 : * @param[in] dev PWM device instance.
765 : * @param channel PWM channel.
766 : *
767 : * @retval 0 If successful.
768 : * @retval -EINVAL if invalid function parameters were given
769 : * @retval -ENOSYS if PWM capture is not supported
770 : * @retval -EIO if IO error occurred while disabling PWM capture
771 : */
772 1 : __syscall int pwm_disable_capture(const struct device *dev, uint32_t channel);
773 :
774 : #ifdef CONFIG_PWM_CAPTURE
775 : static inline int z_impl_pwm_disable_capture(const struct device *dev,
776 : uint32_t channel)
777 : {
778 : const struct pwm_driver_api *api =
779 : (const struct pwm_driver_api *)dev->api;
780 :
781 : if (api->disable_capture == NULL) {
782 : return -ENOSYS;
783 : }
784 :
785 : return api->disable_capture(dev, channel);
786 : }
787 : #endif /* CONFIG_PWM_CAPTURE */
788 :
789 : /**
790 : * @brief Capture a single PWM period/pulse width in clock cycles for a single
791 : * PWM input.
792 : *
793 : * This API function wraps calls to pwm_configure_capture(),
794 : * pwm_enable_capture(), and pwm_disable_capture() and passes
795 : * the capture result to the caller. The function is blocking until either the
796 : * PWM capture is completed or a timeout occurs.
797 : *
798 : * @note @kconfig{CONFIG_PWM_CAPTURE} must be selected for this function to be
799 : * available.
800 : *
801 : * @param[in] dev PWM device instance.
802 : * @param channel PWM channel.
803 : * @param flags PWM capture flags.
804 : * @param[out] period Pointer to the memory to store the captured PWM period
805 : * width (in clock cycles). HW specific.
806 : * @param[out] pulse Pointer to the memory to store the captured PWM pulse width
807 : * (in clock cycles). HW specific.
808 : * @param timeout Waiting period for the capture to complete.
809 : *
810 : * @retval 0 If successful.
811 : * @retval -EBUSY PWM capture already in progress.
812 : * @retval -EAGAIN Waiting period timed out.
813 : * @retval -EIO IO error while capturing.
814 : * @retval -ERANGE If result is too large.
815 : */
816 1 : __syscall int pwm_capture_cycles(const struct device *dev, uint32_t channel,
817 : pwm_flags_t flags, uint32_t *period,
818 : uint32_t *pulse, k_timeout_t timeout);
819 :
820 : /**
821 : * @brief Capture a single PWM period/pulse width in microseconds for a single
822 : * PWM input.
823 : *
824 : * This API function wraps calls to pwm_capture_cycles() and
825 : * pwm_cycles_to_usec() and passes the capture result to the caller. The
826 : * function is blocking until either the PWM capture is completed or a timeout
827 : * occurs.
828 : *
829 : * @note @kconfig{CONFIG_PWM_CAPTURE} must be selected for this function to be
830 : * available.
831 : *
832 : * @param[in] dev PWM device instance.
833 : * @param channel PWM channel.
834 : * @param flags PWM capture flags.
835 : * @param[out] period Pointer to the memory to store the captured PWM period
836 : * width (in usec).
837 : * @param[out] pulse Pointer to the memory to store the captured PWM pulse width
838 : * (in usec).
839 : * @param timeout Waiting period for the capture to complete.
840 : *
841 : * @retval 0 If successful.
842 : * @retval -EBUSY PWM capture already in progress.
843 : * @retval -EAGAIN Waiting period timed out.
844 : * @retval -EIO IO error while capturing.
845 : * @retval -ERANGE If result is too large.
846 : * @retval -errno Other negative errno code on failure.
847 : */
848 1 : static inline int pwm_capture_usec(const struct device *dev, uint32_t channel,
849 : pwm_flags_t flags, uint64_t *period,
850 : uint64_t *pulse, k_timeout_t timeout)
851 : {
852 : int err;
853 : uint32_t pulse_cycles;
854 : uint32_t period_cycles;
855 :
856 : err = pwm_capture_cycles(dev, channel, flags, &period_cycles,
857 : &pulse_cycles, timeout);
858 : if (err < 0) {
859 : return err;
860 : }
861 :
862 : err = pwm_cycles_to_usec(dev, channel, period_cycles, period);
863 : if (err < 0) {
864 : return err;
865 : }
866 :
867 : err = pwm_cycles_to_usec(dev, channel, pulse_cycles, pulse);
868 : if (err < 0) {
869 : return err;
870 : }
871 :
872 : return 0;
873 : }
874 :
875 : /**
876 : * @brief Capture a single PWM period/pulse width in nanoseconds for a single
877 : * PWM input.
878 : *
879 : * This API function wraps calls to pwm_capture_cycles() and
880 : * pwm_cycles_to_nsec() and passes the capture result to the caller. The
881 : * function is blocking until either the PWM capture is completed or a timeout
882 : * occurs.
883 : *
884 : * @note @kconfig{CONFIG_PWM_CAPTURE} must be selected for this function to be
885 : * available.
886 : *
887 : * @param[in] dev PWM device instance.
888 : * @param channel PWM channel.
889 : * @param flags PWM capture flags.
890 : * @param[out] period Pointer to the memory to store the captured PWM period
891 : * width (in nsec).
892 : * @param[out] pulse Pointer to the memory to store the captured PWM pulse width
893 : * (in nsec).
894 : * @param timeout Waiting period for the capture to complete.
895 : *
896 : * @retval 0 If successful.
897 : * @retval -EBUSY PWM capture already in progress.
898 : * @retval -EAGAIN Waiting period timed out.
899 : * @retval -EIO IO error while capturing.
900 : * @retval -ERANGE If result is too large.
901 : * @retval -errno Other negative errno code on failure.
902 : */
903 1 : static inline int pwm_capture_nsec(const struct device *dev, uint32_t channel,
904 : pwm_flags_t flags, uint64_t *period,
905 : uint64_t *pulse, k_timeout_t timeout)
906 : {
907 : int err;
908 : uint32_t pulse_cycles;
909 : uint32_t period_cycles;
910 :
911 : err = pwm_capture_cycles(dev, channel, flags, &period_cycles,
912 : &pulse_cycles, timeout);
913 : if (err < 0) {
914 : return err;
915 : }
916 :
917 : err = pwm_cycles_to_nsec(dev, channel, period_cycles, period);
918 : if (err < 0) {
919 : return err;
920 : }
921 :
922 : err = pwm_cycles_to_nsec(dev, channel, pulse_cycles, pulse);
923 : if (err < 0) {
924 : return err;
925 : }
926 :
927 : return 0;
928 : }
929 :
930 : /**
931 : * @brief Validate that the PWM device is ready.
932 : *
933 : * @param spec PWM specification from devicetree
934 : *
935 : * @retval true If the PWM device is ready for use
936 : * @retval false If the PWM device is not ready for use
937 : */
938 1 : static inline bool pwm_is_ready_dt(const struct pwm_dt_spec *spec)
939 : {
940 : return device_is_ready(spec->dev);
941 : }
942 :
943 : #ifdef __cplusplus
944 : }
945 : #endif
946 :
947 : /**
948 : * @}
949 : */
950 :
951 : #include <zephyr/syscalls/pwm.h>
952 :
953 : #endif /* ZEPHYR_INCLUDE_DRIVERS_PWM_H_ */
|