diff options
Diffstat (limited to 'include/asm-arm/arch-arc/time.h')
-rw-r--r-- | include/asm-arm/arch-arc/time.h | 159 |
1 files changed, 128 insertions, 31 deletions
diff --git a/include/asm-arm/arch-arc/time.h b/include/asm-arm/arch-arc/time.h index 6df347484..c02ac8df5 100644 --- a/include/asm-arm/arch-arc/time.h +++ b/include/asm-arm/arch-arc/time.h @@ -8,6 +8,9 @@ * 10-Oct-1996 RMK Brought up to date with arch-sa110eval * 04-Dec-1997 RMK Updated for new arch/arm/time.c */ +#include <asm/ioc.h> + +static long last_rtc_update = 0; /* last time the cmos clock got updated */ extern __inline__ unsigned long gettimeoffset (void) { @@ -51,46 +54,140 @@ extern __inline__ unsigned long gettimeoffset (void) return offset; } -/* - * No need to reset the timer at every irq - */ -#define reset_timer() 1 +extern int iic_control (unsigned char, int, char *, int); -/* - * Updating of the RTC. We don't currently write the time to the - * CMOS clock. - */ -#define update_rtc() +static int set_rtc_time(unsigned long nowtime) +{ + char buf[5], ctrl; + + if (iic_control(0xa1, 0, &ctrl, 1) != 0) + printk("RTC: failed to read control reg\n"); + + /* + * Reset divider + */ + ctrl |= 0x80; + + if (iic_control(0xa0, 0, &ctrl, 1) != 0) + printk("RTC: failed to stop the clock\n"); + + /* + * We only set the time - we don't set the date. + * This means that there is the possibility once + * a day for the correction to disrupt the date. + * We really ought to write the time and date, or + * nothing at all. + */ + buf[0] = 0; + buf[1] = nowtime % 60; nowtime /= 60; + buf[2] = nowtime % 60; nowtime /= 60; + buf[3] = nowtime % 24; + + BIN_TO_BCD(buf[1]); + BIN_TO_BCD(buf[2]); + BIN_TO_BCD(buf[3]); + + if (iic_control(0xa0, 1, buf, 4) != 0) + printk("RTC: Failed to set the time\n"); + + /* + * Re-enable divider + */ + ctrl &= ~0x80; + + if (iic_control(0xa0, 0, &ctrl, 1) != 0) + printk("RTC: failed to start the clock\n"); + + return 0; +} + +extern __inline__ unsigned long get_rtc_time(void) +{ + unsigned int year, i; + char buf[8]; + + /* + * The year is not part of the RTC counter + * registers, and is stored in RAM. This + * means that it will not be automatically + * updated. + */ + if (iic_control(0xa1, 0xc0, buf, 1) != 0) + printk("RTC: failed to read the year\n"); + + /* + * If the year is before 1970, then the year + * is actually 100 in advance. This gives us + * a year 2070 bug... + */ + year = 1900 + buf[0]; + if (year < 1970) + year += 100; + + /* + * Read the time and date in one go - this + * will ensure that we don't get any effects + * due to carry (the RTC latches the counters + * during a read). + */ + if (iic_control(0xa1, 2, buf, 5) != 0) { + printk("RTC: failed to read the time and date\n"); + memset(buf, 0, sizeof(buf)); + } + + /* + * The RTC combines years with date and weekday + * with month. We need to mask off this extra + * information before converting the date to + * binary. + */ + buf[4] &= 0x1f; + buf[3] &= 0x3f; + + for (i = 0; i < 5; i++) + BCD_TO_BIN(buf[i]); + + return mktime(year, buf[4], buf[3], buf[2], buf[1], buf[0]); +} + +static void timer_interrupt(int irq, void *dev_id, struct pt_regs *regs) +{ + do_timer(regs); + + /* If we have an externally synchronized linux clock, then update + * CMOS clock accordingly every ~11 minutes. Set_rtc_mmss() has to be + * called as close as possible to 500 ms before the new second starts. + */ + if ((time_status & STA_UNSYNC) == 0 && + xtime.tv_sec > last_rtc_update + 660 && + xtime.tv_usec >= 50000 - (tick >> 1) && + xtime.tv_usec < 50000 + (tick >> 1)) { + if (set_rtc_time(xtime.tv_sec) == 0) + last_rtc_update = xtime.tv_sec; + else + last_rtc_update = xtime.tv_sec - 600; /* do it again in 60 s */ + } +} + +static struct irqaction timerirq = { + timer_interrupt, + 0, + 0, + "timer", + NULL, + NULL +}; /* * Set up timer interrupt, and return the current time in seconds. */ -extern __inline__ unsigned long setup_timer (void) +extern __inline__ void setup_timer(void) { - extern int iic_control (unsigned char, int, char *, int); - unsigned int year, mon, day, hour, min, sec; - char buf[8]; - outb(LATCH & 255, IOC_T0LTCHL); outb(LATCH >> 8, IOC_T0LTCHH); outb(0, IOC_T0GO); - iic_control (0xa0, 0xc0, buf, 1); - year = buf[0]; - if ((year += 1900) < 1970) - year += 100; + xtime.tv_sec = get_rtc_time(); - iic_control (0xa0, 2, buf, 5); - mon = buf[4] & 0x1f; - day = buf[3] & 0x3f; - hour = buf[2]; - min = buf[1]; - sec = buf[0]; - BCD_TO_BIN(mon); - BCD_TO_BIN(day); - BCD_TO_BIN(hour); - BCD_TO_BIN(min); - BCD_TO_BIN(sec); - - return mktime(year, mon, day, hour, min, sec); + setup_arm_irq(IRQ_TIMER, &timerirq); } |