Skip to content

Commit 7f21dc2

Browse files
nzmichaelhkartben
authored andcommitted
drivers: watchdog: add a CH32V00x Independent Watchdog (IWDT) driver
The CH32V003 has a built-in watchdog that runs off the low speed internal oscillator. Add a driver. Signed-off-by: Michael Hope <michaelh@juju.nz>
1 parent e358713 commit 7f21dc2

File tree

7 files changed

+130
-0
lines changed

7 files changed

+130
-0
lines changed

drivers/watchdog/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@ zephyr_library_sources_ifdef(CONFIG_WDT_AMBIQ wdt_ambiq.c)
5151
zephyr_library_sources_ifdef(CONFIG_WDT_XMC4XXX wdt_xmc4xxx.c)
5252
zephyr_library_sources_ifdef(CONFIG_WWDT_NUMAKER wdt_wwdt_numaker.c)
5353
zephyr_library_sources_ifdef(CONFIG_WDT_ENE_KB1200 wdt_ene_kb1200.c)
54+
zephyr_library_sources_ifdef(CONFIG_WDT_IWDG_WCH wdt_iwdg_wch.c)
5455

5556
zephyr_library_sources_ifdef(CONFIG_WDT_DW wdt_dw.c wdt_dw_common.c)
5657
zephyr_library_sources_ifdef(CONFIG_WDT_INTEL_ADSP wdt_intel_adsp.c wdt_dw_common.c)

drivers/watchdog/Kconfig

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -151,4 +151,6 @@ source "drivers/watchdog/Kconfig.rts5912"
151151

152152
source "drivers/watchdog/Kconfig.renesas_ra"
153153

154+
source "drivers/watchdog/Kconfig.wch"
155+
154156
endif # WATCHDOG

drivers/watchdog/Kconfig.wch

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
# Copyright (c) 2025 Michael Hope <michaelh@juju.nz>
2+
# SPDX-License-Identifier: Apache-2.0
3+
4+
config WDT_IWDG_WCH
5+
bool "WCH Independent Watchdog (IWDG) driver"
6+
default y
7+
depends on DT_HAS_WCH_IWDG_ENABLED
8+
help
9+
Enable the Independent Watchdog (IWDG) driver. Tested on the
10+
CH32V003 and CH32V208.

drivers/watchdog/wdt_iwdg_wch.c

Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
/*
2+
* Copyright (c) 2025 Michael Hope <michaelh@juju.nz>
3+
*
4+
* SPDX-License-Identifier: Apache-2.0
5+
*/
6+
7+
#define DT_DRV_COMPAT wch_iwdg
8+
9+
#include <zephyr/drivers/watchdog.h>
10+
#include <zephyr/kernel.h>
11+
#include <zephyr/sys_clock.h>
12+
#include <errno.h>
13+
14+
#include <ch32fun.h>
15+
16+
static int iwdg_wch_setup(const struct device *dev, uint8_t options)
17+
{
18+
if (options != 0) {
19+
return -ENOTSUP;
20+
}
21+
22+
IWDG->CTLR = CTLR_KEY_Enable;
23+
24+
return 0;
25+
}
26+
27+
static int iwdg_wch_disable(const struct device *dev)
28+
{
29+
return -EPERM;
30+
}
31+
32+
static int iwdg_wch_install_timeout(const struct device *dev,
33+
const struct wdt_timeout_cfg *config)
34+
{
35+
int prescaler = 0;
36+
/* The IWDT is driven by the 128 kHz LSI oscillator with at least a /4 prescaler. */
37+
uint32_t lsi_frequency = DT_PROP(DT_NODELABEL(clk_lsi), clock_frequency);
38+
uint32_t reload = config->window.max * (lsi_frequency / 1000 / 4);
39+
40+
if (config->callback != NULL) {
41+
return -ENOTSUP;
42+
}
43+
if (config->window.min != 0) {
44+
return -ENOTSUP;
45+
}
46+
if ((config->flags & WDT_FLAG_RESET_MASK) != WDT_FLAG_RESET_SOC) {
47+
return -ENOTSUP;
48+
}
49+
50+
for (; reload > IWDG_RL && prescaler < IWDG_PR;) {
51+
prescaler++;
52+
reload /= 2;
53+
}
54+
if (reload > IWDG_RL) {
55+
/* The reload is too high even with the maximum prescaler */
56+
return -EINVAL;
57+
}
58+
59+
/* Wait for the watchdog to be idle, unlock it, update, and wait for idle. */
60+
while ((IWDG->STATR & (IWDG_RVU | IWDG_PVU)) != 0) {
61+
}
62+
63+
IWDG->CTLR = IWDG_WriteAccess_Enable;
64+
IWDG->PSCR = prescaler;
65+
IWDG->RLDR = reload;
66+
67+
while ((IWDG->STATR & (IWDG_RVU | IWDG_PVU)) != 0) {
68+
}
69+
70+
return 0;
71+
}
72+
73+
static int iwdg_wch_feed(const struct device *dev, int channel_id)
74+
{
75+
IWDG->CTLR = CTLR_KEY_Reload;
76+
77+
return 0;
78+
}
79+
80+
static const struct wdt_driver_api iwdg_wch_api = {
81+
.setup = iwdg_wch_setup,
82+
.disable = iwdg_wch_disable,
83+
.install_timeout = iwdg_wch_install_timeout,
84+
.feed = iwdg_wch_feed,
85+
};
86+
87+
static int iwdg_wch_init(const struct device *dev)
88+
{
89+
return 0;
90+
}
91+
92+
DEVICE_DT_INST_DEFINE(0, iwdg_wch_init, NULL, NULL, NULL, PRE_KERNEL_1,
93+
CONFIG_KERNEL_INIT_PRIORITY_DEVICE, &iwdg_wch_api);

dts/bindings/watchdog/wch,iwdg.yaml

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
# Copyright (c) 2025 Michael Hope <michaelh@juju.nz>
2+
# SPDX-License-Identifier: Apache-2.0
3+
4+
description: WCH Independent Watchdog (IWDG)
5+
6+
compatible: "wch,iwdg"
7+
8+
include: base.yaml
9+
10+
properties:
11+
reg:
12+
required: true

dts/riscv/wch/ch32v0/ch32v003.dtsi

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,12 @@
6666
reg = <0x40007000 0x10>;
6767
};
6868

69+
iwdg: watchdog@40003000 {
70+
compatible = "wch,iwdg";
71+
reg = <0x40003000 0x10>;
72+
status = "disabled";
73+
};
74+
6975
pinctrl: pin-controller@40010000 {
7076
compatible = "wch,afio";
7177
reg = <0x40010000 0x10>;

dts/riscv/wch/ch32v208/ch32v208.dtsi

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,12 @@
6565
reg = <0x40007000 16>;
6666
};
6767

68+
iwdg: watchdog@40003000 {
69+
compatible = "wch,iwdg";
70+
reg = <0x40003000 0x10>;
71+
status = "disabled";
72+
};
73+
6874
pinctrl: pin-controller@40010000 {
6975
compatible = "wch,20x_30x-afio";
7076
reg = <0x40010000 16>;

0 commit comments

Comments
 (0)