Skip site navigation (1)Skip section navigation (2)
Date:      Sun, 7 Oct 2012 20:36:47 +0000 (UTC)
From:      Warner Losh <imp@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org
Subject:   svn commit: r241333 - head/sys/arm/at91
Message-ID:  <201210072036.q97KalP6066720@svn.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: imp
Date: Sun Oct  7 20:36:46 2012
New Revision: 241333
URL: http://svn.freebsd.org/changeset/base/241333

Log:
  Loop reading the RTC registers until the same values are obtained
  twice, as advised in the atmel docs.
  
  Submitted by:	Ian Lapore

Modified:
  head/sys/arm/at91/at91_rtc.c

Modified: head/sys/arm/at91/at91_rtc.c
==============================================================================
--- head/sys/arm/at91/at91_rtc.c	Sun Oct  7 20:17:24 2012	(r241332)
+++ head/sys/arm/at91/at91_rtc.c	Sun Oct  7 20:36:46 2012	(r241333)
@@ -256,7 +256,7 @@ static int
 at91_rtc_gettime(device_t dev, struct timespec *ts)
 {
 	struct clocktime ct;
-	uint32_t timr, calr;
+	uint32_t calr, calr2, timr, timr2;
 	struct at91_rtc_softc *sc;
 
 	sc = device_get_softc(dev);
@@ -266,8 +266,19 @@ at91_rtc_gettime(device_t dev, struct ti
 	if (RD4(sc, RTC_VER) & (RTC_VER_NVTIM | RTC_VER_NVCAL))
 		return EINVAL;
 
-	timr = RD4(sc, RTC_TIMR);
-	calr = RD4(sc, RTC_CALR);
+	/*
+	 * The RTC hardware can update registers while the CPU is reading them.
+	 * The manual advises reading until you obtain the same values twice.
+	 * Interleaving the reads (rather than timr, timr2, calr, calr2 order)
+	 * also ensures we don't miss a midnight rollover/carry between reads.
+	 */
+	do {
+		timr = RD4(sc, RTC_TIMR);
+		calr = RD4(sc, RTC_CALR);
+		timr2 = RD4(sc, RTC_TIMR);
+		calr2 = RD4(sc, RTC_CALR);
+	} while (timr != timr2 || calr != calr2);
+
 	ct.nsec = 0;
 	ct.sec = RTC_TIMR_SEC(timr);
 	ct.min = RTC_TIMR_MIN(timr);



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201210072036.q97KalP6066720>