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