11/*
22 * Copyright (c) 2016 Intel Corporation.
33 * Copyright (c) 2020-2021 Vestas Wind Systems A/S
4+ * Copyright (c) 2025 Basalte bv
45 *
56 * SPDX-License-Identifier: Apache-2.0
67 */
3536#include <zephyr/devicetree.h>
3637#include <zephyr/sys_clock.h>
3738#include <zephyr/sys/math_extras.h>
39+ #include <zephyr/sys/slist.h>
3840#include <zephyr/toolchain.h>
3941
4042#include <zephyr/dt-bindings/pwm/pwm.h>
@@ -75,6 +77,27 @@ extern "C" {
7577
7678/** @} */
7779
80+ /**
81+ * @name PWM event types
82+ * @anchor PWM_EVENT_TYPES
83+ * @{
84+ */
85+
86+ #define PWM_EVENT_TYPE_SHIFT 0U
87+
88+ /** Configure the event to trigger at the end of each PWM period */
89+ #define PWM_EVENT_TYPE_PERIOD (1U << PWM_EVENT_TYPE_SHIFT)
90+
91+ /** Configure the event to trigger at a fault. These can be used to
92+ * react to error events that caused a change of behaviour of the PWM
93+ * peripheral (often disabling the output). These error events can have
94+ * an internal (e.g., oscillator malfunction) or external (e.g., pio)
95+ * source
96+ */
97+ #define PWM_EVENT_TYPE_FAULT (2U << PWM_EVENT_TYPE_SHIFT)
98+
99+ /** @} */
100+
78101/**
79102 * @brief Provides a type to hold PWM configuration flags.
80103 *
@@ -86,6 +109,14 @@ extern "C" {
86109
87110typedef uint16_t pwm_flags_t ;
88111
112+ /**
113+ * @brief Provides a type to hold PWM events.
114+ *
115+ * @see @ref PWM_EVENT_TYPES.
116+ */
117+
118+ typedef uint16_t pwm_events_t ;
119+
89120/**
90121 * @brief Container for PWM information specified in devicetree.
91122 *
@@ -400,6 +431,52 @@ typedef void (*pwm_capture_callback_handler_t)(const struct device *dev,
400431 uint32_t pulse_cycles ,
401432 int status , void * user_data );
402433
434+ struct pwm_event_callback ;
435+
436+ /**
437+ * @brief PWM event callback handler function signature.
438+ *
439+ * @note The callback handler can be called in an interrupt context.
440+ *
441+ * @note @kconfig{CONFIG_PWM_EVENT} must be selected to enable PWM event
442+ * support.
443+ *
444+ * @param[in] dev PWM device instance.
445+ * @param callback Original struct gpio_callback owning this handler.
446+ * @param channel PWM channel.
447+ * @param events Event mask. See @ref PWM_EVENT_TYPES.
448+ *
449+ */
450+ typedef void (* pwm_event_callback_handler_t )(const struct device * dev ,
451+ struct pwm_event_callback * callback , uint32_t channel ,
452+ pwm_events_t events );
453+
454+ /**
455+ * @brief PWM event callback structure
456+ *
457+ * Used to register an event callback in the driver instance callback list.
458+ * As many callbacks as needed can be added as long as each of them
459+ * are unique pointers of struct pwm_event_callback.
460+ * Beware such structure should not be allocated on stack.
461+ *
462+ * Note: to help setting it, see pwm_init_event_callback().
463+ *
464+ */
465+ struct pwm_event_callback {
466+ /** @cond INTERNAL_HIDDEN */
467+ sys_snode_t node ;
468+ /** @endcond */
469+
470+ /** Actual callback function being called when relevant. */
471+ pwm_event_callback_handler_t handler ;
472+
473+ /** Channel the callback is interested in. */
474+ uint32_t channel ;
475+
476+ /** A mask of events the callback is interested in. */
477+ pwm_events_t event_mask ;
478+ };
479+
403480/** @cond INTERNAL_HIDDEN */
404481/**
405482 * @brief PWM driver API call to configure PWM pin period and pulse width.
@@ -440,6 +517,16 @@ typedef int (*pwm_disable_capture_t)(const struct device *dev,
440517 uint32_t channel );
441518#endif /* CONFIG_PWM_CAPTURE */
442519
520+ #ifdef CONFIG_PWM_EVENT
521+
522+ /**
523+ * @brief PWM driver API to manage callbacks for events.
524+ * @see pwm_set_event_callback() and pwm_remove_event_callback() for argument description.
525+ */
526+ typedef int (* pwm_manage_event_callback_t )(const struct device * dev ,
527+ struct pwm_event_callback * callback , bool set );
528+ #endif /* CONFIG_PWM_EVENT */
529+
443530/** @brief PWM driver API definition. */
444531__subsystem struct pwm_driver_api {
445532 pwm_set_cycles_t set_cycles ;
@@ -449,6 +536,9 @@ __subsystem struct pwm_driver_api {
449536 pwm_enable_capture_t enable_capture ;
450537 pwm_disable_capture_t disable_capture ;
451538#endif /* CONFIG_PWM_CAPTURE */
539+ #ifdef CONFIG_PWM_EVENT
540+ pwm_manage_event_callback_t manage_event_callback ;
541+ #endif /* CONFIG_PWM_EVENT */
452542};
453543/** @endcond */
454544
@@ -933,6 +1023,74 @@ static inline int pwm_capture_nsec(const struct device *dev, uint32_t channel,
9331023 return 0 ;
9341024}
9351025
1026+ #if defined(CONFIG_PWM_EVENT ) || defined(__DOXYGEN__ )
1027+ /**
1028+ * @brief Helper to initialize a struct pwm_event_callback properly.
1029+ *
1030+ * @param callback A valid application's callback structure pointer.
1031+ * @param handler A valid handler function pointer.
1032+ * @param channel Relevant channel for the handler.
1033+ * @param event_mask A bit mask of relevant events for the handler.
1034+ */
1035+ static inline void pwm_init_event_callback (struct pwm_event_callback * callback ,
1036+ pwm_event_callback_handler_t handler , uint32_t channel ,
1037+ pwm_events_t event_mask )
1038+ {
1039+ __ASSERT_NO_MSG (callback != NULL );
1040+ __ASSERT_NO_MSG (handler != NULL );
1041+
1042+ callback -> handler = handler ;
1043+ callback -> channel = channel ;
1044+ callback -> event_mask = event_mask ;
1045+ }
1046+
1047+ /**
1048+ * @brief Add an application event callback.
1049+ *
1050+ * @note As many callbacks as needed can be added on a PWM device instance.
1051+ *
1052+ * @param[in] dev PWM device instance.
1053+ * @param callback A valid applications callback structure pointer.
1054+ *
1055+ * @retval 0 on success.
1056+ * @retval -ENOSYS if driver does not manage event callbacks.
1057+ * @retval negative errno on failure.
1058+ */
1059+ static inline int pwm_add_event_callback (const struct device * dev ,
1060+ struct pwm_event_callback * callback )
1061+ {
1062+ const struct pwm_driver_api * api = (const struct pwm_driver_api * )dev -> api ;
1063+
1064+ if (api -> manage_event_callback == NULL ) {
1065+ return - ENOSYS ;
1066+ }
1067+
1068+ return api -> manage_event_callback (dev , callback , true);
1069+ }
1070+
1071+ /**
1072+ * @brief Remove an application event callback.
1073+ *
1074+ * @param[in] dev PWM device instance.
1075+ * @param callback A valid applications callback structure pointer.
1076+ *
1077+ * @retval 0 on success.
1078+ * @retval -ENOSYS if driver does not manage event callbacks.
1079+ * @retval negative errno on failure.
1080+ */
1081+ static inline int pwm_remove_event_callback (const struct device * dev ,
1082+ struct pwm_event_callback * callback )
1083+ {
1084+ const struct pwm_driver_api * api = (const struct pwm_driver_api * )dev -> api ;
1085+
1086+ if (api -> manage_event_callback == NULL ) {
1087+ return - ENOSYS ;
1088+ }
1089+
1090+ return api -> manage_event_callback (dev , callback , false);
1091+ }
1092+ #endif /* defined(CONFIG_PWM_EVENT) || defined(__DOXYGEN__) */
1093+
9361094/**
9371095 * @brief Validate that the PWM device is ready.
9381096 *
0 commit comments