| /* |
| * 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. |
| * |
| * You should have received a copy of the GNU General Public License |
| * along with this program; if not, write to the Free Software |
| * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
| */ |
| |
| #include <linux/kernel.h> |
| #include <linux/time.h> |
| #include <linux/init.h> |
| #include <linux/rtc.h> |
| |
| #include <mach/hardware.h> |
| #include <asm/io.h> |
| #include <linux/rtc.h> |
| |
| #include "mvCommon.h" |
| #include "rtc/integ_rtc/mvRtc.h" |
| |
| #define FEBRUARY 2 |
| #define STARTOFTIME 1970 |
| #define SECDAY 86400L |
| #define SECYR (SECDAY * 365) |
| |
| /* |
| * Note: this is wrong for 2100, but our signed 32-bit time_t will |
| * have overflowed long before that, so who cares. -- paulus |
| */ |
| #define leapyear(year) ((year) % 4 == 0) |
| #define days_in_year(a) (leapyear(a) ? 366 : 365) |
| #define days_in_month(a) (month_days[(a) - 1]) |
| |
| static int month_days[12] = { |
| 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 |
| }; |
| |
| void to_tm(int tim, MV_RTC_TIME *tm) |
| { |
| register int i; |
| register long hms, day, gday; |
| |
| gday = day = tim / SECDAY; |
| hms = tim % SECDAY; |
| /* Hours, minutes, seconds are easy */ |
| tm->hours = hms / 3600; |
| tm->minutes = (hms % 3600) / 60; |
| tm->seconds = (hms % 3600) % 60; |
| |
| /* Number of years in days */ |
| for (i = STARTOFTIME; day >= days_in_year(i); i++) |
| day -= days_in_year(i); |
| tm->year = i; |
| |
| /* Number of months in days left */ |
| if (leapyear(tm->year)) |
| days_in_month(FEBRUARY) = 29; |
| for (i = 1; day >= days_in_month(i); i++) |
| day -= days_in_month(i); |
| days_in_month(FEBRUARY) = 28; |
| tm->month = i; |
| |
| /* Days are what is left over (+1) from all that. */ |
| tm->date = day + 1; |
| |
| /* |
| * Determine the day of week. Jan. 1, 1970 was a Thursday. |
| */ |
| tm->day = (gday + 4) % 7; |
| } |
| |
| |
| static int mv_set_rtc(void) |
| { |
| MV_RTC_TIME time; |
| to_tm(xtime.tv_sec, &time); |
| time.year -= 2000; |
| mvRtcTimeSet(&time); |
| |
| return 1; |
| } |
| |
| |
| extern int (*set_rtc)(void); |
| |
| static inline int mv_rtc_set_time(struct device *dev, struct rtc_time *tm) |
| { |
| MV_RTC_TIME time; |
| unsigned long temp_t; |
| |
| rtc_tm_to_time(tm, &temp_t); |
| to_tm(temp_t, &time); |
| /* same as in the U-Boot we use the year for century 20 only */ |
| time.year -= 2000; |
| mvRtcTimeSet(&time); |
| |
| return 0; |
| } |
| |
| static int mv_rtc_read_time(struct device *dev, struct rtc_time *tm) |
| { |
| MV_RTC_TIME time; |
| unsigned long temp_t; |
| |
| mvRtcTimeGet(&time); |
| /* same as in the U-Boot we use the year for century 20 only */ |
| temp_t = mktime ( time.year + 2000, time.month, |
| time.date, time.hours, |
| time.minutes, time.seconds); |
| rtc_time_to_tm(temp_t, tm); |
| |
| return 0; |
| } |
| |
| static struct rtc_class_ops rtc_ops = { |
| .read_time = mv_rtc_read_time, |
| .set_time = mv_rtc_set_time, |
| }; |
| |
| static int mv_rtc_init(void) |
| { |
| MV_RTC_TIME time; |
| struct timespec tv; |
| struct device *dev; |
| |
| mvRtcTimeGet(&time); |
| dev = device_create(rtc_class, NULL, -1, NULL, "mv_rtc"); |
| |
| /* Date which is not in the 21 century will stop the RTC on |
| 00:00:00 - 01/01/2000, write operation will trigger it */ |
| if ((time.year == 0) && (time.month == 1) && (time.date == 1)) { |
| mvRtcTimeSet(&time); |
| printk(KERN_INFO "RTC has been updated!!!\n"); |
| } |
| |
| tv.tv_nsec = 0; |
| /* same as in the U-Boot we use the year for century 20 only */ |
| tv.tv_sec = mktime ( time.year + 2000, time.month, |
| time.date, time.hours, |
| time.minutes, time.seconds); |
| do_settimeofday(&tv); |
| set_rtc = mv_set_rtc; |
| |
| rtc_device_register("kw-rtc", dev, &rtc_ops, THIS_MODULE); |
| printk("RTC registered\n"); |
| |
| return 0; |
| } |
| __initcall(mv_rtc_init); |