diff --git a/drivers/watchdog/CMakeLists.txt b/drivers/watchdog/CMakeLists.txt index 913b4091e5b..e4f25a098e0 100644 --- a/drivers/watchdog/CMakeLists.txt +++ b/drivers/watchdog/CMakeLists.txt @@ -30,6 +30,7 @@ zephyr_library_sources_ifdef(CONFIG_WDT_XEC wdt_mchp_xec.c) zephyr_library_sources_ifdef(CONFIG_WDT_COUNTER wdt_counter.c) zephyr_library_sources_ifdef(CONFIG_WDT_NXP_S32 wdt_nxp_s32.c) zephyr_library_sources_ifdef(CONFIG_WDT_SMARTBOND wdt_smartbond.c) +zephyr_library_sources_ifdef(CONFIG_WDT_TI_TPS382X wdt_ti_tps382x.c) zephyr_library_sources_ifdef(CONFIG_WDT_DW wdt_dw.c) diff --git a/drivers/watchdog/Kconfig b/drivers/watchdog/Kconfig index 9bc18b28669..05f43080445 100644 --- a/drivers/watchdog/Kconfig +++ b/drivers/watchdog/Kconfig @@ -98,4 +98,6 @@ source "drivers/watchdog/Kconfig.dw" source "drivers/watchdog/Kconfig.smartbond" +source "drivers/watchdog/Kconfig.ti_tps382x" + endif # WATCHDOG diff --git a/drivers/watchdog/Kconfig.ti_tps382x b/drivers/watchdog/Kconfig.ti_tps382x new file mode 100644 index 00000000000..9ff0400af3e --- /dev/null +++ b/drivers/watchdog/Kconfig.ti_tps382x @@ -0,0 +1,12 @@ +# Copyright (c) 2023 Prevas A/S +# +# SPDX-License-Identifier: Apache-2.0 + +config WDT_TI_TPS382X + bool "External TI TPS382x Watchdog (WDT) Driver" + default y + depends on DT_HAS_TI_TPS382X_ENABLED + depends on GPIO + help + Enable WDT driver for TI TPS382x. This is an external IC and requires + a GPIO connection from the processor. diff --git a/drivers/watchdog/wdt_ti_tps382x.c b/drivers/watchdog/wdt_ti_tps382x.c new file mode 100644 index 00000000000..c9e94310c3f --- /dev/null +++ b/drivers/watchdog/wdt_ti_tps382x.c @@ -0,0 +1,96 @@ +/* + * Copyright (c) 2023, Prevas A/S + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#define DT_DRV_COMPAT ti_tps382x + +#include +#include +#include +#include + +LOG_MODULE_REGISTER(wdt_ti_tps382x, CONFIG_WDT_LOG_LEVEL); + +struct ti_tps382x_config { + struct gpio_dt_spec wdi_gpio; + int timeout; +}; + +static int ti_tps382x_init(const struct device *dev) +{ + const struct ti_tps382x_config *config = dev->config; + + if (!gpio_is_ready_dt(&config->wdi_gpio)) { + LOG_ERR("WDI gpio not ready"); + return -ENODEV; + } + + return 0; +} + +static int ti_tps382x_setup(const struct device *dev, uint8_t options) +{ + const struct ti_tps382x_config *config = dev->config; + + return gpio_pin_configure_dt(&config->wdi_gpio, GPIO_OUTPUT); +} + +static int ti_tps382x_disable(const struct device *dev) +{ + const struct ti_tps382x_config *config = dev->config; + + /* The watchdog timer can be disabled by disconnecting the WDI pin from + * the system. Do this by changing the gpio to an input (tri-state). + */ + return gpio_pin_configure_dt(&config->wdi_gpio, GPIO_INPUT); +} + +static int ti_tps382x_install_timeout(const struct device *dev, + const struct wdt_timeout_cfg *cfg) +{ + const struct ti_tps382x_config *config = dev->config; + + if (cfg->window.max != config->timeout) { + LOG_ERR("Upper limit of watchdog timeout must be %d not %u", + config->timeout, cfg->window.max); + return -EINVAL; + } else if (cfg->window.min != 0) { + LOG_ERR("Window timeouts not supported"); + return -EINVAL; + } else if (cfg->callback != NULL) { + LOG_ERR("Callbacks not supported"); + return -EINVAL; + } + + return 0; +} + +static int ti_tps382x_feed(const struct device *dev, int channel_id) +{ + const struct ti_tps382x_config *config = dev->config; + + return gpio_pin_toggle_dt(&config->wdi_gpio); +} + +static const struct wdt_driver_api ti_tps382x_api = { + .setup = ti_tps382x_setup, + .disable = ti_tps382x_disable, + .install_timeout = ti_tps382x_install_timeout, + .feed = ti_tps382x_feed, +}; + +#define WDT_TI_TPS382X_INIT(n) \ + static const struct ti_tps382x_config ti_tps382x_##n##config = { \ + .wdi_gpio = GPIO_DT_SPEC_INST_GET(n, wdi_gpios), \ + .timeout = DT_INST_PROP(n, timeout_period), \ + }; \ + \ + DEVICE_DT_INST_DEFINE( \ + n, ti_tps382x_init, NULL, NULL, &ti_tps382x_##n##config, \ + POST_KERNEL, CONFIG_KERNEL_INIT_PRIORITY_DEVICE, \ + &ti_tps382x_api \ + ); + +DT_INST_FOREACH_STATUS_OKAY(WDT_TI_TPS382X_INIT); diff --git a/dts/bindings/watchdog/ti,tps382x.yaml b/dts/bindings/watchdog/ti,tps382x.yaml new file mode 100644 index 00000000000..c6f1e1cd1c6 --- /dev/null +++ b/dts/bindings/watchdog/ti,tps382x.yaml @@ -0,0 +1,31 @@ +# Copyright (c) 2023, Prevas A/S + +description: Watchdog driver for external IC (TPS382x) + +compatible: "ti,tps382x" + +include: base.yaml + +properties: + wdi-gpios: + type: phandle-array + required: true + description: + WDI gpio. If WDI remains high or low longer than the timeout period, + then reset is triggered. The reset has a typical delay time of 200 ms for + TPS3823/4/8, TPS3823A. The timer clears when reset is asserted or + when WDI sees a rising edge or a falling edge. If unused, the WDI + connection must be high impedance to prevent it from causing a reset + event. + + timeout-period: + type: int + default: 1600 + description: + Time-out period in milliseconds. Typical for TPS3823/4/8 and TPS3823A is + 1.6 seconds but minimum is 0.9. To avoid false positive watchdog reset + the watchdog should be kicked within the minimum timeout period. The kick + interval also needs to compensate for MCU clock tolerances which means it + should be kicked with an interval less than 0.9 seconds. If this device + is used as fallback for the task watchdog this can be achieved by setting + e.g. TASK_WDT_MIN_TIMEOUT to 850 and TASK_WDT_HW_FALLBACK_DELAY to 750.