1 /*
2  * Copyright (c) 2006-2022, RT-Thread Development Team
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  *
6  * Change Logs:
7  * Date           Author       Notes
8  * 2019-05-06     sundm75       first version
9  */
10 
11 #include <rtthread.h>
12 #include <rtdevice.h>
13 
14 #ifdef  RT_USING_WDT
15 
16 #include "drivers/dev_watchdog.h"
17 #include "drv_wdt.h"
18 
19 #include "ls1c_wdog.h"
20 #include "ls1c_clock.h"
21 
22 typedef enum
23 {
24     RESTENABLE      = 0x0,
25     INTERRUPTENABLE = 0x1,
26 }wdt_enable_mode;
27 
28 static rt_uint32_t heartbeat = 0;
29 
wdt_stop(void)30 static rt_err_t wdt_stop(void)
31 {
32     rt_err_t ret = RT_EOK;
33 
34     Wdog_Reset();
35     ret = (rt_err_t) Wdog_Disable();
36     if (ret != RT_EOK)
37     {
38         rt_kprintf("Wdog_Disable error!\n");
39         return -RT_ERROR;
40     }
41     return ret;
42 }
43 
wdt_start(int mode)44 static rt_err_t wdt_start(int mode)
45 {
46     rt_err_t ret = RT_EOK;
47     wdt_enable_mode wdt_mode = RESTENABLE;
48 
49     ret = (rt_err_t) Wdog_Disable();
50     if (ret != RT_EOK)
51     {
52         rt_kprintf("Wdog_Disable error!\n");
53         return -RT_ERROR;
54     }
55 
56     if((mode == RESTENABLE) || (mode == INTERRUPTENABLE))
57     {
58         wdt_mode = mode;
59     }
60     Wdog_Enable();
61     Wdog_Set();
62     if (ret != RT_EOK)
63     {
64         rt_kprintf("Wdog_Enable error!\n");
65         return -RT_ERROR;
66     }
67 
68     return ret;
69 }
70 
wdt_keepalive(void)71 static rt_err_t wdt_keepalive(void)
72 {
73     rt_err_t ret = RT_EOK;
74     rt_uint32_t index = 0;
75 
76     index = heartbeat * clk_get_apb_rate();
77     ret = (rt_err_t) Wdog_LoadValue(index);
78     Wdog_Set();
79     if (ret != 0)
80     {
81         rt_kprintf("LS1C_Wdog_ClrTimeout error!\n");
82         return -RT_ERROR;
83     }
84 
85     return ret;
86 }
87 
wdt_get_timeleft(void)88 static rt_uint32_t wdt_get_timeleft(void)
89 {
90     rt_uint32_t  cnt = 0;
91     rt_uint32_t second  = 0;
92 
93     cnt =  (rt_uint32_t) Wdog_GetValue();
94     second = cnt/clk_get_apb_rate();
95 
96     return second;
97 }
98 
wdt_set_timeout(rt_uint32_t second)99 static rt_err_t wdt_set_timeout(rt_uint32_t second)
100 {
101     rt_err_t ret = RT_EOK;
102     rt_uint32_t index = 0;
103 
104     index = second * clk_get_apb_rate();
105     ret = (rt_err_t) Wdog_LoadValue(index);
106     if (ret != RT_EOK)
107     {
108         rt_kprintf("Wdog_LoadValue error!\n");
109         return -RT_ERROR;
110     }
111     return ret;
112 }
113 
watchdog_init(rt_watchdog_t * wdt)114 static rt_err_t watchdog_init(rt_watchdog_t *wdt)
115 {
116     struct wdt_driver *wdt_drv = wdt->parent.user_data;
117     if (wdt_drv->in_use) return -RT_EBUSY;
118 
119     Wdog_Init();
120 
121     return RT_EOK;
122 }
123 
watchdog_ctrl(rt_watchdog_t * wdt,int cmd,void * arg)124 static rt_err_t watchdog_ctrl(rt_watchdog_t *wdt, int cmd, void *arg)
125 {
126     rt_uint32_t val;
127     int mode;
128 
129     switch (cmd)
130     {
131         case RT_DEVICE_CTRL_WDT_START:
132             mode = *((int *)(arg));
133             wdt_start(mode);
134             break;
135 
136         case RT_DEVICE_CTRL_WDT_STOP:
137             Wdog_Disable();
138             break;
139 
140         case RT_DEVICE_CTRL_WDT_KEEPALIVE:
141             wdt_keepalive();
142             break;
143 
144         case RT_DEVICE_CTRL_WDT_SET_TIMEOUT:
145             heartbeat = *((rt_uint32_t *)(arg));
146             wdt_set_timeout(heartbeat);
147             break;
148 
149         case RT_DEVICE_CTRL_WDT_GET_TIMEOUT:
150             arg = &heartbeat;
151             break;
152 
153         case RT_DEVICE_CTRL_WDT_GET_TIMELEFT:
154             val = (rt_uint32_t) wdt_get_timeleft();
155             arg = &val;
156             break;
157 
158         default:
159             return -RT_EIO;
160     }
161     return RT_EOK;
162 }
163 
164 struct rt_watchdog_ops watchdog_ops =
165 {
166     .init = &watchdog_init,
167     .control = &watchdog_ctrl,
168 };
169 
wdt_exit(void * priv_data)170 int wdt_exit(void *priv_data)
171 {
172     return 0;
173 }
174 
rt_hw_wdt_init(void)175 int rt_hw_wdt_init(void)
176 {
177     rt_watchdog_t *wdt_dev;
178     struct wdt_driver *wdt_drv;
179 
180     wdt_drv = (struct wdt_driver *)rt_malloc(sizeof(struct wdt_driver));
181     rt_memset(wdt_drv, 0, sizeof(struct wdt_driver));
182 
183     wdt_dev = (rt_watchdog_t *)rt_malloc(sizeof(rt_watchdog_t));
184 
185     if (wdt_dev == RT_NULL)
186     {
187         rt_kprintf("ERROR: %s rt_watchdog_t malloc failed\n", __func__);
188     }
189 
190     wdt_dev->ops = &watchdog_ops;
191 
192     rt_hw_watchdog_register(wdt_dev, "wdt", RT_DEVICE_OFLAG_RDWR, wdt_drv);
193 
194     return 0;
195 }
196 
197 INIT_BOARD_EXPORT(rt_hw_wdt_init);
198 
199 #endif
200