diff --git a/drivers/Kconfig b/drivers/Kconfig index 12a9d8c..d38032c 100644 --- a/drivers/Kconfig +++ b/drivers/Kconfig @@ -28,5 +28,6 @@ source "drivers/regulator/Kconfig" source "drivers/reset/Kconfig" source "drivers/pci/Kconfig" +source "drivers/rtc/Kconfig" endmenu diff --git a/drivers/Makefile b/drivers/Makefile index 1990e86..4591f9a 100644 --- a/drivers/Makefile +++ b/drivers/Makefile @@ -27,3 +27,4 @@ obj-$(CONFIG_REGULATOR) += regulator/ obj-$(CONFIG_RESET_CONTROLLER) += reset/ obj-$(CONFIG_PCI) += pci/ +obj-y += rtc/ diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig new file mode 100644 index 0000000..5401503 --- /dev/null +++ b/drivers/rtc/Kconfig @@ -0,0 +1,15 @@ +# +# RTC class/drivers configuration +# + +config RTC_LIB + bool + +menuconfig RTC_CLASS + bool "Real Time Clock" + default n + select RTC_LIB + help + Generic RTC class support. If you say yes here, you will + be allowed to plug one or more RTCs to your system. You will + probably want to enable one or more of the interfaces below. diff --git a/drivers/rtc/Makefile b/drivers/rtc/Makefile new file mode 100644 index 0000000..7d1b5bc --- /dev/null +++ b/drivers/rtc/Makefile @@ -0,0 +1,6 @@ +# +# Makefile for RTC class/drivers. +# + +obj-$(CONFIG_RTC_LIB) += rtc-lib.o +obj-$(CONFIG_RTC_CLASS) += class.o diff --git a/drivers/rtc/class.c b/drivers/rtc/class.c new file mode 100644 index 0000000..356707b --- /dev/null +++ b/drivers/rtc/class.c @@ -0,0 +1,70 @@ +/* + * RTC barebox subsystem, base class + * + * Copyright (C) 2014 Antony Pavlov + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * 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 +#include +#include + +LIST_HEAD(rtc_list); +EXPORT_SYMBOL(rtc_list); + +struct rtc_device *rtc_lookup(const char *name) +{ + struct rtc_device *r; + + if (!name) + return ERR_PTR(-ENODEV); + + list_for_each_entry(r, &rtc_list, list) { + if (!strcmp(dev_name(&r->class_dev), name)) + return r; + } + + return ERR_PTR(-ENODEV); +} +EXPORT_SYMBOL(rtc_lookup); + +int rtc_read_time(struct rtc_device *rtc, struct rtc_time *tm) +{ + return rtc->ops->read_time(rtc, tm); +} +EXPORT_SYMBOL(rtc_read_time); + +int rtc_set_time(struct rtc_device *rtc, struct rtc_time *tm) +{ + return rtc->ops->set_time(rtc, tm); +} +EXPORT_SYMBOL(rtc_set_time); + +int rtc_register(struct rtc_device *rtcdev) +{ + struct device_d *dev = &rtcdev->class_dev; + + if (!rtcdev->ops) + return -EINVAL; + + dev->id = DEVICE_ID_DYNAMIC; + strcpy(dev->name, "rtc"); + if (rtcdev->dev) + dev->parent = rtcdev->dev; + platform_device_register(dev); + + list_add_tail(&rtcdev->list, &rtc_list); + + return 0; +} +EXPORT_SYMBOL(rtc_register); diff --git a/drivers/rtc/rtc-lib.c b/drivers/rtc/rtc-lib.c new file mode 100644 index 0000000..0d6acde --- /dev/null +++ b/drivers/rtc/rtc-lib.c @@ -0,0 +1,68 @@ +/* + * rtc and date/time utility functions + * + * This code was ported from linux-3.15 kernel by Antony Pavlov. + * + * Copyright (C) 2005-06 Tower Technologies + * Author: Alessandro Zummo + * + * based on arch/arm/common/rtctime.c and other bits + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. +*/ + +#include +#include + +static const unsigned char rtc_days_in_month[] = { + 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 +}; + +static const unsigned short rtc_ydays[2][13] = { + /* Normal years */ + { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365 }, + /* Leap years */ + { 0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335, 366 } +}; + +#define LEAPS_THRU_END_OF(y) ((y)/4 - (y)/100 + (y)/400) + +/* + * The number of days in the month. + */ +int rtc_month_days(unsigned int month, unsigned int year) +{ + return rtc_days_in_month[month] + (is_leap_year(year) && month == 1); +} +EXPORT_SYMBOL(rtc_month_days); + +/* + * Does the rtc_time represent a valid date/time? + */ +int rtc_valid_tm(struct rtc_time *tm) +{ + if (tm->tm_year < 70 + || ((unsigned)tm->tm_mon) >= 12 + || tm->tm_mday < 1 + || tm->tm_mday > rtc_month_days(tm->tm_mon, tm->tm_year + 1900) + || ((unsigned)tm->tm_hour) >= 24 + || ((unsigned)tm->tm_min) >= 60 + || ((unsigned)tm->tm_sec) >= 60) + return -EINVAL; + + return 0; +} +EXPORT_SYMBOL(rtc_valid_tm); + +/* + * Convert Gregorian date to seconds since 01-01-1970 00:00:00. + */ +int rtc_tm_to_time(struct rtc_time *tm, unsigned long *time) +{ + *time = mktime(tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday, + tm->tm_hour, tm->tm_min, tm->tm_sec); + return 0; +} +EXPORT_SYMBOL(rtc_tm_to_time); diff --git a/include/linux/rtc.h b/include/linux/rtc.h new file mode 100644 index 0000000..2e034f6 --- /dev/null +++ b/include/linux/rtc.h @@ -0,0 +1,46 @@ +/* + * Generic RTC interface. + * This version contains the part of the user interface to the Real Time Clock + * service. It is used with both the legacy mc146818 and also EFI + * Struct rtc_time and first 12 ioctl by Paul Gortmaker, 1996 - separated out + * from to this file for 2.4 kernels. + * + * Copyright (C) 1999 Hewlett-Packard Co. + * Copyright (C) 1999 Stephane Eranian + */ +#ifndef _LINUX_RTC_H_ +#define _LINUX_RTC_H_ + +#include +#include + +extern int rtc_month_days(unsigned int month, unsigned int year); +extern int rtc_valid_tm(struct rtc_time *tm); +extern int rtc_tm_to_time(struct rtc_time *tm, unsigned long *time); + +struct rtc_class_ops; + +struct rtc_device { + struct device_d *dev; + struct device_d class_dev; + struct list_head list; + + const struct rtc_class_ops *ops; +}; + +struct rtc_class_ops { + int (*read_time)(struct rtc_device *, struct rtc_time *); + int (*set_time)(struct rtc_device *, struct rtc_time *); +}; + +extern int rtc_register(struct rtc_device *rtcdev); + +extern int rtc_read_time(struct rtc_device *rtc, struct rtc_time *tm); +extern int rtc_set_time(struct rtc_device *rtc, struct rtc_time *tm); + +static inline bool is_leap_year(unsigned int year) +{ + return (!(year % 4) && (year % 100)) || !(year % 400); +} + +#endif /* _LINUX_RTC_H_ */ diff --git a/include/rtc.h b/include/rtc.h index c2d8bce..e2414fb 100644 --- a/include/rtc.h +++ b/include/rtc.h @@ -53,4 +53,6 @@ unsigned long mktime (unsigned int, unsigned int, unsigned int, unsigned int, unsigned int, unsigned int); +extern struct rtc_device *rtc_lookup(const char *name); + #endif /* _RTC_H_ */