diff --git a/drivers/gpio/gpio_rts5912.c b/drivers/gpio/gpio_rts5912.c index c043bd372d844..2c944a75033f3 100644 --- a/drivers/gpio/gpio_rts5912.c +++ b/drivers/gpio/gpio_rts5912.c @@ -15,6 +15,9 @@ #include "zephyr/drivers/gpio/gpio_utils.h" #include #include +#include +#include +#include #include @@ -33,6 +36,22 @@ struct gpio_rts5912_data { sys_slist_t callbacks; }; +#if defined(CONFIG_PM) +#define GPIO_EXPIRED_TIMEOUT_MS 1000 +static struct k_work_delayable gpio_wake_delay_work; +static atomic_t gpio_wake_hold; /* 0: no hold, 1: holding */ +static atomic_t gpio_wake_init_once; /* 0: not inited, 1: inited */ + +static void gpio_wake_delay_work_handler(struct k_work *work) +{ + ARG_UNUSED(work); + + if (atomic_cas(&gpio_wake_hold, 1, 0)) { + pm_policy_state_lock_put(PM_STATE_SUSPEND_TO_IDLE, PM_ALL_SUBSTATES); + } +} +#endif /* CONFIG_PM */ + static int pin_is_valid(const struct gpio_rts5912_config *config, gpio_pin_t pin) { if (pin >= config->num_pins) { @@ -455,6 +474,14 @@ static void gpio_rts5912_isr(const void *arg) if (gcr[pin] & GPIO_GCR_INTSTS_Msk) { gcr[pin] |= GPIO_GCR_INTSTS_Msk; +#if defined(CONFIG_PM) + if (atomic_cas(&gpio_wake_hold, 0, 1)) { + pm_policy_state_lock_get(PM_STATE_SUSPEND_TO_IDLE, PM_ALL_SUBSTATES); + } + k_work_reschedule(&gpio_wake_delay_work, + K_MSEC(GPIO_EXPIRED_TIMEOUT_MS)); +#endif + gpio_fire_callbacks(&data->callbacks, port, BIT(pin)); } irq_unlock(key); @@ -567,6 +594,14 @@ static DEVICE_API(gpio, gpio_rts5912_driver_api) = { { \ if (!(DT_INST_IRQ_HAS_CELL(id, irq))) { \ return 0; \ + } \ + \ + if (IS_ENABLED(CONFIG_PM)) { \ + if (atomic_cas(&gpio_wake_init_once, 0, 1)) { \ + k_work_init_delayable(&gpio_wake_delay_work, \ + gpio_wake_delay_work_handler); \ + atomic_clear(&gpio_wake_hold); \ + } \ } \ \ RTS5912_GPIO_DTNAMIC_IRQ(id) \