ade49f081d
Updated API version enables multi-instance GPIOTE driver. Additionally obsolete symbol that was used to specify API version in the past was removed. Affected drivers have been adjusted and appropriate changes in affected files have been made. Signed-off-by: Jakub Zymelka <jakub.zymelka@nordicsemi.no>
225 lines
5.4 KiB
C
225 lines
5.4 KiB
C
/*
|
|
* Copyright (c) 2018, Nordic Semiconductor ASA
|
|
*
|
|
* SPDX-License-Identifier: Apache-2.0
|
|
*/
|
|
|
|
#include <zephyr/sys/math_extras.h>
|
|
#include <nrfx_wdt.h>
|
|
#include <zephyr/drivers/watchdog.h>
|
|
|
|
#define LOG_LEVEL CONFIG_WDT_LOG_LEVEL
|
|
#include <zephyr/logging/log.h>
|
|
#include <zephyr/irq.h>
|
|
LOG_MODULE_REGISTER(wdt_nrfx);
|
|
|
|
struct wdt_nrfx_data {
|
|
wdt_callback_t m_callbacks[NRF_WDT_CHANNEL_NUMBER];
|
|
uint32_t m_timeout;
|
|
uint8_t m_allocated_channels;
|
|
};
|
|
|
|
struct wdt_nrfx_config {
|
|
nrfx_wdt_t wdt;
|
|
};
|
|
|
|
static int wdt_nrf_setup(const struct device *dev, uint8_t options)
|
|
{
|
|
const struct wdt_nrfx_config *config = dev->config;
|
|
const struct wdt_nrfx_data *data = dev->data;
|
|
nrfx_err_t err_code;
|
|
|
|
nrfx_wdt_config_t wdt_config = {
|
|
.reload_value = data->m_timeout
|
|
};
|
|
|
|
#if NRF_WDT_HAS_STOP
|
|
wdt_config.behaviour |= NRF_WDT_BEHAVIOUR_STOP_ENABLE_MASK;
|
|
#endif
|
|
|
|
if (!(options & WDT_OPT_PAUSE_IN_SLEEP)) {
|
|
wdt_config.behaviour |= NRF_WDT_BEHAVIOUR_RUN_SLEEP_MASK;
|
|
}
|
|
|
|
if (!(options & WDT_OPT_PAUSE_HALTED_BY_DBG)) {
|
|
wdt_config.behaviour |= NRF_WDT_BEHAVIOUR_RUN_HALT_MASK;
|
|
}
|
|
|
|
err_code = nrfx_wdt_reconfigure(&config->wdt, &wdt_config);
|
|
|
|
if (err_code != NRFX_SUCCESS) {
|
|
return -EBUSY;
|
|
}
|
|
|
|
nrfx_wdt_enable(&config->wdt);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int wdt_nrf_disable(const struct device *dev)
|
|
{
|
|
#if NRFX_WDT_HAS_STOP
|
|
const struct wdt_nrfx_config *config = dev->config;
|
|
nrfx_err_t err_code;
|
|
|
|
err_code = nrfx_wdt_stop(&config->wdt);
|
|
|
|
if (err_code != NRFX_SUCCESS) {
|
|
return -ENOTSUP;
|
|
}
|
|
|
|
return 0;
|
|
#else
|
|
ARG_UNUSED(dev);
|
|
return -EPERM;
|
|
#endif
|
|
}
|
|
|
|
static int wdt_nrf_install_timeout(const struct device *dev,
|
|
const struct wdt_timeout_cfg *cfg)
|
|
{
|
|
const struct wdt_nrfx_config *config = dev->config;
|
|
struct wdt_nrfx_data *data = dev->data;
|
|
nrfx_err_t err_code;
|
|
nrfx_wdt_channel_id channel_id;
|
|
|
|
if (cfg->flags != WDT_FLAG_RESET_SOC) {
|
|
return -ENOTSUP;
|
|
}
|
|
|
|
if (cfg->window.min != 0U) {
|
|
return -EINVAL;
|
|
}
|
|
|
|
if (data->m_allocated_channels == 0U) {
|
|
/* According to relevant Product Specifications, watchdogs
|
|
* in all nRF chips can use reload values (determining
|
|
* the timeout) from range 0xF-0xFFFFFFFF given in 32768 Hz
|
|
* clock ticks. This makes the allowed range of 0x1-0x07CFFFFF
|
|
* in milliseconds. Check if the provided value is within
|
|
* this range. */
|
|
if ((cfg->window.max == 0U) || (cfg->window.max > 0x07CFFFFF)) {
|
|
return -EINVAL;
|
|
}
|
|
|
|
/* Save timeout value from first registered watchdog channel. */
|
|
data->m_timeout = cfg->window.max;
|
|
} else if (cfg->window.max != data->m_timeout) {
|
|
return -EINVAL;
|
|
}
|
|
|
|
err_code = nrfx_wdt_channel_alloc(&config->wdt,
|
|
&channel_id);
|
|
|
|
if (err_code == NRFX_ERROR_NO_MEM) {
|
|
return -ENOMEM;
|
|
}
|
|
|
|
if (cfg->callback != NULL) {
|
|
data->m_callbacks[channel_id] = cfg->callback;
|
|
}
|
|
|
|
data->m_allocated_channels++;
|
|
return channel_id;
|
|
}
|
|
|
|
static int wdt_nrf_feed(const struct device *dev, int channel_id)
|
|
{
|
|
const struct wdt_nrfx_config *config = dev->config;
|
|
struct wdt_nrfx_data *data = dev->data;
|
|
|
|
if (channel_id > data->m_allocated_channels) {
|
|
return -EINVAL;
|
|
}
|
|
|
|
nrfx_wdt_channel_feed(&config->wdt,
|
|
(nrfx_wdt_channel_id)channel_id);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static const struct wdt_driver_api wdt_nrfx_driver_api = {
|
|
.setup = wdt_nrf_setup,
|
|
.disable = wdt_nrf_disable,
|
|
.install_timeout = wdt_nrf_install_timeout,
|
|
.feed = wdt_nrf_feed,
|
|
};
|
|
|
|
static void wdt_event_handler(const struct device *dev, nrf_wdt_event_t event_type,
|
|
uint32_t requests, void *p_context)
|
|
{
|
|
(void)event_type;
|
|
(void)p_context;
|
|
|
|
struct wdt_nrfx_data *data = dev->data;
|
|
|
|
while (requests) {
|
|
uint8_t i = u32_count_trailing_zeros(requests);
|
|
|
|
if (data->m_callbacks[i]) {
|
|
data->m_callbacks[i](dev, i);
|
|
}
|
|
requests &= ~BIT(i);
|
|
}
|
|
}
|
|
|
|
#define WDT(idx) DT_NODELABEL(wdt##idx)
|
|
|
|
#define WDT_NRFX_WDT_DEVICE(idx) \
|
|
static void wdt_##idx##_event_handler(nrf_wdt_event_t event_type, \
|
|
uint32_t requests, \
|
|
void *p_context) \
|
|
{ \
|
|
wdt_event_handler(DEVICE_DT_GET(WDT(idx)), event_type, \
|
|
requests, p_context); \
|
|
} \
|
|
static int wdt_##idx##_init(const struct device *dev) \
|
|
{ \
|
|
const struct wdt_nrfx_config *config = dev->config; \
|
|
nrfx_err_t err_code; \
|
|
IRQ_CONNECT(DT_IRQN(WDT(idx)), DT_IRQ(WDT(idx), priority), \
|
|
nrfx_isr, nrfx_wdt_##idx##_irq_handler, 0); \
|
|
err_code = nrfx_wdt_init(&config->wdt, \
|
|
NULL, \
|
|
wdt_##idx##_event_handler, \
|
|
NULL); \
|
|
if (err_code != NRFX_SUCCESS) { \
|
|
return -EBUSY; \
|
|
} \
|
|
return 0; \
|
|
} \
|
|
static struct wdt_nrfx_data wdt_##idx##_data = { \
|
|
.m_timeout = 0, \
|
|
.m_allocated_channels = 0, \
|
|
}; \
|
|
static const struct wdt_nrfx_config wdt_##idx##z_config = { \
|
|
.wdt = NRFX_WDT_INSTANCE(idx), \
|
|
}; \
|
|
DEVICE_DT_DEFINE(WDT(idx), \
|
|
wdt_##idx##_init, \
|
|
NULL, \
|
|
&wdt_##idx##_data, \
|
|
&wdt_##idx##z_config, \
|
|
PRE_KERNEL_1, CONFIG_KERNEL_INIT_PRIORITY_DEVICE, \
|
|
&wdt_nrfx_driver_api)
|
|
|
|
#ifdef CONFIG_HAS_HW_NRF_WDT0
|
|
WDT_NRFX_WDT_DEVICE(0);
|
|
#endif
|
|
|
|
#ifdef CONFIG_HAS_HW_NRF_WDT1
|
|
WDT_NRFX_WDT_DEVICE(1);
|
|
#endif
|
|
|
|
#ifdef CONFIG_HAS_HW_NRF_WDT30
|
|
WDT_NRFX_WDT_DEVICE(30);
|
|
#endif
|
|
|
|
#ifdef CONFIG_HAS_HW_NRF_WDT31
|
|
WDT_NRFX_WDT_DEVICE(31);
|
|
#endif
|
|
|
|
#ifdef CONFIG_HAS_HW_NRF_WDT130
|
|
WDT_NRFX_WDT_DEVICE(130);
|
|
#endif
|