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 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 */ 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 */ 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