xref: /openbmc/u-boot/cmd/date.c (revision c507d306)
183d290c5STom Rini // SPDX-License-Identifier: GPL-2.0+
22e192b24SSimon Glass /*
32e192b24SSimon Glass  * (C) Copyright 2001
42e192b24SSimon Glass  * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
52e192b24SSimon Glass  */
62e192b24SSimon Glass 
72e192b24SSimon Glass /*
82e192b24SSimon Glass  * RTC, Date & Time support: get and set date & time
92e192b24SSimon Glass  */
102e192b24SSimon Glass #include <common.h>
112e192b24SSimon Glass #include <command.h>
122e192b24SSimon Glass #include <dm.h>
132e192b24SSimon Glass #include <rtc.h>
142e192b24SSimon Glass #include <i2c.h>
152e192b24SSimon Glass 
162e192b24SSimon Glass DECLARE_GLOBAL_DATA_PTR;
172e192b24SSimon Glass 
182e192b24SSimon Glass static const char * const weekdays[] = {
192e192b24SSimon Glass 	"Sun", "Mon", "Tues", "Wednes", "Thurs", "Fri", "Satur",
202e192b24SSimon Glass };
212e192b24SSimon Glass 
222e192b24SSimon Glass #ifdef CONFIG_NEEDS_MANUAL_RELOC
232e192b24SSimon Glass #define RELOC(a)	((typeof(a))((unsigned long)(a) + gd->reloc_off))
242e192b24SSimon Glass #else
252e192b24SSimon Glass #define RELOC(a)	a
262e192b24SSimon Glass #endif
272e192b24SSimon Glass 
282e192b24SSimon Glass int mk_date (const char *, struct rtc_time *);
292e192b24SSimon Glass 
302e192b24SSimon Glass static struct rtc_time default_tm = { 0, 0, 0, 1, 1, 2000, 6, 0, 0 };
312e192b24SSimon Glass 
do_date(cmd_tbl_t * cmdtp,int flag,int argc,char * const argv[])322e192b24SSimon Glass static int do_date(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
332e192b24SSimon Glass {
342e192b24SSimon Glass 	struct rtc_time tm;
352e192b24SSimon Glass 	int rcode = 0;
362e192b24SSimon Glass 	int old_bus __maybe_unused;
372e192b24SSimon Glass 
382e192b24SSimon Glass 	/* switch to correct I2C bus */
392e192b24SSimon Glass #ifdef CONFIG_DM_RTC
402e192b24SSimon Glass 	struct udevice *dev;
412e192b24SSimon Glass 
422e192b24SSimon Glass 	rcode = uclass_get_device(UCLASS_RTC, 0, &dev);
432e192b24SSimon Glass 	if (rcode) {
442e192b24SSimon Glass 		printf("Cannot find RTC: err=%d\n", rcode);
452e192b24SSimon Glass 		return CMD_RET_FAILURE;
462e192b24SSimon Glass 	}
472e192b24SSimon Glass #elif defined(CONFIG_SYS_I2C)
482e192b24SSimon Glass 	old_bus = i2c_get_bus_num();
492e192b24SSimon Glass 	i2c_set_bus_num(CONFIG_SYS_RTC_BUS_NUM);
502e192b24SSimon Glass #else
512e192b24SSimon Glass 	old_bus = I2C_GET_BUS();
522e192b24SSimon Glass 	I2C_SET_BUS(CONFIG_SYS_RTC_BUS_NUM);
532e192b24SSimon Glass #endif
542e192b24SSimon Glass 
552e192b24SSimon Glass 	switch (argc) {
562e192b24SSimon Glass 	case 2:			/* set date & time */
572e192b24SSimon Glass 		if (strcmp(argv[1],"reset") == 0) {
582e192b24SSimon Glass 			puts ("Reset RTC...\n");
592e192b24SSimon Glass #ifdef CONFIG_DM_RTC
602e192b24SSimon Glass 			rcode = dm_rtc_reset(dev);
612e192b24SSimon Glass 			if (!rcode)
622e192b24SSimon Glass 				rcode = dm_rtc_set(dev, &default_tm);
632e192b24SSimon Glass #else
642e192b24SSimon Glass 			rtc_reset();
652e192b24SSimon Glass 			rcode = rtc_set(&default_tm);
662e192b24SSimon Glass #endif
672e192b24SSimon Glass 			if (rcode)
682e192b24SSimon Glass 				puts("## Failed to set date after RTC reset\n");
692e192b24SSimon Glass 		} else {
702e192b24SSimon Glass 			/* initialize tm with current time */
712e192b24SSimon Glass #ifdef CONFIG_DM_RTC
722e192b24SSimon Glass 			rcode = dm_rtc_get(dev, &tm);
732e192b24SSimon Glass #else
742e192b24SSimon Glass 			rcode = rtc_get(&tm);
752e192b24SSimon Glass #endif
762e192b24SSimon Glass 			if (!rcode) {
772e192b24SSimon Glass 				/* insert new date & time */
782e192b24SSimon Glass 				if (mk_date(argv[1], &tm) != 0) {
792e192b24SSimon Glass 					puts ("## Bad date format\n");
802e192b24SSimon Glass 					break;
812e192b24SSimon Glass 				}
822e192b24SSimon Glass 				/* and write to RTC */
832e192b24SSimon Glass #ifdef CONFIG_DM_RTC
842e192b24SSimon Glass 				rcode = dm_rtc_set(dev, &tm);
852e192b24SSimon Glass #else
862e192b24SSimon Glass 				rcode = rtc_set(&tm);
872e192b24SSimon Glass #endif
882e192b24SSimon Glass 				if (rcode) {
892e192b24SSimon Glass 					printf("## Set date failed: err=%d\n",
902e192b24SSimon Glass 					       rcode);
912e192b24SSimon Glass 				}
922e192b24SSimon Glass 			} else {
932e192b24SSimon Glass 				puts("## Get date failed\n");
942e192b24SSimon Glass 			}
952e192b24SSimon Glass 		}
962e192b24SSimon Glass 		/* FALL TROUGH */
972e192b24SSimon Glass 	case 1:			/* get date & time */
982e192b24SSimon Glass #ifdef CONFIG_DM_RTC
992e192b24SSimon Glass 		rcode = dm_rtc_get(dev, &tm);
1002e192b24SSimon Glass #else
1012e192b24SSimon Glass 		rcode = rtc_get(&tm);
1022e192b24SSimon Glass #endif
1032e192b24SSimon Glass 		if (rcode) {
1042e192b24SSimon Glass 			puts("## Get date failed\n");
1052e192b24SSimon Glass 			break;
1062e192b24SSimon Glass 		}
1072e192b24SSimon Glass 
1082e192b24SSimon Glass 		printf ("Date: %4d-%02d-%02d (%sday)    Time: %2d:%02d:%02d\n",
1092e192b24SSimon Glass 			tm.tm_year, tm.tm_mon, tm.tm_mday,
1102e192b24SSimon Glass 			(tm.tm_wday<0 || tm.tm_wday>6) ?
1112e192b24SSimon Glass 				"unknown " : RELOC(weekdays[tm.tm_wday]),
1122e192b24SSimon Glass 			tm.tm_hour, tm.tm_min, tm.tm_sec);
1132e192b24SSimon Glass 
1142e192b24SSimon Glass 		break;
1152e192b24SSimon Glass 	default:
1162e192b24SSimon Glass 		rcode = CMD_RET_USAGE;
1172e192b24SSimon Glass 	}
1182e192b24SSimon Glass 
1192e192b24SSimon Glass 	/* switch back to original I2C bus */
1202e192b24SSimon Glass #ifdef CONFIG_SYS_I2C
1212e192b24SSimon Glass 	i2c_set_bus_num(old_bus);
1222e192b24SSimon Glass #elif !defined(CONFIG_DM_RTC)
1232e192b24SSimon Glass 	I2C_SET_BUS(old_bus);
1242e192b24SSimon Glass #endif
1252e192b24SSimon Glass 
1262e192b24SSimon Glass 	return rcode ? CMD_RET_FAILURE : 0;
1272e192b24SSimon Glass }
1282e192b24SSimon Glass 
1292e192b24SSimon Glass /*
1302e192b24SSimon Glass  * simple conversion of two-digit string with error checking
1312e192b24SSimon Glass  */
cnvrt2(const char * str,int * valp)1322e192b24SSimon Glass static int cnvrt2 (const char *str, int *valp)
1332e192b24SSimon Glass {
1342e192b24SSimon Glass 	int val;
1352e192b24SSimon Glass 
1362e192b24SSimon Glass 	if ((*str < '0') || (*str > '9'))
1372e192b24SSimon Glass 		return (-1);
1382e192b24SSimon Glass 
1392e192b24SSimon Glass 	val = *str - '0';
1402e192b24SSimon Glass 
1412e192b24SSimon Glass 	++str;
1422e192b24SSimon Glass 
1432e192b24SSimon Glass 	if ((*str < '0') || (*str > '9'))
1442e192b24SSimon Glass 		return (-1);
1452e192b24SSimon Glass 
1462e192b24SSimon Glass 	*valp = 10 * val + (*str - '0');
1472e192b24SSimon Glass 
1482e192b24SSimon Glass 	return (0);
1492e192b24SSimon Glass }
1502e192b24SSimon Glass 
1512e192b24SSimon Glass /*
1522e192b24SSimon Glass  * Convert date string: MMDDhhmm[[CC]YY][.ss]
1532e192b24SSimon Glass  *
1542e192b24SSimon Glass  * Some basic checking for valid values is done, but this will not catch
1552e192b24SSimon Glass  * all possible error conditions.
1562e192b24SSimon Glass  */
mk_date(const char * datestr,struct rtc_time * tmp)1572e192b24SSimon Glass int mk_date (const char *datestr, struct rtc_time *tmp)
1582e192b24SSimon Glass {
1592e192b24SSimon Glass 	int len, val;
1602e192b24SSimon Glass 	char *ptr;
1612e192b24SSimon Glass 
1622e192b24SSimon Glass 	ptr = strchr(datestr, '.');
1632e192b24SSimon Glass 	len = strlen(datestr);
1642e192b24SSimon Glass 
1652e192b24SSimon Glass 	/* Set seconds */
1662e192b24SSimon Glass 	if (ptr) {
1672e192b24SSimon Glass 		int sec;
1682e192b24SSimon Glass 
169*44ac80e7SRoman Kapl 		ptr++;
1702e192b24SSimon Glass 		if ((len - (ptr - datestr)) != 2)
1712e192b24SSimon Glass 			return (-1);
1722e192b24SSimon Glass 
173*44ac80e7SRoman Kapl 		len -= 3;
1742e192b24SSimon Glass 
1752e192b24SSimon Glass 		if (cnvrt2 (ptr, &sec))
1762e192b24SSimon Glass 			return (-1);
1772e192b24SSimon Glass 
1782e192b24SSimon Glass 		tmp->tm_sec = sec;
1792e192b24SSimon Glass 	} else {
1802e192b24SSimon Glass 		tmp->tm_sec = 0;
1812e192b24SSimon Glass 	}
1822e192b24SSimon Glass 
1832e192b24SSimon Glass 	if (len == 12) {		/* MMDDhhmmCCYY	*/
1842e192b24SSimon Glass 		int year, century;
1852e192b24SSimon Glass 
1862e192b24SSimon Glass 		if (cnvrt2 (datestr+ 8, &century) ||
1872e192b24SSimon Glass 		    cnvrt2 (datestr+10, &year) ) {
1882e192b24SSimon Glass 			return (-1);
1892e192b24SSimon Glass 		}
1902e192b24SSimon Glass 		tmp->tm_year = 100 * century + year;
1912e192b24SSimon Glass 	} else if (len == 10) {		/* MMDDhhmmYY	*/
1922e192b24SSimon Glass 		int year, century;
1932e192b24SSimon Glass 
1942e192b24SSimon Glass 		century = tmp->tm_year / 100;
1952e192b24SSimon Glass 		if (cnvrt2 (datestr+ 8, &year))
1962e192b24SSimon Glass 			return (-1);
1972e192b24SSimon Glass 		tmp->tm_year = 100 * century + year;
1982e192b24SSimon Glass 	}
1992e192b24SSimon Glass 
2002e192b24SSimon Glass 	switch (len) {
2012e192b24SSimon Glass 	case 8:			/* MMDDhhmm	*/
2022e192b24SSimon Glass 		/* fall thru */
2032e192b24SSimon Glass 	case 10:		/* MMDDhhmmYY	*/
2042e192b24SSimon Glass 		/* fall thru */
2052e192b24SSimon Glass 	case 12:		/* MMDDhhmmCCYY	*/
2062e192b24SSimon Glass 		if (cnvrt2 (datestr+0, &val) ||
2072e192b24SSimon Glass 		    val > 12) {
2082e192b24SSimon Glass 			break;
2092e192b24SSimon Glass 		}
2102e192b24SSimon Glass 		tmp->tm_mon  = val;
2112e192b24SSimon Glass 		if (cnvrt2 (datestr+2, &val) ||
2122e192b24SSimon Glass 		    val > ((tmp->tm_mon==2) ? 29 : 31)) {
2132e192b24SSimon Glass 			break;
2142e192b24SSimon Glass 		}
2152e192b24SSimon Glass 		tmp->tm_mday = val;
2162e192b24SSimon Glass 
2172e192b24SSimon Glass 		if (cnvrt2 (datestr+4, &val) ||
2182e192b24SSimon Glass 		    val > 23) {
2192e192b24SSimon Glass 			break;
2202e192b24SSimon Glass 		}
2212e192b24SSimon Glass 		tmp->tm_hour = val;
2222e192b24SSimon Glass 
2232e192b24SSimon Glass 		if (cnvrt2 (datestr+6, &val) ||
2242e192b24SSimon Glass 		    val > 59) {
2252e192b24SSimon Glass 			break;
2262e192b24SSimon Glass 		}
2272e192b24SSimon Glass 		tmp->tm_min  = val;
2282e192b24SSimon Glass 
2292e192b24SSimon Glass 		/* calculate day of week */
2302e192b24SSimon Glass 		rtc_calc_weekday(tmp);
2312e192b24SSimon Glass 
2322e192b24SSimon Glass 		return (0);
2332e192b24SSimon Glass 	default:
2342e192b24SSimon Glass 		break;
2352e192b24SSimon Glass 	}
2362e192b24SSimon Glass 
2372e192b24SSimon Glass 	return (-1);
2382e192b24SSimon Glass }
2392e192b24SSimon Glass 
2402e192b24SSimon Glass /***************************************************/
2412e192b24SSimon Glass 
2422e192b24SSimon Glass U_BOOT_CMD(
2432e192b24SSimon Glass 	date,	2,	1,	do_date,
2442e192b24SSimon Glass 	"get/set/reset date & time",
2452e192b24SSimon Glass 	"[MMDDhhmm[[CC]YY][.ss]]\ndate reset\n"
2462e192b24SSimon Glass 	"  - without arguments: print date & time\n"
2472e192b24SSimon Glass 	"  - with numeric argument: set the system date & time\n"
2482e192b24SSimon Glass 	"  - with 'reset' argument: reset the RTC"
2492e192b24SSimon Glass );
250