xref: /rk3399_rockchip-uboot/drivers/rtc/date.c (revision 199e87c340bdd69a89e22f12e1201d67767e91a8)
10c698dcaSJean-Christophe PLAGNIOL-VILLARD /*
20c698dcaSJean-Christophe PLAGNIOL-VILLARD  * (C) Copyright 2001
30c698dcaSJean-Christophe PLAGNIOL-VILLARD  * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
40c698dcaSJean-Christophe PLAGNIOL-VILLARD  *
51a459660SWolfgang Denk  * SPDX-License-Identifier:	GPL-2.0+
60c698dcaSJean-Christophe PLAGNIOL-VILLARD  */
70c698dcaSJean-Christophe PLAGNIOL-VILLARD 
80c698dcaSJean-Christophe PLAGNIOL-VILLARD /*
90c698dcaSJean-Christophe PLAGNIOL-VILLARD  * Date & Time support for Philips PCF8563 RTC
100c698dcaSJean-Christophe PLAGNIOL-VILLARD  */
110c698dcaSJean-Christophe PLAGNIOL-VILLARD 
120c698dcaSJean-Christophe PLAGNIOL-VILLARD #include <common.h>
130c698dcaSJean-Christophe PLAGNIOL-VILLARD #include <command.h>
14*199e87c3SSimon Glass #include <errno.h>
150c698dcaSJean-Christophe PLAGNIOL-VILLARD #include <rtc.h>
160c698dcaSJean-Christophe PLAGNIOL-VILLARD 
170c698dcaSJean-Christophe PLAGNIOL-VILLARD #if defined(CONFIG_CMD_DATE) || defined(CONFIG_TIMESTAMP)
180c698dcaSJean-Christophe PLAGNIOL-VILLARD 
190c698dcaSJean-Christophe PLAGNIOL-VILLARD #define FEBRUARY		2
200c698dcaSJean-Christophe PLAGNIOL-VILLARD #define	STARTOFTIME		1970
210c698dcaSJean-Christophe PLAGNIOL-VILLARD #define SECDAY			86400L
220c698dcaSJean-Christophe PLAGNIOL-VILLARD #define SECYR			(SECDAY * 365)
230c698dcaSJean-Christophe PLAGNIOL-VILLARD #define	leapyear(year)		((year) % 4 == 0)
240c698dcaSJean-Christophe PLAGNIOL-VILLARD #define	days_in_year(a)		(leapyear(a) ? 366 : 365)
250c698dcaSJean-Christophe PLAGNIOL-VILLARD #define	days_in_month(a)	(month_days[(a) - 1])
260c698dcaSJean-Christophe PLAGNIOL-VILLARD 
270c698dcaSJean-Christophe PLAGNIOL-VILLARD static int month_days[12] = {
280c698dcaSJean-Christophe PLAGNIOL-VILLARD 	31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
290c698dcaSJean-Christophe PLAGNIOL-VILLARD };
300c698dcaSJean-Christophe PLAGNIOL-VILLARD 
310c698dcaSJean-Christophe PLAGNIOL-VILLARD /*
320c698dcaSJean-Christophe PLAGNIOL-VILLARD  * This only works for the Gregorian calendar - i.e. after 1752 (in the UK)
330c698dcaSJean-Christophe PLAGNIOL-VILLARD  */
34*199e87c3SSimon Glass int rtc_calc_weekday(struct rtc_time *tm)
350c698dcaSJean-Christophe PLAGNIOL-VILLARD {
360c698dcaSJean-Christophe PLAGNIOL-VILLARD 	int leapsToDate;
370c698dcaSJean-Christophe PLAGNIOL-VILLARD 	int lastYear;
380c698dcaSJean-Christophe PLAGNIOL-VILLARD 	int day;
390c698dcaSJean-Christophe PLAGNIOL-VILLARD 	int MonthOffset[] = { 0,31,59,90,120,151,181,212,243,273,304,334 };
400c698dcaSJean-Christophe PLAGNIOL-VILLARD 
41*199e87c3SSimon Glass 	if (tm->tm_year < 1753)
42*199e87c3SSimon Glass 		return -EINVAL;
430c698dcaSJean-Christophe PLAGNIOL-VILLARD 	lastYear=tm->tm_year-1;
440c698dcaSJean-Christophe PLAGNIOL-VILLARD 
450c698dcaSJean-Christophe PLAGNIOL-VILLARD 	/*
460c698dcaSJean-Christophe PLAGNIOL-VILLARD 	 * Number of leap corrections to apply up to end of last year
470c698dcaSJean-Christophe PLAGNIOL-VILLARD 	 */
480c698dcaSJean-Christophe PLAGNIOL-VILLARD 	leapsToDate = lastYear/4 - lastYear/100 + lastYear/400;
490c698dcaSJean-Christophe PLAGNIOL-VILLARD 
500c698dcaSJean-Christophe PLAGNIOL-VILLARD 	/*
510c698dcaSJean-Christophe PLAGNIOL-VILLARD 	 * This year is a leap year if it is divisible by 4 except when it is
520c698dcaSJean-Christophe PLAGNIOL-VILLARD 	 * divisible by 100 unless it is divisible by 400
530c698dcaSJean-Christophe PLAGNIOL-VILLARD 	 *
540c698dcaSJean-Christophe PLAGNIOL-VILLARD 	 * e.g. 1904 was a leap year, 1900 was not, 1996 is, and 2000 will be
550c698dcaSJean-Christophe PLAGNIOL-VILLARD 	 */
560c698dcaSJean-Christophe PLAGNIOL-VILLARD 	if((tm->tm_year%4==0) &&
570c698dcaSJean-Christophe PLAGNIOL-VILLARD 	   ((tm->tm_year%100!=0) || (tm->tm_year%400==0)) &&
580c698dcaSJean-Christophe PLAGNIOL-VILLARD 	   (tm->tm_mon>2)) {
590c698dcaSJean-Christophe PLAGNIOL-VILLARD 		/*
600c698dcaSJean-Christophe PLAGNIOL-VILLARD 		 * We are past Feb. 29 in a leap year
610c698dcaSJean-Christophe PLAGNIOL-VILLARD 		 */
620c698dcaSJean-Christophe PLAGNIOL-VILLARD 		day=1;
630c698dcaSJean-Christophe PLAGNIOL-VILLARD 	} else {
640c698dcaSJean-Christophe PLAGNIOL-VILLARD 		day=0;
650c698dcaSJean-Christophe PLAGNIOL-VILLARD 	}
660c698dcaSJean-Christophe PLAGNIOL-VILLARD 
670c698dcaSJean-Christophe PLAGNIOL-VILLARD 	day += lastYear*365 + leapsToDate + MonthOffset[tm->tm_mon-1] + tm->tm_mday;
680c698dcaSJean-Christophe PLAGNIOL-VILLARD 
690c698dcaSJean-Christophe PLAGNIOL-VILLARD 	tm->tm_wday=day%7;
70*199e87c3SSimon Glass 
71*199e87c3SSimon Glass 	return 0;
720c698dcaSJean-Christophe PLAGNIOL-VILLARD }
730c698dcaSJean-Christophe PLAGNIOL-VILLARD 
740c698dcaSJean-Christophe PLAGNIOL-VILLARD void to_tm(int tim, struct rtc_time * tm)
750c698dcaSJean-Christophe PLAGNIOL-VILLARD {
760c698dcaSJean-Christophe PLAGNIOL-VILLARD 	register int    i;
770c698dcaSJean-Christophe PLAGNIOL-VILLARD 	register long   hms, day;
780c698dcaSJean-Christophe PLAGNIOL-VILLARD 
790c698dcaSJean-Christophe PLAGNIOL-VILLARD 	day = tim / SECDAY;
800c698dcaSJean-Christophe PLAGNIOL-VILLARD 	hms = tim % SECDAY;
810c698dcaSJean-Christophe PLAGNIOL-VILLARD 
820c698dcaSJean-Christophe PLAGNIOL-VILLARD 	/* Hours, minutes, seconds are easy */
830c698dcaSJean-Christophe PLAGNIOL-VILLARD 	tm->tm_hour = hms / 3600;
840c698dcaSJean-Christophe PLAGNIOL-VILLARD 	tm->tm_min = (hms % 3600) / 60;
850c698dcaSJean-Christophe PLAGNIOL-VILLARD 	tm->tm_sec = (hms % 3600) % 60;
860c698dcaSJean-Christophe PLAGNIOL-VILLARD 
870c698dcaSJean-Christophe PLAGNIOL-VILLARD 	/* Number of years in days */
880c698dcaSJean-Christophe PLAGNIOL-VILLARD 	for (i = STARTOFTIME; day >= days_in_year(i); i++) {
890c698dcaSJean-Christophe PLAGNIOL-VILLARD 		day -= days_in_year(i);
900c698dcaSJean-Christophe PLAGNIOL-VILLARD 	}
910c698dcaSJean-Christophe PLAGNIOL-VILLARD 	tm->tm_year = i;
920c698dcaSJean-Christophe PLAGNIOL-VILLARD 
930c698dcaSJean-Christophe PLAGNIOL-VILLARD 	/* Number of months in days left */
940c698dcaSJean-Christophe PLAGNIOL-VILLARD 	if (leapyear(tm->tm_year)) {
950c698dcaSJean-Christophe PLAGNIOL-VILLARD 		days_in_month(FEBRUARY) = 29;
960c698dcaSJean-Christophe PLAGNIOL-VILLARD 	}
970c698dcaSJean-Christophe PLAGNIOL-VILLARD 	for (i = 1; day >= days_in_month(i); i++) {
980c698dcaSJean-Christophe PLAGNIOL-VILLARD 		day -= days_in_month(i);
990c698dcaSJean-Christophe PLAGNIOL-VILLARD 	}
1000c698dcaSJean-Christophe PLAGNIOL-VILLARD 	days_in_month(FEBRUARY) = 28;
1010c698dcaSJean-Christophe PLAGNIOL-VILLARD 	tm->tm_mon = i;
1020c698dcaSJean-Christophe PLAGNIOL-VILLARD 
1030c698dcaSJean-Christophe PLAGNIOL-VILLARD 	/* Days are what is left over (+1) from all that. */
1040c698dcaSJean-Christophe PLAGNIOL-VILLARD 	tm->tm_mday = day + 1;
1050c698dcaSJean-Christophe PLAGNIOL-VILLARD 
1060c698dcaSJean-Christophe PLAGNIOL-VILLARD 	/*
1070c698dcaSJean-Christophe PLAGNIOL-VILLARD 	 * Determine the day of week
1080c698dcaSJean-Christophe PLAGNIOL-VILLARD 	 */
109*199e87c3SSimon Glass 	rtc_calc_weekday(tm);
1100c698dcaSJean-Christophe PLAGNIOL-VILLARD }
1110c698dcaSJean-Christophe PLAGNIOL-VILLARD 
1120c698dcaSJean-Christophe PLAGNIOL-VILLARD /* Converts Gregorian date to seconds since 1970-01-01 00:00:00.
1130c698dcaSJean-Christophe PLAGNIOL-VILLARD  * Assumes input in normal date format, i.e. 1980-12-31 23:59:59
1140c698dcaSJean-Christophe PLAGNIOL-VILLARD  * => year=1980, mon=12, day=31, hour=23, min=59, sec=59.
1150c698dcaSJean-Christophe PLAGNIOL-VILLARD  *
1160c698dcaSJean-Christophe PLAGNIOL-VILLARD  * [For the Julian calendar (which was used in Russia before 1917,
1170c698dcaSJean-Christophe PLAGNIOL-VILLARD  * Britain & colonies before 1752, anywhere else before 1582,
1180c698dcaSJean-Christophe PLAGNIOL-VILLARD  * and is still in use by some communities) leave out the
1190c698dcaSJean-Christophe PLAGNIOL-VILLARD  * -year/100+year/400 terms, and add 10.]
1200c698dcaSJean-Christophe PLAGNIOL-VILLARD  *
1210c698dcaSJean-Christophe PLAGNIOL-VILLARD  * This algorithm was first published by Gauss (I think).
1220c698dcaSJean-Christophe PLAGNIOL-VILLARD  *
1230c698dcaSJean-Christophe PLAGNIOL-VILLARD  * WARNING: this function will overflow on 2106-02-07 06:28:16 on
1240c698dcaSJean-Christophe PLAGNIOL-VILLARD  * machines were long is 32-bit! (However, as time_t is signed, we
1250c698dcaSJean-Christophe PLAGNIOL-VILLARD  * will already get problems at other places on 2038-01-19 03:14:08)
1260c698dcaSJean-Christophe PLAGNIOL-VILLARD  */
1270c698dcaSJean-Christophe PLAGNIOL-VILLARD unsigned long
1280c698dcaSJean-Christophe PLAGNIOL-VILLARD mktime (unsigned int year, unsigned int mon,
1290c698dcaSJean-Christophe PLAGNIOL-VILLARD 	unsigned int day, unsigned int hour,
1300c698dcaSJean-Christophe PLAGNIOL-VILLARD 	unsigned int min, unsigned int sec)
1310c698dcaSJean-Christophe PLAGNIOL-VILLARD {
1320c698dcaSJean-Christophe PLAGNIOL-VILLARD 	if (0 >= (int) (mon -= 2)) {	/* 1..12 -> 11,12,1..10 */
1330c698dcaSJean-Christophe PLAGNIOL-VILLARD 		mon += 12;		/* Puts Feb last since it has leap day */
1340c698dcaSJean-Christophe PLAGNIOL-VILLARD 		year -= 1;
1350c698dcaSJean-Christophe PLAGNIOL-VILLARD 	}
1360c698dcaSJean-Christophe PLAGNIOL-VILLARD 
1370c698dcaSJean-Christophe PLAGNIOL-VILLARD 	return (((
1380c698dcaSJean-Christophe PLAGNIOL-VILLARD 		(unsigned long) (year/4 - year/100 + year/400 + 367*mon/12 + day) +
1390c698dcaSJean-Christophe PLAGNIOL-VILLARD 			year*365 - 719499
1400c698dcaSJean-Christophe PLAGNIOL-VILLARD 	    )*24 + hour /* now have hours */
1410c698dcaSJean-Christophe PLAGNIOL-VILLARD 	  )*60 + min /* now have minutes */
1420c698dcaSJean-Christophe PLAGNIOL-VILLARD 	)*60 + sec; /* finally seconds */
1430c698dcaSJean-Christophe PLAGNIOL-VILLARD }
1440c698dcaSJean-Christophe PLAGNIOL-VILLARD 
1450c698dcaSJean-Christophe PLAGNIOL-VILLARD #endif
146