Re: [RFC][PATCH] Unify interface to persistent CMOS/RTC/whatever clock

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



On Saturday 19 August 2006 9:39 am, David Brownell wrote:
> > So if we go w/  the "it may not be available, so always assume it isn't"
> > way of thinking, it forces us to rely upon the RTC driver(s) to resume
> > time (which means every RTC, no matter how simple has to have
> > suspend/resume hooks and call settimeofday at least). 
> 
> No, that was the point of my comment about using the new class level
> suspend/resume calls.  The RTC drivers wouldn't be responsible for
> that; the RTC framework would be.  RTC drivers may still want the
> suspend/resume hooks to make sure they issue system wakeup events,
> and so on, but no longer for maintaining the wall clock.  I'll send
> a patch (of the "it compiles" type) later.

Welcome to "later"!

------------------------

Preliminary RTC class suspend/resume support:

 - Inlining the same code used by ARM, save and restore the delta between
   a selected RTC and the current system time.

 - Removes calls to that ARM code from the AT91 and S3C RTCs; the AT91
   calls are left as stubs, because a pending patch still needs those
   (currently empty) routines to properly issue system wakeup events.

 - Selects rtc0 by default, else CONFIG_RTC_HCTOSYS_DEVICE.  We expect all RTCs
   to be powered during "real" sleep states, but swsusp/hibernation requires
   something that's also battery-backed.

Depends on new class suspend/resume methods, added by a patch in the MM tree.

(Preliminary because untested, and because of a FIXME ... nothing recovers
from unregistering the selected RTC; that could happen only with badly written
RTC drivers though.)


Index: g26/drivers/rtc/class.c
===================================================================
--- g26.orig/drivers/rtc/class.c	2006-08-19 09:20:36.000000000 -0700
+++ g26/drivers/rtc/class.c	2006-08-19 09:20:37.000000000 -0700
@@ -29,6 +29,86 @@ static void rtc_device_release(struct cl
 	kfree(rtc);
 }
 
+#ifdef	CONFIG_PM
+
+/*
+ * Re-initialize wall clock on resume, to match the delta (calculated
+ * during suspend) between that and an appropriate RTC.
+ *
+ * We assume any RTC is good enough, meaning it stays running during
+ * system sleep states; but prefer the CONFIG_RTC_HCTOSYS_DEVICE on
+ * the grounds that it's expected to be battery-backed and thus will
+ * stay running even during the "off" states used by swsusp.
+ *
+ * REVISIT ... we should probably have a way to tell if a given RTC
+ * will stay powered during the target system state, rather than just
+ * assume a "valid" configuration (where no RTC that powers off will
+ * be selected, and no selected RTC will be removed).  That could let
+ * us get rid of the need for CONFIG_RTC_HCTOSYS_DEVICE too...
+ */
+
+static struct class_device	*sleep_rtc;
+static struct timespec		delta;
+
+static int rtc_suspend(struct device *dev, pm_message_t mesg)
+{
+	struct rtc_time tm;
+	struct timespec time;
+
+	if (!sleep_rtc || dev != sleep_rtc->dev)
+		return 0;
+
+	time.tv_nsec = 0;
+
+	rtc_read_time(sleep_rtc, &tm);
+	rtc_tm_to_time(&tm, &time.tv_sec);
+
+	set_normalized_timespec(&delta,
+				xtime.tv_sec - time.tv_sec,
+				xtime.tv_nsec - time.tv_nsec);
+
+	pr_debug("%s:  %s %4d-%02d-%02d %02d:%02d:%02d\n",
+		sleep_rtc->class_id, "suspend",
+		1900 + tm.tm_year, tm.tm_mon, tm.tm_mday,
+		tm.tm_hour, tm.tm_min, tm.tm_sec);
+
+	return 0;
+}
+
+static int rtc_resume(struct device *dev)
+{
+	struct rtc_time tm;
+	struct timespec time;
+
+	/* REVISIT some swsusp configurations may feed us an RTC that
+	 * lost power ... we should probably try detecting that, and
+	 * refuse to update the time using a bogus clock.
+	 */
+
+	if (!sleep_rtc || dev != sleep_rtc->dev)
+		return 0;
+
+	time.tv_nsec = 0;
+
+	rtc_read_time(sleep_rtc, &tm);
+	rtc_tm_to_time(&tm, &time.tv_sec);
+
+	set_normalized_timespec(&time,
+				xtime.tv_sec - time.tv_sec,
+				xtime.tv_nsec - time.tv_nsec);
+	do_settimeofday(&time);
+
+	pr_debug("%s:  %s %4d-%02d-%02d %02d:%02d:%02d\n",
+		sleep_rtc->class_id, "resume",
+		1900 + tm.tm_year, tm.tm_mon, tm.tm_mday,
+		tm.tm_hour, tm.tm_min, tm.tm_sec);
+
+	return 0;
+}
+
+#endif
+
+
 /**
  * rtc_device_register - register w/ RTC class
  * @dev: the device to register
@@ -85,6 +165,21 @@ struct rtc_device *rtc_device_register(c
 	if (err)
 		goto exit_kfree;
 
+#ifdef	CONFIG_PM
+	mutex_lock(&idr_lock);
+#ifdef CONFIG_RTC_HCTOSYS_DEVICE
+	if (sleep_rtc && strncmp(rtc->class_dev.class_id,
+				CONFIG_RTC_HCTOSYS_DEVICE,
+				BUS_ID_SIZE) == 0) {
+		rtc_class_close(sleep_rtc);
+		sleep_rtc = NULL;
+	}
+#endif
+	if (!sleep_rtc)
+		sleep_rtc = rtc_class_open(rtc->class_dev.class_id);
+	mutex_unlock(&idr_lock);
+#endif
+
 	dev_info(dev, "rtc core: registered %s as %s\n",
 			rtc->name, rtc->class_dev.class_id);
 
@@ -113,6 +208,17 @@ EXPORT_SYMBOL_GPL(rtc_device_register);
  */
 void rtc_device_unregister(struct rtc_device *rtc)
 {
+#ifdef	CONFIG_PM
+	mutex_lock(&idr_lock);
+	if (&rtc->class_dev == sleep_rtc) {
+		rtc_class_close(sleep_rtc);
+		sleep_rtc = NULL;
+		/* FIXME */
+		printk(KERN_WARNING "rtc: now what to use during sleep??\n");
+	}
+	mutex_unlock(&idr_lock);
+#endif
+
 	mutex_lock(&rtc->ops_lock);
 	rtc->ops = NULL;
 	mutex_unlock(&rtc->ops_lock);
@@ -134,6 +240,10 @@ static int __init rtc_init(void)
 		printk(KERN_ERR "%s: couldn't create class\n", __FILE__);
 		return PTR_ERR(rtc_class);
 	}
+#ifdef	CONFIG_PM
+	rtc_class->suspend = rtc_suspend;
+	rtc_class->resume = rtc_resume;
+#endif
 	return 0;
 }
 
Index: g26/drivers/rtc/rtc-at91.c
===================================================================
--- g26.orig/drivers/rtc/rtc-at91.c	2006-08-19 09:20:36.000000000 -0700
+++ g26/drivers/rtc/rtc-at91.c	2006-08-19 09:20:37.000000000 -0700
@@ -339,38 +339,13 @@ static struct timespec at91_rtc_delta;
 
 static int at91_rtc_suspend(struct platform_device *pdev, pm_message_t state)
 {
-	struct rtc_time tm;
-	struct timespec time;
-
-	time.tv_nsec = 0;
-
-	/* calculate time delta for suspend */
-	at91_rtc_readtime(&pdev->dev, &tm);
-	rtc_tm_to_time(&tm, &time.tv_sec);
-	save_time_delta(&at91_rtc_delta, &time);
-
-	pr_debug("%s(): %4d-%02d-%02d %02d:%02d:%02d\n", __FUNCTION__,
-		1900 + tm.tm_year, tm.tm_mon, tm.tm_mday,
-		tm.tm_hour, tm.tm_min, tm.tm_sec);
-
+	/* STUB, pending merge of rtc wakeup patch */
 	return 0;
 }
 
 static int at91_rtc_resume(struct platform_device *pdev)
 {
-	struct rtc_time tm;
-	struct timespec time;
-
-	time.tv_nsec = 0;
-
-	at91_rtc_readtime(&pdev->dev, &tm);
-	rtc_tm_to_time(&tm, &time.tv_sec);
-	restore_time_delta(&at91_rtc_delta, &time);
-
-	pr_debug("%s(): %4d-%02d-%02d %02d:%02d:%02d\n", __FUNCTION__,
-		1900 + tm.tm_year, tm.tm_mon, tm.tm_mday,
-		tm.tm_hour, tm.tm_min, tm.tm_sec);
-
+	/* STUB, pending merge of rtc wakeup patch */
 	return 0;
 }
 #else
Index: g26/drivers/rtc/rtc-s3c.c
===================================================================
--- g26.orig/drivers/rtc/rtc-s3c.c	2006-08-19 09:20:36.000000000 -0700
+++ g26/drivers/rtc/rtc-s3c.c	2006-08-19 09:20:37.000000000 -0700
@@ -536,37 +536,15 @@ static int ticnt_save;
 
 static int s3c_rtc_suspend(struct platform_device *pdev, pm_message_t state)
 {
-	struct rtc_time tm;
-	struct timespec time;
-
-	time.tv_nsec = 0;
-
 	/* save TICNT for anyone using periodic interrupts */
-
 	ticnt_save = readb(S3C2410_TICNT);
-
-	/* calculate time delta for suspend */
-
-	s3c_rtc_gettime(&pdev->dev, &tm);
-	rtc_tm_to_time(&tm, &time.tv_sec);
-	save_time_delta(&s3c_rtc_delta, &time);
 	s3c_rtc_enable(pdev, 0);
-
 	return 0;
 }
 
 static int s3c_rtc_resume(struct platform_device *pdev)
 {
-	struct rtc_time tm;
-	struct timespec time;
-
-	time.tv_nsec = 0;
-
 	s3c_rtc_enable(pdev, 1);
-	s3c_rtc_gettime(&pdev->dev, &tm);
-	rtc_tm_to_time(&tm, &time.tv_sec);
-	restore_time_delta(&s3c_rtc_delta, &time);
-
 	writeb(ticnt_save, S3C2410_TICNT);
 	return 0;
 }
-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to [email protected]
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

[Index of Archives]     [Kernel Newbies]     [Netfilter]     [Bugtraq]     [Photo]     [Stuff]     [Gimp]     [Yosemite News]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux RAID]     [Video 4 Linux]     [Linux for the blind]     [Linux Resources]
  Powered by Linux