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