public inbox for linux-kernel@vger.kernel.org
 help / color / mirror / Atom feed
* [patch 2.6.19-rc6 0/6] more rtc framework/driver updates
@ 2006-11-20 18:14 David Brownell
  2006-11-20 18:17 ` [patch 2.6.19-rc6 1/6] rtc class /proc/driver/rtc update David Brownell
                   ` (5 more replies)
  0 siblings, 6 replies; 19+ messages in thread
From: David Brownell @ 2006-11-20 18:14 UTC (permalink / raw)
  To: Alessandro Zummo, Linux Kernel list

Here are more RTC framework updates, basically for the 2.6.20 queue:

 - /proc/driver/rtc update ... display the 'struct rtc_wkalrm' status
   bits more sensibly (though the EFI "irq pending" flag is nonsense
   with an OS running)

 - rtc-sa1100 update ... wasn't reporting "alarm enabled", and its
   extra procfs info duplicated information already found there

 - X86_PC updates ... create an rtc_cmos platform device when PNPACPI
   isn't available do make one through PNP.  (Non-PC platforms can do
   similar things if they have a "cmos" RTC.)

 - Export ACPI RTC extensions through platform_data to the PNP device
   or the platform device, as appropriate.

 - New "rtc-cmos" driver, for the RTC on most PCs.  For most folk this
   seems like it should be able to replace drivers/char/rtc.c ...

 - Newish "rtc-omap" driver, for the RTC on OMAP1 processors.  No point
   in having this just live in the OMAP tree.

Folk wanting to try "rtc-cmos" will likely be wanting to tweak their
/dev/rtc node to become a symlink to /dev/rtc0, at least until the
new version of util-linux comes out (with updated "hwclock" knowing
about the new RTC class devices).

- Dave


^ permalink raw reply	[flat|nested] 19+ messages in thread

* [patch 2.6.19-rc6 1/6] rtc class /proc/driver/rtc update
  2006-11-20 18:14 [patch 2.6.19-rc6 0/6] more rtc framework/driver updates David Brownell
@ 2006-11-20 18:17 ` David Brownell
  2006-11-20 23:13   ` Alessandro Zummo
  2006-11-20 18:19 ` [patch 2.6.19-rc6 2/6] rtc-sa1100 tweaks David Brownell
                   ` (4 subsequent siblings)
  5 siblings, 1 reply; 19+ messages in thread
From: David Brownell @ 2006-11-20 18:17 UTC (permalink / raw)
  To: Alessandro Zummo; +Cc: Linux Kernel list

Fix two minor botches in the procfs dumping of RTC alarm status:

 - Stop confusing "alarm enabled" with "wakeup enabled".

 - Don't display bogus "irq pending/un-acked" status; those are the rather
   pointless semantics EFI assigned to this (for a no-IRQs environment).

The main RTC that seems confused about this is the sa1100 one, which
doesn't actually report whether it enabled the alarm.

Signed-off-by: David Brownell <dbrownell@users.sourceforge.net>

Index: g26/drivers/rtc/rtc-proc.c
===================================================================
--- g26.orig/drivers/rtc/rtc-proc.c	2006-11-20 09:35:39.000000000 -0800
+++ g26/drivers/rtc/rtc-proc.c	2006-11-20 09:36:23.000000000 -0800
@@ -66,9 +66,11 @@ static int rtc_proc_show(struct seq_file
 		else
 			seq_printf(seq, "**\n");
 		seq_printf(seq, "alrm_wakeup\t: %s\n",
+				device_may_wakeup(class_dev->dev)
+					? "yes" : "no");
+		seq_printf(seq, "alrm_enabled\t: %s\n",
 				alrm.enabled ? "yes" : "no");
-		seq_printf(seq, "alrm_pending\t: %s\n",
-				alrm.pending ? "yes" : "no");
+		/* alrm.pending ("irq un-acked") is useless ... */
 	}
 
 	seq_printf(seq, "24hr\t\t: yes\n");

^ permalink raw reply	[flat|nested] 19+ messages in thread

* [patch 2.6.19-rc6 2/6] rtc-sa1100 tweaks
  2006-11-20 18:14 [patch 2.6.19-rc6 0/6] more rtc framework/driver updates David Brownell
  2006-11-20 18:17 ` [patch 2.6.19-rc6 1/6] rtc class /proc/driver/rtc update David Brownell
@ 2006-11-20 18:19 ` David Brownell
  2006-11-20 22:48   ` Russell King
  2006-11-20 18:22 ` [patch 2.6.19-rc6 3/6] X86_PC optionally creates rtc_cmos platform device David Brownell
                   ` (3 subsequent siblings)
  5 siblings, 1 reply; 19+ messages in thread
From: David Brownell @ 2006-11-20 18:19 UTC (permalink / raw)
  To: Alessandro Zummo; +Cc: Linux Kernel list, rpurdie

Minor updates to rtc-sa1100: report whether the alarm is enabled, remove
duplicate procfs reporting of that factoid, and stick a FIXME at a place
where alarms should be enabled (but aren't).

Signed-off-by: David Brownell <dbrownell@users.sourceforge.net>

Index: g26/drivers/rtc/rtc-sa1100.c
===================================================================
--- g26.orig/drivers/rtc/rtc-sa1100.c	2006-11-20 09:35:19.000000000 -0800
+++ g26/drivers/rtc/rtc-sa1100.c	2006-11-20 09:36:24.000000000 -0800
@@ -263,8 +263,12 @@ static int sa1100_rtc_set_time(struct de
 
 static int sa1100_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm)
 {
+	u32	rtsr;
+
 	memcpy(&alrm->time, &rtc_alarm, sizeof(struct rtc_time));
-	alrm->pending = RTSR & RTSR_AL ? 1 : 0;
+	rtsr = RTSR;
+	alrm->pending = (rtsr & RTSR_AL) ? 1 : 0;
+	alrm->enabled = (rtsr & RTSR_ALE) ? 1 : 0;
 	return 0;
 }
 
@@ -277,6 +281,7 @@ static int sa1100_rtc_set_alarm(struct d
 	if (ret == 0) {
 		memcpy(&rtc_alarm, &alrm->time, sizeof(struct rtc_time));
 
+		/* FIXME 'enabled' should update RTSR_ALE instead */
 		if (alrm->enabled)
 			enable_irq_wake(IRQ_RTCAlrm);
 		else
@@ -290,8 +295,6 @@ static int sa1100_rtc_set_alarm(struct d
 static int sa1100_rtc_proc(struct device *dev, struct seq_file *seq)
 {
 	seq_printf(seq, "trim/divider\t: 0x%08lx\n", RTTR);
-	seq_printf(seq, "alarm_IRQ\t: %s\n",
-			(RTSR & RTSR_ALE) ? "yes" : "no" );
 	seq_printf(seq, "update_IRQ\t: %s\n",
 			(RTSR & RTSR_HZE) ? "yes" : "no");
 	seq_printf(seq, "periodic_IRQ\t: %s\n",

^ permalink raw reply	[flat|nested] 19+ messages in thread

* [patch 2.6.19-rc6 3/6] X86_PC optionally creates rtc_cmos platform device
  2006-11-20 18:14 [patch 2.6.19-rc6 0/6] more rtc framework/driver updates David Brownell
  2006-11-20 18:17 ` [patch 2.6.19-rc6 1/6] rtc class /proc/driver/rtc update David Brownell
  2006-11-20 18:19 ` [patch 2.6.19-rc6 2/6] rtc-sa1100 tweaks David Brownell
@ 2006-11-20 18:22 ` David Brownell
  2006-11-20 18:27 ` [patch 2.6.19-rc6 5/6] rtc-cmos driver David Brownell
                   ` (2 subsequent siblings)
  5 siblings, 0 replies; 19+ messages in thread
From: David Brownell @ 2006-11-20 18:22 UTC (permalink / raw)
  To: Alessandro Zummo; +Cc: Linux Kernel list

Update X86_PC platforms (i386, x86_64) to create an "rtc_cmos" platform device
when PNPACPI won't be creating a corresponding PNP node for us.  There may be
other platform devices that should get corresponding treatment; it might help
get rid of more legacy ISA probing logic.

Signed-off-by: David Brownell <dbrownell@users.sourceforge.net>

Index: g26/arch/x86_64/kernel/setup.c
===================================================================
--- g26.orig/arch/x86_64/kernel/setup.c	2006-11-20 10:03:06.000000000 -0800
+++ g26/arch/x86_64/kernel/setup.c	2006-11-20 10:10:43.000000000 -0800
@@ -1212,22 +1212,58 @@ struct seq_operations cpuinfo_op = {
 	.show =	show_cpuinfo,
 };
 
-#if defined(CONFIG_INPUT_PCSPKR) || defined(CONFIG_INPUT_PCSPKR_MODULE)
+
+#ifdef CONFIG_X86_PC
+
 #include <linux/platform_device.h>
-static __init int add_pcspkr(void)
-{
-	struct platform_device *pd;
-	int ret;
+#include <asm/mc146818rtc.h>
+
+#if defined(CONFIG_INPUT_PCSPKR) || defined(CONFIG_INPUT_PCSPKR_MODULE)
+static struct platform_device pcspkr_dev = {
+	.name		= "pcspkr",
+	.id		= -1,
+};
+#endif	/* PCSPKR */
 
-	pd = platform_device_alloc("pcspkr", -1);
-	if (!pd)
-		return -ENOMEM;
-
-	ret = platform_device_add(pd);
-	if (ret)
-		platform_device_put(pd);
+#ifndef	CONFIG_PNPACPI
+struct resource rtc_platform_resources[] = { {
+	.flags		= IORESOURCE_IO,
+	.start		= RTC_PORT(0),
+	.end		= RTC_PORT(1),
+}, {
+	.flags		= IORESOURCE_IRQ,
+	.start		= RTC_IRQ
+} };
 
-	return ret;
-}
-device_initcall(add_pcspkr);
+struct platform_device rtc_dev = {
+	.name		= "rtc_cmos",
+	.id		= -1,
+	.resource	= rtc_platform_resources,
+	.num_resources	= ARRAY_SIZE(rtc_platform_resources),
+};
+#endif	/* !PNPACPI */
+
+static struct platform_device *x86_pc_devs[] __initdata = {
+#if defined(CONFIG_INPUT_PCSPKR) || defined(CONFIG_INPUT_PCSPKR_MODULE)
+	&pcspkr_dev,
+#endif
+#ifndef	CONFIG_PNPACPI
+	&rtc_dev,
+#endif
+};
+
+static __init int add_devices(void)
+{
+#ifndef	CONFIG_PNPACPI
+	/* On most motherboards starting with ATX (1995+),
+	 * RTC alarms can wake the system
+	 */
+	device_init_wakeup(&rtc_dev.dev, 1);
 #endif
+
+	return platform_add_devices(x86_pc_devs, ARRAY_SIZE(x86_pc_devs));
+}
+arch_initcall(add_devices);
+
+#endif	/* X86_PC */
+
Index: g26/arch/i386/kernel/setup.c
===================================================================
--- g26.orig/arch/i386/kernel/setup.c	2006-11-20 10:03:06.000000000 -0800
+++ g26/arch/i386/kernel/setup.c	2006-11-20 10:10:43.000000000 -0800
@@ -1481,22 +1481,56 @@ void __init setup_arch(char **cmdline_p)
 	tsc_init();
 }
 
-static __init int add_pcspkr(void)
-{
-	struct platform_device *pd;
-	int ret;
 
-	pd = platform_device_alloc("pcspkr", -1);
-	if (!pd)
-		return -ENOMEM;
-
-	ret = platform_device_add(pd);
-	if (ret)
-		platform_device_put(pd);
+#ifdef CONFIG_X86_PC
+
+#include <linux/platform_device.h>
+#include <asm/mc146818rtc.h>
+
+static struct platform_device pcspkr_dev = {
+	.name		= "pcspkr",
+	.id		= -1,
+};
+
+#ifndef	CONFIG_PNPACPI
+struct resource rtc_platform_resources[] = { {
+	.flags		= IORESOURCE_IO,
+	.start		= RTC_PORT(0),
+	.end		= RTC_PORT(1),
+}, {
+	.flags		= IORESOURCE_IRQ,
+	.start		= RTC_IRQ
+} };
+
+struct platform_device rtc_dev = {
+	.name		= "rtc_cmos",
+	.id		= -1,
+	.resource	= rtc_platform_resources,
+	.num_resources	= ARRAY_SIZE(rtc_platform_resources),
+};
+#endif	/* !PNPACPI */
 
-	return ret;
+static struct platform_device *x86_pc_devs[] __initdata = {
+	&pcspkr_dev,
+#ifndef	CONFIG_PNPACPI
+	&rtc_dev,
+#endif
+};
+
+static __init int add_devices(void)
+{
+#ifndef	CONFIG_PNPACPI
+	/* On most motherboards starting with ATX (1995+),
+	 * RTC alarms can wake the system
+	 */
+	device_init_wakeup(&rtc_dev.dev, 1);
+#endif
+
+	return platform_add_devices(x86_pc_devs, ARRAY_SIZE(x86_pc_devs));
 }
-device_initcall(add_pcspkr);
+arch_initcall(add_devices);
+
+#endif	/* X86_PC */
 
 /*
  * Local Variables:

^ permalink raw reply	[flat|nested] 19+ messages in thread

* [patch 2.6.19-rc6 5/6] rtc-cmos driver
  2006-11-20 18:14 [patch 2.6.19-rc6 0/6] more rtc framework/driver updates David Brownell
                   ` (2 preceding siblings ...)
  2006-11-20 18:22 ` [patch 2.6.19-rc6 3/6] X86_PC optionally creates rtc_cmos platform device David Brownell
@ 2006-11-20 18:27 ` David Brownell
  2006-11-20 18:27 ` [patch 2.6.19-rc6 4/6] ACPI exports RTC extensions through platform_data David Brownell
  2006-11-20 18:28 ` [patch 2.6.19-rc6 6/6] rtc-omap driver David Brownell
  5 siblings, 0 replies; 19+ messages in thread
From: David Brownell @ 2006-11-20 18:27 UTC (permalink / raw)
  To: Alessandro Zummo; +Cc: Brown, Len, Linux Kernel list

This is a "new RTC framework" driver for the "CMOS" RTCs which are standard
on PCs and some other platforms.  That's an MC146818, or compatibles like
the ones in most south bridges, the M48T86 and DS12887, etc.  Advantages of
this vs. drivers/char/rtc.c (use one _or_ the other) include:

 - This leverages both the new RTC framework and the driver model;
   both PNPACPI and platform device modes are supported.

 - It supports ACPI extensions like longer alarms.

 - Likewise, system wakeup events use "real driver model support", with
   policy control via sysfs "wakeup" attributes and and using normal rtc
   ioctls to manage wakeup.
   
 - Obsoletes and removes the acpi-only /proc/acpi/alarm interface.

Disadvantages include no testing on non-x86 systems, or with HPET; and
issues associated with newness of this code and the relatively limited
use of the RTC framework (i.e. primarily on embedded Linuxes, not PCs). 

Significant changes since last version:  handles periodic irqs, given
the rtc core patch for RTC_IRQP_{GET,SET}; renamed as rtc-cmos; better
platform device support; cares less about ACPI; passes "rtctest".

Issues of note:

 - Some tools like "hwclock" expect /dev/rtc not /dev/rtc0; upcoming
   util-linux and busybox versions should resolve this.

 - ACPI wakeup doesn't always work ... this is not specific to RTC,
   but it's worth remembering.  (Or fixing, please!, if you can.)

 - The ALSA sound/core/rtctimer.c doesn't understand the new RTC API,
   or the fact that not every RTC can generate 1K/sec IRQs.

This version seems generally usable, though it may need tweaks yet.

Signed-off-by: David Brownell <dbrownell@users.sourceforge.net>

Index: g26/drivers/rtc/Kconfig
===================================================================
--- g26.orig/drivers/rtc/Kconfig	2006-11-20 10:03:06.000000000 -0800
+++ g26/drivers/rtc/Kconfig	2006-11-20 10:10:47.000000000 -0800
@@ -95,6 +95,25 @@ config RTC_INTF_DEV_UIE_EMUL
 comment "RTC drivers"
 	depends on RTC_CLASS
 
+config RTC_DRV_CMOS
+	tristate "CMOS real time clock"
+	depends on RTC_CLASS && (X86_PC || ACPI)
+	help
+	  Say "yes" here to get direct support for the real time clock
+	  found in every PC or ACPI-based system, and some others.
+	  Specifically the original MC146818, or compatibles like those
+	  in PC south bridges, the DS12887 or M48T86, and so on.
+
+	  This RTC can be used to wake most systems from suspend-to-RAM or
+	  standby sleep modes, and on some systems from suspend-to-disk.
+	  (Any PC predating the 1995 introduction of ATX power supplies
+	  probably can't be woken up by its RTC.)
+
+	  This obsoletes the old /proc/acpi/alarm interface.
+
+	  This driver can also be built as a module. If so, the module
+	  will be called rtc-cmos.
+
 config RTC_DRV_X1205
 	tristate "Xicor/Intersil X1205"
 	depends on RTC_CLASS && I2C
Index: g26/drivers/rtc/Makefile
===================================================================
--- g26.orig/drivers/rtc/Makefile	2006-11-20 10:03:06.000000000 -0800
+++ g26/drivers/rtc/Makefile	2006-11-20 10:10:47.000000000 -0800
@@ -15,6 +15,7 @@ obj-$(CONFIG_RTC_INTF_SYSFS)	+= rtc-sysf
 obj-$(CONFIG_RTC_INTF_PROC)	+= rtc-proc.o
 obj-$(CONFIG_RTC_INTF_DEV)	+= rtc-dev.o
 
+obj-$(CONFIG_RTC_DRV_CMOS)	+= rtc-cmos.o
 obj-$(CONFIG_RTC_DRV_X1205)	+= rtc-x1205.o
 obj-$(CONFIG_RTC_DRV_ISL1208)	+= rtc-isl1208.o
 obj-$(CONFIG_RTC_DRV_TEST)	+= rtc-test.o
Index: g26/drivers/rtc/rtc-cmos.c
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ g26/drivers/rtc/rtc-cmos.c	2006-11-20 10:10:47.000000000 -0800
@@ -0,0 +1,738 @@
+/*
+ * RTC class driver for "CMOS RTC":  PCs, ACPI, etc
+ *
+ * Copyright (C) 1996 Paul Gortmaker (drivers/char/rtc.c)
+ * Copyright (C) 2006 David Brownell (convert to new framework)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+
+/*
+ * The original "cmos clock" chip was an MC146818 chip, now obsolete.
+ * That defined the register interface now provided by all PCs, some
+ * non-PC systems, and incorporated into ACPI.  Modern PC chipsets
+ * integrate an MC146818 clone in their southbridge, and boards use
+ * that instead of discrete clones like the DS12887 or M48T86.  There
+ * are also clones that connect using the LPC bus.
+ *
+ * That register API is also used directly by various other drivers,
+ * (notably for integrated NVRAM), infrastructure (x86 has code to
+ * bypass the RTC framework, directly reading the RTC during boot
+ * and updating minutes/seconds for systems using NTP synch) and
+ * utilities (like userspace 'hwclock', if no /dev node exists).
+ *
+ * So **ALL** calls to CMOS_READ and CMOS_WRITE must be done with
+ * interrupts disabled, holding the global rtc_lock, to exclude those
+ * other drivers and utilities on correctly configured systems.
+ */
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/spinlock.h>
+#include <linux/platform_device.h>
+#include <linux/mod_devicetable.h>
+
+#include <acpi/acpi.h>
+#include <asm/rtc.h>
+
+
+struct cmos_rtc {
+	struct rtc_device	*rtc;
+	struct device		*dev;
+	int			irq;
+	struct resource		*iomem;
+	u8			acpi;
+
+	/* newer hardware extends the original register set */
+	u8			day_alrm;
+	u8			mon_alrm;
+	u8			century;
+};
+
+#ifdef	CONFIG_ACPI_SLEEP
+#define	use_acpi_wake(cmos)	((cmos)->acpi)
+#else
+#define	use_acpi_wake(cmos)	0
+#endif
+
+/* both platform and pnp busses use negative numbers for invalid irqs */
+#define is_valid_irq(n)		((n) >= 0)
+
+static const char driver_name[] = "rtc_cmos";
+
+/*----------------------------------------------------------------*/
+
+static int cmos_read_time(struct device *dev, struct rtc_time *t)
+{
+	/* REVISIT:  if the clock has a "century" register, use
+	 * that instead of the heuristic in get_rtc_time().
+	 * That'll make Y3K compatility (year > 2070) easy!
+	 */
+	get_rtc_time(t);
+	return 0;
+}
+
+static int cmos_set_time(struct device *dev, struct rtc_time *t)
+{
+	/* REVISIT:  set the "century" register if available
+	 *
+	 * NOTE: this ignores the issue whereby updating the seconds
+	 * takes effect exactly 500ms after we write the register.
+	 * (Also queueing and other delays before we get this far.)
+	 */
+	return set_rtc_time(t);
+}
+
+static int cmos_read_alarm(struct device *dev, struct rtc_wkalrm *t)
+{
+	struct cmos_rtc	*cmos = dev_get_drvdata(dev);
+	unsigned char	rtc_control;
+
+	if (!is_valid_irq(cmos->irq))
+		return -EIO;
+
+	/* Basic alarms only support hour, minute, and seconds fields.
+	 * Some also support day and month, for alarms up to a year in
+	 * the future.
+	 */
+	t->time.tm_mday = -1;
+	t->time.tm_mon = -1;
+
+	spin_lock_irq(&rtc_lock);
+	t->time.tm_sec = CMOS_READ(RTC_SECONDS_ALARM);
+	t->time.tm_min = CMOS_READ(RTC_MINUTES_ALARM);
+	t->time.tm_hour = CMOS_READ(RTC_HOURS_ALARM);
+
+	if (cmos->day_alrm) {
+		t->time.tm_mday = CMOS_READ(cmos->day_alrm);
+		if (!t->time.tm_mday)
+			t->time.tm_mday = -1;
+
+		if (cmos->mon_alrm) {
+			t->time.tm_mon = CMOS_READ(cmos->mon_alrm);
+			if (!t->time.tm_mon)
+				t->time.tm_mon = -1;
+		}
+	}
+
+	rtc_control = CMOS_READ(RTC_CONTROL);
+	spin_unlock_irq(&rtc_lock);
+
+	/* REVISIT this assumes PC style usage:  always BCD */
+
+	if (((unsigned)t->time.tm_sec) < 0x60)
+		t->time.tm_sec = BCD2BIN(t->time.tm_sec);
+	else
+		t->time.tm_sec = -1;
+	if (((unsigned)t->time.tm_min) < 0x60)
+		t->time.tm_min = BCD2BIN(t->time.tm_min);
+	else
+		t->time.tm_min = -1;
+	if (((unsigned)t->time.tm_hour) < 0x24)
+		t->time.tm_hour = BCD2BIN(t->time.tm_hour);
+	else
+		t->time.tm_hour = -1;
+
+	if (cmos->day_alrm) {
+		if (((unsigned)t->time.tm_mday) <= 0x31)
+			t->time.tm_mday = BCD2BIN(t->time.tm_mday);
+		else
+			t->time.tm_mday = -1;
+		if (cmos->mon_alrm) {
+			if (((unsigned)t->time.tm_mon) <= 0x12)
+				t->time.tm_mon = BCD2BIN(t->time.tm_mon) - 1;
+			else
+				t->time.tm_mon = -1;
+		}
+	}
+	t->time.tm_year = -1;
+
+	t->enabled = !!(rtc_control & RTC_AIE);
+	t->pending = 0;
+
+	return 0;
+}
+
+static int cmos_set_alarm(struct device *dev, struct rtc_wkalrm *t)
+{
+	struct cmos_rtc	*cmos = dev_get_drvdata(dev);
+	unsigned char	mon, mday, hrs, min, sec;
+	unsigned char	rtc_control, rtc_intr;
+
+	if (!is_valid_irq(cmos->irq))
+		return -EIO;
+
+	/* REVISIT this assumes PC style usage:  always BCD */
+
+	/* Writing 0xff means "don't care" or "match all".  */
+
+	mon = t->time.tm_mon;
+	mon = (mon < 12) ? BIN2BCD(mon) : 0xff;
+	mon++;
+
+	mday = t->time.tm_mday;
+	mday = (mday >= 1 && mday <= 31) ? BIN2BCD(mday) : 0xff;
+
+	hrs = t->time.tm_hour;
+	hrs = (hrs < 24) ? BIN2BCD(hrs) : 0xff;
+
+	min = t->time.tm_min;
+	min = (min < 60) ? BIN2BCD(min) : 0xff;
+
+	sec = t->time.tm_sec;
+	sec = (sec < 60) ? BIN2BCD(sec) : 0xff;
+
+	/* scrub old acpi state */
+	if (use_acpi_wake(cmos)) {
+		acpi_disable_event(ACPI_EVENT_RTC, 0);
+		acpi_clear_event(ACPI_EVENT_RTC);
+	}
+
+	spin_lock_irq(&rtc_lock);
+
+	/* next rtc irq must not be from previous alarm setting */
+	rtc_control = CMOS_READ(RTC_CONTROL);
+	rtc_control &= ~RTC_AIE;
+	CMOS_WRITE(rtc_control, RTC_CONTROL);
+	rtc_intr = CMOS_READ(RTC_INTR_FLAGS);
+	if (rtc_intr)
+		rtc_update_irq(&cmos->rtc->class_dev, 1, rtc_intr);
+
+	/* update alarm */
+	CMOS_WRITE(hrs, RTC_HOURS_ALARM);
+	CMOS_WRITE(min, RTC_MINUTES_ALARM);
+	CMOS_WRITE(sec, RTC_SECONDS_ALARM);
+
+	/* the system may support an "enhanced" alarm */
+	if (cmos->day_alrm) {
+		CMOS_WRITE(mday, cmos->day_alrm);
+		if (cmos->mon_alrm)
+			CMOS_WRITE(mon, cmos->mon_alrm);
+	}
+
+	if (t->enabled) {
+		rtc_control |= RTC_AIE;
+		CMOS_WRITE(rtc_control, RTC_CONTROL);
+		rtc_intr = CMOS_READ(RTC_INTR_FLAGS);
+		if (rtc_intr)
+			rtc_update_irq(&cmos->rtc->class_dev, 1, rtc_intr);
+	}
+
+	spin_unlock_irq(&rtc_lock);
+
+#ifdef	DEBUG
+/* REVISIT ... does this ACPI event mechanism behave?
+ * I've never observed it to work correctly, on any system...
+ * we'd prefer to call this with the lock held, avoiding a race.
+ */
+	if (use_acpi_wake(cmos)) {
+		acpi_enable_event(ACPI_EVENT_RTC, 0);
+	}
+#endif
+
+	return 0;
+}
+
+static int cmos_set_freq(struct device *dev, int freq)
+{
+	struct cmos_rtc	*cmos = dev_get_drvdata(dev);
+	int		f;
+	unsigned long	flags;
+
+	if (!is_valid_irq(cmos->irq))
+		return -ENXIO;
+
+	/* 0 = no irqs; 1 = 2^15 Hz ... 15 = 2^0 Hz */
+	f = ffs(freq);
+	if (f != 0) {
+		if (f-- > 16 || freq != (1 << f))
+			return -EINVAL;
+		f = 16 - f;
+	}
+
+	spin_lock_irqsave(&rtc_lock, flags);
+	CMOS_WRITE(RTC_REF_CLCK_32KHZ | f, RTC_FREQ_SELECT);
+	spin_unlock_irqrestore(&rtc_lock, flags);
+
+	return 0;
+}
+
+#if defined(CONFIG_RTC_INTF_DEV) || defined(CONFIG_RTC_INTF_DEV_MODULE)
+
+static int
+cmos_rtc_ioctl(struct device *dev, unsigned int cmd, unsigned long arg)
+{
+	struct cmos_rtc	*cmos = dev_get_drvdata(dev);
+	unsigned char	rtc_control, rtc_intr;
+	unsigned long	flags;
+
+	switch (cmd) {
+	case RTC_AIE_OFF:
+	case RTC_AIE_ON:
+	case RTC_UIE_OFF:
+	case RTC_UIE_ON:
+	case RTC_PIE_OFF:
+	case RTC_PIE_ON:
+		if (!is_valid_irq(cmos->irq))
+			return -EINVAL;
+		break;
+	default:
+		return -ENOIOCTLCMD;
+	}
+
+	spin_lock_irqsave(&rtc_lock, flags);
+	rtc_control = CMOS_READ(RTC_CONTROL);
+	switch (cmd) {
+	case RTC_AIE_OFF:	/* alarm off */
+		rtc_control &= ~RTC_AIE;
+		break;
+	case RTC_AIE_ON:	/* alarm on */
+		rtc_control |= RTC_AIE;
+		break;
+	case RTC_UIE_OFF:	/* update off */
+		rtc_control &= ~RTC_UIE;
+		break;
+	case RTC_UIE_ON:	/* update on */
+		rtc_control |= RTC_UIE;
+		break;
+	case RTC_PIE_OFF:	/* periodic off */
+		rtc_control &= ~RTC_PIE;
+		break;
+	case RTC_PIE_ON:	/* periodic on */
+		rtc_control |= RTC_PIE;
+		break;
+	}
+	CMOS_WRITE(rtc_control, RTC_CONTROL);
+	rtc_intr = CMOS_READ(RTC_INTR_FLAGS);
+	if (rtc_intr)
+		rtc_update_irq(&cmos->rtc->class_dev, 1, rtc_intr);
+	spin_unlock_irqrestore(&rtc_lock, flags);
+	return 0;
+}
+
+#else
+#define	cmos_rtc_ioctl	NULL
+#endif
+
+#if defined(CONFIG_RTC_INTF_PROC) || defined(CONFIG_RTC_INTF_PROC_MODULE)
+
+static int cmos_procfs(struct device *dev, struct seq_file *seq)
+{
+	struct cmos_rtc	*cmos = dev_get_drvdata(dev);
+	unsigned char	rtc_control, valid;
+
+	spin_lock_irq(&rtc_lock);
+	rtc_control = CMOS_READ(RTC_CONTROL);
+	valid = CMOS_READ(RTC_VALID);
+	spin_unlock_irq(&rtc_lock);
+
+	return seq_printf(seq,
+			"periodic_IRQ\t: %s\n"
+			"update_IRQ\t: %s\n"
+			// "square_wave\t: %s\n"
+			// "BCD\t\t: %s\n"
+			"DST_enable\t: %s\n"
+			"periodic_freq\t: %d\n"
+			"batt_status\t: %s\n",
+			(rtc_control & RTC_PIE) ? "yes" : "no",
+			(rtc_control & RTC_UIE) ? "yes" : "no",
+			// (rtc_control & RTC_SQWE) ? "yes" : "no",
+			// (rtc_control & RTC_DM_BINARY) ? "no" : "yes",
+			(rtc_control & RTC_DST_EN) ? "yes" : "no",
+			cmos->rtc->irq_freq,
+			(valid & RTC_VRT) ? "okay" : "dead");
+}
+
+#else
+#define	cmos_procfs	NULL
+#endif
+
+static const struct rtc_class_ops cmos_rtc_ops = {
+	.ioctl		= cmos_rtc_ioctl,
+	.read_time	= cmos_read_time,
+	.set_time	= cmos_set_time,
+	.read_alarm	= cmos_read_alarm,
+	.set_alarm	= cmos_set_alarm,
+	.proc		= cmos_procfs,
+	.irq_set_freq	= cmos_set_freq,
+};
+
+/*----------------------------------------------------------------*/
+
+static struct cmos_rtc	cmos_rtc;
+
+static irqreturn_t cmos_interrupt(int irq, void *p)
+{
+	u8		irqstat;
+
+	spin_lock(&rtc_lock);
+	irqstat = CMOS_READ(RTC_INTR_FLAGS);
+	spin_unlock(&rtc_lock);
+
+	if (irqstat) {
+		/* NOTE: irqstat may have e.g. RTC_PF set
+		 * even when RTC_PIE is clear...
+		 */
+		rtc_update_irq(p, 1, irqstat);
+		return IRQ_HANDLED;
+	} else
+		return IRQ_NONE;
+}
+
+#ifdef	CONFIG_PM
+
+static u32 cmos_acpi_handler(void *p)
+{
+	acpi_clear_event(ACPI_EVENT_RTC);
+	acpi_disable_event(ACPI_EVENT_RTC, 0);
+
+	/* REVISIT doesn't seem like acpi events work ... */
+
+printk("%s\n", __FUNCTION__);
+
+	// call this with irqs blocked:
+	// rtc_update_irq(p, 1, RTC_IRQF | RTC_AF);
+
+	return ACPI_INTERRUPT_HANDLED;
+}
+
+#endif
+
+#ifdef	CONFIG_PNPACPI
+#define	is_pnpacpi()	1
+#else
+#define	is_pnpacpi()	0
+#endif
+
+static int __devinit
+cmos_do_probe(struct device *dev, struct resource *ports, int rtc_irq)
+{
+	struct cmos_rtc_board_info	*info = dev->platform_data;
+	int				retval = 0;
+	unsigned char			rtc_control;
+	int				wake_std = 0;
+
+	/* there can be only one ... */
+	if (cmos_rtc.dev)
+		return -EBUSY;
+
+	if (!ports)
+		return -ENODEV;
+
+	cmos_rtc.irq = rtc_irq;
+	cmos_rtc.iomem = ports;
+
+	if (info) {
+		/* REVISIT this driver should not care about ACPI.
+		 * The ACPI alarms never seem to fire, anyway...
+		 */
+		cmos_rtc.acpi = 1;
+
+		cmos_rtc.day_alrm = info->rtc_day_alarm;
+		cmos_rtc.mon_alrm = info->rtc_mon_alarm;
+		cmos_rtc.century = info->rtc_century;
+		wake_std = info->wake_from_std;
+	}
+
+	cmos_rtc.rtc = rtc_device_register(driver_name, dev,
+				&cmos_rtc_ops, THIS_MODULE);
+	if (IS_ERR(cmos_rtc.rtc))
+		return PTR_ERR(cmos_rtc.rtc);
+
+	cmos_rtc.dev = dev;
+	dev_set_drvdata(dev, &cmos_rtc);
+
+	/* platform and pnp busses handle resources incompatibly.
+	 *
+	 * REVISIT for non-x86 systems we may need to handle io memory
+	 * resources: ioremap them, and request_mem_region().
+	 */
+	if (is_pnpacpi()) {
+		retval = request_resource(&ioport_resource, ports);
+		if (retval < 0) {
+			dev_dbg(dev, "i/o registers already in use\n");
+			goto cleanup0;
+		}
+	}
+	rename_region(ports, cmos_rtc.rtc->class_dev.class_id);
+
+	spin_lock_irq(&rtc_lock);
+
+	/* force periodic irq to CMOS reset default of 1024Hz;
+	 *
+	 * REVISIT it's been reported that at least one x86_64 ALI mobo
+	 * doesn't use 32KHz here ... for portability we might need to
+	 * do something about other clock frequencies.
+	 */
+	CMOS_WRITE(RTC_REF_CLCK_32KHZ | 0x06, RTC_FREQ_SELECT);
+	cmos_rtc.rtc->irq_freq = 1024;
+
+	/* disable irqs.
+	 *
+	 * NOTE after changing RTC_xIE bits we always read INTR_FLAGS;
+	 * allegedly some older rtcs need that to handle irqs properly
+	 */
+	rtc_control = CMOS_READ(RTC_CONTROL);
+	rtc_control &= ~(RTC_PIE | RTC_AIE | RTC_UIE);
+	CMOS_WRITE(rtc_control, RTC_CONTROL);
+	CMOS_READ(RTC_INTR_FLAGS);
+
+	spin_unlock_irq(&rtc_lock);
+
+	/* FIXME teach the alarm code how to handle binary mode;
+	 * <asm-generic/rtc.h> doesn't know 12-hour mode either.
+	 */
+	if (!(rtc_control & RTC_24H) || (rtc_control & (RTC_DM_BINARY))) {
+		dev_dbg(dev, "only 24-hr BCD mode supported\n");
+		retval = -ENXIO;
+		goto cleanup1;
+	}
+
+	if (is_valid_irq(rtc_irq))
+		retval = request_irq(rtc_irq, cmos_interrupt, IRQF_DISABLED,
+				cmos_rtc.rtc->class_dev.class_id,
+				&cmos_rtc.rtc->class_dev);
+	if (retval < 0) {
+		dev_dbg(dev, "IRQ %d is already in use\n", rtc_irq);
+		goto cleanup1;
+	}
+
+	pr_info("%s: %s, %s alarm%s%s\n",
+			cmos_rtc.rtc->class_dev.class_id,
+			dev->driver->name,
+			is_valid_irq(rtc_irq)
+				?  (cmos_rtc.mon_alrm
+					? "year"
+					: (cmos_rtc.day_alrm
+						? "month" : "day"))
+				: "no",
+			wake_std ? ", wake from STD" : "",
+			cmos_rtc.century ? ", y3k" : ""
+			);
+
+	if (use_acpi_wake(&cmos_rtc)) {
+		acpi_install_fixed_event_handler(ACPI_EVENT_RTC,
+				cmos_acpi_handler, &cmos_rtc.rtc->class_dev);
+		acpi_disable_event(ACPI_EVENT_RTC, 0);
+	}
+
+	return 0;
+
+cleanup1:
+	rename_region(ports, NULL);
+cleanup0:
+	rtc_device_unregister(cmos_rtc.rtc);
+	return retval;
+}
+
+static void cmos_do_shutdown(void)
+{
+	unsigned char	rtc_control;
+
+	spin_lock_irq(&rtc_lock);
+	rtc_control = CMOS_READ(RTC_CONTROL);
+	rtc_control &= ~(RTC_PIE|RTC_AIE|RTC_UIE);
+	CMOS_WRITE(rtc_control, RTC_CONTROL);
+	CMOS_READ(RTC_INTR_FLAGS);
+	spin_unlock_irq(&rtc_lock);
+}
+
+static void __devexit cmos_do_remove(struct device *dev)
+{
+	struct cmos_rtc	*cmos = dev_get_drvdata(dev);
+
+	cmos_do_shutdown();
+
+	if (use_acpi_wake(cmos)) {
+		acpi_disable_event(ACPI_EVENT_RTC, 0);
+		acpi_remove_fixed_event_handler(ACPI_EVENT_RTC,
+				cmos_acpi_handler);
+	}
+
+	if (dev->bus != &platform_bus_type)
+		release_resource(cmos->iomem);
+	rename_region(cmos->iomem, NULL);
+
+	if (is_valid_irq(cmos->irq))
+		free_irq(cmos->irq, &cmos_rtc.rtc->class_dev);
+
+	rtc_device_unregister(cmos_rtc.rtc);
+
+	cmos_rtc.dev = NULL;
+	dev_set_drvdata(dev, NULL);
+}
+
+#ifdef	CONFIG_PM
+
+static int cmos_suspend(struct device *dev, pm_message_t mesg)
+{
+	struct cmos_rtc	*cmos = dev_get_drvdata(dev);
+	int		do_wake = cmos->acpi && device_may_wakeup(dev);
+
+	/* force RTC_EN value during system sleep states */
+	if (use_acpi_wake(cmos)) {
+		if (do_wake)
+			acpi_enable_event(ACPI_EVENT_RTC, 0);
+		else
+			acpi_disable_event(ACPI_EVENT_RTC, 0);
+	}
+
+pr_debug("%s, EVENT_RTC %sabled\n", __FUNCTION__, do_wake ? "en" : "dis");
+
+	return 0;
+}
+
+static int cmos_resume(struct device *dev)
+{
+	struct cmos_rtc	*cmos = dev_get_drvdata(dev);
+
+	/* REVISIT:  the mechanism to resync jiffies on resume
+	 * should be portable between platforms ...
+	 */
+
+pr_debug("%s\n", __FUNCTION__);
+
+	if (use_acpi_wake(cmos))
+		acpi_disable_event(ACPI_EVENT_RTC, 0);
+
+	return 0;
+}
+
+#else
+#define	cmos_suspend	NULL
+#define	cmos_resume	NULL
+#endif
+
+/*----------------------------------------------------------------*/
+
+/* On ACPI systems, the device node may be created as either a PNP
+ * device or a platform_device.  In either case the FADT data should
+ * have been transferred to us through platform_data.
+ */
+
+#ifdef	CONFIG_PNPACPI
+
+#include <linux/pnp.h>
+
+static int __devinit
+cmos_pnp_probe(struct pnp_dev *pnp, const struct pnp_device_id *id)
+{
+	/* REVISIT paranoia argues for a shutdown notifier, since PNP
+	 * drivers can't provide shutdown() methods to disable IRQs.
+	 * Or better yet, fix PNP to allow those methods...
+	 */
+	return cmos_do_probe(&pnp->dev,
+			&pnp->res.port_resource[0],
+			pnp->res.irq_resource[0].start);
+}
+
+static void __devexit cmos_pnp_remove(struct pnp_dev *pnp)
+{
+	cmos_do_remove(&pnp->dev);
+}
+
+#ifdef	CONFIG_PM
+
+static int cmos_pnp_suspend(struct pnp_dev *pnp, pm_message_t mesg)
+{
+	return cmos_suspend(&pnp->dev, mesg);
+}
+
+static int cmos_pnp_resume(struct pnp_dev *pnp)
+{
+	return cmos_resume(&pnp->dev);
+}
+
+#else
+#define	cmos_pnp_suspend	NULL
+#define	cmos_pnp_resume		NULL
+#endif
+
+
+static const struct pnp_device_id rtc_ids[] = {
+	{ .id = "PNP0b00", },
+	{ .id = "PNP0b01", },
+	{ .id = "PNP0b02", },
+	{ },
+};
+MODULE_DEVICE_TABLE(pnp, rtc_ids);
+
+static struct pnp_driver cmos_pnp_driver = {
+	.name		= (char *) driver_name,
+	.id_table	= rtc_ids,
+	.probe		= cmos_pnp_probe,
+	.remove		= __devexit_p(cmos_pnp_remove),
+	.suspend	= cmos_pnp_suspend,
+	.resume		= cmos_pnp_resume,
+};
+
+static int __init cmos_init(void)
+{
+	return pnp_register_driver(&cmos_pnp_driver);
+}
+module_init(cmos_init);
+
+static void __exit cmos_exit(void)
+{
+	pnp_unregister_driver(&cmos_pnp_driver);
+}
+module_exit(cmos_exit);
+
+#else	/* no PNPACPI */
+
+/*----------------------------------------------------------------*/
+
+/* Platform setup should have set up an RTC device, when PNPACPI is
+ * unavailable ... including non-PC and non-ACPI platforms.
+ */
+
+static int __devinit cmos_platform_probe(struct platform_device *pdev)
+{
+	return cmos_do_probe(&pdev->dev,
+			platform_get_resource(pdev, IORESOURCE_IO, 0),
+			platform_get_irq(pdev, 0));
+}
+
+static int __devexit cmos_platform_remove(struct platform_device *pdev)
+{
+	cmos_do_remove(&pdev->dev);
+	return 0;
+}
+
+static void cmos_platform_shutdown(struct platform_device *pdev)
+{
+	cmos_do_shutdown();
+}
+
+static struct platform_driver cmos_platform_driver = {
+	.probe		= cmos_platform_probe,
+	.remove		= __devexit_p(cmos_platform_remove),
+	.shutdown	= cmos_platform_shutdown,
+	.driver = {
+		.name		= (char *) driver_name,
+		.suspend	= cmos_suspend,
+		.resume		= cmos_resume,
+	}
+};
+
+static int __init cmos_init(void)
+{
+	return platform_driver_register(&cmos_platform_driver);
+}
+module_init(cmos_init);
+
+static void __exit cmos_exit(void)
+{
+	platform_driver_unregister(&cmos_platform_driver);
+}
+module_exit(cmos_exit);
+
+
+#endif	/* !PNPACPI */
+
+MODULE_DESCRIPTION("'CMOS' RTC driver:  PCs, ACPI, etc");
+MODULE_LICENSE("GPL");
Index: g26/drivers/acpi/sleep/proc.c
===================================================================
--- g26.orig/drivers/acpi/sleep/proc.c	2006-11-20 10:03:06.000000000 -0800
+++ g26/drivers/acpi/sleep/proc.c	2006-11-20 10:10:47.000000000 -0800
@@ -70,6 +70,14 @@ acpi_system_write_sleep(struct file *fil
 }
 #endif				/* CONFIG_ACPI_SLEEP_PROC_SLEEP */
 
+#if defined(CONFIG_RTC_DRV_CMOS) || defined(CONFIG_RTC_DRV_CMOS_MODULE)
+/* use code that fits into standard Linux driver frameworks */
+#else
+#define	HAVE_ACPI_LEGACY_ALARM
+#endif
+
+#ifdef	HAVE_ACPI_LEGACY_ALARM
+
 static int acpi_system_alarm_seq_show(struct seq_file *seq, void *offset)
 {
 	u32 sec, min, hr;
@@ -339,6 +347,8 @@ acpi_system_write_alarm(struct file *fil
       end:
 	return_VALUE(result ? result : count);
 }
+#endif	/* HAVE_ACPI_LEGACY_ALARM */
+
 
 extern struct list_head acpi_wakeup_device_list;
 extern spinlock_t acpi_device_lock;
@@ -452,6 +462,7 @@ static const struct file_operations acpi
 };
 #endif				/* CONFIG_ACPI_SLEEP_PROC_SLEEP */
 
+#ifdef	HAVE_ACPI_LEGACY_ALARM
 static const struct file_operations acpi_system_alarm_fops = {
 	.open = acpi_system_alarm_open_fs,
 	.read = seq_read,
@@ -467,8 +478,9 @@ static u32 rtc_handler(void *context)
 
 	return ACPI_INTERRUPT_HANDLED;
 }
+#endif	/* HAVE_ACPI_LEGACY_ALARM */
 
-static int acpi_sleep_proc_init(void)
+static int __init acpi_sleep_proc_init(void)
 {
 	struct proc_dir_entry *entry = NULL;
 
@@ -484,6 +496,7 @@ static int acpi_sleep_proc_init(void)
 		entry->proc_fops = &acpi_system_sleep_fops;
 #endif
 
+#ifdef	HAVE_ACPI_LEGACY_ALARM
 	/* 'alarm' [R/W] */
 	entry =
 	    create_proc_entry("alarm", S_IFREG | S_IRUGO | S_IWUSR,
@@ -491,6 +504,9 @@ static int acpi_sleep_proc_init(void)
 	if (entry)
 		entry->proc_fops = &acpi_system_alarm_fops;
 
+	acpi_install_fixed_event_handler(ACPI_EVENT_RTC, rtc_handler, NULL);
+#endif	/* HAVE_ACPI_LEGACY_ALARM */
+
 	/* 'wakeup device' [R/W] */
 	entry =
 	    create_proc_entry("wakeup", S_IFREG | S_IRUGO | S_IWUSR,
@@ -498,7 +514,6 @@ static int acpi_sleep_proc_init(void)
 	if (entry)
 		entry->proc_fops = &acpi_system_wakeup_device_fops;
 
-	acpi_install_fixed_event_handler(ACPI_EVENT_RTC, rtc_handler, NULL);
 	return 0;
 }
 

^ permalink raw reply	[flat|nested] 19+ messages in thread

* [patch 2.6.19-rc6 4/6] ACPI exports RTC extensions through platform_data
  2006-11-20 18:14 [patch 2.6.19-rc6 0/6] more rtc framework/driver updates David Brownell
                   ` (3 preceding siblings ...)
  2006-11-20 18:27 ` [patch 2.6.19-rc6 5/6] rtc-cmos driver David Brownell
@ 2006-11-20 18:27 ` David Brownell
  2006-11-20 18:28 ` [patch 2.6.19-rc6 6/6] rtc-omap driver David Brownell
  5 siblings, 0 replies; 19+ messages in thread
From: David Brownell @ 2006-11-20 18:27 UTC (permalink / raw)
  To: Alessandro Zummo; +Cc: Linux Kernel list, Len Brown

Define platform_data for the MC146818 based RTCs, currently just holding
extensions standardized by ACPI (but available on some ACPI-neutral clones).

Update ACPI to export that RTC extension information through platform_data
to the PNP or platform bus device node.

Signed-off-by: David Brownell <dbrownell@users.sourceforge.net>

Index: g26/include/linux/mc146818rtc.h
===================================================================
--- g26.orig/include/linux/mc146818rtc.h	2006-11-20 10:03:06.000000000 -0800
+++ g26/include/linux/mc146818rtc.h	2006-11-20 10:10:45.000000000 -0800
@@ -18,6 +18,18 @@
 #ifdef __KERNEL__
 #include <linux/spinlock.h>		/* spinlock_t */
 extern spinlock_t rtc_lock;		/* serialize CMOS RAM access */
+
+/* Some RTCs extend the mc146818 register set to support alarms of more
+ * than 24 hours in the future; or dates that include a century code.
+ * And sometimes the RTC alarm can wake the system from suspend-to-disk.
+ * This platform_data structure can pass this information to the driver.
+ */
+struct cmos_rtc_board_info {
+	u8	rtc_day_alarm;		/* zero, or register index */
+	u8	rtc_mon_alarm;		/* zero, or register index */
+	u8	rtc_century;		/* zero, or register index */
+	u8	wake_from_std;		/* true iff alarm wakes from STD */
+};
 #endif
 
 /**********************************************************************
Index: g26/drivers/acpi/glue.c
===================================================================
--- g26.orig/drivers/acpi/glue.c	2006-11-20 10:03:06.000000000 -0800
+++ g26/drivers/acpi/glue.c	2006-11-20 10:10:45.000000000 -0800
@@ -358,3 +358,107 @@ static int __init init_acpi_device_notif
 }
 
 arch_initcall(init_acpi_device_notify);
+
+
+#if defined(CONFIG_RTC_DRV_CMOS) || defined(CONFIG_RTC_DRV_CMOS_MODULE)
+
+/* Every ACPI platform has a mc146818 compatible "cmos rtc".  We want
+ * to find its device node, so we can pass ACPI-specific config data
+ * to its driver.  So we'll just probe for that device -- with a dummy
+ * driver, using the relevant bus -- before the RTC driver initializes.
+ */
+#include <linux/mc146818rtc.h>
+
+static struct cmos_rtc_board_info rtc_info;
+
+static struct device *rtc_dev __initdata;
+static char drvname[] __initdata = "rtc_cmos";
+
+
+#ifdef CONFIG_PNPACPI
+
+/* PNP devices are registered in a subsys_initcall();
+ * ACPI specifies the PNP IDs to use.
+ */
+#include <linux/pnp.h>
+
+static struct pnp_device_id rtc_ids[] __initdata = {
+	{ .id = "PNP0b00", },
+	{ .id = "PNP0b01", },
+	{ .id = "PNP0b02", },
+	{ },
+};
+
+static int __init
+rtc_pnp_probe(struct pnp_dev *pnp, const struct pnp_device_id *id)
+{
+	rtc_dev = &pnp->dev;
+	return -ENXIO;
+}
+
+static struct pnp_driver cmos_pnp_driver __initdata = {
+	.name		= drvname,
+	.id_table	= rtc_ids,
+	.probe		= rtc_pnp_probe,
+};
+
+static struct device *__init get_rtc_dev(void)
+{
+	if (pnp_register_driver(&cmos_pnp_driver) == 0)
+		pnp_unregister_driver(&cmos_pnp_driver);
+	return rtc_dev;
+}
+
+#else
+
+/* We expect platforms to register an RTC device, conventionally at or
+ * near arch_initcall().  That should work even without ACPI.  The driver
+ * name matters; it must match the driver.
+ */
+#include <linux/platform_device.h>
+
+static int __init rtc_platform_probe(struct platform_device *pdev)
+{
+	rtc_dev = &pdev->dev;
+	return -ENXIO;
+}
+
+static struct platform_driver rtc_platform_driver __initdata = {
+	.driver = {
+		.name		= drvname,
+	},
+	.probe		= rtc_platform_probe,
+};
+
+static struct device *__init get_rtc_dev(void)
+{
+	if (platform_driver_register(&rtc_platform_driver) == 0)
+		platform_driver_unregister(&rtc_platform_driver);
+	return rtc_dev;
+}
+
+#endif
+
+static int __init acpi_rtc_init(void)
+{
+	struct device *dev = get_rtc_dev();
+
+	if (dev) {
+		rtc_info.rtc_day_alarm = acpi_gbl_FADT->day_alrm;
+		rtc_info.rtc_mon_alarm = acpi_gbl_FADT->mon_alrm;
+		rtc_info.rtc_century = acpi_gbl_FADT->century;
+
+		/* REVISIT iff revision > FADT2_REVISION_ID ? */
+		rtc_info.wake_from_std = acpi_gbl_FADT->rtcs4;
+
+		dev->platform_data = &rtc_info;
+
+		/* RTC always wakes from S1/S2/S3, and often S4/STD */
+		device_init_wakeup(dev, 1);
+	} else
+		pr_debug("ACPI: RTC unavailable?\n");
+	return 0;
+}
+fs_initcall(acpi_rtc_init);
+
+#endif


^ permalink raw reply	[flat|nested] 19+ messages in thread

* [patch 2.6.19-rc6 6/6] rtc-omap driver
  2006-11-20 18:14 [patch 2.6.19-rc6 0/6] more rtc framework/driver updates David Brownell
                   ` (4 preceding siblings ...)
  2006-11-20 18:27 ` [patch 2.6.19-rc6 4/6] ACPI exports RTC extensions through platform_data David Brownell
@ 2006-11-20 18:28 ` David Brownell
  2006-11-20 23:09   ` Alessandro Zummo
  2006-11-22  1:19   ` Andrew Morton
  5 siblings, 2 replies; 19+ messages in thread
From: David Brownell @ 2006-11-20 18:28 UTC (permalink / raw)
  To: Alessandro Zummo; +Cc: Linux Kernel list, Tony Lindgren

This creates a new RTC-framework driver for the RTC/calendar module found
in various OMAP1 chips.  (OMAP2 and OMAP3 use external RTCs, like those in
TI's multifunction PM companion chips.)  It's been in the Linux-OMAP tree
for several months now, and other trees before that, so it's quite stable.
The most notable issue is that the OMAP IRQ code doesn't yet support the
RTC IRQ as a wakeup event.  Once that's fixed, a patch will be needed.

Signed-off-by: David Brownell <dbrownell@users.sourceforge.net>

Index: g26/drivers/rtc/Kconfig
===================================================================
--- g26.orig/drivers/rtc/Kconfig	2006-11-20 10:10:47.000000000 -0800
+++ g26/drivers/rtc/Kconfig	2006-11-20 10:10:49.000000000 -0800
@@ -182,6 +182,14 @@ config RTC_DRV_DS1742
 	  This driver can also be built as a module. If so, the module
 	  will be called rtc-ds1742.
 
+config RTC_DRV_OMAP
+	tristate "TI OMAP1"
+	depends on RTC_CLASS && ( \
+		ARCH_OMAP15XX || ARCH_OMAP16XX || ARCH_OMAP730 )
+	help
+	  Say "yes" here to support the real time clock on TI OMAP1 chips.
+	  This driver can also be built as a module called rtc-omap.
+
 config RTC_DRV_PCF8563
 	tristate "Philips PCF8563/Epson RTC8564"
 	depends on RTC_CLASS && I2C
Index: g26/arch/arm/mach-omap1/devices.c
===================================================================
--- g26.orig/arch/arm/mach-omap1/devices.c	2006-11-20 10:03:05.000000000 -0800
+++ g26/arch/arm/mach-omap1/devices.c	2006-11-20 10:10:49.000000000 -0800
@@ -55,7 +55,7 @@ static inline void omap_init_irda(void) 
 
 /*-------------------------------------------------------------------------*/
 
-#if	defined(CONFIG_OMAP_RTC) || defined(CONFIG_OMAP_RTC)
+#if defined(CONFIG_RTC_DRV_OMAP) || defined(CONFIG_RTC_DRV_OMAP_MODULE)
 
 #define	OMAP_RTC_BASE		0xfffb4800
 
Index: g26/drivers/rtc/Makefile
===================================================================
--- g26.orig/drivers/rtc/Makefile	2006-11-20 10:10:47.000000000 -0800
+++ g26/drivers/rtc/Makefile	2006-11-20 10:10:49.000000000 -0800
@@ -22,6 +22,7 @@ obj-$(CONFIG_RTC_DRV_TEST)	+= rtc-test.o
 obj-$(CONFIG_RTC_DRV_DS1307)	+= rtc-ds1307.o
 obj-$(CONFIG_RTC_DRV_DS1672)	+= rtc-ds1672.o
 obj-$(CONFIG_RTC_DRV_DS1742)	+= rtc-ds1742.o
+obj-$(CONFIG_RTC_DRV_OMAP)	+= rtc-omap.o
 obj-$(CONFIG_RTC_DRV_PCF8563)	+= rtc-pcf8563.o
 obj-$(CONFIG_RTC_DRV_PCF8583)	+= rtc-pcf8583.o
 obj-$(CONFIG_RTC_DRV_RS5C372)	+= rtc-rs5c372.o
Index: g26/drivers/rtc/rtc-omap.c
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ g26/drivers/rtc/rtc-omap.c	2006-11-20 10:10:49.000000000 -0800
@@ -0,0 +1,572 @@
+/*
+ * TI OMAP1 Real Time Clock interface for Linux
+ *
+ * Copyright (C) 2003 MontaVista Software, Inc.
+ * Author: George G. Davis <gdavis@mvista.com> or <source@mvista.com>
+ *
+ * Copyright (C) 2006 David Brownell (new RTC framework)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/ioport.h>
+#include <linux/delay.h>
+#include <linux/rtc.h>
+#include <linux/bcd.h>
+#include <linux/platform_device.h>
+
+#include <asm/io.h>
+#include <asm/mach/time.h>
+
+
+/* The OMAP1 RTC is a year/month/day/hours/minutes/seconds BCD clock
+ * with century-range alarm matching, driven by the 32kHz clock.
+ *
+ * The main user-visible ways it differs from PC RTCs are by omitting
+ * "don't care" alarm fields and sub-second periodic IRQs, and having
+ * an autoadjust mechanism to calibrate to the true oscillator rate.
+ *
+ * Board-specific wiring options include using split power mode with
+ * RTC_OFF_NOFF used as the reset signal (so the RTC won't be reset),
+ * and wiring RTC_WAKE_INT (so the RTC alarm can wake the system from
+ * low power modes).  See the BOARD-SPECIFIC CUSTOMIZATION comment.
+ */
+
+#define OMAP_RTC_BASE			0xfffb4800
+
+/* RTC registers */
+#define OMAP_RTC_SECONDS_REG		0x00
+#define OMAP_RTC_MINUTES_REG		0x04
+#define OMAP_RTC_HOURS_REG		0x08
+#define OMAP_RTC_DAYS_REG		0x0C
+#define OMAP_RTC_MONTHS_REG		0x10
+#define OMAP_RTC_YEARS_REG		0x14
+#define OMAP_RTC_WEEKS_REG		0x18
+
+#define OMAP_RTC_ALARM_SECONDS_REG	0x20
+#define OMAP_RTC_ALARM_MINUTES_REG	0x24
+#define OMAP_RTC_ALARM_HOURS_REG	0x28
+#define OMAP_RTC_ALARM_DAYS_REG		0x2c
+#define OMAP_RTC_ALARM_MONTHS_REG	0x30
+#define OMAP_RTC_ALARM_YEARS_REG	0x34
+
+#define OMAP_RTC_CTRL_REG		0x40
+#define OMAP_RTC_STATUS_REG		0x44
+#define OMAP_RTC_INTERRUPTS_REG		0x48
+
+#define OMAP_RTC_COMP_LSB_REG		0x4c
+#define OMAP_RTC_COMP_MSB_REG		0x50
+#define OMAP_RTC_OSC_REG		0x54
+
+/* OMAP_RTC_CTRL_REG bit fields: */
+#define OMAP_RTC_CTRL_SPLIT		(1<<7)
+#define OMAP_RTC_CTRL_DISABLE		(1<<6)
+#define OMAP_RTC_CTRL_SET_32_COUNTER	(1<<5)
+#define OMAP_RTC_CTRL_TEST		(1<<4)
+#define OMAP_RTC_CTRL_MODE_12_24	(1<<3)
+#define OMAP_RTC_CTRL_AUTO_COMP		(1<<2)
+#define OMAP_RTC_CTRL_ROUND_30S		(1<<1)
+#define OMAP_RTC_CTRL_STOP		(1<<0)
+
+/* OMAP_RTC_STATUS_REG bit fields: */
+#define OMAP_RTC_STATUS_POWER_UP        (1<<7)
+#define OMAP_RTC_STATUS_ALARM           (1<<6)
+#define OMAP_RTC_STATUS_1D_EVENT        (1<<5)
+#define OMAP_RTC_STATUS_1H_EVENT        (1<<4)
+#define OMAP_RTC_STATUS_1M_EVENT        (1<<3)
+#define OMAP_RTC_STATUS_1S_EVENT        (1<<2)
+#define OMAP_RTC_STATUS_RUN             (1<<1)
+#define OMAP_RTC_STATUS_BUSY            (1<<0)
+
+/* OMAP_RTC_INTERRUPTS_REG bit fields: */
+#define OMAP_RTC_INTERRUPTS_IT_ALARM    (1<<3)
+#define OMAP_RTC_INTERRUPTS_IT_TIMER    (1<<2)
+
+
+#define rtc_read(addr)		omap_readb(OMAP_RTC_BASE + (addr))
+#define rtc_write(val, addr)	omap_writeb(val, OMAP_RTC_BASE + (addr))
+
+
+/* platform_bus isn't hotpluggable, so for static linkage it'd be safe
+ * to get rid of probe() and remove() code ... too bad the driver struct
+ * remembers probe(), that's about 25% of the runtime footprint!!
+ */
+#ifndef	MODULE
+#undef	__devexit
+#undef	__devexit_p
+#define	__devexit	__exit
+#define	__devexit_p	__exit_p
+#endif
+
+
+/* we rely on the rtc framework to handle locking (rtc->ops_lock),
+ * so the only other requirement is that register accesses which
+ * require BUSY to be clear are made with IRQs locally disabled
+ */
+static void rtc_wait_not_busy(void)
+{
+	int	count = 0;
+	u8	status;
+
+	/* BUSY may stay active for 1/32768 second (~30 usec) */
+	for (count = 0; count < 50; count++) {
+		status = rtc_read(OMAP_RTC_STATUS_REG);
+		if ((status & (u8)OMAP_RTC_STATUS_BUSY) == 0)
+			break;
+		udelay(1);
+	}
+	/* now we have ~15 usec to read/write various registers */
+}
+
+static irqreturn_t rtc_irq(int irq, void *class_dev)
+{
+	unsigned long		events = 0;
+	u8			irq_data;
+
+	irq_data = rtc_read(OMAP_RTC_STATUS_REG);
+
+	/* alarm irq? */
+	if (irq_data & OMAP_RTC_STATUS_ALARM) {
+		rtc_write(OMAP_RTC_STATUS_ALARM, OMAP_RTC_STATUS_REG);
+		events |= RTC_IRQF | RTC_AF;
+	}
+
+	/* 1/sec periodic/update irq? */
+	if (irq_data & OMAP_RTC_STATUS_1S_EVENT)
+		events |= RTC_IRQF | RTC_UF;
+
+	rtc_update_irq(class_dev, 1, events);
+
+	return IRQ_HANDLED;
+}
+
+#ifdef	CONFIG_RTC_INTF_DEV
+
+static int
+omap_rtc_ioctl(struct device *dev, unsigned int cmd, unsigned long arg)
+{
+	u8 reg;
+
+	switch (cmd) {
+	case RTC_AIE_OFF:
+	case RTC_AIE_ON:
+	case RTC_UIE_OFF:
+	case RTC_UIE_ON:
+		break;
+	default:
+		return -ENOIOCTLCMD;
+	}
+
+	local_irq_disable();
+	rtc_wait_not_busy();
+	reg = rtc_read(OMAP_RTC_INTERRUPTS_REG);
+	switch (cmd) {
+	/* AIE = Alarm Interrupt Enable */
+	case RTC_AIE_OFF:
+		reg &= ~OMAP_RTC_INTERRUPTS_IT_ALARM;
+		break;
+	case RTC_AIE_ON:
+		reg |= OMAP_RTC_INTERRUPTS_IT_ALARM;
+		break;
+	/* UIE = Update Interrupt Enable (1/second) */
+	case RTC_UIE_OFF:
+		reg &= ~OMAP_RTC_INTERRUPTS_IT_TIMER;
+		break;
+	case RTC_UIE_ON:
+		reg |= OMAP_RTC_INTERRUPTS_IT_TIMER;
+		break;
+	}
+	rtc_wait_not_busy();
+	rtc_write(reg, OMAP_RTC_INTERRUPTS_REG);
+	local_irq_enable();
+
+	return 0;
+}
+
+#else
+#define	omap_rtc_ioctl	NULL
+#endif
+
+/* this hardware doesn't support "don't care" alarm fields */
+static int tm2bcd(struct rtc_time *tm)
+{
+	if (rtc_valid_tm(tm) != 0)
+		return -EINVAL;
+
+	tm->tm_sec = BIN2BCD(tm->tm_sec);
+	tm->tm_min = BIN2BCD(tm->tm_min);
+	tm->tm_hour = BIN2BCD(tm->tm_hour);
+	tm->tm_mday = BIN2BCD(tm->tm_mday);
+
+	tm->tm_mon = BIN2BCD(tm->tm_mon + 1);
+
+	/* epoch == 1900 */
+	if (tm->tm_year < 100 || tm->tm_year > 199)
+		return -EINVAL;
+	tm->tm_year = BIN2BCD(tm->tm_year - 100);
+
+	return 0;
+}
+
+static void bcd2tm(struct rtc_time *tm)
+{
+	tm->tm_sec = BCD2BIN(tm->tm_sec);
+	tm->tm_min = BCD2BIN(tm->tm_min);
+	tm->tm_hour = BCD2BIN(tm->tm_hour);
+	tm->tm_mday = BCD2BIN(tm->tm_mday);
+	tm->tm_mon = BCD2BIN(tm->tm_mon) - 1;
+	/* epoch == 1900 */
+	tm->tm_year = BCD2BIN(tm->tm_year) + 100;
+}
+
+
+static int omap_rtc_read_time(struct device *dev, struct rtc_time *tm)
+{
+	/* we don't report wday/yday/isdst ... */
+	local_irq_disable();
+	rtc_wait_not_busy();
+
+	tm->tm_sec = rtc_read(OMAP_RTC_SECONDS_REG);
+	tm->tm_min = rtc_read(OMAP_RTC_MINUTES_REG);
+	tm->tm_hour = rtc_read(OMAP_RTC_HOURS_REG);
+	tm->tm_mday = rtc_read(OMAP_RTC_DAYS_REG);
+	tm->tm_mon = rtc_read(OMAP_RTC_MONTHS_REG);
+	tm->tm_year = rtc_read(OMAP_RTC_YEARS_REG);
+
+	local_irq_enable();
+
+	bcd2tm(tm);
+	return 0;
+}
+
+static int omap_rtc_set_time(struct device *dev, struct rtc_time *tm)
+{
+	if (tm2bcd(tm) < 0)
+		return -EINVAL;
+	local_irq_disable();
+	rtc_wait_not_busy();
+
+	rtc_write(tm->tm_year, OMAP_RTC_YEARS_REG);
+	rtc_write(tm->tm_mon, OMAP_RTC_MONTHS_REG);
+	rtc_write(tm->tm_mday, OMAP_RTC_DAYS_REG);
+	rtc_write(tm->tm_hour, OMAP_RTC_HOURS_REG);
+	rtc_write(tm->tm_min, OMAP_RTC_MINUTES_REG);
+	rtc_write(tm->tm_sec, OMAP_RTC_SECONDS_REG);
+
+	local_irq_enable();
+
+	return 0;
+}
+
+static int omap_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alm)
+{
+	local_irq_disable();
+	rtc_wait_not_busy();
+
+	alm->time.tm_sec = rtc_read(OMAP_RTC_ALARM_SECONDS_REG);
+	alm->time.tm_min = rtc_read(OMAP_RTC_ALARM_MINUTES_REG);
+	alm->time.tm_hour = rtc_read(OMAP_RTC_ALARM_HOURS_REG);
+	alm->time.tm_mday = rtc_read(OMAP_RTC_ALARM_DAYS_REG);
+	alm->time.tm_mon = rtc_read(OMAP_RTC_ALARM_MONTHS_REG);
+	alm->time.tm_year = rtc_read(OMAP_RTC_ALARM_YEARS_REG);
+
+	local_irq_enable();
+
+	bcd2tm(&alm->time);
+	alm->pending = !!(rtc_read(OMAP_RTC_INTERRUPTS_REG)
+			& OMAP_RTC_INTERRUPTS_IT_ALARM);
+	alm->enabled = alm->pending && device_may_wakeup(dev);
+
+	return 0;
+}
+
+static int omap_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alm)
+{
+	u8 reg;
+
+	/* Much userspace code uses RTC_ALM_SET, thus "don't care" for
+	 * day/month/year specifies alarms up to 24 hours in the future.
+	 * So we need to handle that ... but let's ignore the "don't care"
+	 * values for hours/minutes/seconds.
+	 */
+	if (alm->time.tm_mday <= 0
+			&& alm->time.tm_mon < 0
+			&& alm->time.tm_year < 0) {
+		struct rtc_time tm;
+		unsigned long now, then;
+
+		omap_rtc_read_time(dev, &tm);
+		rtc_tm_to_time(&tm, &now);
+
+		alm->time.tm_mday = tm.tm_mday;
+		alm->time.tm_mon = tm.tm_mon;
+		alm->time.tm_year = tm.tm_year;
+		rtc_tm_to_time(&alm->time, &then);
+
+		/* sometimes the alarm wraps into tomorrow */
+		if (then < now) {
+			rtc_time_to_tm(now + 24 * 60 * 60, &tm);
+			alm->time.tm_mday = tm.tm_mday;
+			alm->time.tm_mon = tm.tm_mon;
+			alm->time.tm_year = tm.tm_year;
+		}
+	}
+
+	if (tm2bcd(&alm->time) < 0)
+		return -EINVAL;
+
+	local_irq_disable();
+	rtc_wait_not_busy();
+
+	rtc_write(alm->time.tm_year, OMAP_RTC_ALARM_YEARS_REG);
+	rtc_write(alm->time.tm_mon, OMAP_RTC_ALARM_MONTHS_REG);
+	rtc_write(alm->time.tm_mday, OMAP_RTC_ALARM_DAYS_REG);
+	rtc_write(alm->time.tm_hour, OMAP_RTC_ALARM_HOURS_REG);
+	rtc_write(alm->time.tm_min, OMAP_RTC_ALARM_MINUTES_REG);
+	rtc_write(alm->time.tm_sec, OMAP_RTC_ALARM_SECONDS_REG);
+
+	reg = rtc_read(OMAP_RTC_INTERRUPTS_REG);
+	if (alm->enabled)
+		reg |= OMAP_RTC_INTERRUPTS_IT_ALARM;
+	else
+		reg &= ~OMAP_RTC_INTERRUPTS_IT_ALARM;
+	rtc_write(reg, OMAP_RTC_INTERRUPTS_REG);
+
+	local_irq_enable();
+
+	return 0;
+}
+
+static struct rtc_class_ops omap_rtc_ops = {
+	.ioctl		= omap_rtc_ioctl,
+	.read_time	= omap_rtc_read_time,
+	.set_time	= omap_rtc_set_time,
+	.read_alarm	= omap_rtc_read_alarm,
+	.set_alarm	= omap_rtc_set_alarm,
+};
+
+static int omap_rtc_alarm;
+static int omap_rtc_timer;
+
+static int __devinit omap_rtc_probe(struct platform_device *pdev)
+{
+	struct resource		*res, *mem;
+	struct rtc_device	*rtc;
+	u8			reg, new_ctrl;
+
+	omap_rtc_timer = platform_get_irq(pdev, 0);
+	if (omap_rtc_timer <= 0) {
+		pr_debug("%s: no update irq?\n", pdev->name);
+		return -ENOENT;
+	}
+
+	omap_rtc_alarm = platform_get_irq(pdev, 1);
+	if (omap_rtc_alarm <= 0) {
+		pr_debug("%s: no alarm irq?\n", pdev->name);
+		return -ENOENT;
+	}
+
+	/* NOTE:  using static mapping for RTC registers */
+	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+	if (res && res->start != OMAP_RTC_BASE) {
+		pr_debug("%s: RTC registers at %08x, expected %08x\n",
+			pdev->name, (unsigned) res->start, OMAP_RTC_BASE);
+		return -ENOENT;
+	}
+
+	if (res)
+		mem = request_mem_region(res->start,
+				res->end - res->start + 1,
+				pdev->name);
+	else
+		mem = NULL;
+	if (!mem) {
+		pr_debug("%s: RTC registers at %08x are not free\n",
+			pdev->name, OMAP_RTC_BASE);
+		return -EBUSY;
+	}
+
+	rtc = rtc_device_register(pdev->name, &pdev->dev,
+			&omap_rtc_ops, THIS_MODULE);
+	if (IS_ERR(rtc)) {
+		pr_debug("%s: can't register RTC device, err %ld\n",
+			pdev->name, PTR_ERR(rtc));
+		goto fail;
+	}
+	platform_set_drvdata(pdev, rtc);
+	class_set_devdata(&rtc->class_dev, mem);
+
+	/* clear pending irqs, and set 1/second periodic,
+	 * which we'll use instead of update irqs
+	 */
+	rtc_write(0, OMAP_RTC_INTERRUPTS_REG);
+
+	/* clear old status */
+	reg = rtc_read(OMAP_RTC_STATUS_REG);
+	if (reg & (u8) OMAP_RTC_STATUS_POWER_UP) {
+		pr_info("%s: RTC power up reset detected\n",
+			pdev->name);
+		rtc_write(OMAP_RTC_STATUS_POWER_UP, OMAP_RTC_STATUS_REG);
+	}
+	if (reg & (u8) OMAP_RTC_STATUS_ALARM)
+		rtc_write(OMAP_RTC_STATUS_ALARM, OMAP_RTC_STATUS_REG);
+
+	/* handle periodic and alarm irqs */
+	if (request_irq(omap_rtc_timer, rtc_irq, SA_INTERRUPT,
+			rtc->class_dev.class_id, &rtc->class_dev)) {
+		pr_debug("%s: RTC timer interrupt IRQ%d already claimed\n",
+			pdev->name, omap_rtc_timer);
+		goto fail0;
+	}
+	if (request_irq(omap_rtc_alarm, rtc_irq, SA_INTERRUPT,
+			rtc->class_dev.class_id, &rtc->class_dev)) {
+		pr_debug("%s: RTC alarm interrupt IRQ%d already claimed\n",
+			pdev->name, omap_rtc_alarm);
+		goto fail1;
+	}
+
+	/* On boards with split power, RTC_ON_NOFF won't reset the RTC */
+	reg = rtc_read(OMAP_RTC_CTRL_REG);
+	if (reg & (u8) OMAP_RTC_CTRL_STOP)
+		pr_info("%s: already running\n", pdev->name);
+
+	/* force to 24 hour mode */
+	new_ctrl = reg & ~(OMAP_RTC_CTRL_SPLIT|OMAP_RTC_CTRL_AUTO_COMP);
+	new_ctrl |= OMAP_RTC_CTRL_STOP;
+
+	/* BOARD-SPECIFIC CUSTOMIZATION CAN GO HERE:
+	 *
+	 *  - Boards wired so that RTC_WAKE_INT does something, and muxed
+	 *    right (W13_1610_RTC_WAKE_INT is the default after chip reset),
+	 *    should initialize the device wakeup flag appropriately.
+	 *
+	 *  - Boards wired so RTC_ON_nOFF is used as the reset signal,
+	 *    rather than nPWRON_RESET, should forcibly enable split
+	 *    power mode.  (Some chip errata report that RTC_CTRL_SPLIT
+	 *    is write-only, and always reads as zero...)
+	 */
+	device_init_wakeup(&pdev->dev, 0);
+
+	if (new_ctrl & (u8) OMAP_RTC_CTRL_SPLIT)
+		pr_info("%s: split power mode\n", pdev->name);
+
+	if (reg != new_ctrl)
+		rtc_write(new_ctrl, OMAP_RTC_CTRL_REG);
+
+	return 0;
+
+fail1:
+	free_irq(omap_rtc_timer, NULL);
+fail0:
+	rtc_device_unregister(rtc);
+fail:
+	release_resource(mem);
+	return -EIO;
+}
+
+static int __devexit omap_rtc_remove(struct platform_device *pdev)
+{
+	struct rtc_device	*rtc = platform_get_drvdata(pdev);;
+
+	device_init_wakeup(&pdev->dev, 0);
+
+	/* leave rtc running, but disable irqs */
+	rtc_write(0, OMAP_RTC_INTERRUPTS_REG);
+
+	free_irq(omap_rtc_timer, rtc);
+	free_irq(omap_rtc_alarm, rtc);
+
+	release_resource(class_get_devdata(&rtc->class_dev));
+	rtc_device_unregister(rtc);
+	return 0;
+}
+
+#ifdef CONFIG_PM
+
+static struct timespec rtc_delta;
+static u8 irqstat;
+
+static int omap_rtc_suspend(struct platform_device *pdev, pm_message_t state)
+{
+	struct rtc_time rtc_tm;
+	struct timespec time;
+
+	time.tv_nsec = 0;
+	omap_rtc_read_time(NULL, &rtc_tm);
+	rtc_tm_to_time(&rtc_tm, &time.tv_sec);
+
+	save_time_delta(&rtc_delta, &time);
+	irqstat = rtc_read(OMAP_RTC_INTERRUPTS_REG);
+
+	/* FIXME the RTC alarm is not currently acting as a wakeup event
+	 * source, and in fact this enable() call is just saving a flag
+	 * that's never used...
+	 */
+	if (device_may_wakeup(&pdev->dev))
+		enable_irq_wake(omap_rtc_alarm);
+	else
+		rtc_write(0, OMAP_RTC_INTERRUPTS_REG);
+
+	return 0;
+}
+
+static int omap_rtc_resume(struct platform_device *pdev)
+{
+	struct rtc_time rtc_tm;
+	struct timespec time;
+
+	time.tv_nsec = 0;
+	omap_rtc_read_time(NULL, &rtc_tm);
+	rtc_tm_to_time(&rtc_tm, &time.tv_sec);
+
+	restore_time_delta(&rtc_delta, &time);
+	if (device_may_wakeup(&pdev->dev))
+		disable_irq_wake(omap_rtc_alarm);
+	else
+		rtc_write(irqstat, OMAP_RTC_INTERRUPTS_REG);
+	return 0;
+}
+
+#else
+#define omap_rtc_suspend NULL
+#define omap_rtc_resume  NULL
+#endif
+
+static void omap_rtc_shutdown(struct platform_device *pdev)
+{
+	rtc_write(0, OMAP_RTC_INTERRUPTS_REG);
+}
+
+MODULE_ALIAS("omap_rtc");
+static struct platform_driver omap_rtc_driver = {
+	.probe		= omap_rtc_probe,
+	.remove		= __devexit_p(omap_rtc_remove),
+	.suspend	= omap_rtc_suspend,
+	.resume		= omap_rtc_resume,
+	.shutdown	= omap_rtc_shutdown,
+	.driver		= {
+		.name	= "omap_rtc",
+		.owner	= THIS_MODULE,
+	},
+};
+
+static int __init rtc_init(void)
+{
+	return platform_driver_register(&omap_rtc_driver);
+}
+module_init(rtc_init);
+
+static void __exit rtc_exit(void)
+{
+	platform_driver_unregister(&omap_rtc_driver);
+}
+module_exit(rtc_exit);
+
+MODULE_AUTHOR("George G. Davis (and others)");
+MODULE_LICENSE("GPL");

^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: [patch 2.6.19-rc6 2/6] rtc-sa1100 tweaks
  2006-11-20 18:19 ` [patch 2.6.19-rc6 2/6] rtc-sa1100 tweaks David Brownell
@ 2006-11-20 22:48   ` Russell King
  2006-11-21  1:46     ` David Brownell
  0 siblings, 1 reply; 19+ messages in thread
From: Russell King @ 2006-11-20 22:48 UTC (permalink / raw)
  To: David Brownell; +Cc: Alessandro Zummo, Linux Kernel list, rpurdie

On Mon, Nov 20, 2006 at 10:19:53AM -0800, David Brownell wrote:
> Minor updates to rtc-sa1100: report whether the alarm is enabled, remove
> duplicate procfs reporting of that factoid, and stick a FIXME at a place
> where alarms should be enabled (but aren't).

I think you're rather confused about alarms, but you're going to tell
me that it's me who is no doubt, so I'm not sure why I'm bothering to
write this mail.

The pre-rtc-lib user API was as follows:

- ALM_SET - sets the time of the alarm, does not enable or disable
            current alarm settings
- AIE_ON - enables alarm interrupts
- AIE_OFF - disables alarm interrupts
- WKALM_SET - sets the wake up alarm, enables wake up alarm, indicates
              whether wake up alarm is pending

So, alrm->enabled indicates _independently_ of the alarm interrupt whether
this should cause a wakeup, as per the SA1100 driver.  Whether a wakeup
can occur with or without AIE_ON is implementation defined.

Now, if the new RTC library treats this differently, then /it's/ changing
the userspace API and is therefore buggy.

Note also that _lots_ of drivers don't support these new weird
device_set_wakeup_enable() and device_may_wakeup() calls - it seems
that there's an exercise for someone to go through and add a load of
device_set_wakeup_enable() before we go trying to use device_may_wakeup()
on those devices.  I'm not presently sure what they're supposed to do
or achieve.

-- 
Russell King
 Linux kernel    2.6 ARM Linux   - http://www.arm.linux.org.uk/
 maintainer of:  2.6 Serial core

^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: [patch 2.6.19-rc6 6/6] rtc-omap driver
  2006-11-20 18:28 ` [patch 2.6.19-rc6 6/6] rtc-omap driver David Brownell
@ 2006-11-20 23:09   ` Alessandro Zummo
  2006-11-22  1:19   ` Andrew Morton
  1 sibling, 0 replies; 19+ messages in thread
From: Alessandro Zummo @ 2006-11-20 23:09 UTC (permalink / raw)
  To: David Brownell; +Cc: Linux Kernel list, Tony Lindgren, Andrew Morton

On Mon, 20 Nov 2006 10:28:48 -0800
David Brownell <david-b@pacbell.net> wrote:

> This creates a new RTC-framework driver for the RTC/calendar module found
> in various OMAP1 chips.  (OMAP2 and OMAP3 use external RTCs, like those in
> TI's multifunction PM companion chips.)  It's been in the Linux-OMAP tree
> for several months now, and other trees before that, so it's quite stable.
> The most notable issue is that the OMAP IRQ code doesn't yet support the
> RTC IRQ as a wakeup event.  Once that's fixed, a patch will be needed.
> 
> Signed-off-by: David Brownell <dbrownell@users.sourceforge.net>

 Thanks David!

 Acked-by: Alessandro Zummo <a.zummo@towertech.it>

-- 

 Best regards,

 Alessandro Zummo,
  Tower Technologies - Turin, Italy

  http://www.towertech.it


^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: [patch 2.6.19-rc6 1/6] rtc class /proc/driver/rtc update
  2006-11-20 18:17 ` [patch 2.6.19-rc6 1/6] rtc class /proc/driver/rtc update David Brownell
@ 2006-11-20 23:13   ` Alessandro Zummo
  2006-11-21  2:47     ` [Bulk] " David Brownell
  0 siblings, 1 reply; 19+ messages in thread
From: Alessandro Zummo @ 2006-11-20 23:13 UTC (permalink / raw)
  To: David Brownell; +Cc: Linux Kernel list, Russell King

On Mon, 20 Nov 2006 10:17:19 -0800
David Brownell <david-b@pacbell.net> wrote:

> Fix two minor botches in the procfs dumping of RTC alarm status:
> 
>  - Stop confusing "alarm enabled" with "wakeup enabled".
> 
>  - Don't display bogus "irq pending/un-acked" status; those are the rather
>    pointless semantics EFI assigned to this (for a no-IRQs environment).

 I wouldn't change that, the /proc interface to rtc is old
 and should not be used anyhow. Here I'm trying to mimic
 the behaviour of the original one.

 sysfs provides a much better interface
 (once we'll have all the attributes exported, of course :) )

 I don't know if there's any user space tool relying on this.
 If yes, then it should be fixed.

 Any thoughts?

-- 

 Best regards,

 Alessandro Zummo,
  Tower Technologies - Turin, Italy

  http://www.towertech.it


^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: [patch 2.6.19-rc6 2/6] rtc-sa1100 tweaks
  2006-11-20 22:48   ` Russell King
@ 2006-11-21  1:46     ` David Brownell
  0 siblings, 0 replies; 19+ messages in thread
From: David Brownell @ 2006-11-21  1:46 UTC (permalink / raw)
  To: Russell King; +Cc: Alessandro Zummo, Linux Kernel list, rpurdie

On Monday 20 November 2006 2:48 pm, Russell King wrote:
> On Mon, Nov 20, 2006 at 10:19:53AM -0800, David Brownell wrote:
> > Minor updates to rtc-sa1100: report whether the alarm is enabled, remove
> > duplicate procfs reporting of that factoid, and stick a FIXME at a place
> > where alarms should be enabled (but aren't).
> 
> I think you're rather confused about alarms, but you're going to tell
> me that it's me who is no doubt, so I'm not sure why I'm bothering to
> write this mail.

Because you think it likely that more than one person is confused,
and you're 100% certain that will continue unless someone like you
asks a question to help sort it out?  :)


> The pre-rtc-lib user API was as follows:

There were actually several such APIs.  Most tried to act like
the drivers/char/rtc.c driver (/dev/rtc on a PC), but of course
not all RTCs are at heart MC146818 clones.

ARM is as usual a rich source of counter-examples, with varying
capabilities; and it has its own RTC API, now being more or less
replaced by the generic framework.  (I only see Integrator left
in terms of in-tree callers.)

 
> - ALM_SET - sets the time of the alarm, does not enable or disable
>             current alarm settings
> - AIE_ON - enables alarm interrupts
> - AIE_OFF - disables alarm interrupts

Agreed; that's what the PC "rtc.c" did, and most drivers did a good
job of emulating those parts.

One thing that seemed to vary between drivers though:  just what an
"alarm setting" is.  A MC146818 supports only HH:MM:SS alarms, but
any of those fields can be wildcards.  Lots of drivers implemented
that without the wildcard functionality.  Some also handled DD-MON,
or DD-MON-YEAR specifiers.

I believe that for Linux today, that wildcard functionality is in
the "nonportable behavior" category.


> - WKALM_SET - sets the wake up alarm, enables wake up alarm, indicates
>               whether wake up alarm is pending

Sort of.  Semantics varied a lot.

Near as I can tell, WKALM_SET joined us with IA64 and the "efirtc.c"
driver (/dev/efirtc on IA64) which **DOES NOT** implement the other
calls above ... and implemented WKALM_SET by punting directly to EFI
firmware.  Ditto its sibling WKALM_GET.

(The arch/arm/common/rtctime.c code seems to have come about four
years after the efirtc.c driver, and defined *different* semantics
for those calls ...)


Now, I happened to look up what EFI said about the semantics of those
firmware requests.  Summarizing its manual, the two RTC calls are:

   SET ... takes a YYYY-MON-DD HH:MM:SS date and an enable flag,
	which affects "wakeup" (including power on)
   GET ... returns the above, plus a "irq pending" flag, which is
	cleared by calling SET with enable=false (and date=ignored)

The original definition of the WKLAM_* ioctls on Linux was operationally,
with respect to EFI firmware.


> So, alrm->enabled indicates _independently_ of the alarm interrupt whether
> this should cause a wakeup, as per the SA1100 driver.

Not according to the EFI docs.  There is no other way to enable an alarm,
and there is no way to enable an alarm that doesn't do system wakeup.
They're joined at the hip, and there's no such notion as AIE_ON.


>		 Whether a wakeup 
> can occur with or without AIE_ON is implementation defined.

See above ... a program expecting /dev/rtc0 and /dev/efirtc to act
the same would justifiably say it's a bug if WKALM_SET wasn't a
one-stop-shopping solution for setting and activating the alarm.


> Now, if the new RTC library treats this differently, then /it's/ changing
> the userspace API and is therefore buggy.

As shown above, it's not changing WKALM_SET ... at least in the way
you described, since AIE_ON has always been implicit there.  It's
quite possible that folk implementing that call in the ARM framework
were not implementing those original semantics ("therefore buggy").


So it's arguable just how that call should be implemented.  The
original definition seems clear, and that's what I've tried to use;
although that whole "pending" thing does not make sense to me if
there are real IRQs.

It seemed to me that the consensus about how to implement WKLALM_SET
(judging just by votes in drivers/rtc/*.c drivers) is:  (a) it's a
combination of ALM_SET plus either AIE_ON or AIE_OFF, as with EFI;
(b) unlike ALM_SET, it supports alarms more than 24 hours in the
future; and (c) system wakeup, or lack thereof, is orthogonal to the
basic alarm functionality.


> Note also that _lots_ of drivers don't support these new weird
> device_set_wakeup_enable() and device_may_wakeup() calls - it seems
> that there's an exercise for someone to go through and add a load of
> device_set_wakeup_enable()

Wakeup is only relevant for PM-enabled platforms, and there aren't all
that many PM-enabled platforms in the first place.  And among those,
there are darn few that support wakeup events sanely ... with PCs
solidly in the "does not support wakeup" category.

Initialization of wakeup-capable devices should device_init_wakeup().

Probably the best example of how to do that is in the at91rm9200 code,
where many drivers -- CF, MMC, USB host, USB peripheral, RTC, and
more -- are all wakeup-enabled.


> 		before we go trying to use device_may_wakeup() 
> on those devices.  I'm not presently sure what they're supposed to do
> or achieve.

Drivers should use device_may_wakeup() to decide whether they should
enable their wakeup capabilities.  By default the answer is "yes" if
the hardware allows it.  Userspace can change that, and would do so
for two basic reasons:

   (1) It might not work correctly on a given system, even when it
       looks to the kernel as if it should.  Maybe some switch wore
       out; I have a USB mouse that lies about being wakeup-capable.

   (2) Drivers can usually save more power if they don't have to be
       wakeup-capable.  If disabling a few wakeup event sources were
       to save 20 mA battery power, that could be very critical in
       the effort to get another few hours out of a charge.

Plus of course just not wanting a particular thing to be a wakeup
event ... maybe inserting an MMC or CF card isn't such a big deal
on one system as it is on another.

- Dave


^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: [Bulk] Re: [patch 2.6.19-rc6 1/6] rtc class /proc/driver/rtc update
  2006-11-20 23:13   ` Alessandro Zummo
@ 2006-11-21  2:47     ` David Brownell
  2006-11-22 20:37       ` Alessandro Zummo
  0 siblings, 1 reply; 19+ messages in thread
From: David Brownell @ 2006-11-21  2:47 UTC (permalink / raw)
  To: Alessandro Zummo; +Cc: Linux Kernel list, Russell King

On Monday 20 November 2006 3:13 pm, Alessandro Zummo wrote:
> On Mon, 20 Nov 2006 10:17:19 -0800
> David Brownell <david-b@pacbell.net> wrote:
> 
> > Fix two minor botches in the procfs dumping of RTC alarm status:
> > 
> >  - Stop confusing "alarm enabled" with "wakeup enabled".
> > 
> >  - Don't display bogus "irq pending/un-acked" status; those are the rather
> >    pointless semantics EFI assigned to this (for a no-IRQs environment).
> 
>  I wouldn't change that, the /proc interface to rtc is old
>  and should not be used anyhow. Here I'm trying to mimic
>  the behaviour of the original one.

The "original" one never had such fields.  Even the efirtc.c
code (which originated those flags) didn't call them that;
it used "Enabled" not "alrm_enabled", so at least this patch
moves closer to that "original" behavior.


>  sysfs provides a much better interface
>  (once we'll have all the attributes exported, of course :) )

That's an orthgonal issue.  (Though one can argue that the
procfs file should be /proc/driver/rtc0 etc, one per RTC,
rather than /proc/driver/rtc...)


>  I don't know if there's any user space tool relying on this.

There shouldn't be any code parsing /proc/driver/rtc ... if there
is such stuff, it's already got so many variants to cope with that
adding one that actually matches the rest of the system would be
a net simplification.


>  If yes, then it should be fixed.
> 
>  Any thoughts?

The whole RTC framework is still labeled "experimental", and
AFAIK I'm the first person to audit the use of those flags.

Until it's no longer experimental, I have a hard time thinking
that backwards compatibility should prevent fixing such interface
bugs ... interface bugs are normally in the "fix ASAP" category,
since if you delay fixing them the costs grow exponentially.

- Dave

^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: [patch 2.6.19-rc6 6/6] rtc-omap driver
  2006-11-20 18:28 ` [patch 2.6.19-rc6 6/6] rtc-omap driver David Brownell
  2006-11-20 23:09   ` Alessandro Zummo
@ 2006-11-22  1:19   ` Andrew Morton
  2006-11-22  2:15     ` David Brownell
  1 sibling, 1 reply; 19+ messages in thread
From: Andrew Morton @ 2006-11-22  1:19 UTC (permalink / raw)
  To: David Brownell; +Cc: Alessandro Zummo, Linux Kernel list, Tony Lindgren

On Mon, 20 Nov 2006 10:28:48 -0800
David Brownell <david-b@pacbell.net> wrote:

> This creates a new RTC-framework driver for the RTC/calendar module found
> in various OMAP1 chips.  (OMAP2 and OMAP3 use external RTCs, like those in
> TI's multifunction PM companion chips.)  It's been in the Linux-OMAP tree
> for several months now, and other trees before that, so it's quite stable.
> The most notable issue is that the OMAP IRQ code doesn't yet support the
> RTC IRQ as a wakeup event.  Once that's fixed, a patch will be needed.
> 
> ...
>
> +static int omap_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alm)
> +{
> +	u8 reg;
> +
> +	/* Much userspace code uses RTC_ALM_SET, thus "don't care" for
> +	 * day/month/year specifies alarms up to 24 hours in the future.
> +	 * So we need to handle that ... but let's ignore the "don't care"
> +	 * values for hours/minutes/seconds.
> +	 */
> +	if (alm->time.tm_mday <= 0
> +			&& alm->time.tm_mon < 0
> +			&& alm->time.tm_year < 0) {
> +		struct rtc_time tm;
> +		unsigned long now, then;
> +
> +		omap_rtc_read_time(dev, &tm);
> +		rtc_tm_to_time(&tm, &now);
> +
> +		alm->time.tm_mday = tm.tm_mday;
> +		alm->time.tm_mon = tm.tm_mon;
> +		alm->time.tm_year = tm.tm_year;
> +		rtc_tm_to_time(&alm->time, &then);
> +
> +		/* sometimes the alarm wraps into tomorrow */
> +		if (then < now) {

This isn't wraparound-safe.  If you have then=0xffffffff and now=0x00000001.

Perhaps that can't happen.

> +MODULE_AUTHOR("George G. Davis (and others)");

Maybe some additional signoffs would be appropirate?

^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: [patch 2.6.19-rc6 6/6] rtc-omap driver
  2006-11-22  1:19   ` Andrew Morton
@ 2006-11-22  2:15     ` David Brownell
  2006-11-22  2:28       ` Andrew Morton
  2006-11-22 20:34       ` Alessandro Zummo
  0 siblings, 2 replies; 19+ messages in thread
From: David Brownell @ 2006-11-22  2:15 UTC (permalink / raw)
  To: Andrew Morton; +Cc: Alessandro Zummo, Linux Kernel list, Tony Lindgren

On Tuesday 21 November 2006 5:19 pm, Andrew Morton wrote:
> On Mon, 20 Nov 2006 10:28:48 -0800

> > +		/* sometimes the alarm wraps into tomorrow */
> > +		if (then < now) {
> 
> This isn't wraparound-safe.  If you have then=0xffffffff and now=0x00000001.
> 
> Perhaps that can't happen.

Starting in 2037 or whenever, various things will be breaking...

Probably the RTC lib routines should use a time_t, and when that gets
changed to 64 bits then things like this will be fixed automagically.
Right now they use "unsigned long".

I suggest Alessandro handle those issues.


> > +MODULE_AUTHOR("George G. Davis (and others)");
> 
> Maybe some additional signoffs would be appropirate?

I pinged the MontaVista emails from the original driver; maybe
they'll send signoffs.

- Dave
 

^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: [patch 2.6.19-rc6 6/6] rtc-omap driver
  2006-11-22  2:15     ` David Brownell
@ 2006-11-22  2:28       ` Andrew Morton
  2006-11-23  0:09         ` David Brownell
  2006-11-22 20:34       ` Alessandro Zummo
  1 sibling, 1 reply; 19+ messages in thread
From: Andrew Morton @ 2006-11-22  2:28 UTC (permalink / raw)
  To: David Brownell; +Cc: Alessandro Zummo, Linux Kernel list, Tony Lindgren

On Tue, 21 Nov 2006 18:15:42 -0800
David Brownell <david-b@pacbell.net> wrote:

> On Tuesday 21 November 2006 5:19 pm, Andrew Morton wrote:
> > On Mon, 20 Nov 2006 10:28:48 -0800
> 
> > > +		/* sometimes the alarm wraps into tomorrow */
> > > +		if (then < now) {
> > 
> > This isn't wraparound-safe.  If you have then=0xffffffff and now=0x00000001.
> > 
> > Perhaps that can't happen.
> 
> Starting in 2037 or whenever, various things will be breaking...
> 
> Probably the RTC lib routines should use a time_t, and when that gets
> changed to 64 bits then things like this will be fixed automagically.
> Right now they use "unsigned long".
> 
> I suggest Alessandro handle those issues.
> 

We could simply (ab)use timer_after() here.

> 
> > > +MODULE_AUTHOR("George G. Davis (and others)");
> > 
> > Maybe some additional signoffs would be appropirate?
> 
> I pinged the MontaVista emails from the original driver; maybe
> they'll send signoffs.
> 

OK.  Such signoffs are certainly not a DCO _requirement_.  If the MV guys
are asleep, no big deal - we trust david-b's assertion.



^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: [patch 2.6.19-rc6 6/6] rtc-omap driver
  2006-11-22  2:15     ` David Brownell
  2006-11-22  2:28       ` Andrew Morton
@ 2006-11-22 20:34       ` Alessandro Zummo
  1 sibling, 0 replies; 19+ messages in thread
From: Alessandro Zummo @ 2006-11-22 20:34 UTC (permalink / raw)
  To: David Brownell; +Cc: Andrew Morton, Linux Kernel list, Tony Lindgren

On Tue, 21 Nov 2006 18:15:42 -0800
David Brownell <david-b@pacbell.net> wrote:

> On Tuesday 21 November 2006 5:19 pm, Andrew Morton wrote:
> > On Mon, 20 Nov 2006 10:28:48 -0800
> 
> > > +		/* sometimes the alarm wraps into tomorrow */
> > > +		if (then < now) {
> > 
> > This isn't wraparound-safe.  If you have then=0xffffffff and now=0x00000001.
> > 
> > Perhaps that can't happen.
> 
> Starting in 2037 or whenever, various things will be breaking...
> 
> Probably the RTC lib routines should use a time_t, and when that gets
> changed to 64 bits then things like this will be fixed automagically.
> Right now they use "unsigned long".
> 
> I suggest Alessandro handle those issues.

 I'll make a note for switching to time_t before
 2037 :)
  


-- 

 Best regards,

 Alessandro Zummo,
  Tower Technologies - Turin, Italy

  http://www.towertech.it


^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: [Bulk] Re: [patch 2.6.19-rc6 1/6] rtc class /proc/driver/rtc update
  2006-11-21  2:47     ` [Bulk] " David Brownell
@ 2006-11-22 20:37       ` Alessandro Zummo
  2006-11-23  0:39         ` David Brownell
  0 siblings, 1 reply; 19+ messages in thread
From: Alessandro Zummo @ 2006-11-22 20:37 UTC (permalink / raw)
  To: David Brownell; +Cc: Linux Kernel list, Russell King

On Mon, 20 Nov 2006 18:47:57 -0800
David Brownell <david-b@pacbell.net> wrote:

> >  I wouldn't change that, the /proc interface to rtc is old
> >  and should not be used anyhow. Here I'm trying to mimic
> >  the behaviour of the original one.
> 
> The "original" one never had such fields.  Even the efirtc.c
> code (which originated those flags) didn't call them that;
> it used "Enabled" not "alrm_enabled", so at least this patch
> moves closer to that "original" behavior.

 [..]

> >  I don't know if there's any user space tool relying on this.
> 
> There shouldn't be any code parsing /proc/driver/rtc ... if there
> is such stuff, it's already got so many variants to cope with that
> adding one that actually matches the rest of the system would be
> a net simplification.

> The whole RTC framework is still labeled "experimental", and
> AFAIK I'm the first person to audit the use of those flags.
> 
> Until it's no longer experimental, I have a hard time thinking
> that backwards compatibility should prevent fixing such interface
> bugs ... interface bugs are normally in the "fix ASAP" category,
> since if you delay fixing them the costs grow exponentially.

 given the experimental status, I'm inclined to remove the /proc
 driver right now.

 Any objection?

-- 

 Best regards,

 Alessandro Zummo,
  Tower Technologies - Turin, Italy

  http://www.towertech.it


^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: [patch 2.6.19-rc6 6/6] rtc-omap driver
  2006-11-22  2:28       ` Andrew Morton
@ 2006-11-23  0:09         ` David Brownell
  0 siblings, 0 replies; 19+ messages in thread
From: David Brownell @ 2006-11-23  0:09 UTC (permalink / raw)
  To: Andrew Morton; +Cc: Alessandro Zummo, Linux Kernel list, Tony Lindgren

On Tuesday 21 November 2006 6:28 pm, Andrew Morton wrote:

> > Starting in 2037 or whenever, various things will be breaking...
> > 
> > Probably the RTC lib routines should use a time_t, and when that gets
> > changed to 64 bits then things like this will be fixed automagically.
> > Right now they use "unsigned long".
> > 
> > I suggest Alessandro handle those issues.
> 
> We could simply (ab)use timer_after() here.

We could indeed.  But things will still break badly in 2037,
and the timer_after() thing is clearly an incomplete fix.

- Dave

^ permalink raw reply	[flat|nested] 19+ messages in thread

* Re: [patch 2.6.19-rc6 1/6] rtc class /proc/driver/rtc update
  2006-11-22 20:37       ` Alessandro Zummo
@ 2006-11-23  0:39         ` David Brownell
  0 siblings, 0 replies; 19+ messages in thread
From: David Brownell @ 2006-11-23  0:39 UTC (permalink / raw)
  To: Alessandro Zummo; +Cc: Linux Kernel list, Russell King

On Wednesday 22 November 2006 12:37 pm, Alessandro Zummo wrote:
> 
>  given the experimental status, I'm inclined to remove the /proc
>  driver right now.

I actually prefer the /proc/driver/rtc* file to the sysfs stuff.
Even though some people would call that "politically incorrect".

- Dave

^ permalink raw reply	[flat|nested] 19+ messages in thread

end of thread, other threads:[~2006-11-23  0:41 UTC | newest]

Thread overview: 19+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2006-11-20 18:14 [patch 2.6.19-rc6 0/6] more rtc framework/driver updates David Brownell
2006-11-20 18:17 ` [patch 2.6.19-rc6 1/6] rtc class /proc/driver/rtc update David Brownell
2006-11-20 23:13   ` Alessandro Zummo
2006-11-21  2:47     ` [Bulk] " David Brownell
2006-11-22 20:37       ` Alessandro Zummo
2006-11-23  0:39         ` David Brownell
2006-11-20 18:19 ` [patch 2.6.19-rc6 2/6] rtc-sa1100 tweaks David Brownell
2006-11-20 22:48   ` Russell King
2006-11-21  1:46     ` David Brownell
2006-11-20 18:22 ` [patch 2.6.19-rc6 3/6] X86_PC optionally creates rtc_cmos platform device David Brownell
2006-11-20 18:27 ` [patch 2.6.19-rc6 5/6] rtc-cmos driver David Brownell
2006-11-20 18:27 ` [patch 2.6.19-rc6 4/6] ACPI exports RTC extensions through platform_data David Brownell
2006-11-20 18:28 ` [patch 2.6.19-rc6 6/6] rtc-omap driver David Brownell
2006-11-20 23:09   ` Alessandro Zummo
2006-11-22  1:19   ` Andrew Morton
2006-11-22  2:15     ` David Brownell
2006-11-22  2:28       ` Andrew Morton
2006-11-23  0:09         ` David Brownell
2006-11-22 20:34       ` Alessandro Zummo

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox