in atari/time.c [199:319]
int atari_tt_hwclk( int op, struct rtc_time *t )
{
int sec=0, min=0, hour=0, day=0, mon=0, year=0, wday=0;
unsigned long flags;
unsigned char ctrl;
int pm = 0;
ctrl = RTC_READ(RTC_CONTROL); /* control registers are
* independent from the UIP */
if (op) {
/* write: prepare values */
sec = t->tm_sec;
min = t->tm_min;
hour = t->tm_hour;
day = t->tm_mday;
mon = t->tm_mon + 1;
year = t->tm_year - atari_rtc_year_offset;
wday = t->tm_wday + (t->tm_wday >= 0);
if (!(ctrl & RTC_24H)) {
if (hour > 11) {
pm = 0x80;
if (hour != 12)
hour -= 12;
}
else if (hour == 0)
hour = 12;
}
if (!(ctrl & RTC_DM_BINARY)) {
sec = bin2bcd(sec);
min = bin2bcd(min);
hour = bin2bcd(hour);
day = bin2bcd(day);
mon = bin2bcd(mon);
year = bin2bcd(year);
if (wday >= 0)
wday = bin2bcd(wday);
}
}
/* Reading/writing the clock registers is a bit critical due to
* the regular update cycle of the RTC. While an update is in
* progress, registers 0..9 shouldn't be touched.
* The problem is solved like that: If an update is currently in
* progress (the UIP bit is set), the process sleeps for a while
* (50ms). This really should be enough, since the update cycle
* normally needs 2 ms.
* If the UIP bit reads as 0, we have at least 244 usecs until the
* update starts. This should be enough... But to be sure,
* additionally the RTC_SET bit is set to prevent an update cycle.
*/
while( RTC_READ(RTC_FREQ_SELECT) & RTC_UIP ) {
if (in_atomic() || irqs_disabled())
mdelay(1);
else
schedule_timeout_interruptible(HWCLK_POLL_INTERVAL);
}
local_irq_save(flags);
RTC_WRITE( RTC_CONTROL, ctrl | RTC_SET );
if (!op) {
sec = RTC_READ( RTC_SECONDS );
min = RTC_READ( RTC_MINUTES );
hour = RTC_READ( RTC_HOURS );
day = RTC_READ( RTC_DAY_OF_MONTH );
mon = RTC_READ( RTC_MONTH );
year = RTC_READ( RTC_YEAR );
wday = RTC_READ( RTC_DAY_OF_WEEK );
}
else {
RTC_WRITE( RTC_SECONDS, sec );
RTC_WRITE( RTC_MINUTES, min );
RTC_WRITE( RTC_HOURS, hour + pm);
RTC_WRITE( RTC_DAY_OF_MONTH, day );
RTC_WRITE( RTC_MONTH, mon );
RTC_WRITE( RTC_YEAR, year );
if (wday >= 0) RTC_WRITE( RTC_DAY_OF_WEEK, wday );
}
RTC_WRITE( RTC_CONTROL, ctrl & ~RTC_SET );
local_irq_restore(flags);
if (!op) {
/* read: adjust values */
if (hour & 0x80) {
hour &= ~0x80;
pm = 1;
}
if (!(ctrl & RTC_DM_BINARY)) {
sec = bcd2bin(sec);
min = bcd2bin(min);
hour = bcd2bin(hour);
day = bcd2bin(day);
mon = bcd2bin(mon);
year = bcd2bin(year);
wday = bcd2bin(wday);
}
if (!(ctrl & RTC_24H)) {
if (!pm && hour == 12)
hour = 0;
else if (pm && hour != 12)
hour += 12;
}
t->tm_sec = sec;
t->tm_min = min;
t->tm_hour = hour;
t->tm_mday = day;
t->tm_mon = mon - 1;
t->tm_year = year + atari_rtc_year_offset;
t->tm_wday = wday - 1;
}
return( 0 );
}