You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
176 lines
4.5 KiB
176 lines
4.5 KiB
/* |
|
* Copyright (c) 2024-2025 Espressif Systems (Shanghai) Co., Ltd. |
|
* |
|
* SPDX-License-Identifier: Apache-2.0 |
|
*/ |
|
#define DT_DRV_COMPAT espressif_esp32_xt_wdt |
|
|
|
#include <soc/rtc_cntl_reg.h> |
|
#include <hal/xt_wdt_hal.h> |
|
#include <rom/ets_sys.h> |
|
|
|
#include <string.h> |
|
#include <zephyr/drivers/watchdog.h> |
|
#include <zephyr/drivers/clock_control.h> |
|
#include <zephyr/drivers/clock_control/esp32_clock_control.h> |
|
|
|
#include <zephyr/drivers/interrupt_controller/intc_esp32.h> |
|
#include <zephyr/device.h> |
|
#include <zephyr/logging/log.h> |
|
|
|
LOG_MODULE_REGISTER(xt_wdt_esp32, CONFIG_WDT_LOG_LEVEL); |
|
|
|
#define ESP32_XT_WDT_MAX_TIMEOUT 255 |
|
|
|
struct esp32_xt_wdt_data { |
|
xt_wdt_hal_context_t hal; |
|
wdt_callback_t callback; |
|
uint32_t timeout; |
|
}; |
|
|
|
struct esp32_xt_wdt_config { |
|
const struct device *clock_dev; |
|
const clock_control_subsys_t clock_subsys; |
|
int irq_source; |
|
int irq_priority; |
|
int irq_flags; |
|
}; |
|
|
|
static int esp32_xt_wdt_setup(const struct device *dev, uint8_t options) |
|
{ |
|
ARG_UNUSED(options); |
|
struct esp32_xt_wdt_data *data = dev->data; |
|
|
|
xt_wdt_hal_config_t xt_wdt_hal_config = { |
|
.timeout = data->timeout, |
|
}; |
|
|
|
xt_wdt_hal_init(&data->hal, &xt_wdt_hal_config); |
|
xt_wdt_hal_enable(&data->hal, true); |
|
|
|
return 0; |
|
} |
|
|
|
static int esp32_xt_wdt_disable(const struct device *dev) |
|
{ |
|
struct esp32_xt_wdt_data *data = dev->data; |
|
|
|
xt_wdt_hal_enable(&data->hal, false); |
|
|
|
return 0; |
|
} |
|
|
|
static int esp32_xt_wdt_feed(const struct device *dev, int channel_id) |
|
{ |
|
ARG_UNUSED(dev); |
|
ARG_UNUSED(channel_id); |
|
|
|
return -ENOSYS; |
|
} |
|
|
|
static int esp32_xt_wdt_install_timeout(const struct device *dev, |
|
const struct wdt_timeout_cfg *cfg) |
|
{ |
|
struct esp32_xt_wdt_data *data = dev->data; |
|
|
|
if (cfg->window.min != 0U || cfg->window.max == 0U || |
|
cfg->window.max >= ESP32_XT_WDT_MAX_TIMEOUT) { |
|
LOG_ERR("Invalid timeout configuration"); |
|
return -EINVAL; |
|
} |
|
|
|
data->timeout = cfg->window.max; |
|
data->callback = cfg->callback; |
|
|
|
return 0; |
|
} |
|
|
|
static void esp32_xt_wdt_isr(void *arg) |
|
{ |
|
const struct device *dev = (const struct device *)arg; |
|
const struct esp32_xt_wdt_config *cfg = dev->config; |
|
struct esp32_xt_wdt_data *data = dev->data; |
|
struct esp32_clock_config clk_cfg = {0}; |
|
uint32_t status = REG_READ(RTC_CNTL_INT_ST_REG); |
|
|
|
if (!(status & RTC_CNTL_XTAL32K_DEAD_INT_ST)) { |
|
return; |
|
} |
|
|
|
REG_WRITE(RTC_CNTL_INT_CLR_REG, status); |
|
|
|
clk_cfg.rtc.rtc_slow_clock_src = ESP32_RTC_SLOW_CLK_SRC_RC_SLOW; |
|
|
|
clock_control_configure(cfg->clock_dev, |
|
(clock_control_subsys_t)ESP32_CLOCK_CONTROL_SUBSYS_RTC_SLOW, |
|
&clk_cfg); |
|
|
|
if (data->callback != NULL) { |
|
data->callback(dev, 0); |
|
} |
|
} |
|
|
|
static int esp32_xt_wdt_init(const struct device *dev) |
|
{ |
|
const struct esp32_xt_wdt_config *cfg = dev->config; |
|
struct esp32_xt_wdt_data *data = dev->data; |
|
xt_wdt_hal_config_t xt_wdt_hal_config = { |
|
.timeout = ESP32_XT_WDT_MAX_TIMEOUT, |
|
}; |
|
int err, flags = 0; |
|
|
|
xt_wdt_hal_init(&data->hal, &xt_wdt_hal_config); |
|
xt_wdt_hal_enable_backup_clk(&data->hal, ESP32_RTC_SLOW_CLK_SRC_RC_SLOW_FREQ/1000); |
|
|
|
flags = ESP_PRIO_TO_FLAGS(cfg->irq_priority) | ESP_INT_FLAGS_CHECK(cfg->irq_flags) | |
|
ESP_INTR_FLAG_SHARED; |
|
err = esp_intr_alloc(cfg->irq_source, flags, (intr_handler_t)esp32_xt_wdt_isr, (void *)dev, |
|
NULL); |
|
if (err) { |
|
LOG_ERR("Failed to register ISR\n"); |
|
return -EFAULT; |
|
} |
|
|
|
REG_WRITE(RTC_CNTL_INT_ENA_REG, 0); |
|
REG_WRITE(RTC_CNTL_INT_CLR_REG, UINT32_MAX); |
|
|
|
return 0; |
|
} |
|
|
|
static DEVICE_API(wdt, esp32_xt_wdt_api) = { |
|
.setup = esp32_xt_wdt_setup, |
|
.disable = esp32_xt_wdt_disable, |
|
.install_timeout = esp32_xt_wdt_install_timeout, |
|
.feed = esp32_xt_wdt_feed |
|
}; |
|
|
|
static struct esp32_xt_wdt_data esp32_xt_wdt_data0; |
|
|
|
static struct esp32_xt_wdt_config esp32_xt_wdt_config0 = { |
|
.clock_dev = DEVICE_DT_GET(DT_INST_CLOCKS_CTLR(0)), |
|
.clock_subsys = (clock_control_subsys_t)DT_INST_CLOCKS_CELL(0, offset), |
|
.irq_source = DT_INST_IRQ_BY_IDX(0, 0, irq), |
|
.irq_priority = DT_INST_IRQ_BY_IDX(0, 0, priority), |
|
.irq_flags = DT_INST_IRQ_BY_IDX(0, 0, flags) |
|
}; |
|
|
|
DEVICE_DT_DEFINE(DT_NODELABEL(xt_wdt), |
|
&esp32_xt_wdt_init, |
|
NULL, |
|
&esp32_xt_wdt_data0, |
|
&esp32_xt_wdt_config0, |
|
POST_KERNEL, |
|
CONFIG_KERNEL_INIT_PRIORITY_DEVICE, |
|
&esp32_xt_wdt_api); |
|
|
|
#if !(defined(CONFIG_SOC_SERIES_ESP32S2) || \ |
|
defined(CONFIG_SOC_SERIES_ESP32S3) || \ |
|
defined(CONFIG_SOC_SERIES_ESP32C3)) |
|
#error "XT WDT is not supported" |
|
#else |
|
BUILD_ASSERT((DT_PROP(DT_INST(0, espressif_esp32_clock), slow_clk_src) == |
|
ESP32_RTC_SLOW_CLK_SRC_XTAL32K) || |
|
(DT_PROP(DT_INST(0, espressif_esp32_clock), slow_clk_src) == |
|
ESP32_RTC_SLOW_CLK_32K_EXT_OSC), |
|
"XT WDT is only supported with XTAL32K or 32K_EXT_OSC as slow clock source"); |
|
#endif
|
|
|