* rtc_adapter.c
*
* rtc driver adapter of linux
*
* Copyright (c) 2020-2021 Huawei Device Co., Ltd.
*
* This software is licensed under the terms of the GNU General Public
* License version 2, as published by the Free Software Foundation, and
* may be copied, distributed, and modified under those terms.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
*/
#include <linux/rtc.h>
#include "device_resource_if.h"
#include "hdf_device_desc.h"
#include "hdf_log.h"
#include "rtc_core.h"
#define HDF_LOG_TAG RTC_ADAPTER
#define MONTH_DIFF 1
#define YEAR_BASE 1900
static inline void HdfTimeToLinuxTime(const struct RtcTime *hdfTime, struct rtc_time *linuxTime)
{
linuxTime->tm_sec = hdfTime->second;
linuxTime->tm_min = hdfTime->minute;
linuxTime->tm_hour = hdfTime->hour;
linuxTime->tm_mday = hdfTime->day;
linuxTime->tm_mon = hdfTime->month - MONTH_DIFF;
linuxTime->tm_year = hdfTime->year - YEAR_BASE;
linuxTime->tm_wday = hdfTime->weekday;
linuxTime->tm_yday = rtc_year_days(linuxTime->tm_mday, linuxTime->tm_mon, linuxTime->tm_year);
}
static inline void LinuxTimeToHdfTime(struct RtcTime *hdfTime, const struct rtc_time *linuxTime)
{
hdfTime->second = linuxTime->tm_sec;
hdfTime->minute = linuxTime->tm_min;
hdfTime->hour = linuxTime->tm_hour;
hdfTime->day = linuxTime->tm_mday;
hdfTime->month = linuxTime->tm_mon + MONTH_DIFF;
hdfTime->year = linuxTime->tm_year + YEAR_BASE;
hdfTime->weekday = linuxTime->tm_wday;
}
static inline struct rtc_device *HdfGetRtcDevice(void)
{
struct rtc_device *dev = rtc_class_open(CONFIG_RTC_SYSTOHC_DEVICE);
if (dev == NULL) {
HDF_LOGE("%s: failed to get rtc device", __func__);
}
return dev;
}
static inline void HdfPutRtcDevice(struct rtc_device *dev)
{
rtc_class_close(dev);
}
static int32_t HiRtcReadTime(struct RtcHost *host, struct RtcTime *hdfTime)
{
int32_t ret;
struct rtc_time linuxTime = {0};
struct rtc_device *dev = HdfGetRtcDevice();
(void)host;
if (dev == NULL) {
return HDF_FAILURE;
}
ret = rtc_read_time(dev, &linuxTime);
if (ret < 0) {
HDF_LOGE("%s: rtc_read_time error, ret is %d", __func__, ret);
return ret;
}
HdfPutRtcDevice(dev);
LinuxTimeToHdfTime(hdfTime, &linuxTime);
return HDF_SUCCESS;
}
static int32_t HiRtcWriteTime(struct RtcHost *host, const struct RtcTime *hdfTime)
{
int32_t ret;
struct rtc_time linuxTime = {0};
struct rtc_device *dev = HdfGetRtcDevice();
(void)host;
if (dev == NULL) {
return HDF_FAILURE;
}
HdfTimeToLinuxTime(hdfTime, &linuxTime);
ret = rtc_set_time(dev, &linuxTime);
if (ret < 0) {
HDF_LOGE("%s: rtc_set_time error, ret is %d", __func__, ret);
return ret;
}
HdfPutRtcDevice(dev);
return HDF_SUCCESS;
}
static int32_t HiReadAlarm(struct RtcHost *host, enum RtcAlarmIndex alarmIndex, struct RtcTime *hdfTime)
{
int32_t ret;
struct rtc_wkalrm alarm = {0};
struct rtc_device *dev = HdfGetRtcDevice();
(void)host;
(void)alarmIndex;
if (dev == NULL) {
return HDF_FAILURE;
}
ret = rtc_read_alarm(dev, &alarm);
if (ret < 0) {
HDF_LOGE("%s: rtc_read_alarm error, ret is %d", __func__, ret);
return ret;
}
LinuxTimeToHdfTime(hdfTime, &(alarm.time));
HdfPutRtcDevice(dev);
return HDF_SUCCESS;
}
static int32_t HiWriteAlarm(struct RtcHost *host, enum RtcAlarmIndex alarmIndex, const struct RtcTime *hdfTime)
{
int32_t ret;
struct rtc_wkalrm alarm = {0};
struct rtc_device *dev = HdfGetRtcDevice();
(void)host;
(void)alarmIndex;
if (dev == NULL) {
return HDF_FAILURE;
}
HdfTimeToLinuxTime(hdfTime, &(alarm.time));
alarm.enabled = 0;
ret = rtc_set_alarm(dev, &alarm);
if (ret < 0) {
HDF_LOGE("%s: rtc_read_alarm error, ret is %d", __func__, ret);
return ret;
}
HdfPutRtcDevice(dev);
return HDF_SUCCESS;
}
static int32_t HiAlarmInterruptEnable(struct RtcHost *host, enum RtcAlarmIndex alarmIndex, uint8_t enable)
{
int32_t ret;
struct rtc_device *dev = HdfGetRtcDevice();
(void)host;
(void)alarmIndex;
if (dev == NULL) {
return HDF_FAILURE;
}
ret = rtc_alarm_irq_enable(dev, enable);
if (ret < 0) {
HDF_LOGE("%s: rtc_read_alarm error, ret is %d", __func__, ret);
return ret;
}
HdfPutRtcDevice(dev);
return HDF_SUCCESS;
}
static struct RtcMethod g_method = {
.ReadTime = HiRtcReadTime,
.WriteTime = HiRtcWriteTime,
.ReadAlarm = HiReadAlarm,
.WriteAlarm = HiWriteAlarm,
.RegisterAlarmCallback = NULL,
.AlarmInterruptEnable = HiAlarmInterruptEnable,
.GetFreq = NULL,
.SetFreq = NULL,
.Reset = NULL,
.ReadReg = NULL,
.WriteReg = NULL,
};
static int32_t HiRtcBind(struct HdfDeviceObject *device)
{
struct RtcHost *host = NULL;
host = RtcHostCreate(device);
if (host == NULL) {
HDF_LOGE("%s: create host fail", __func__);
return HDF_ERR_INVALID_OBJECT;
}
host->device = device;
device->service = &host->service;
return HDF_SUCCESS;
}
static int32_t HiRtcInit(struct HdfDeviceObject *device)
{
struct RtcHost *host = NULL;
if (device == NULL) {
HDF_LOGE("%s: err, device is null", __func__);
return HDF_ERR_INVALID_OBJECT;
}
host = RtcHostFromDevice(device);
host->method = &g_method;
HDF_LOGI("%s: Hdf dev service:%s init success", __func__, HdfDeviceGetServiceName(device));
return HDF_SUCCESS;
}
static void HiRtcRelease(struct HdfDeviceObject *device)
{
struct RtcHost *host = NULL;
if (device == NULL) {
return;
}
host = RtcHostFromDevice(device);
RtcHostDestroy(host);
}
struct HdfDriverEntry g_rtcDriverEntry = {
.moduleVersion = 1,
.Bind = HiRtcBind,
.Init = HiRtcInit,
.Release = HiRtcRelease,
.moduleName = "HDF_PLATFORM_RTC",
};
HDF_INIT(g_rtcDriverEntry);