1 /*
2  * Copyright (c) 2022 Renesas Electronics Corporation and/or its affiliates
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 #include <soc.h>
8 #include <zephyr/arch/arm/nmi.h>
9 #include <zephyr/kernel.h>
10 #include <zephyr/drivers/watchdog.h>
11 #include <zephyr/logging/log.h>
12 
13 LOG_MODULE_REGISTER(wdog_smartbond, CONFIG_WDT_LOG_LEVEL);
14 
15 #define DT_DRV_COMPAT renesas_smartbond_watchdog
16 
17 /* driver data */
18 struct wdog_smartbond_data {
19 	/* Reload value calculated in setup */
20 	uint32_t reload_val;
21 #ifdef CONFIG_WDT_SMARTBOND_NMI
22 	const struct device *wdog_device;
23 	wdt_callback_t callback;
24 #endif
25 };
26 
27 static struct wdog_smartbond_data wdog_smartbond_dev_data = {};
28 
wdg_smartbond_setup(const struct device * dev,uint8_t options)29 static int wdg_smartbond_setup(const struct device *dev, uint8_t options)
30 {
31 	ARG_UNUSED(dev);
32 
33 	if (options & WDT_OPT_PAUSE_IN_SLEEP) {
34 		LOG_ERR("Watchdog pause in sleep is not supported");
35 		return -ENOTSUP;
36 	}
37 	return 0;
38 }
39 
wdg_smartbond_disable(const struct device * dev)40 static int wdg_smartbond_disable(const struct device *dev)
41 {
42 	ARG_UNUSED(dev);
43 
44 	if (SYS_WDOG->WATCHDOG_CTRL_REG & SYS_WDOG_WATCHDOG_CTRL_REG_NMI_RST_Msk) {
45 		/* watchdog cannot be stopped once started when NMI_RST is 1 */
46 		return -EPERM;
47 	}
48 
49 	GPREG->SET_FREEZE_REG = GPREG_SET_FREEZE_REG_FRZ_SYS_WDOG_Msk;
50 	return 0;
51 }
52 
53 #ifdef CONFIG_WDT_SMARTBOND_NMI
wdog_smartbond_nmi_isr(void)54 static void wdog_smartbond_nmi_isr(void)
55 {
56 	if (wdog_smartbond_dev_data.callback) {
57 		wdog_smartbond_dev_data.callback(wdog_smartbond_dev_data.wdog_device, 0);
58 	}
59 }
60 #endif /* CONFIG_RUNTIME_NMI */
61 
wdg_smartbond_install_timeout(const struct device * dev,const struct wdt_timeout_cfg * config)62 static int wdg_smartbond_install_timeout(const struct device *dev,
63 					 const struct wdt_timeout_cfg *config)
64 {
65 	struct wdog_smartbond_data *data = (struct wdog_smartbond_data *)(dev)->data;
66 	uint32_t reload_val;
67 
68 #ifndef CONFIG_WDT_SMARTBOND_NMI
69 	if (config->callback != NULL) {
70 		return -ENOTSUP;
71 	}
72 #endif
73 	/* For RC32K timer ticks every ~10ms, for RCX ~21ms */
74 	if (CRG_TOP->CLK_RCX_REG & CRG_TOP_CLK_RCX_REG_RCX_ENABLE_Msk) {
75 		reload_val = config->window.max / 21;
76 	} else {
77 		reload_val = config->window.max / 10;
78 	}
79 
80 	if (reload_val < 1 || reload_val >= 0x2000 || config->window.min != 0) {
81 		/* Out of range supported by watchdog */
82 		LOG_ERR("Watchdog timeout out of range");
83 		return -EINVAL;
84 	}
85 #if CONFIG_WDT_SMARTBOND_NMI
86 	data->callback = config->callback;
87 	data->wdog_device = dev;
88 	z_arm_nmi_set_handler(wdog_smartbond_nmi_isr);
89 	SYS_WDOG->WATCHDOG_CTRL_REG = 2;
90 #else
91 	SYS_WDOG->WATCHDOG_CTRL_REG = 2 | SYS_WDOG_WATCHDOG_CTRL_REG_NMI_RST_Msk;
92 #endif
93 
94 	data->reload_val = reload_val;
95 	while (SYS_WDOG->WATCHDOG_CTRL_REG & SYS_WDOG_WATCHDOG_CTRL_REG_WRITE_BUSY_Msk) {
96 		/* wait */
97 	}
98 	SYS_WDOG->WATCHDOG_REG = reload_val;
99 
100 	return 0;
101 }
102 
wdg_smartbond_feed(const struct device * dev,int channel_id)103 static int wdg_smartbond_feed(const struct device *dev, int channel_id)
104 {
105 	struct wdog_smartbond_data *data = (struct wdog_smartbond_data *)(dev)->data;
106 
107 	ARG_UNUSED(channel_id);
108 
109 	while (SYS_WDOG->WATCHDOG_CTRL_REG & SYS_WDOG_WATCHDOG_CTRL_REG_WRITE_BUSY_Msk) {
110 		/* wait */
111 	}
112 	SYS_WDOG->WATCHDOG_REG = data->reload_val;
113 
114 	return 0;
115 }
116 
117 static DEVICE_API(wdt, wdg_smartbond_api) = {
118 	.setup = wdg_smartbond_setup,
119 	.disable = wdg_smartbond_disable,
120 	.install_timeout = wdg_smartbond_install_timeout,
121 	.feed = wdg_smartbond_feed,
122 };
123 
wdg_smartbond_init(const struct device * dev)124 static int wdg_smartbond_init(const struct device *dev)
125 {
126 	ARG_UNUSED(dev);
127 
128 #ifdef CONFIG_WDT_DISABLE_AT_BOOT
129 	GPREG->SET_FREEZE_REG = GPREG_SET_FREEZE_REG_FRZ_SYS_WDOG_Msk;
130 #endif
131 
132 	return 0;
133 }
134 
135 DEVICE_DT_INST_DEFINE(0, wdg_smartbond_init, NULL, &wdog_smartbond_dev_data, NULL, POST_KERNEL,
136 		      CONFIG_KERNEL_INIT_PRIORITY_DEVICE, &wdg_smartbond_api);
137