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  * 2018-03-15     Liuguang     the first version.
9  * 2019-04-22     tyustli      add imxrt series support
10  *
11  */
12 #include <rtthread.h>
13 #include <rtdevice.h>
14 #include <sys/time.h>
15 #ifdef BSP_USING_RTC
16 
17 #define LOG_TAG             "drv.rtc"
18 #include <drv_log.h>
19 
20 #include "drv_rtc.h"
21 #include "fsl_snvs_hp.h"
22 #include "fsl_snvs_lp.h"
23 #include <sys/time.h>
24 
25 #if defined(FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL) && FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL
26 #error "Please don't define 'FSL_SDK_DISABLE_DRIVER_CLOCK_CONTROL'!"
27 #endif
28 
imxrt_hp_get_timestamp(void)29 static time_t imxrt_hp_get_timestamp(void)
30 {
31     struct tm tm_new = {0};
32     snvs_hp_rtc_datetime_t rtcDate = {0};
33     snvs_lp_srtc_datetime_t srtcDate = {0};
34 
35     SNVS_LP_SRTC_GetDatetime(SNVS, &srtcDate);
36     SNVS_HP_RTC_TimeSynchronize(SNVS);
37     SNVS_HP_RTC_GetDatetime(SNVS, &rtcDate);
38 
39     tm_new.tm_sec  = rtcDate.second;
40     tm_new.tm_min  = rtcDate.minute;
41     tm_new.tm_hour = rtcDate.hour;
42 
43     tm_new.tm_mday = rtcDate.day;
44     tm_new.tm_mon  = rtcDate.month - 1;
45     tm_new.tm_year = rtcDate.year - 1900;
46 
47     return timegm(&tm_new);
48 }
49 
imxrt_hp_set_timestamp(time_t timestamp)50 static int imxrt_hp_set_timestamp(time_t timestamp)
51 {
52     struct tm now;
53     snvs_lp_srtc_datetime_t srtcDate = {0};
54 
55     gmtime_r(&timestamp, &now);
56 
57     srtcDate.second = now.tm_sec;
58     srtcDate.minute = now.tm_min;
59     srtcDate.hour = now.tm_hour;
60 
61     srtcDate.day = now.tm_mday;
62     srtcDate.month = now.tm_mon + 1;
63     srtcDate.year = now.tm_year + 1900;
64 
65 
66     if (SNVS_LP_SRTC_SetDatetime(SNVS, &srtcDate) != kStatus_Success)
67     {
68         LOG_E("set rtc date time failed\n");
69         return -RT_ERROR;
70     }
71 
72     SNVS_HP_RTC_TimeSynchronize(SNVS);
73 
74     return RT_EOK;
75 }
76 
imxrt_hp_rtc_init(rt_device_t dev)77 static rt_err_t imxrt_hp_rtc_init(rt_device_t dev)
78 {
79     snvs_hp_rtc_config_t snvsRtcConfig;
80     snvs_lp_srtc_config_t snvsSrtcConfig;
81 
82     /* Init SNVS_HP */
83     SNVS_HP_RTC_GetDefaultConfig(&snvsRtcConfig);
84     SNVS_HP_RTC_Init(SNVS, &snvsRtcConfig);
85 
86     /* Init SNVS_LP */
87     SNVS_LP_SRTC_GetDefaultConfig(&snvsSrtcConfig);
88     SNVS_LP_SRTC_Init(SNVS, &snvsSrtcConfig);
89     return RT_EOK;
90 }
91 
imxrt_hp_rtc_open(rt_device_t dev,rt_uint16_t oflag)92 static rt_err_t imxrt_hp_rtc_open(rt_device_t dev, rt_uint16_t oflag)
93 {
94     SNVS_HP_RTC_StartTimer(SNVS);
95     SNVS_LP_SRTC_StartTimer(SNVS);
96     return RT_EOK;
97 }
98 
imxrt_hp_rtc_close(rt_device_t dev)99 static rt_err_t imxrt_hp_rtc_close(rt_device_t dev)
100 {
101     SNVS_HP_RTC_StopTimer(SNVS);
102 
103     return RT_EOK;
104 }
105 
imxrt_hp_rtc_read(rt_device_t dev,rt_off_t pos,void * buffer,rt_size_t size)106 static rt_ssize_t imxrt_hp_rtc_read(rt_device_t dev, rt_off_t pos, void* buffer, rt_size_t size)
107 {
108     return -RT_EINVAL;
109 }
110 
imxrt_hp_rtc_write(rt_device_t dev,rt_off_t pos,const void * buffer,rt_size_t size)111 static rt_ssize_t imxrt_hp_rtc_write(rt_device_t dev, rt_off_t pos, const void* buffer, rt_size_t size)
112 {
113     return -RT_EINVAL;
114 }
115 
imxrt_hp_rtc_control(rt_device_t dev,int cmd,void * args)116 static rt_err_t imxrt_hp_rtc_control(rt_device_t dev, int cmd, void *args)
117 {
118     RT_ASSERT(dev != RT_NULL);
119 
120     switch(cmd)
121     {
122     case RT_DEVICE_CTRL_RTC_GET_TIME:
123     {
124         *(uint32_t *)args = imxrt_hp_get_timestamp();
125     }
126     break;
127 
128     case RT_DEVICE_CTRL_RTC_SET_TIME:
129     {
130         imxrt_hp_set_timestamp(*(time_t *)args);
131     }
132     break;
133 
134     default:
135         return -RT_EINVAL;
136     }
137 
138     return RT_EOK;
139 }
140 
141 static struct rt_device device =
142 {
143     .type    = RT_Device_Class_RTC,
144     .init    = imxrt_hp_rtc_init,
145     .open    = imxrt_hp_rtc_open,
146     .close   = imxrt_hp_rtc_close,
147     .read    = imxrt_hp_rtc_read,
148     .write   = imxrt_hp_rtc_write,
149     .control = imxrt_hp_rtc_control,
150 };
151 
rt_hw_rtc_init(void)152 int rt_hw_rtc_init(void)
153 {
154     rt_err_t ret = RT_EOK;
155 
156     ret = rt_device_register(&device, "rtc", RT_DEVICE_FLAG_RDWR);
157 
158     if(ret != RT_EOK)
159     {
160         LOG_E("rt device register failed %d\n", ret);
161         return ret;
162     }
163 
164     rt_device_open(&device, RT_DEVICE_OFLAG_RDWR);
165 
166     return RT_EOK;
167 }
168 
169 INIT_DEVICE_EXPORT(rt_hw_rtc_init);
170 
171 #include <rtthread.h>
172 #include <rtdevice.h>
173 
174 #define RTC_NAME       "rtc"
175 
rtc_sample(int argc,char * argv[])176 static int rtc_sample(int argc, char *argv[])
177 {
178     rt_err_t ret = RT_EOK;
179     time_t now;
180     rt_device_t device = RT_NULL;
181 
182     device = rt_device_find(RTC_NAME);
183     if (!device)
184     {
185       LOG_E("find %s failed!", RTC_NAME);
186       return -RT_ERROR;
187     }
188 
189     if(rt_device_open(device, 0) != RT_EOK)
190     {
191       LOG_E("open %s failed!", RTC_NAME);
192       return -RT_ERROR;
193     }
194 
195     ret = set_date(2018, 12, 3);
196     if (ret != RT_EOK)
197     {
198         rt_kprintf("set RTC date failed\n");
199         return ret;
200     }
201 
202     ret = set_time(11, 15, 50);
203     if (ret != RT_EOK)
204     {
205         rt_kprintf("set RTC time failed\n");
206         return ret;
207     }
208 
209     rt_thread_mdelay(1000);
210 
211     now = time(RT_NULL);
212     rt_kprintf("%s\n", ctime(&now));
213 
214     return ret;
215 }
216 MSH_CMD_EXPORT(rtc_sample, rtc sample);
217 #endif /* BSP_USING_RTC */
218