From 64b8d9e0cfa105df97d7a5f847e90f07d5fb48ce Mon Sep 17 00:00:00 2001 From: Alex Rodriguez Date: Thu, 8 May 2025 23:14:48 -0500 Subject: [PATCH] drivers: watchdog: wdt_mcux_wwdt: Add PM support for low power modes Enables sleep mode (PM3) on RW61x. The driver re-enables the wdt on wake-up based on the previous configuration. Note that the wdt counter value always resets to the max window value on wake-up Signed-off-by: Alex Rodriguez --- drivers/watchdog/wdt_mcux_wwdt.c | 52 +++++++++++++++++++++++++++++--- 1 file changed, 48 insertions(+), 4 deletions(-) diff --git a/drivers/watchdog/wdt_mcux_wwdt.c b/drivers/watchdog/wdt_mcux_wwdt.c index 81ab8a5b001..43ad1cd5048 100644 --- a/drivers/watchdog/wdt_mcux_wwdt.c +++ b/drivers/watchdog/wdt_mcux_wwdt.c @@ -3,7 +3,7 @@ * * Based on wdt_mcux_wdog32.c, which is: * Copyright (c) 2019 Vestas Wind Systems A/S - * Copyright (c) 2018, NXP + * Copyright 2018, 2025 NXP * * SPDX-License-Identifier: Apache-2.0 */ @@ -13,6 +13,7 @@ #include #include #include +#include #include #include @@ -32,6 +33,7 @@ struct mcux_wwdt_data { wdt_callback_t callback; wwdt_config_t wwdt_config; bool timeout_valid; + bool active_before_sleep; }; static int mcux_wwdt_setup(const struct device *dev, uint8_t options) @@ -59,6 +61,7 @@ static int mcux_wwdt_disable(const struct device *dev) WWDT_Deinit(base); data->timeout_valid = false; + data->active_before_sleep = false; LOG_DBG("Disabled the watchdog"); return 0; @@ -167,13 +170,52 @@ static void mcux_wwdt_isr(const struct device *dev) } } +/* + * Power Management: + * When the system enters sleep mode, this driver maintains awareness + * of whether the WWDT was active. After wake up, the WDT counter + * resets to its reload value. + */ +static int mcux_wwdt_driver_pm_action(const struct device *dev, + enum pm_device_action action) +{ + const struct mcux_wwdt_config *config = dev->config; + struct mcux_wwdt_data *data = dev->data; + int err = 0; + + switch (action) { + case PM_DEVICE_ACTION_RESUME: + break; + case PM_DEVICE_ACTION_TURN_ON: + if (data->active_before_sleep) { + err = mcux_wwdt_setup(dev, 0); + data->active_before_sleep = false; + } + break; + case PM_DEVICE_ACTION_SUSPEND: + break; + case PM_DEVICE_ACTION_TURN_OFF: + if (config->base->MOD & WWDT_MOD_WDEN_MASK) { + data->active_before_sleep = true; + } + break; + default: + err = -ENOTSUP; + } + + return err; +} + static int mcux_wwdt_init(const struct device *dev) { const struct mcux_wwdt_config *config = dev->config; + /* The rest of the device init is done from the + * PM_DEVICE_ACTION_TURN_ON in the pm callback + * which is invoked by pm_device_driver_init. + */ config->irq_config_func(dev); - - return 0; + return pm_device_driver_init(dev, mcux_wwdt_driver_pm_action); } static DEVICE_API(wdt, mcux_wwdt_api) = { @@ -194,8 +236,10 @@ static const struct mcux_wwdt_config mcux_wwdt_config_0 = { static struct mcux_wwdt_data mcux_wwdt_data_0; +PM_DEVICE_DT_INST_DEFINE(0, mcux_wwdt_driver_pm_action); + DEVICE_DT_INST_DEFINE(0, &mcux_wwdt_init, - NULL, &mcux_wwdt_data_0, + PM_DEVICE_DT_INST_GET(0), &mcux_wwdt_data_0, &mcux_wwdt_config_0, POST_KERNEL, CONFIG_KERNEL_INIT_PRIORITY_DEVICE, &mcux_wwdt_api);