| /* |
| * 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); |
| } |
| } |
| #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); |