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  * 2009-04-26     yi.qiu        first version
9  * 2010-03-18     Gary Lee  add functions such as GregorianDay
10  *                                  and rtc_time_to_tm
11  * 2009-03-20     yi.qiu        clean up
12  */
13 
14 #include <rtthread.h>
15 #include <rtdevice.h>
16 #include <sys/time.h>
17 #include <s3c24x0.h>
18 
19 // #define RTC_DEBUG
20 #ifdef RT_USING_RTC
21 #define RTC_ENABLE      RTCCON |=  0x01;    /*RTC read and write enable */
22 #define RTC_DISABLE     RTCCON &= ~0x01;    /* RTC read and write disable */
23 #define BCD2BIN(n)      (((((n) >> 4) & 0x0F) * 10) + ((n) & 0x0F))
24 #define BIN2BCD(n)      ((((n) / 10) << 4) | ((n) % 10))
25 
26 /**
27  * This function get rtc time
28  */
rt_hw_rtc_get(struct tm * ti)29 void rt_hw_rtc_get(struct tm *ti)
30 {
31     rt_uint8_t sec, min, hour, mday, wday, mon, year;
32 
33     /* enable access to RTC registers */
34     RTCCON |= RTC_ENABLE;
35 
36     /* read RTC registers */
37     do
38     {
39         sec     = BCDSEC;
40         min     = BCDMIN;
41         hour    = BCDHOUR;
42         mday    = BCDDATE;
43         wday    = BCDDAY;
44         mon     = BCDMON;
45         year    = BCDYEAR;
46     } while (sec != BCDSEC);
47 
48 #ifdef RTC_DEBUG
49     rt_kprintf("sec:%x min:%x hour:%x mday:%x wday:%x mon:%x year:%x\n",
50         sec, min, hour, mday, wday, mon, year);
51 #endif
52 
53     /* disable access to RTC registers */
54     RTC_DISABLE
55 
56     ti->tm_sec      = BCD2BIN(sec  & 0x7F);
57     ti->tm_min      = BCD2BIN(min  & 0x7F);
58     ti->tm_hour     = BCD2BIN(hour & 0x3F);
59     ti->tm_mday     = BCD2BIN(mday & 0x3F);
60     ti->tm_mon      = BCD2BIN(mon & 0x1F);
61     ti->tm_year     = BCD2BIN(year);
62     ti->tm_wday     = BCD2BIN(wday & 0x07);
63     ti->tm_yday     = 0;
64     ti->tm_isdst    = 0;
65 }
66 
67 /**
68  * This function set rtc time
69  */
rt_hw_rtc_set(struct tm * ti)70 void rt_hw_rtc_set(struct tm *ti)
71 {
72     rt_uint8_t sec, min, hour, mday, wday, mon, year;
73 
74     year    = BIN2BCD(ti->tm_year);
75     mon     = BIN2BCD(ti->tm_mon);
76     wday    = BIN2BCD(ti->tm_wday);
77     mday    = BIN2BCD(ti->tm_mday);
78     hour    = BIN2BCD(ti->tm_hour);
79     min     = BIN2BCD(ti->tm_min);
80     sec     = BIN2BCD(ti->tm_sec);
81 
82     /* enable access to RTC registers */
83     RTC_ENABLE
84 
85     do{
86         /* write RTC registers */
87         BCDSEC      = sec;
88         BCDMIN      = min;
89         BCDHOUR     = hour;
90         BCDDATE     = mday;
91         BCDDAY      = wday;
92         BCDMON  = mon;
93         BCDYEAR     = year;
94     }while (sec != BCDSEC);
95 
96     /* disable access to RTC registers */
97     RTC_DISABLE
98 }
99 
100 /**
101  * This function reset rtc
102  */
rt_hw_rtc_reset(void)103 void rt_hw_rtc_reset (void)
104 {
105     RTCCON = (RTCCON & ~0x06) | 0x08;
106     RTCCON &= ~(0x08|0x01);
107 }
108 
109 static struct rt_device rtc;
rtc_open(rt_device_t dev,rt_uint16_t oflag)110 static rt_err_t rtc_open(rt_device_t dev, rt_uint16_t oflag)
111 {
112     RTC_ENABLE
113     return RT_EOK;
114 }
115 
rtc_close(rt_device_t dev)116 static rt_err_t rtc_close(rt_device_t dev)
117 {
118     RTC_DISABLE
119     return RT_EOK;
120 }
121 
rtc_read(rt_device_t dev,rt_off_t pos,void * buffer,rt_size_t size)122 static rt_ssize_t rtc_read(rt_device_t dev, rt_off_t pos, void* buffer, rt_size_t size)
123 {
124     return RT_EOK;
125 }
126 
rtc_control(rt_device_t dev,int cmd,void * args)127 static rt_err_t rtc_control(rt_device_t dev, int cmd, void *args)
128 {
129     struct tm tmp;
130     time_t *time;
131     RT_ASSERT(dev != RT_NULL);
132 
133     time = (time_t *)args;
134     switch (cmd)
135     {
136         case RT_DEVICE_CTRL_RTC_GET_TIME:
137             /* read device */
138             rt_hw_rtc_get(&tmp);
139             *((rt_time_t *)args) = timegm(&tmp);
140             break;
141 
142         case RT_DEVICE_CTRL_RTC_SET_TIME:
143             /* write device */
144             gmtime_r(time, &tmp);
145             rt_hw_rtc_set(&tmp);
146             break;
147     }
148 
149     return RT_EOK;
150 }
151 
rt_hw_rtc_init(void)152 void rt_hw_rtc_init(void)
153 {
154     rtc.type    = RT_Device_Class_RTC;
155 
156     /* register rtc device */
157     rtc.init    = RT_NULL;
158     rtc.open    = rtc_open;
159     rtc.close   = rtc_close;
160     rtc.read    = rtc_read;
161     rtc.write   = RT_NULL;
162     rtc.control = rtc_control;
163 
164     /* no private */
165     rtc.user_data = RT_NULL;
166 
167     rt_device_register(&rtc, "rtc", RT_DEVICE_FLAG_RDWR);
168 }
169 
170 #ifdef RT_USING_FINSH
171 #include <finsh.h>
list_date()172 void list_date()
173 {
174     time_t time;
175     rt_device_t device;
176 
177     device = rt_device_find("rtc");
178     if (device != RT_NULL)
179     {
180         rt_device_control(device, RT_DEVICE_CTRL_RTC_GET_TIME, &time);
181 
182         rt_kprintf("%d, %s\n", time, ctime(&time));
183     }
184 }
185 FINSH_FUNCTION_EXPORT(list_date, list date);
186 #endif
187 #endif
188