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 #define PWM_CAPTURE_TYPE_PERIOD (1U << PWM_CAPTURE_TYPE_SHIFT)
56
57 /** PWM pin capture captures pulse width. */
58 #define PWM_CAPTURE_TYPE_PULSE (2U << PWM_CAPTURE_TYPE_SHIFT)
59
60 /** PWM pin capture captures both period and pulse width. */
61 #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 #define PWM_CAPTURE_MODE_SINGLE (0U << PWM_CAPTURE_MODE_SHIFT)
66
67 /** PWM pin capture captures period/pulse width continuously. */
68 #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 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 struct pwm_dt_spec {
99 /** PWM device instance. */
100 const struct device *dev;
101 /** Channel number. */
102 uint32_t channel;
103 /** Period in nanoseconds. */
104 uint32_t period;
105 /** Flags. */
106 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 #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 #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 #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 #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 #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 #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 #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 #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 #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 #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 #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 #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 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 __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
z_impl_pwm_set_cycles(const struct device * dev,uint32_t channel,uint32_t period,uint32_t pulse,pwm_flags_t flags)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 __syscall int pwm_get_cycles_per_sec(const struct device *dev, uint32_t channel,
509 uint64_t *cycles);
510
z_impl_pwm_get_cycles_per_sec(const struct device * dev,uint32_t channel,uint64_t * cycles)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 */
pwm_set(const struct device * dev,uint32_t channel,uint32_t period,uint32_t pulse,pwm_flags_t flags)537 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 */
pwm_set_dt(const struct pwm_dt_spec * spec,uint32_t period,uint32_t pulse)583 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 */
pwm_set_pulse_dt(const struct pwm_dt_spec * spec,uint32_t pulse)604 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 */
pwm_cycles_to_usec(const struct device * dev,uint32_t channel,uint32_t cycles,uint64_t * usec)623 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 */
pwm_cycles_to_nsec(const struct device * dev,uint32_t channel,uint32_t cycles,uint64_t * nsec)656 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 */
pwm_configure_capture(const struct device * dev,uint32_t channel,pwm_flags_t flags,pwm_capture_callback_handler_t cb,void * user_data)706 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 __syscall int pwm_enable_capture(const struct device *dev, uint32_t channel);
742
743 #ifdef CONFIG_PWM_CAPTURE
z_impl_pwm_enable_capture(const struct device * dev,uint32_t channel)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 __syscall int pwm_disable_capture(const struct device *dev, uint32_t channel);
773
774 #ifdef CONFIG_PWM_CAPTURE
z_impl_pwm_disable_capture(const struct device * dev,uint32_t channel)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 __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 */
pwm_capture_usec(const struct device * dev,uint32_t channel,pwm_flags_t flags,uint64_t * period,uint64_t * pulse,k_timeout_t timeout)848 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 */
pwm_capture_nsec(const struct device * dev,uint32_t channel,pwm_flags_t flags,uint64_t * period,uint64_t * pulse,k_timeout_t timeout)903 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 */
pwm_is_ready_dt(const struct pwm_dt_spec * spec)938 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_ */
954