1 /*
2  * Copyright (c) 2024 Espressif Systems (Shanghai) Co., Ltd.
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 #define DT_DRV_COMPAT espressif_esp32_xt_wdt
7 
8 #include <soc/rtc_cntl_reg.h>
9 #include <hal/xt_wdt_hal.h>
10 #include <rom/ets_sys.h>
11 
12 #include <string.h>
13 #include <zephyr/drivers/watchdog.h>
14 #include <zephyr/drivers/clock_control.h>
15 #include <zephyr/drivers/clock_control/esp32_clock_control.h>
16 
17 #ifndef CONFIG_SOC_SERIES_ESP32C3
18 #include <zephyr/drivers/interrupt_controller/intc_esp32.h>
19 #else
20 #include <zephyr/drivers/interrupt_controller/intc_esp32c3.h>
21 #endif
22 #include <zephyr/device.h>
23 #include <zephyr/logging/log.h>
24 
25 LOG_MODULE_REGISTER(xt_wdt_esp32, CONFIG_WDT_LOG_LEVEL);
26 
27 #ifdef CONFIG_SOC_SERIES_ESP32C3
28 #define ISR_HANDLER isr_handler_t
29 #else
30 #define ISR_HANDLER intr_handler_t
31 #endif
32 
33 #define ESP32_XT_WDT_MAX_TIMEOUT 255
34 
35 struct esp32_xt_wdt_data {
36 	xt_wdt_hal_context_t hal;
37 	wdt_callback_t callback;
38 	uint32_t timeout;
39 };
40 
41 struct esp32_xt_wdt_config {
42 	const struct device *clock_dev;
43 	const clock_control_subsys_t clock_subsys;
44 	int irq_source;
45 	int irq_priority;
46 	int irq_flags;
47 };
48 
esp32_xt_wdt_setup(const struct device * dev,uint8_t options)49 static int esp32_xt_wdt_setup(const struct device *dev, uint8_t options)
50 {
51 	ARG_UNUSED(options);
52 	struct esp32_xt_wdt_data *data = dev->data;
53 
54 	xt_wdt_hal_config_t xt_wdt_hal_config = {
55 		.timeout = data->timeout,
56 	};
57 
58 	xt_wdt_hal_init(&data->hal, &xt_wdt_hal_config);
59 	xt_wdt_hal_enable(&data->hal, true);
60 
61 	return 0;
62 }
63 
esp32_xt_wdt_disable(const struct device * dev)64 static int esp32_xt_wdt_disable(const struct device *dev)
65 {
66 	struct esp32_xt_wdt_data *data = dev->data;
67 
68 	xt_wdt_hal_enable(&data->hal, false);
69 
70 	return 0;
71 }
72 
esp32_xt_wdt_feed(const struct device * dev,int channel_id)73 static int esp32_xt_wdt_feed(const struct device *dev, int channel_id)
74 {
75 	ARG_UNUSED(dev);
76 	ARG_UNUSED(channel_id);
77 
78 	return -ENOSYS;
79 }
80 
esp32_xt_wdt_install_timeout(const struct device * dev,const struct wdt_timeout_cfg * cfg)81 static int esp32_xt_wdt_install_timeout(const struct device *dev,
82 				     const struct wdt_timeout_cfg *cfg)
83 {
84 	struct esp32_xt_wdt_data *data = dev->data;
85 
86 	if (cfg->window.min != 0U || cfg->window.max == 0U ||
87 	    cfg->window.max >= ESP32_XT_WDT_MAX_TIMEOUT) {
88 		LOG_ERR("Invalid timeout configuration");
89 		return -EINVAL;
90 	}
91 
92 	data->timeout = cfg->window.max;
93 	data->callback = cfg->callback;
94 
95 	return 0;
96 }
97 
esp32_xt_wdt_isr(void * arg)98 static void esp32_xt_wdt_isr(void *arg)
99 {
100 	const struct device *dev = (const struct device *)arg;
101 	const struct esp32_xt_wdt_config *cfg = dev->config;
102 	struct esp32_xt_wdt_data *data = dev->data;
103 	struct esp32_clock_config clk_cfg = {0};
104 	uint32_t status = REG_READ(RTC_CNTL_INT_ST_REG);
105 
106 	if (!(status & RTC_CNTL_XTAL32K_DEAD_INT_ST)) {
107 		return;
108 	}
109 
110 	REG_WRITE(RTC_CNTL_INT_CLR_REG, status);
111 
112 	clk_cfg.rtc.rtc_slow_clock_src = ESP32_RTC_SLOW_CLK_SRC_RC_SLOW;
113 
114 	clock_control_configure(cfg->clock_dev,
115 				(clock_control_subsys_t)ESP32_CLOCK_CONTROL_SUBSYS_RTC_SLOW,
116 				&clk_cfg);
117 
118 	if (data->callback != NULL) {
119 		data->callback(dev, 0);
120 	}
121 }
122 
esp32_xt_wdt_init(const struct device * dev)123 static int esp32_xt_wdt_init(const struct device *dev)
124 {
125 	const struct esp32_xt_wdt_config *cfg = dev->config;
126 	struct esp32_xt_wdt_data *data = dev->data;
127 	xt_wdt_hal_config_t xt_wdt_hal_config = {
128 		.timeout = ESP32_XT_WDT_MAX_TIMEOUT,
129 	};
130 	int err, flags = 0;
131 
132 	xt_wdt_hal_init(&data->hal, &xt_wdt_hal_config);
133 	xt_wdt_hal_enable_backup_clk(&data->hal, ESP32_RTC_SLOW_CLK_SRC_RC_SLOW_FREQ/1000);
134 
135 	flags = ESP_PRIO_TO_FLAGS(cfg->irq_priority) | ESP_INT_FLAGS_CHECK(cfg->irq_flags) |
136 		ESP_INTR_FLAG_SHARED;
137 	err = esp_intr_alloc(cfg->irq_source, flags, (ISR_HANDLER)esp32_xt_wdt_isr, (void *)dev,
138 			     NULL);
139 	if (err) {
140 		LOG_ERR("Failed to register ISR\n");
141 		return -EFAULT;
142 	}
143 
144 	REG_WRITE(RTC_CNTL_INT_ENA_REG, 0);
145 	REG_WRITE(RTC_CNTL_INT_CLR_REG, UINT32_MAX);
146 
147 	return 0;
148 }
149 
150 static DEVICE_API(wdt, esp32_xt_wdt_api) = {
151 	.setup = esp32_xt_wdt_setup,
152 	.disable = esp32_xt_wdt_disable,
153 	.install_timeout = esp32_xt_wdt_install_timeout,
154 	.feed = esp32_xt_wdt_feed
155 };
156 
157 static struct esp32_xt_wdt_data esp32_xt_wdt_data0;
158 
159 static struct esp32_xt_wdt_config esp32_xt_wdt_config0 = {
160 	.clock_dev = DEVICE_DT_GET(DT_INST_CLOCKS_CTLR(0)),
161 	.clock_subsys = (clock_control_subsys_t)DT_INST_CLOCKS_CELL(0, offset),
162 	.irq_source = DT_INST_IRQ_BY_IDX(0, 0, irq),
163 	.irq_priority = DT_INST_IRQ_BY_IDX(0, 0, priority),
164 	.irq_flags = DT_INST_IRQ_BY_IDX(0, 0, flags)
165 };
166 
167 DEVICE_DT_DEFINE(DT_NODELABEL(xt_wdt),
168 		 &esp32_xt_wdt_init,
169 		 NULL,
170 		 &esp32_xt_wdt_data0,
171 		 &esp32_xt_wdt_config0,
172 		 POST_KERNEL,
173 		 CONFIG_KERNEL_INIT_PRIORITY_DEVICE,
174 		 &esp32_xt_wdt_api);
175 
176 #if !(defined(CONFIG_SOC_SERIES_ESP32S2) ||	\
177 	defined(CONFIG_SOC_SERIES_ESP32S3) ||   \
178 	defined(CONFIG_SOC_SERIES_ESP32C3))
179 #error "XT WDT is not supported"
180 #else
181 BUILD_ASSERT((DT_PROP(DT_INST(0, espressif_esp32_rtc), slow_clk_src) ==
182 	      ESP32_RTC_SLOW_CLK_SRC_XTAL32K) ||
183 		     (DT_PROP(DT_INST(0, espressif_esp32_rtc), slow_clk_src) ==
184 		      ESP32_RTC_SLOW_CLK_32K_EXT_OSC),
185 	     "XT WDT is only supported with XTAL32K or 32K_EXT_OSC as slow clock source");
186 #endif
187