1 /*
2  * Copyright (c) 2015 Intel Corporation
3  * Copyright (c) 2018 Nordic Semiconductor
4  * Copyright (c) 2019 Centaur Analytics, Inc
5  * Copyright 2023 NXP
6  *
7  * SPDX-License-Identifier: Apache-2.0
8  */
9 
10 #include <zephyr/kernel.h>
11 #include <zephyr/device.h>
12 #include <zephyr/drivers/watchdog.h>
13 #include <zephyr/sys/printk.h>
14 #include <stdbool.h>
15 
16 #define WDT_FEED_TRIES 5
17 
18 /*
19  * To use this sample the devicetree's /aliases must have a 'watchdog0' property.
20  */
21 #if DT_HAS_COMPAT_STATUS_OKAY(st_stm32_window_watchdog)
22 #define WDT_MAX_WINDOW  100U
23 #elif DT_HAS_COMPAT_STATUS_OKAY(nordic_nrf_wdt)
24 /* Nordic supports a callback, but it has 61.2 us to complete before
25  * the reset occurs, which is too short for this sample to do anything
26  * useful.  Explicitly disallow use of the callback.
27  */
28 #define WDT_ALLOW_CALLBACK 0
29 #elif DT_HAS_COMPAT_STATUS_OKAY(raspberrypi_pico_watchdog)
30 #define WDT_ALLOW_CALLBACK 0
31 #elif DT_HAS_COMPAT_STATUS_OKAY(gd_gd32_wwdgt)
32 #define WDT_MAX_WINDOW 24U
33 #define WDT_MIN_WINDOW 18U
34 #define WDG_FEED_INTERVAL 12U
35 #elif DT_HAS_COMPAT_STATUS_OKAY(intel_tco_wdt)
36 #define WDT_ALLOW_CALLBACK 0
37 #define WDT_MAX_WINDOW 3000U
38 #elif DT_HAS_COMPAT_STATUS_OKAY(nxp_fs26_wdog)
39 #define WDT_MAX_WINDOW  1024U
40 #define WDT_MIN_WINDOW	320U
41 #define WDT_OPT 0
42 #define WDG_FEED_INTERVAL (WDT_MIN_WINDOW + ((WDT_MAX_WINDOW - WDT_MIN_WINDOW) / 4))
43 #endif
44 
45 #ifndef WDT_ALLOW_CALLBACK
46 #define WDT_ALLOW_CALLBACK 1
47 #endif
48 
49 #ifndef WDT_MAX_WINDOW
50 #define WDT_MAX_WINDOW  1000U
51 #endif
52 
53 #ifndef WDT_MIN_WINDOW
54 #define WDT_MIN_WINDOW  0U
55 #endif
56 
57 #ifndef WDG_FEED_INTERVAL
58 #define WDG_FEED_INTERVAL 50U
59 #endif
60 
61 #ifndef WDT_OPT
62 #define WDT_OPT WDT_OPT_PAUSE_HALTED_BY_DBG
63 #endif
64 
65 #if WDT_ALLOW_CALLBACK
wdt_callback(const struct device * wdt_dev,int channel_id)66 static void wdt_callback(const struct device *wdt_dev, int channel_id)
67 {
68 	static bool handled_event;
69 
70 	if (handled_event) {
71 		return;
72 	}
73 
74 	wdt_feed(wdt_dev, channel_id);
75 
76 	printk("Handled things..ready to reset\n");
77 	handled_event = true;
78 }
79 #endif /* WDT_ALLOW_CALLBACK */
80 
main(void)81 int main(void)
82 {
83 	int err;
84 	int wdt_channel_id;
85 	const struct device *const wdt = DEVICE_DT_GET(DT_ALIAS(watchdog0));
86 
87 	printk("Watchdog sample application\n");
88 
89 	if (!device_is_ready(wdt)) {
90 		printk("%s: device not ready.\n", wdt->name);
91 		return 0;
92 	}
93 
94 	struct wdt_timeout_cfg wdt_config = {
95 		/* Reset SoC when watchdog timer expires. */
96 		.flags = WDT_FLAG_RESET_SOC,
97 
98 		/* Expire watchdog after max window */
99 		.window.min = WDT_MIN_WINDOW,
100 		.window.max = WDT_MAX_WINDOW,
101 	};
102 
103 #if WDT_ALLOW_CALLBACK
104 	/* Set up watchdog callback. */
105 	wdt_config.callback = wdt_callback;
106 
107 	printk("Attempting to test pre-reset callback\n");
108 #else /* WDT_ALLOW_CALLBACK */
109 	printk("Callback in RESET_SOC disabled for this platform\n");
110 #endif /* WDT_ALLOW_CALLBACK */
111 
112 	wdt_channel_id = wdt_install_timeout(wdt, &wdt_config);
113 	if (wdt_channel_id == -ENOTSUP) {
114 		/* IWDG driver for STM32 doesn't support callback */
115 		printk("Callback support rejected, continuing anyway\n");
116 		wdt_config.callback = NULL;
117 		wdt_channel_id = wdt_install_timeout(wdt, &wdt_config);
118 	}
119 	if (wdt_channel_id < 0) {
120 		printk("Watchdog install error\n");
121 		return 0;
122 	}
123 
124 	err = wdt_setup(wdt, WDT_OPT);
125 	if (err < 0) {
126 		printk("Watchdog setup error\n");
127 		return 0;
128 	}
129 
130 #if WDT_MIN_WINDOW != 0
131 	/* Wait opening window. */
132 	k_msleep(WDT_MIN_WINDOW);
133 #endif
134 	/* Feeding watchdog. */
135 	printk("Feeding watchdog %d times\n", WDT_FEED_TRIES);
136 	for (int i = 0; i < WDT_FEED_TRIES; ++i) {
137 		printk("Feeding watchdog...\n");
138 		wdt_feed(wdt, wdt_channel_id);
139 		k_sleep(K_MSEC(WDG_FEED_INTERVAL));
140 	}
141 
142 	/* Waiting for the SoC reset. */
143 	printk("Waiting for reset...\n");
144 	while (1) {
145 		k_yield();
146 	}
147 	return 0;
148 }
149