1 /*
2 * rtc_adapter.c
3 *
4 * rtc driver adapter of linux
5 *
6 * Copyright (c) 2020-2021 Huawei Device Co., Ltd.
7 *
8 * This software is licensed under the terms of the GNU General Public
9 * License version 2, as published by the Free Software Foundation, and
10 * may be copied, distributed, and modified under those terms.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 */
18
19 #include <linux/rtc.h>
20 #include "device_resource_if.h"
21 #include "hdf_device_desc.h"
22 #include "hdf_log.h"
23 #include "rtc_core.h"
24
25 #define HDF_LOG_TAG RTC_ADAPTER
26 #define MONTH_DIFF 1
27 #define YEAR_BASE 1900
28
HdfTimeToLinuxTime(const struct RtcTime * hdfTime,struct rtc_time * linuxTime)29 static inline void HdfTimeToLinuxTime(const struct RtcTime *hdfTime, struct rtc_time *linuxTime)
30 {
31 linuxTime->tm_sec = hdfTime->second;
32 linuxTime->tm_min = hdfTime->minute;
33 linuxTime->tm_hour = hdfTime->hour;
34 linuxTime->tm_mday = hdfTime->day;
35 linuxTime->tm_mon = hdfTime->month - MONTH_DIFF;
36 linuxTime->tm_year = hdfTime->year - YEAR_BASE;
37 linuxTime->tm_wday = hdfTime->weekday;
38 linuxTime->tm_yday = rtc_year_days(linuxTime->tm_mday, linuxTime->tm_mon, linuxTime->tm_year);
39 }
40
LinuxTimeToHdfTime(struct RtcTime * hdfTime,const struct rtc_time * linuxTime)41 static inline void LinuxTimeToHdfTime(struct RtcTime *hdfTime, const struct rtc_time *linuxTime)
42 {
43 hdfTime->second = linuxTime->tm_sec;
44 hdfTime->minute = linuxTime->tm_min;
45 hdfTime->hour = linuxTime->tm_hour;
46 hdfTime->day = linuxTime->tm_mday;
47 hdfTime->month = linuxTime->tm_mon + MONTH_DIFF;
48 hdfTime->year = linuxTime->tm_year + YEAR_BASE;
49 hdfTime->weekday = linuxTime->tm_wday;
50 }
51
HdfGetRtcDevice(void)52 static inline struct rtc_device *HdfGetRtcDevice(void)
53 {
54 struct rtc_device *dev = rtc_class_open(CONFIG_RTC_SYSTOHC_DEVICE);
55
56 if (dev == NULL) {
57 HDF_LOGE("%s: failed to get rtc device", __func__);
58 }
59 return dev;
60 }
61
HdfPutRtcDevice(struct rtc_device * dev)62 static inline void HdfPutRtcDevice(struct rtc_device *dev)
63 {
64 rtc_class_close(dev);
65 }
66
HiRtcReadTime(struct RtcHost * host,struct RtcTime * hdfTime)67 static int32_t HiRtcReadTime(struct RtcHost *host, struct RtcTime *hdfTime)
68 {
69 int32_t ret;
70 struct rtc_time linuxTime = {0};
71 struct rtc_device *dev = HdfGetRtcDevice();
72
73 (void)host;
74 if (dev == NULL) {
75 return HDF_FAILURE;
76 }
77 ret = rtc_read_time(dev, &linuxTime);
78 if (ret < 0) {
79 HDF_LOGE("%s: rtc_read_time error, ret is %d", __func__, ret);
80 return ret;
81 }
82 HdfPutRtcDevice(dev);
83 LinuxTimeToHdfTime(hdfTime, &linuxTime);
84 return HDF_SUCCESS;
85 }
86
HiRtcWriteTime(struct RtcHost * host,const struct RtcTime * hdfTime)87 static int32_t HiRtcWriteTime(struct RtcHost *host, const struct RtcTime *hdfTime)
88 {
89 int32_t ret;
90 struct rtc_time linuxTime = {0};
91 struct rtc_device *dev = HdfGetRtcDevice();
92
93 (void)host;
94 if (dev == NULL) {
95 return HDF_FAILURE;
96 }
97 HdfTimeToLinuxTime(hdfTime, &linuxTime);
98 ret = rtc_set_time(dev, &linuxTime);
99 if (ret < 0) {
100 HDF_LOGE("%s: rtc_set_time error, ret is %d", __func__, ret);
101 return ret;
102 }
103
104 HdfPutRtcDevice(dev);
105 return HDF_SUCCESS;
106 }
107
HiReadAlarm(struct RtcHost * host,enum RtcAlarmIndex alarmIndex,struct RtcTime * hdfTime)108 static int32_t HiReadAlarm(struct RtcHost *host, enum RtcAlarmIndex alarmIndex, struct RtcTime *hdfTime)
109 {
110 int32_t ret;
111 struct rtc_wkalrm alarm = {0};
112 struct rtc_device *dev = HdfGetRtcDevice();
113
114 (void)host;
115 (void)alarmIndex;
116 if (dev == NULL) {
117 return HDF_FAILURE;
118 }
119 ret = rtc_read_alarm(dev, &alarm);
120 if (ret < 0) {
121 HDF_LOGE("%s: rtc_read_alarm error, ret is %d", __func__, ret);
122 return ret;
123 }
124
125 LinuxTimeToHdfTime(hdfTime, &(alarm.time));
126 HdfPutRtcDevice(dev);
127 return HDF_SUCCESS;
128 }
129
HiWriteAlarm(struct RtcHost * host,enum RtcAlarmIndex alarmIndex,const struct RtcTime * hdfTime)130 static int32_t HiWriteAlarm(struct RtcHost *host, enum RtcAlarmIndex alarmIndex, const struct RtcTime *hdfTime)
131 {
132 int32_t ret;
133 struct rtc_wkalrm alarm = {0};
134 struct rtc_device *dev = HdfGetRtcDevice();
135
136 (void)host;
137 (void)alarmIndex;
138 if (dev == NULL) {
139 return HDF_FAILURE;
140 }
141
142 HdfTimeToLinuxTime(hdfTime, &(alarm.time));
143 alarm.enabled = 0;
144 ret = rtc_set_alarm(dev, &alarm);
145 if (ret < 0) {
146 HDF_LOGE("%s: rtc_read_alarm error, ret is %d", __func__, ret);
147 return ret;
148 }
149
150 HdfPutRtcDevice(dev);
151 return HDF_SUCCESS;
152 }
153
HiAlarmInterruptEnable(struct RtcHost * host,enum RtcAlarmIndex alarmIndex,uint8_t enable)154 static int32_t HiAlarmInterruptEnable(struct RtcHost *host, enum RtcAlarmIndex alarmIndex, uint8_t enable)
155 {
156 int32_t ret;
157 struct rtc_device *dev = HdfGetRtcDevice();
158
159 (void)host;
160 (void)alarmIndex;
161 if (dev == NULL) {
162 return HDF_FAILURE;
163 }
164 ret = rtc_alarm_irq_enable(dev, enable);
165 if (ret < 0) {
166 HDF_LOGE("%s: rtc_read_alarm error, ret is %d", __func__, ret);
167 return ret;
168 }
169
170 HdfPutRtcDevice(dev);
171 return HDF_SUCCESS;
172 }
173
174 static struct RtcMethod g_method = {
175 .ReadTime = HiRtcReadTime,
176 .WriteTime = HiRtcWriteTime,
177 .ReadAlarm = HiReadAlarm,
178 .WriteAlarm = HiWriteAlarm,
179 .RegisterAlarmCallback = NULL,
180 .AlarmInterruptEnable = HiAlarmInterruptEnable,
181 .GetFreq = NULL,
182 .SetFreq = NULL,
183 .Reset = NULL,
184 .ReadReg = NULL,
185 .WriteReg = NULL,
186 };
187
HiRtcBind(struct HdfDeviceObject * device)188 static int32_t HiRtcBind(struct HdfDeviceObject *device)
189 {
190 struct RtcHost *host = NULL;
191
192 host = RtcHostCreate(device);
193 if (host == NULL) {
194 HDF_LOGE("%s: create host fail", __func__);
195 return HDF_ERR_INVALID_OBJECT;
196 }
197
198 host->device = device;
199 device->service = &host->service;
200 return HDF_SUCCESS;
201 }
202
HiRtcInit(struct HdfDeviceObject * device)203 static int32_t HiRtcInit(struct HdfDeviceObject *device)
204 {
205 struct RtcHost *host = NULL;
206
207 if (device == NULL) {
208 HDF_LOGE("%s: err, device is null", __func__);
209 return HDF_ERR_INVALID_OBJECT;
210 }
211 host = RtcHostFromDevice(device);
212 host->method = &g_method;
213 HDF_LOGI("%s: Hdf dev service:%s init success", __func__, HdfDeviceGetServiceName(device));
214 return HDF_SUCCESS;
215 }
216
HiRtcRelease(struct HdfDeviceObject * device)217 static void HiRtcRelease(struct HdfDeviceObject *device)
218 {
219 struct RtcHost *host = NULL;
220
221 if (device == NULL) {
222 return;
223 }
224
225 host = RtcHostFromDevice(device);
226 RtcHostDestroy(host);
227 }
228
229 struct HdfDriverEntry g_rtcDriverEntry = {
230 .moduleVersion = 1,
231 .Bind = HiRtcBind,
232 .Init = HiRtcInit,
233 .Release = HiRtcRelease,
234 .moduleName = "HDF_PLATFORM_RTC",
235 };
236
237 HDF_INIT(g_rtcDriverEntry);
238