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