zephyr/drivers/watchdog/wdt_nxp_s32.c
Manuel Argüelles 6744d6084d watchdog: nxp_s32: use instance-based DT macros
At present, many of the NXP S32 shim drivers do not make use of
devicetree instance-based macros because the NXP S32 HAL relies on an
index-based approach, requiring knowledge of the peripheral instance
index during both compilation and runtime, and this index might not
align with the devicetree instance index.

The proposed solution in this patch eliminates this limitation by
determining the peripheral instance index during compilation
through macrobatics and defining the driver's ISR within the shim
driver itself.

Note that for some peripheral instances is needed to redefine the
HAL macros of the peripheral base address, since the naming is not
uniform for all instances.

Signed-off-by: Manuel Argüelles <manuel.arguelles@nxp.com>
2023-11-09 10:20:27 +00:00

220 lines
5.7 KiB
C

/*
* Copyright 2022-2023 NXP
*
* SPDX-License-Identifier: Apache-2.0
*/
#define DT_DRV_COMPAT nxp_s32_swt
#include <zephyr/drivers/watchdog.h>
#include <zephyr/drivers/clock_control.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 {
uint8_t instance;
const struct device *clock_dev;
clock_control_subsys_t clock_subsys;
};
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;
uint32_t clock_rate;
int err;
if (data->timeout_valid) {
LOG_ERR("No more timeouts can be installed");
return -ENOMEM;
}
err = clock_control_get_rate(config->clock_dev, config->clock_subsys, &clock_rate);
if (err) {
LOG_ERR("Failed to get module clock frequency");
return err;
}
data->swt_config.u32TimeoutValue = clock_rate / 1000U * cfg->window.max;
if (cfg->window.min) {
data->swt_config.bEnWindow = true;
data->swt_config.u32WindowValue =
clock_rate / 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;
}
void swt_nxp_s32_isr(const struct device *dev)
{
const struct swt_nxp_s32_config *config = dev->config;
Swt_Ip_IrqHandler(config->instance);
}
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_NXP_S32_CALLBACK(n) \
void swt_nxp_s32_##n##_callback(void) \
{ \
const struct device *dev = DEVICE_DT_INST_GET(n); \
struct swt_nxp_s32_data *data = dev->data; \
\
if (data->callback) { \
data->callback(dev, PARAM_UNUSED); \
} \
}
#define SWT_NXP_S32_HW_INSTANCE_CHECK(i, n) \
((DT_INST_REG_ADDR(n) == IP_SWT_##i##_BASE) ? i : 0)
#define SWT_NXP_S32_HW_INSTANCE(n) \
LISTIFY(__DEBRACKET SWT_INSTANCE_COUNT, SWT_NXP_S32_HW_INSTANCE_CHECK, (|), n)
#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 = { \
.instance = SWT_NXP_S32_HW_INSTANCE(n), \
.clock_dev = DEVICE_DT_GET(DT_INST_CLOCKS_CTLR(n)), \
.clock_subsys = (clock_control_subsys_t) \
DT_INST_CLOCKS_CELL(n, name), \
}; \
\
static int swt_nxp_s32_##n##_init(const struct device *dev) \
{ \
const struct swt_nxp_s32_config *config = dev->config; \
int err; \
\
if (!device_is_ready(config->clock_dev)) { \
return -ENODEV; \
} \
\
err = clock_control_on(config->clock_dev, config->clock_subsys);\
if (err) { \
return err; \
} \
\
IRQ_CONNECT(DT_INST_IRQN(n), DT_INST_IRQ(n, priority), \
swt_nxp_s32_isr, DEVICE_DT_INST_GET(n), \
DT_INST_IRQ(n, flags)); \
irq_enable(DT_INST_IRQN(n)); \
\
return 0; \
} \
\
DEVICE_DT_INST_DEFINE(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);
DT_INST_FOREACH_STATUS_OKAY(SWT_NXP_S32_DEVICE_INIT)