1 /*
2  * Copyright (c) 2006-2023, RT-Thread Development Team
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  *
6  * Change Logs:
7  * Date           Author            Notes
8  * 2022-01-21     charlown           first version
9  */
10 
11 #include <rtthread.h>
12 #include <rtdevice.h>
13 #include <board.h>
14 #include "ch32f20x_iwdg.h"
15 
16 #ifdef BSP_USING_IWDT
17 
18 #define LOG_TAG "drv.wdt"
19 #include "drv_log.h"
20 
21 struct watchdog_device
22 {
23     rt_watchdog_t parent;
24     IWDG_TypeDef *instance;
25     rt_uint32_t Prescaler;
26     rt_uint32_t Reload;
27     rt_uint16_t is_start;
28 };
29 static struct watchdog_device watchdog_dev;
30 
ch32_wdt_init(rt_watchdog_t * wdt)31 static rt_err_t ch32_wdt_init(rt_watchdog_t *wdt)
32 {
33     return RT_EOK;
34 }
35 
ch32_wdt_control(rt_watchdog_t * wdt,int cmd,void * arg)36 static rt_err_t ch32_wdt_control(rt_watchdog_t *wdt, int cmd, void *arg)
37 {
38 
39     struct watchdog_device *wdt_dev;
40 
41     wdt_dev = (struct watchdog_device *)wdt;
42 
43     switch (cmd)
44     {
45     /* feed the watchdog */
46     case RT_DEVICE_CTRL_WDT_KEEPALIVE:
47 
48         IWDG_ReloadCounter();
49 
50         break;
51         /* set watchdog timeout */
52     case RT_DEVICE_CTRL_WDT_SET_TIMEOUT:
53 
54 #if defined(LSI_VALUE)
55         if (LSI_VALUE)
56         {
57             wdt_dev->Reload = (*((rt_uint32_t *)arg)) * LSI_VALUE / 256;
58         }
59         else
60         {
61             LOG_E("Please define the value of LSI_VALUE!");
62         }
63         if (wdt_dev->Reload > 0xFFF)
64         {
65             LOG_E("wdg set timeout parameter too large, please less than %ds", 0xFFF * 256 / LSI_VALUE);
66             return -RT_EINVAL;
67         }
68 #else
69 #error "Please define the value of LSI_VALUE!"
70 #endif
71         if (wdt_dev->is_start)
72         {
73             IWDG_WriteAccessCmd(IWDG_WriteAccess_Enable);
74             IWDG_SetPrescaler(wdt_dev->Prescaler);
75             IWDG_SetReload(wdt_dev->Reload);
76             IWDG_ReloadCounter();
77             IWDG_Enable();
78         }
79         break;
80     case RT_DEVICE_CTRL_WDT_GET_TIMEOUT:
81 
82 #if defined(LSI_VALUE)
83         if (LSI_VALUE)
84         {
85             (*((rt_uint32_t *)arg)) = wdt_dev->Reload * 256 / LSI_VALUE;
86         }
87         else
88         {
89             LOG_E("Please define the value of LSI_VALUE!");
90         }
91 #else
92 #error "Please define the value of LSI_VALUE!"
93 #endif
94         break;
95     case RT_DEVICE_CTRL_WDT_START:
96 
97         IWDG_WriteAccessCmd(IWDG_WriteAccess_Enable);
98         IWDG_SetPrescaler(wdt_dev->Prescaler);
99         IWDG_SetReload(wdt_dev->Reload);
100         IWDG_ReloadCounter();
101         IWDG_Enable();
102         wdt_dev->is_start = 1;
103 
104         break;
105     default:
106         LOG_W("This command is not supported.");
107         return -RT_ERROR;
108     }
109 
110     return RT_EOK;
111 }
112 
113 static struct rt_watchdog_ops watchdog_ops =
114     {
115         .init = ch32_wdt_init,
116         .control = ch32_wdt_control,
117 };
118 
rt_hw_wdt_init(void)119 int rt_hw_wdt_init(void)
120 {
121     watchdog_dev.instance = IWDG;
122     watchdog_dev.Prescaler = IWDG_Prescaler_256;
123     watchdog_dev.Reload = 0x0000FFF;
124     watchdog_dev.is_start = 0;
125     watchdog_dev.parent.ops = &watchdog_ops;
126 
127     /* register watchdog device */
128     if (rt_hw_watchdog_register(&watchdog_dev.parent, "wdt", RT_DEVICE_FLAG_DEACTIVATE, RT_NULL) != RT_EOK)
129     {
130         LOG_E("wdt device register failed.");
131         return -RT_ERROR;
132     }
133     LOG_D("wdt device register success.");
134 
135     return RT_EOK;
136 }
137 INIT_BOARD_EXPORT(rt_hw_wdt_init);
138 
139 #endif /* BSP_USING_IWDT */
140