Browse Source

drivers: watchdog: siwx91x: Add siwx91x WDT driver

Implement Watchdog driver for siwx91x device

Signed-off-by: Sai Santhosh Malae <Santhosh.Malae@silabs.com>
pull/87214/head
Sai Santhosh Malae 5 months ago committed by Benjamin Cabé
parent
commit
c6198008f5
  1. 1
      boards/silabs/radio_boards/siwx917_rb4338a/siwx917_rb4338a.yaml
  2. 12
      drivers/clock_control/clock_control_silabs_siwx91x.c
  3. 1
      drivers/watchdog/CMakeLists.txt
  4. 2
      drivers/watchdog/Kconfig
  5. 9
      drivers/watchdog/Kconfig.siwx91x
  6. 270
      drivers/watchdog/wdt_silabs_siwx91x.c
  7. 11
      dts/arm/silabs/siwg917.dtsi
  8. 12
      dts/bindings/watchdog/silabs,siwx91x-wdt.yaml
  9. 1
      include/zephyr/dt-bindings/clock/silabs/siwx91x-clock.h
  10. 3
      modules/hal_silabs/wiseconnect/CMakeLists.txt
  11. 15
      samples/drivers/watchdog/boards/siwx917_rb4338a.overlay
  12. 9
      tests/drivers/watchdog/wdt_basic_api/boards/siwx917_rb4338a.overlay
  13. 2
      tests/drivers/watchdog/wdt_basic_api/src/test_wdt.c

1
boards/silabs/radio_boards/siwx917_rb4338a/siwx917_rb4338a.yaml

@ -15,5 +15,6 @@ supported: @@ -15,5 +15,6 @@ supported:
- gpio
- i2c
- pwm
- watchdog
- wifi
vendor: silabs

12
drivers/clock_control/clock_control_silabs_siwx91x.c

@ -12,10 +12,13 @@ @@ -12,10 +12,13 @@
#include "rsi_power_save.h"
#include "rsi_rom_ulpss_clk.h"
#include "rsi_rom_clks.h"
#include "rsi_sysrtc.h"
#include "clock_update.h"
#include "sl_si91x_clock_manager.h"
#define DT_DRV_COMPAT silabs_siwx91x_clock
#define DT_DRV_COMPAT silabs_siwx91x_clock
#define LF_FSM_CLOCK_FREQUENCY 32768
LOG_MODULE_REGISTER(siwx91x_clock, CONFIG_CLOCK_CONTROL_LOG_LEVEL);
@ -68,6 +71,12 @@ static int siwx91x_clock_on(const struct device *dev, clock_control_subsys_t sys @@ -68,6 +71,12 @@ static int siwx91x_clock_on(const struct device *dev, clock_control_subsys_t sys
RSI_PS_M4ssPeriPowerUp(M4SS_PWRGATE_ULP_EFUSE_PERI);
RSI_CLK_PeripheralClkEnable(M4CLK, PWM_CLK, ENABLE_STATIC_CLK);
break;
case SIWX91X_CLK_WATCHDOG:
/* Both SYSRTC and WDT are clocked using LF-FSM XTAL which is initialized in
* SystemCoreClockUpdate(). This function allows clock to stabilize before use.
*/
rsi_sysrtc_clk_set(RSI_SYSRTC_CLK_32kHz_Xtal, 0);
break;
default:
return -EINVAL;
}
@ -129,6 +138,9 @@ static int siwx91x_clock_get_rate(const struct device *dev, clock_control_subsys @@ -129,6 +138,9 @@ static int siwx91x_clock_get_rate(const struct device *dev, clock_control_subsys
/* PWM peripheral operates at the system clock frequency */
*rate = CONFIG_SYS_CLOCK_HW_CYCLES_PER_SEC;
return 0;
case SIWX91X_CLK_WATCHDOG:
*rate = LF_FSM_CLOCK_FREQUENCY;
return 0;
default:
/* For now, no other driver need clock rate */
return -EINVAL;

1
drivers/watchdog/CMakeLists.txt

@ -36,6 +36,7 @@ zephyr_library_sources_ifdef(CONFIG_WDT_SAM wdt_sam.c) @@ -36,6 +36,7 @@ zephyr_library_sources_ifdef(CONFIG_WDT_SAM wdt_sam.c)
zephyr_library_sources_ifdef(CONFIG_WDT_SAM4L wdt_sam4l.c)
zephyr_library_sources_ifdef(CONFIG_WDT_SAM0 wdt_sam0.c)
zephyr_library_sources_ifdef(CONFIG_WDT_SIFIVE wdt_sifive.c)
zephyr_library_sources_ifdef(CONFIG_WDT_SILABS_SIWX91X wdt_silabs_siwx91x.c)
zephyr_library_sources_ifdef(CONFIG_WDT_TCO wdt_tco.c)
zephyr_library_sources_ifdef(CONFIG_WDT_XEC wdt_mchp_xec.c)
zephyr_library_sources_ifdef(CONFIG_WDT_COUNTER wdt_counter.c)

2
drivers/watchdog/Kconfig

@ -87,6 +87,8 @@ source "drivers/watchdog/Kconfig.xec" @@ -87,6 +87,8 @@ source "drivers/watchdog/Kconfig.xec"
source "drivers/watchdog/Kconfig.gecko"
source "drivers/watchdog/Kconfig.siwx91x"
source "drivers/watchdog/Kconfig.sifive"
source "drivers/watchdog/Kconfig.npcx"

9
drivers/watchdog/Kconfig.siwx91x

@ -0,0 +1,9 @@ @@ -0,0 +1,9 @@
# Copyright (c) 2025 Silicon Laboratories Inc.
# SPDX-License-Identifier: Apache-2.0
config WDT_SILABS_SIWX91X
bool "Silabs SiWx91x Watchdog driver"
default y
depends on DT_HAS_SILABS_SIWX91X_WDT_ENABLED
help
Enable the Watchdog driver for the Silabs SiWx91x SoC series.

270
drivers/watchdog/wdt_silabs_siwx91x.c

@ -0,0 +1,270 @@ @@ -0,0 +1,270 @@
/*
* Copyright (c) 2025 Silicon Laboratories Inc.
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <errno.h>
#include <zephyr/irq.h>
#include <zephyr/types.h>
#include <zephyr/device.h>
#include <zephyr/sys/util.h>
#include <zephyr/sys/bitarray.h>
#include <zephyr/drivers/watchdog.h>
#include <zephyr/drivers/clock_control.h>
#include <math.h>
#include "rsi_wwdt.h"
#include "rsi_sysrtc.h"
#define DT_DRV_COMPAT silabs_siwx91x_wdt
#define SIWX91X_WDT_SYSTEM_RESET_TIMER_MASK 0x0000001F
struct siwx91x_wdt_config {
/* WDT register base address */
MCU_WDT_Type *reg;
/* Pointer to the clock device structure */
const struct device *clock_dev;
/* Clock control subsystem */
clock_control_subsys_t clock_subsys;
/* Function pointer for the IRQ (Interrupt Request) configuration */
void (*irq_config)(void);
};
struct siwx91x_wdt_data {
/* Callback function to be called on watchdog timer events */
wdt_callback_t callback;
/* WDT operating clock (LF-FSM) frequency */
uint32_t clock_frequency;
/* Timer system reset duration in ms */
uint8_t delay_reset;
/* Timer interrupt duration in ms */
uint8_t delay_irq;
/* Flag indicating the timeout install status */
bool timeout_install_status;
/* Flag indicating the setup status */
bool setup_status;
};
/* Function to get the delay in milliseconds from the register value */
static uint32_t siwx91x_wdt_delay_from_hw(uint8_t value, int clock_frequency)
{
uint32_t ticks = BIT(value);
float timeout = (float)ticks / clock_frequency;
timeout *= 1000;
/* Return the timeout value as an unsigned 32-bit integer in milliseconds */
return (uint32_t)timeout;
}
/* Function to get the register value from the delay in milliseconds */
static uint8_t siwx91x_wdt_delay_to_hw(uint32_t delay, int clock_frequency)
{
/* reg_value = log((timeout * clock_frequency)/1000)base2 */
float value = ((float)delay * (float)clock_frequency) / 1000;
float result = log2f(value);
/* Round the result to nearest integer */
result = roundf(result);
return (uint8_t)result;
}
static int siwx91x_wdt_install_timeout(const struct device *dev, const struct wdt_timeout_cfg *cfg)
{
struct siwx91x_wdt_data *data = dev->data;
/* Check the WDT setup status */
if (data->setup_status) {
/* WDT setup is already done */
return -EBUSY;
}
/* Check the WDT timeout status */
if (data->timeout_install_status) {
/* Only single timeout can be installed */
return -ENOMEM;
}
if (cfg->window.max > siwx91x_wdt_delay_from_hw(SIWX91X_WDT_SYSTEM_RESET_TIMER_MASK,
data->clock_frequency) ||
cfg->window.max == 0) {
/* Requested value is out of range */
return -EINVAL;
}
if (cfg->window.min > 0) {
/* This feature is currently not supported */
return -ENOTSUP;
}
switch (cfg->flags) {
case WDT_FLAG_RESET_SOC:
case WDT_FLAG_RESET_CPU_CORE:
if (cfg->callback != NULL) {
/* Callback is not supported for reset flags */
return -ENOTSUP;
}
data->delay_reset = siwx91x_wdt_delay_to_hw(cfg->window.max, data->clock_frequency);
/* During a system or CPU core reset, interrupts are not needed. Thus, we set
* the interrupt time to 0 to ensure no interrupts occur while resetting.
*/
data->delay_irq = 0;
/* Mask the WWDT interrupt */
RSI_WWDT_IntrMask();
break;
case WDT_FLAG_RESET_NONE:
/* Set the reset time to maximum value */
data->delay_reset = SIWX91X_WDT_SYSTEM_RESET_TIMER_MASK;
data->delay_irq = siwx91x_wdt_delay_to_hw(cfg->window.max, data->clock_frequency);
if (cfg->callback != NULL) {
data->callback = cfg->callback;
}
break;
default:
/* Unsupported WDT config options */
return -ENOTSUP;
}
data->timeout_install_status = true;
return 0;
}
/* Function to setup and start WDT */
static int siwx91x_wdt_setup(const struct device *dev, uint8_t options)
{
const struct siwx91x_wdt_config *config = dev->config;
struct siwx91x_wdt_data *data = dev->data;
/* Check the WDT setup status */
if (data->setup_status) {
/* WDT is already running */
return -EBUSY;
}
/* Check the WDT timeout status */
if (!data->timeout_install_status) {
/* Timeout need to be set before setup */
return -ENOTSUP;
}
if (options & (WDT_OPT_PAUSE_IN_SLEEP)) {
return -ENOTSUP;
}
RSI_WWDT_ConfigSysRstTimer(config->reg, data->delay_reset);
RSI_WWDT_ConfigIntrTimer(config->reg, data->delay_irq);
RSI_WWDT_Start(config->reg);
data->setup_status = true;
return 0;
}
static int siwx91x_wdt_disable(const struct device *dev)
{
const struct siwx91x_wdt_config *config = dev->config;
struct siwx91x_wdt_data *data = dev->data;
if (!data->timeout_install_status) {
/* No timeout installed */
return -EFAULT;
}
RSI_WWDT_Disable(config->reg);
data->timeout_install_status = false;
data->setup_status = false;
return 0;
}
static int siwx91x_wdt_feed(const struct device *dev, int channel_id)
{
const struct siwx91x_wdt_config *config = dev->config;
struct siwx91x_wdt_data *data = dev->data;
if (!(data->timeout_install_status && data->setup_status)) {
/* WDT is not configured */
return -EINVAL;
}
if (channel_id != 0) {
/* Channel id must be 0 */
return -EINVAL;
}
RSI_WWDT_ReStart(config->reg);
return 0;
}
static void siwx91x_wdt_isr(const struct device *dev)
{
const struct siwx91x_wdt_config *config = dev->config;
struct siwx91x_wdt_data *data = dev->data;
/* Clear WDT interrupt */
RSI_WWDT_IntrClear();
if (data->delay_irq) {
/* Restart the timer */
RSI_WWDT_ReStart(config->reg);
}
if (data->callback != NULL) {
data->callback(dev, 0);
}
}
static int siwx91x_wdt_init(const struct device *dev)
{
const struct siwx91x_wdt_config *config = dev->config;
struct siwx91x_wdt_data *data = dev->data;
int ret;
ret = clock_control_on(config->clock_dev, config->clock_subsys);
if (ret) {
return ret;
}
ret = clock_control_get_rate(config->clock_dev, config->clock_subsys,
&data->clock_frequency);
if (ret) {
return ret;
}
RSI_WWDT_Init(config->reg);
config->irq_config();
RSI_WWDT_IntrUnMask();
return 0;
}
static DEVICE_API(wdt, siwx91x_wdt_driver_api) = {
.setup = siwx91x_wdt_setup,
.disable = siwx91x_wdt_disable,
.install_timeout = siwx91x_wdt_install_timeout,
.feed = siwx91x_wdt_feed,
};
#define siwx91x_WDT_INIT(inst) \
static struct siwx91x_wdt_data siwx91x_wdt_data_##inst; \
static void siwx91x_wdt_irq_configure_##inst(void) \
{ \
IRQ_CONNECT(DT_INST_IRQ(inst, irq), DT_INST_IRQ(inst, priority), siwx91x_wdt_isr, \
DEVICE_DT_INST_GET(inst), 0); \
irq_enable(DT_INST_IRQ(inst, irq)); \
} \
static const struct siwx91x_wdt_config siwx91x_wdt_config_##inst = { \
.reg = (MCU_WDT_Type *)DT_INST_REG_ADDR(inst), \
.clock_dev = DEVICE_DT_GET(DT_INST_CLOCKS_CTLR(inst)), \
.clock_subsys = (clock_control_subsys_t)DT_INST_PHA(inst, clocks, clkid), \
.irq_config = siwx91x_wdt_irq_configure_##inst, \
}; \
DEVICE_DT_INST_DEFINE(inst, &siwx91x_wdt_init, NULL, &siwx91x_wdt_data_##inst, \
&siwx91x_wdt_config_##inst, PRE_KERNEL_1, \
CONFIG_KERNEL_INIT_PRIORITY_DEFAULT, &siwx91x_wdt_driver_api);
DT_INST_FOREACH_STATUS_OKAY(siwx91x_WDT_INIT)

11
dts/arm/silabs/siwg917.dtsi

@ -274,6 +274,17 @@ @@ -274,6 +274,17 @@
silabs,ch_prescaler = <64 64 64 64>;
status = "disabled";
};
watchdog: wdt@24048300 {
compatible = "silabs,siwx91x-wdt";
#address-cells = <1>;
#size-cells = <0>;
reg = <0x24048300 0x1C>;
interrupts = <20 0>;
interrupt-names = "watchdog";
clocks = <&clock0 SIWX91X_CLK_WATCHDOG>;
status = "disabled";
};
};
};

12
dts/bindings/watchdog/silabs,siwx91x-wdt.yaml

@ -0,0 +1,12 @@ @@ -0,0 +1,12 @@
description: Silabs SiWx91x Watchdog node
compatible: "silabs,siwx91x-wdt"
include: base.yaml
properties:
reg:
required: true
interrupts:
required: true

1
include/zephyr/dt-bindings/clock/silabs/siwx91x-clock.h

@ -12,6 +12,7 @@ @@ -12,6 +12,7 @@
#define SIWX91X_CLK_I2C0 5
#define SIWX91X_CLK_I2C1 6
#define SIWX91X_CLK_DMA0 7
#define SIWX91X_CLK_WATCHDOG 8
#define SIWX91X_CLK_PWM 9
#endif

3
modules/hal_silabs/wiseconnect/CMakeLists.txt

@ -25,6 +25,7 @@ zephyr_include_directories( @@ -25,6 +25,7 @@ zephyr_include_directories(
${WISECONNECT_DIR}/components/board/silabs/inc
${WISECONNECT_DIR}/components/device/silabs/si91x/mcu/core/config
${WISECONNECT_DIR}/components/device/silabs/si91x/mcu/core/chip/inc
${WISECONNECT_DIR}/components/device/silabs/si91x/mcu/core/chip/config
${WISECONNECT_DIR}/components/device/silabs/si91x/mcu/drivers/rom_driver/inc
${WISECONNECT_DIR}/components/device/silabs/si91x/mcu/drivers/peripheral_drivers/inc
${WISECONNECT_DIR}/components/device/silabs/si91x/mcu/drivers/service/clock_manager/inc
@ -42,9 +43,11 @@ zephyr_library_sources( @@ -42,9 +43,11 @@ zephyr_library_sources(
${WISECONNECT_DIR}/components/device/silabs/si91x/mcu/core/chip/src/system_si91x.c
${WISECONNECT_DIR}/components/device/silabs/si91x/mcu/drivers/peripheral_drivers/src/clock_update.c
${WISECONNECT_DIR}/components/device/silabs/si91x/mcu/drivers/peripheral_drivers/src/rsi_pwm.c
${WISECONNECT_DIR}/components/device/silabs/si91x/mcu/drivers/peripheral_drivers/src/rsi_sysrtc.c
${WISECONNECT_DIR}/components/device/silabs/si91x/mcu/drivers/systemlevel/src/rsi_ipmu.c
${WISECONNECT_DIR}/components/device/silabs/si91x/mcu/drivers/systemlevel/src/rsi_pll.c
${WISECONNECT_DIR}/components/device/silabs/si91x/mcu/drivers/systemlevel/src/rsi_ulpss_clk.c
${WISECONNECT_DIR}/components/device/silabs/si91x/mcu/drivers/systemlevel/src/rsi_wwdt.c
${WISECONNECT_DIR}/components/device/silabs/si91x/mcu/drivers/service/clock_manager/src/sl_si91x_clock_manager.c
${WISECONNECT_DIR}/components/device/silabs/si91x/mcu/drivers/unified_api/src/sl_si91x_driver_gpio.c
${WISECONNECT_DIR}/components/device/silabs/si91x/mcu/drivers/unified_api/src/sl_si91x_pwm.c

15
samples/drivers/watchdog/boards/siwx917_rb4338a.overlay

@ -0,0 +1,15 @@ @@ -0,0 +1,15 @@
/*
* Copyright (c) 2025 Silicon Laboratories Inc.
*
* SPDX-License-Identifier: Apache-2.0
*/
/ {
aliases {
watchdog0 = &watchdog;
};
};
&watchdog {
status = "okay";
};

9
tests/drivers/watchdog/wdt_basic_api/boards/siwx917_rb4338a.overlay

@ -0,0 +1,9 @@ @@ -0,0 +1,9 @@
/*
* Copyright (c) 2025 Silicon Laboratories Inc.
*
* SPDX-License-Identifier: Apache-2.0
*/
&watchdog {
status = "okay";
};

2
tests/drivers/watchdog/wdt_basic_api/src/test_wdt.c

@ -98,6 +98,8 @@ @@ -98,6 +98,8 @@
#define WDT_NODE DT_INST(0, gd_gd32_fwdgt)
#elif DT_HAS_COMPAT_STATUS_OKAY(zephyr_counter_watchdog)
#define WDT_NODE DT_COMPAT_GET_ANY_STATUS_OKAY(zephyr_counter_watchdog)
#elif DT_HAS_COMPAT_STATUS_OKAY(silabs_siwx91x_wdt)
#define WDT_NODE DT_INST(0, silabs_siwx91x_wdt)
#elif DT_HAS_COMPAT_STATUS_OKAY(nuvoton_numaker_wwdt)
#define WDT_NODE DT_INST(0, nuvoton_numaker_wwdt)
#define TIMEOUTS 1

Loading…
Cancel
Save