xref: /openbmc/linux/tools/testing/selftests/rtc/rtctest.c (revision d8da8665e8e34c14f9b20fe3f21dff29b24cbf02)
1*d8da8665SAlexandre Belloni // SPDX-License-Identifier: GPL-2.0
2a12ab9e1SAlexandre Belloni /*
3*d8da8665SAlexandre Belloni  * Real Time Clock Driver Test Program
4a12ab9e1SAlexandre Belloni  *
5*d8da8665SAlexandre Belloni  * Copyright (c) 2018 Alexandre Belloni <alexandre.belloni@bootlin.com>
6a12ab9e1SAlexandre Belloni  */
7a12ab9e1SAlexandre Belloni 
8*d8da8665SAlexandre Belloni #include <errno.h>
9*d8da8665SAlexandre Belloni #include <fcntl.h>
10a12ab9e1SAlexandre Belloni #include <linux/rtc.h>
11*d8da8665SAlexandre Belloni #include <stdio.h>
12*d8da8665SAlexandre Belloni #include <stdlib.h>
13a12ab9e1SAlexandre Belloni #include <sys/ioctl.h>
14a12ab9e1SAlexandre Belloni #include <sys/time.h>
15a12ab9e1SAlexandre Belloni #include <sys/types.h>
16*d8da8665SAlexandre Belloni #include <time.h>
17a12ab9e1SAlexandre Belloni #include <unistd.h>
18a12ab9e1SAlexandre Belloni 
19*d8da8665SAlexandre Belloni #include "../kselftest_harness.h"
20a12ab9e1SAlexandre Belloni 
21*d8da8665SAlexandre Belloni #define NUM_UIE 3
22*d8da8665SAlexandre Belloni #define ALARM_DELTA 3
23a12ab9e1SAlexandre Belloni 
24*d8da8665SAlexandre Belloni static char *rtc_file = "/dev/rtc0";
25*d8da8665SAlexandre Belloni 
26*d8da8665SAlexandre Belloni FIXTURE(rtc) {
27*d8da8665SAlexandre Belloni 	int fd;
28a12ab9e1SAlexandre Belloni };
29a12ab9e1SAlexandre Belloni 
30*d8da8665SAlexandre Belloni FIXTURE_SETUP(rtc) {
31*d8da8665SAlexandre Belloni 	self->fd = open(rtc_file, O_RDONLY);
32*d8da8665SAlexandre Belloni 	ASSERT_NE(-1, self->fd);
33*d8da8665SAlexandre Belloni }
34a12ab9e1SAlexandre Belloni 
35*d8da8665SAlexandre Belloni FIXTURE_TEARDOWN(rtc) {
36*d8da8665SAlexandre Belloni 	close(self->fd);
37*d8da8665SAlexandre Belloni }
38*d8da8665SAlexandre Belloni 
39*d8da8665SAlexandre Belloni TEST_F(rtc, date_read) {
40*d8da8665SAlexandre Belloni 	int rc;
41*d8da8665SAlexandre Belloni 	struct rtc_time rtc_tm;
42*d8da8665SAlexandre Belloni 
43*d8da8665SAlexandre Belloni 	/* Read the RTC time/date */
44*d8da8665SAlexandre Belloni 	rc = ioctl(self->fd, RTC_RD_TIME, &rtc_tm);
45*d8da8665SAlexandre Belloni 	ASSERT_NE(-1, rc);
46*d8da8665SAlexandre Belloni 
47*d8da8665SAlexandre Belloni 	TH_LOG("Current RTC date/time is %02d/%02d/%02d %02d:%02d:%02d.",
48*d8da8665SAlexandre Belloni 	       rtc_tm.tm_mday, rtc_tm.tm_mon + 1, rtc_tm.tm_year + 1900,
49*d8da8665SAlexandre Belloni 	       rtc_tm.tm_hour, rtc_tm.tm_min, rtc_tm.tm_sec);
50*d8da8665SAlexandre Belloni }
51*d8da8665SAlexandre Belloni 
52*d8da8665SAlexandre Belloni TEST_F(rtc, uie_read) {
53*d8da8665SAlexandre Belloni 	int i, rc, irq = 0;
54*d8da8665SAlexandre Belloni 	unsigned long data;
55*d8da8665SAlexandre Belloni 
56*d8da8665SAlexandre Belloni 	/* Turn on update interrupts */
57*d8da8665SAlexandre Belloni 	rc = ioctl(self->fd, RTC_UIE_ON, 0);
58*d8da8665SAlexandre Belloni 	if (rc == -1) {
59*d8da8665SAlexandre Belloni 		ASSERT_EQ(EINVAL, errno);
60*d8da8665SAlexandre Belloni 		TH_LOG("skip update IRQs not supported.");
61*d8da8665SAlexandre Belloni 		return;
62*d8da8665SAlexandre Belloni 	}
63*d8da8665SAlexandre Belloni 
64*d8da8665SAlexandre Belloni 	for (i = 0; i < NUM_UIE; i++) {
65*d8da8665SAlexandre Belloni 		/* This read will block */
66*d8da8665SAlexandre Belloni 		rc = read(self->fd, &data, sizeof(data));
67*d8da8665SAlexandre Belloni 		ASSERT_NE(-1, rc);
68*d8da8665SAlexandre Belloni 		irq++;
69*d8da8665SAlexandre Belloni 	}
70*d8da8665SAlexandre Belloni 
71*d8da8665SAlexandre Belloni 	EXPECT_EQ(NUM_UIE, irq);
72*d8da8665SAlexandre Belloni 
73*d8da8665SAlexandre Belloni 	rc = ioctl(self->fd, RTC_UIE_OFF, 0);
74*d8da8665SAlexandre Belloni 	ASSERT_NE(-1, rc);
75*d8da8665SAlexandre Belloni }
76*d8da8665SAlexandre Belloni 
77*d8da8665SAlexandre Belloni TEST_F(rtc, uie_select) {
78*d8da8665SAlexandre Belloni 	int i, rc, irq = 0;
79*d8da8665SAlexandre Belloni 	unsigned long data;
80*d8da8665SAlexandre Belloni 
81*d8da8665SAlexandre Belloni 	/* Turn on update interrupts */
82*d8da8665SAlexandre Belloni 	rc = ioctl(self->fd, RTC_UIE_ON, 0);
83*d8da8665SAlexandre Belloni 	if (rc == -1) {
84*d8da8665SAlexandre Belloni 		ASSERT_EQ(EINVAL, errno);
85*d8da8665SAlexandre Belloni 		TH_LOG("skip update IRQs not supported.");
86*d8da8665SAlexandre Belloni 		return;
87*d8da8665SAlexandre Belloni 	}
88*d8da8665SAlexandre Belloni 
89*d8da8665SAlexandre Belloni 	for (i = 0; i < NUM_UIE; i++) {
90*d8da8665SAlexandre Belloni 		struct timeval tv = { .tv_sec = 2 };
91*d8da8665SAlexandre Belloni 		fd_set readfds;
92*d8da8665SAlexandre Belloni 
93*d8da8665SAlexandre Belloni 		FD_ZERO(&readfds);
94*d8da8665SAlexandre Belloni 		FD_SET(self->fd, &readfds);
95*d8da8665SAlexandre Belloni 		/* The select will wait until an RTC interrupt happens. */
96*d8da8665SAlexandre Belloni 		rc = select(self->fd + 1, &readfds, NULL, NULL, &tv);
97*d8da8665SAlexandre Belloni 		ASSERT_NE(-1, rc);
98*d8da8665SAlexandre Belloni 		ASSERT_NE(0, rc);
99*d8da8665SAlexandre Belloni 
100*d8da8665SAlexandre Belloni 		/* This read won't block */
101*d8da8665SAlexandre Belloni 		rc = read(self->fd, &data, sizeof(unsigned long));
102*d8da8665SAlexandre Belloni 		ASSERT_NE(-1, rc);
103*d8da8665SAlexandre Belloni 		irq++;
104*d8da8665SAlexandre Belloni 	}
105*d8da8665SAlexandre Belloni 
106*d8da8665SAlexandre Belloni 	EXPECT_EQ(NUM_UIE, irq);
107*d8da8665SAlexandre Belloni 
108*d8da8665SAlexandre Belloni 	rc = ioctl(self->fd, RTC_UIE_OFF, 0);
109*d8da8665SAlexandre Belloni 	ASSERT_NE(-1, rc);
110*d8da8665SAlexandre Belloni }
111*d8da8665SAlexandre Belloni 
112*d8da8665SAlexandre Belloni TEST_F(rtc, alarm_alm_set) {
113*d8da8665SAlexandre Belloni 	struct timeval tv = { .tv_sec = ALARM_DELTA + 2 };
114*d8da8665SAlexandre Belloni 	unsigned long data;
115*d8da8665SAlexandre Belloni 	struct rtc_time tm;
116*d8da8665SAlexandre Belloni 	fd_set readfds;
117*d8da8665SAlexandre Belloni 	time_t secs, new;
118*d8da8665SAlexandre Belloni 	int rc;
119*d8da8665SAlexandre Belloni 
120*d8da8665SAlexandre Belloni 	rc = ioctl(self->fd, RTC_RD_TIME, &tm);
121*d8da8665SAlexandre Belloni 	ASSERT_NE(-1, rc);
122*d8da8665SAlexandre Belloni 
123*d8da8665SAlexandre Belloni 	secs = timegm((struct tm *)&tm) + ALARM_DELTA;
124*d8da8665SAlexandre Belloni 	gmtime_r(&secs, (struct tm *)&tm);
125*d8da8665SAlexandre Belloni 
126*d8da8665SAlexandre Belloni 	rc = ioctl(self->fd, RTC_ALM_SET, &tm);
127*d8da8665SAlexandre Belloni 	if (rc == -1) {
128*d8da8665SAlexandre Belloni 		ASSERT_EQ(EINVAL, errno);
129*d8da8665SAlexandre Belloni 		TH_LOG("skip alarms are not supported.");
130*d8da8665SAlexandre Belloni 		return;
131*d8da8665SAlexandre Belloni 	}
132*d8da8665SAlexandre Belloni 
133*d8da8665SAlexandre Belloni 	rc = ioctl(self->fd, RTC_ALM_READ, &tm);
134*d8da8665SAlexandre Belloni 	ASSERT_NE(-1, rc);
135*d8da8665SAlexandre Belloni 
136*d8da8665SAlexandre Belloni 	TH_LOG("Alarm time now set to %02d:%02d:%02d.",
137*d8da8665SAlexandre Belloni 	       tm.tm_hour, tm.tm_min, tm.tm_sec);
138*d8da8665SAlexandre Belloni 
139*d8da8665SAlexandre Belloni 	/* Enable alarm interrupts */
140*d8da8665SAlexandre Belloni 	rc = ioctl(self->fd, RTC_AIE_ON, 0);
141*d8da8665SAlexandre Belloni 	ASSERT_NE(-1, rc);
142*d8da8665SAlexandre Belloni 
143*d8da8665SAlexandre Belloni 	FD_ZERO(&readfds);
144*d8da8665SAlexandre Belloni 	FD_SET(self->fd, &readfds);
145*d8da8665SAlexandre Belloni 
146*d8da8665SAlexandre Belloni 	rc = select(self->fd + 1, &readfds, NULL, NULL, &tv);
147*d8da8665SAlexandre Belloni 	ASSERT_NE(-1, rc);
148*d8da8665SAlexandre Belloni 	EXPECT_NE(0, rc);
149*d8da8665SAlexandre Belloni 
150*d8da8665SAlexandre Belloni 	/* Disable alarm interrupts */
151*d8da8665SAlexandre Belloni 	rc = ioctl(self->fd, RTC_AIE_OFF, 0);
152*d8da8665SAlexandre Belloni 	ASSERT_NE(-1, rc);
153*d8da8665SAlexandre Belloni 
154*d8da8665SAlexandre Belloni 	if (rc == 0)
155*d8da8665SAlexandre Belloni 		return;
156*d8da8665SAlexandre Belloni 
157*d8da8665SAlexandre Belloni 	rc = read(self->fd, &data, sizeof(unsigned long));
158*d8da8665SAlexandre Belloni 	ASSERT_NE(-1, rc);
159*d8da8665SAlexandre Belloni 	TH_LOG("data: %lx", data);
160*d8da8665SAlexandre Belloni 
161*d8da8665SAlexandre Belloni 	rc = ioctl(self->fd, RTC_RD_TIME, &tm);
162*d8da8665SAlexandre Belloni 	ASSERT_NE(-1, rc);
163*d8da8665SAlexandre Belloni 
164*d8da8665SAlexandre Belloni 	new = timegm((struct tm *)&tm);
165*d8da8665SAlexandre Belloni 	ASSERT_EQ(new, secs);
166*d8da8665SAlexandre Belloni }
167*d8da8665SAlexandre Belloni 
168*d8da8665SAlexandre Belloni TEST_F(rtc, alarm_wkalm_set) {
169*d8da8665SAlexandre Belloni 	struct timeval tv = { .tv_sec = ALARM_DELTA + 2 };
170*d8da8665SAlexandre Belloni 	struct rtc_wkalrm alarm = { 0 };
171*d8da8665SAlexandre Belloni 	struct rtc_time tm;
172*d8da8665SAlexandre Belloni 	unsigned long data;
173*d8da8665SAlexandre Belloni 	fd_set readfds;
174*d8da8665SAlexandre Belloni 	time_t secs, new;
175*d8da8665SAlexandre Belloni 	int rc;
176*d8da8665SAlexandre Belloni 
177*d8da8665SAlexandre Belloni 	rc = ioctl(self->fd, RTC_RD_TIME, &alarm.time);
178*d8da8665SAlexandre Belloni 	ASSERT_NE(-1, rc);
179*d8da8665SAlexandre Belloni 
180*d8da8665SAlexandre Belloni 	secs = timegm((struct tm *)&alarm.time) + ALARM_DELTA;
181*d8da8665SAlexandre Belloni 	gmtime_r(&secs, (struct tm *)&alarm.time);
182*d8da8665SAlexandre Belloni 
183*d8da8665SAlexandre Belloni 	alarm.enabled = 1;
184*d8da8665SAlexandre Belloni 
185*d8da8665SAlexandre Belloni 	rc = ioctl(self->fd, RTC_WKALM_SET, &alarm);
186*d8da8665SAlexandre Belloni 	if (rc == -1) {
187*d8da8665SAlexandre Belloni 		ASSERT_EQ(EINVAL, errno);
188*d8da8665SAlexandre Belloni 		TH_LOG("skip alarms are not supported.");
189*d8da8665SAlexandre Belloni 		return;
190*d8da8665SAlexandre Belloni 	}
191*d8da8665SAlexandre Belloni 
192*d8da8665SAlexandre Belloni 	rc = ioctl(self->fd, RTC_WKALM_RD, &alarm);
193*d8da8665SAlexandre Belloni 	ASSERT_NE(-1, rc);
194*d8da8665SAlexandre Belloni 
195*d8da8665SAlexandre Belloni 	TH_LOG("Alarm time now set to %02d/%02d/%02d %02d:%02d:%02d.",
196*d8da8665SAlexandre Belloni 	       alarm.time.tm_mday, alarm.time.tm_mon + 1,
197*d8da8665SAlexandre Belloni 	       alarm.time.tm_year + 1900, alarm.time.tm_hour,
198*d8da8665SAlexandre Belloni 	       alarm.time.tm_min, alarm.time.tm_sec);
199*d8da8665SAlexandre Belloni 
200*d8da8665SAlexandre Belloni 	FD_ZERO(&readfds);
201*d8da8665SAlexandre Belloni 	FD_SET(self->fd, &readfds);
202*d8da8665SAlexandre Belloni 
203*d8da8665SAlexandre Belloni 	rc = select(self->fd + 1, &readfds, NULL, NULL, &tv);
204*d8da8665SAlexandre Belloni 	ASSERT_NE(-1, rc);
205*d8da8665SAlexandre Belloni 	EXPECT_NE(0, rc);
206*d8da8665SAlexandre Belloni 
207*d8da8665SAlexandre Belloni 	rc = read(self->fd, &data, sizeof(unsigned long));
208*d8da8665SAlexandre Belloni 	ASSERT_NE(-1, rc);
209*d8da8665SAlexandre Belloni 
210*d8da8665SAlexandre Belloni 	rc = ioctl(self->fd, RTC_RD_TIME, &tm);
211*d8da8665SAlexandre Belloni 	ASSERT_NE(-1, rc);
212*d8da8665SAlexandre Belloni 
213*d8da8665SAlexandre Belloni 	new = timegm((struct tm *)&tm);
214*d8da8665SAlexandre Belloni 	ASSERT_EQ(new, secs);
215*d8da8665SAlexandre Belloni }
216*d8da8665SAlexandre Belloni 
217*d8da8665SAlexandre Belloni static void __attribute__((constructor))
218*d8da8665SAlexandre Belloni __constructor_order_last(void)
219*d8da8665SAlexandre Belloni {
220*d8da8665SAlexandre Belloni 	if (!__constructor_order)
221*d8da8665SAlexandre Belloni 		__constructor_order = _CONSTRUCTOR_ORDER_BACKWARD;
222a12ab9e1SAlexandre Belloni }
223a12ab9e1SAlexandre Belloni 
224a12ab9e1SAlexandre Belloni int main(int argc, char **argv)
225a12ab9e1SAlexandre Belloni {
226a12ab9e1SAlexandre Belloni 	switch (argc) {
227a12ab9e1SAlexandre Belloni 	case 2:
228*d8da8665SAlexandre Belloni 		rtc_file = argv[1];
229a12ab9e1SAlexandre Belloni 		/* FALLTHROUGH */
230a12ab9e1SAlexandre Belloni 	case 1:
231a12ab9e1SAlexandre Belloni 		break;
232a12ab9e1SAlexandre Belloni 	default:
233*d8da8665SAlexandre Belloni 		fprintf(stderr, "usage: %s [rtcdev]\n", argv[0]);
234a12ab9e1SAlexandre Belloni 		return 1;
235a12ab9e1SAlexandre Belloni 	}
236a12ab9e1SAlexandre Belloni 
237*d8da8665SAlexandre Belloni 	return test_harness_run(argc, argv);
238a12ab9e1SAlexandre Belloni }
239