patch-2.2.8 linux/include/asm-arm/arch-arc/time.h

Next file: linux/include/asm-arm/arch-arc/uncompress.h
Previous file: linux/include/asm-arm/arch-arc/processor.h
Back to the patch index
Back to the overall index

diff -u --recursive --new-file v2.2.7/linux/include/asm-arm/arch-arc/time.h linux/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 @@
 	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;
-
-	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);
+	xtime.tv_sec = get_rtc_time();
 
-	return mktime(year, mon, day, hour, min, sec);
+	setup_arm_irq(IRQ_TIMER, &timerirq);
 }

FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)