xref: /aosp_15_r20/external/linux-kselftest/tools/testing/selftests/rtc/rtctest.c (revision 053f45be4e351dfd5e965df293cd45b779f579ee)
1*053f45beSAndroid Build Coastguard Worker // SPDX-License-Identifier: GPL-2.0
2*053f45beSAndroid Build Coastguard Worker /*
3*053f45beSAndroid Build Coastguard Worker  * Real Time Clock Driver Test Program
4*053f45beSAndroid Build Coastguard Worker  *
5*053f45beSAndroid Build Coastguard Worker  * Copyright (c) 2018 Alexandre Belloni <[email protected]>
6*053f45beSAndroid Build Coastguard Worker  */
7*053f45beSAndroid Build Coastguard Worker 
8*053f45beSAndroid Build Coastguard Worker #include <errno.h>
9*053f45beSAndroid Build Coastguard Worker #include <fcntl.h>
10*053f45beSAndroid Build Coastguard Worker #include <linux/rtc.h>
11*053f45beSAndroid Build Coastguard Worker #include <stdio.h>
12*053f45beSAndroid Build Coastguard Worker #include <stdlib.h>
13*053f45beSAndroid Build Coastguard Worker #include <sys/ioctl.h>
14*053f45beSAndroid Build Coastguard Worker #include <sys/time.h>
15*053f45beSAndroid Build Coastguard Worker #include <sys/types.h>
16*053f45beSAndroid Build Coastguard Worker #include <time.h>
17*053f45beSAndroid Build Coastguard Worker #include <unistd.h>
18*053f45beSAndroid Build Coastguard Worker 
19*053f45beSAndroid Build Coastguard Worker #include "../kselftest_harness.h"
20*053f45beSAndroid Build Coastguard Worker 
21*053f45beSAndroid Build Coastguard Worker #define NUM_UIE 3
22*053f45beSAndroid Build Coastguard Worker #define ALARM_DELTA 3
23*053f45beSAndroid Build Coastguard Worker #define READ_LOOP_DURATION_SEC 30
24*053f45beSAndroid Build Coastguard Worker #define READ_LOOP_SLEEP_MS 11
25*053f45beSAndroid Build Coastguard Worker 
26*053f45beSAndroid Build Coastguard Worker static char *rtc_file = "/dev/rtc0";
27*053f45beSAndroid Build Coastguard Worker 
FIXTURE(rtc)28*053f45beSAndroid Build Coastguard Worker FIXTURE(rtc) {
29*053f45beSAndroid Build Coastguard Worker 	int fd;
30*053f45beSAndroid Build Coastguard Worker };
31*053f45beSAndroid Build Coastguard Worker 
FIXTURE_SETUP(rtc)32*053f45beSAndroid Build Coastguard Worker FIXTURE_SETUP(rtc) {
33*053f45beSAndroid Build Coastguard Worker 	self->fd = open(rtc_file, O_RDONLY);
34*053f45beSAndroid Build Coastguard Worker 	ASSERT_NE(-1, self->fd);
35*053f45beSAndroid Build Coastguard Worker }
36*053f45beSAndroid Build Coastguard Worker 
FIXTURE_TEARDOWN(rtc)37*053f45beSAndroid Build Coastguard Worker FIXTURE_TEARDOWN(rtc) {
38*053f45beSAndroid Build Coastguard Worker 	close(self->fd);
39*053f45beSAndroid Build Coastguard Worker }
40*053f45beSAndroid Build Coastguard Worker 
TEST_F(rtc,date_read)41*053f45beSAndroid Build Coastguard Worker TEST_F(rtc, date_read) {
42*053f45beSAndroid Build Coastguard Worker 	int rc;
43*053f45beSAndroid Build Coastguard Worker 	struct rtc_time rtc_tm;
44*053f45beSAndroid Build Coastguard Worker 
45*053f45beSAndroid Build Coastguard Worker 	/* Read the RTC time/date */
46*053f45beSAndroid Build Coastguard Worker 	rc = ioctl(self->fd, RTC_RD_TIME, &rtc_tm);
47*053f45beSAndroid Build Coastguard Worker 	ASSERT_NE(-1, rc);
48*053f45beSAndroid Build Coastguard Worker 
49*053f45beSAndroid Build Coastguard Worker 	TH_LOG("Current RTC date/time is %02d/%02d/%02d %02d:%02d:%02d.",
50*053f45beSAndroid Build Coastguard Worker 	       rtc_tm.tm_mday, rtc_tm.tm_mon + 1, rtc_tm.tm_year + 1900,
51*053f45beSAndroid Build Coastguard Worker 	       rtc_tm.tm_hour, rtc_tm.tm_min, rtc_tm.tm_sec);
52*053f45beSAndroid Build Coastguard Worker }
53*053f45beSAndroid Build Coastguard Worker 
rtc_time_to_timestamp(struct rtc_time * rtc_time)54*053f45beSAndroid Build Coastguard Worker static time_t rtc_time_to_timestamp(struct rtc_time *rtc_time)
55*053f45beSAndroid Build Coastguard Worker {
56*053f45beSAndroid Build Coastguard Worker 	struct tm tm_time = {
57*053f45beSAndroid Build Coastguard Worker 	       .tm_sec = rtc_time->tm_sec,
58*053f45beSAndroid Build Coastguard Worker 	       .tm_min = rtc_time->tm_min,
59*053f45beSAndroid Build Coastguard Worker 	       .tm_hour = rtc_time->tm_hour,
60*053f45beSAndroid Build Coastguard Worker 	       .tm_mday = rtc_time->tm_mday,
61*053f45beSAndroid Build Coastguard Worker 	       .tm_mon = rtc_time->tm_mon,
62*053f45beSAndroid Build Coastguard Worker 	       .tm_year = rtc_time->tm_year,
63*053f45beSAndroid Build Coastguard Worker 	};
64*053f45beSAndroid Build Coastguard Worker 
65*053f45beSAndroid Build Coastguard Worker 	return mktime(&tm_time);
66*053f45beSAndroid Build Coastguard Worker }
67*053f45beSAndroid Build Coastguard Worker 
nanosleep_with_retries(long ns)68*053f45beSAndroid Build Coastguard Worker static void nanosleep_with_retries(long ns)
69*053f45beSAndroid Build Coastguard Worker {
70*053f45beSAndroid Build Coastguard Worker 	struct timespec req = {
71*053f45beSAndroid Build Coastguard Worker 		.tv_sec = 0,
72*053f45beSAndroid Build Coastguard Worker 		.tv_nsec = ns,
73*053f45beSAndroid Build Coastguard Worker 	};
74*053f45beSAndroid Build Coastguard Worker 	struct timespec rem;
75*053f45beSAndroid Build Coastguard Worker 
76*053f45beSAndroid Build Coastguard Worker 	while (nanosleep(&req, &rem) != 0) {
77*053f45beSAndroid Build Coastguard Worker 		req.tv_sec = rem.tv_sec;
78*053f45beSAndroid Build Coastguard Worker 		req.tv_nsec = rem.tv_nsec;
79*053f45beSAndroid Build Coastguard Worker 	}
80*053f45beSAndroid Build Coastguard Worker }
81*053f45beSAndroid Build Coastguard Worker 
82*053f45beSAndroid Build Coastguard Worker TEST_F_TIMEOUT(rtc, date_read_loop, READ_LOOP_DURATION_SEC + 2) {
83*053f45beSAndroid Build Coastguard Worker 	int rc;
84*053f45beSAndroid Build Coastguard Worker 	long iter_count = 0;
85*053f45beSAndroid Build Coastguard Worker 	struct rtc_time rtc_tm;
86*053f45beSAndroid Build Coastguard Worker 	time_t start_rtc_read, prev_rtc_read;
87*053f45beSAndroid Build Coastguard Worker 
88*053f45beSAndroid Build Coastguard Worker 	TH_LOG("Continuously reading RTC time for %ds (with %dms breaks after every read).",
89*053f45beSAndroid Build Coastguard Worker 	       READ_LOOP_DURATION_SEC, READ_LOOP_SLEEP_MS);
90*053f45beSAndroid Build Coastguard Worker 
91*053f45beSAndroid Build Coastguard Worker 	rc = ioctl(self->fd, RTC_RD_TIME, &rtc_tm);
92*053f45beSAndroid Build Coastguard Worker 	ASSERT_NE(-1, rc);
93*053f45beSAndroid Build Coastguard Worker 	start_rtc_read = rtc_time_to_timestamp(&rtc_tm);
94*053f45beSAndroid Build Coastguard Worker 	prev_rtc_read = start_rtc_read;
95*053f45beSAndroid Build Coastguard Worker 
96*053f45beSAndroid Build Coastguard Worker 	do  {
97*053f45beSAndroid Build Coastguard Worker 		time_t rtc_read;
98*053f45beSAndroid Build Coastguard Worker 
99*053f45beSAndroid Build Coastguard Worker 		rc = ioctl(self->fd, RTC_RD_TIME, &rtc_tm);
100*053f45beSAndroid Build Coastguard Worker 		ASSERT_NE(-1, rc);
101*053f45beSAndroid Build Coastguard Worker 
102*053f45beSAndroid Build Coastguard Worker 		rtc_read = rtc_time_to_timestamp(&rtc_tm);
103*053f45beSAndroid Build Coastguard Worker 		/* Time should not go backwards */
104*053f45beSAndroid Build Coastguard Worker 		ASSERT_LE(prev_rtc_read, rtc_read);
105*053f45beSAndroid Build Coastguard Worker 		/* Time should not increase more then 1s at a time */
106*053f45beSAndroid Build Coastguard Worker 		ASSERT_GE(prev_rtc_read + 1, rtc_read);
107*053f45beSAndroid Build Coastguard Worker 
108*053f45beSAndroid Build Coastguard Worker 		/* Sleep 11ms to avoid killing / overheating the RTC */
109*053f45beSAndroid Build Coastguard Worker 		nanosleep_with_retries(READ_LOOP_SLEEP_MS * 1000000);
110*053f45beSAndroid Build Coastguard Worker 
111*053f45beSAndroid Build Coastguard Worker 		prev_rtc_read = rtc_read;
112*053f45beSAndroid Build Coastguard Worker 		iter_count++;
113*053f45beSAndroid Build Coastguard Worker 	} while (prev_rtc_read <= start_rtc_read + READ_LOOP_DURATION_SEC);
114*053f45beSAndroid Build Coastguard Worker 
115*053f45beSAndroid Build Coastguard Worker 	TH_LOG("Performed %ld RTC time reads.", iter_count);
116*053f45beSAndroid Build Coastguard Worker }
117*053f45beSAndroid Build Coastguard Worker 
118*053f45beSAndroid Build Coastguard Worker #ifndef __ANDROID__ // b/31578457
119*053f45beSAndroid Build Coastguard Worker TEST_F_TIMEOUT(rtc, uie_read, NUM_UIE + 2) {
120*053f45beSAndroid Build Coastguard Worker 	int i, rc, irq = 0;
121*053f45beSAndroid Build Coastguard Worker 	unsigned long data;
122*053f45beSAndroid Build Coastguard Worker 
123*053f45beSAndroid Build Coastguard Worker 	/* Turn on update interrupts */
124*053f45beSAndroid Build Coastguard Worker 	rc = ioctl(self->fd, RTC_UIE_ON, 0);
125*053f45beSAndroid Build Coastguard Worker 	if (rc == -1) {
126*053f45beSAndroid Build Coastguard Worker 		ASSERT_EQ(EINVAL, errno);
127*053f45beSAndroid Build Coastguard Worker 		TH_LOG("skip update IRQs not supported.");
128*053f45beSAndroid Build Coastguard Worker 		return;
129*053f45beSAndroid Build Coastguard Worker 	}
130*053f45beSAndroid Build Coastguard Worker 
131*053f45beSAndroid Build Coastguard Worker 	for (i = 0; i < NUM_UIE; i++) {
132*053f45beSAndroid Build Coastguard Worker 		/* This read will block */
133*053f45beSAndroid Build Coastguard Worker 		rc = read(self->fd, &data, sizeof(data));
134*053f45beSAndroid Build Coastguard Worker 		ASSERT_NE(-1, rc);
135*053f45beSAndroid Build Coastguard Worker 		irq++;
136*053f45beSAndroid Build Coastguard Worker 	}
137*053f45beSAndroid Build Coastguard Worker 
138*053f45beSAndroid Build Coastguard Worker 	EXPECT_EQ(NUM_UIE, irq);
139*053f45beSAndroid Build Coastguard Worker 
140*053f45beSAndroid Build Coastguard Worker 	rc = ioctl(self->fd, RTC_UIE_OFF, 0);
141*053f45beSAndroid Build Coastguard Worker 	ASSERT_NE(-1, rc);
142*053f45beSAndroid Build Coastguard Worker }
143*053f45beSAndroid Build Coastguard Worker 
TEST_F(rtc,uie_select)144*053f45beSAndroid Build Coastguard Worker TEST_F(rtc, uie_select) {
145*053f45beSAndroid Build Coastguard Worker 	int i, rc, irq = 0;
146*053f45beSAndroid Build Coastguard Worker 	unsigned long data;
147*053f45beSAndroid Build Coastguard Worker 
148*053f45beSAndroid Build Coastguard Worker 	/* Turn on update interrupts */
149*053f45beSAndroid Build Coastguard Worker 	rc = ioctl(self->fd, RTC_UIE_ON, 0);
150*053f45beSAndroid Build Coastguard Worker 	if (rc == -1) {
151*053f45beSAndroid Build Coastguard Worker 		ASSERT_EQ(EINVAL, errno);
152*053f45beSAndroid Build Coastguard Worker 		TH_LOG("skip update IRQs not supported.");
153*053f45beSAndroid Build Coastguard Worker 		return;
154*053f45beSAndroid Build Coastguard Worker 	}
155*053f45beSAndroid Build Coastguard Worker 
156*053f45beSAndroid Build Coastguard Worker 	for (i = 0; i < NUM_UIE; i++) {
157*053f45beSAndroid Build Coastguard Worker 		struct timeval tv = { .tv_sec = 2 };
158*053f45beSAndroid Build Coastguard Worker 		fd_set readfds;
159*053f45beSAndroid Build Coastguard Worker 
160*053f45beSAndroid Build Coastguard Worker 		FD_ZERO(&readfds);
161*053f45beSAndroid Build Coastguard Worker 		FD_SET(self->fd, &readfds);
162*053f45beSAndroid Build Coastguard Worker 		/* The select will wait until an RTC interrupt happens. */
163*053f45beSAndroid Build Coastguard Worker 		rc = select(self->fd + 1, &readfds, NULL, NULL, &tv);
164*053f45beSAndroid Build Coastguard Worker 		ASSERT_NE(-1, rc);
165*053f45beSAndroid Build Coastguard Worker 		ASSERT_NE(0, rc);
166*053f45beSAndroid Build Coastguard Worker 
167*053f45beSAndroid Build Coastguard Worker 		/* This read won't block */
168*053f45beSAndroid Build Coastguard Worker 		rc = read(self->fd, &data, sizeof(unsigned long));
169*053f45beSAndroid Build Coastguard Worker 		ASSERT_NE(-1, rc);
170*053f45beSAndroid Build Coastguard Worker 		irq++;
171*053f45beSAndroid Build Coastguard Worker 	}
172*053f45beSAndroid Build Coastguard Worker 
173*053f45beSAndroid Build Coastguard Worker 	EXPECT_EQ(NUM_UIE, irq);
174*053f45beSAndroid Build Coastguard Worker 
175*053f45beSAndroid Build Coastguard Worker 	rc = ioctl(self->fd, RTC_UIE_OFF, 0);
176*053f45beSAndroid Build Coastguard Worker 	ASSERT_NE(-1, rc);
177*053f45beSAndroid Build Coastguard Worker }
178*053f45beSAndroid Build Coastguard Worker 
TEST_F(rtc,alarm_alm_set)179*053f45beSAndroid Build Coastguard Worker TEST_F(rtc, alarm_alm_set) {
180*053f45beSAndroid Build Coastguard Worker 	struct timeval tv = { .tv_sec = ALARM_DELTA + 2 };
181*053f45beSAndroid Build Coastguard Worker 	unsigned long data;
182*053f45beSAndroid Build Coastguard Worker 	struct rtc_time tm;
183*053f45beSAndroid Build Coastguard Worker 	fd_set readfds;
184*053f45beSAndroid Build Coastguard Worker 	time_t secs, new;
185*053f45beSAndroid Build Coastguard Worker 	int rc;
186*053f45beSAndroid Build Coastguard Worker 
187*053f45beSAndroid Build Coastguard Worker 	rc = ioctl(self->fd, RTC_RD_TIME, &tm);
188*053f45beSAndroid Build Coastguard Worker 	ASSERT_NE(-1, rc);
189*053f45beSAndroid Build Coastguard Worker 
190*053f45beSAndroid Build Coastguard Worker 	secs = timegm((struct tm *)&tm) + ALARM_DELTA;
191*053f45beSAndroid Build Coastguard Worker 	gmtime_r(&secs, (struct tm *)&tm);
192*053f45beSAndroid Build Coastguard Worker 
193*053f45beSAndroid Build Coastguard Worker 	rc = ioctl(self->fd, RTC_ALM_SET, &tm);
194*053f45beSAndroid Build Coastguard Worker 	if (rc == -1) {
195*053f45beSAndroid Build Coastguard Worker 		ASSERT_EQ(EINVAL, errno);
196*053f45beSAndroid Build Coastguard Worker 		TH_LOG("skip alarms are not supported.");
197*053f45beSAndroid Build Coastguard Worker 		return;
198*053f45beSAndroid Build Coastguard Worker 	}
199*053f45beSAndroid Build Coastguard Worker 
200*053f45beSAndroid Build Coastguard Worker 	rc = ioctl(self->fd, RTC_ALM_READ, &tm);
201*053f45beSAndroid Build Coastguard Worker 	ASSERT_NE(-1, rc);
202*053f45beSAndroid Build Coastguard Worker 
203*053f45beSAndroid Build Coastguard Worker 	TH_LOG("Alarm time now set to %02d:%02d:%02d.",
204*053f45beSAndroid Build Coastguard Worker 	       tm.tm_hour, tm.tm_min, tm.tm_sec);
205*053f45beSAndroid Build Coastguard Worker 
206*053f45beSAndroid Build Coastguard Worker 	/* Enable alarm interrupts */
207*053f45beSAndroid Build Coastguard Worker 	rc = ioctl(self->fd, RTC_AIE_ON, 0);
208*053f45beSAndroid Build Coastguard Worker 	ASSERT_NE(-1, rc);
209*053f45beSAndroid Build Coastguard Worker 
210*053f45beSAndroid Build Coastguard Worker 	FD_ZERO(&readfds);
211*053f45beSAndroid Build Coastguard Worker 	FD_SET(self->fd, &readfds);
212*053f45beSAndroid Build Coastguard Worker 
213*053f45beSAndroid Build Coastguard Worker 	rc = select(self->fd + 1, &readfds, NULL, NULL, &tv);
214*053f45beSAndroid Build Coastguard Worker 	ASSERT_NE(-1, rc);
215*053f45beSAndroid Build Coastguard Worker 	ASSERT_NE(0, rc);
216*053f45beSAndroid Build Coastguard Worker 
217*053f45beSAndroid Build Coastguard Worker 	/* Disable alarm interrupts */
218*053f45beSAndroid Build Coastguard Worker 	rc = ioctl(self->fd, RTC_AIE_OFF, 0);
219*053f45beSAndroid Build Coastguard Worker 	ASSERT_NE(-1, rc);
220*053f45beSAndroid Build Coastguard Worker 
221*053f45beSAndroid Build Coastguard Worker 	rc = read(self->fd, &data, sizeof(unsigned long));
222*053f45beSAndroid Build Coastguard Worker 	ASSERT_NE(-1, rc);
223*053f45beSAndroid Build Coastguard Worker 	TH_LOG("data: %lx", data);
224*053f45beSAndroid Build Coastguard Worker 
225*053f45beSAndroid Build Coastguard Worker 	rc = ioctl(self->fd, RTC_RD_TIME, &tm);
226*053f45beSAndroid Build Coastguard Worker 	ASSERT_NE(-1, rc);
227*053f45beSAndroid Build Coastguard Worker 
228*053f45beSAndroid Build Coastguard Worker 	new = timegm((struct tm *)&tm);
229*053f45beSAndroid Build Coastguard Worker 	ASSERT_EQ(new, secs);
230*053f45beSAndroid Build Coastguard Worker }
231*053f45beSAndroid Build Coastguard Worker 
TEST_F(rtc,alarm_wkalm_set)232*053f45beSAndroid Build Coastguard Worker TEST_F(rtc, alarm_wkalm_set) {
233*053f45beSAndroid Build Coastguard Worker 	struct timeval tv = { .tv_sec = ALARM_DELTA + 2 };
234*053f45beSAndroid Build Coastguard Worker 	struct rtc_wkalrm alarm = { 0 };
235*053f45beSAndroid Build Coastguard Worker 	struct rtc_time tm;
236*053f45beSAndroid Build Coastguard Worker 	unsigned long data;
237*053f45beSAndroid Build Coastguard Worker 	fd_set readfds;
238*053f45beSAndroid Build Coastguard Worker 	time_t secs, new;
239*053f45beSAndroid Build Coastguard Worker 	int rc;
240*053f45beSAndroid Build Coastguard Worker 
241*053f45beSAndroid Build Coastguard Worker 	rc = ioctl(self->fd, RTC_RD_TIME, &alarm.time);
242*053f45beSAndroid Build Coastguard Worker 	ASSERT_NE(-1, rc);
243*053f45beSAndroid Build Coastguard Worker 
244*053f45beSAndroid Build Coastguard Worker 	secs = timegm((struct tm *)&alarm.time) + ALARM_DELTA;
245*053f45beSAndroid Build Coastguard Worker 	gmtime_r(&secs, (struct tm *)&alarm.time);
246*053f45beSAndroid Build Coastguard Worker 
247*053f45beSAndroid Build Coastguard Worker 	alarm.enabled = 1;
248*053f45beSAndroid Build Coastguard Worker 
249*053f45beSAndroid Build Coastguard Worker 	rc = ioctl(self->fd, RTC_WKALM_SET, &alarm);
250*053f45beSAndroid Build Coastguard Worker 	if (rc == -1) {
251*053f45beSAndroid Build Coastguard Worker 		ASSERT_EQ(EINVAL, errno);
252*053f45beSAndroid Build Coastguard Worker 		TH_LOG("skip alarms are not supported.");
253*053f45beSAndroid Build Coastguard Worker 		return;
254*053f45beSAndroid Build Coastguard Worker 	}
255*053f45beSAndroid Build Coastguard Worker 
256*053f45beSAndroid Build Coastguard Worker 	rc = ioctl(self->fd, RTC_WKALM_RD, &alarm);
257*053f45beSAndroid Build Coastguard Worker 	ASSERT_NE(-1, rc);
258*053f45beSAndroid Build Coastguard Worker 
259*053f45beSAndroid Build Coastguard Worker 	TH_LOG("Alarm time now set to %02d/%02d/%02d %02d:%02d:%02d.",
260*053f45beSAndroid Build Coastguard Worker 	       alarm.time.tm_mday, alarm.time.tm_mon + 1,
261*053f45beSAndroid Build Coastguard Worker 	       alarm.time.tm_year + 1900, alarm.time.tm_hour,
262*053f45beSAndroid Build Coastguard Worker 	       alarm.time.tm_min, alarm.time.tm_sec);
263*053f45beSAndroid Build Coastguard Worker 
264*053f45beSAndroid Build Coastguard Worker 	FD_ZERO(&readfds);
265*053f45beSAndroid Build Coastguard Worker 	FD_SET(self->fd, &readfds);
266*053f45beSAndroid Build Coastguard Worker 
267*053f45beSAndroid Build Coastguard Worker 	rc = select(self->fd + 1, &readfds, NULL, NULL, &tv);
268*053f45beSAndroid Build Coastguard Worker 	ASSERT_NE(-1, rc);
269*053f45beSAndroid Build Coastguard Worker 	ASSERT_NE(0, rc);
270*053f45beSAndroid Build Coastguard Worker 
271*053f45beSAndroid Build Coastguard Worker 	rc = read(self->fd, &data, sizeof(unsigned long));
272*053f45beSAndroid Build Coastguard Worker 	ASSERT_NE(-1, rc);
273*053f45beSAndroid Build Coastguard Worker 
274*053f45beSAndroid Build Coastguard Worker 	rc = ioctl(self->fd, RTC_RD_TIME, &tm);
275*053f45beSAndroid Build Coastguard Worker 	ASSERT_NE(-1, rc);
276*053f45beSAndroid Build Coastguard Worker 
277*053f45beSAndroid Build Coastguard Worker 	new = timegm((struct tm *)&tm);
278*053f45beSAndroid Build Coastguard Worker 	ASSERT_EQ(new, secs);
279*053f45beSAndroid Build Coastguard Worker }
280*053f45beSAndroid Build Coastguard Worker 
281*053f45beSAndroid Build Coastguard Worker TEST_F_TIMEOUT(rtc, alarm_alm_set_minute, 65) {
282*053f45beSAndroid Build Coastguard Worker 	struct timeval tv = { .tv_sec = 62 };
283*053f45beSAndroid Build Coastguard Worker 	unsigned long data;
284*053f45beSAndroid Build Coastguard Worker 	struct rtc_time tm;
285*053f45beSAndroid Build Coastguard Worker 	fd_set readfds;
286*053f45beSAndroid Build Coastguard Worker 	time_t secs, new;
287*053f45beSAndroid Build Coastguard Worker 	int rc;
288*053f45beSAndroid Build Coastguard Worker 
289*053f45beSAndroid Build Coastguard Worker 	rc = ioctl(self->fd, RTC_RD_TIME, &tm);
290*053f45beSAndroid Build Coastguard Worker 	ASSERT_NE(-1, rc);
291*053f45beSAndroid Build Coastguard Worker 
292*053f45beSAndroid Build Coastguard Worker 	secs = timegm((struct tm *)&tm) + 60 - tm.tm_sec;
293*053f45beSAndroid Build Coastguard Worker 	gmtime_r(&secs, (struct tm *)&tm);
294*053f45beSAndroid Build Coastguard Worker 
295*053f45beSAndroid Build Coastguard Worker 	rc = ioctl(self->fd, RTC_ALM_SET, &tm);
296*053f45beSAndroid Build Coastguard Worker 	if (rc == -1) {
297*053f45beSAndroid Build Coastguard Worker 		ASSERT_EQ(EINVAL, errno);
298*053f45beSAndroid Build Coastguard Worker 		TH_LOG("skip alarms are not supported.");
299*053f45beSAndroid Build Coastguard Worker 		return;
300*053f45beSAndroid Build Coastguard Worker 	}
301*053f45beSAndroid Build Coastguard Worker 
302*053f45beSAndroid Build Coastguard Worker 	rc = ioctl(self->fd, RTC_ALM_READ, &tm);
303*053f45beSAndroid Build Coastguard Worker 	ASSERT_NE(-1, rc);
304*053f45beSAndroid Build Coastguard Worker 
305*053f45beSAndroid Build Coastguard Worker 	TH_LOG("Alarm time now set to %02d:%02d:%02d.",
306*053f45beSAndroid Build Coastguard Worker 	       tm.tm_hour, tm.tm_min, tm.tm_sec);
307*053f45beSAndroid Build Coastguard Worker 
308*053f45beSAndroid Build Coastguard Worker 	/* Enable alarm interrupts */
309*053f45beSAndroid Build Coastguard Worker 	rc = ioctl(self->fd, RTC_AIE_ON, 0);
310*053f45beSAndroid Build Coastguard Worker 	ASSERT_NE(-1, rc);
311*053f45beSAndroid Build Coastguard Worker 
312*053f45beSAndroid Build Coastguard Worker 	FD_ZERO(&readfds);
313*053f45beSAndroid Build Coastguard Worker 	FD_SET(self->fd, &readfds);
314*053f45beSAndroid Build Coastguard Worker 
315*053f45beSAndroid Build Coastguard Worker 	rc = select(self->fd + 1, &readfds, NULL, NULL, &tv);
316*053f45beSAndroid Build Coastguard Worker 	ASSERT_NE(-1, rc);
317*053f45beSAndroid Build Coastguard Worker 	ASSERT_NE(0, rc);
318*053f45beSAndroid Build Coastguard Worker 
319*053f45beSAndroid Build Coastguard Worker 	/* Disable alarm interrupts */
320*053f45beSAndroid Build Coastguard Worker 	rc = ioctl(self->fd, RTC_AIE_OFF, 0);
321*053f45beSAndroid Build Coastguard Worker 	ASSERT_NE(-1, rc);
322*053f45beSAndroid Build Coastguard Worker 
323*053f45beSAndroid Build Coastguard Worker 	rc = read(self->fd, &data, sizeof(unsigned long));
324*053f45beSAndroid Build Coastguard Worker 	ASSERT_NE(-1, rc);
325*053f45beSAndroid Build Coastguard Worker 	TH_LOG("data: %lx", data);
326*053f45beSAndroid Build Coastguard Worker 
327*053f45beSAndroid Build Coastguard Worker 	rc = ioctl(self->fd, RTC_RD_TIME, &tm);
328*053f45beSAndroid Build Coastguard Worker 	ASSERT_NE(-1, rc);
329*053f45beSAndroid Build Coastguard Worker 
330*053f45beSAndroid Build Coastguard Worker 	new = timegm((struct tm *)&tm);
331*053f45beSAndroid Build Coastguard Worker 	ASSERT_EQ(new, secs);
332*053f45beSAndroid Build Coastguard Worker }
333*053f45beSAndroid Build Coastguard Worker 
334*053f45beSAndroid Build Coastguard Worker TEST_F_TIMEOUT(rtc, alarm_wkalm_set_minute, 65) {
335*053f45beSAndroid Build Coastguard Worker 	struct timeval tv = { .tv_sec = 62 };
336*053f45beSAndroid Build Coastguard Worker 	struct rtc_wkalrm alarm = { 0 };
337*053f45beSAndroid Build Coastguard Worker 	struct rtc_time tm;
338*053f45beSAndroid Build Coastguard Worker 	unsigned long data;
339*053f45beSAndroid Build Coastguard Worker 	fd_set readfds;
340*053f45beSAndroid Build Coastguard Worker 	time_t secs, new;
341*053f45beSAndroid Build Coastguard Worker 	int rc;
342*053f45beSAndroid Build Coastguard Worker 
343*053f45beSAndroid Build Coastguard Worker 	rc = ioctl(self->fd, RTC_RD_TIME, &alarm.time);
344*053f45beSAndroid Build Coastguard Worker 	ASSERT_NE(-1, rc);
345*053f45beSAndroid Build Coastguard Worker 
346*053f45beSAndroid Build Coastguard Worker 	secs = timegm((struct tm *)&alarm.time) + 60 - alarm.time.tm_sec;
347*053f45beSAndroid Build Coastguard Worker 	gmtime_r(&secs, (struct tm *)&alarm.time);
348*053f45beSAndroid Build Coastguard Worker 
349*053f45beSAndroid Build Coastguard Worker 	alarm.enabled = 1;
350*053f45beSAndroid Build Coastguard Worker 
351*053f45beSAndroid Build Coastguard Worker 	rc = ioctl(self->fd, RTC_WKALM_SET, &alarm);
352*053f45beSAndroid Build Coastguard Worker 	if (rc == -1) {
353*053f45beSAndroid Build Coastguard Worker 		ASSERT_EQ(EINVAL, errno);
354*053f45beSAndroid Build Coastguard Worker 		TH_LOG("skip alarms are not supported.");
355*053f45beSAndroid Build Coastguard Worker 		return;
356*053f45beSAndroid Build Coastguard Worker 	}
357*053f45beSAndroid Build Coastguard Worker 
358*053f45beSAndroid Build Coastguard Worker 	rc = ioctl(self->fd, RTC_WKALM_RD, &alarm);
359*053f45beSAndroid Build Coastguard Worker 	ASSERT_NE(-1, rc);
360*053f45beSAndroid Build Coastguard Worker 
361*053f45beSAndroid Build Coastguard Worker 	TH_LOG("Alarm time now set to %02d/%02d/%02d %02d:%02d:%02d.",
362*053f45beSAndroid Build Coastguard Worker 	       alarm.time.tm_mday, alarm.time.tm_mon + 1,
363*053f45beSAndroid Build Coastguard Worker 	       alarm.time.tm_year + 1900, alarm.time.tm_hour,
364*053f45beSAndroid Build Coastguard Worker 	       alarm.time.tm_min, alarm.time.tm_sec);
365*053f45beSAndroid Build Coastguard Worker 
366*053f45beSAndroid Build Coastguard Worker 	FD_ZERO(&readfds);
367*053f45beSAndroid Build Coastguard Worker 	FD_SET(self->fd, &readfds);
368*053f45beSAndroid Build Coastguard Worker 
369*053f45beSAndroid Build Coastguard Worker 	rc = select(self->fd + 1, &readfds, NULL, NULL, &tv);
370*053f45beSAndroid Build Coastguard Worker 	ASSERT_NE(-1, rc);
371*053f45beSAndroid Build Coastguard Worker 	ASSERT_NE(0, rc);
372*053f45beSAndroid Build Coastguard Worker 
373*053f45beSAndroid Build Coastguard Worker 	rc = read(self->fd, &data, sizeof(unsigned long));
374*053f45beSAndroid Build Coastguard Worker 	ASSERT_NE(-1, rc);
375*053f45beSAndroid Build Coastguard Worker 
376*053f45beSAndroid Build Coastguard Worker 	rc = ioctl(self->fd, RTC_RD_TIME, &tm);
377*053f45beSAndroid Build Coastguard Worker 	ASSERT_NE(-1, rc);
378*053f45beSAndroid Build Coastguard Worker 
379*053f45beSAndroid Build Coastguard Worker 	new = timegm((struct tm *)&tm);
380*053f45beSAndroid Build Coastguard Worker 	ASSERT_EQ(new, secs);
381*053f45beSAndroid Build Coastguard Worker }
382*053f45beSAndroid Build Coastguard Worker #endif
383*053f45beSAndroid Build Coastguard Worker 
384*053f45beSAndroid Build Coastguard Worker static void __attribute__((constructor))
__constructor_order_last(void)385*053f45beSAndroid Build Coastguard Worker __constructor_order_last(void)
386*053f45beSAndroid Build Coastguard Worker {
387*053f45beSAndroid Build Coastguard Worker 	if (!__constructor_order)
388*053f45beSAndroid Build Coastguard Worker 		__constructor_order = _CONSTRUCTOR_ORDER_BACKWARD;
389*053f45beSAndroid Build Coastguard Worker }
390*053f45beSAndroid Build Coastguard Worker 
main(int argc,char ** argv)391*053f45beSAndroid Build Coastguard Worker int main(int argc, char **argv)
392*053f45beSAndroid Build Coastguard Worker {
393*053f45beSAndroid Build Coastguard Worker 	switch (argc) {
394*053f45beSAndroid Build Coastguard Worker 	case 2:
395*053f45beSAndroid Build Coastguard Worker 		rtc_file = argv[1];
396*053f45beSAndroid Build Coastguard Worker 		/* FALLTHROUGH */
397*053f45beSAndroid Build Coastguard Worker 	case 1:
398*053f45beSAndroid Build Coastguard Worker 		break;
399*053f45beSAndroid Build Coastguard Worker 	default:
400*053f45beSAndroid Build Coastguard Worker 		fprintf(stderr, "usage: %s [rtcdev]\n", argv[0]);
401*053f45beSAndroid Build Coastguard Worker 		return 1;
402*053f45beSAndroid Build Coastguard Worker 	}
403*053f45beSAndroid Build Coastguard Worker 
404*053f45beSAndroid Build Coastguard Worker 	return test_harness_run(argc, argv);
405*053f45beSAndroid Build Coastguard Worker }
406