Skip to content

Commit e9e2e5c

Browse files
SangTranRVCquytranpzz
authored andcommitted
drivers: watchdog: Support Renesas RX independent watchdog timer driver
Add initial support for independent watchdog driver for Renesas RX with r_iwdt_rx RDP HAL Signed-off-by: Sang Tran <sang.tran.jc@renesas.com>
1 parent 74f5f27 commit e9e2e5c

File tree

6 files changed

+375
-0
lines changed

6 files changed

+375
-0
lines changed

drivers/watchdog/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ zephyr_syscall_header(${ZEPHYR_BASE}/include/zephyr/drivers/watchdog.h)
55
zephyr_library()
66

77
zephyr_library_sources_ifdef(CONFIG_IWDG_STM32 wdt_iwdg_stm32.c)
8+
zephyr_library_sources_ifdef(CONFIG_IWDT_RENESAS_RX wdt_iwdt_renesas_rx.c)
89
zephyr_library_sources_ifdef(CONFIG_WWDG_STM32 wdt_wwdg_stm32.c)
910

1011
zephyr_library_sources_ifdef(CONFIG_FWDGT_GD32 wdt_fwdgt_gd32.c)

drivers/watchdog/Kconfig

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

154154
source "drivers/watchdog/Kconfig.renesas_ra"
155155

156+
source "drivers/watchdog/Kconfig.renesas_rx"
157+
156158
source "drivers/watchdog/Kconfig.wch"
157159

158160
source "drivers/watchdog/Kconfig.nxp_ewm"

drivers/watchdog/Kconfig.renesas_rx

Lines changed: 104 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,104 @@
1+
# Renesas RX Independent Watchdog (IWDT) configuration
2+
3+
# Copyright (c) 2025 Renesas Electronics Corporation
4+
# SPDX-License-Identifier: Apache-2.0
5+
6+
config IWDT_RENESAS_RX
7+
bool "Renesas RX Series Independent Watchdog Driver"
8+
default y
9+
depends on DT_HAS_RENESAS_RX_IWDT_ENABLED
10+
select HAS_WDT_DISABLE_AT_BOOT
11+
select USE_RX_RDP_IWDT
12+
help
13+
Enable Renesas RX series watchdog driver.
14+
15+
if IWDT_RENESAS_RX
16+
17+
config IWDT_RX_NMI
18+
bool "Non-maskable interrupt for IWDT"
19+
default y
20+
help
21+
Enable NMI for IWDT.
22+
23+
choice
24+
prompt "IWDT Start Mode"
25+
default IWDT_RENESAS_RX_IWDT
26+
help
27+
Select the IWDT start mode.
28+
- IWDT_RENESAS_RX_AUTO_START_MODE: Counting automatically starts after a reset
29+
(auto-start mode), controlled by option function select register 0 (OFS0).
30+
- IWDT_RENESAS_RX_IWDT: Counting is started by refreshing the counter.
31+
(controlled by the IWDT registers)
32+
33+
config IWDT_RENESAS_RX_AUTO_START_MODE
34+
bool "Start IWDT automatically on reset"
35+
36+
config IWDT_RENESAS_RX_IWDT
37+
bool "IWDT Start Mode Select"
38+
select USE_RX_RDP_IWDT
39+
40+
endchoice
41+
42+
if IWDT_RENESAS_RX_AUTO_START_MODE
43+
44+
config IWDT_RENESAS_RX_IWDTSTRT
45+
int "IWDT OFS0 Start Mode Select"
46+
default 0
47+
help
48+
0: IWDT is automatically activated in auto-start mode after a reset
49+
1: IWDT is halted after a reset
50+
51+
config IWDT_RENESAS_RX_OFS0_IWDTTOPS
52+
int "IWDT Timeout Period Select"
53+
default 3
54+
help
55+
0: 128 cycles (007Fh)
56+
1: 512 cycles (01FFh)
57+
2: 1024 cycles (03FFh)
58+
3: 2048 cycles (07FFh)
59+
60+
config IWDT_RENESAS_RX_OFS0_IWDTCKS
61+
int "IWDT Clock Divide Ratio Select"
62+
default 15
63+
help
64+
0: No division
65+
2: Divide-by-16
66+
3: Divide-by-32
67+
4: Divide-by-64
68+
15: Divide-by-128
69+
5: Divide-by-256
70+
71+
config IWDT_RENESAS_RX_OFS0_IWDTRPSS
72+
int "IWDT Window Start Position Select"
73+
default 3
74+
help
75+
0: 25%
76+
1: 50%
77+
2: 75%
78+
3: 100% (window start position is not specified.)
79+
80+
config IWDT_RENESAS_RX_OFS0_IWDTRPES
81+
int "IWDT Window End Position Select"
82+
default 3
83+
help
84+
0: 75%
85+
1: 50%
86+
2: 25%
87+
3: 0% (window end position is not specified.)
88+
89+
config IWDT_RENESAS_RX_OFS0_IWDTRSTIRQS
90+
int "IWDT Reset Interrupt Request Select"
91+
default 0
92+
help
93+
0: Non-maskable interrupt request output is enabled.
94+
1: Reset output is enabled.
95+
96+
config IWDT_RENESAS_RX_OFS0_IWDTSLCSTP
97+
int "IWDT Sleep Mode Count Stop Control"
98+
default 0
99+
help
100+
0: Count stop is disabled.
101+
1: Count is stopped at a transition to sleep mode, software standby mode, or deep sleep mode.
102+
103+
endif # IWDT_RENESAS_RX_AUTO_START_MODE
104+
endif # IWDT_RENESAS_RX
Lines changed: 224 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,224 @@
1+
/*
2+
* Copyright (c) 2025 Renesas Electronics Corporation and/or its affiliates
3+
*
4+
* SPDX-License-Identifier: Apache-2.0
5+
*/
6+
7+
/**
8+
* @brief Independent Watchdog (IWDT) Driver for Renesas RX
9+
*/
10+
11+
#define DT_DRV_COMPAT renesas_rx_iwdt
12+
13+
#include <zephyr/drivers/watchdog.h>
14+
#include <soc.h>
15+
#include <zephyr/kernel.h>
16+
#include <stdlib.h>
17+
#include <zephyr/arch/rx/sw_nmi_table.h>
18+
19+
#include "r_iwdt_rx_if.h"
20+
21+
#include <platform.h>
22+
23+
#define LOG_LEVEL CONFIG_WDT_LOG_LEVEL
24+
#include <zephyr/logging/log.h>
25+
LOG_MODULE_REGISTER(wdt_iwdt_rx);
26+
27+
#define IWDT_NODELABEL DT_NODELABEL(iwdt)
28+
#define IWDT_NMI_VECTOR 2
29+
#define IWDT_WINDOW_START DT_PROP(IWDT_NODELABEL, window_start)
30+
#define IWDT_WINDOW_END DT_PROP(IWDT_NODELABEL, window_end)
31+
32+
#define WDT_RENESAS_RX_SUPPORTED_FLAGS (WDT_FLAG_RESET_NONE | WDT_FLAG_RESET_SOC)
33+
struct wdt_iwdt_rx_config {
34+
struct st_iwdt *const regs;
35+
const struct device *clock_dev;
36+
};
37+
38+
struct wdt_iwdt_rx_data {
39+
wdt_callback_t callback;
40+
iwdt_config_t iwdt_config;
41+
bool timeout_installed;
42+
};
43+
44+
#if CONFIG_IWDT_RX_NMI
45+
static void wdt_iwdt_isr(const struct device *dev)
46+
{
47+
struct wdt_iwdt_rx_data *data = dev->data;
48+
49+
if (data->callback) {
50+
data->callback(dev, 0);
51+
}
52+
}
53+
54+
static void iwdt_enable_nmi(void)
55+
{
56+
ICU.NMIER.BIT.IWDTEN = 0x1;
57+
}
58+
#endif /* CONFIG_IWDT_RX_NMI */
59+
60+
static int wdt_iwdt_rx_disable(const struct device *dev)
61+
{
62+
ARG_UNUSED(dev);
63+
64+
/* watchdog cannot be stopped once started */
65+
LOG_ERR("Independent Watchdog cannot be stopped once started");
66+
67+
return -EPERM;
68+
}
69+
70+
static int wdt_iwdt_rx_feed(const struct device *dev, int channel_id)
71+
{
72+
ARG_UNUSED(dev);
73+
ARG_UNUSED(channel_id);
74+
iwdt_err_t err;
75+
76+
/* Reset counter */
77+
err = R_IWDT_Control(IWDT_CMD_REFRESH_COUNTING, NULL);
78+
if (err != IWDT_SUCCESS) {
79+
return -EIO;
80+
}
81+
82+
return 0;
83+
}
84+
85+
static int wdt_iwdt_rx_install_timeout(const struct device *dev, const struct wdt_timeout_cfg *cfg)
86+
{
87+
struct wdt_iwdt_rx_data *data = dev->data;
88+
const struct wdt_iwdt_rx_config *iwdt_cfg = dev->config;
89+
uint32_t clock_rate;
90+
int ret;
91+
92+
/* Get the iwdt clock rate in hz */
93+
ret = clock_control_get_rate(iwdt_cfg->clock_dev, NULL, &clock_rate);
94+
if (ret != 0) {
95+
return ret;
96+
}
97+
98+
uint32_t clock_rate_khz = clock_rate / 1000;
99+
100+
const uint16_t timeout_period[4] = {128, 512, 1024, 2048};
101+
const uint16_t clock_divide[6][2] = {{IWDT_CLOCK_DIV_1, 1}, {IWDT_CLOCK_DIV_16, 16},
102+
{IWDT_CLOCK_DIV_32, 32}, {IWDT_CLOCK_DIV_64, 64},
103+
{IWDT_CLOCK_DIV_128, 128}, {IWDT_CLOCK_DIV_256, 256}};
104+
int16_t last_error = INT16_MAX;
105+
int32_t error;
106+
uint16_t iwdt_tops = 0;
107+
uint16_t iwdt_clock_div = 0;
108+
uint16_t iwdt_timeout = ((uint32_t)timeout_period[0] * clock_divide[0][1]) / clock_rate_khz;
109+
110+
if (cfg->window.min > cfg->window.max || cfg->window.max < iwdt_timeout) {
111+
return -EINVAL;
112+
}
113+
114+
if ((cfg->flags & ~WDT_RENESAS_RX_SUPPORTED_FLAGS) != 0) {
115+
return -ENOTSUP;
116+
}
117+
118+
if (cfg->callback != NULL && (cfg->flags & WDT_FLAG_RESET_MASK) != 0) {
119+
LOG_ERR("WDT_FLAG_RESET_NONE should be chosen in case of interrupt response");
120+
return -ENOTSUP;
121+
}
122+
123+
#if CONFIG_IWDT_RENESAS_RX_IWDT
124+
for (int idx_p = 0; idx_p < 4; idx_p++) {
125+
for (int idx_d = 0; idx_d < 6; idx_d++) {
126+
iwdt_timeout = ((uint32_t)timeout_period[idx_p] * clock_divide[idx_d][1]) /
127+
clock_rate_khz;
128+
error = cfg->window.max - iwdt_timeout;
129+
130+
if (error < 0) {
131+
break;
132+
}
133+
134+
if (error < last_error) {
135+
last_error = error;
136+
iwdt_tops = idx_p;
137+
iwdt_clock_div = clock_divide[idx_d][0];
138+
}
139+
}
140+
}
141+
142+
data->iwdt_config.timeout = iwdt_tops;
143+
data->iwdt_config.iwdtclk_div = iwdt_clock_div;
144+
data->iwdt_config.window_start = IWDT_WINDOW_START;
145+
data->iwdt_config.window_end = IWDT_WINDOW_END;
146+
data->iwdt_config.timeout_control =
147+
(cfg->flags & WDT_FLAG_RESET_MASK) != 0 ? IWDT_TIMEOUT_RESET : IWDT_TIMEOUT_NMI;
148+
data->iwdt_config.count_stop_enable = IWDT_COUNT_STOP_DISABLE;
149+
#endif /* CONFIG_IWDT_RENESAS_RX_IWDT */
150+
151+
data->timeout_installed = true;
152+
153+
#if CONFIG_IWDT_RX_NMI
154+
data->callback = cfg->callback;
155+
#endif
156+
157+
return 0;
158+
}
159+
160+
static int wdt_iwdt_rx_setup(const struct device *dev, uint8_t options)
161+
{
162+
struct wdt_iwdt_rx_data *data = dev->data;
163+
iwdt_err_t err;
164+
int ret;
165+
166+
#if CONFIG_IWDT_RENESAS_RX_IWDT
167+
if (!data->timeout_installed) {
168+
return -EINVAL;
169+
}
170+
#endif /* CONFIG_IWDT_RENESAS_RX_IWDT */
171+
172+
if (options & WDT_OPT_PAUSE_IN_SLEEP) {
173+
data->iwdt_config.count_stop_enable = IWDT_COUNT_STOP_ENABLE;
174+
} else {
175+
data->iwdt_config.count_stop_enable = IWDT_COUNT_STOP_DISABLE;
176+
}
177+
178+
if (options & WDT_OPT_PAUSE_HALTED_BY_DBG) {
179+
return -ENOTSUP;
180+
}
181+
182+
#if CONFIG_IWDT_RX_NMI
183+
nmi_enable(IWDT_NMI_VECTOR, (nmi_callback_t)wdt_iwdt_isr, (void *)dev);
184+
iwdt_enable_nmi();
185+
#endif /* CONFIG_IWDT_RX_NMI */
186+
187+
#if CONFIG_IWDT_RENESAS_RX_IWDT
188+
189+
err = R_IWDT_Open(&data->iwdt_config);
190+
if (err != IWDT_SUCCESS) {
191+
return -EINVAL;
192+
}
193+
194+
ret = wdt_iwdt_rx_feed(dev, 0);
195+
if (ret != 0) {
196+
return ret;
197+
}
198+
#endif /* CONFIG_IWDT_RENESAS_RX_IWDT */
199+
200+
return 0;
201+
}
202+
203+
static DEVICE_API(wdt, wdt_iwdt_rx_api) = {
204+
.disable = wdt_iwdt_rx_disable,
205+
.feed = wdt_iwdt_rx_feed,
206+
.install_timeout = wdt_iwdt_rx_install_timeout,
207+
.setup = wdt_iwdt_rx_setup,
208+
};
209+
210+
#define IWDT_RENESAS_RX_DEFINE(idx) \
211+
static struct wdt_iwdt_rx_config iwdt_rx_cfg##idx = { \
212+
.regs = (struct st_iwdt *)DT_REG_ADDR(IWDT_NODELABEL), \
213+
.clock_dev = DEVICE_DT_GET(DT_CLOCKS_CTLR(idx)), \
214+
}; \
215+
static struct wdt_iwdt_rx_data iwdt_rx_data##idx = { \
216+
.timeout_installed = false, \
217+
.iwdt_config = {.count_stop_enable = IWDT_COUNT_STOP_DISABLE, \
218+
.timeout_control = IWDT_TIMEOUT_RESET}, \
219+
}; \
220+
\
221+
DEVICE_DT_DEFINE(idx, NULL, NULL, &iwdt_rx_data##idx, &iwdt_rx_cfg##idx, POST_KERNEL, \
222+
CONFIG_KERNEL_INIT_PRIORITY_DEVICE, &wdt_iwdt_rx_api);
223+
224+
DT_FOREACH_STATUS_OKAY(renesas_rx_iwdt, IWDT_RENESAS_RX_DEFINE);
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
# Copyright (c) 2025 Renesas Electronics Corporation and/or its affiliates
2+
# SPDX-License-Identifier: Apache-2.0
3+
4+
description: Renesas RX Independent Watchdog
5+
6+
compatible: "renesas,rx-iwdt"
7+
8+
include: base.yaml
9+
10+
properties:
11+
reg:
12+
required: true
13+
14+
clocks:
15+
required: true
16+
17+
window-start:
18+
required: true
19+
type: int
20+
enum: [0, 0x1000, 0x2000, 0x3000]
21+
description: |
22+
The start of the window in clock cycles. The watchdog will reset the system
23+
if the watchdog is not refreshed within the window.
24+
- 0: 25%
25+
- 0x1000: 50%
26+
- 0x2000: 75%
27+
- 0x3000: 100% (window end position is not specified.)
28+
29+
window-end:
30+
required: true
31+
type: int
32+
enum: [0, 0x100, 0x200, 0x300]
33+
description: |
34+
The end of the window in clock cycles. The watchdog will reset the system
35+
if the watchdog is not refreshed within the window.
36+
- 0: 75%
37+
- 0x200: 50%
38+
- 0x200: 25%
39+
- 0x300: 0% (window start position is not specified.)

modules/Kconfig.renesas

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -274,4 +274,9 @@ config USE_RX_RDP_SCI_UART
274274
help
275275
Enable RX RDP SCI UART driver
276276

277+
config USE_RX_RDP_IWDT
278+
bool
279+
help
280+
Enable RX RDP IWDT driver
281+
277282
endif # HAS_RENESAS_RX_RDP

0 commit comments

Comments
 (0)