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