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-03-04 stevetong459 first version
9 * 2022-12-26 luobeihai add APM32F0 series MCU support
10 * 2023-03-28 luobeihai add APM32E1/S1 series MCU support
11 */
12
13 #include <board.h>
14 #include <sys/time.h>
15
16 #ifdef RT_USING_WDT
17
18 #define DBG_TAG "drv.wdt"
19 #define DBG_LVL DBG_INFO
20 #include <rtdbg.h>
21
22 #ifndef LSI_VALUE
23 #define LSI_VALUE ((uint32_t)40000)
24 #endif
25
26 #define DRV_WDT_TIME_OUT 0xFFFF
27
28 typedef struct
29 {
30 struct rt_watchdog_device wdt;
31 rt_uint32_t min_threshold;
32 rt_uint32_t max_threshold;
33 rt_uint32_t current_threshold;
34 } apm32_wdt_t;
35
36 static apm32_wdt_t wdt_config;
37
apm32_iwdt_init(rt_watchdog_t * wdt)38 static rt_err_t apm32_iwdt_init(rt_watchdog_t *wdt)
39 {
40 rt_uint32_t counter = 0;
41
42 RCM_EnableLSI();
43
44 while (!RCM_ReadStatusFlag(RCM_FLAG_LSIRDY))
45 {
46 if (++counter > DRV_WDT_TIME_OUT)
47 {
48 LOG_E("LSI clock open failed.");
49 return -RT_ERROR;
50 }
51 }
52
53 wdt_config.min_threshold = 1;
54 wdt_config.max_threshold = (0xfff << 8) / LSI_VALUE;
55 LOG_I("threshold section [%u, %d]", \
56 wdt_config.min_threshold,
57 wdt_config.max_threshold);
58
59 #if defined(SOC_SERIES_APM32F0)
60 while (IWDT_ReadStatusFlag(IWDT_FLAG_DIVU))
61 #elif defined(SOC_SERIES_APM32F1) || defined(SOC_SERIES_APM32E1) || defined(SOC_SERIES_APM32S1) \
62 || defined(SOC_SERIES_APM32F4)
63 while (IWDT_ReadStatusFlag(IWDT_FLAG_PSCU))
64 #endif
65 {
66 if (++counter > DRV_WDT_TIME_OUT)
67 {
68 LOG_E("watchdog prescaler init failed.");
69 return -RT_ERROR;
70 }
71 }
72
73 IWDT_EnableWriteAccess();
74
75 #if defined(SOC_SERIES_APM32F0)
76 IWDT_ConfigDivider(IWDT_DIV_256);
77 #elif defined(SOC_SERIES_APM32F1) || defined(SOC_SERIES_APM32E1) || defined(SOC_SERIES_APM32S1) \
78 || defined(SOC_SERIES_APM32F4)
79 IWDT_ConfigDivider(IWDT_DIVIDER_256);
80 #endif
81
82 IWDT_DisableWriteAccess();
83
84 return RT_EOK;
85 }
86
87 /**
88 * @brief This function will control watchdog device.
89 *
90 * @param wdt is a pointer to i2c config class.
91 *
92 * @return RT_EOK indicates successful , other value indicates failed.
93 */
apm32_iwdt_control(rt_watchdog_t * wdt,int cmd,void * arg)94 static rt_err_t apm32_iwdt_control(rt_watchdog_t *wdt, int cmd, void *arg)
95 {
96 volatile rt_uint32_t param, counter = 0;
97
98 switch (cmd)
99 {
100 case RT_DEVICE_CTRL_WDT_KEEPALIVE:
101 IWDT_Refresh();
102 break;
103 case RT_DEVICE_CTRL_WDT_SET_TIMEOUT:
104 param = *(rt_uint32_t *) arg;
105 if ((param > wdt_config.max_threshold) || \
106 (param < wdt_config.min_threshold))
107 {
108 LOG_E("invalid param@%u.", param);
109 return -RT_ERROR;
110 }
111 else
112 {
113 wdt_config.current_threshold = param;
114 }
115 while (IWDT_ReadStatusFlag(IWDT_FLAG_CNTU))
116 {
117 if (++counter > DRV_WDT_TIME_OUT)
118 {
119 LOG_E("Update watchdog reload value complete.");
120 return -RT_ERROR;
121 }
122 }
123 IWDT_Refresh();
124 IWDT_EnableWriteAccess();
125 IWDT_ConfigReload(param * LSI_VALUE >> 8);
126 IWDT_DisableWriteAccess();
127 break;
128 case RT_DEVICE_CTRL_WDT_GET_TIMEOUT:
129 *(rt_uint32_t *)arg = wdt_config.current_threshold;
130 break;
131 case RT_DEVICE_CTRL_WDT_START:
132 IWDT_Enable();
133 IWDT_Refresh();
134 break;
135 default:
136 LOG_W("This command is not supported.");
137 return -RT_ERROR;
138 }
139
140 return RT_EOK;
141 }
142
143 static struct rt_watchdog_ops apm32_wdt_ops =
144 {
145 apm32_iwdt_init,
146 apm32_iwdt_control,
147 };
148
rt_hw_wdt_init(void)149 static int rt_hw_wdt_init(void)
150 {
151 wdt_config.wdt.ops = &apm32_wdt_ops;
152 /* register watchdog device */
153 if (rt_hw_watchdog_register(&wdt_config.wdt, "wdt", \
154 RT_DEVICE_FLAG_DEACTIVATE, RT_NULL) != RT_EOK)
155 {
156 LOG_E("wdt device register failed.");
157 return -RT_ERROR;
158 }
159 LOG_D("wdt device register success.");
160
161 return RT_EOK;
162 }
163 INIT_BOARD_EXPORT(rt_hw_wdt_init);
164
165 #endif
166