209 lines
5.2 KiB
C
209 lines
5.2 KiB
C
/*
|
|
* Copyright 2022 NXP
|
|
*
|
|
* SPDX-License-Identifier: Apache-2.0
|
|
*/
|
|
|
|
#include <zephyr/drivers/watchdog.h>
|
|
#include <zephyr/irq.h>
|
|
#include <Swt_Ip.h>
|
|
#include <Swt_Ip_Irq.h>
|
|
|
|
#define LOG_LEVEL CONFIG_WDT_LOG_LEVEL
|
|
#include <zephyr/logging/log.h>
|
|
LOG_MODULE_REGISTER(swt_nxp_s32);
|
|
|
|
#define PARAM_UNUSED 0
|
|
|
|
struct swt_nxp_s32_config {
|
|
uint32_t clock_freq;
|
|
uint8_t instance;
|
|
};
|
|
|
|
struct swt_nxp_s32_data {
|
|
Swt_Ip_ConfigType swt_config;
|
|
wdt_callback_t callback;
|
|
bool timeout_valid;
|
|
};
|
|
|
|
static int swt_nxp_s32_setup(const struct device *dev, uint8_t options)
|
|
{
|
|
const struct swt_nxp_s32_config *config = dev->config;
|
|
struct swt_nxp_s32_data *data = dev->data;
|
|
Swt_Ip_StatusType status;
|
|
|
|
if (!data->timeout_valid) {
|
|
LOG_ERR("No valid timeouts installed");
|
|
return -EINVAL;
|
|
}
|
|
|
|
data->swt_config.bEnRunInStopMode =
|
|
(options & WDT_OPT_PAUSE_IN_SLEEP) == 0U;
|
|
|
|
data->swt_config.bEnRunInDebugMode =
|
|
(options & WDT_OPT_PAUSE_HALTED_BY_DBG) == 0U;
|
|
|
|
status = Swt_Ip_Init(config->instance, &data->swt_config);
|
|
|
|
if (status != SWT_IP_STATUS_SUCCESS) {
|
|
LOG_ERR("Setting up watchdog failed");
|
|
return -EIO;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int swt_nxp_s32_disable(const struct device *dev)
|
|
{
|
|
const struct swt_nxp_s32_config *config = dev->config;
|
|
struct swt_nxp_s32_data *data = dev->data;
|
|
Swt_Ip_StatusType status;
|
|
|
|
status = Swt_Ip_Deinit(config->instance);
|
|
|
|
if (status != SWT_IP_STATUS_SUCCESS) {
|
|
LOG_ERR("Disabling watchdog failed");
|
|
return -EIO;
|
|
}
|
|
|
|
data->timeout_valid = false;
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int swt_nxp_s32_install_timeout(const struct device *dev,
|
|
const struct wdt_timeout_cfg *cfg)
|
|
{
|
|
const struct swt_nxp_s32_config *config = dev->config;
|
|
struct swt_nxp_s32_data *data = dev->data;
|
|
|
|
if (data->timeout_valid) {
|
|
LOG_ERR("No more timeouts can be installed");
|
|
return -ENOMEM;
|
|
}
|
|
|
|
data->swt_config.u32TimeoutValue = config->clock_freq / 1000U * cfg->window.max;
|
|
|
|
if (cfg->window.min) {
|
|
data->swt_config.bEnWindow = true;
|
|
data->swt_config.u32WindowValue =
|
|
config->clock_freq / 1000U * (cfg->window.max - cfg->window.min);
|
|
} else {
|
|
data->swt_config.bEnWindow = false;
|
|
data->swt_config.u32WindowValue = 0;
|
|
}
|
|
|
|
if ((data->swt_config.u32TimeoutValue < SWT_MIN_VALUE_TIMEOUT_U32) ||
|
|
(data->swt_config.u32TimeoutValue < data->swt_config.u32WindowValue)) {
|
|
LOG_ERR("Invalid timeout");
|
|
return -EINVAL;
|
|
}
|
|
|
|
data->swt_config.bEnInterrupt = cfg->callback != NULL;
|
|
data->callback = cfg->callback;
|
|
data->timeout_valid = true;
|
|
LOG_DBG("Installed timeout (timeoutValue = %d)",
|
|
data->swt_config.u32TimeoutValue);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int swt_nxp_s32_feed(const struct device *dev, int channel_id)
|
|
{
|
|
ARG_UNUSED(channel_id);
|
|
const struct swt_nxp_s32_config *config = dev->config;
|
|
|
|
Swt_Ip_Service(config->instance);
|
|
LOG_DBG("Fed the watchdog");
|
|
|
|
return 0;
|
|
}
|
|
|
|
static const struct wdt_driver_api swt_nxp_s32_driver_api = {
|
|
.setup = swt_nxp_s32_setup,
|
|
.disable = swt_nxp_s32_disable,
|
|
.install_timeout = swt_nxp_s32_install_timeout,
|
|
.feed = swt_nxp_s32_feed,
|
|
};
|
|
|
|
#define SWT_NODE(n) DT_NODELABEL(swt##n)
|
|
#define RTU0_SWT_OFFSET_IDX 2
|
|
#define RTU1_SWT_OFFSET_IDX 7
|
|
#define RTU_SWT(n) \
|
|
COND_CODE_1(CONFIG_NXP_S32_RTU_INDEX, (RTU1_SWT_OFFSET_IDX + n), \
|
|
(RTU0_SWT_OFFSET_IDX + n))
|
|
|
|
#define SWT_NXP_S32_CALLBACK(n) \
|
|
void swt_nxp_s32_##n##_callback(void) \
|
|
{ \
|
|
const struct device *dev = DEVICE_DT_GET(SWT_NODE(n)); \
|
|
struct swt_nxp_s32_data *data = dev->data; \
|
|
\
|
|
if (data->callback) { \
|
|
data->callback(dev, PARAM_UNUSED); \
|
|
} \
|
|
}
|
|
|
|
#define SWT_NXP_S32_DEVICE_INIT(n) \
|
|
SWT_NXP_S32_CALLBACK(n) \
|
|
static struct swt_nxp_s32_data swt_nxp_s32_data_##n = { \
|
|
.swt_config = { \
|
|
.u8MapEnBitmask = SWT_IP_ALL_MAP_DISABLE | \
|
|
SWT_IP_MAP0_ENABLE | SWT_IP_MAP1_ENABLE | \
|
|
SWT_IP_MAP2_ENABLE | SWT_IP_MAP3_ENABLE | \
|
|
SWT_IP_MAP4_ENABLE | SWT_IP_MAP5_ENABLE | \
|
|
SWT_IP_MAP6_ENABLE | SWT_IP_MAP7_ENABLE, \
|
|
.bEnResetOnInvalidAccess = TRUE, \
|
|
.eServiceMode = FALSE, \
|
|
.u16InitialKey = 0, \
|
|
.lockConfig = SWT_IP_UNLOCK, \
|
|
.pfSwtCallback = &swt_nxp_s32_##n##_callback, \
|
|
}, \
|
|
}; \
|
|
static const struct swt_nxp_s32_config swt_nxp_s32_config_##n = { \
|
|
.clock_freq = DT_PROP(SWT_NODE(n), clock_frequency), \
|
|
.instance = (uint8_t)(RTU_SWT(n)), \
|
|
}; \
|
|
\
|
|
static int swt_nxp_s32_##n##_init(const struct device *dev) \
|
|
{ \
|
|
IRQ_CONNECT(DT_IRQN(SWT_NODE(n)), \
|
|
DT_IRQ(SWT_NODE(n), priority), \
|
|
Swt_Ip_IrqHandler, \
|
|
(uint8_t)(RTU_SWT(n)), \
|
|
DT_IRQ(SWT_NODE(n), flags)); \
|
|
irq_enable(DT_IRQN(SWT_NODE(n))); \
|
|
\
|
|
return 0; \
|
|
} \
|
|
\
|
|
DEVICE_DT_DEFINE(SWT_NODE(n), \
|
|
swt_nxp_s32_##n##_init, \
|
|
NULL, \
|
|
&swt_nxp_s32_data_##n, \
|
|
&swt_nxp_s32_config_##n, \
|
|
POST_KERNEL, \
|
|
CONFIG_KERNEL_INIT_PRIORITY_DEVICE, \
|
|
&swt_nxp_s32_driver_api);
|
|
|
|
|
|
#if DT_NODE_HAS_STATUS(SWT_NODE(0), okay)
|
|
SWT_NXP_S32_DEVICE_INIT(0)
|
|
#endif
|
|
|
|
#if DT_NODE_HAS_STATUS(SWT_NODE(1), okay)
|
|
SWT_NXP_S32_DEVICE_INIT(1)
|
|
#endif
|
|
|
|
#if DT_NODE_HAS_STATUS(SWT_NODE(2), okay)
|
|
SWT_NXP_S32_DEVICE_INIT(2)
|
|
#endif
|
|
|
|
#if DT_NODE_HAS_STATUS(SWT_NODE(3), okay)
|
|
SWT_NXP_S32_DEVICE_INIT(3)
|
|
#endif
|
|
|
|
#if DT_NODE_HAS_STATUS(SWT_NODE(4), okay)
|
|
SWT_NXP_S32_DEVICE_INIT(4)
|
|
#endif
|