1 // SPDX-License-Identifier: GPL-2.0
3 * Real Time Clock Driver Test Program
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";
33 self->fd = open(rtc_file, O_RDONLY);
36 FIXTURE_TEARDOWN(rtc) {
40 TEST_F(rtc, date_read) {
42 struct rtc_time rtc_tm;
44 if (self->fd == -1 && errno == ENOENT)
45 SKIP(return, "Skipping test since %s does not exist", rtc_file);
46 ASSERT_NE(-1, self->fd);
48 /* Read the RTC time/date */
49 rc = ioctl(self->fd, RTC_RD_TIME, &rtc_tm);
52 TH_LOG("Current RTC date/time is %02d/%02d/%02d %02d:%02d:%02d.",
53 rtc_tm.tm_mday, rtc_tm.tm_mon + 1, rtc_tm.tm_year + 1900,
54 rtc_tm.tm_hour, rtc_tm.tm_min, rtc_tm.tm_sec);
57 static time_t rtc_time_to_timestamp(struct rtc_time *rtc_time)
60 .tm_sec = rtc_time->tm_sec,
61 .tm_min = rtc_time->tm_min,
62 .tm_hour = rtc_time->tm_hour,
63 .tm_mday = rtc_time->tm_mday,
64 .tm_mon = rtc_time->tm_mon,
65 .tm_year = rtc_time->tm_year,
68 return mktime(&tm_time);
71 static void nanosleep_with_retries(long ns)
73 struct timespec req = {
79 while (nanosleep(&req, &rem) != 0) {
80 req.tv_sec = rem.tv_sec;
81 req.tv_nsec = rem.tv_nsec;
85 TEST_F_TIMEOUT(rtc, date_read_loop, READ_LOOP_DURATION_SEC + 2) {
88 struct rtc_time rtc_tm;
89 time_t start_rtc_read, prev_rtc_read;
91 if (self->fd == -1 && errno == ENOENT)
92 SKIP(return, "Skipping test since %s does not exist", rtc_file);
93 ASSERT_NE(-1, self->fd);
95 TH_LOG("Continuously reading RTC time for %ds (with %dms breaks after every read).",
96 READ_LOOP_DURATION_SEC, READ_LOOP_SLEEP_MS);
98 rc = ioctl(self->fd, RTC_RD_TIME, &rtc_tm);
100 start_rtc_read = rtc_time_to_timestamp(&rtc_tm);
101 prev_rtc_read = start_rtc_read;
106 rc = ioctl(self->fd, RTC_RD_TIME, &rtc_tm);
109 rtc_read = rtc_time_to_timestamp(&rtc_tm);
110 /* Time should not go backwards */
111 ASSERT_LE(prev_rtc_read, rtc_read);
112 /* Time should not increase more then 1s at a time */
113 ASSERT_GE(prev_rtc_read + 1, rtc_read);
115 /* Sleep 11ms to avoid killing / overheating the RTC */
116 nanosleep_with_retries(READ_LOOP_SLEEP_MS * 1000000);
118 prev_rtc_read = rtc_read;
120 } while (prev_rtc_read <= start_rtc_read + READ_LOOP_DURATION_SEC);
122 TH_LOG("Performed %ld RTC time reads.", iter_count);
125 TEST_F_TIMEOUT(rtc, uie_read, NUM_UIE + 2) {
129 if (self->fd == -1 && errno == ENOENT)
130 SKIP(return, "Skipping test since %s does not exist", rtc_file);
131 ASSERT_NE(-1, self->fd);
133 /* Turn on update interrupts */
134 rc = ioctl(self->fd, RTC_UIE_ON, 0);
136 ASSERT_EQ(EINVAL, errno);
137 TH_LOG("skip update IRQs not supported.");
141 for (i = 0; i < NUM_UIE; i++) {
142 /* This read will block */
143 rc = read(self->fd, &data, sizeof(data));
148 EXPECT_EQ(NUM_UIE, irq);
150 rc = ioctl(self->fd, RTC_UIE_OFF, 0);
154 TEST_F(rtc, uie_select) {
158 if (self->fd == -1 && errno == ENOENT)
159 SKIP(return, "Skipping test since %s does not exist", rtc_file);
160 ASSERT_NE(-1, self->fd);
162 /* Turn on update interrupts */
163 rc = ioctl(self->fd, RTC_UIE_ON, 0);
165 ASSERT_EQ(EINVAL, errno);
166 TH_LOG("skip update IRQs not supported.");
170 for (i = 0; i < NUM_UIE; i++) {
171 struct timeval tv = { .tv_sec = 2 };
175 FD_SET(self->fd, &readfds);
176 /* The select will wait until an RTC interrupt happens. */
177 rc = select(self->fd + 1, &readfds, NULL, NULL, &tv);
181 /* This read won't block */
182 rc = read(self->fd, &data, sizeof(unsigned long));
187 EXPECT_EQ(NUM_UIE, irq);
189 rc = ioctl(self->fd, RTC_UIE_OFF, 0);
193 TEST_F(rtc, alarm_alm_set) {
194 struct timeval tv = { .tv_sec = ALARM_DELTA + 2 };
201 if (self->fd == -1 && errno == ENOENT)
202 SKIP(return, "Skipping test since %s does not exist", rtc_file);
203 ASSERT_NE(-1, self->fd);
205 rc = ioctl(self->fd, RTC_RD_TIME, &tm);
208 secs = timegm((struct tm *)&tm) + ALARM_DELTA;
209 gmtime_r(&secs, (struct tm *)&tm);
211 rc = ioctl(self->fd, RTC_ALM_SET, &tm);
213 ASSERT_EQ(EINVAL, errno);
214 TH_LOG("skip alarms are not supported.");
218 rc = ioctl(self->fd, RTC_ALM_READ, &tm);
221 TH_LOG("Alarm time now set to %02d:%02d:%02d.",
222 tm.tm_hour, tm.tm_min, tm.tm_sec);
224 /* Enable alarm interrupts */
225 rc = ioctl(self->fd, RTC_AIE_ON, 0);
229 FD_SET(self->fd, &readfds);
231 rc = select(self->fd + 1, &readfds, NULL, NULL, &tv);
235 /* Disable alarm interrupts */
236 rc = ioctl(self->fd, RTC_AIE_OFF, 0);
239 rc = read(self->fd, &data, sizeof(unsigned long));
241 TH_LOG("data: %lx", data);
243 rc = ioctl(self->fd, RTC_RD_TIME, &tm);
246 new = timegm((struct tm *)&tm);
247 ASSERT_EQ(new, secs);
250 TEST_F(rtc, alarm_wkalm_set) {
251 struct timeval tv = { .tv_sec = ALARM_DELTA + 2 };
252 struct rtc_wkalrm alarm = { 0 };
259 if (self->fd == -1 && errno == ENOENT)
260 SKIP(return, "Skipping test since %s does not exist", rtc_file);
261 ASSERT_NE(-1, self->fd);
263 rc = ioctl(self->fd, RTC_RD_TIME, &alarm.time);
266 secs = timegm((struct tm *)&alarm.time) + ALARM_DELTA;
267 gmtime_r(&secs, (struct tm *)&alarm.time);
271 rc = ioctl(self->fd, RTC_WKALM_SET, &alarm);
273 ASSERT_EQ(EINVAL, errno);
274 TH_LOG("skip alarms are not supported.");
278 rc = ioctl(self->fd, RTC_WKALM_RD, &alarm);
281 TH_LOG("Alarm time now set to %02d/%02d/%02d %02d:%02d:%02d.",
282 alarm.time.tm_mday, alarm.time.tm_mon + 1,
283 alarm.time.tm_year + 1900, alarm.time.tm_hour,
284 alarm.time.tm_min, alarm.time.tm_sec);
287 FD_SET(self->fd, &readfds);
289 rc = select(self->fd + 1, &readfds, NULL, NULL, &tv);
293 rc = read(self->fd, &data, sizeof(unsigned long));
296 rc = ioctl(self->fd, RTC_RD_TIME, &tm);
299 new = timegm((struct tm *)&tm);
300 ASSERT_EQ(new, secs);
303 TEST_F_TIMEOUT(rtc, alarm_alm_set_minute, 65) {
304 struct timeval tv = { .tv_sec = 62 };
311 if (self->fd == -1 && errno == ENOENT)
312 SKIP(return, "Skipping test since %s does not exist", rtc_file);
313 ASSERT_NE(-1, self->fd);
315 rc = ioctl(self->fd, RTC_RD_TIME, &tm);
318 secs = timegm((struct tm *)&tm) + 60 - tm.tm_sec;
319 gmtime_r(&secs, (struct tm *)&tm);
321 rc = ioctl(self->fd, RTC_ALM_SET, &tm);
323 ASSERT_EQ(EINVAL, errno);
324 TH_LOG("skip alarms are not supported.");
328 rc = ioctl(self->fd, RTC_ALM_READ, &tm);
331 TH_LOG("Alarm time now set to %02d:%02d:%02d.",
332 tm.tm_hour, tm.tm_min, tm.tm_sec);
334 /* Enable alarm interrupts */
335 rc = ioctl(self->fd, RTC_AIE_ON, 0);
339 FD_SET(self->fd, &readfds);
341 rc = select(self->fd + 1, &readfds, NULL, NULL, &tv);
345 /* Disable alarm interrupts */
346 rc = ioctl(self->fd, RTC_AIE_OFF, 0);
349 rc = read(self->fd, &data, sizeof(unsigned long));
351 TH_LOG("data: %lx", data);
353 rc = ioctl(self->fd, RTC_RD_TIME, &tm);
356 new = timegm((struct tm *)&tm);
357 ASSERT_EQ(new, secs);
360 TEST_F_TIMEOUT(rtc, alarm_wkalm_set_minute, 65) {
361 struct timeval tv = { .tv_sec = 62 };
362 struct rtc_wkalrm alarm = { 0 };
369 if (self->fd == -1 && errno == ENOENT)
370 SKIP(return, "Skipping test since %s does not exist", rtc_file);
371 ASSERT_NE(-1, self->fd);
373 rc = ioctl(self->fd, RTC_RD_TIME, &alarm.time);
376 secs = timegm((struct tm *)&alarm.time) + 60 - alarm.time.tm_sec;
377 gmtime_r(&secs, (struct tm *)&alarm.time);
381 rc = ioctl(self->fd, RTC_WKALM_SET, &alarm);
383 ASSERT_EQ(EINVAL, errno);
384 TH_LOG("skip alarms are not supported.");
388 rc = ioctl(self->fd, RTC_WKALM_RD, &alarm);
391 TH_LOG("Alarm time now set to %02d/%02d/%02d %02d:%02d:%02d.",
392 alarm.time.tm_mday, alarm.time.tm_mon + 1,
393 alarm.time.tm_year + 1900, alarm.time.tm_hour,
394 alarm.time.tm_min, alarm.time.tm_sec);
397 FD_SET(self->fd, &readfds);
399 rc = select(self->fd + 1, &readfds, NULL, NULL, &tv);
403 rc = read(self->fd, &data, sizeof(unsigned long));
406 rc = ioctl(self->fd, RTC_RD_TIME, &tm);
409 new = timegm((struct tm *)&tm);
410 ASSERT_EQ(new, secs);
413 static void __attribute__((constructor))
414 __constructor_order_last(void)
416 if (!__constructor_order)
417 __constructor_order = _CONSTRUCTOR_ORDER_BACKWARD;
420 int main(int argc, char **argv)
429 fprintf(stderr, "usage: %s [rtcdev]\n", argv[0]);
433 return test_harness_run(argc, argv);