drivers: watchdog: mcux_wwdt: add driver for NXP LPC 55xxx WWDT
Adds shim driver for LPC 55xxx Windowed Watchdog Timer (WWDT). Also updates the "Supported features" table in LPCXpresso55S69 board documentation page. Fixes #22704. Signed-off-by: Jiří Keresteš <jiri@kerestes.cz>
This commit is contained in:
parent
c8bc3753aa
commit
3a87517c5e
14 changed files with 257 additions and 0 deletions
|
@ -68,6 +68,8 @@ features:
|
|||
+-----------+------------+-------------------------------------+
|
||||
| USART | on-chip | serial port-polling |
|
||||
+-----------+------------+-------------------------------------+
|
||||
| WWDT | on-chip | windowed watchdog timer |
|
||||
+-----------+------------+-------------------------------------+
|
||||
|
||||
The default configuration file
|
||||
``boards/arm/lpcxpresso55s69/lpcxpresso55s69_cpu0_defconfig``
|
||||
|
|
|
@ -77,6 +77,10 @@
|
|||
status = "okay";
|
||||
};
|
||||
|
||||
&wwdt0 {
|
||||
status = "okay";
|
||||
};
|
||||
|
||||
&flash0 {
|
||||
/*
|
||||
* For more information, see:
|
||||
|
|
|
@ -20,3 +20,4 @@ supported:
|
|||
- gpio
|
||||
- i2c
|
||||
- spi
|
||||
- watchdog
|
||||
|
|
|
@ -79,3 +79,7 @@
|
|||
&hs_lspi {
|
||||
status = "okay";
|
||||
};
|
||||
|
||||
&wwdt0 {
|
||||
status = "okay";
|
||||
};
|
||||
|
|
|
@ -18,3 +18,4 @@ supported:
|
|||
- arduino_spi
|
||||
- gpio
|
||||
- spi
|
||||
- watchdog
|
||||
|
|
|
@ -9,6 +9,7 @@ zephyr_sources_ifdef(CONFIG_WDT_SAM0 wdt_sam0.c)
|
|||
zephyr_sources_ifdef(CONFIG_WDT_NRFX wdt_nrfx.c)
|
||||
zephyr_sources_ifdef(CONFIG_WDT_MCUX_WDOG wdt_mcux_wdog.c)
|
||||
zephyr_sources_ifdef(CONFIG_WDT_MCUX_WDOG32 wdt_mcux_wdog32.c)
|
||||
zephyr_sources_ifdef(CONFIG_WDT_MCUX_WWDT wdt_mcux_wwdt.c)
|
||||
zephyr_sources_ifdef(CONFIG_WDT_XEC wdt_mchp_xec.c)
|
||||
zephyr_sources_ifdef(CONFIG_WDT_GECKO wdt_gecko.c)
|
||||
zephyr_sources_ifdef(CONFIG_USERSPACE wdt_handlers.c)
|
||||
|
|
|
@ -14,3 +14,9 @@ config WDT_MCUX_WDOG32
|
|||
depends on HAS_MCUX_WDOG32 && CLOCK_CONTROL
|
||||
help
|
||||
Enable the mcux wdog32 driver.
|
||||
|
||||
config WDT_MCUX_WWDT
|
||||
bool "MCUX WWDT driver"
|
||||
depends on HAS_MCUX_WWDT
|
||||
help
|
||||
Enable the mcux wwdt driver.
|
||||
|
|
190
drivers/watchdog/wdt_mcux_wwdt.c
Normal file
190
drivers/watchdog/wdt_mcux_wwdt.c
Normal file
|
@ -0,0 +1,190 @@
|
|||
/*
|
||||
* Copyright (c) 2020, Jiri Kerestes
|
||||
*
|
||||
* Based on wdt_mcux_wdog32.c, which is:
|
||||
* Copyright (c) 2019 Vestas Wind Systems A/S
|
||||
* Copyright (c) 2018, NXP
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
#define DT_DRV_COMPAT nxp_lpc_wwdt
|
||||
|
||||
#include <drivers/watchdog.h>
|
||||
#include <fsl_wwdt.h>
|
||||
#include <fsl_clock.h>
|
||||
|
||||
#define LOG_LEVEL CONFIG_WDT_LOG_LEVEL
|
||||
#include <logging/log.h>
|
||||
LOG_MODULE_REGISTER(wdt_mcux_wwdt);
|
||||
|
||||
#define MIN_TIMEOUT 0xFF
|
||||
|
||||
struct mcux_wwdt_config {
|
||||
WWDT_Type *base;
|
||||
uint8_t clk_divider;
|
||||
void (*irq_config_func)(struct device *dev);
|
||||
};
|
||||
|
||||
struct mcux_wwdt_data {
|
||||
wdt_callback_t callback;
|
||||
wwdt_config_t wwdt_config;
|
||||
bool timeout_valid;
|
||||
};
|
||||
|
||||
static int mcux_wwdt_setup(struct device *dev, uint8_t options)
|
||||
{
|
||||
const struct mcux_wwdt_config *config = dev->config_info;
|
||||
struct mcux_wwdt_data *data = dev->driver_data;
|
||||
WWDT_Type *base = config->base;
|
||||
|
||||
if (!data->timeout_valid) {
|
||||
LOG_ERR("No valid timeouts installed");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
WWDT_Init(base, &data->wwdt_config);
|
||||
LOG_DBG("Setup the watchdog");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int mcux_wwdt_disable(struct device *dev)
|
||||
{
|
||||
const struct mcux_wwdt_config *config = dev->config_info;
|
||||
struct mcux_wwdt_data *data = dev->driver_data;
|
||||
WWDT_Type *base = config->base;
|
||||
|
||||
WWDT_Deinit(base);
|
||||
data->timeout_valid = false;
|
||||
LOG_DBG("Disabled the watchdog");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* LPC55xxx WWDT has a fixed divide-by-4 clock prescaler.
|
||||
* This prescaler is different from the clock divider specified in Device Tree.
|
||||
*/
|
||||
#define MSEC_TO_WWDT_TICKS(clock_freq, msec) \
|
||||
((uint32_t)(clock_freq * msec / MSEC_PER_SEC / 4))
|
||||
|
||||
static int mcux_wwdt_install_timeout(struct device *dev,
|
||||
const struct wdt_timeout_cfg *cfg)
|
||||
{
|
||||
const struct mcux_wwdt_config *config = dev->config_info;
|
||||
struct mcux_wwdt_data *data = dev->driver_data;
|
||||
uint32_t clock_freq;
|
||||
|
||||
if (data->timeout_valid) {
|
||||
LOG_ERR("No more timeouts can be installed");
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
CLOCK_SetClkDiv(kCLOCK_DivWdtClk, config->clk_divider, true);
|
||||
clock_freq = CLOCK_GetWdtClkFreq();
|
||||
|
||||
WWDT_GetDefaultConfig(&data->wwdt_config);
|
||||
|
||||
data->wwdt_config.clockFreq_Hz = clock_freq;
|
||||
|
||||
data->wwdt_config.timeoutValue =
|
||||
MSEC_TO_WWDT_TICKS(clock_freq, cfg->window.max);
|
||||
|
||||
if (cfg->window.min) {
|
||||
data->wwdt_config.windowValue =
|
||||
MSEC_TO_WWDT_TICKS(clock_freq, cfg->window.min);
|
||||
}
|
||||
|
||||
if ((data->wwdt_config.timeoutValue < MIN_TIMEOUT) ||
|
||||
(data->wwdt_config.timeoutValue > data->wwdt_config.windowValue)) {
|
||||
LOG_ERR("Invalid timeout");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (cfg->flags & WDT_FLAG_RESET_SOC) {
|
||||
data->wwdt_config.enableWatchdogReset = true;
|
||||
LOG_DBG("Enabling SoC reset");
|
||||
}
|
||||
|
||||
data->callback = cfg->callback;
|
||||
data->timeout_valid = true;
|
||||
LOG_DBG("Installed timeout (timeoutValue = %d)",
|
||||
data->wwdt_config.timeoutValue);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int mcux_wwdt_feed(struct device *dev, int channel_id)
|
||||
{
|
||||
const struct mcux_wwdt_config *config = dev->config_info;
|
||||
WWDT_Type *base = config->base;
|
||||
|
||||
if (channel_id != 0) {
|
||||
LOG_ERR("Invalid channel id");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
WWDT_Refresh(base);
|
||||
LOG_DBG("Fed the watchdog");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void mcux_wwdt_isr(void *arg)
|
||||
{
|
||||
struct device *dev = (struct device *)arg;
|
||||
const struct mcux_wwdt_config *config = dev->config_info;
|
||||
struct mcux_wwdt_data *data = dev->driver_data;
|
||||
WWDT_Type *base = config->base;
|
||||
uint32_t flags;
|
||||
|
||||
flags = WWDT_GetStatusFlags(base);
|
||||
WWDT_ClearStatusFlags(base, flags);
|
||||
|
||||
if (data->callback) {
|
||||
data->callback(dev, 0);
|
||||
}
|
||||
}
|
||||
|
||||
static int mcux_wwdt_init(struct device *dev)
|
||||
{
|
||||
const struct mcux_wwdt_config *config = dev->config_info;
|
||||
|
||||
config->irq_config_func(dev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct wdt_driver_api mcux_wwdt_api = {
|
||||
.setup = mcux_wwdt_setup,
|
||||
.disable = mcux_wwdt_disable,
|
||||
.install_timeout = mcux_wwdt_install_timeout,
|
||||
.feed = mcux_wwdt_feed,
|
||||
};
|
||||
|
||||
static void mcux_wwdt_config_func_0(struct device *dev);
|
||||
|
||||
static const struct mcux_wwdt_config mcux_wwdt_config_0 = {
|
||||
.base = (WWDT_Type *) DT_INST_REG_ADDR(0),
|
||||
.clk_divider =
|
||||
DT_INST_PROP(0, clk_divider),
|
||||
.irq_config_func = mcux_wwdt_config_func_0,
|
||||
};
|
||||
|
||||
static struct mcux_wwdt_data mcux_wwdt_data_0;
|
||||
|
||||
DEVICE_AND_API_INIT(mcux_wwdt_0, DT_INST_LABEL(0),
|
||||
&mcux_wwdt_init, &mcux_wwdt_data_0,
|
||||
&mcux_wwdt_config_0, POST_KERNEL,
|
||||
CONFIG_KERNEL_INIT_PRIORITY_DEVICE,
|
||||
&mcux_wwdt_api);
|
||||
|
||||
static void mcux_wwdt_config_func_0(struct device *dev)
|
||||
{
|
||||
IRQ_CONNECT(DT_INST_IRQN(0),
|
||||
DT_INST_IRQ(0, priority),
|
||||
mcux_wwdt_isr, DEVICE_GET(mcux_wwdt_0), 0);
|
||||
|
||||
irq_enable(DT_INST_IRQN(0));
|
||||
}
|
|
@ -13,6 +13,7 @@
|
|||
aliases {
|
||||
gpio-0 = &gpio0;
|
||||
gpio-1 = &gpio1;
|
||||
watchdog0 = &wwdt0;
|
||||
};
|
||||
|
||||
chosen {
|
||||
|
@ -212,6 +213,15 @@
|
|||
status = "okay";
|
||||
label = "RNG";
|
||||
};
|
||||
|
||||
wwdt0: watchdog@c000 {
|
||||
compatible = "nxp,lpc-wwdt";
|
||||
reg = <0xc000 0x1000>;
|
||||
interrupts = <0 0>;
|
||||
status = "disabled";
|
||||
clk-divider = <1>;
|
||||
label = "WWDT_0";
|
||||
};
|
||||
};
|
||||
|
||||
&nvic {
|
||||
|
|
23
dts/bindings/watchdog/nxp,lpc-wwdt.yaml
Normal file
23
dts/bindings/watchdog/nxp,lpc-wwdt.yaml
Normal file
|
@ -0,0 +1,23 @@
|
|||
# Copyright (c) 2020 Jiri Kerestes
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
description: LPC Windowed Watchdog Timer
|
||||
|
||||
compatible: "nxp,lpc-wwdt"
|
||||
|
||||
include: base.yaml
|
||||
|
||||
properties:
|
||||
reg:
|
||||
required: true
|
||||
|
||||
label:
|
||||
required: true
|
||||
|
||||
interrupts:
|
||||
required: true
|
||||
|
||||
clk-divider:
|
||||
type: int
|
||||
description: Watchdog clock divider
|
||||
required: true
|
|
@ -159,6 +159,11 @@ config HAS_MCUX_WDOG32
|
|||
help
|
||||
Set if the watchdog (WDOG32) module is present in the SoC.
|
||||
|
||||
config HAS_MCUX_WWDT
|
||||
bool
|
||||
help
|
||||
Set if the watchdog (WWDT) module is present in the SoC.
|
||||
|
||||
config HAS_MCUX_PWM
|
||||
bool
|
||||
help
|
||||
|
|
|
@ -24,4 +24,8 @@ config SOC_FLASH_MCUX
|
|||
default y
|
||||
depends on FLASH
|
||||
|
||||
config WDT_MCUX_WWDT
|
||||
default y
|
||||
depends on WATCHDOG
|
||||
|
||||
endif # SOC_LPC55S69_CPU0
|
||||
|
|
|
@ -9,6 +9,7 @@ config SOC_SERIES_LPC55XXX
|
|||
select HAS_MCUX
|
||||
select HAS_MCUX_FLEXCOMM
|
||||
select HAS_MCUX_RNG
|
||||
select HAS_MCUX_WWDT
|
||||
select SOC_FAMILY_LPC
|
||||
select CPU_CORTEX_M_HAS_SYSTICK
|
||||
select CPU_CORTEX_M_HAS_DWT
|
||||
|
|
|
@ -77,6 +77,11 @@ static ALWAYS_INLINE void clock_init(void)
|
|||
RESET_PeripheralReset(kHSLSPI_RST_SHIFT_RSTn);
|
||||
#endif
|
||||
|
||||
#if DT_NODE_HAS_COMPAT_STATUS(DT_NODELABEL(wwdt0), nxp_lpc_wwdt, okay)
|
||||
/* Enable 1 MHz FRO clock for WWDT */
|
||||
SYSCON->CLOCK_CTRL |= SYSCON_CLOCK_CTRL_FRO1MHZ_CLK_ENA_MASK;
|
||||
#endif
|
||||
|
||||
#endif /* CONFIG_SOC_LPC55S69_CPU0 */
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue