1 /*
2 * Copyright (c) 2006-2024 RT-Thread Development Team
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 *
6 * Change Logs:
7 * Date Author Notes
8 * 2022-07-25 Rbb666 first version
9 * 2024-11-06 kurisaw add alarm function
10 */
11
12 #include <rtthread.h>
13 #include <rtdevice.h>
14 #include <sys/time.h>
15 #include "drv_common.h"
16
17 #ifdef BSP_USING_RTC
18
19 /*#define DRV_DEBUG*/
20 #define LOG_TAG "drv.rtc"
21 #include <drv_log.h>
22
23 cyhal_rtc_t rtc_obj;
24
25 struct rtc_device_object
26 {
27 rt_rtc_dev_t rtc_dev;
28 #ifdef RT_USING_ALARM
29 struct rt_rtc_wkalarm wkalarm;
30 #endif
31 };
32
33 static struct rtc_device_object ifx32_rtc_dev;
34
get_day_of_week(int day,int month,int year)35 static int get_day_of_week(int day, int month, int year)
36 {
37 int ret;
38 int k = 0;
39 int j = 0;
40
41 if (month < CY_RTC_MARCH)
42 {
43 month += CY_RTC_MONTHS_PER_YEAR;
44 year--;
45 }
46
47 k = (year % 100);
48 j = (year / 100);
49 ret = (day + (13 * (month + 1) / 5) + k + (k / 4) + (j / 4) + (5 * j)) % 7;
50 ret = ((ret + 6) % 7);
51
52 return ret;
53 }
54
set_rtc_time_stamp(time_t time_stamp)55 static rt_err_t set_rtc_time_stamp(time_t time_stamp)
56 {
57 struct tm tm = {0};
58 struct tm new_time = {0};
59
60 gmtime_r(&time_stamp, &tm);
61
62 if (tm.tm_year < 100)
63 {
64 return -RT_ERROR;
65 }
66
67 new_time.tm_sec = tm.tm_sec ;
68 new_time.tm_min = tm.tm_min ;
69 new_time.tm_hour = tm.tm_hour;
70 new_time.tm_mday = tm.tm_mday;
71 new_time.tm_mon = tm.tm_mon;
72 new_time.tm_year = tm.tm_year;
73 new_time.tm_wday = get_day_of_week(tm.tm_mday, tm.tm_mon, tm.tm_year);
74
75 if (cyhal_rtc_write(&rtc_obj, &new_time) != RT_EOK)
76 {
77 return -RT_ERROR;
78 }
79
80 LOG_D("set rtc time.");
81
82 return RT_EOK;
83 }
84
ifx_rtc_get_timeval(struct timeval * tv)85 static rt_err_t ifx_rtc_get_timeval(struct timeval *tv)
86 {
87 struct tm tm_new = {0};
88 struct tm date_time = {0};
89
90 cyhal_rtc_read(&rtc_obj, &date_time);
91
92 tm_new.tm_sec = date_time.tm_sec;
93 tm_new.tm_min = date_time.tm_min;
94 tm_new.tm_hour = date_time.tm_hour;
95 tm_new.tm_mday = date_time.tm_mday;
96 tm_new.tm_mon = date_time.tm_mon;
97 tm_new.tm_year = date_time.tm_year;
98
99 tv->tv_sec = timegm(&tm_new);
100
101 return RT_EOK;
102 }
103
_rtc_init(void)104 static rt_err_t _rtc_init(void)
105 {
106 #ifdef BSP_RTC_USING_LSE
107 Cy_RTC_SelectClockSource(CY_RTC_CLK_SELECT_WCO);
108 #else
109 Cy_RTC_SelectClockSource(CY_RTC_CLK_SELECT_ILO);
110 #endif /* BSP_RTC_USING_LSE */
111 if (cyhal_rtc_init(&rtc_obj) != RT_EOK)
112 {
113 LOG_E("rtc init failed.");
114 return -RT_ERROR;
115 }
116
117 #ifdef RT_USING_ALARM
118 cyhal_rtc_register_callback(&rtc_obj, rtc_alarm_callback, NULL);
119 cyhal_rtc_enable_event(&rtc_obj, CYHAL_RTC_ALARM, 3u, true);
120 #endif
121 return RT_EOK;
122 }
123
_rtc_get_secs(time_t * sec)124 static rt_err_t _rtc_get_secs(time_t *sec)
125 {
126 struct timeval tv;
127
128 ifx_rtc_get_timeval(&tv);
129 *(time_t *) sec = tv.tv_sec;
130 LOG_D("RTC: get rtc_time %d", *sec);
131
132 return RT_EOK;
133 }
134
_rtc_set_secs(time_t * sec)135 static rt_err_t _rtc_set_secs(time_t *sec)
136 {
137 rt_err_t result = RT_EOK;
138
139 if (set_rtc_time_stamp(*sec))
140 {
141 result = -RT_ERROR;
142 }
143
144 LOG_D("RTC: set rtc_time %d", *sec);
145
146 return result;
147 }
148
149 #if defined(RT_USING_ALARM)
150
_rtc_get_alarm(struct rt_rtc_wkalarm * alarm)151 static rt_err_t _rtc_get_alarm(struct rt_rtc_wkalarm *alarm)
152 {
153 #ifdef RT_USING_ALARM
154 *alarm = ifx32_rtc_dev.wkalarm;
155 LOG_D("GET_ALARM %d:%d:%d",ifx32_rtc_dev.wkalarm.tm_hour,
156 ifx32_rtc_dev.wkalarm.tm_min,ifx32_rtc_dev.wkalarm.tm_sec);
157 return RT_EOK;
158 #else
159 return -RT_ERROR;
160 #endif
161 }
162
_rtc_set_alarm(struct rt_rtc_wkalarm * alarm)163 static rt_err_t _rtc_set_alarm(struct rt_rtc_wkalarm *alarm)
164 {
165 #ifdef RT_USING_ALARM
166 LOG_D("RT_DEVICE_CTRL_RTC_SET_ALARM");
167 if (alarm != RT_NULL)
168 {
169 ifx32_rtc_dev.wkalarm.enable = alarm->enable;
170 ifx32_rtc_dev.wkalarm.tm_hour = alarm->tm_hour;
171 ifx32_rtc_dev.wkalarm.tm_min = alarm->tm_min;
172 ifx32_rtc_dev.wkalarm.tm_sec = alarm->tm_sec;
173
174 cyhal_rtc_set_alarm_by_seconds(&rtc_obj, 1);
175 }
176 else
177 {
178 LOG_E("RT_DEVICE_CTRL_RTC_SET_ALARM error!!");
179 return -RT_ERROR;
180 }
181 LOG_D("SET_ALARM %d:%d:%d",alarm->tm_hour,
182 alarm->tm_min, alarm->tm_sec);
183 return RT_EOK;
184 #else
185 return -RT_ERROR;
186 #endif
187 }
188
189 #ifdef RT_USING_ALARM
rtc_alarm_callback(void)190 void rtc_alarm_callback(void)
191 {
192 rt_interrupt_enter();
193 rt_alarm_update(0, 0);
194 rt_interrupt_leave();
195 }
196 #endif
197
198 static const struct rt_rtc_ops _rtc_ops =
199 {
200 _rtc_init,
201 _rtc_get_secs,
202 _rtc_set_secs,
203 _rtc_get_alarm,
204 _rtc_set_alarm,
205 ifx_rtc_get_timeval,
206 RT_NULL,
207 };
208
209 /**
210 * @brief RTC initialization function.
211 *
212 * @return RT_EOK indicates successful initialization, other value indicates failed;
213 */
rt_hw_rtc_init(void)214 static int rt_hw_rtc_init(void)
215 {
216 rt_err_t result = RT_EOK;
217
218 ifx32_rtc_dev.rtc_dev.ops = &_rtc_ops;
219
220 if (rt_hw_rtc_register(&(ifx32_rtc_dev.rtc_dev), "rtc", RT_DEVICE_FLAG_RDWR, RT_NULL) != RT_EOK)
221 {
222 LOG_E("rtc init failed");
223 result = -RT_ERROR;
224 }
225 else
226 {
227 LOG_D("rtc init success");
228 }
229
230 return result;
231 }
232
233 INIT_DEVICE_EXPORT(rt_hw_rtc_init);
234 #endif
235