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