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