diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig index 2747695486..f22ea78be9 100644 --- a/drivers/gpio/Kconfig +++ b/drivers/gpio/Kconfig @@ -59,6 +59,16 @@ config GPIO_HOGS_INIT_PRIORITY GPIO hogs initialization priority. GPIO hogs must be initialized after the GPIO controller drivers. +config GPIO_ENABLE_DISABLE_INTERRUPT + bool "Support for enable/disable interrupt without re-config [EXPERIMENTAL]" + select EXPERIMENTAL + help + This option enables the support for enabling/disabling interrupt with + previous configuration, and enabling/disabling the interrupt only turns + on/off the interrupt signal without changing other registers, such as + pending register, etc. The driver must implement it to work. + + source "drivers/gpio/Kconfig.b91" source "drivers/gpio/Kconfig.dw" diff --git a/include/zephyr/drivers/gpio.h b/include/zephyr/drivers/gpio.h index d73e20c8aa..112a448e05 100644 --- a/include/zephyr/drivers/gpio.h +++ b/include/zephyr/drivers/gpio.h @@ -86,6 +86,11 @@ extern "C" { * flag. If a pin was configured as Active Low, physical level low will be * considered as logical level 1 (an active state), physical level high will * be considered as logical level 0 (an inactive state). + * The GPIO controller should reset the interrupt status, such as clearing the + * pending bit, etc, when configuring the interrupt triggering properties. + * Applications should use the `GPIO_INT_MODE_ENABLE_ONLY` and + * `GPIO_INT_MODE_DISABLE_ONLY` flags to enable and disable interrupts on the + * pin without changing any GPIO settings. * @{ */ @@ -129,6 +134,16 @@ extern "C" { */ #define GPIO_INT_HIGH_1 (1U << 26) +#ifdef CONFIG_GPIO_ENABLE_DISABLE_INTERRUPT +/* Disable/Enable interrupt functionality without changing other interrupt + * related register, such as clearing the pending register. + * + * This is a component flag that should be combined with `GPIO_INT_ENABLE` or + * `GPIO_INT_DISABLE` flags to produce a meaningful configuration. + */ +#define GPIO_INT_ENABLE_DISABLE_ONLY (1u << 27) +#endif /* CONFIG_GPIO_ENABLE_DISABLE_INTERRUPT */ + #define GPIO_INT_MASK (GPIO_INT_DISABLE | \ GPIO_INT_ENABLE | \ GPIO_INT_LEVELS_LOGICAL | \ @@ -509,6 +524,10 @@ enum gpio_int_mode { GPIO_INT_MODE_DISABLED = GPIO_INT_DISABLE, GPIO_INT_MODE_LEVEL = GPIO_INT_ENABLE, GPIO_INT_MODE_EDGE = GPIO_INT_ENABLE | GPIO_INT_EDGE, +#ifdef CONFIG_GPIO_ENABLE_DISABLE_INTERRUPT + GPIO_INT_MODE_DISABLE_ONLY = GPIO_INT_DISABLE | GPIO_INT_ENABLE_DISABLE_ONLY, + GPIO_INT_MODE_ENABLE_ONLY = GPIO_INT_ENABLE | GPIO_INT_ENABLE_DISABLE_ONLY, +#endif /* CONFIG_GPIO_ENABLE_DISABLE_INTERRUPT */ }; enum gpio_int_trig { @@ -624,7 +643,12 @@ static inline int z_impl_gpio_pin_interrupt_configure(const struct device *port, "enabled for a level interrupt."); __ASSERT(((flags & GPIO_INT_ENABLE) == 0) || - ((flags & (GPIO_INT_LOW_0 | GPIO_INT_HIGH_1)) != 0), +#ifdef CONFIG_GPIO_ENABLE_DISABLE_INTERRUPT + ((flags & (GPIO_INT_LOW_0 | GPIO_INT_HIGH_1)) != 0) || + (flags & GPIO_INT_ENABLE_DISABLE_ONLY) != 0, +#else + ((flags & (GPIO_INT_LOW_0 | GPIO_INT_HIGH_1)) != 0), +#endif /* CONFIG_GPIO_ENABLE_DISABLE_INTERRUPT */ "At least one of GPIO_INT_LOW_0, GPIO_INT_HIGH_1 has to be " "enabled."); @@ -638,7 +662,12 @@ static inline int z_impl_gpio_pin_interrupt_configure(const struct device *port, } trig = (enum gpio_int_trig)(flags & (GPIO_INT_LOW_0 | GPIO_INT_HIGH_1)); +#ifdef CONFIG_GPIO_ENABLE_DISABLE_INTERRUPT + mode = (enum gpio_int_mode)(flags & (GPIO_INT_EDGE | GPIO_INT_DISABLE | GPIO_INT_ENABLE | + GPIO_INT_ENABLE_DISABLE_ONLY)); +#else mode = (enum gpio_int_mode)(flags & (GPIO_INT_EDGE | GPIO_INT_DISABLE | GPIO_INT_ENABLE)); +#endif /* CONFIG_GPIO_ENABLE_DISABLE_INTERRUPT */ return api->pin_interrupt_configure(port, pin, mode, trig); }