All of lore.kernel.org
 help / color / mirror / Atom feed
From: David Brownell <david-b@pacbell.net>
To: john stultz <johnstul@us.ibm.com>
Cc: Linux Kernel list <linux-kernel@vger.kernel.org>,
	Alessandro Zummo <alessandro.zummo@towertech.it>
Subject: Re: [RFC][PATCH] Unify interface to persistent CMOS/RTC/whatever clock
Date: Sat, 19 Aug 2006 09:44:39 -0700	[thread overview]
Message-ID: <200608190944.40724.david-b@pacbell.net> (raw)
In-Reply-To: <200608190939.11421.david-b@pacbell.net>

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;
 }

  reply	other threads:[~2006-08-19 16:50 UTC|newest]

Thread overview: 14+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2006-08-17  5:47 [RFC][PATCH] Unify interface to persistent CMOS/RTC/whatever clock David Brownell
2006-08-17 19:08 ` john stultz
2006-08-17 20:28   ` David Brownell
2006-08-17 21:42     ` john stultz
2006-08-17 23:41       ` David Brownell
2006-08-18  0:07         ` john stultz
2006-08-18  1:38           ` David Brownell
2006-08-18 23:36             ` john stultz
2006-08-19 16:39               ` David Brownell
2006-08-19 16:44                 ` David Brownell [this message]
2006-08-18  5:50           ` David Brownell
  -- strict thread matches above, loose matches on Subject: below --
2006-08-16 22:45 john stultz
2006-08-17  1:49 ` john stultz
2006-08-17  9:20 ` Martin Schwidefsky

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=200608190944.40724.david-b@pacbell.net \
    --to=david-b@pacbell.net \
    --cc=alessandro.zummo@towertech.it \
    --cc=johnstul@us.ibm.com \
    --cc=linux-kernel@vger.kernel.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.