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