144 lines
3.3 KiB
C
144 lines
3.3 KiB
C
/*
|
|
* Copyright 2023 Cypress Semiconductor Corporation (an Infineon company) or
|
|
* an affiliate of Cypress Semiconductor Corporation
|
|
*
|
|
* SPDX-License-Identifier: Apache-2.0
|
|
*/
|
|
|
|
#define DT_DRV_COMPAT infineon_cat1_watchdog
|
|
|
|
#include "cyhal_wdt.h"
|
|
|
|
#include <zephyr/devicetree.h>
|
|
#include <zephyr/drivers/watchdog.h>
|
|
#include <zephyr/kernel.h>
|
|
#include <zephyr/logging/log.h>
|
|
LOG_MODULE_REGISTER(wdt_infineon_cat1, CONFIG_WDT_LOG_LEVEL);
|
|
|
|
#define IFX_CAT1_WDT_IS_IRQ_EN DT_NODE_HAS_PROP(DT_DRV_INST(0), interrupts)
|
|
|
|
struct ifx_cat1_wdt_data {
|
|
cyhal_wdt_t obj;
|
|
#ifdef IFX_CAT1_WDT_IS_IRQ_EN
|
|
wdt_callback_t callback;
|
|
#endif /* IFX_CAT1_WDT_IS_IRQ_EN */
|
|
uint32_t timeout;
|
|
bool timeout_installed;
|
|
};
|
|
|
|
struct ifx_cat1_wdt_data wdt_data;
|
|
|
|
#ifdef IFX_CAT1_WDT_IS_IRQ_EN
|
|
static void ifx_cat1_wdt_isr_handler(const struct device *dev)
|
|
{
|
|
struct ifx_cat1_wdt_data *dev_data = dev->data;
|
|
|
|
if (dev_data->callback) {
|
|
dev_data->callback(dev, 0);
|
|
}
|
|
Cy_WDT_MaskInterrupt();
|
|
}
|
|
#endif /* IFX_CAT1_WDT_IS_IRQ_EN */
|
|
|
|
static int ifx_cat1_wdt_setup(const struct device *dev, uint8_t options)
|
|
{
|
|
cy_rslt_t result;
|
|
struct ifx_cat1_wdt_data *dev_data = dev->data;
|
|
|
|
/* Initialize the WDT */
|
|
result = cyhal_wdt_init(&dev_data->obj, dev_data->timeout);
|
|
if (result != CY_RSLT_SUCCESS) {
|
|
LOG_ERR("Initialization failure : 0x%x", result);
|
|
return -ENOMSG;
|
|
}
|
|
|
|
#ifdef IFX_CAT1_WDT_IS_IRQ_EN
|
|
if (dev_data->callback) {
|
|
Cy_WDT_UnmaskInterrupt();
|
|
irq_enable(DT_INST_IRQN(0));
|
|
}
|
|
#endif /* IFX_CAT1_WDT_IS_IRQ_EN */
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int ifx_cat1_wdt_disable(const struct device *dev)
|
|
{
|
|
struct ifx_cat1_wdt_data *dev_data = dev->data;
|
|
|
|
#ifdef IFX_CAT1_WDT_IS_IRQ_EN
|
|
Cy_WDT_MaskInterrupt();
|
|
irq_disable(DT_INST_IRQN(0));
|
|
#endif /* IFX_CAT1_WDT_IS_IRQ_EN */
|
|
|
|
cyhal_wdt_free(&dev_data->obj);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int ifx_cat1_wdt_install_timeout(const struct device *dev, const struct wdt_timeout_cfg *cfg)
|
|
{
|
|
struct ifx_cat1_wdt_data *dev_data = dev->data;
|
|
|
|
if (dev_data->timeout_installed) {
|
|
LOG_ERR("No more timeouts can be installed");
|
|
return -ENOMEM;
|
|
}
|
|
|
|
if (cfg->flags) {
|
|
LOG_WRN("Watchdog behavior is not configurable.");
|
|
}
|
|
|
|
if (cfg->callback) {
|
|
#ifndef IFX_CAT1_WDT_IS_IRQ_EN
|
|
LOG_WRN("Interrupt is not configured, can't set a callback.");
|
|
#else
|
|
dev_data->callback = cfg->callback;
|
|
#endif /* IFX_CAT1_WDT_IS_IRQ_EN */
|
|
}
|
|
|
|
/* window watchdog not supported */
|
|
if (cfg->window.min != 0U || cfg->window.max == 0U) {
|
|
return -EINVAL;
|
|
}
|
|
|
|
dev_data->timeout = cfg->window.max;
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int ifx_cat1_wdt_feed(const struct device *dev, int channel_id)
|
|
{
|
|
struct ifx_cat1_wdt_data *data = dev->data;
|
|
|
|
/* Only channel 0 is supported */
|
|
if (channel_id) {
|
|
return -EINVAL;
|
|
}
|
|
|
|
cyhal_wdt_kick(&data->obj);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int ifx_cat1_wdt_init(const struct device *dev)
|
|
{
|
|
#ifdef IFX_CAT1_WDT_IS_IRQ_EN
|
|
/* Connect WDT interrupt to ISR */
|
|
IRQ_CONNECT(DT_INST_IRQN(0), DT_INST_IRQ(0, priority), ifx_cat1_wdt_isr_handler,
|
|
DEVICE_DT_INST_GET(0), 0);
|
|
#endif /* IFX_CAT1_WDT_IS_IRQ_EN */
|
|
|
|
return 0;
|
|
}
|
|
|
|
static const struct wdt_driver_api ifx_cat1_wdt_api = {
|
|
.setup = ifx_cat1_wdt_setup,
|
|
.disable = ifx_cat1_wdt_disable,
|
|
.install_timeout = ifx_cat1_wdt_install_timeout,
|
|
.feed = ifx_cat1_wdt_feed,
|
|
};
|
|
|
|
DEVICE_DT_INST_DEFINE(0, ifx_cat1_wdt_init, NULL, &wdt_data, NULL, POST_KERNEL,
|
|
CONFIG_KERNEL_INIT_PRIORITY_DEVICE, &ifx_cat1_wdt_api);
|