diff --git a/CODEOWNERS b/CODEOWNERS index d26dd48aa6d..620f669309f 100644 --- a/CODEOWNERS +++ b/CODEOWNERS @@ -302,6 +302,7 @@ /drivers/watchdog/*gecko* @oanerer /drivers/watchdog/*sifive* @katsuster /drivers/watchdog/wdt_handlers.c @dcpleung @nashif +/drivers/watchdog/*cc32xx* @pavlohamov /drivers/wifi/ @jukkar @tbursztyka @pfalcon /drivers/wifi/esp/ @mniestroj /drivers/wifi/eswifi/ @loicpoulain @nandojve diff --git a/drivers/watchdog/CMakeLists.txt b/drivers/watchdog/CMakeLists.txt index 33c1cc49b5d..7b2af17894f 100644 --- a/drivers/watchdog/CMakeLists.txt +++ b/drivers/watchdog/CMakeLists.txt @@ -15,4 +15,5 @@ zephyr_sources_ifdef(CONFIG_WDT_XEC wdt_mchp_xec.c) zephyr_sources_ifdef(CONFIG_WDT_GECKO wdt_gecko.c) zephyr_sources_ifdef(CONFIG_WDT_SIFIVE wdt_sifive.c) zephyr_sources_ifdef(CONFIG_WDT_NPCX wdt_npcx.c) +zephyr_sources_ifdef(CONFIG_WDT_CC32XX wdt_cc32xx.c) zephyr_sources_ifdef(CONFIG_USERSPACE wdt_handlers.c) diff --git a/drivers/watchdog/Kconfig b/drivers/watchdog/Kconfig index 0e803dab3b9..023e58e830d 100644 --- a/drivers/watchdog/Kconfig +++ b/drivers/watchdog/Kconfig @@ -54,4 +54,6 @@ source "drivers/watchdog/Kconfig.sifive" source "drivers/watchdog/Kconfig.npcx" +source "drivers/watchdog/Kconfig.cc32xx" + endif diff --git a/drivers/watchdog/Kconfig.cc32xx b/drivers/watchdog/Kconfig.cc32xx new file mode 100644 index 00000000000..11a3113921b --- /dev/null +++ b/drivers/watchdog/Kconfig.cc32xx @@ -0,0 +1,21 @@ +# Copyright (c) 2021 Pavlo Hamov +# SPDX-License-Identifier: Apache-2.0 + +DT_COMPAT_TI_CC32XX_WDG := ti,cc32xx-watchdog + +config WDT_CC32XX + bool "Watchdog Driver for cc32xx family of MCUs" + default $(dt_compat_enabled,$(DT_COMPAT_TI_CC32XX_WDG)) + depends on SOC_SERIES_CC32XX + depends on SOC_FAMILY_TISIMPLELINK + help + Watchdog for cc32xx family of MCUs + +config WDT_CC32XX_INITIAL_TIMEOUT + int "Value for WDT timeout in ms" + depends on WDT_CC32XX + default 2000 + range 1 53687 + help + Max value depend on system frequency. + 80 Mhz: 0xFFFFFFFF / (80e9 / 1000) diff --git a/drivers/watchdog/wdt_cc32xx.c b/drivers/watchdog/wdt_cc32xx.c new file mode 100644 index 00000000000..85c7e21b505 --- /dev/null +++ b/drivers/watchdog/wdt_cc32xx.c @@ -0,0 +1,197 @@ +/* + * Copyright (c) 2021 Pavlo Hamov + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#define DT_DRV_COMPAT ti_cc32xx_watchdog + +#include +#include +#include + +/* Driverlib includes */ +#include +#include +#include +#include +#include +#include +#include + +#define MAX_RELOAD_VALUE 0xFFFFFFFF + +#define LOG_LEVEL CONFIG_WDT_LOG_LEVEL +#include +#include +LOG_MODULE_REGISTER(wdt_cc32xx); + +struct wdt_cc32xx_data { + int reload; + wdt_callback_t cb; + uint8_t flags; +}; + +struct wdt_cc32xx_cfg { + const unsigned long reg; + void (*irq_cfg_func)(void); +}; + +static uint32_t wdt_cc32xx_msToTicks(uint32_t ms) +{ + static const uint32_t ratio = CONFIG_SYS_CLOCK_HW_CYCLES_PER_SEC / 1000; + static const uint32_t maxMs = MAX_RELOAD_VALUE / ratio; + + if (ms > maxMs) { + return maxMs; + } + + return ms * ratio; +} + +static int wdt_cc32xx_enable(const struct device *dev) +{ + struct wdt_cc32xx_data *data = dev->data; + const struct wdt_cc32xx_cfg *config = dev->config; + const uint32_t reload = wdt_cc32xx_msToTicks(data->reload); + + MAP_WatchdogIntClear(config->reg); + MAP_WatchdogReloadSet(config->reg, reload); + MAP_WatchdogEnable(config->reg); + LOG_DBG("Enabled"); + return 0; +} + +static int wdt_cc32xx_setup(const struct device *dev, uint8_t options) +{ + const struct wdt_cc32xx_cfg *config = dev->config; + int rv; + + if (options & WDT_OPT_PAUSE_IN_SLEEP) { + return -ENOTSUP; + } + + MAP_WatchdogUnlock(config->reg); + if (options & WDT_OPT_PAUSE_HALTED_BY_DBG) { + MAP_WatchdogStallEnable(config->reg); + } else { + MAP_WatchdogStallDisable(config->reg); + } + rv = wdt_cc32xx_enable(dev); + MAP_WatchdogLock(config->reg); + return rv; +} + +static int wdt_cc32xx_disable(const struct device *dev) +{ + return -ENOTSUP; +} + +static int wdt_cc32xx_install_timeout(const struct device *dev, + const struct wdt_timeout_cfg *cfg) +{ + struct wdt_cc32xx_data *data = dev->data; + + if (COND_CODE_1(CONFIG_WDT_MULTISTAGE, (cfg->next), (0))) { + return -ENOTSUP; + } + + data->reload = cfg->window.max; + data->cb = cfg->callback; + data->flags = cfg->flags; + LOG_DBG("Reload time %d", data->reload); + return 0; +} + +static int wdt_cc32xx_feed(const struct device *dev, int channel_id) +{ + struct wdt_cc32xx_data *data = dev->data; + const struct wdt_cc32xx_cfg *config = dev->config; + const uint32_t reload = wdt_cc32xx_msToTicks(data->reload); + bool inIsr = k_is_in_isr(); + + if (!inIsr) { + MAP_WatchdogUnlock(config->reg); + } + MAP_WatchdogIntClear(config->reg); + MAP_WatchdogReloadSet(config->reg, reload); + if (!inIsr) { + MAP_WatchdogLock(config->reg); + } + LOG_DBG("Feed"); + return 0; +} + +static void wdt_cc32xx_isr(const struct device *dev) +{ + struct wdt_cc32xx_data *data = dev->data; + + LOG_DBG("ISR"); + if (data->cb) { + data->cb(dev, 0); + } + if (data->flags != WDT_FLAG_RESET_NONE) { + LOG_PANIC(); + MAP_PRCMMCUReset(data->flags & WDT_FLAG_RESET_SOC); + while (1) { + } + } +} + +static int wdt_cc32xx_init(const struct device *dev) +{ + const struct wdt_cc32xx_cfg *config = dev->config; + int rv; + + LOG_DBG("init"); + config->irq_cfg_func(); + + MAP_PRCMPeripheralClkEnable(PRCM_WDT, PRCM_RUN_MODE_CLK | PRCM_SLP_MODE_CLK); + while (!MAP_PRCMPeripheralStatusGet(PRCM_WDT)) { + } + + if (IS_ENABLED(CONFIG_WDT_DISABLE_AT_BOOT)) { + return 0; + } + + MAP_WatchdogUnlock(config->reg); + rv = wdt_cc32xx_enable(dev); + MAP_WatchdogLock(config->reg); + return rv; +} + +static const struct wdt_driver_api wdt_cc32xx_api = { + .setup = wdt_cc32xx_setup, + .disable = wdt_cc32xx_disable, + .install_timeout = wdt_cc32xx_install_timeout, + .feed = wdt_cc32xx_feed, +}; + +#define cc32xx_WDT_INIT(index) \ + \ + static void wdt_cc32xx_irq_cfg_##index(void) \ + { \ + IRQ_CONNECT(DT_INST_IRQN(index), \ + DT_INST_IRQ(index, priority), \ + wdt_cc32xx_isr, DEVICE_DT_INST_GET(index), 0); \ + irq_enable(DT_INST_IRQN(index)); \ + } \ + \ + static struct wdt_cc32xx_data wdt_cc32xx_data_##index = { \ + .reload = CONFIG_WDT_CC32XX_INITIAL_TIMEOUT, \ + .cb = NULL, \ + .flags = 0, \ + }; \ + \ + static struct wdt_cc32xx_cfg wdt_cc32xx_cfg_##index = { \ + .reg = (unsigned long)DT_INST_REG_ADDR(index), \ + .irq_cfg_func = wdt_cc32xx_irq_cfg_##index, \ + }; \ + \ + DEVICE_DT_INST_DEFINE(index, \ + &wdt_cc32xx_init, device_pm_control_nop, \ + &wdt_cc32xx_data_##index, &wdt_cc32xx_cfg_##index, \ + POST_KERNEL, CONFIG_KERNEL_INIT_PRIORITY_DEFAULT, \ + &wdt_cc32xx_api); + +DT_INST_FOREACH_STATUS_OKAY(cc32xx_WDT_INIT) diff --git a/dts/arm/ti/cc32xx.dtsi b/dts/arm/ti/cc32xx.dtsi index 4c85e7cc96e..bc3bcba4a48 100644 --- a/dts/arm/ti/cc32xx.dtsi +++ b/dts/arm/ti/cc32xx.dtsi @@ -12,6 +12,7 @@ #define INT_ADCCH1 31 // ADC channel 1 #define INT_ADCCH2 32 // ADC channel 2 #define INT_ADCCH3 33 // ADC channel 3 +#define INT_WDT 34 // Watchdog Timer /* Note: Zephyr uses exception numbers, vs the IRQ #s used by the CC32XX SDK */ /* which are offset by 16: */ @@ -22,6 +23,7 @@ #define EXP_ADCCH1 (INT_ADCCH1 - 16) #define EXP_ADCCH2 (INT_ADCCH2 - 16) #define EXP_ADCCH3 (INT_ADCCH3 - 16) +#define EXP_WDT (INT_WDT - 16) #define EXC_GPIOA0 0 /* (INT_GPIOA0 - 16) = (16-16) */ #define EXC_GPIOA1 1 /* (INT_GPIOA1 - 16) = (17-16) */ #define EXC_GPIOA2 2 /* (INT_GPIOA2 - 16) = (18-16) */ @@ -128,6 +130,14 @@ label = "ADC_0"; #io-channel-cells = <1>; }; + + wdt0: watchdog@40000000 { + compatible = "ti,cc32xx-watchdog"; + reg = <0x40000000 0x1000>; + interrupts = ; + label = "WDT_0"; + status = "disabled"; + }; }; }; diff --git a/dts/bindings/watchdog/ti,cc32xx-watchdog.yaml b/dts/bindings/watchdog/ti,cc32xx-watchdog.yaml new file mode 100644 index 00000000000..1528a0ea1d2 --- /dev/null +++ b/dts/bindings/watchdog/ti,cc32xx-watchdog.yaml @@ -0,0 +1,15 @@ +# Copyright (c) 2021 Pavlo Hamov +# SPDX-License-Identifier: Apache-2.0 + +description: cc32xx watchdog + +compatible: "ti,cc32xx-watchdog" + +include: base.yaml + +properties: + reg: + required: true + + label: + required: true