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