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