xref: /aosp_15_r20/external/ltp/testcases/kernel/device-drivers/rtc/rtc02.c (revision 49cdfc7efb34551c7342be41a7384b9c40d7cab7)
1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /*
3  * Copyright (C) 2020 Unisoc Communications Inc.
4  */
5 
6 /*\
7  * [Description]
8  *
9  * RTC device set time function test.
10  *
11  * [Algorithm]
12  *
13  * - Save RTC time
14  * - Set RTC time
15  * - Read the RTC time back
16  * - Check if the set time and the read time are identical
17  * - Restore RTC time
18  */
19 
20 #include <stdio.h>
21 #include "tst_rtctime.h"
22 #include "tst_wallclock.h"
23 #include "tst_test.h"
24 
25 static char *rtc_dev = "/dev/rtc";
26 
rtctime_to_str(struct rtc_time * tm)27 static char *rtctime_to_str(struct rtc_time *tm)
28 {
29 	static char rtctime_buf[128];
30 
31 	sprintf(rtctime_buf, "%04d-%02d-%02d %02d:%02d:%02d",
32 		tm->tm_year + 1900,
33 		tm->tm_mon + 1,
34 		tm->tm_mday,
35 		tm->tm_hour,
36 		tm->tm_min,
37 		tm->tm_sec);
38 	return rtctime_buf;
39 }
40 
rtc_tm_cmp(struct rtc_time * set_tm,struct rtc_time * read_tm)41 static int rtc_tm_cmp(struct rtc_time *set_tm, struct rtc_time *read_tm)
42 {
43 	long delta, seconds1, seconds2;
44 
45 	if (set_tm->tm_year != read_tm->tm_year)
46 		return 1;
47 
48 	if (set_tm->tm_mon != read_tm->tm_mon)
49 		return 1;
50 
51 	if (set_tm->tm_mday != read_tm->tm_mday)
52 		return 1;
53 
54 	/*
55 	 * Convert hour/min/sec into seconds to handle the normal
56 	 * and special situations:
57 	 * 1#
58 	 *       set_tm:  2022-04-28 13:00:50
59 	 *       read_tm: 2022-04-28 13:00:50
60 	 * 2#
61 	 *       set_tm:  2022-04-28 13:00:50
62 	 *       read_tm: 2022-04-28 13:00:51
63 	 * 3#
64 	 *       set_tm:  2022-04-28 13:00:59
65 	 *       read_tm: 2022-04-28 13:01:00
66 	 * 4#
67 	 *       set_tm:  2022-04-28 13:59:59
68 	 *       read_tm: 2022-04-28 14:00:00
69 	 *
70 	 * Note: as we have avoided testing around the zero
71 	 * clock, so it's impossible to hit situation 5#
72 	 *       set_tm:  2022-04-28 23:59:59
73 	 *       read_tm: 2022-04-29 00:00:00
74 	 */
75 	if ((set_tm->tm_hour != read_tm->tm_hour)
76 		|| (set_tm->tm_min != read_tm->tm_min)
77 		|| (set_tm->tm_sec != read_tm->tm_sec)) {
78 
79 		seconds1 = (set_tm->tm_hour  * 3600) + (set_tm->tm_min  * 60) + set_tm->tm_sec;
80 		seconds2 = (read_tm->tm_hour * 3600) + (read_tm->tm_min * 60) + read_tm->tm_sec;
81 
82 		delta = seconds2 - seconds1;
83 
84 		if (delta < 0 || delta > 3) {
85 			tst_res(TFAIL, "seconds1 is %ld, seconds2 is %ld", seconds1, seconds2);
86 			return 1;
87 		}
88 	}
89 
90 	return 0;
91 }
92 
set_rtc_test(void)93 static void set_rtc_test(void)
94 {
95 	struct rtc_time read_tm, set_tm;
96 	int ret;
97 
98 	/* Read current RTC Time */
99 	ret = tst_rtc_gettime(rtc_dev, &read_tm);
100 	if (ret != 0) {
101 		tst_res(TFAIL | TERRNO, "ioctl() RTC_RD_TIME");
102 		return;
103 	}
104 
105 	/* set rtc to +/-1 hour */
106 	set_tm = read_tm;
107 	if (set_tm.tm_hour == 0)
108 		set_tm.tm_hour += 1;
109 	else
110 		set_tm.tm_hour -= 1;
111 
112 	tst_res(TINFO, "To set RTC date/time is: %s", rtctime_to_str(&set_tm));
113 
114 	ret = tst_rtc_settime(rtc_dev, &set_tm);
115 	if (ret != 0) {
116 		tst_res(TFAIL | TERRNO, "ioctl() RTC_SET_TIME");
117 		return;
118 	}
119 
120 	/* Read new RTC Time */
121 	ret = tst_rtc_gettime(rtc_dev, &read_tm);
122 	if (ret != 0) {
123 		tst_res(TFAIL | TERRNO, "ioctl() RTC_RD_TIME");
124 		return;
125 	}
126 	tst_res(TINFO, "read RTC date/time is: %s", rtctime_to_str(&read_tm));
127 
128 	if (rtc_tm_cmp(&set_tm, &read_tm)) {
129 		tst_res(TFAIL, "RTC SET TEST");
130 		return;
131 	}
132 	tst_res(TPASS, "The read RTC time is consistent with set time");
133 }
134 
rtc_setup(void)135 static void rtc_setup(void)
136 {
137 	int exists = access(rtc_dev, F_OK);
138 
139 	if (exists < 0)
140 		tst_brk(TCONF, "RTC device %s not available", rtc_dev);
141 
142 	tst_rtc_clock_save(rtc_dev);
143 }
144 
rtc_cleanup(void)145 static void rtc_cleanup(void)
146 {
147 	tst_rtc_clock_restore(rtc_dev);
148 }
149 
150 static struct tst_test test = {
151 	.setup = rtc_setup,
152 	.test_all = set_rtc_test,
153 	.cleanup = rtc_cleanup,
154 	.needs_root = 1,
155 };
156