Skip to content

Commit 41bc8ef

Browse files
RuibinChangkartben
authored andcommitted
drivers/watchdog/it51xxx: implement watchdog driver
Implement watchdog driver for ITE it51xxx series chip. Signed-off-by: Ruibin Chang <Ruibin.Chang@ite.com.tw>
1 parent 38a81f1 commit 41bc8ef

File tree

7 files changed

+377
-0
lines changed

7 files changed

+377
-0
lines changed

boards/ite/it515xx_evb/it515xx_evb.dts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616

1717
aliases {
1818
led0 = &led0;
19+
watchdog0 = &twd0;
1920
};
2021

2122
chosen {

drivers/watchdog/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ zephyr_library_sources_ifdef(CONFIG_WDT_CC13XX_CC26XX wdt_cc13xx_cc26xx.c)
1717
zephyr_library_sources_ifdef(CONFIG_WDT_ESP32 wdt_esp32.c)
1818
zephyr_library_sources_ifdef(CONFIG_WDT_XT_ESP32 xt_wdt_esp32.c)
1919
zephyr_library_sources_ifdef(CONFIG_WDT_GECKO wdt_gecko.c)
20+
zephyr_library_sources_ifdef(CONFIG_WDT_ITE_IT51XXX wdt_ite_it51xxx.c)
2021
zephyr_library_sources_ifdef(CONFIG_WDT_ITE_IT8XXX2 wdt_ite_it8xxx2.c)
2122
zephyr_library_sources_ifdef(CONFIG_WDT_LITEX wdt_litex.c)
2223
zephyr_library_sources_ifdef(CONFIG_WDT_MAX32 wdt_max32.c)

drivers/watchdog/Kconfig

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

9898
source "drivers/watchdog/Kconfig.cc13xx_cc26xx"
9999

100+
source "drivers/watchdog/Kconfig.it51xxx"
101+
100102
source "drivers/watchdog/Kconfig.it8xxx2"
101103

102104
source "drivers/watchdog/Kconfig.rpi_pico"

drivers/watchdog/Kconfig.it51xxx

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
# Copyright (c) 2025 ITE Corporation. All Rights Reserved.
2+
# SPDX-License-Identifier: Apache-2.0
3+
4+
config WDT_ITE_IT51XXX
5+
bool "ITE it51xxx Watchdog Timer (WDT) driver"
6+
default y
7+
depends on DT_HAS_ITE_IT51XXX_WATCHDOG_ENABLED
8+
select HAS_WDT_DISABLE_AT_BOOT
9+
help
10+
This option enables the Watchdog Timer driver for ITE it51xxx.
11+
This driver supports only one channel that id is 0 and 16-bits
12+
resolution WDT.
13+
14+
config WDT_ITE_WARNING_LEADING_TIME_MS
15+
int "Number of ms before generating watchdog event/signal"
16+
depends on WDT_ITE_IT51XXX
17+
default 500
18+
help
19+
This option defines the window in which a watchdog event must be
20+
handled. After this time window, the watchdog reset triggers
21+
immediately.
22+
23+
config WDT_ITE_REDUCE_WARNING_LEADING_TIME
24+
bool "Reduce warning leading time"
25+
depends on WDT_ITE_IT51XXX
26+
help
27+
Once warning timer triggered, if watchdog timer isn't reloaded,
28+
then we will reduce interval of warning timer to 30ms to print
29+
more warning messages before watchdog reset.

drivers/watchdog/wdt_ite_it51xxx.c

Lines changed: 322 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,322 @@
1+
/*
2+
* Copyright (c) 2025 ITE Corporation. All Rights Reserved.
3+
* SPDX-License-Identifier: Apache-2.0
4+
*/
5+
6+
#define DT_DRV_COMPAT ite_it51xxx_watchdog
7+
8+
#include <errno.h>
9+
#include <soc.h>
10+
#include <zephyr/drivers/watchdog.h>
11+
#include <zephyr/irq.h>
12+
13+
#include <zephyr/logging/log.h>
14+
#define LOG_LEVEL CONFIG_WDT_LOG_LEVEL
15+
LOG_MODULE_REGISTER(wdt_ite_it51xxx);
16+
17+
#define IT51XXX_WATCHDOG_MAGIC_BYTE 0x5c
18+
#define WARNING_TIMER_PERIOD_MS_TO_1024HZ_COUNT(ms) ((ms) * 1024 / 1000)
19+
20+
/* 0x81: External Timer1/WDT Configuration */
21+
#define REG_ETWCFG 0x01
22+
#define WDT_EWDKEYEN BIT(5)
23+
#define WDT_EWDSRC BIT(4)
24+
#define WDT_LEWDCNTL BIT(3)
25+
#define WDT_LET1CNTL BIT(2)
26+
#define WDT_LET1PS BIT(1)
27+
#define WDT_LETWCFG BIT(0)
28+
/* 0x82: External Timer1 Prescaler */
29+
#define REG_ET1PSR 0x02
30+
#define WDT_ETPS_32P768_KHZ 0x00
31+
#define WDT_ETPS_1P024_KHZ 0x01
32+
#define WDT_ETPS_32_HZ 0x02
33+
/* 0x83: External Timer1 Counter High Byte */
34+
#define REG_ET1CNTLHR 0x03
35+
/* 0x84: External Timer1 Counter Low Byte */
36+
#define REG_ET1CNTLLR 0x04
37+
/* 0x85: External Timer1/WDT Control */
38+
#define REG_ETWCTRL 0x05
39+
#define WDT_EWDSCEN BIT(5)
40+
#define WDT_EWDSCMS BIT(4)
41+
#define WDT_ET1TC BIT(1)
42+
#define WDT_ET1RST BIT(0)
43+
/* 0x86: External WDT Counter Low Byte */
44+
#define REG_EWDCNTLR 0x06
45+
/* 0x87: External WDT Key */
46+
#define REG_EWDKEYR 0x07
47+
/* 0x89: External WDT Counter High Byte */
48+
#define REG_EWDCNTHR 0x09
49+
50+
/* device config */
51+
struct wdt_it51xxx_config {
52+
/* wdt register base address */
53+
uintptr_t base;
54+
};
55+
56+
/* driver data */
57+
struct wdt_it51xxx_data {
58+
/* timeout callback used to handle watchdog event */
59+
wdt_callback_t callback;
60+
/* indicate whether a watchdog timeout is installed */
61+
bool timeout_installed;
62+
/* watchdog feed timeout in milliseconds */
63+
uint32_t timeout;
64+
/* pre-warning timer1 fired times */
65+
int wdt_warning_fired;
66+
};
67+
68+
static int wdt_it51xxx_install_timeout(const struct device *dev,
69+
const struct wdt_timeout_cfg *config)
70+
{
71+
const struct wdt_it51xxx_config *const wdt_config = dev->config;
72+
struct wdt_it51xxx_data *data = dev->data;
73+
const uintptr_t base = wdt_config->base;
74+
75+
/* if watchdog is already running */
76+
if (sys_read8(base + REG_ETWCFG) & WDT_LEWDCNTL) {
77+
return -EBUSY;
78+
}
79+
80+
/*
81+
* Not support lower limit window timeouts (min value must be equal to
82+
* 0). Upper limit window timeouts can't be 0 when we install timeout.
83+
*/
84+
if ((config->window.min != 0) || (config->window.max == 0)) {
85+
data->timeout_installed = false;
86+
return -EINVAL;
87+
}
88+
89+
/* save watchdog timeout */
90+
data->timeout = config->window.max;
91+
92+
/* install user timeout isr */
93+
data->callback = config->callback;
94+
95+
/* mark installed */
96+
data->timeout_installed = true;
97+
98+
return 0;
99+
}
100+
101+
static int wdt_it51xxx_setup(const struct device *dev, uint8_t options)
102+
{
103+
const struct wdt_it51xxx_config *const wdt_config = dev->config;
104+
struct wdt_it51xxx_data *data = dev->data;
105+
const uintptr_t base = wdt_config->base;
106+
uint16_t cnt0 = WARNING_TIMER_PERIOD_MS_TO_1024HZ_COUNT(data->timeout);
107+
uint16_t cnt1 = WARNING_TIMER_PERIOD_MS_TO_1024HZ_COUNT(
108+
(data->timeout + CONFIG_WDT_ITE_WARNING_LEADING_TIME_MS));
109+
uint8_t reg_val;
110+
111+
/* disable pre-warning timer1 interrupt */
112+
irq_disable(DT_INST_IRQN(0));
113+
114+
if (!data->timeout_installed) {
115+
LOG_ERR("No valid WDT timeout installed");
116+
return -EINVAL;
117+
}
118+
119+
if (sys_read8(base + REG_ETWCFG) & WDT_LEWDCNTL) {
120+
LOG_ERR("WDT is already running");
121+
return -EBUSY;
122+
}
123+
124+
if ((options & WDT_OPT_PAUSE_IN_SLEEP) != 0) {
125+
LOG_ERR("WDT_OPT_PAUSE_IN_SLEEP is not supported");
126+
return -ENOTSUP;
127+
}
128+
129+
/* pre-warning timer1 is 16-bit counter down timer */
130+
sys_write8((cnt0 >> 8) & 0xff, base + REG_ET1CNTLHR);
131+
sys_write8(cnt0 & 0xff, base + REG_ET1CNTLLR);
132+
133+
/* clear pre-warning timer1 interrupt status */
134+
ite_intc_isr_clear(DT_INST_IRQN(0));
135+
136+
/* enable pre-warning timer1 interrupt */
137+
irq_enable(DT_INST_IRQN(0));
138+
139+
/* don't stop watchdog timer counting */
140+
reg_val = sys_read8(base + REG_ETWCTRL);
141+
sys_write8(reg_val & ~WDT_EWDSCEN, base + REG_ETWCTRL);
142+
143+
/* set watchdog timer count */
144+
sys_write8((cnt1 >> 8) & 0xff, base + REG_EWDCNTHR);
145+
sys_write8(cnt1 & 0xff, base + REG_EWDCNTLR);
146+
147+
/* allow to write timer1 count register */
148+
reg_val = sys_read8(base + REG_ETWCFG);
149+
sys_write8(reg_val & ~WDT_LET1CNTL, base + REG_ETWCFG);
150+
151+
/*
152+
* bit5 = 1: enable key match function to touch watchdog
153+
* bit4 = 1: select watchdog clock source from prescaler
154+
* bit3 = 1: lock watchdog count register (also mark as watchdog running)
155+
* bit1 = 1: lock timer1 prescaler register
156+
*/
157+
sys_write8((WDT_EWDKEYEN | WDT_EWDSRC | WDT_LEWDCNTL | WDT_LET1PS), base + REG_ETWCFG);
158+
159+
LOG_DBG("WDT Setup and enabled");
160+
161+
return 0;
162+
}
163+
164+
/*
165+
* reload the WDT and pre-warning timer1 counter
166+
*
167+
* @param dev Pointer to the device structure for the driver instance.
168+
* @param channel_id Index of the fed channel, and we only support
169+
* channel_id = 0 now.
170+
*/
171+
static int wdt_it51xxx_feed(const struct device *dev, int channel_id)
172+
{
173+
const struct wdt_it51xxx_config *const wdt_config = dev->config;
174+
struct wdt_it51xxx_data *data = dev->data;
175+
const uintptr_t base = wdt_config->base;
176+
uint16_t cnt0 = WARNING_TIMER_PERIOD_MS_TO_1024HZ_COUNT(data->timeout);
177+
uint8_t reg_val;
178+
179+
ARG_UNUSED(channel_id);
180+
181+
/* reset pre-warning timer1 */
182+
reg_val = sys_read8(base + REG_ETWCTRL);
183+
sys_write8(reg_val | WDT_ET1RST, base + REG_ETWCTRL);
184+
185+
/* restart watchdog timer */
186+
sys_write8(IT51XXX_WATCHDOG_MAGIC_BYTE, base + REG_EWDKEYR);
187+
188+
/* reset pre-warning timer1 to default if time is touched */
189+
if (data->wdt_warning_fired) {
190+
data->wdt_warning_fired = 0;
191+
192+
/* pre-warning timer1 is 16-bit counter down timer */
193+
sys_write8((cnt0 >> 8) & 0xff, base + REG_ET1CNTLHR);
194+
sys_write8(cnt0 & 0xff, base + REG_ET1CNTLLR);
195+
196+
/* clear timer1 interrupt status */
197+
ite_intc_isr_clear(DT_INST_IRQN(0));
198+
199+
/* enable timer1 interrupt */
200+
irq_enable(DT_INST_IRQN(0));
201+
}
202+
203+
LOG_DBG("WDT Kicking");
204+
205+
return 0;
206+
}
207+
208+
static int wdt_it51xxx_disable(const struct device *dev)
209+
{
210+
const struct wdt_it51xxx_config *const wdt_config = dev->config;
211+
struct wdt_it51xxx_data *data = dev->data;
212+
const uintptr_t base = wdt_config->base;
213+
uint8_t reg_val;
214+
215+
/* stop watchdog timer counting */
216+
reg_val = sys_read8(base + REG_ETWCTRL);
217+
sys_write8(reg_val | WDT_EWDSCEN, base + REG_ETWCTRL);
218+
219+
/* unlock watchdog count register (also mark as watchdog not running) */
220+
reg_val = sys_read8(base + REG_ETWCFG);
221+
sys_write8(reg_val & ~WDT_LEWDCNTL, base + REG_ETWCFG);
222+
223+
/* disable pre-warning timer1 interrupt */
224+
irq_disable(DT_INST_IRQN(0));
225+
226+
/* mark uninstalled */
227+
data->timeout_installed = false;
228+
229+
LOG_DBG("WDT Disabled");
230+
231+
return 0;
232+
}
233+
234+
static void wdt_it51xxx_isr(const struct device *dev)
235+
{
236+
const struct wdt_it51xxx_config *const wdt_config = dev->config;
237+
struct wdt_it51xxx_data *data = dev->data;
238+
const uintptr_t base = wdt_config->base;
239+
uint8_t reg_val;
240+
241+
/* clear pre-warning timer1 interrupt status */
242+
ite_intc_isr_clear(DT_INST_IRQN(0));
243+
244+
/* reset pre-warning timer1 */
245+
reg_val = sys_read8(base + REG_ETWCTRL);
246+
sys_write8(reg_val | WDT_ET1RST, base + REG_ETWCTRL);
247+
248+
/* callback function, ex. print warning message */
249+
if (data->callback) {
250+
data->callback(dev, 0);
251+
}
252+
253+
if (IS_ENABLED(CONFIG_WDT_ITE_REDUCE_WARNING_LEADING_TIME)) {
254+
/*
255+
* Once warning timer triggered: if watchdog timer isn't reloaded,
256+
* then we will reduce interval of warning timer to 30ms to print
257+
* more warning messages before watchdog reset.
258+
*/
259+
if (!(data->wdt_warning_fired)) {
260+
uint16_t cnt0 = WARNING_TIMER_PERIOD_MS_TO_1024HZ_COUNT(30);
261+
262+
/* pre-warning timer1 is 16-bit counter down timer */
263+
sys_write8((cnt0 >> 8) & 0xff, base + REG_ET1CNTLHR);
264+
sys_write8(cnt0 & 0xff, base + REG_ET1CNTLLR);
265+
266+
/* clear pre-warning timer1 interrupt status */
267+
ite_intc_isr_clear(DT_INST_IRQN(0));
268+
}
269+
}
270+
data->wdt_warning_fired++;
271+
272+
LOG_DBG("WDT ISR");
273+
}
274+
275+
static DEVICE_API(wdt, wdt_it51xxx_api) = {
276+
.setup = wdt_it51xxx_setup,
277+
.disable = wdt_it51xxx_disable,
278+
.install_timeout = wdt_it51xxx_install_timeout,
279+
.feed = wdt_it51xxx_feed,
280+
};
281+
282+
static int wdt_it51xxx_init(const struct device *dev)
283+
{
284+
const struct wdt_it51xxx_config *const wdt_config = dev->config;
285+
const uintptr_t base = wdt_config->base;
286+
uint8_t reg_val;
287+
288+
if (IS_ENABLED(CONFIG_WDT_DISABLE_AT_BOOT)) {
289+
wdt_it51xxx_disable(dev);
290+
}
291+
292+
/* unlock access to watchdog registers */
293+
sys_write8(0x00, base + REG_ETWCFG);
294+
295+
/* set WDT and timer1 to use 1.024kHz clock */
296+
sys_write8(WDT_ETPS_1P024_KHZ, base + REG_ET1PSR);
297+
298+
/* set WDT key match enabled and WDT clock to use ET1PSR */
299+
sys_write8(WDT_EWDKEYEN | WDT_EWDSRC, base + REG_ETWCFG);
300+
301+
/*
302+
* select the mode that watchdog can be stopped, this is needed for
303+
* wdt_it51xxx_disable() api and WDT_OPT_PAUSE_HALTED_BY_DBG flag
304+
*/
305+
reg_val = sys_read8(base + REG_ETWCTRL);
306+
sys_write8(reg_val | WDT_EWDSCMS, base + REG_ETWCTRL);
307+
308+
IRQ_CONNECT(DT_INST_IRQN(0), 0, wdt_it51xxx_isr, DEVICE_DT_INST_GET(0), 0);
309+
return 0;
310+
}
311+
312+
static const struct wdt_it51xxx_config wdt_it51xxx_cfg_0 = {
313+
.base = DT_INST_REG_ADDR(0),
314+
};
315+
316+
static struct wdt_it51xxx_data wdt_it51xxx_dev_data;
317+
318+
DEVICE_DT_INST_DEFINE(0, wdt_it51xxx_init, NULL, &wdt_it51xxx_dev_data, &wdt_it51xxx_cfg_0,
319+
PRE_KERNEL_1, CONFIG_KERNEL_INIT_PRIORITY_DEFAULT, &wdt_it51xxx_api);
320+
321+
BUILD_ASSERT(DT_NUM_INST_STATUS_OKAY(DT_DRV_COMPAT) == 1,
322+
"only one ite,it51xxx-watchdog compatible node can be supported");
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
# Copyright (c) 2025 ITE Corporation. All Rights Reserved.
2+
# SPDX-License-Identifier: Apache-2.0
3+
4+
description: ITE watchdog timer
5+
6+
include: base.yaml
7+
8+
compatible: "ite,it51xxx-watchdog"
9+
10+
properties:
11+
reg:
12+
required: true
13+
14+
interrupts:
15+
required: true

0 commit comments

Comments
 (0)