1 /*
2 * Copyright (c) 2021 - 2022 HPMicro
3 *
4 * SPDX-License-Identifier: BSD-3-Clause
5 *
6 */
7
8 #include <rthw.h>
9 #include <rtdevice.h>
10 #include <rtdbg.h>
11 #include "board.h"
12 #include "drv_wdt.h"
13 #include "hpm_wdg_drv.h"
14 #include "hpm_sysctl_drv.h"
15
16
17
18 #ifdef BSP_USING_WDG
19
20
21 typedef struct hpm_wdog
22 {
23 WDG_Type *wdog_base;
24 char *device_name;
25 clock_name_t clock_name;
26 uint32_t irq_num;
27 rt_watchdog_t *wdog;
28 }hpm_wdog_t;
29
30 static rt_err_t hpm_wdog_init(rt_watchdog_t *wdt);
31 static rt_err_t hpm_wdog_open(rt_watchdog_t *wdt, rt_uint16_t oflag);
32 static rt_err_t hpm_wdog_close(rt_watchdog_t *wdt);
33 static rt_err_t hpm_wdog_refresh(rt_watchdog_t *wdt);
34 static rt_err_t hpm_wdog_control(rt_watchdog_t *wdt, int cmd, void *args);
35
36 static void hpm_wdog_isr(rt_watchdog_t *wdt);
37
38 static wdg_control_t wdog_ctrl = {
39 .reset_interval = reset_interval_clock_period_mult_16k,
40 .interrupt_interval = interrupt_interval_clock_period_multi_8k,
41 .reset_enable = true,
42 .interrupt_enable = false,
43 .clksrc = wdg_clksrc_extclk,
44 .wdg_enable = false,
45 };
46
47 #if defined(BSP_USING_WDG0)
48 rt_watchdog_t wdog0;
wdog0_isr(void)49 void wdog0_isr(void)
50 {
51 hpm_wdog_isr(&wdog0);
52 }
SDK_DECLARE_EXT_ISR_M(IRQn_WDG0,wdog0_isr)53 SDK_DECLARE_EXT_ISR_M(IRQn_WDG0, wdog0_isr)
54 #endif
55
56 #if defined(BSP_USING_WDG1)
57 rt_watchdog_t wdog1;
58 void wdog1_isr(void)
59 {
60 hpm_wdog_isr(&wdog1);
61 }
SDK_DECLARE_EXT_ISR_M(IRQn_WDG1,wdog1_isr)62 SDK_DECLARE_EXT_ISR_M(IRQn_WDG1, wdog1_isr)
63 #endif
64
65 #if defined(BSP_USING_WDG2)
66 rt_watchdog_t wdog2;
67 void wdog2_isr(void)
68 {
69 hpm_wdog_isr(&wdog2);
70 }
SDK_DECLARE_EXT_ISR_M(IRQn_WDG2,wdog2_isr)71 SDK_DECLARE_EXT_ISR_M(IRQn_WDG2, wdog2_isr)
72 #endif
73
74 #if defined(BSP_USING_WDG3)
75 rt_watchdog_t wdog3;
76 void wdog3_isr(void)
77 {
78 hpm_wdog_isr(&wdog3);
79 }
80 SDK_DECLARE_EXT_ISR_M(IRQn_WDG3, wdog3_isr)
81 #endif
82
83 static hpm_wdog_t wdogs[] = {
84 #ifdef BSP_USING_WDG0
85 {
86 .wdog_base = HPM_WDG0,
87 .device_name = "wdt0",
88 .clock_name = clock_watchdog0,
89 .irq_num = IRQn_WDG0,
90 .wdog = &wdog0,
91 },
92 #endif
93
94 #ifdef BSP_USING_WDG1
95 {
96 .wdog_base = HPM_WDG1,
97 .device_name = "wdt1",
98 .clock_name = clock_watchdog1,
99 .irq_num = IRQn_WDG1,
100 .wdog = &wdog1,
101 },
102 #endif
103
104 #ifdef BSP_USING_WDG2
105 {
106 .wdog_base = HPM_WDG2,
107 .device_name = "wdt2",
108 .clock_name = clock_watchdog2,
109 .irq_num = IRQn_WDG2,
110 .wdog = &wdog2,
111 },
112 #endif
113
114 #ifdef BSP_USING_WDG3
115 {
116 .wdog_name = HPM_WDG3,
117 .device_name = "wdt3",
118 .clock_name = clock_watchdog3,
119 .irq_num = IRQn_WDG3,
120 .wdog = &wdog3,
121 },
122 #endif
123 };
124
125 static struct rt_watchdog_ops hpm_wdog_ops = {
126 .init = hpm_wdog_init,
127 .control = hpm_wdog_control,
128 };
129
hpm_wdog_init(rt_watchdog_t * wdt)130 static rt_err_t hpm_wdog_init(rt_watchdog_t *wdt)
131 {
132 hpm_wdog_t *hpm_wdog = (hpm_wdog_t*)wdt->parent.user_data;
133 WDG_Type *base = hpm_wdog->wdog_base;
134
135 wdg_init(base, &wdog_ctrl);
136
137 return RT_EOK;
138 }
139
hpm_wdog_open(rt_watchdog_t * wdt,rt_uint16_t oflag)140 static rt_err_t hpm_wdog_open(rt_watchdog_t *wdt, rt_uint16_t oflag)
141 {
142 hpm_wdog_t *hpm_wdog = (hpm_wdog_t*)wdt->parent.user_data;
143 WDG_Type *base = hpm_wdog->wdog_base;
144
145 rt_enter_critical();
146 wdg_enable(base);
147 rt_exit_critical();
148 }
149
hpm_wdog_close(rt_watchdog_t * wdt)150 static rt_err_t hpm_wdog_close(rt_watchdog_t *wdt)
151 {
152 hpm_wdog_t *hpm_wdog = (hpm_wdog_t*)wdt->parent.user_data;
153 WDG_Type *base = hpm_wdog->wdog_base;
154
155 rt_enter_critical();
156 wdg_disable(base);
157 rt_exit_critical();
158
159 return RT_EOK;
160 }
161
hpm_wdog_refresh(rt_watchdog_t * wdt)162 static rt_err_t hpm_wdog_refresh(rt_watchdog_t *wdt)
163 {
164 hpm_wdog_t *hpm_wdog = (hpm_wdog_t*)wdt->parent.user_data;
165 WDG_Type *base = hpm_wdog->wdog_base;
166
167 rt_enter_critical();
168 wdg_restart(base);
169 rt_exit_critical();
170
171 return RT_EOK;
172 }
173
hpm_wdog_control(rt_watchdog_t * wdt,int cmd,void * args)174 static rt_err_t hpm_wdog_control(rt_watchdog_t *wdt, int cmd, void *args)
175 {
176 rt_err_t ret = RT_EOK;
177
178 hpm_wdog_t *hpm_wdog = (hpm_wdog_t*)wdt->parent.user_data;
179 WDG_Type *base = hpm_wdog->wdog_base;
180
181 uint32_t temp;
182 switch (cmd)
183 {
184 case RT_DEVICE_CTRL_WDT_GET_TIMEOUT:
185 temp = wdg_get_total_reset_interval_in_us(base, WDG_EXT_CLK_FREQ);
186 temp /= 1000000UL; /* Convert to seconds */
187 *(uint32_t *)args = temp;
188 break;
189 case RT_DEVICE_CTRL_WDT_SET_TIMEOUT:
190 RT_ASSERT(*(uint32_t *)args != 0);
191 temp = *(uint32_t *)args;
192 temp *= 1000000U; /* Convert to microseconds */
193 wdog_ctrl.interrupt_interval = wdg_convert_interrupt_interval_from_us(WDG_EXT_CLK_FREQ, temp);
194 wdog_ctrl.reset_interval = reset_interval_clock_period_mult_128;
195 wdog_ctrl.reset_enable = true;
196 wdog_ctrl.interrupt_enable = true;
197 wdog_ctrl.clksrc = wdg_clksrc_extclk;
198 wdog_ctrl.wdg_enable = false;
199 hpm_wdog_init(wdt);
200 break;
201 case RT_DEVICE_CTRL_WDT_KEEPALIVE:
202 hpm_wdog_refresh(wdt);
203 break;
204 case RT_DEVICE_CTRL_WDT_START:
205 hpm_wdog_open(wdt, *(uint16_t*)args);
206 break;
207 case RT_DEVICE_CTRL_WDT_STOP:
208 hpm_wdog_close(wdt);
209 break;
210 default:
211 ret = RT_EINVAL;
212 break;
213 }
214
215 return RT_EOK;
216 }
217
hpm_wdog_isr(rt_watchdog_t * wdt)218 void hpm_wdog_isr(rt_watchdog_t *wdt)
219 {
220 hpm_wdog_t *hpm_wdog = (hpm_wdog_t*)wdt->parent.user_data;
221 WDG_Type *base = hpm_wdog->wdog_base;
222
223 uint32_t status = wdg_get_status(base);
224
225 if (IS_HPM_BITMASK_SET(status, WDG_ST_INTEXPIRED_MASK)) {
226 wdg_clear_status(base, WDG_ST_INTEXPIRED_MASK);
227 }
228 }
229
rt_hw_wdt_init(void)230 int rt_hw_wdt_init(void)
231 {
232 rt_err_t err = RT_EOK;
233
234 #if defined(BSP_USING_WDG)
235 for (uint32_t i = 0; i < sizeof(wdogs) / sizeof(wdogs[0]); i++)
236 {
237 wdogs[i].wdog->ops = &hpm_wdog_ops;
238 clock_add_to_group(wdogs[i].clock_name, 0);
239 err = rt_hw_watchdog_register(wdogs[i].wdog, wdogs[i].device_name, RT_DEVICE_FLAG_RDWR, (void *)&wdogs[i]);
240 if (err != RT_EOK)
241 {
242 LOG_E("rt device %s failed, status=%d\n", wdogs[i].device_name, err);
243 }
244 }
245 #endif
246 return err;
247 }
248
249 INIT_BOARD_EXPORT(rt_hw_wdt_init);
250 #endif /* RT_USING_WDT */