1c58411e95d7f5062dedd1a3064af4d359da1e633Alessandro Zummo/*
2c58411e95d7f5062dedd1a3064af4d359da1e633Alessandro Zummo * rtc and date/time utility functions
3c58411e95d7f5062dedd1a3064af4d359da1e633Alessandro Zummo *
4c58411e95d7f5062dedd1a3064af4d359da1e633Alessandro Zummo * Copyright (C) 2005-06 Tower Technologies
5c58411e95d7f5062dedd1a3064af4d359da1e633Alessandro Zummo * Author: Alessandro Zummo <a.zummo@towertech.it>
6c58411e95d7f5062dedd1a3064af4d359da1e633Alessandro Zummo *
7c58411e95d7f5062dedd1a3064af4d359da1e633Alessandro Zummo * based on arch/arm/common/rtctime.c and other bits
8c58411e95d7f5062dedd1a3064af4d359da1e633Alessandro Zummo *
9c58411e95d7f5062dedd1a3064af4d359da1e633Alessandro Zummo * This program is free software; you can redistribute it and/or modify
10c58411e95d7f5062dedd1a3064af4d359da1e633Alessandro Zummo * it under the terms of the GNU General Public License version 2 as
11c58411e95d7f5062dedd1a3064af4d359da1e633Alessandro Zummo * published by the Free Software Foundation.
12c58411e95d7f5062dedd1a3064af4d359da1e633Alessandro Zummo*/
13c58411e95d7f5062dedd1a3064af4d359da1e633Alessandro Zummo
14c58411e95d7f5062dedd1a3064af4d359da1e633Alessandro Zummo#include <linux/module.h>
15c58411e95d7f5062dedd1a3064af4d359da1e633Alessandro Zummo#include <linux/rtc.h>
16c58411e95d7f5062dedd1a3064af4d359da1e633Alessandro Zummo
17c58411e95d7f5062dedd1a3064af4d359da1e633Alessandro Zummostatic const unsigned char rtc_days_in_month[] = {
18c58411e95d7f5062dedd1a3064af4d359da1e633Alessandro Zummo	31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
19c58411e95d7f5062dedd1a3064af4d359da1e633Alessandro Zummo};
20c58411e95d7f5062dedd1a3064af4d359da1e633Alessandro Zummo
218232212e0b4ee4eb3e407f5a9b098f6377820164Andrew Victorstatic const unsigned short rtc_ydays[2][13] = {
228232212e0b4ee4eb3e407f5a9b098f6377820164Andrew Victor	/* Normal years */
238232212e0b4ee4eb3e407f5a9b098f6377820164Andrew Victor	{ 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365 },
248232212e0b4ee4eb3e407f5a9b098f6377820164Andrew Victor	/* Leap years */
258232212e0b4ee4eb3e407f5a9b098f6377820164Andrew Victor	{ 0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335, 366 }
268232212e0b4ee4eb3e407f5a9b098f6377820164Andrew Victor};
278232212e0b4ee4eb3e407f5a9b098f6377820164Andrew Victor
28c58411e95d7f5062dedd1a3064af4d359da1e633Alessandro Zummo#define LEAPS_THRU_END_OF(y) ((y)/4 - (y)/100 + (y)/400)
29c58411e95d7f5062dedd1a3064af4d359da1e633Alessandro Zummo
308232212e0b4ee4eb3e407f5a9b098f6377820164Andrew Victor/*
318232212e0b4ee4eb3e407f5a9b098f6377820164Andrew Victor * The number of days in the month.
328232212e0b4ee4eb3e407f5a9b098f6377820164Andrew Victor */
33c58411e95d7f5062dedd1a3064af4d359da1e633Alessandro Zummoint rtc_month_days(unsigned int month, unsigned int year)
34c58411e95d7f5062dedd1a3064af4d359da1e633Alessandro Zummo{
3578d89ef40c2ff7265df077e20c4d76be7d415204Andrew Morton	return rtc_days_in_month[month] + (is_leap_year(year) && month == 1);
36c58411e95d7f5062dedd1a3064af4d359da1e633Alessandro Zummo}
37c58411e95d7f5062dedd1a3064af4d359da1e633Alessandro ZummoEXPORT_SYMBOL(rtc_month_days);
38c58411e95d7f5062dedd1a3064af4d359da1e633Alessandro Zummo
39c58411e95d7f5062dedd1a3064af4d359da1e633Alessandro Zummo/*
408232212e0b4ee4eb3e407f5a9b098f6377820164Andrew Victor * The number of days since January 1. (0 to 365)
418232212e0b4ee4eb3e407f5a9b098f6377820164Andrew Victor */
428232212e0b4ee4eb3e407f5a9b098f6377820164Andrew Victorint rtc_year_days(unsigned int day, unsigned int month, unsigned int year)
438232212e0b4ee4eb3e407f5a9b098f6377820164Andrew Victor{
4478d89ef40c2ff7265df077e20c4d76be7d415204Andrew Morton	return rtc_ydays[is_leap_year(year)][month] + day-1;
458232212e0b4ee4eb3e407f5a9b098f6377820164Andrew Victor}
468232212e0b4ee4eb3e407f5a9b098f6377820164Andrew VictorEXPORT_SYMBOL(rtc_year_days);
478232212e0b4ee4eb3e407f5a9b098f6377820164Andrew Victor
488232212e0b4ee4eb3e407f5a9b098f6377820164Andrew Victor/*
49c58411e95d7f5062dedd1a3064af4d359da1e633Alessandro Zummo * Convert seconds since 01-01-1970 00:00:00 to Gregorian date.
50c58411e95d7f5062dedd1a3064af4d359da1e633Alessandro Zummo */
51c58411e95d7f5062dedd1a3064af4d359da1e633Alessandro Zummovoid rtc_time_to_tm(unsigned long time, struct rtc_time *tm)
52c58411e95d7f5062dedd1a3064af4d359da1e633Alessandro Zummo{
5373442daf2ea85e2a779396b76b1a39b10188ecb5Jan Altenberg	unsigned int month, year;
5473442daf2ea85e2a779396b76b1a39b10188ecb5Jan Altenberg	int days;
55c58411e95d7f5062dedd1a3064af4d359da1e633Alessandro Zummo
56c58411e95d7f5062dedd1a3064af4d359da1e633Alessandro Zummo	days = time / 86400;
5773442daf2ea85e2a779396b76b1a39b10188ecb5Jan Altenberg	time -= (unsigned int) days * 86400;
58c58411e95d7f5062dedd1a3064af4d359da1e633Alessandro Zummo
59c58411e95d7f5062dedd1a3064af4d359da1e633Alessandro Zummo	/* day of the week, 1970-01-01 was a Thursday */
60c58411e95d7f5062dedd1a3064af4d359da1e633Alessandro Zummo	tm->tm_wday = (days + 4) % 7;
61c58411e95d7f5062dedd1a3064af4d359da1e633Alessandro Zummo
62c58411e95d7f5062dedd1a3064af4d359da1e633Alessandro Zummo	year = 1970 + days / 365;
63c58411e95d7f5062dedd1a3064af4d359da1e633Alessandro Zummo	days -= (year - 1970) * 365
64c58411e95d7f5062dedd1a3064af4d359da1e633Alessandro Zummo		+ LEAPS_THRU_END_OF(year - 1)
65c58411e95d7f5062dedd1a3064af4d359da1e633Alessandro Zummo		- LEAPS_THRU_END_OF(1970 - 1);
66c58411e95d7f5062dedd1a3064af4d359da1e633Alessandro Zummo	if (days < 0) {
67c58411e95d7f5062dedd1a3064af4d359da1e633Alessandro Zummo		year -= 1;
6878d89ef40c2ff7265df077e20c4d76be7d415204Andrew Morton		days += 365 + is_leap_year(year);
69c58411e95d7f5062dedd1a3064af4d359da1e633Alessandro Zummo	}
70c58411e95d7f5062dedd1a3064af4d359da1e633Alessandro Zummo	tm->tm_year = year - 1900;
71c58411e95d7f5062dedd1a3064af4d359da1e633Alessandro Zummo	tm->tm_yday = days + 1;
72c58411e95d7f5062dedd1a3064af4d359da1e633Alessandro Zummo
73c58411e95d7f5062dedd1a3064af4d359da1e633Alessandro Zummo	for (month = 0; month < 11; month++) {
74c58411e95d7f5062dedd1a3064af4d359da1e633Alessandro Zummo		int newdays;
75c58411e95d7f5062dedd1a3064af4d359da1e633Alessandro Zummo
76c58411e95d7f5062dedd1a3064af4d359da1e633Alessandro Zummo		newdays = days - rtc_month_days(month, year);
77c58411e95d7f5062dedd1a3064af4d359da1e633Alessandro Zummo		if (newdays < 0)
78c58411e95d7f5062dedd1a3064af4d359da1e633Alessandro Zummo			break;
79c58411e95d7f5062dedd1a3064af4d359da1e633Alessandro Zummo		days = newdays;
80c58411e95d7f5062dedd1a3064af4d359da1e633Alessandro Zummo	}
81c58411e95d7f5062dedd1a3064af4d359da1e633Alessandro Zummo	tm->tm_mon = month;
82c58411e95d7f5062dedd1a3064af4d359da1e633Alessandro Zummo	tm->tm_mday = days + 1;
83c58411e95d7f5062dedd1a3064af4d359da1e633Alessandro Zummo
84c58411e95d7f5062dedd1a3064af4d359da1e633Alessandro Zummo	tm->tm_hour = time / 3600;
85c58411e95d7f5062dedd1a3064af4d359da1e633Alessandro Zummo	time -= tm->tm_hour * 3600;
86c58411e95d7f5062dedd1a3064af4d359da1e633Alessandro Zummo	tm->tm_min = time / 60;
87c58411e95d7f5062dedd1a3064af4d359da1e633Alessandro Zummo	tm->tm_sec = time - tm->tm_min * 60;
88a7402deb324f62106566f5a95199a54c41e200efMike Waychison
89a7402deb324f62106566f5a95199a54c41e200efMike Waychison	tm->tm_isdst = 0;
90c58411e95d7f5062dedd1a3064af4d359da1e633Alessandro Zummo}
91c58411e95d7f5062dedd1a3064af4d359da1e633Alessandro ZummoEXPORT_SYMBOL(rtc_time_to_tm);
92c58411e95d7f5062dedd1a3064af4d359da1e633Alessandro Zummo
93c58411e95d7f5062dedd1a3064af4d359da1e633Alessandro Zummo/*
94c58411e95d7f5062dedd1a3064af4d359da1e633Alessandro Zummo * Does the rtc_time represent a valid date/time?
95c58411e95d7f5062dedd1a3064af4d359da1e633Alessandro Zummo */
96c58411e95d7f5062dedd1a3064af4d359da1e633Alessandro Zummoint rtc_valid_tm(struct rtc_time *tm)
97c58411e95d7f5062dedd1a3064af4d359da1e633Alessandro Zummo{
98c58411e95d7f5062dedd1a3064af4d359da1e633Alessandro Zummo	if (tm->tm_year < 70
99db621f174d2c017d960089ea8cbc91c0763f1069David Brownell		|| ((unsigned)tm->tm_mon) >= 12
100c58411e95d7f5062dedd1a3064af4d359da1e633Alessandro Zummo		|| tm->tm_mday < 1
101c58411e95d7f5062dedd1a3064af4d359da1e633Alessandro Zummo		|| tm->tm_mday > rtc_month_days(tm->tm_mon, tm->tm_year + 1900)
102db621f174d2c017d960089ea8cbc91c0763f1069David Brownell		|| ((unsigned)tm->tm_hour) >= 24
103db621f174d2c017d960089ea8cbc91c0763f1069David Brownell		|| ((unsigned)tm->tm_min) >= 60
104db621f174d2c017d960089ea8cbc91c0763f1069David Brownell		|| ((unsigned)tm->tm_sec) >= 60)
105c58411e95d7f5062dedd1a3064af4d359da1e633Alessandro Zummo		return -EINVAL;
106c58411e95d7f5062dedd1a3064af4d359da1e633Alessandro Zummo
107c58411e95d7f5062dedd1a3064af4d359da1e633Alessandro Zummo	return 0;
108c58411e95d7f5062dedd1a3064af4d359da1e633Alessandro Zummo}
109c58411e95d7f5062dedd1a3064af4d359da1e633Alessandro ZummoEXPORT_SYMBOL(rtc_valid_tm);
110c58411e95d7f5062dedd1a3064af4d359da1e633Alessandro Zummo
111c58411e95d7f5062dedd1a3064af4d359da1e633Alessandro Zummo/*
112c58411e95d7f5062dedd1a3064af4d359da1e633Alessandro Zummo * Convert Gregorian date to seconds since 01-01-1970 00:00:00.
113c58411e95d7f5062dedd1a3064af4d359da1e633Alessandro Zummo */
114c58411e95d7f5062dedd1a3064af4d359da1e633Alessandro Zummoint rtc_tm_to_time(struct rtc_time *tm, unsigned long *time)
115c58411e95d7f5062dedd1a3064af4d359da1e633Alessandro Zummo{
116c58411e95d7f5062dedd1a3064af4d359da1e633Alessandro Zummo	*time = mktime(tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday,
117c58411e95d7f5062dedd1a3064af4d359da1e633Alessandro Zummo			tm->tm_hour, tm->tm_min, tm->tm_sec);
118c58411e95d7f5062dedd1a3064af4d359da1e633Alessandro Zummo	return 0;
119c58411e95d7f5062dedd1a3064af4d359da1e633Alessandro Zummo}
120c58411e95d7f5062dedd1a3064af4d359da1e633Alessandro ZummoEXPORT_SYMBOL(rtc_tm_to_time);
121c58411e95d7f5062dedd1a3064af4d359da1e633Alessandro Zummo
1226610e0893b8bc6f59b14fed7f089c5997f035f88John Stultz/*
1236610e0893b8bc6f59b14fed7f089c5997f035f88John Stultz * Convert rtc_time to ktime
1246610e0893b8bc6f59b14fed7f089c5997f035f88John Stultz */
1256610e0893b8bc6f59b14fed7f089c5997f035f88John Stultzktime_t rtc_tm_to_ktime(struct rtc_time tm)
1266610e0893b8bc6f59b14fed7f089c5997f035f88John Stultz{
1276610e0893b8bc6f59b14fed7f089c5997f035f88John Stultz	time_t time;
1286610e0893b8bc6f59b14fed7f089c5997f035f88John Stultz	rtc_tm_to_time(&tm, &time);
1296610e0893b8bc6f59b14fed7f089c5997f035f88John Stultz	return ktime_set(time, 0);
1306610e0893b8bc6f59b14fed7f089c5997f035f88John Stultz}
1316610e0893b8bc6f59b14fed7f089c5997f035f88John StultzEXPORT_SYMBOL_GPL(rtc_tm_to_ktime);
1326610e0893b8bc6f59b14fed7f089c5997f035f88John Stultz
1336610e0893b8bc6f59b14fed7f089c5997f035f88John Stultz/*
1346610e0893b8bc6f59b14fed7f089c5997f035f88John Stultz * Convert ktime to rtc_time
1356610e0893b8bc6f59b14fed7f089c5997f035f88John Stultz */
1366610e0893b8bc6f59b14fed7f089c5997f035f88John Stultzstruct rtc_time rtc_ktime_to_tm(ktime_t kt)
1376610e0893b8bc6f59b14fed7f089c5997f035f88John Stultz{
1386610e0893b8bc6f59b14fed7f089c5997f035f88John Stultz	struct timespec ts;
1396610e0893b8bc6f59b14fed7f089c5997f035f88John Stultz	struct rtc_time ret;
1406610e0893b8bc6f59b14fed7f089c5997f035f88John Stultz
1416610e0893b8bc6f59b14fed7f089c5997f035f88John Stultz	ts = ktime_to_timespec(kt);
1426610e0893b8bc6f59b14fed7f089c5997f035f88John Stultz	/* Round up any ns */
1436610e0893b8bc6f59b14fed7f089c5997f035f88John Stultz	if (ts.tv_nsec)
1446610e0893b8bc6f59b14fed7f089c5997f035f88John Stultz		ts.tv_sec++;
1456610e0893b8bc6f59b14fed7f089c5997f035f88John Stultz	rtc_time_to_tm(ts.tv_sec, &ret);
1466610e0893b8bc6f59b14fed7f089c5997f035f88John Stultz	return ret;
1476610e0893b8bc6f59b14fed7f089c5997f035f88John Stultz}
1486610e0893b8bc6f59b14fed7f089c5997f035f88John StultzEXPORT_SYMBOL_GPL(rtc_ktime_to_tm);
1496610e0893b8bc6f59b14fed7f089c5997f035f88John Stultz
150c58411e95d7f5062dedd1a3064af4d359da1e633Alessandro ZummoMODULE_LICENSE("GPL");
151