1*2e192b24SSimon Glass /* 2*2e192b24SSimon Glass * (C) Copyright 2001 3*2e192b24SSimon Glass * Wolfgang Denk, DENX Software Engineering, wd@denx.de. 4*2e192b24SSimon Glass * 5*2e192b24SSimon Glass * SPDX-License-Identifier: GPL-2.0+ 6*2e192b24SSimon Glass */ 7*2e192b24SSimon Glass 8*2e192b24SSimon Glass /* 9*2e192b24SSimon Glass * RTC, Date & Time support: get and set date & time 10*2e192b24SSimon Glass */ 11*2e192b24SSimon Glass #include <common.h> 12*2e192b24SSimon Glass #include <command.h> 13*2e192b24SSimon Glass #include <dm.h> 14*2e192b24SSimon Glass #include <rtc.h> 15*2e192b24SSimon Glass #include <i2c.h> 16*2e192b24SSimon Glass 17*2e192b24SSimon Glass DECLARE_GLOBAL_DATA_PTR; 18*2e192b24SSimon Glass 19*2e192b24SSimon Glass static const char * const weekdays[] = { 20*2e192b24SSimon Glass "Sun", "Mon", "Tues", "Wednes", "Thurs", "Fri", "Satur", 21*2e192b24SSimon Glass }; 22*2e192b24SSimon Glass 23*2e192b24SSimon Glass #ifdef CONFIG_NEEDS_MANUAL_RELOC 24*2e192b24SSimon Glass #define RELOC(a) ((typeof(a))((unsigned long)(a) + gd->reloc_off)) 25*2e192b24SSimon Glass #else 26*2e192b24SSimon Glass #define RELOC(a) a 27*2e192b24SSimon Glass #endif 28*2e192b24SSimon Glass 29*2e192b24SSimon Glass int mk_date (const char *, struct rtc_time *); 30*2e192b24SSimon Glass 31*2e192b24SSimon Glass static struct rtc_time default_tm = { 0, 0, 0, 1, 1, 2000, 6, 0, 0 }; 32*2e192b24SSimon Glass 33*2e192b24SSimon Glass static int do_date(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) 34*2e192b24SSimon Glass { 35*2e192b24SSimon Glass struct rtc_time tm; 36*2e192b24SSimon Glass int rcode = 0; 37*2e192b24SSimon Glass int old_bus __maybe_unused; 38*2e192b24SSimon Glass 39*2e192b24SSimon Glass /* switch to correct I2C bus */ 40*2e192b24SSimon Glass #ifdef CONFIG_DM_RTC 41*2e192b24SSimon Glass struct udevice *dev; 42*2e192b24SSimon Glass 43*2e192b24SSimon Glass rcode = uclass_get_device(UCLASS_RTC, 0, &dev); 44*2e192b24SSimon Glass if (rcode) { 45*2e192b24SSimon Glass printf("Cannot find RTC: err=%d\n", rcode); 46*2e192b24SSimon Glass return CMD_RET_FAILURE; 47*2e192b24SSimon Glass } 48*2e192b24SSimon Glass #elif defined(CONFIG_SYS_I2C) 49*2e192b24SSimon Glass old_bus = i2c_get_bus_num(); 50*2e192b24SSimon Glass i2c_set_bus_num(CONFIG_SYS_RTC_BUS_NUM); 51*2e192b24SSimon Glass #else 52*2e192b24SSimon Glass old_bus = I2C_GET_BUS(); 53*2e192b24SSimon Glass I2C_SET_BUS(CONFIG_SYS_RTC_BUS_NUM); 54*2e192b24SSimon Glass #endif 55*2e192b24SSimon Glass 56*2e192b24SSimon Glass switch (argc) { 57*2e192b24SSimon Glass case 2: /* set date & time */ 58*2e192b24SSimon Glass if (strcmp(argv[1],"reset") == 0) { 59*2e192b24SSimon Glass puts ("Reset RTC...\n"); 60*2e192b24SSimon Glass #ifdef CONFIG_DM_RTC 61*2e192b24SSimon Glass rcode = dm_rtc_reset(dev); 62*2e192b24SSimon Glass if (!rcode) 63*2e192b24SSimon Glass rcode = dm_rtc_set(dev, &default_tm); 64*2e192b24SSimon Glass #else 65*2e192b24SSimon Glass rtc_reset(); 66*2e192b24SSimon Glass rcode = rtc_set(&default_tm); 67*2e192b24SSimon Glass #endif 68*2e192b24SSimon Glass if (rcode) 69*2e192b24SSimon Glass puts("## Failed to set date after RTC reset\n"); 70*2e192b24SSimon Glass } else { 71*2e192b24SSimon Glass /* initialize tm with current time */ 72*2e192b24SSimon Glass #ifdef CONFIG_DM_RTC 73*2e192b24SSimon Glass rcode = dm_rtc_get(dev, &tm); 74*2e192b24SSimon Glass #else 75*2e192b24SSimon Glass rcode = rtc_get(&tm); 76*2e192b24SSimon Glass #endif 77*2e192b24SSimon Glass if (!rcode) { 78*2e192b24SSimon Glass /* insert new date & time */ 79*2e192b24SSimon Glass if (mk_date(argv[1], &tm) != 0) { 80*2e192b24SSimon Glass puts ("## Bad date format\n"); 81*2e192b24SSimon Glass break; 82*2e192b24SSimon Glass } 83*2e192b24SSimon Glass /* and write to RTC */ 84*2e192b24SSimon Glass #ifdef CONFIG_DM_RTC 85*2e192b24SSimon Glass rcode = dm_rtc_set(dev, &tm); 86*2e192b24SSimon Glass #else 87*2e192b24SSimon Glass rcode = rtc_set(&tm); 88*2e192b24SSimon Glass #endif 89*2e192b24SSimon Glass if (rcode) { 90*2e192b24SSimon Glass printf("## Set date failed: err=%d\n", 91*2e192b24SSimon Glass rcode); 92*2e192b24SSimon Glass } 93*2e192b24SSimon Glass } else { 94*2e192b24SSimon Glass puts("## Get date failed\n"); 95*2e192b24SSimon Glass } 96*2e192b24SSimon Glass } 97*2e192b24SSimon Glass /* FALL TROUGH */ 98*2e192b24SSimon Glass case 1: /* get date & time */ 99*2e192b24SSimon Glass #ifdef CONFIG_DM_RTC 100*2e192b24SSimon Glass rcode = dm_rtc_get(dev, &tm); 101*2e192b24SSimon Glass #else 102*2e192b24SSimon Glass rcode = rtc_get(&tm); 103*2e192b24SSimon Glass #endif 104*2e192b24SSimon Glass if (rcode) { 105*2e192b24SSimon Glass puts("## Get date failed\n"); 106*2e192b24SSimon Glass break; 107*2e192b24SSimon Glass } 108*2e192b24SSimon Glass 109*2e192b24SSimon Glass printf ("Date: %4d-%02d-%02d (%sday) Time: %2d:%02d:%02d\n", 110*2e192b24SSimon Glass tm.tm_year, tm.tm_mon, tm.tm_mday, 111*2e192b24SSimon Glass (tm.tm_wday<0 || tm.tm_wday>6) ? 112*2e192b24SSimon Glass "unknown " : RELOC(weekdays[tm.tm_wday]), 113*2e192b24SSimon Glass tm.tm_hour, tm.tm_min, tm.tm_sec); 114*2e192b24SSimon Glass 115*2e192b24SSimon Glass break; 116*2e192b24SSimon Glass default: 117*2e192b24SSimon Glass rcode = CMD_RET_USAGE; 118*2e192b24SSimon Glass } 119*2e192b24SSimon Glass 120*2e192b24SSimon Glass /* switch back to original I2C bus */ 121*2e192b24SSimon Glass #ifdef CONFIG_SYS_I2C 122*2e192b24SSimon Glass i2c_set_bus_num(old_bus); 123*2e192b24SSimon Glass #elif !defined(CONFIG_DM_RTC) 124*2e192b24SSimon Glass I2C_SET_BUS(old_bus); 125*2e192b24SSimon Glass #endif 126*2e192b24SSimon Glass 127*2e192b24SSimon Glass return rcode ? CMD_RET_FAILURE : 0; 128*2e192b24SSimon Glass } 129*2e192b24SSimon Glass 130*2e192b24SSimon Glass /* 131*2e192b24SSimon Glass * simple conversion of two-digit string with error checking 132*2e192b24SSimon Glass */ 133*2e192b24SSimon Glass static int cnvrt2 (const char *str, int *valp) 134*2e192b24SSimon Glass { 135*2e192b24SSimon Glass int val; 136*2e192b24SSimon Glass 137*2e192b24SSimon Glass if ((*str < '0') || (*str > '9')) 138*2e192b24SSimon Glass return (-1); 139*2e192b24SSimon Glass 140*2e192b24SSimon Glass val = *str - '0'; 141*2e192b24SSimon Glass 142*2e192b24SSimon Glass ++str; 143*2e192b24SSimon Glass 144*2e192b24SSimon Glass if ((*str < '0') || (*str > '9')) 145*2e192b24SSimon Glass return (-1); 146*2e192b24SSimon Glass 147*2e192b24SSimon Glass *valp = 10 * val + (*str - '0'); 148*2e192b24SSimon Glass 149*2e192b24SSimon Glass return (0); 150*2e192b24SSimon Glass } 151*2e192b24SSimon Glass 152*2e192b24SSimon Glass /* 153*2e192b24SSimon Glass * Convert date string: MMDDhhmm[[CC]YY][.ss] 154*2e192b24SSimon Glass * 155*2e192b24SSimon Glass * Some basic checking for valid values is done, but this will not catch 156*2e192b24SSimon Glass * all possible error conditions. 157*2e192b24SSimon Glass */ 158*2e192b24SSimon Glass int mk_date (const char *datestr, struct rtc_time *tmp) 159*2e192b24SSimon Glass { 160*2e192b24SSimon Glass int len, val; 161*2e192b24SSimon Glass char *ptr; 162*2e192b24SSimon Glass 163*2e192b24SSimon Glass ptr = strchr (datestr,'.'); 164*2e192b24SSimon Glass len = strlen (datestr); 165*2e192b24SSimon Glass 166*2e192b24SSimon Glass /* Set seconds */ 167*2e192b24SSimon Glass if (ptr) { 168*2e192b24SSimon Glass int sec; 169*2e192b24SSimon Glass 170*2e192b24SSimon Glass *ptr++ = '\0'; 171*2e192b24SSimon Glass if ((len - (ptr - datestr)) != 2) 172*2e192b24SSimon Glass return (-1); 173*2e192b24SSimon Glass 174*2e192b24SSimon Glass len = strlen (datestr); 175*2e192b24SSimon Glass 176*2e192b24SSimon Glass if (cnvrt2 (ptr, &sec)) 177*2e192b24SSimon Glass return (-1); 178*2e192b24SSimon Glass 179*2e192b24SSimon Glass tmp->tm_sec = sec; 180*2e192b24SSimon Glass } else { 181*2e192b24SSimon Glass tmp->tm_sec = 0; 182*2e192b24SSimon Glass } 183*2e192b24SSimon Glass 184*2e192b24SSimon Glass if (len == 12) { /* MMDDhhmmCCYY */ 185*2e192b24SSimon Glass int year, century; 186*2e192b24SSimon Glass 187*2e192b24SSimon Glass if (cnvrt2 (datestr+ 8, ¢ury) || 188*2e192b24SSimon Glass cnvrt2 (datestr+10, &year) ) { 189*2e192b24SSimon Glass return (-1); 190*2e192b24SSimon Glass } 191*2e192b24SSimon Glass tmp->tm_year = 100 * century + year; 192*2e192b24SSimon Glass } else if (len == 10) { /* MMDDhhmmYY */ 193*2e192b24SSimon Glass int year, century; 194*2e192b24SSimon Glass 195*2e192b24SSimon Glass century = tmp->tm_year / 100; 196*2e192b24SSimon Glass if (cnvrt2 (datestr+ 8, &year)) 197*2e192b24SSimon Glass return (-1); 198*2e192b24SSimon Glass tmp->tm_year = 100 * century + year; 199*2e192b24SSimon Glass } 200*2e192b24SSimon Glass 201*2e192b24SSimon Glass switch (len) { 202*2e192b24SSimon Glass case 8: /* MMDDhhmm */ 203*2e192b24SSimon Glass /* fall thru */ 204*2e192b24SSimon Glass case 10: /* MMDDhhmmYY */ 205*2e192b24SSimon Glass /* fall thru */ 206*2e192b24SSimon Glass case 12: /* MMDDhhmmCCYY */ 207*2e192b24SSimon Glass if (cnvrt2 (datestr+0, &val) || 208*2e192b24SSimon Glass val > 12) { 209*2e192b24SSimon Glass break; 210*2e192b24SSimon Glass } 211*2e192b24SSimon Glass tmp->tm_mon = val; 212*2e192b24SSimon Glass if (cnvrt2 (datestr+2, &val) || 213*2e192b24SSimon Glass val > ((tmp->tm_mon==2) ? 29 : 31)) { 214*2e192b24SSimon Glass break; 215*2e192b24SSimon Glass } 216*2e192b24SSimon Glass tmp->tm_mday = val; 217*2e192b24SSimon Glass 218*2e192b24SSimon Glass if (cnvrt2 (datestr+4, &val) || 219*2e192b24SSimon Glass val > 23) { 220*2e192b24SSimon Glass break; 221*2e192b24SSimon Glass } 222*2e192b24SSimon Glass tmp->tm_hour = val; 223*2e192b24SSimon Glass 224*2e192b24SSimon Glass if (cnvrt2 (datestr+6, &val) || 225*2e192b24SSimon Glass val > 59) { 226*2e192b24SSimon Glass break; 227*2e192b24SSimon Glass } 228*2e192b24SSimon Glass tmp->tm_min = val; 229*2e192b24SSimon Glass 230*2e192b24SSimon Glass /* calculate day of week */ 231*2e192b24SSimon Glass rtc_calc_weekday(tmp); 232*2e192b24SSimon Glass 233*2e192b24SSimon Glass return (0); 234*2e192b24SSimon Glass default: 235*2e192b24SSimon Glass break; 236*2e192b24SSimon Glass } 237*2e192b24SSimon Glass 238*2e192b24SSimon Glass return (-1); 239*2e192b24SSimon Glass } 240*2e192b24SSimon Glass 241*2e192b24SSimon Glass /***************************************************/ 242*2e192b24SSimon Glass 243*2e192b24SSimon Glass U_BOOT_CMD( 244*2e192b24SSimon Glass date, 2, 1, do_date, 245*2e192b24SSimon Glass "get/set/reset date & time", 246*2e192b24SSimon Glass "[MMDDhhmm[[CC]YY][.ss]]\ndate reset\n" 247*2e192b24SSimon Glass " - without arguments: print date & time\n" 248*2e192b24SSimon Glass " - with numeric argument: set the system date & time\n" 249*2e192b24SSimon Glass " - with 'reset' argument: reset the RTC" 250*2e192b24SSimon Glass ); 251