drivers: watchdog: Added Driver for the EWM
Added a driver for the External Watchdog Driver Signed-off-by: Emilio Benavente <emilio.benavente@nxp.com>
This commit is contained in:
parent
54b826336b
commit
5fd6715917
6 changed files with 240 additions and 0 deletions
|
@ -60,5 +60,6 @@ zephyr_library_sources_ifdef(CONFIG_WDT_ANDES_ATCWDT200 wdt_andes_atcwdt200.c)
|
||||||
zephyr_library_sources_ifdef(CONFIG_WDT_NXP_FS26 wdt_nxp_fs26.c)
|
zephyr_library_sources_ifdef(CONFIG_WDT_NXP_FS26 wdt_nxp_fs26.c)
|
||||||
zephyr_library_sources_ifdef(CONFIG_WDT_SHELL wdt_shell.c)
|
zephyr_library_sources_ifdef(CONFIG_WDT_SHELL wdt_shell.c)
|
||||||
zephyr_library_sources_ifdef(CONFIG_WDT_RENESAS_RA wdt_renesas_ra.c)
|
zephyr_library_sources_ifdef(CONFIG_WDT_RENESAS_RA wdt_renesas_ra.c)
|
||||||
|
zephyr_library_sources_ifdef(CONFIG_WDT_NXP_EWM wdt_nxp_ewm.c)
|
||||||
|
|
||||||
zephyr_library_sources_ifdef(CONFIG_USERSPACE wdt_handlers.c)
|
zephyr_library_sources_ifdef(CONFIG_USERSPACE wdt_handlers.c)
|
||||||
|
|
|
@ -155,4 +155,6 @@ source "drivers/watchdog/Kconfig.renesas_ra"
|
||||||
|
|
||||||
source "drivers/watchdog/Kconfig.wch"
|
source "drivers/watchdog/Kconfig.wch"
|
||||||
|
|
||||||
|
source "drivers/watchdog/Kconfig.nxp_ewm"
|
||||||
|
|
||||||
endif # WATCHDOG
|
endif # WATCHDOG
|
||||||
|
|
9
drivers/watchdog/Kconfig.nxp_ewm
Normal file
9
drivers/watchdog/Kconfig.nxp_ewm
Normal file
|
@ -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.
|
192
drivers/watchdog/wdt_nxp_ewm.c
Normal file
192
drivers/watchdog/wdt_nxp_ewm.c
Normal file
|
@ -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)
|
32
dts/bindings/watchdog/nxp,ewm.yaml
Normal file
32
dts/bindings/watchdog/nxp,ewm.yaml
Normal file
|
@ -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.
|
|
@ -188,6 +188,10 @@ __weak void clock_init(void)
|
||||||
if (DT_NODE_HAS_COMPAT_STATUS(adc0, nxp_lpadc, okay)) {
|
if (DT_NODE_HAS_COMPAT_STATUS(adc0, nxp_lpadc, okay)) {
|
||||||
CLOCK_EnableClock(kCLOCK_Lpadc0);
|
CLOCK_EnableClock(kCLOCK_Lpadc0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (DT_NODE_HAS_COMPAT_STATUS(DT_NODELABEL(ewm0), nxp_ewm, okay)) {
|
||||||
|
CLOCK_EnableClock(kCLOCK_Ewm0);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void vbat_init(void)
|
static void vbat_init(void)
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue