--- zzzz-none-000/linux-2.6.19.2/Documentation/rtc.txt 2007-01-10 19:10:37.000000000 +0000 +++ davinci-8020-5505/linux-2.6.19.2/Documentation/rtc.txt 2007-01-11 07:38:19.000000000 +0000 @@ -1,49 +1,12 @@ - Real Time Clock (RTC) Drivers for Linux - ======================================= - -When Linux developers talk about a "Real Time Clock", they usually mean -something that tracks wall clock time and is battery backed so that it -works even with system power off. Such clocks will normally not track -the local time zone or daylight savings time -- unless they dual boot -with MS-Windows -- but will instead be set to Coordinated Universal Time -(UTC, formerly "Greenwich Mean Time"). - -The newest non-PC hardware tends to just count seconds, like the time(2) -system call reports, but RTCs also very commonly represent time using -the Gregorian calendar and 24 hour time, as reported by gmtime(3). - -Linux has two largely-compatible userspace RTC API families you may -need to know about: - - * /dev/rtc ... is the RTC provided by PC compatible systems, - so it's not very portable to non-x86 systems. - - * /dev/rtc0, /dev/rtc1 ... are part of a framework that's - supported by a wide variety of RTC chips on all systems. - -Programmers need to understand that the PC/AT functionality is not -always available, and some systems can do much more. That is, the -RTCs use the same API to make requests in both RTC frameworks (using -different filenames of course), but the hardware may not offer the -same functionality. For example, not every RTC is hooked up to an -IRQ, so they can't all issue alarms; and where standard PC RTCs can -only issue an alarm up to 24 hours in the future, other hardware may -be able to schedule one any time in the upcoming century. - - - Old PC/AT-Compatible driver: /dev/rtc - -------------------------------------- + Real Time Clock Driver for Linux + ================================ All PCs (even Alpha machines) have a Real Time Clock built into them. Usually they are built into the chipset of the computer, but some may actually have a Motorola MC146818 (or clone) on the board. This is the clock that keeps the date and time while your computer is turned off. -ACPI has standardized that MC146818 functionality, and extended it in -a few ways (enabling longer alarm periods, and wake-from-hibernate). -That functionality is NOT exposed in the old driver. - However it can also be used to generate signals from a slow 2Hz to a relatively fast 8192Hz, in increments of powers of two. These signals are reported by interrupt number 8. (Oh! So *that* is what IRQ 8 is @@ -100,331 +63,223 @@ perhaps more useful to include a small test program that demonstrates how to use them, and demonstrates the features of the driver. This is probably a lot more useful to people interested in writing applications -that will be using this driver. See the code at the end of this document. - -(The original /dev/rtc driver was written by Paul Gortmaker.) - - - New portable "RTC Class" drivers: /dev/rtcN - -------------------------------------------- - -Because Linux supports many non-ACPI and non-PC platforms, some of which -have more than one RTC style clock, it needed a more portable solution -than expecting a single battery-backed MC146818 clone on every system. -Accordingly, a new "RTC Class" framework has been defined. It offers -three different userspace interfaces: - - * /dev/rtcN ... much the same as the older /dev/rtc interface - - * /sys/class/rtc/rtcN ... sysfs attributes support readonly - access to some RTC attributes. - - * /proc/driver/rtc ... the first RTC (rtc0) may expose itself - using a procfs interface. More information is (currently) shown - here than through sysfs. - -The RTC Class framework supports a wide variety of RTCs, ranging from those -integrated into embeddable system-on-chip (SOC) processors to discrete chips -using I2C, SPI, or some other bus to communicate with the host CPU. There's -even support for PC-style RTCs ... including the features exposed on newer PCs -through ACPI. - -The new framework also removes the "one RTC per system" restriction. For -example, maybe the low-power battery-backed RTC is a discrete I2C chip, but -a high functionality RTC is integrated into the SOC. That system might read -the system clock from the discrete RTC, but use the integrated one for all -other tasks, because of its greater functionality. - -The ioctl() calls supported by /dev/rtc are also supported by the RTC class -framework. However, because the chips and systems are not standardized, -some PC/AT functionality might not be provided. And in the same way, some -newer features -- including those enabled by ACPI -- are exposed by the -RTC class framework, but can't be supported by the older driver. - - * RTC_RD_TIME, RTC_SET_TIME ... every RTC supports at least reading - time, returning the result as a Gregorian calendar date and 24 hour - wall clock time. To be most useful, this time may also be updated. - - * RTC_AIE_ON, RTC_AIE_OFF, RTC_ALM_SET, RTC_ALM_READ ... when the RTC - is connected to an IRQ line, it can often issue an alarm IRQ up to - 24 hours in the future. - - * RTC_WKALM_SET, RTC_WKALM_READ ... RTCs that can issue alarms beyond - the next 24 hours use a slightly more powerful API, which supports - setting the longer alarm time and enabling its IRQ using a single - request (using the same model as EFI firmware). - - * RTC_UIE_ON, RTC_UIE_OFF ... if the RTC offers IRQs, it probably - also offers update IRQs whenever the "seconds" counter changes. - If needed, the RTC framework can emulate this mechanism. - - * RTC_PIE_ON, RTC_PIE_OFF, RTC_IRQP_SET, RTC_IRQP_READ ... another - feature often accessible with an IRQ line is a periodic IRQ, issued - at settable frequencies (usually 2^N Hz). - -In many cases, the RTC alarm can be a system wake event, used to force -Linux out of a low power sleep state (or hibernation) back to a fully -operational state. For example, a system could enter a deep power saving -state until it's time to execute some scheduled tasks. +that will be using this driver. + Paul Gortmaker -------------------- 8< ---------------- 8< ----------------------------- /* - * Real Time Clock Driver Test/Example Program + * Real Time Clock Driver Test/Example Program * - * Compile with: - * gcc -s -Wall -Wstrict-prototypes rtctest.c -o rtctest + * Compile with: + * gcc -s -Wall -Wstrict-prototypes rtctest.c -o rtctest * - * Copyright (C) 1996, Paul Gortmaker. + * Copyright (C) 1996, Paul Gortmaker. * - * Released under the GNU General Public License, version 2, - * included herein by reference. + * Released under the GNU General Public License, version 2, + * included herein by reference. * */ #include +#include #include #include #include #include #include #include -#include #include +int main(void) { -/* - * This expects the new RTC class driver framework, working with - * clocks that will often not be clones of what the PC-AT had. - * Use the command line to specify another RTC if you need one. - */ -static const char default_rtc[] = "/dev/rtc0"; - +int i, fd, retval, irqcount = 0; +unsigned long tmp, data; +struct rtc_time rtc_tm; -int main(int argc, char **argv) -{ - int i, fd, retval, irqcount = 0; - unsigned long tmp, data; - struct rtc_time rtc_tm; - const char *rtc = default_rtc; - - switch (argc) { - case 2: - rtc = argv[1]; - /* FALLTHROUGH */ - case 1: - break; - default: - fprintf(stderr, "usage: rtctest [rtcdev]\n"); - return 1; - } +fd = open ("/dev/rtc", O_RDONLY); - fd = open(rtc, O_RDONLY); +if (fd == -1) { + perror("/dev/rtc"); + exit(errno); +} - if (fd == -1) { - perror(rtc); - exit(errno); - } +fprintf(stderr, "\n\t\t\tRTC Driver Test Example.\n\n"); - fprintf(stderr, "\n\t\t\tRTC Driver Test Example.\n\n"); +/* Turn on update interrupts (one per second) */ +retval = ioctl(fd, RTC_UIE_ON, 0); +if (retval == -1) { + perror("ioctl"); + exit(errno); +} - /* Turn on update interrupts (one per second) */ - retval = ioctl(fd, RTC_UIE_ON, 0); +fprintf(stderr, "Counting 5 update (1/sec) interrupts from reading /dev/rtc:"); +fflush(stderr); +for (i=1; i<6; i++) { + /* This read will block */ + retval = read(fd, &data, sizeof(unsigned long)); if (retval == -1) { - if (errno == ENOTTY) { - fprintf(stderr, - "\n...Update IRQs not supported.\n"); - goto test_READ; - } - perror("ioctl"); + perror("read"); exit(errno); } - - fprintf(stderr, "Counting 5 update (1/sec) interrupts from reading %s:", - rtc); - fflush(stderr); - for (i=1; i<6; i++) { - /* This read will block */ - retval = read(fd, &data, sizeof(unsigned long)); - if (retval == -1) { - perror("read"); - exit(errno); - } - fprintf(stderr, " %d",i); - fflush(stderr); - irqcount++; - } - - fprintf(stderr, "\nAgain, from using select(2) on /dev/rtc:"); + fprintf(stderr, " %d",i); fflush(stderr); - for (i=1; i<6; i++) { - struct timeval tv = {5, 0}; /* 5 second timeout on select */ - fd_set readfds; - - FD_ZERO(&readfds); - FD_SET(fd, &readfds); - /* The select will wait until an RTC interrupt happens. */ - retval = select(fd+1, &readfds, NULL, NULL, &tv); - if (retval == -1) { - perror("select"); - exit(errno); - } - /* This read won't block unlike the select-less case above. */ - retval = read(fd, &data, sizeof(unsigned long)); - if (retval == -1) { - perror("read"); - exit(errno); - } - fprintf(stderr, " %d",i); - fflush(stderr); - irqcount++; - } + irqcount++; +} - /* Turn off update interrupts */ - retval = ioctl(fd, RTC_UIE_OFF, 0); +fprintf(stderr, "\nAgain, from using select(2) on /dev/rtc:"); +fflush(stderr); +for (i=1; i<6; i++) { + struct timeval tv = {5, 0}; /* 5 second timeout on select */ + fd_set readfds; + + FD_ZERO(&readfds); + FD_SET(fd, &readfds); + /* The select will wait until an RTC interrupt happens. */ + retval = select(fd+1, &readfds, NULL, NULL, &tv); if (retval == -1) { - perror("ioctl"); + perror("select"); exit(errno); } - -test_READ: - /* Read the RTC time/date */ - retval = ioctl(fd, RTC_RD_TIME, &rtc_tm); + /* This read won't block unlike the select-less case above. */ + retval = read(fd, &data, sizeof(unsigned long)); if (retval == -1) { - perror("ioctl"); + perror("read"); exit(errno); } + fprintf(stderr, " %d",i); + fflush(stderr); + irqcount++; +} - fprintf(stderr, "\n\nCurrent RTC date/time is %d-%d-%d, %02d:%02d:%02d.\n", - rtc_tm.tm_mday, rtc_tm.tm_mon + 1, rtc_tm.tm_year + 1900, - rtc_tm.tm_hour, rtc_tm.tm_min, rtc_tm.tm_sec); - - /* Set the alarm to 5 sec in the future, and check for rollover */ - rtc_tm.tm_sec += 5; - if (rtc_tm.tm_sec >= 60) { - rtc_tm.tm_sec %= 60; - rtc_tm.tm_min++; - } - if (rtc_tm.tm_min == 60) { - rtc_tm.tm_min = 0; - rtc_tm.tm_hour++; - } - if (rtc_tm.tm_hour == 24) - rtc_tm.tm_hour = 0; +/* Turn off update interrupts */ +retval = ioctl(fd, RTC_UIE_OFF, 0); +if (retval == -1) { + perror("ioctl"); + exit(errno); +} - retval = ioctl(fd, RTC_ALM_SET, &rtc_tm); - if (retval == -1) { - if (errno == ENOTTY) { - fprintf(stderr, - "\n...Alarm IRQs not supported.\n"); - goto test_PIE; - } - perror("ioctl"); - exit(errno); - } +/* Read the RTC time/date */ +retval = ioctl(fd, RTC_RD_TIME, &rtc_tm); +if (retval == -1) { + perror("ioctl"); + exit(errno); +} - /* Read the current alarm settings */ - retval = ioctl(fd, RTC_ALM_READ, &rtc_tm); - if (retval == -1) { - perror("ioctl"); - exit(errno); - } +fprintf(stderr, "\n\nCurrent RTC date/time is %d-%d-%d, %02d:%02d:%02d.\n", + rtc_tm.tm_mday, rtc_tm.tm_mon + 1, rtc_tm.tm_year + 1900, + rtc_tm.tm_hour, rtc_tm.tm_min, rtc_tm.tm_sec); + +/* Set the alarm to 5 sec in the future, and check for rollover */ +rtc_tm.tm_sec += 5; +if (rtc_tm.tm_sec >= 60) { + rtc_tm.tm_sec %= 60; + rtc_tm.tm_min++; +} +if (rtc_tm.tm_min == 60) { + rtc_tm.tm_min = 0; + rtc_tm.tm_hour++; +} +if (rtc_tm.tm_hour == 24) + rtc_tm.tm_hour = 0; - fprintf(stderr, "Alarm time now set to %02d:%02d:%02d.\n", - rtc_tm.tm_hour, rtc_tm.tm_min, rtc_tm.tm_sec); +retval = ioctl(fd, RTC_ALM_SET, &rtc_tm); +if (retval == -1) { + perror("ioctl"); + exit(errno); +} - /* Enable alarm interrupts */ - retval = ioctl(fd, RTC_AIE_ON, 0); - if (retval == -1) { - perror("ioctl"); - exit(errno); - } +/* Read the current alarm settings */ +retval = ioctl(fd, RTC_ALM_READ, &rtc_tm); +if (retval == -1) { + perror("ioctl"); + exit(errno); +} - fprintf(stderr, "Waiting 5 seconds for alarm..."); - fflush(stderr); - /* This blocks until the alarm ring causes an interrupt */ - retval = read(fd, &data, sizeof(unsigned long)); - if (retval == -1) { - perror("read"); - exit(errno); - } - irqcount++; - fprintf(stderr, " okay. Alarm rang.\n"); +fprintf(stderr, "Alarm time now set to %02d:%02d:%02d.\n", + rtc_tm.tm_hour, rtc_tm.tm_min, rtc_tm.tm_sec); + +/* Enable alarm interrupts */ +retval = ioctl(fd, RTC_AIE_ON, 0); +if (retval == -1) { + perror("ioctl"); + exit(errno); +} + +fprintf(stderr, "Waiting 5 seconds for alarm..."); +fflush(stderr); +/* This blocks until the alarm ring causes an interrupt */ +retval = read(fd, &data, sizeof(unsigned long)); +if (retval == -1) { + perror("read"); + exit(errno); +} +irqcount++; +fprintf(stderr, " okay. Alarm rang.\n"); + +/* Disable alarm interrupts */ +retval = ioctl(fd, RTC_AIE_OFF, 0); +if (retval == -1) { + perror("ioctl"); + exit(errno); +} + +/* Read periodic IRQ rate */ +retval = ioctl(fd, RTC_IRQP_READ, &tmp); +if (retval == -1) { + perror("ioctl"); + exit(errno); +} +fprintf(stderr, "\nPeriodic IRQ rate was %ldHz.\n", tmp); + +fprintf(stderr, "Counting 20 interrupts at:"); +fflush(stderr); - /* Disable alarm interrupts */ - retval = ioctl(fd, RTC_AIE_OFF, 0); +/* The frequencies 128Hz, 256Hz, ... 8192Hz are only allowed for root. */ +for (tmp=2; tmp<=64; tmp*=2) { + + retval = ioctl(fd, RTC_IRQP_SET, tmp); if (retval == -1) { perror("ioctl"); exit(errno); } -test_PIE: - /* Read periodic IRQ rate */ - retval = ioctl(fd, RTC_IRQP_READ, &tmp); + fprintf(stderr, "\n%ldHz:\t", tmp); + fflush(stderr); + + /* Enable periodic interrupts */ + retval = ioctl(fd, RTC_PIE_ON, 0); if (retval == -1) { - /* not all RTCs support periodic IRQs */ - if (errno == ENOTTY) { - fprintf(stderr, "\nNo periodic IRQ support\n"); - return 0; - } perror("ioctl"); exit(errno); } - fprintf(stderr, "\nPeriodic IRQ rate is %ldHz.\n", tmp); - - fprintf(stderr, "Counting 20 interrupts at:"); - fflush(stderr); - - /* The frequencies 128Hz, 256Hz, ... 8192Hz are only allowed for root. */ - for (tmp=2; tmp<=64; tmp*=2) { - retval = ioctl(fd, RTC_IRQP_SET, tmp); + for (i=1; i<21; i++) { + /* This blocks */ + retval = read(fd, &data, sizeof(unsigned long)); if (retval == -1) { - /* not all RTCs can change their periodic IRQ rate */ - if (errno == ENOTTY) { - fprintf(stderr, - "\n...Periodic IRQ rate is fixed\n"); - goto done; - } - perror("ioctl"); - exit(errno); + perror("read"); + exit(errno); } - - fprintf(stderr, "\n%ldHz:\t", tmp); + fprintf(stderr, " %d",i); fflush(stderr); + irqcount++; + } - /* Enable periodic interrupts */ - retval = ioctl(fd, RTC_PIE_ON, 0); - if (retval == -1) { - perror("ioctl"); - exit(errno); - } - - for (i=1; i<21; i++) { - /* This blocks */ - retval = read(fd, &data, sizeof(unsigned long)); - if (retval == -1) { - perror("read"); - exit(errno); - } - fprintf(stderr, " %d",i); - fflush(stderr); - irqcount++; - } - - /* Disable periodic interrupts */ - retval = ioctl(fd, RTC_PIE_OFF, 0); - if (retval == -1) { - perror("ioctl"); - exit(errno); - } + /* Disable periodic interrupts */ + retval = ioctl(fd, RTC_PIE_OFF, 0); + if (retval == -1) { + perror("ioctl"); + exit(errno); } +} -done: - fprintf(stderr, "\n\n\t\t\t *** Test complete ***\n"); +fprintf(stderr, "\n\n\t\t\t *** Test complete ***\n"); +fprintf(stderr, "\nTyping \"cat /proc/interrupts\" will show %d more events on IRQ 8.\n\n", + irqcount); - close(fd); +close(fd); +return 0; - return 0; -} +} /* end main */