1 /*
2  * Copyright (c) 2006-2025, RT-Thread Development Team
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  *
6  * Change Logs:
7  * Date           Author       Notes
8  * 2021-08-14     Mr.Tiger     first version
9  */
10 
11 #include <rtthread.h>
12 #include <rtdevice.h>
13 #include "board.h"
14 #include <sys/time.h>
15 #include "hal_data.h"
16 
17 #ifdef BSP_USING_ONCHIP_RTC
18 
19 #define DBG_TAG              "drv.rtc"
20 #ifdef DRV_DEBUG
21     #define DBG_LVL               DBG_LOG
22 #else
23     #define DBG_LVL               DBG_INFO
24 #endif /* DRV_DEBUG */
25 #include <rtdbg.h>
26 
ra_rtc_init(void)27 static rt_err_t ra_rtc_init(void)
28 {
29     rt_err_t result = RT_EOK;
30 
31     if (R_RTC_Open(&g_rtc_ctrl, &g_rtc_cfg) != RT_EOK)
32     {
33         LOG_E("rtc init failed.");
34         result = -RT_ERROR;
35     }
36 
37 #if defined(SOC_SERIES_R9A07G0)
38     rtc_time_t default_set_time =
39     {
40         .tm_sec  = 0,
41         .tm_min  = 0,
42         .tm_hour = 0,
43         .tm_mday = 1,
44         .tm_wday = 1,
45         .tm_mon  = 1,
46         .tm_year = 1900,
47     };
48 
49     R_RTC_CalendarTimeSet(&g_rtc_ctrl, &default_set_time);
50 #endif
51     return result;
52 }
53 
get_rtc_timestamp(void)54 static time_t get_rtc_timestamp(void)
55 {
56     struct tm tm_new = {0};
57     rtc_time_t g_current_time = {0};
58 
59     R_RTC_CalendarTimeGet(&g_rtc_ctrl, &g_current_time);
60 
61     tm_new.tm_year  = g_current_time.tm_year;
62     tm_new.tm_mon   = g_current_time.tm_mon;
63     tm_new.tm_mday  = g_current_time.tm_mday;
64 
65     tm_new.tm_hour  = g_current_time.tm_hour;
66     tm_new.tm_min   = g_current_time.tm_min;
67     tm_new.tm_sec   = g_current_time.tm_sec;
68 
69     tm_new.tm_wday  = g_current_time.tm_wday;
70     tm_new.tm_yday  = g_current_time.tm_yday;
71     tm_new.tm_isdst = g_current_time.tm_isdst;
72 
73     return timegm(&tm_new);
74 }
75 
ra_get_secs(time_t * sec)76 static rt_err_t ra_get_secs(time_t *sec)
77 {
78     *(rt_uint32_t *)sec = get_rtc_timestamp();
79     LOG_D("RTC: get rtc_time %x\n", *(rt_uint32_t *)sec);
80 
81     return RT_EOK;
82 }
83 
set_rtc_time_stamp(time_t time_stamp)84 static rt_err_t set_rtc_time_stamp(time_t time_stamp)
85 {
86     struct tm now;
87     rtc_time_t g_current_time = {0};
88     gmtime_r(&time_stamp, &now);
89     if (now.tm_year < 100)
90     {
91         return -RT_ERROR;
92     }
93 
94     g_current_time.tm_sec    = now.tm_sec ;
95     g_current_time.tm_min    = now.tm_min ;
96     g_current_time.tm_hour   = now.tm_hour;
97     g_current_time.tm_mday   = now.tm_mday;
98     g_current_time.tm_mon    = now.tm_mon;
99     g_current_time.tm_year   = now.tm_year;
100     g_current_time.tm_wday   = now.tm_wday;
101     g_current_time.tm_yday   = now.tm_yday;
102 
103     if (R_RTC_CalendarTimeSet(&g_rtc_ctrl, &g_current_time) != FSP_SUCCESS)
104     {
105         LOG_E("set rtc time failed.");
106         return -RT_ERROR;
107     }
108 
109     return RT_EOK;
110 }
111 
ra_set_secs(time_t * sec)112 static rt_err_t ra_set_secs(time_t *sec)
113 {
114 
115     rt_err_t result = RT_EOK;
116 
117     if (set_rtc_time_stamp(*(rt_uint32_t *)sec))
118     {
119         result = -RT_ERROR;
120     }
121     LOG_D("RTC: set rtc_time %x\n", *(rt_uint32_t *)sec);
122 
123     return result;
124 }
125 
126 #ifdef RT_USING_ALARM
ra_get_alarm(struct rt_rtc_wkalarm * alarm)127 static rt_err_t ra_get_alarm(struct rt_rtc_wkalarm *alarm)
128 {
129     rt_err_t result = RT_EOK;
130     struct rt_rtc_wkalarm *wkalarm = alarm;
131     rtc_alarm_time_t alarm_time_get =
132     {
133         .sec_match        =  RT_FALSE,
134         .min_match        =  RT_FALSE,
135         .hour_match       =  RT_FALSE,
136         .mday_match       =  RT_FALSE,
137         .mon_match        =  RT_FALSE,
138         .year_match       =  RT_FALSE,
139         .dayofweek_match  =  RT_FALSE,
140     };
141 
142     if (RT_EOK == R_RTC_CalendarAlarmGet(&g_rtc_ctrl, &alarm_time_get))
143     {
144         wkalarm->tm_hour = alarm_time_get.time.tm_hour;
145         wkalarm->tm_min  = alarm_time_get.time.tm_min;
146         wkalarm->tm_sec  = alarm_time_get.time.tm_sec;
147     }
148     else
149     {
150         LOG_E("Calendar alarm Get failed.");
151     }
152 
153     return result;
154 }
155 
ra_set_alarm(struct rt_rtc_wkalarm * alarm)156 static rt_err_t ra_set_alarm(struct rt_rtc_wkalarm *alarm)
157 {
158     rt_err_t result = RT_EOK;
159     struct rt_rtc_wkalarm *wkalarm = alarm;
160     rtc_alarm_time_t alarm_time_set =
161     {
162         .sec_match        =  RT_TRUE,
163         .min_match        =  RT_TRUE,
164         .hour_match       =  RT_TRUE,
165         .mday_match       =  RT_FALSE,
166         .mon_match        =  RT_FALSE,
167         .year_match       =  RT_FALSE,
168         .dayofweek_match  =  RT_FALSE,
169     };
170 
171     alarm_time_set.time.tm_hour = wkalarm->tm_hour;
172     alarm_time_set.time.tm_min  = wkalarm->tm_min;
173     alarm_time_set.time.tm_sec  = wkalarm->tm_sec;
174     if (1 == wkalarm->enable)
175     {
176         if (RT_EOK != R_RTC_CalendarAlarmSet(&g_rtc_ctrl, &alarm_time_set))
177         {
178             LOG_E("Calendar alarm Set failed.");
179             result = -RT_ERROR;
180         }
181     }
182     else
183     {
184         alarm_time_set.sec_match        =  RT_FALSE;
185         alarm_time_set.min_match        =  RT_FALSE;
186         alarm_time_set.hour_match       =  RT_FALSE;
187         if (RT_EOK != R_RTC_CalendarAlarmSet(&g_rtc_ctrl, &alarm_time_set))
188         {
189             LOG_E("Calendar alarm Stop failed.");
190             result = -RT_ERROR;
191         }
192     }
193     return result;
194 }
195 #endif /* RT_USING_ALARM */
196 
rtc_callback(rtc_callback_args_t * p_args)197 void rtc_callback(rtc_callback_args_t *p_args)
198 {
199 #ifdef RT_USING_ALARM
200     static rt_device_t ra_device;
201     if (RTC_EVENT_ALARM_IRQ == p_args->event)
202     {
203         rt_alarm_update(ra_device, 1);
204     }
205 #endif
206 }
207 
208 static const struct rt_rtc_ops ra_rtc_ops =
209 {
210     .init      = ra_rtc_init,
211     .get_secs  = ra_get_secs,
212     .set_secs  = ra_set_secs,
213 #ifdef RT_USING_ALARM
214     .set_alarm = ra_set_alarm,
215     .get_alarm = ra_get_alarm,
216 #endif
217 };
218 
219 static rt_rtc_dev_t ra_rtc_dev;
220 
rt_hw_rtc_init(void)221 static int rt_hw_rtc_init(void)
222 {
223     rt_err_t result;
224 
225     ra_rtc_dev.ops = &ra_rtc_ops;
226 
227     result = rt_hw_rtc_register(&ra_rtc_dev, "rtc", RT_DEVICE_FLAG_RDWR, RT_NULL);
228     if (result != RT_EOK)
229     {
230         LOG_E("rtc register err code: %d", result);
231         return result;
232     }
233     LOG_D("rtc init success");
234 
235     return RT_EOK;
236 }
237 INIT_DEVICE_EXPORT(rt_hw_rtc_init);
238 #endif
239