Skip to content

Commit 805bedd

Browse files
committed
drivers: watchdog: Added Driver for the EWM
Added a driver for the External Watchdog Driver Signed-off-by: Emilio Benavente <[email protected]>
1 parent 8a4bb18 commit 805bedd

File tree

6 files changed

+247
-0
lines changed

6 files changed

+247
-0
lines changed

drivers/watchdog/CMakeLists.txt

+1
Original file line numberDiff line numberDiff line change
@@ -57,5 +57,6 @@ zephyr_library_sources_ifdef(CONFIG_WDT_ANDES_ATCWDT200 wdt_andes_atcwdt200.c)
5757
zephyr_library_sources_ifdef(CONFIG_WDT_NXP_FS26 wdt_nxp_fs26.c)
5858
zephyr_library_sources_ifdef(CONFIG_WDT_SHELL wdt_shell.c)
5959
zephyr_library_sources_ifdef(CONFIG_WDT_RENESAS_RA wdt_renesas_ra.c)
60+
zephyr_library_sources_ifdef(CONFIG_WDT_NXP_EWM wdt_nxp_ewm.c)
6061

6162
zephyr_library_sources_ifdef(CONFIG_USERSPACE wdt_handlers.c)

drivers/watchdog/Kconfig

+2
Original file line numberDiff line numberDiff line change
@@ -149,4 +149,6 @@ source "drivers/watchdog/Kconfig.rts5912"
149149

150150
source "drivers/watchdog/Kconfig.renesas_ra"
151151

152+
source "drivers/watchdog/Kconfig.nxp_ewm"
153+
152154
endif # WATCHDOG

drivers/watchdog/Kconfig.nxp_ewm

+9
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
# Copyright 2025 NXP
2+
# SPDX-License-Identifier: Apache-2.0
3+
4+
config WDT_NXP_EWM
5+
bool "NXP EWM driver"
6+
default y
7+
depends on DT_HAS_NXP_EWM_ENABLED
8+
help
9+
Enable the nxp ewm driver.

drivers/watchdog/wdt_nxp_ewm.c

+199
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,199 @@
1+
/*
2+
*
3+
* Copyright 2025 NXP
4+
*
5+
* SPDX-License-Identifier: Apache-2.0
6+
*/
7+
8+
#define DT_DRV_COMPAT nxp_ewm
9+
10+
#include <zephyr/drivers/watchdog.h>
11+
#include <zephyr/irq.h>
12+
#include <fsl_clock.h>
13+
14+
#define LOG_LEVEL CONFIG_WDT_LOG_LEVEL
15+
#include <zephyr/logging/log.h>
16+
LOG_MODULE_REGISTER(wdt_nxp_ewm);
17+
18+
#define NXP_EWM_FEED_MAGIC_NUMBER 0x2CB4
19+
#define NXP_EWM_MAX_TIMEOUT_WINDOW 0xFE
20+
21+
struct nxp_ewm_config {
22+
EWM_Type *base;
23+
void (*irq_config_func)(const struct device *dev);
24+
bool is_input_enabled;
25+
bool is_input_active_high;
26+
uint8_t clk_divider;
27+
};
28+
29+
struct nxp_ewm_data {
30+
struct wdt_timeout_cfg timeout_cfg;
31+
bool is_watchdog_setup;
32+
};
33+
34+
static int nxp_ewm_setup(const struct device *dev, uint8_t options)
35+
{
36+
const struct nxp_ewm_config *config = dev->config;
37+
struct nxp_ewm_data *data = dev->data;
38+
EWM_Type *base = config->base;
39+
40+
if (!data->is_watchdog_setup) {
41+
if (options) {
42+
/* Unable to halt counter during debugging */
43+
return -ENOTSUP;
44+
}
45+
data->is_watchdog_setup = true;
46+
47+
base->CMPL = EWM_CMPL_COMPAREL(data->timeout_cfg.window.min);
48+
base->CMPH = EWM_CMPH_COMPAREH(data->timeout_cfg.window.max);
49+
50+
/*
51+
* base->CTRL should be the last thing touched due to
52+
* the small watchdog window time.
53+
* After this write, only the INTEN bit is writable until reset.
54+
*
55+
* EWM_CTRL_INTEN enables the interrupt signal
56+
* EWM_CTRL_EWMEN enables the watchdog.
57+
*/
58+
base->CTRL |= EWM_CTRL_INEN(config->is_input_enabled) |
59+
EWM_CTRL_ASSIN(config->is_input_active_high) |
60+
EWM_CTRL_INTEN(1) | EWM_CTRL_EWMEN(1);
61+
62+
return 0;
63+
}
64+
65+
/* Watchdog cannot be re-configured after enabled. */
66+
return -EBUSY;
67+
}
68+
69+
static int nxp_ewm_disable(const struct device *dev)
70+
{
71+
struct nxp_ewm_data *data = dev->data;
72+
73+
if (!data->is_watchdog_setup) {
74+
return -EFAULT;
75+
}
76+
77+
return -EPERM;
78+
}
79+
80+
static int nxp_ewm_install_timeout(const struct device *dev,
81+
const struct wdt_timeout_cfg *cfg)
82+
{
83+
struct nxp_ewm_data *data = dev->data;
84+
85+
if (!data->is_watchdog_setup) {
86+
if (cfg && cfg->window.max <= NXP_EWM_MAX_TIMEOUT_WINDOW &&
87+
cfg->window.min <= cfg->window.max &&
88+
cfg->window.max > 0 &&
89+
cfg->window.min >= 0) {
90+
data->timeout_cfg.window = cfg->window;
91+
} else {
92+
return -EINVAL;
93+
}
94+
95+
#if defined(CONFIG_WDT_MULTISTAGE)
96+
if (cfg->next) {
97+
return -EINVAL;
98+
}
99+
#endif
100+
101+
if (cfg->callback) {
102+
data->timeout_cfg.callback = cfg->callback;
103+
}
104+
105+
if (cfg->flags) {
106+
return -ENOTSUP;
107+
}
108+
109+
return 0;
110+
}
111+
112+
/* Only one watchdog timeout is available */
113+
return -ENOMEM;
114+
}
115+
116+
static int nxp_ewm_feed(const struct device *dev, int channel_id)
117+
{
118+
ARG_UNUSED(channel_id);
119+
const struct nxp_ewm_config *config = dev->config;
120+
EWM_Type *base = config->base;
121+
unsigned int key = irq_lock();
122+
123+
base->SERV = EWM_SERV_SERVICE(NXP_EWM_FEED_MAGIC_NUMBER);
124+
base->SERV = EWM_SERV_SERVICE(NXP_EWM_FEED_MAGIC_NUMBER >> 8);
125+
irq_unlock(key);
126+
127+
return 0;
128+
}
129+
130+
static void nxp_ewm_isr(const struct device *dev)
131+
{
132+
const struct nxp_ewm_config *config = dev->config;
133+
struct nxp_ewm_data *data = dev->data;
134+
EWM_Type *base = config->base;
135+
136+
base->CTRL &= (~EWM_CTRL_INTEN_MASK);
137+
if (data->timeout_cfg.callback) {
138+
data->timeout_cfg.callback(dev, 0);
139+
}
140+
141+
if (data->timeout_cfg.flags) {
142+
143+
}
144+
}
145+
146+
static int nxp_ewm_init(const struct device *dev)
147+
{
148+
const struct nxp_ewm_config *config = dev->config;
149+
EWM_Type *base = config->base;
150+
151+
if (config->clk_divider >= 0 && config->clk_divider <= 0xFF) {
152+
base->CLKPRESCALER = EWM_CLKPRESCALER_CLK_DIV(config->clk_divider);
153+
}
154+
config->irq_config_func(dev);
155+
156+
return 0;
157+
}
158+
159+
static DEVICE_API(wdt, nxp_ewm_api) = {
160+
.setup = nxp_ewm_setup,
161+
.disable = nxp_ewm_disable,
162+
.install_timeout = nxp_ewm_install_timeout,
163+
.feed = nxp_ewm_feed,
164+
};
165+
166+
#define WDT_EWM_INIT(n) \
167+
static void nxp_ewm_config_func_##n(const struct device *dev); \
168+
\
169+
static const struct nxp_ewm_config nxp_ewm_config_##n = { \
170+
.base = (EWM_Type *)DT_INST_REG_ADDR(n), \
171+
.irq_config_func = nxp_ewm_config_func_##n, \
172+
.is_input_enabled = DT_INST_PROP(n, input_trigger_en), \
173+
.is_input_active_high = \
174+
DT_INST_PROP(n, input_trigger_active_high), \
175+
.clk_divider = DT_INST_PROP(n, clk_divider), \
176+
}; \
177+
\
178+
static struct nxp_ewm_data nxp_ewm_data_##n; \
179+
\
180+
DEVICE_DT_INST_DEFINE(n, \
181+
nxp_ewm_init, \
182+
NULL, \
183+
&nxp_ewm_data_##n, &nxp_ewm_config_##n, \
184+
POST_KERNEL, \
185+
CONFIG_KERNEL_INIT_PRIORITY_DEVICE, \
186+
&nxp_ewm_api); \
187+
\
188+
static void nxp_ewm_config_func_##n(const struct device *dev) \
189+
{ \
190+
ARG_UNUSED(dev); \
191+
\
192+
IRQ_CONNECT(DT_INST_IRQN(n), \
193+
DT_INST_IRQ(n, priority), \
194+
nxp_ewm_isr, DEVICE_DT_INST_GET(n), 0); \
195+
\
196+
irq_enable(DT_INST_IRQN(n)); \
197+
}
198+
199+
DT_INST_FOREACH_STATUS_OKAY(WDT_EWM_INIT)

dts/bindings/watchdog/nxp,ewm.yaml

+32
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
# Copyright 2025 NXP
2+
# SPDX-License-Identifier: Apache-2.0
3+
4+
description: NXP External Watchdog Monitor
5+
6+
compatible: "nxp,ewm"
7+
8+
include: base.yaml
9+
10+
properties:
11+
reg:
12+
required: true
13+
14+
interrupts:
15+
required: true
16+
17+
clk-divider:
18+
type: int
19+
description: Watchdog clock divider
20+
required: true
21+
22+
input_trigger_en:
23+
type: boolean
24+
description: |
25+
When enabled the ewm_in signal can be used
26+
to assert the ewm.
27+
28+
input_trigger_active_high:
29+
type: boolean
30+
description: |
31+
When enabled the ewm_in signal is active high.
32+
The ewm_in signal is active low otherwise.

soc/nxp/mcx/mcxw/soc.c

+4
Original file line numberDiff line numberDiff line change
@@ -188,6 +188,10 @@ __weak void clock_init(void)
188188
if (DT_NODE_HAS_COMPAT_STATUS(adc0, nxp_lpadc, okay)) {
189189
CLOCK_EnableClock(kCLOCK_Lpadc0);
190190
}
191+
192+
if (DT_NODE_HAS_COMPAT_STATUS(DT_NODELABEL(ewm0), nxp_ewm, okay)) {
193+
CLOCK_EnableClock(kCLOCK_Ewm0);
194+
}
191195
}
192196

193197
static void vbat_init(void)

0 commit comments

Comments
 (0)