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