1 /*
2 * Copyright (c) 2019 Winner Microelectronics Co., Ltd.
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 *
6 * Change Logs:
7 * Date Author Notes
8 * 2018-09-15 flyingcys 1st version
9 * 2019-03-01 fanwenl add alarm
10 */
11
12 #include <rtdevice.h>
13 #include <rtthread.h>
14 #include <sys/time.h>
15 #include "wm_regs.h"
16 #include "wm_irq.h"
17 #include "tls_common.h"
18 #include "wm_rtc.h"
19 #include "drv_rtc.h"
20
21 #ifdef BSP_USING_RTC
22
23 #if defined(RT_USING_SOFT_RTC)
24 #error "Please CANCEL the RT_USING_SOFT_RTC option. Make sure there is only one RTC device on the system."
25 #endif
26
27 static struct rt_rtc_device rtc_device;
28
wm_get_timestamp(void)29 static time_t wm_get_timestamp(void)
30 {
31 struct tm tm_new = {0};
32
33 int ctrl1 = 0;
34 int ctrl2 = 0;
35
36 ctrl1 = tls_reg_read32(HR_PMU_RTC_CTRL1);
37 ctrl2 = tls_reg_read32(HR_PMU_RTC_CTRL2);
38 tm_new.tm_year = ((int)((int)ctrl2 & 0x00007f00) >> 8);
39 tm_new.tm_mon = (ctrl2 & 0x0000000f);
40 tm_new.tm_mday = (ctrl1 & 0x1f000000) >> 24;
41 tm_new.tm_hour = (ctrl1 & 0x001f0000) >> 16;
42 tm_new.tm_min = (ctrl1 & 0x00003f00) >> 8;
43 tm_new.tm_sec = ctrl1 & 0x0000003f;
44
45 return timegm(&tm_new);
46 }
47
wm_set_timestamp(time_t timestamp)48 static int wm_set_timestamp(time_t timestamp)
49 {
50 int ctrl1 = 0;
51 int ctrl2 = 0;
52
53 struct tm tblock;
54
55 gmtime_r(×tamp, &tblock);
56
57 ctrl2 = tls_reg_read32(HR_PMU_RTC_CTRL2); /* disable */
58 ctrl2 &= ~(1 << 16);
59 tls_reg_write32(HR_PMU_RTC_CTRL2, ctrl2);
60
61 ctrl1 |= tblock.tm_sec;
62 ctrl1 |= tblock.tm_min << 8;
63 ctrl1 |= tblock.tm_hour << 16;
64 ctrl1 |= tblock.tm_mday << 24;
65 tls_reg_write32(HR_PMU_RTC_CTRL1, ctrl1);
66
67 ctrl2 = 0;
68 ctrl2 |= tblock.tm_mon;
69 ctrl2 |= tblock.tm_year << 8;
70 tls_reg_write32(HR_PMU_RTC_CTRL2, ctrl2);
71
72 ctrl2 = tls_reg_read32(HR_PMU_RTC_CTRL2);/* enable */
73 ctrl2 |= (1 << 16);
74 tls_reg_write32(HR_PMU_RTC_CTRL2, ctrl2);
75
76 return RT_EOK;
77 }
78 #ifdef BSP_USING_ALARM
wm_alarm_set_timestamp(struct rt_rtc_wkalarm * wkalarm)79 static int wm_alarm_set_timestamp(struct rt_rtc_wkalarm *wkalarm)
80 {
81 int ctrl1 = 0;
82 int ctrl2 = 0;
83 struct tm tblock;
84 time_t timestamp = 0;
85
86 timestamp = wm_get_timestamp();
87 gmtime_r(×tamp, &tblock);
88
89 tls_irq_enable(PMU_RTC_INT);
90
91 ctrl1 |= wkalarm->tm_sec;
92 ctrl1 |= wkalarm->tm_min << 8;
93 ctrl1 |= wkalarm->tm_hour << 16;
94 ctrl1 |= tblock.tm_mday << 24;
95
96 ctrl2 |= tblock.tm_mon;
97 ctrl2 |= tblock.tm_year << 8;
98
99 tls_reg_write32(HR_PMU_RTC_CTRL2, ctrl2 | BIT(16));
100
101 tls_reg_write32(HR_PMU_RTC_CTRL1, ctrl1 | BIT(31));/* must set the enable */
102
103 return RT_EOK;
104 }
105
wm_rtc_alarm_callback(void * arg)106 static void wm_rtc_alarm_callback(void *arg)
107 {
108 rt_alarm_update(0, 0);
109 }
110 #endif
wm_rtc_init(rt_device_t dev)111 static rt_err_t wm_rtc_init(rt_device_t dev)
112 {
113 wm_set_timestamp((time_t)0);
114
115 #ifdef BSP_USING_ALARM
116 tls_rtc_isr_register(wm_rtc_alarm_callback, (void *)0);
117 #endif
118 return RT_EOK;
119 }
120
wm_rtc_open(rt_device_t dev,rt_uint16_t oflag)121 static rt_err_t wm_rtc_open(rt_device_t dev, rt_uint16_t oflag)
122 {
123 return RT_EOK;
124 }
125
wm_rtc_close(rt_device_t dev)126 static rt_err_t wm_rtc_close(rt_device_t dev)
127 {
128 return RT_EOK;
129 }
130
wm_rtc_control(rt_device_t dev,int cmd,void * args)131 static rt_err_t wm_rtc_control(rt_device_t dev, int cmd, void *args)
132 {
133 #ifdef BSP_USING_ALARM
134 struct rt_rtc_device* rtc_device;
135 rtc_device = (struct rt_rtc_device* )dev;
136 #endif
137 RT_ASSERT(dev != RT_NULL);
138
139 switch (cmd)
140 {
141 case RT_DEVICE_CTRL_RTC_GET_TIME:
142 *(rt_uint32_t *)args = wm_get_timestamp();
143 break;
144 case RT_DEVICE_CTRL_RTC_SET_TIME:
145 wm_set_timestamp(*(time_t *)args);
146 break;
147 #ifdef BSP_USING_ALARM
148 case RT_DEVICE_CTRL_RTC_GET_ALARM:
149 *(struct rt_rtc_wkalarm *)args = rtc_device->wkalarm;
150 return RT_EOK;
151 case RT_DEVICE_CTRL_RTC_SET_ALARM:
152 rtc_device->wkalarm = *(struct rt_rtc_wkalarm *)args;
153 wm_alarm_set_timestamp(&rtc_device->wkalarm);
154 break;
155 #endif
156 default:
157 return -RT_EINVAL;
158 }
159 return RT_EOK;
160 }
161
wm_rtc_read(rt_device_t dev,rt_off_t pos,void * buffer,rt_size_t size)162 static rt_ssize_t wm_rtc_read(rt_device_t dev, rt_off_t pos, void *buffer, rt_size_t size)
163 {
164 wm_rtc_control(dev, RT_DEVICE_CTRL_RTC_GET_TIME, buffer);
165 return size;
166 }
167
wm_rtc_write(rt_device_t dev,rt_off_t pos,const void * buffer,rt_size_t size)168 static rt_ssize_t wm_rtc_write(rt_device_t dev, rt_off_t pos, const void *buffer, rt_size_t size)
169 {
170 wm_rtc_control(dev, RT_DEVICE_CTRL_RTC_SET_TIME, (void *)buffer);
171 return size;
172 }
173
174 #ifdef RT_USING_DEVICE_OPS
175 const static struct rt_device_ops _ops =
176 {
177 .init = wm_rtc_init,
178 .open = wm_rtc_open,
179 .close = wm_rtc_close,
180 .read = wm_rtc_read,
181 .write = wm_rtc_write,
182 .control = wm_rtc_control
183 };
184 #endif
185
wm_hw_rtc_init(void)186 int wm_hw_rtc_init(void)
187 {
188 rt_memset(&rtc_device, 0, sizeof(rtc_device));
189
190 rtc_device.device.type = RT_Device_Class_RTC;
191 rtc_device.device.rx_indicate = RT_NULL;
192 rtc_device.device.tx_complete = RT_NULL;
193
194 #ifdef RT_USING_DEVICE_OPS
195 rtc_device.ops = &_ops;
196 #else
197 rtc_device.device.init = wm_rtc_init;
198 rtc_device.device.open = wm_rtc_open;
199 rtc_device.device.close = wm_rtc_close;
200 rtc_device.device.read = wm_rtc_read;
201 rtc_device.device.write = wm_rtc_write;
202 rtc_device.device.control = wm_rtc_control;
203 #endif
204 rtc_device.device.user_data = RT_NULL;
205
206 /* register a rtc device */
207 rt_device_register(&rtc_device.device, "rtc", RT_DEVICE_FLAG_RDWR);
208
209 return 0;
210 }
211 INIT_DEVICE_EXPORT(wm_hw_rtc_init);
212 #endif /* BSP_USING_RTC */
213