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