1 /*
2 * Copyright (c) 2006-2021, RT-Thread Development Team
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 *
6 * Change Logs:
7 * Date Author Notes
8 * 2022-05-16 shelton first version
9 * 2023-04-08 shelton add support f423
10 * 2023-10-18 shelton add support f402/f405
11 * 2024-04-12 shelton add support a403a and a423
12 * 2024-08-30 shelton add support m412 and m416
13 * 2024-12-18 shelton add support f455/f456 and f457
14 */
15
16 #include <rtthread.h>
17 #include <rtdevice.h>
18 #include <sys/time.h>
19 #include "drv_common.h"
20
21 #ifdef BSP_USING_RTC
22
23 //#define DRV_DEBUG
24 #define LOG_TAG "drv.rtc"
25 #include <drv_log.h>
26
27 #define BKUP_REG_DATA 0xA5A5
28
29 #if defined (SOC_SERIES_AT32F403A) || defined (SOC_SERIES_AT32F407) || \
30 defined (SOC_SERIES_AT32F413) || defined (SOC_SERIES_AT32A403A)
31 #define Alarm_IRQn RTCAlarm_IRQn
32 #define Alarm_IRQHandler RTCAlarm_IRQHandler
33 #elif defined (SOC_SERIES_AT32F421) || defined (SOC_SERIES_AT32F425)
34 #define Alarm_IRQn RTC_IRQn
35 #define Alarm_IRQHandler RTC_IRQHandler
36 #else
37 #define Alarm_IRQn ERTCAlarm_IRQn
38 #define Alarm_IRQHandler ERTCAlarm_IRQHandler
39 #endif
40
41 struct rtc_device_object
42 {
43 rt_rtc_dev_t rtc_dev;
44 #ifdef RT_USING_ALARM
45 struct rt_rtc_wkalarm wkalarm;
46 #endif
47 };
48
49 static struct rtc_device_object rtc_device;
50
get_rtc_timestamp(void)51 static time_t get_rtc_timestamp(void)
52 {
53 #if defined (SOC_SERIES_AT32F435) || defined (SOC_SERIES_AT32F437) || \
54 defined (SOC_SERIES_AT32F415) || defined (SOC_SERIES_AT32F421) || \
55 defined (SOC_SERIES_AT32F425) || defined (SOC_SERIES_AT32F423) || \
56 defined (SOC_SERIES_AT32F402) || defined (SOC_SERIES_AT32F405) || \
57 defined (SOC_SERIES_AT32A423) || defined (SOC_SERIES_AT32M412) || \
58 defined (SOC_SERIES_AT32M416) || defined (SOC_SERIES_AT32F455) || \
59 defined (SOC_SERIES_AT32F456) || defined (SOC_SERIES_AT32F457)
60 struct tm tm_new;
61 ertc_time_type ertc_time_struct;
62
63 ertc_calendar_get(&ertc_time_struct);
64
65 tm_new.tm_sec = ertc_time_struct.sec;
66 tm_new.tm_min = ertc_time_struct.min;
67 tm_new.tm_hour = ertc_time_struct.hour;
68 tm_new.tm_mday = ertc_time_struct.day;
69 tm_new.tm_mon = ertc_time_struct.month - 1;
70 tm_new.tm_year = ertc_time_struct.year + 100;
71
72 LOG_D("get rtc time.");
73
74 return timegm(&tm_new);
75 #else
76 return rtc_counter_get();
77 #endif
78 }
79
set_rtc_time_stamp(time_t time_stamp)80 static rt_err_t set_rtc_time_stamp(time_t time_stamp)
81 {
82 #if defined (SOC_SERIES_AT32F435) || defined (SOC_SERIES_AT32F437) || \
83 defined (SOC_SERIES_AT32F415) || defined (SOC_SERIES_AT32F421) || \
84 defined (SOC_SERIES_AT32F425) || defined (SOC_SERIES_AT32F423) || \
85 defined (SOC_SERIES_AT32F402) || defined (SOC_SERIES_AT32F405) || \
86 defined (SOC_SERIES_AT32A423) || defined (SOC_SERIES_AT32M412) || \
87 defined (SOC_SERIES_AT32M416) || defined (SOC_SERIES_AT32F455) || \
88 defined (SOC_SERIES_AT32F456) || defined (SOC_SERIES_AT32F457)
89 struct tm now;
90
91 gmtime_r(&time_stamp, &now);
92 if (now.tm_year < 100)
93 {
94 return -RT_ERROR;
95 }
96
97 /* set time */
98 if(ertc_time_set(now.tm_hour, now.tm_min, now.tm_sec, ERTC_AM) != SUCCESS)
99 {
100 return -RT_ERROR;
101 }
102
103 /* set date */
104 if(ertc_date_set(now.tm_year - 100, now.tm_mon + 1, now.tm_mday, now.tm_wday + 1) != SUCCESS)
105 {
106 return -RT_ERROR;
107 }
108
109 LOG_D("set rtc time.");
110
111 /* indicator for the ertc configuration */
112 ertc_bpr_data_write(ERTC_DT1, BKUP_REG_DATA);
113 #else
114 /* set the rtc counter value */
115 rtc_counter_set(time_stamp);
116 /* wait until last write operation on rtc registers has finished */
117 rtc_wait_config_finish();
118 LOG_D("set rtc time.");
119
120 bpr_data_write(BPR_DATA1, BKUP_REG_DATA);
121 #endif
122
123 return RT_EOK;
124 }
125
rt_rtc_config(void)126 static rt_err_t rt_rtc_config(void)
127 {
128 /* allow access to pattery powered domain */
129 pwc_battery_powered_domain_access(TRUE);
130
131 #if defined (SOC_SERIES_AT32F435) || defined (SOC_SERIES_AT32F437) || \
132 defined (SOC_SERIES_AT32F415) || defined (SOC_SERIES_AT32F421) || \
133 defined (SOC_SERIES_AT32F425) || defined (SOC_SERIES_AT32F423) || \
134 defined (SOC_SERIES_AT32F402) || defined (SOC_SERIES_AT32F405) || \
135 defined (SOC_SERIES_AT32A423) || defined (SOC_SERIES_AT32M412) || \
136 defined (SOC_SERIES_AT32M416) || defined (SOC_SERIES_AT32F455) || \
137 defined (SOC_SERIES_AT32F456) || defined (SOC_SERIES_AT32F457)
138
139 /* select rtc clock source */
140 #ifdef BSP_RTC_USING_LICK
141 crm_ertc_clock_select(CRM_ERTC_CLOCK_LICK);
142 #else
143 crm_ertc_clock_select(CRM_ERTC_CLOCK_LEXT);
144 #endif /* BSP_RTC_USING_LICK */
145
146 /* enable rtc */
147 crm_ertc_clock_enable(TRUE);
148
149 /* wait for ertc registers update */
150 ertc_wait_update();
151
152 if (ertc_bpr_data_read(ERTC_DT1)!= BKUP_REG_DATA)
153 {
154 LOG_I("RTC hasn't been configured, please use <date> command to config.");
155
156 /* configure the ertc divider */
157 ertc_divider_set(0x7F, 0xFF);
158 /* configure the ertc hour mode */
159 ertc_hour_mode_set(ERTC_HOUR_MODE_24);
160 }
161 #else
162
163 #ifdef BSP_RTC_USING_LICK
164 crm_rtc_clock_select(CRM_RTC_CLOCK_LICK);
165 #else
166 crm_rtc_clock_select(CRM_RTC_CLOCK_LEXT);
167 #endif /* BSP_RTC_USING_LICK */
168 /* enable rtc */
169 crm_rtc_clock_enable(TRUE);
170
171 /* wait for rtc registers update finish */
172 rtc_wait_update_finish();
173 /* wait until last write operation on rtc registers has finished */
174 rtc_wait_config_finish();
175
176 if (bpr_data_read(BPR_DATA1) != BKUP_REG_DATA)
177 {
178 LOG_I("RTC hasn't been configured, please use <date> command to config.");
179 /* set rtc divider: set rtc period to 1sec */
180 rtc_divider_set(32767);
181 /* wait until last write operation on rtc registers has finished */
182 rtc_wait_config_finish();
183 }
184 #endif
185
186 return RT_EOK;
187 }
188
_rtc_init(void)189 static rt_err_t _rtc_init(void)
190 {
191 crm_periph_clock_enable(CRM_PWC_PERIPH_CLOCK, TRUE);
192
193 #if defined (SOC_SERIES_AT32F403A) || defined (SOC_SERIES_AT32F407) || \
194 defined (SOC_SERIES_AT32F413) || defined (SOC_SERIES_AT32A403A)
195 crm_periph_clock_enable(CRM_BPR_PERIPH_CLOCK, TRUE);
196 #endif
197
198 #ifdef BSP_RTC_USING_LICK
199 crm_clock_source_enable(CRM_CLOCK_SOURCE_LICK, TRUE);
200 while(crm_flag_get(CRM_LICK_STABLE_FLAG) == RESET);
201 #else
202 pwc_battery_powered_domain_access(TRUE);
203 crm_clock_source_enable(CRM_CLOCK_SOURCE_LEXT, TRUE);
204 while(crm_flag_get(CRM_LEXT_STABLE_FLAG) == RESET);
205 #endif /* BSP_RTC_USING_LICK */
206
207 if (rt_rtc_config() != RT_EOK)
208 {
209 LOG_E("rtc init failed.");
210 return -RT_ERROR;
211 }
212
213 return RT_EOK;
214 }
215
_rtc_get_secs(time_t * args)216 static rt_err_t _rtc_get_secs(time_t *args)
217 {
218 *(rt_uint32_t *)args = get_rtc_timestamp();
219 LOG_D("RTC: get rtc_time %x\n", *(rt_uint32_t *)args);
220
221 return RT_EOK;
222 }
223
_rtc_set_secs(time_t * args)224 static rt_err_t _rtc_set_secs(time_t *args)
225 {
226 rt_err_t result = RT_EOK;
227
228 if (set_rtc_time_stamp(*(rt_uint32_t *)args))
229 {
230 result = -RT_ERROR;
231 }
232 LOG_D("RTC: set rtc_time %x\n", *(rt_uint32_t *)args);
233
234 return result;
235 }
236
237 #ifdef RT_USING_ALARM
rtc_alarm_time_set(struct rtc_device_object * p_dev)238 static rt_err_t rtc_alarm_time_set(struct rtc_device_object* p_dev)
239 {
240 exint_init_type exint_init_struct;
241
242 #if defined (SOC_SERIES_AT32F403A) || defined (SOC_SERIES_AT32F407) || \
243 defined (SOC_SERIES_AT32F413) || defined (SOC_SERIES_AT32A403A)
244 struct tm tm_new;
245 time_t sec_count;
246 #endif
247 /* config the exint line of the rtc alarm */
248 exint_init_struct.line_select = EXINT_LINE_17;
249 exint_init_struct.line_enable = TRUE;
250 exint_init_struct.line_mode = EXINT_LINE_INTERRUPUT;
251 exint_init_struct.line_polarity = EXINT_TRIGGER_RISING_EDGE;
252 exint_init(&exint_init_struct);
253
254 if (p_dev->wkalarm.enable)
255 {
256 nvic_irq_enable(Alarm_IRQn, 0, 0);
257
258 #if defined (SOC_SERIES_AT32F403A) || defined (SOC_SERIES_AT32F407) || \
259 defined (SOC_SERIES_AT32F413) || defined (SOC_SERIES_AT32A403A)
260 /* clear alarm flag */
261 rtc_flag_clear(RTC_TA_FLAG);
262 /* wait for the register write to complete */
263 rtc_wait_config_finish();
264 /* enable alarm interrupt */
265 rtc_interrupt_enable(RTC_TA_INT, TRUE);
266 /* wait for the register write to complete */
267 rtc_wait_config_finish();
268
269 tm_new.tm_sec = p_dev->wkalarm.tm_sec;
270 tm_new.tm_min = p_dev->wkalarm.tm_min;
271 tm_new.tm_hour = p_dev->wkalarm.tm_hour;
272 tm_new.tm_mday = p_dev->wkalarm.tm_mday;
273 tm_new.tm_mon = p_dev->wkalarm.tm_mon;
274 tm_new.tm_year = p_dev->wkalarm.tm_year;
275
276 sec_count = timegm(&tm_new);
277 rtc_alarm_set(sec_count);
278 /* wait for the register write to complete */
279 rtc_wait_config_finish();
280 #else
281 ertc_alarm_enable(ERTC_ALA, FALSE);
282 ertc_flag_clear(ERTC_ALAF_FLAG);
283 ertc_alarm_mask_set(ERTC_ALA, ERTC_ALARM_MASK_DATE_WEEK);
284 ertc_alarm_week_date_select(ERTC_ALA, ERTC_SLECT_DATE);
285 ertc_alarm_set(ERTC_ALA, p_dev->wkalarm.tm_mday, p_dev->wkalarm.tm_hour, \
286 p_dev->wkalarm.tm_min, p_dev->wkalarm.tm_sec, ERTC_24H);
287
288 ertc_interrupt_enable(ERTC_ALA_INT, TRUE);
289 ertc_alarm_enable(ERTC_ALA, TRUE);
290 ertc_flag_clear(ERTC_ALAF_FLAG);
291 #endif
292 }
293
294 return RT_EOK;
295 }
296
Alarm_IRQHandler(void)297 void Alarm_IRQHandler(void)
298 {
299 rt_interrupt_enter();
300
301 #if defined (SOC_SERIES_AT32F403A) || defined (SOC_SERIES_AT32F407) || \
302 defined (SOC_SERIES_AT32F413) || defined (SOC_SERIES_AT32A403A)
303 if(rtc_flag_get(RTC_TA_FLAG) != RESET)
304 {
305 /* clear exint line flag */
306 exint_flag_clear(EXINT_LINE_17);
307
308 /* wait for the register write to complete */
309 rtc_wait_config_finish();
310
311 /* clear alarm flag */
312 rtc_flag_clear(RTC_TA_FLAG);
313
314 /* wait for the register write to complete */
315 rtc_wait_config_finish();
316
317 rt_alarm_update(&rtc_device.rtc_dev.parent, 1);
318 }
319 #else
320 if(ertc_flag_get(ERTC_ALAF_FLAG) != RESET)
321 {
322 /* clear alarm flag */
323 ertc_flag_clear(ERTC_ALAF_FLAG);
324
325 /* clear exint flag */
326 exint_flag_clear(EXINT_LINE_17);
327
328 rt_alarm_update(&rtc_device.rtc_dev.parent, 1);
329 }
330 #endif
331 rt_interrupt_leave();
332 }
333 #endif
334
_rtc_get_alarm(struct rt_rtc_wkalarm * alarm)335 static rt_err_t _rtc_get_alarm(struct rt_rtc_wkalarm *alarm)
336 {
337 #ifdef RT_USING_ALARM
338 *alarm = rtc_device.wkalarm;
339 LOG_D("GET_ALARM %d:%d:%d",rtc_device.wkalarm.tm_hour,
340 rtc_device.wkalarm.tm_min,rtc_device.wkalarm.tm_sec);
341 return RT_EOK;
342 #else
343 return -RT_ERROR;
344 #endif
345 }
346
_rtc_set_alarm(struct rt_rtc_wkalarm * alarm)347 static rt_err_t _rtc_set_alarm(struct rt_rtc_wkalarm *alarm)
348 {
349 #ifdef RT_USING_ALARM
350 LOG_D("RT_DEVICE_CTRL_RTC_SET_ALARM");
351 if (alarm != RT_NULL)
352 {
353 rtc_device.wkalarm.enable = alarm->enable;
354 rtc_device.wkalarm.tm_year = alarm->tm_year;
355 rtc_device.wkalarm.tm_mon = alarm->tm_mon;
356 rtc_device.wkalarm.tm_mday = alarm->tm_mday;
357 rtc_device.wkalarm.tm_hour = alarm->tm_hour;
358 rtc_device.wkalarm.tm_min = alarm->tm_min;
359 rtc_device.wkalarm.tm_sec = alarm->tm_sec;
360 rtc_alarm_time_set(&rtc_device);
361 }
362 else
363 {
364 LOG_E("RT_DEVICE_CTRL_RTC_SET_ALARM error!!");
365 return -RT_ERROR;
366 }
367 LOG_D("SET_ALARM %d:%d:%d",alarm->tm_hour,
368 alarm->tm_min, alarm->tm_sec);
369 return RT_EOK;
370 #else
371 return -RT_ERROR;
372 #endif
373 }
374
_rtc_get_timeval(struct timeval * tv)375 static rt_err_t _rtc_get_timeval(struct timeval *tv)
376 {
377 tv->tv_sec = get_rtc_timestamp();
378
379 return RT_EOK;
380 }
381
382 static const struct rt_rtc_ops _rtc_ops =
383 {
384 _rtc_init,
385 _rtc_get_secs,
386 _rtc_set_secs,
387 _rtc_get_alarm,
388 _rtc_set_alarm,
389 _rtc_get_timeval,
390 RT_NULL,
391 };
392
rt_hw_rtc_init(void)393 int rt_hw_rtc_init(void)
394 {
395 rt_err_t result;
396 rtc_device.rtc_dev.ops = &_rtc_ops;
397 result = rt_hw_rtc_register(&rtc_device.rtc_dev, "rtc", RT_DEVICE_FLAG_RDWR, RT_NULL);
398 if (result != RT_EOK)
399 {
400 LOG_E("rtc register err code: %d", result);
401 return result;
402 }
403 LOG_D("rtc init success");
404 return RT_EOK;
405 }
406
407 INIT_DEVICE_EXPORT(rt_hw_rtc_init);
408
409 #endif /* BSP_USING_RTC */
410