Skip to content

drivers: wdt: Watchdog API redesign and shim for nrfx wdt driver #7007

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

Merged
merged 4 commits into from
May 14, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions arch/arm/soc/nordic_nrf/nrf51/dts.fixup
Original file line number Diff line number Diff line change
Expand Up @@ -19,4 +19,8 @@
#define CONFIG_I2C_1_IRQ_PRI NORDIC_NRF5_I2C_40004000_IRQ_0_PRIORITY
#define CONFIG_I2C_1_IRQ NORDIC_NRF5_I2C_40004000_IRQ_0

#define CONFIG_WDT_0_NAME NORDIC_NRF_WATCHDOG_40010000_LABEL
#define CONFIG_WDT_NRF_IRQ NORDIC_NRF_WATCHDOG_40010000_IRQ_WDT
#define CONFIG_WDT_NRF_IRQ_PRI NORDIC_NRF_WATCHDOG_40010000_IRQ_WDT_PRIORITY

/* End of SoC Level DTS fixup file */
4 changes: 4 additions & 0 deletions arch/arm/soc/nordic_nrf/nrf52/dts.fixup
Original file line number Diff line number Diff line change
Expand Up @@ -28,4 +28,8 @@
#define CONFIG_USBD_NRF5_NUM_ISOOUT_EP NORDIC_NRF_USBD_0X40027000_NUM_ISOOUT_ENDPOINTS
#define CONFIG_USBD_NRF5_NAME NORDIC_NRF_USBD_0X40027000_LABEL

#define CONFIG_WDT_0_NAME NORDIC_NRF_WATCHDOG_40010000_LABEL
#define CONFIG_WDT_NRF_IRQ NORDIC_NRF_WATCHDOG_40010000_IRQ_WDT
#define CONFIG_WDT_NRF_IRQ_PRI NORDIC_NRF_WATCHDOG_40010000_IRQ_WDT_PRIORITY

/* End of SoC Level DTS fixup file */
1 change: 1 addition & 0 deletions doc/api/api.rst
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ The Zephyr APIs are used the same way on all SoCs and boards.
bluetooth.rst
networking.rst
io_interfaces.rst
timer_counter_interfaces.rst
power_management_api
file_system
display_api
Expand Down
15 changes: 15 additions & 0 deletions doc/api/timer_counter_interfaces.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
.. _timer_counter_interfaces:

Timer / Counter Driver APIs
###########################

.. contents::
:depth: 1
:local:
:backlinks: top

Watchdog Interface
******************

.. doxygengroup:: watchdog_interface
:project: Zephyr
1 change: 1 addition & 0 deletions drivers/watchdog/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,4 @@ zephyr_sources_ifdef(CONFIG_WDOG_CMSDK_APB wdog_cmsdk_apb.c)
zephyr_sources_ifdef(CONFIG_WDT_SAM wdt_sam.c)
zephyr_sources_ifdef(CONFIG_WDT_ESP32 wdt_esp32.c)
zephyr_sources_ifdef(CONFIG_WDT_SAM0 wdt_sam0.c)
zephyr_sources_ifdef(CONFIG_WDT_NRFX wdt_nrfx.c)
39 changes: 34 additions & 5 deletions drivers/watchdog/Kconfig
Original file line number Diff line number Diff line change
@@ -1,23 +1,50 @@
# Kconfig - Watchdog configuration options
#
#
# Copyright (c) 2015 Intel Corporation
# Copyright (c) 2017 Nordic Semiconductor ASA
#
# SPDX-License-Identifier: Apache-2.0
#

#
# Watchdog options
#
menuconfig WATCHDOG
bool
prompt "Watchdog Support"
default n
help
Include support for watchdogs.

if WATCHDOG

config WDT_DISABLE_AT_BOOT
bool
prompt "Disable at boot"
help
Disable watchdog at Zephyr system startup.

config SYS_LOG_WDT_LEVEL
int
prompt "Watchdog Driver Log level"
depends on SYS_LOG
default 0
range 0 4
help
Sets log level for Watchdog drivers.
Levels are:
0 OFF, do not write
1 ERROR, only write SYS_LOG_ERR
2 WARNING, write SYS_LOG_WRN in addition to previous level
3 INFO, write SYS_LOG_INF in addition to previous levels
4 DEBUG, write SYS_LOG_DBG in addition to previous levels

config HAS_WDT_MULTISTAGE
bool

config WDT_MULTISTAGE
bool
prompt "Enable multistage timeouts"
depends on HAS_WDT_MULTISTAGE
help
Enable multistage operation of watchdog timeouts.

source "drivers/watchdog/Kconfig.qmsi"

source "drivers/watchdog/Kconfig.stm32"
Expand All @@ -30,4 +57,6 @@ source "drivers/watchdog/Kconfig.esp32"

source "drivers/watchdog/Kconfig.sam0"

source "drivers/watchdog/Kconfig.nrfx"

endif
14 changes: 14 additions & 0 deletions drivers/watchdog/Kconfig.nrfx
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
# Kconfig - nrfx WDT support
#
# Copyright (c) 2018, Nordic Semiconductor ASA
#
# SPDX-License-Identifier: Apache-2.0

menuconfig WDT_NRFX
bool "nRF WDT nrfx driver"
depends on SOC_FAMILY_NRF && CLOCK_CONTROL_NRF5
select HAS_DTS_WDT
select NRFX_WDT
default n
help
Enable support for nrfx WDT driver for nRF MCU series.
4 changes: 3 additions & 1 deletion drivers/watchdog/iwdg_stm32.c
Original file line number Diff line number Diff line change
Expand Up @@ -68,10 +68,12 @@ static void iwdg_stm32_enable(struct device *dev)
LL_IWDG_Enable(iwdg);
}

static void iwdg_stm32_disable(struct device *dev)
static int iwdg_stm32_disable(struct device *dev)
{
/* watchdog cannot be stopped once started */
ARG_UNUSED(dev);

return 0;
}

static int iwdg_stm32_set_config(struct device *dev,
Expand Down
4 changes: 3 additions & 1 deletion drivers/watchdog/wdog_cmsdk_apb.c
Original file line number Diff line number Diff line change
Expand Up @@ -87,14 +87,16 @@ static void wdog_cmsdk_apb_enable(struct device *dev)
wdog->ctrl = (CMSDK_APB_WDOG_CTRL_RESEN | CMSDK_APB_WDOG_CTRL_INTEN);
}

static void wdog_cmsdk_apb_disable(struct device *dev)
static int wdog_cmsdk_apb_disable(struct device *dev)
{
volatile struct wdog_cmsdk_apb *wdog = WDOG_STRUCT;

ARG_UNUSED(dev);

/* Stop the watchdog counter with INTEN bit */
wdog->ctrl = ~(CMSDK_APB_WDOG_CTRL_RESEN | CMSDK_APB_WDOG_CTRL_INTEN);

return 0;
}

static int wdog_cmsdk_apb_set_config(struct device *dev,
Expand Down
4 changes: 3 additions & 1 deletion drivers/watchdog/wdt_esp32.c
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ static void wdt_esp32_enable(struct device *dev)
wdt_esp32_seal();
}

static void wdt_esp32_disable(struct device *dev)
static int wdt_esp32_disable(struct device *dev)
{
volatile u32_t *reg = (u32_t *)TIMG_WDTCONFIG0_REG(1);

Expand All @@ -57,6 +57,8 @@ static void wdt_esp32_disable(struct device *dev)
wdt_esp32_unseal();
*reg &= ~BIT(TIMG_WDT_EN_S);
wdt_esp32_seal();

return 0;
}

static void adjust_timeout(u32_t timeout)
Expand Down
209 changes: 209 additions & 0 deletions drivers/watchdog/wdt_nrfx.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,209 @@
/*
* Copyright (c) 2018, Nordic Semiconductor ASA
*
* SPDX-License-Identifier: Apache-2.0
*/

#include <nrfx_wdt.h>
#include <nrf_clock.h>
#include <clock_control.h>
#include <watchdog.h>

#define SYS_LOG_DOMAIN "wdt_nrfx"
#define SYS_LOG_LEVEL CONFIG_SYS_LOG_WDT_LEVEL
#include <logging/sys_log.h>

DEVICE_DECLARE(wdt_nrfx);

/* Each activated and not reloaded channel can generate watchdog interrupt.
* Array m_callbacks provides storing callbacks for each channel.
*/
static wdt_callback_t m_callbacks[NRF_WDT_CHANNEL_NUMBER];

/*
* The m_allocated_channels variable stores number of currently allocated
* and activated watchdog channels.
*/
static u8_t m_allocated_channels;

/*
* The m_timeout variable stores watchdog timeout value in millisecond units.
* It is used to check whether installing watchdog provide the same timeout
* value in the window configuration.
*/
static u32_t m_timeout;


static void wdt_event_handler(void)
{
int i;

for (i = 0; i < m_allocated_channels ; ++i) {
if (nrf_wdt_request_status((nrf_wdt_rr_register_t)i)) {
if (m_callbacks[i]) {
m_callbacks[i](DEVICE_GET(wdt_nrfx), i);
}
}
}
}

static void wdt_nrf_isr(struct device *dev)
{
ARG_UNUSED(dev);
/* We need to implement our own interrupt handler until nrfx one will
* be fixed.
* Clearing events also clears the reload register and has to be done
* AFTER event handler.
*/
wdt_event_handler();
nrf_wdt_event_clear(NRF_WDT_EVENT_TIMEOUT);
}

static int wdt_nrf_setup(struct device *dev, u8_t options)
{
nrfx_wdt_config_t config;
nrfx_err_t err_code;

ARG_UNUSED(dev);

if (!nrf_clock_lf_is_running()) {
return -ENOTSUP;
}

/* Activate all available options. Run in all cases. */
config.behaviour = NRF_WDT_BEHAVIOUR_RUN_SLEEP_HALT;

/* Deactivate running in sleep mode. */
if (options & WDT_OPT_PAUSE_IN_SLEEP) {
config.behaviour &= ~NRF_WDT_BEHAVIOUR_RUN_SLEEP;
}

/* Deactivate running when debugger is attached. */
if (options & WDT_OPT_PAUSE_HALTED_BY_DBG) {
config.behaviour &= ~NRF_WDT_BEHAVIOUR_RUN_HALT;
}

config.reload_value = m_timeout;

err_code = nrfx_wdt_init(&config, wdt_event_handler);
if (err_code != NRFX_SUCCESS) {
return -EBUSY;
}

IRQ_CONNECT(CONFIG_WDT_NRF_IRQ,
CONFIG_WDT_NRF_IRQ_PRI, wdt_nrf_isr,
DEVICE_GET(wdt_nrfx), 0);
irq_enable(CONFIG_WDT_NRF_IRQ);

nrfx_wdt_enable();

return 0;
}

static int wdt_nrf_disable(struct device *dev)
{
/* Started watchdog cannot be stopped on nRF devices. */
ARG_UNUSED(dev);
return -EPERM;
}

static int wdt_nrf_install_timeout(struct device *dev,
const struct wdt_timeout_cfg *cfg)
{
nrfx_err_t err_code;
nrfx_wdt_channel_id channel_id;

ARG_UNUSED(dev);

if (cfg->flags != WDT_FLAG_RESET_SOC) {
return -ENOTSUP;
}

if (cfg->window.min != 0) {
return -EINVAL;
}

if (m_allocated_channels == 0) {
/* Save timeout value from first registered watchdog channel. */
m_timeout = cfg->window.max;
} else if (cfg->window.max != m_timeout) {
return -EINVAL;
}

err_code = nrfx_wdt_channel_alloc(&channel_id);

if (err_code == NRFX_ERROR_NO_MEM) {
return -ENOMEM;
}

if (cfg->callback != NULL) {
m_callbacks[channel_id] = cfg->callback;
}

m_allocated_channels++;
return channel_id;
}

static int wdt_nrf_feed(struct device *dev, int channel_id)
{
ARG_UNUSED(dev);
if (channel_id > m_allocated_channels) {
return -EINVAL;
}

nrfx_wdt_channel_feed((nrfx_wdt_channel_id)channel_id);

return 0;
}

static void wdt_nrf_enable(struct device *dev)
{
ARG_UNUSED(dev);
/* Deprecated function. No implementation needed. */
SYS_LOG_ERR("Function not implemented!");
}

static int wdt_nrf_set_config(struct device *dev, struct wdt_config *config)
{
ARG_UNUSED(dev);
ARG_UNUSED(config);
/* Deprecated function. No implementation needed. */
SYS_LOG_ERR("Function not implemented!");
return 0;
}

static void wdt_nrf_get_config(struct device *dev, struct wdt_config *config)
{
ARG_UNUSED(dev);
ARG_UNUSED(config);
/* Deprecated function. No implementation needed. */
SYS_LOG_ERR("Function not implemented!");
}

static void wdt_nrf_reload(struct device *dev)
{
ARG_UNUSED(dev);
/* Deprecated function. No implementation needed. */
SYS_LOG_ERR("Function not implemented!");
}

static const struct wdt_driver_api wdt_nrf_api = {
.setup = wdt_nrf_setup,
.disable = wdt_nrf_disable,
.install_timeout = wdt_nrf_install_timeout,
.feed = wdt_nrf_feed,
.enable = wdt_nrf_enable,
.get_config = wdt_nrf_get_config,
.set_config = wdt_nrf_set_config,
.reload = wdt_nrf_reload,
};

static int init_wdt(struct device *dev)
{
ARG_UNUSED(dev);
return 0;
}

DEVICE_AND_API_INIT(wdt_nrf, CONFIG_WDT_0_NAME, init_wdt,
NULL, NULL, PRE_KERNEL_1,
CONFIG_KERNEL_INIT_PRIORITY_DEVICE, &wdt_nrf_api);
4 changes: 3 additions & 1 deletion drivers/watchdog/wdt_qmsi.c
Original file line number Diff line number Diff line change
Expand Up @@ -94,9 +94,11 @@ static void enable(struct device *dev)
clk_periph_enable(CLK_PERIPH_WDT_REGISTER | CLK_PERIPH_CLK);
}

static void disable(struct device *dev)
static int disable(struct device *dev)
{
clk_periph_disable(CLK_PERIPH_WDT_REGISTER);

return 0;
}

static const struct wdt_driver_api api = {
Expand Down
Loading