1 /*
2 * Copyright 2023 Cypress Semiconductor Corporation (an Infineon company) or
3 * an affiliate of Cypress Semiconductor Corporation
4 *
5 * SPDX-License-Identifier: Apache-2.0
6 */
7
8 #define DT_DRV_COMPAT infineon_cat1_watchdog
9
10 #include "cyhal_wdt.h"
11
12 #include <zephyr/devicetree.h>
13 #include <zephyr/drivers/watchdog.h>
14 #include <zephyr/kernel.h>
15 #include <zephyr/logging/log.h>
16 LOG_MODULE_REGISTER(wdt_infineon_cat1, CONFIG_WDT_LOG_LEVEL);
17
18 #define IFX_CAT1_WDT_IS_IRQ_EN DT_NODE_HAS_PROP(DT_DRV_INST(0), interrupts)
19
20 struct ifx_cat1_wdt_data {
21 cyhal_wdt_t obj;
22 #ifdef IFX_CAT1_WDT_IS_IRQ_EN
23 wdt_callback_t callback;
24 #endif /* IFX_CAT1_WDT_IS_IRQ_EN */
25 uint32_t timeout;
26 bool timeout_installed;
27 };
28
29 struct ifx_cat1_wdt_data wdt_data;
30
31 #ifdef IFX_CAT1_WDT_IS_IRQ_EN
ifx_cat1_wdt_isr_handler(const struct device * dev)32 static void ifx_cat1_wdt_isr_handler(const struct device *dev)
33 {
34 struct ifx_cat1_wdt_data *dev_data = dev->data;
35
36 if (dev_data->callback) {
37 dev_data->callback(dev, 0);
38 }
39 Cy_WDT_MaskInterrupt();
40 }
41 #endif /* IFX_CAT1_WDT_IS_IRQ_EN */
42
ifx_cat1_wdt_setup(const struct device * dev,uint8_t options)43 static int ifx_cat1_wdt_setup(const struct device *dev, uint8_t options)
44 {
45 cy_rslt_t result;
46 struct ifx_cat1_wdt_data *dev_data = dev->data;
47
48 /* Initialize the WDT */
49 result = cyhal_wdt_init(&dev_data->obj, dev_data->timeout);
50 if (result != CY_RSLT_SUCCESS) {
51 LOG_ERR("Initialization failure : 0x%x", result);
52 return -ENOMSG;
53 }
54
55 #ifdef IFX_CAT1_WDT_IS_IRQ_EN
56 if (dev_data->callback) {
57 Cy_WDT_UnmaskInterrupt();
58 irq_enable(DT_INST_IRQN(0));
59 }
60 #endif /* IFX_CAT1_WDT_IS_IRQ_EN */
61
62 return 0;
63 }
64
ifx_cat1_wdt_disable(const struct device * dev)65 static int ifx_cat1_wdt_disable(const struct device *dev)
66 {
67 struct ifx_cat1_wdt_data *dev_data = dev->data;
68
69 #ifdef IFX_CAT1_WDT_IS_IRQ_EN
70 Cy_WDT_MaskInterrupt();
71 irq_disable(DT_INST_IRQN(0));
72 #endif /* IFX_CAT1_WDT_IS_IRQ_EN */
73
74 cyhal_wdt_free(&dev_data->obj);
75
76 return 0;
77 }
78
ifx_cat1_wdt_install_timeout(const struct device * dev,const struct wdt_timeout_cfg * cfg)79 static int ifx_cat1_wdt_install_timeout(const struct device *dev, const struct wdt_timeout_cfg *cfg)
80 {
81 struct ifx_cat1_wdt_data *dev_data = dev->data;
82
83 if (dev_data->timeout_installed) {
84 LOG_ERR("No more timeouts can be installed");
85 return -ENOMEM;
86 }
87
88 if (cfg->flags) {
89 LOG_WRN("Watchdog behavior is not configurable.");
90 }
91
92 if (cfg->callback) {
93 #ifndef IFX_CAT1_WDT_IS_IRQ_EN
94 LOG_WRN("Interrupt is not configured, can't set a callback.");
95 #else
96 dev_data->callback = cfg->callback;
97 #endif /* IFX_CAT1_WDT_IS_IRQ_EN */
98 }
99
100 /* window watchdog not supported */
101 if (cfg->window.min != 0U || cfg->window.max == 0U) {
102 return -EINVAL;
103 }
104
105 dev_data->timeout = cfg->window.max;
106
107 return 0;
108 }
109
ifx_cat1_wdt_feed(const struct device * dev,int channel_id)110 static int ifx_cat1_wdt_feed(const struct device *dev, int channel_id)
111 {
112 struct ifx_cat1_wdt_data *data = dev->data;
113
114 /* Only channel 0 is supported */
115 if (channel_id) {
116 return -EINVAL;
117 }
118
119 cyhal_wdt_kick(&data->obj);
120
121 return 0;
122 }
123
ifx_cat1_wdt_init(const struct device * dev)124 static int ifx_cat1_wdt_init(const struct device *dev)
125 {
126 #ifdef IFX_CAT1_WDT_IS_IRQ_EN
127 /* Connect WDT interrupt to ISR */
128 IRQ_CONNECT(DT_INST_IRQN(0), DT_INST_IRQ(0, priority), ifx_cat1_wdt_isr_handler,
129 DEVICE_DT_INST_GET(0), 0);
130 #endif /* IFX_CAT1_WDT_IS_IRQ_EN */
131
132 return 0;
133 }
134
135 static const struct wdt_driver_api ifx_cat1_wdt_api = {
136 .setup = ifx_cat1_wdt_setup,
137 .disable = ifx_cat1_wdt_disable,
138 .install_timeout = ifx_cat1_wdt_install_timeout,
139 .feed = ifx_cat1_wdt_feed,
140 };
141
142 DEVICE_DT_INST_DEFINE(0, ifx_cat1_wdt_init, NULL, &wdt_data, NULL, POST_KERNEL,
143 CONFIG_KERNEL_INIT_PRIORITY_DEVICE, &ifx_cat1_wdt_api);
144