-
Notifications
You must be signed in to change notification settings - Fork 7.3k
Added EWM Driver #88389
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Added EWM Driver #88389
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
# Copyright 2025 NXP | ||
# SPDX-License-Identifier: Apache-2.0 | ||
|
||
config WDT_NXP_EWM | ||
bool "NXP EWM driver" | ||
default y | ||
depends on DT_HAS_NXP_EWM_ENABLED | ||
help | ||
Enable the nxp ewm driver. |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,192 @@ | ||
/* | ||
* Copyright 2025 NXP | ||
* | ||
* SPDX-License-Identifier: Apache-2.0 | ||
*/ | ||
|
||
#define DT_DRV_COMPAT nxp_ewm | ||
|
||
#include <zephyr/drivers/watchdog.h> | ||
#include <zephyr/irq.h> | ||
|
||
#include <zephyr/logging/log.h> | ||
LOG_MODULE_REGISTER(wdt_nxp_ewm); | ||
|
||
#define NXP_EWM_FEED_MAGIC_NUMBER 0x2CB4 | ||
#define NXP_EWM_MAX_TIMEOUT_WINDOW 0xFE | ||
|
||
struct nxp_ewm_config { | ||
EWM_Type *base; | ||
void (*irq_config_func)(const struct device *dev); | ||
bool is_input_enabled; | ||
bool is_input_active_high; | ||
uint8_t clk_divider; | ||
}; | ||
|
||
struct nxp_ewm_data { | ||
struct wdt_timeout_cfg timeout_cfg; | ||
bool is_watchdog_setup; | ||
}; | ||
|
||
static int nxp_ewm_setup(const struct device *dev, uint8_t options) | ||
{ | ||
const struct nxp_ewm_config *config = dev->config; | ||
struct nxp_ewm_data *data = dev->data; | ||
EWM_Type *base = config->base; | ||
|
||
if (data->is_watchdog_setup) { | ||
/* Watchdog cannot be re-configured after enabled. */ | ||
return -EBUSY; | ||
} | ||
|
||
if (options) { | ||
/* Unable to halt counter during debugging */ | ||
return -ENOTSUP; | ||
} | ||
|
||
data->is_watchdog_setup = true; | ||
base->CMPL = EWM_CMPL_COMPAREL(data->timeout_cfg.window.min); | ||
base->CMPH = EWM_CMPH_COMPAREH(data->timeout_cfg.window.max); | ||
|
||
/* | ||
* base->CTRL should be the last thing touched due to | ||
* the small watchdog window time. | ||
* After this write, only the INTEN bit is writable until reset. | ||
* | ||
* EWM_CTRL_INTEN enables the interrupt signal | ||
* EWM_CTRL_EWMEN enables the watchdog. | ||
*/ | ||
base->CTRL |= EWM_CTRL_INEN(config->is_input_enabled) | | ||
EWM_CTRL_ASSIN(config->is_input_active_high) | | ||
EWM_CTRL_INTEN(1) | EWM_CTRL_EWMEN(1); | ||
|
||
return 0; | ||
} | ||
|
||
static int nxp_ewm_disable(const struct device *dev) | ||
{ | ||
struct nxp_ewm_data *data = dev->data; | ||
|
||
if (!data->is_watchdog_setup) { | ||
return -EFAULT; | ||
} | ||
|
||
return -EPERM; | ||
} | ||
|
||
static int nxp_ewm_install_timeout(const struct device *dev, | ||
const struct wdt_timeout_cfg *cfg) | ||
{ | ||
struct nxp_ewm_data *data = dev->data; | ||
|
||
if (cfg->flags) { | ||
return -ENOTSUP; | ||
} | ||
|
||
if (data->is_watchdog_setup) { | ||
return -ENOMEM; | ||
} | ||
|
||
if (cfg && cfg->window.max <= NXP_EWM_MAX_TIMEOUT_WINDOW && | ||
cfg->window.min <= cfg->window.max && | ||
cfg->window.max > 0 && | ||
cfg->window.min >= 0) { | ||
data->timeout_cfg.window = cfg->window; | ||
} else { | ||
return -EINVAL; | ||
} | ||
|
||
#if defined(CONFIG_WDT_MULTISTAGE) | ||
if (cfg->next) { | ||
return -EINVAL; | ||
} | ||
#endif | ||
|
||
if (cfg->callback) { | ||
data->timeout_cfg.callback = cfg->callback; | ||
} | ||
|
||
return 0; | ||
} | ||
|
||
static int nxp_ewm_feed(const struct device *dev, int channel_id) | ||
{ | ||
ARG_UNUSED(channel_id); | ||
const struct nxp_ewm_config *config = dev->config; | ||
EWM_Type *base = config->base; | ||
unsigned int key = irq_lock(); | ||
|
||
base->SERV = EWM_SERV_SERVICE(NXP_EWM_FEED_MAGIC_NUMBER); | ||
base->SERV = EWM_SERV_SERVICE((uint8_t)(NXP_EWM_FEED_MAGIC_NUMBER >> 8)); | ||
irq_unlock(key); | ||
|
||
return 0; | ||
} | ||
|
||
static void nxp_ewm_isr(const struct device *dev) | ||
{ | ||
const struct nxp_ewm_config *config = dev->config; | ||
struct nxp_ewm_data *data = dev->data; | ||
EWM_Type *base = config->base; | ||
|
||
base->CTRL &= (~EWM_CTRL_INTEN_MASK); | ||
|
||
if (data->timeout_cfg.callback) { | ||
data->timeout_cfg.callback(dev, 0); | ||
} | ||
} | ||
|
||
static int nxp_ewm_init(const struct device *dev) | ||
{ | ||
const struct nxp_ewm_config *config = dev->config; | ||
EWM_Type *base = config->base; | ||
|
||
if (config->clk_divider >= 0 && config->clk_divider <= 0xFF) { | ||
base->CLKPRESCALER = EWM_CLKPRESCALER_CLK_DIV(config->clk_divider); | ||
} | ||
config->irq_config_func(dev); | ||
|
||
return 0; | ||
} | ||
|
||
static DEVICE_API(wdt, nxp_ewm_api) = { | ||
.setup = nxp_ewm_setup, | ||
.disable = nxp_ewm_disable, | ||
.install_timeout = nxp_ewm_install_timeout, | ||
.feed = nxp_ewm_feed, | ||
}; | ||
|
||
#define WDT_EWM_INIT(n) \ | ||
static void nxp_ewm_config_func_##n(const struct device *dev); \ | ||
\ | ||
static const struct nxp_ewm_config nxp_ewm_config_##n = { \ | ||
.base = (EWM_Type *)DT_INST_REG_ADDR(n), \ | ||
.irq_config_func = nxp_ewm_config_func_##n, \ | ||
.is_input_enabled = DT_INST_PROP(n, input_trigger_en), \ | ||
.is_input_active_high = \ | ||
DT_INST_PROP(n, input_trigger_active_high), \ | ||
.clk_divider = DT_INST_PROP(n, clk_divider), \ | ||
}; \ | ||
\ | ||
static struct nxp_ewm_data nxp_ewm_data_##n; \ | ||
\ | ||
DEVICE_DT_INST_DEFINE(n, \ | ||
nxp_ewm_init, \ | ||
NULL, \ | ||
&nxp_ewm_data_##n, &nxp_ewm_config_##n, \ | ||
POST_KERNEL, \ | ||
CONFIG_KERNEL_INIT_PRIORITY_DEVICE, \ | ||
&nxp_ewm_api); \ | ||
\ | ||
static void nxp_ewm_config_func_##n(const struct device *dev) \ | ||
{ \ | ||
ARG_UNUSED(dev); \ | ||
\ | ||
IRQ_CONNECT(DT_INST_IRQN(n), \ | ||
DT_INST_IRQ(n, priority), \ | ||
nxp_ewm_isr, DEVICE_DT_INST_GET(n), 0); \ | ||
\ | ||
irq_enable(DT_INST_IRQN(n)); \ | ||
} | ||
|
||
DT_INST_FOREACH_STATUS_OKAY(WDT_EWM_INIT) |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,32 @@ | ||
# Copyright 2025 NXP | ||
# SPDX-License-Identifier: Apache-2.0 | ||
|
||
description: NXP External Watchdog Monitor | ||
|
||
compatible: "nxp,ewm" | ||
|
||
include: base.yaml | ||
|
||
properties: | ||
reg: | ||
required: true | ||
|
||
interrupts: | ||
required: true | ||
|
||
clk-divider: | ||
type: int | ||
description: Watchdog clock divider | ||
required: true | ||
|
||
input_trigger_en: | ||
type: boolean | ||
description: | | ||
When enabled the ewm_in signal can be used | ||
to assert the ewm. | ||
|
||
input_trigger_active_high: | ||
type: boolean | ||
description: | | ||
When enabled the ewm_in signal is active high. | ||
The ewm_in signal is active low otherwise. |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
# Copyright 2025 NXP | ||
# SPDX-License-Identifier: Apache-2.0 | ||
|
||
source "Kconfig.zephyr" | ||
|
||
config TEST_WDT_MAX_WINDOW_TIME | ||
int "Watchdog Max Value" | ||
default 1000 | ||
help | ||
Set the watchdog max window time to feed the watchdog. | ||
The units for this value will change based on the watchdog | ||
driver being tested. Most drivers represent this as milliseconds | ||
due to the max window reaching the millisecond feed window. | ||
|
||
config TEST_WDT_SLEEP_TIME | ||
int "Watchdog Sleep Time" | ||
default 500 | ||
help | ||
Set the test sleep time between watchdog feeds. | ||
DerekSnell marked this conversation as resolved.
Show resolved
Hide resolved
|
||
The units for this value will change based on the watchdog | ||
driver being tested. Most drivers represent this as milliseconds | ||
due to the max window reaching the millisecond feed window. |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
/* | ||
* Copyright 2025 NXP | ||
* SPDX-License-Identifier: Apache-2.0 | ||
*/ | ||
|
||
/ { | ||
aliases { | ||
watchdog0 = &ewm0; | ||
}; | ||
}; | ||
|
||
&ewm0 { | ||
status = "okay"; | ||
}; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,5 +1,5 @@ | ||
/* | ||
* Copyright 2022 NXP | ||
* Copyright 2022, 2025 NXP | ||
* | ||
* SPDX-License-Identifier: Apache-2.0 | ||
*/ | ||
|
@@ -20,10 +20,18 @@ | |
#endif | ||
|
||
#define WDT_FEED_TRIES 2 | ||
#define WDT_MAX_WINDOW 1000 | ||
#define WDT_TIMEOUT K_MSEC(1100) | ||
#define SLEEP_TIME K_MSEC(500) | ||
#define WDT_TEST_CB_TEST_VALUE 0xCB | ||
#define WDT_TIMEOUT_VALUE CONFIG_TEST_WDT_MAX_WINDOW_TIME + 10 | ||
|
||
#if defined(CONFIG_WDT_NXP_EWM) | ||
#define WDT_SETUP_FLAGS 0 | ||
#define WDT_TIMEOUT K_TICKS(WDT_TIMEOUT_VALUE) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Why does the There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The watchdog window to feed the watchdog is in the Microsecond range. The Tick value is the most accurate speed to test this EWM without having to worry about the test unintentionally missing a watchdog feed. |
||
#define SLEEP_TIME K_TICKS(CONFIG_TEST_WDT_SLEEP_TIME) | ||
#else | ||
#define WDT_SETUP_FLAGS WDT_OPT_PAUSE_HALTED_BY_DBG | ||
#define WDT_TIMEOUT K_MSEC(WDT_TIMEOUT_VALUE) | ||
#define SLEEP_TIME K_MSEC(CONFIG_TEST_WDT_SLEEP_TIME) | ||
#endif | ||
|
||
static struct wdt_timeout_cfg m_cfg_wdt0; | ||
static volatile int wdt_interrupted_flag; | ||
|
@@ -49,7 +57,7 @@ static int test_wdt_callback_reset_none(void) | |
} | ||
|
||
m_cfg_wdt0.window.min = 0U; | ||
m_cfg_wdt0.window.max = WDT_MAX_WINDOW; | ||
m_cfg_wdt0.window.max = CONFIG_TEST_WDT_MAX_WINDOW_TIME; | ||
m_cfg_wdt0.flags = WDT_FLAG_RESET_NONE; | ||
m_cfg_wdt0.callback = wdt_callback; | ||
|
||
|
@@ -62,7 +70,7 @@ static int test_wdt_callback_reset_none(void) | |
return TC_FAIL; | ||
} | ||
|
||
err = wdt_setup(wdt, WDT_OPT_PAUSE_HALTED_BY_DBG); | ||
err = wdt_setup(wdt, WDT_SETUP_FLAGS); | ||
if (err != 0) { | ||
TC_PRINT("Watchdog setup error\n"); | ||
return TC_FAIL; | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
is this macro going to convert the 16 bit integer literal to 8 bit ?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It should but extra precaution I added a cast to 8 bit