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, ¢ury) ||
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