1 // SPDX-License-Identifier: GPL-2.0
3 * Real Time Clock Driver Test Program
5 * Copyright (c) 2018 Alexandre Belloni <alexandre.belloni@bootlin.com>
10 #include <linux/rtc.h>
13 #include <sys/ioctl.h>
15 #include <sys/types.h>
19 #include "../kselftest_harness.h"
23 #define READ_LOOP_DURATION_SEC 30
24 #define READ_LOOP_SLEEP_MS 11
26 static char *rtc_file
= "/dev/rtc0";
28 enum rtc_alarm_state
{
39 self
->fd
= open(rtc_file
, O_RDONLY
);
42 FIXTURE_TEARDOWN(rtc
) {
46 TEST_F(rtc
, date_read
) {
48 struct rtc_time rtc_tm
;
50 if (self
->fd
== -1 && errno
== ENOENT
)
51 SKIP(return, "Skipping test since %s does not exist", rtc_file
);
52 ASSERT_NE(-1, self
->fd
);
54 /* Read the RTC time/date */
55 rc
= ioctl(self
->fd
, RTC_RD_TIME
, &rtc_tm
);
58 TH_LOG("Current RTC date/time is %02d/%02d/%02d %02d:%02d:%02d.",
59 rtc_tm
.tm_mday
, rtc_tm
.tm_mon
+ 1, rtc_tm
.tm_year
+ 1900,
60 rtc_tm
.tm_hour
, rtc_tm
.tm_min
, rtc_tm
.tm_sec
);
63 static time_t rtc_time_to_timestamp(struct rtc_time
*rtc_time
)
66 .tm_sec
= rtc_time
->tm_sec
,
67 .tm_min
= rtc_time
->tm_min
,
68 .tm_hour
= rtc_time
->tm_hour
,
69 .tm_mday
= rtc_time
->tm_mday
,
70 .tm_mon
= rtc_time
->tm_mon
,
71 .tm_year
= rtc_time
->tm_year
,
74 return mktime(&tm_time
);
77 static void nanosleep_with_retries(long ns
)
79 struct timespec req
= {
85 while (nanosleep(&req
, &rem
) != 0) {
86 req
.tv_sec
= rem
.tv_sec
;
87 req
.tv_nsec
= rem
.tv_nsec
;
91 static enum rtc_alarm_state
get_rtc_alarm_state(int fd
)
93 struct rtc_param param
= { 0 };
96 /* Validate kernel reflects unsupported RTC alarm state */
97 param
.param
= RTC_PARAM_FEATURES
;
99 rc
= ioctl(fd
, RTC_PARAM_GET
, ¶m
);
101 return RTC_ALARM_UNKNOWN
;
103 if ((param
.uvalue
& _BITUL(RTC_FEATURE_ALARM
)) == 0)
104 return RTC_ALARM_DISABLED
;
106 return RTC_ALARM_ENABLED
;
109 TEST_F_TIMEOUT(rtc
, date_read_loop
, READ_LOOP_DURATION_SEC
+ 2) {
112 struct rtc_time rtc_tm
;
113 time_t start_rtc_read
, prev_rtc_read
;
115 if (self
->fd
== -1 && errno
== ENOENT
)
116 SKIP(return, "Skipping test since %s does not exist", rtc_file
);
117 ASSERT_NE(-1, self
->fd
);
119 TH_LOG("Continuously reading RTC time for %ds (with %dms breaks after every read).",
120 READ_LOOP_DURATION_SEC
, READ_LOOP_SLEEP_MS
);
122 rc
= ioctl(self
->fd
, RTC_RD_TIME
, &rtc_tm
);
124 start_rtc_read
= rtc_time_to_timestamp(&rtc_tm
);
125 prev_rtc_read
= start_rtc_read
;
130 rc
= ioctl(self
->fd
, RTC_RD_TIME
, &rtc_tm
);
133 rtc_read
= rtc_time_to_timestamp(&rtc_tm
);
134 /* Time should not go backwards */
135 ASSERT_LE(prev_rtc_read
, rtc_read
);
136 /* Time should not increase more then 1s at a time */
137 ASSERT_GE(prev_rtc_read
+ 1, rtc_read
);
139 /* Sleep 11ms to avoid killing / overheating the RTC */
140 nanosleep_with_retries(READ_LOOP_SLEEP_MS
* 1000000);
142 prev_rtc_read
= rtc_read
;
144 } while (prev_rtc_read
<= start_rtc_read
+ READ_LOOP_DURATION_SEC
);
146 TH_LOG("Performed %ld RTC time reads.", iter_count
);
149 TEST_F_TIMEOUT(rtc
, uie_read
, NUM_UIE
+ 2) {
153 if (self
->fd
== -1 && errno
== ENOENT
)
154 SKIP(return, "Skipping test since %s does not exist", rtc_file
);
155 ASSERT_NE(-1, self
->fd
);
157 /* Turn on update interrupts */
158 rc
= ioctl(self
->fd
, RTC_UIE_ON
, 0);
160 ASSERT_EQ(EINVAL
, errno
);
161 TH_LOG("skip update IRQs not supported.");
165 for (i
= 0; i
< NUM_UIE
; i
++) {
166 /* This read will block */
167 rc
= read(self
->fd
, &data
, sizeof(data
));
172 EXPECT_EQ(NUM_UIE
, irq
);
174 rc
= ioctl(self
->fd
, RTC_UIE_OFF
, 0);
178 TEST_F(rtc
, uie_select
) {
182 if (self
->fd
== -1 && errno
== ENOENT
)
183 SKIP(return, "Skipping test since %s does not exist", rtc_file
);
184 ASSERT_NE(-1, self
->fd
);
186 /* Turn on update interrupts */
187 rc
= ioctl(self
->fd
, RTC_UIE_ON
, 0);
189 ASSERT_EQ(EINVAL
, errno
);
190 TH_LOG("skip update IRQs not supported.");
194 for (i
= 0; i
< NUM_UIE
; i
++) {
195 struct timeval tv
= { .tv_sec
= 2 };
199 FD_SET(self
->fd
, &readfds
);
200 /* The select will wait until an RTC interrupt happens. */
201 rc
= select(self
->fd
+ 1, &readfds
, NULL
, NULL
, &tv
);
205 /* This read won't block */
206 rc
= read(self
->fd
, &data
, sizeof(unsigned long));
211 EXPECT_EQ(NUM_UIE
, irq
);
213 rc
= ioctl(self
->fd
, RTC_UIE_OFF
, 0);
217 TEST_F(rtc
, alarm_alm_set
) {
218 struct timeval tv
= { .tv_sec
= ALARM_DELTA
+ 2 };
224 enum rtc_alarm_state alarm_state
= RTC_ALARM_UNKNOWN
;
226 if (self
->fd
== -1 && errno
== ENOENT
)
227 SKIP(return, "Skipping test since %s does not exist", rtc_file
);
228 ASSERT_NE(-1, self
->fd
);
230 alarm_state
= get_rtc_alarm_state(self
->fd
);
231 if (alarm_state
== RTC_ALARM_DISABLED
)
232 SKIP(return, "Skipping test since alarms are not supported.");
234 rc
= ioctl(self
->fd
, RTC_RD_TIME
, &tm
);
237 secs
= timegm((struct tm
*)&tm
) + ALARM_DELTA
;
238 gmtime_r(&secs
, (struct tm
*)&tm
);
240 rc
= ioctl(self
->fd
, RTC_ALM_SET
, &tm
);
243 * Report error if rtc alarm was enabled. Fallback to check ioctl
244 * error number if rtc alarm state is unknown.
246 ASSERT_EQ(RTC_ALARM_UNKNOWN
, alarm_state
);
247 ASSERT_EQ(EINVAL
, errno
);
248 TH_LOG("skip alarms are not supported.");
252 rc
= ioctl(self
->fd
, RTC_ALM_READ
, &tm
);
255 TH_LOG("Alarm time now set to %02d:%02d:%02d.",
256 tm
.tm_hour
, tm
.tm_min
, tm
.tm_sec
);
258 /* Enable alarm interrupts */
259 rc
= ioctl(self
->fd
, RTC_AIE_ON
, 0);
263 FD_SET(self
->fd
, &readfds
);
265 rc
= select(self
->fd
+ 1, &readfds
, NULL
, NULL
, &tv
);
269 /* Disable alarm interrupts */
270 rc
= ioctl(self
->fd
, RTC_AIE_OFF
, 0);
273 rc
= read(self
->fd
, &data
, sizeof(unsigned long));
275 TH_LOG("data: %lx", data
);
277 rc
= ioctl(self
->fd
, RTC_RD_TIME
, &tm
);
280 new = timegm((struct tm
*)&tm
);
281 ASSERT_EQ(new, secs
);
284 TEST_F(rtc
, alarm_wkalm_set
) {
285 struct timeval tv
= { .tv_sec
= ALARM_DELTA
+ 2 };
286 struct rtc_wkalrm alarm
= { 0 };
292 enum rtc_alarm_state alarm_state
= RTC_ALARM_UNKNOWN
;
294 if (self
->fd
== -1 && errno
== ENOENT
)
295 SKIP(return, "Skipping test since %s does not exist", rtc_file
);
296 ASSERT_NE(-1, self
->fd
);
298 alarm_state
= get_rtc_alarm_state(self
->fd
);
299 if (alarm_state
== RTC_ALARM_DISABLED
)
300 SKIP(return, "Skipping test since alarms are not supported.");
302 rc
= ioctl(self
->fd
, RTC_RD_TIME
, &alarm
.time
);
305 secs
= timegm((struct tm
*)&alarm
.time
) + ALARM_DELTA
;
306 gmtime_r(&secs
, (struct tm
*)&alarm
.time
);
310 rc
= ioctl(self
->fd
, RTC_WKALM_SET
, &alarm
);
313 * Report error if rtc alarm was enabled. Fallback to check ioctl
314 * error number if rtc alarm state is unknown.
316 ASSERT_EQ(RTC_ALARM_UNKNOWN
, alarm_state
);
317 ASSERT_EQ(EINVAL
, errno
);
318 TH_LOG("skip alarms are not supported.");
322 rc
= ioctl(self
->fd
, RTC_WKALM_RD
, &alarm
);
325 TH_LOG("Alarm time now set to %02d/%02d/%02d %02d:%02d:%02d.",
326 alarm
.time
.tm_mday
, alarm
.time
.tm_mon
+ 1,
327 alarm
.time
.tm_year
+ 1900, alarm
.time
.tm_hour
,
328 alarm
.time
.tm_min
, alarm
.time
.tm_sec
);
331 FD_SET(self
->fd
, &readfds
);
333 rc
= select(self
->fd
+ 1, &readfds
, NULL
, NULL
, &tv
);
337 rc
= read(self
->fd
, &data
, sizeof(unsigned long));
340 rc
= ioctl(self
->fd
, RTC_RD_TIME
, &tm
);
343 new = timegm((struct tm
*)&tm
);
344 ASSERT_EQ(new, secs
);
347 TEST_F_TIMEOUT(rtc
, alarm_alm_set_minute
, 65) {
348 struct timeval tv
= { .tv_sec
= 62 };
354 enum rtc_alarm_state alarm_state
= RTC_ALARM_UNKNOWN
;
356 if (self
->fd
== -1 && errno
== ENOENT
)
357 SKIP(return, "Skipping test since %s does not exist", rtc_file
);
358 ASSERT_NE(-1, self
->fd
);
360 alarm_state
= get_rtc_alarm_state(self
->fd
);
361 if (alarm_state
== RTC_ALARM_DISABLED
)
362 SKIP(return, "Skipping test since alarms are not supported.");
364 rc
= ioctl(self
->fd
, RTC_RD_TIME
, &tm
);
367 secs
= timegm((struct tm
*)&tm
) + 60 - tm
.tm_sec
;
368 gmtime_r(&secs
, (struct tm
*)&tm
);
370 rc
= ioctl(self
->fd
, RTC_ALM_SET
, &tm
);
373 * Report error if rtc alarm was enabled. Fallback to check ioctl
374 * error number if rtc alarm state is unknown.
376 ASSERT_EQ(RTC_ALARM_UNKNOWN
, alarm_state
);
377 ASSERT_EQ(EINVAL
, errno
);
378 TH_LOG("skip alarms are not supported.");
382 rc
= ioctl(self
->fd
, RTC_ALM_READ
, &tm
);
385 TH_LOG("Alarm time now set to %02d:%02d:%02d.",
386 tm
.tm_hour
, tm
.tm_min
, tm
.tm_sec
);
388 /* Enable alarm interrupts */
389 rc
= ioctl(self
->fd
, RTC_AIE_ON
, 0);
393 FD_SET(self
->fd
, &readfds
);
395 rc
= select(self
->fd
+ 1, &readfds
, NULL
, NULL
, &tv
);
399 /* Disable alarm interrupts */
400 rc
= ioctl(self
->fd
, RTC_AIE_OFF
, 0);
403 rc
= read(self
->fd
, &data
, sizeof(unsigned long));
405 TH_LOG("data: %lx", data
);
407 rc
= ioctl(self
->fd
, RTC_RD_TIME
, &tm
);
410 new = timegm((struct tm
*)&tm
);
411 ASSERT_EQ(new, secs
);
414 TEST_F_TIMEOUT(rtc
, alarm_wkalm_set_minute
, 65) {
415 struct timeval tv
= { .tv_sec
= 62 };
416 struct rtc_wkalrm alarm
= { 0 };
422 enum rtc_alarm_state alarm_state
= RTC_ALARM_UNKNOWN
;
424 if (self
->fd
== -1 && errno
== ENOENT
)
425 SKIP(return, "Skipping test since %s does not exist", rtc_file
);
426 ASSERT_NE(-1, self
->fd
);
428 alarm_state
= get_rtc_alarm_state(self
->fd
);
429 if (alarm_state
== RTC_ALARM_DISABLED
)
430 SKIP(return, "Skipping test since alarms are not supported.");
432 rc
= ioctl(self
->fd
, RTC_RD_TIME
, &alarm
.time
);
435 secs
= timegm((struct tm
*)&alarm
.time
) + 60 - alarm
.time
.tm_sec
;
436 gmtime_r(&secs
, (struct tm
*)&alarm
.time
);
440 rc
= ioctl(self
->fd
, RTC_WKALM_SET
, &alarm
);
443 * Report error if rtc alarm was enabled. Fallback to check ioctl
444 * error number if rtc alarm state is unknown.
446 ASSERT_EQ(RTC_ALARM_UNKNOWN
, alarm_state
);
447 ASSERT_EQ(EINVAL
, errno
);
448 TH_LOG("skip alarms are not supported.");
452 rc
= ioctl(self
->fd
, RTC_WKALM_RD
, &alarm
);
455 TH_LOG("Alarm time now set to %02d/%02d/%02d %02d:%02d:%02d.",
456 alarm
.time
.tm_mday
, alarm
.time
.tm_mon
+ 1,
457 alarm
.time
.tm_year
+ 1900, alarm
.time
.tm_hour
,
458 alarm
.time
.tm_min
, alarm
.time
.tm_sec
);
461 FD_SET(self
->fd
, &readfds
);
463 rc
= select(self
->fd
+ 1, &readfds
, NULL
, NULL
, &tv
);
467 rc
= read(self
->fd
, &data
, sizeof(unsigned long));
470 rc
= ioctl(self
->fd
, RTC_RD_TIME
, &tm
);
473 new = timegm((struct tm
*)&tm
);
474 ASSERT_EQ(new, secs
);
477 int main(int argc
, char **argv
)
488 fprintf(stderr
, "usage: %s [rtcdev]\n", argv
[0]);
492 /* Run the test if rtc_file is accessible */
493 if (access(rtc_file
, R_OK
) == 0)
494 ret
= test_harness_run(argc
, argv
);
496 ksft_exit_skip("[SKIP]: Cannot access rtc file %s - Exiting\n",