---
 CREDITS                                                    |    5 
 MAINTAINERS                                                |    6 
 arch/arm/Kconfig                                           |    3 
 arch/arm/common/rtctime.c                                  |  108 --
 arch/arm/mach-integrator/time.c                            |   16 
 arch/arm/mach-pxa/generic.c                                |    6 
 arch/arm/mach-sa1100/generic.c                             |    6 
 arch/mips/ddb5xxx/common/rtc_ds1386.c                      |    4 
 arch/mips/dec/time.c                                       |    4 
 arch/mips/ite-boards/generic/time.c                        |    4 
 arch/mips/jmr3927/common/rtc_ds1742.c                      |    4 
 arch/mips/kernel/time.c                                    |   22 
 arch/mips/lasat/setup.c                                    |    4 
 arch/mips/mips-boards/atlas/atlas_setup.c                  |    2 
 arch/mips/mips-boards/malta/malta_setup.c                  |    2 
 arch/mips/momentum/jaguar_atx/setup.c                      |    4 
 arch/mips/momentum/ocelot_3/setup.c                        |    4 
 arch/mips/momentum/ocelot_c/setup.c                        |    4 
 arch/mips/pmc-sierra/yosemite/setup.c                      |    4 
 arch/mips/sgi-ip22/ip22-time.c                             |    4 
 arch/mips/sgi-ip32/ip32-setup.c                            |    4 
 arch/mips/sibyte/swarm/setup.c                             |    8 
 arch/mips/sni/setup.c                                      |    4 
 arch/mips/tx4927/toshiba_rbtx4927/toshiba_rbtx4927_setup.c |    4 
 arch/mips/tx4938/common/rtc_rx5c348.c                      |    4 
 drivers/Kconfig                                            |    2 
 drivers/Makefile                                           |    1 
 drivers/char/Kconfig                                       |    2 
 drivers/i2c/chips/Kconfig                                  |   18 
 drivers/i2c/chips/Makefile                                 |    2 
 drivers/i2c/chips/rtc8564.c                                |  385 -------
 drivers/i2c/chips/rtc8564.h                                |   78 -
 drivers/i2c/chips/x1205.c                                  |  698 -------------
 drivers/rtc/Kconfig                                        |  156 ++
 drivers/rtc/Makefile                                       |   20 
 drivers/rtc/class.c                                        |  145 ++
 drivers/rtc/hctosys.c                                      |   69 +
 drivers/rtc/interface.c                                    |  277 +++++
 drivers/rtc/rtc-dev.c                                      |  382 +++++++
 drivers/rtc/rtc-ds1672.c                                   |  233 ++++
 drivers/rtc/rtc-ep93xx.c                                   |  163 +++
 drivers/rtc/rtc-lib.c                                      |   99 +
 drivers/rtc/rtc-pcf8563.c                                  |  355 ++++++
 drivers/rtc/rtc-proc.c                                     |  162 +++
 drivers/rtc/rtc-rs5c372.c                                  |  295 +++++
 drivers/rtc/rtc-sa1100.c                                   |  392 +++++++
 drivers/rtc/rtc-sysfs.c                                    |  124 ++
 drivers/rtc/rtc-test.c                                     |  205 +++
 drivers/rtc/rtc-x1205.c                                    |  619 +++++++++++
 include/asm-arm/rtc.h                                      |    3 
 include/asm-mips/time.h                                    |   12 
 include/linux/rtc.h                                        |   92 +
 include/linux/x1205.h                                      |   31 
 53 files changed, 3888 insertions(+), 1372 deletions(-)

--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ linux-ixp4xx/drivers/rtc/rtc-lib.c	2006-03-08 01:59:26.000000000 +0100
@@ -0,0 +1,99 @@
+/*
+ * rtc and date/time utility functions
+ *
+ * Copyright (C) 2005-06 Tower Technologies
+ * Author: Alessandro Zummo <a.zummo@towertech.it>
+ *
+ * based on arch/arm/common/rtctime.c and other bits
+ *
+ * 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; version 2 of the License.
+*/
+
+#include <linux/module.h>
+#include <linux/rtc.h>
+
+static const unsigned char rtc_days_in_month[] = {
+	31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
+};
+
+#define LEAPS_THRU_END_OF(y) ((y)/4 - (y)/100 + (y)/400)
+#define LEAP_YEAR(year) ((!(year % 4) && (year % 100)) || !(year % 400))
+
+int rtc_month_days(unsigned int month, unsigned int year)
+{
+	return rtc_days_in_month[month] + (LEAP_YEAR(year) && month == 1);
+}
+EXPORT_SYMBOL(rtc_month_days);
+
+/*
+ * Convert seconds since 01-01-1970 00:00:00 to Gregorian date.
+ */
+void rtc_time_to_tm(unsigned long time, struct rtc_time *tm)
+{
+	register int days, month, year;
+
+	days = time / 86400;
+	time -= days * 86400;
+
+	/* day of the week, 1970-01-01 was a Thursday */
+	tm->tm_wday = (days + 4) % 7;
+
+	year = 1970 + days / 365;
+	days -= (year - 1970) * 365
+		+ LEAPS_THRU_END_OF(year - 1)
+		- LEAPS_THRU_END_OF(1970 - 1);
+	if (days < 0) {
+		year -= 1;
+		days += 365 + LEAP_YEAR(year);
+	}
+	tm->tm_year = year - 1900;
+	tm->tm_yday = days + 1;
+
+	for (month = 0; month < 11; month++) {
+		int newdays;
+
+		newdays = days - rtc_month_days(month, year);
+		if (newdays < 0)
+			break;
+		days = newdays;
+	}
+	tm->tm_mon = month;
+	tm->tm_mday = days + 1;
+
+	tm->tm_hour = time / 3600;
+	time -= tm->tm_hour * 3600;
+	tm->tm_min = time / 60;
+	tm->tm_sec = time - tm->tm_min * 60;
+}
+EXPORT_SYMBOL(rtc_time_to_tm);
+
+/*
+ * Does the rtc_time represent a valid date/time?
+ */
+int rtc_valid_tm(struct rtc_time *tm)
+{
+	if (tm->tm_year < 70
+		|| tm->tm_mon >= 12
+		|| tm->tm_mday < 1
+		|| tm->tm_mday > rtc_month_days(tm->tm_mon, tm->tm_year + 1900)
+		|| tm->tm_hour >= 24
+		|| tm->tm_min >= 60
+		|| tm->tm_sec >= 60)
+		return -EINVAL;
+
+	return 0;
+}
+EXPORT_SYMBOL(rtc_valid_tm);
+
+/*
+ * Convert Gregorian date to seconds since 01-01-1970 00:00:00.
+ */
+int rtc_tm_to_time(struct rtc_time *tm, unsigned long *time)
+{
+	*time = mktime(tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday,
+			tm->tm_hour, tm->tm_min, tm->tm_sec);
+	return 0;
+}
+EXPORT_SYMBOL(rtc_tm_to_time);
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ linux-ixp4xx/drivers/rtc/Makefile	2006-03-08 01:59:26.000000000 +0100
@@ -0,0 +1,20 @@
+#
+# Makefile for RTC class/drivers.
+#
+
+obj-$(CONFIG_RTC_LIB)		+= rtc-lib.o
+obj-$(CONFIG_RTC_HCTOSYS)	+= hctosys.o
+obj-$(CONFIG_RTC_CLASS)		+= rtc-core.o
+rtc-core-y			:= class.o interface.o
+
+obj-$(CONFIG_RTC_INTF_SYSFS)	+= rtc-sysfs.o
+obj-$(CONFIG_RTC_INTF_PROC)	+= rtc-proc.o
+obj-$(CONFIG_RTC_INTF_DEV)	+= rtc-dev.o
+
+obj-$(CONFIG_RTC_DRV_X1205)	+= rtc-x1205.o
+obj-$(CONFIG_RTC_DRV_TEST)	+= rtc-test.o
+obj-$(CONFIG_RTC_DRV_DS1672)	+= rtc-ds1672.o
+obj-$(CONFIG_RTC_DRV_PCF8563)	+= rtc-pcf8563.o
+obj-$(CONFIG_RTC_DRV_RS5C372)	+= rtc-rs5c372.o
+obj-$(CONFIG_RTC_DRV_EP93XX)	+= rtc-ep93xx.o
+obj-$(CONFIG_RTC_DRV_SA1100)	+= rtc-sa1100.o
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ linux-ixp4xx/drivers/rtc/Kconfig	2006-03-08 01:59:26.000000000 +0100
@@ -0,0 +1,156 @@
+\#
+# RTC class/drivers configuration
+#
+
+menu "Real Time Clock"
+
+config RTC_LIB
+	bool
+
+config RTC_CLASS
+	tristate "RTC class"
+	depends on EXPERIMENTAL
+	default n
+	select RTC_LIB
+	help
+	  Generic RTC class support. If you say yes here, you will
+ 	  be allowed to plug one or more RTCs to your system. You will
+	  probably want to enable one of more of the interfaces below.
+
+	  This driver can also be built as a module. If so, the module
+	  will be called rtc-class.
+
+config RTC_HCTOSYS
+	bool "Set system time from RTC on startup"
+	depends on RTC_CLASS = y
+	default y
+	help
+	  If you say yes here, the system time will be set using
+	  the value read from the specified RTC device. This is useful
+	  in order to avoid unnecessary fschk runs.
+
+config RTC_HCTOSYS_DEVICE
+	string "The RTC to read the time from"
+	depends on RTC_HCTOSYS = y
+	default "rtc0"
+	help
+	  The RTC device that will be used as the source for
+	  the system time, usually rtc0.
+
+comment "RTC interfaces"
+	depends on RTC_CLASS
+
+config RTC_INTF_SYSFS
+	tristate "sysfs"
+	depends on RTC_CLASS && SYSFS
+	default RTC_CLASS
+	help
+	  Say yes here if you want to use your RTC using the sysfs
+	  interface, /sys/class/rtc/rtcX .
+
+	  This driver can also be built as a module. If so, the module
+	  will be called rtc-sysfs.
+
+config RTC_INTF_PROC
+	tristate "proc"
+	depends on RTC_CLASS && PROC_FS
+	default RTC_CLASS
+	help
+	  Say yes here if you want to use your RTC using the proc
+	  interface, /proc/driver/rtc .
+
+	  This driver can also be built as a module. If so, the module
+	  will be called rtc-proc.
+
+config RTC_INTF_DEV
+	tristate "dev"
+	depends on RTC_CLASS
+	default RTC_CLASS
+	help
+	  Say yes here if you want to use your RTC using the dev
+	  interface, /dev/rtc .
+
+	  This driver can also be built as a module. If so, the module
+	  will be called rtc-dev.
+
+comment "RTC drivers"
+	depends on RTC_CLASS
+
+config RTC_DRV_X1205
+	tristate "Xicor/Intersil X1205 RTC chip"
+	depends on RTC_CLASS && I2C
+	help
+	  If you say yes here you get support for the
+	  Xicor/Intersil X1205 RTC chip.
+
+	  This driver can also be built as a module. If so, the module
+	  will be called rtc-x1205.
+
+config RTC_DRV_DS1672
+	tristate "Dallas/Maxim DS1672"
+	depends on RTC_CLASS && I2C
+	help
+	  If you say yes here you get support for the
+	  Dallas/Maxim DS1672 timekeeping chip.
+
+	  This driver can also be built as a module. If so, the module
+	  will be called rtc-ds1672.
+
+config RTC_DRV_PCF8563
+	tristate "Philips PCF8563/Epson RTC8564"
+	depends on RTC_CLASS && I2C
+	help
+	  If you say yes here you get support for the
+	  Philips PCF8563 RTC chip. The Epson RTC8564
+	  should work as well.
+
+	  This driver can also be built as a module. If so, the module
+	  will be called rtc-pcf8563.
+
+config RTC_DRV_RS5C372
+	tristate "Ricoh RS5C372A/B"
+	depends on RTC_CLASS && I2C
+	help
+	  If you say yes here you get support for the
+	  Ricoh RS5C372A and RS5C372B RTC chips.
+
+	  This driver can also be built as a module. If so, the module
+	  will be called rtc-rs5c372.
+
+config RTC_DRV_EP93XX
+	tristate "Cirrus Logic EP93XX"
+	depends on RTC_CLASS && ARCH_EP93XX
+	help
+	  If you say yes here you get support for the
+	  RTC embedded in the Cirrus Logic EP93XX processors.
+
+	  This driver can also be built as a module. If so, the module
+	  will be called rtc-ep93xx.
+
+
+config RTC_DRV_SA1100
+	bool "SA11x0/PXA2xx RTC support"
+	depends on ARCH_SA1100 || ARCH_PXA
+	help
+	  If you say Y here you will get access to the real time clock
+	  built into your SA11x0 or PXA2xx CPU.
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called rtc-sa1100.
+
+config RTC_DRV_TEST
+	tristate "Test driver/device"
+	depends on RTC_CLASS
+	help
+	  If you say yes here you get support for the
+	  RTC test driver. It's a software RTC which can be
+	  used to test the RTC subsystem APIs. It gets
+	  the time from the system clock.
+	  You want this driver only if you are doing development
+	  on the RTC subsystem. Please read the source code
+	  for further details.
+
+	  This driver can also be built as a module. If so, the module
+	  will be called rtc-test.
+
+endmenu
--- linux-ixp4xx.orig/drivers/Kconfig	2006-03-08 01:59:18.000000000 +0100
+++ linux-ixp4xx/drivers/Kconfig	2006-03-08 01:59:26.000000000 +0100
@@ -72,4 +72,6 @@ source "drivers/sn/Kconfig"
 
 source "drivers/edac/Kconfig"
 
+source "drivers/rtc/Kconfig"
+
 endmenu
--- linux-ixp4xx.orig/drivers/Makefile	2006-03-08 01:59:18.000000000 +0100
+++ linux-ixp4xx/drivers/Makefile	2006-03-08 01:59:26.000000000 +0100
@@ -56,6 +56,7 @@ obj-$(CONFIG_USB_GADGET)	+= usb/gadget/
 obj-$(CONFIG_GAMEPORT)		+= input/gameport/
 obj-$(CONFIG_INPUT)		+= input/
 obj-$(CONFIG_I2O)		+= message/
+obj-$(CONFIG_RTC_LIB)		+= rtc/
 obj-$(CONFIG_I2C)		+= i2c/
 obj-$(CONFIG_W1)		+= w1/
 obj-$(CONFIG_HWMON)		+= hwmon/
--- linux-ixp4xx.orig/include/linux/rtc.h	2006-03-08 01:59:09.000000000 +0100
+++ linux-ixp4xx/include/linux/rtc.h	2006-03-08 01:59:26.000000000 +0100
@@ -93,8 +93,100 @@ struct rtc_pll_info {
 #define RTC_PLL_GET	_IOR('p', 0x11, struct rtc_pll_info)  /* Get PLL correction */
 #define RTC_PLL_SET	_IOW('p', 0x12, struct rtc_pll_info)  /* Set PLL correction */
 
+/* interrupt flags */
+#define RTC_IRQF 0x80 /* any of the following is active */
+#define RTC_PF 0x40
+#define RTC_AF 0x20
+#define RTC_UF 0x10
+
 #ifdef __KERNEL__
 
+extern int rtc_month_days(unsigned int month, unsigned int year);
+extern int rtc_valid_tm(struct rtc_time *tm);
+extern int rtc_tm_to_time(struct rtc_time *tm, unsigned long *time);
+extern void rtc_time_to_tm(unsigned long time, struct rtc_time *tm);
+
+#include <linux/device.h>
+#include <linux/seq_file.h>
+#include <linux/cdev.h>
+#include <linux/poll.h>
+#include <linux/mutex.h>
+
+extern struct class *rtc_class;
+
+struct rtc_class_ops {
+	int (*open)(struct device *);
+	void (*release)(struct device *);
+	int (*ioctl)(struct device *, unsigned int, unsigned long);
+	int (*read_time)(struct device *, struct rtc_time *);
+	int (*set_time)(struct device *, struct rtc_time *);
+	int (*read_alarm)(struct device *, struct rtc_wkalrm *);
+	int (*set_alarm)(struct device *, struct rtc_wkalrm *);
+	int (*proc)(struct device *, struct seq_file *);
+	int (*set_mmss)(struct device *, unsigned long secs);
+	int (*irq_set_state)(struct device *, int enabled);
+	int (*irq_set_freq)(struct device *, int freq);
+	int (*read_callback)(struct device *, int data);
+};
+
+#define RTC_DEVICE_NAME_SIZE 20
+struct rtc_task;
+
+struct rtc_device
+{
+	struct class_device class_dev;
+	struct module *owner;
+
+	int id;
+	char name[RTC_DEVICE_NAME_SIZE];
+
+	struct rtc_class_ops *ops;
+	struct mutex ops_lock;
+
+	struct class_device *rtc_dev;
+	struct cdev char_dev;
+	struct mutex char_lock;
+
+	unsigned long irq_data;
+	spinlock_t irq_lock;
+	wait_queue_head_t irq_queue;
+	struct fasync_struct *async_queue;
+
+	struct rtc_task *irq_task;
+	spinlock_t irq_task_lock;
+	int irq_freq;
+};
+#define to_rtc_device(d) container_of(d, struct rtc_device, class_dev)
+
+extern struct rtc_device *rtc_device_register(const char *name,
+					struct device *dev,
+					struct rtc_class_ops *ops,
+					struct module *owner);
+extern void rtc_device_unregister(struct rtc_device *rdev);
+extern int rtc_interface_register(struct class_interface *intf);
+
+extern int rtc_read_time(struct class_device *class_dev, struct rtc_time *tm);
+extern int rtc_set_time(struct class_device *class_dev, struct rtc_time *tm);
+extern int rtc_set_mmss(struct class_device *class_dev, unsigned long secs);
+extern int rtc_read_alarm(struct class_device *class_dev,
+			struct rtc_wkalrm *alrm);
+extern int rtc_set_alarm(struct class_device *class_dev,
+				struct rtc_wkalrm *alrm);
+extern void rtc_update_irq(struct class_device *class_dev,
+			unsigned long num, unsigned long events);
+
+extern struct class_device *rtc_class_open(char *name);
+extern void rtc_class_close(struct class_device *class_dev);
+
+extern int rtc_irq_register(struct class_device *class_dev,
+				struct rtc_task *task);
+extern void rtc_irq_unregister(struct class_device *class_dev,
+				struct rtc_task *task);
+extern int rtc_irq_set_state(struct class_device *class_dev,
+				struct rtc_task *task, int enabled);
+extern int rtc_irq_set_freq(struct class_device *class_dev,
+				struct rtc_task *task, int freq);
+
 typedef struct rtc_task {
 	void (*func)(void *private_data);
 	void *private_data;
--- linux-ixp4xx.orig/arch/arm/common/rtctime.c	2006-03-08 01:59:09.000000000 +0100
+++ linux-ixp4xx/arch/arm/common/rtctime.c	2006-03-08 01:59:26.000000000 +0100
@@ -20,6 +20,7 @@
 #include <linux/capability.h>
 #include <linux/device.h>
 #include <linux/mutex.h>
+#include <linux/rtc.h>
 
 #include <asm/rtc.h>
 #include <asm/semaphore.h>
@@ -42,89 +43,6 @@ static struct rtc_ops *rtc_ops;
 
 #define rtc_epoch 1900UL
 
-static const unsigned char days_in_month[] = {
-	31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
-};
-
-#define LEAPS_THRU_END_OF(y) ((y)/4 - (y)/100 + (y)/400)
-#define LEAP_YEAR(year) ((!(year % 4) && (year % 100)) || !(year % 400))
-
-static int month_days(unsigned int month, unsigned int year)
-{
-	return days_in_month[month] + (LEAP_YEAR(year) && month == 1);
-}
-
-/*
- * Convert seconds since 01-01-1970 00:00:00 to Gregorian date.
- */
-void rtc_time_to_tm(unsigned long time, struct rtc_time *tm)
-{
-	int days, month, year;
-
-	days = time / 86400;
-	time -= days * 86400;
-
-	tm->tm_wday = (days + 4) % 7;
-
-	year = 1970 + days / 365;
-	days -= (year - 1970) * 365
-	        + LEAPS_THRU_END_OF(year - 1)
-	        - LEAPS_THRU_END_OF(1970 - 1);
-	if (days < 0) {
-		year -= 1;
-		days += 365 + LEAP_YEAR(year);
-	}
-	tm->tm_year = year - 1900;
-	tm->tm_yday = days + 1;
-
-	for (month = 0; month < 11; month++) {
-		int newdays;
-
-		newdays = days - month_days(month, year);
-		if (newdays < 0)
-			break;
-		days = newdays;
-	}
-	tm->tm_mon = month;
-	tm->tm_mday = days + 1;
-
-	tm->tm_hour = time / 3600;
-	time -= tm->tm_hour * 3600;
-	tm->tm_min = time / 60;
-	tm->tm_sec = time - tm->tm_min * 60;
-}
-EXPORT_SYMBOL(rtc_time_to_tm);
-
-/*
- * Does the rtc_time represent a valid date/time?
- */
-int rtc_valid_tm(struct rtc_time *tm)
-{
-	if (tm->tm_year < 70 ||
-	    tm->tm_mon >= 12 ||
-	    tm->tm_mday < 1 ||
-	    tm->tm_mday > month_days(tm->tm_mon, tm->tm_year + 1900) ||
-	    tm->tm_hour >= 24 ||
-	    tm->tm_min >= 60 ||
-	    tm->tm_sec >= 60)
-		return -EINVAL;
-
-	return 0;
-}
-EXPORT_SYMBOL(rtc_valid_tm);
-
-/*
- * Convert Gregorian date to seconds since 01-01-1970 00:00:00.
- */
-int rtc_tm_to_time(struct rtc_time *tm, unsigned long *time)
-{
-	*time = mktime(tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday,
-		       tm->tm_hour, tm->tm_min, tm->tm_sec);
-
-	return 0;
-}
-EXPORT_SYMBOL(rtc_tm_to_time);
-
 /*
  * Calculate the next alarm time given the requested alarm time mask
  * and the current time.
@@ -151,13 +69,13 @@ void rtc_next_alarm_time(struct rtc_time
 	}
 }
 
-static inline int rtc_read_time(struct rtc_ops *ops, struct rtc_time *tm)
+static inline int rtc_arm_read_time(struct rtc_ops *ops, struct rtc_time *tm)
 {
 	memset(tm, 0, sizeof(struct rtc_time));
 	return ops->read_time(tm);
 }
 
-static inline int rtc_set_time(struct rtc_ops *ops, struct rtc_time *tm)
+static inline int rtc_arm_set_time(struct rtc_ops *ops, struct rtc_time *tm)
 {
 	int ret;
 
@@ -168,7 +86,7 @@ static inline int rtc_set_time(struct rt
 	return ret;
 }
 
-static inline int rtc_read_alarm(struct rtc_ops *ops, struct rtc_wkalrm *alrm)
+static inline int rtc_arm_read_alarm(struct rtc_ops *ops, struct rtc_wkalrm *alrm)
 {
 	int ret = -EINVAL;
 	if (ops->read_alarm) {
@@ -178,7 +96,7 @@ static inline int rtc_read_alarm(struct 
 	return ret;
 }
 
-static inline int rtc_set_alarm(struct rtc_ops *ops, struct rtc_wkalrm *alrm)
+static inline int rtc_arm_set_alarm(struct rtc_ops *ops, struct rtc_wkalrm *alrm)
 {
 	int ret = -EINVAL;
 	if (ops->set_alarm)
@@ -266,7 +184,7 @@ static int rtc_ioctl(struct inode *inode
 
 	switch (cmd) {
 	case RTC_ALM_READ:
-		ret = rtc_read_alarm(ops, &alrm);
+		ret = rtc_arm_read_alarm(ops, &alrm);
 		if (ret)
 			break;
 		ret = copy_to_user(uarg, &alrm.time, sizeof(tm));
@@ -288,11 +206,11 @@ static int rtc_ioctl(struct inode *inode
 		alrm.time.tm_wday = -1;
 		alrm.time.tm_yday = -1;
 		alrm.time.tm_isdst = -1;
-		ret = rtc_set_alarm(ops, &alrm);
+		ret = rtc_arm_set_alarm(ops, &alrm);
 		break;
 
 	case RTC_RD_TIME:
-		ret = rtc_read_time(ops, &tm);
+		ret = rtc_arm_read_time(ops, &tm);
 		if (ret)
 			break;
 		ret = copy_to_user(uarg, &tm, sizeof(tm));
@@ -310,7 +228,7 @@ static int rtc_ioctl(struct inode *inode
 			ret = -EFAULT;
 			break;
 		}
-		ret = rtc_set_time(ops, &tm);
+		ret = rtc_arm_set_time(ops, &tm);
 		break;
 
 	case RTC_EPOCH_SET:
@@ -341,11 +259,11 @@ static int rtc_ioctl(struct inode *inode
 			ret = -EFAULT;
 			break;
 		}
-		ret = rtc_set_alarm(ops, &alrm);
+		ret = rtc_arm_set_alarm(ops, &alrm);
 		break;
 
 	case RTC_WKALM_RD:
-		ret = rtc_read_alarm(ops, &alrm);
+		ret = rtc_arm_read_alarm(ops, &alrm);
 		if (ret)
 			break;
 		ret = copy_to_user(uarg, &alrm, sizeof(alrm));
@@ -435,7 +353,7 @@ static int rtc_read_proc(char *page, cha
 	struct rtc_time tm;
 	char *p = page;
 
-	if (rtc_read_time(ops, &tm) == 0) {
+	if (rtc_arm_read_time(ops, &tm) == 0) {
 		p += sprintf(p,
 			"rtc_time\t: %02d:%02d:%02d\n"
 			"rtc_date\t: %04d-%02d-%02d\n"
@@ -445,7 +363,7 @@ static int rtc_read_proc(char *page, cha
 			rtc_epoch);
 	}
 
-	if (rtc_read_alarm(ops, &alrm) == 0) {
+	if (rtc_arm_read_alarm(ops, &alrm) == 0) {
 		p += sprintf(p, "alrm_time\t: ");
 		if ((unsigned int)alrm.time.tm_hour <= 24)
 			p += sprintf(p, "%02d:", alrm.time.tm_hour);
--- linux-ixp4xx.orig/include/asm-arm/rtc.h	2006-03-08 01:59:09.000000000 +0100
+++ linux-ixp4xx/include/asm-arm/rtc.h	2006-03-08 01:59:26.000000000 +0100
@@ -25,9 +25,6 @@ struct rtc_ops {
 	int		(*proc)(char *buf);
 };
 
-void rtc_time_to_tm(unsigned long, struct rtc_time *);
-int rtc_tm_to_time(struct rtc_time *, unsigned long *);
-int rtc_valid_tm(struct rtc_time *);
 void rtc_next_alarm_time(struct rtc_time *, struct rtc_time *, struct rtc_time *);
 void rtc_update(unsigned long, unsigned long);
 int register_rtc(struct rtc_ops *);
--- linux-ixp4xx.orig/drivers/char/Kconfig	2006-03-08 01:59:09.000000000 +0100
+++ linux-ixp4xx/drivers/char/Kconfig	2006-03-08 01:59:26.000000000 +0100
@@ -695,7 +695,7 @@ config NVRAM
 
 config RTC
 	tristate "Enhanced Real Time Clock Support"
-	depends on !PPC32 && !PARISC && !IA64 && !M68K && (!SPARC || PCI) && !FRV
+	depends on !PPC32 && !PARISC && !IA64 && !M68K && (!SPARC || PCI) && !FRV && !ARM
 	---help---
 	  If you say Y here and create a character special file /dev/rtc with
 	  major number 10 and minor number 135 using mknod ("man mknod"), you
--- linux-ixp4xx.orig/arch/arm/Kconfig	2006-03-08 01:59:18.000000000 +0100
+++ linux-ixp4xx/arch/arm/Kconfig	2006-03-08 01:59:26.000000000 +0100
@@ -8,6 +8,7 @@ mainmenu "Linux Kernel Configuration"
 config ARM
 	bool
 	default y
+	select RTC_LIB
 	help
 	  The ARM series is a line of low-power-consumption RISC chip designs
 	  licensed by ARM Ltd and targeted at embedded applications and
@@ -819,6 +820,8 @@ source "drivers/usb/Kconfig"
 
 source "drivers/mmc/Kconfig"
 
+source "drivers/rtc/Kconfig"
+
 endmenu
 
 source "fs/Kconfig"
--- linux-ixp4xx.orig/arch/arm/mach-integrator/time.c	2006-03-08 01:59:09.000000000 +0100
+++ linux-ixp4xx/arch/arm/mach-integrator/time.c	2006-03-08 01:59:26.000000000 +0100
@@ -40,13 +40,13 @@ static int integrator_set_rtc(void)
 	return 1;
 }
 
-static int rtc_read_alarm(struct rtc_wkalrm *alrm)
+static int integrator_rtc_read_alarm(struct rtc_wkalrm *alrm)
 {
 	rtc_time_to_tm(readl(rtc_base + RTC_MR), &alrm->time);
 	return 0;
 }
 
-static inline int rtc_set_alarm(struct rtc_wkalrm *alrm)
+static inline int integrator_rtc_set_alarm(struct rtc_wkalrm *alrm)
 {
 	unsigned long time;
 	int ret;
@@ -62,7 +62,7 @@ static inline int rtc_set_alarm(struct r
 	return ret;
 }
 
-static int rtc_read_time(struct rtc_time *tm)
+static int integrator_rtc_read_time(struct rtc_time *tm)
 {
 	rtc_time_to_tm(readl(rtc_base + RTC_DR), tm);
 	return 0;
@@ -76,7 +76,7 @@ static int rtc_read_time(struct rtc_time
  * edge of the 1Hz clock, we must write the time one second
  * in advance.
  */
-static inline int rtc_set_time(struct rtc_time *tm)
+static inline int integrator_rtc_set_time(struct rtc_time *tm)
 {
 	unsigned long time;
 	int ret;
@@ -90,10 +90,10 @@ static inline int rtc_set_time(struct rt
 
 static struct rtc_ops rtc_ops = {
 	.owner		= THIS_MODULE,
-	.read_time	= rtc_read_time,
-	.set_time	= rtc_set_time,
-	.read_alarm	= rtc_read_alarm,
-	.set_alarm	= rtc_set_alarm,
+	.read_time	= integrator_rtc_read_time,
+	.set_time	= integrator_rtc_set_time,
+	.read_alarm	= integrator_rtc_read_alarm,
+	.set_alarm	= integrator_rtc_set_alarm,
 };
 
 static irqreturn_t arm_rtc_interrupt(int irq, void *dev_id,
--- linux-ixp4xx.orig/arch/mips/ddb5xxx/common/rtc_ds1386.c	2006-03-08 01:59:09.000000000 +0100
+++ linux-ixp4xx/arch/mips/ddb5xxx/common/rtc_ds1386.c	2006-03-08 01:59:26.000000000 +0100
@@ -165,6 +165,6 @@ rtc_ds1386_init(unsigned long base)
 	WRITE_RTC(0xB, byte);
 
 	/* set the function pointers */
-	rtc_get_time = rtc_ds1386_get_time;
-	rtc_set_time = rtc_ds1386_set_time;
+	rtc_mips_get_time = rtc_ds1386_get_time;
+	rtc_mips_set_time = rtc_ds1386_set_time;
 }
--- linux-ixp4xx.orig/arch/mips/dec/time.c	2006-03-08 01:59:09.000000000 +0100
+++ linux-ixp4xx/arch/mips/dec/time.c	2006-03-08 01:59:26.000000000 +0100
@@ -193,8 +193,8 @@ static void dec_ioasic_hpt_init(unsigned
 
 void __init dec_time_init(void)
 {
-	rtc_get_time = dec_rtc_get_time;
-	rtc_set_mmss = dec_rtc_set_mmss;
+	rtc_mips_get_time = dec_rtc_get_time;
+	rtc_mips_set_mmss = dec_rtc_set_mmss;
 
 	mips_timer_state = dec_timer_state;
 	mips_timer_ack = dec_timer_ack;
--- linux-ixp4xx.orig/arch/mips/ite-boards/generic/time.c	2006-03-08 01:59:09.000000000 +0100
+++ linux-ixp4xx/arch/mips/ite-boards/generic/time.c	2006-03-08 01:59:26.000000000 +0100
@@ -227,8 +227,8 @@ void __init it8172_time_init(void)
 
 	local_irq_restore(flags);
 
-	rtc_get_time = it8172_rtc_get_time;
-	rtc_set_time = it8172_rtc_set_time;
+	rtc_mips_get_time = it8172_rtc_get_time;
+	rtc_mips_set_time = it8172_rtc_set_time;
 }
 
 #define ALLINTS (IE_IRQ0 | IE_IRQ1 | IE_IRQ2 | IE_IRQ3 | IE_IRQ4 | IE_IRQ5)
--- linux-ixp4xx.orig/arch/mips/jmr3927/common/rtc_ds1742.c	2006-03-08 01:59:09.000000000 +0100
+++ linux-ixp4xx/arch/mips/jmr3927/common/rtc_ds1742.c	2006-03-08 01:59:26.000000000 +0100
@@ -159,8 +159,8 @@ rtc_ds1742_init(unsigned long base)
 	db_assert((rtc_base & 0xe0000000) == KSEG1);
 
 	/* set the function pointers */
-	rtc_get_time = rtc_ds1742_get_time;
-	rtc_set_time = rtc_ds1742_set_time;
+	rtc_mips_get_time = rtc_ds1742_get_time;
+	rtc_mips_set_time = rtc_ds1742_set_time;
 
 	/* clear oscillator stop bit */
 	CMOS_WRITE(RTC_READ, RTC_CONTROL);
--- linux-ixp4xx.orig/arch/mips/kernel/time.c	2006-03-08 01:59:09.000000000 +0100
+++ linux-ixp4xx/arch/mips/kernel/time.c	2006-03-08 01:59:26.000000000 +0100
@@ -65,9 +65,9 @@ static int null_rtc_set_time(unsigned lo
 	return 0;
 }
 
-unsigned long (*rtc_get_time)(void) = null_rtc_get_time;
-int (*rtc_set_time)(unsigned long) = null_rtc_set_time;
-int (*rtc_set_mmss)(unsigned long);
+unsigned long (*rtc_mips_get_time)(void) = null_rtc_get_time;
+int (*rtc_mips_set_time)(unsigned long) = null_rtc_set_time;
+int (*rtc_mips_set_mmss)(unsigned long);
 
 
 /* usecs per counter cycle, shifted to left by 32 bits */
@@ -438,7 +438,7 @@ irqreturn_t timer_interrupt(int irq, voi
 
 	/*
 	 * If we have an externally synchronized Linux clock, then update
-	 * CMOS clock accordingly every ~11 minutes. rtc_set_time() has to be
+	 * CMOS clock accordingly every ~11 minutes. rtc_mips_set_time() has to be
 	 * called as close as possible to 500 ms before the new second starts.
 	 */
 	write_seqlock(&xtime_lock);
@@ -446,7 +446,7 @@ irqreturn_t timer_interrupt(int irq, voi
 	    xtime.tv_sec > last_rtc_update + 660 &&
 	    (xtime.tv_nsec / 1000) >= 500000 - ((unsigned) TICK_SIZE) / 2 &&
 	    (xtime.tv_nsec / 1000) <= 500000 + ((unsigned) TICK_SIZE) / 2) {
-		if (rtc_set_mmss(xtime.tv_sec) == 0) {
+		if (rtc_mips_set_mmss(xtime.tv_sec) == 0) {
 			last_rtc_update = xtime.tv_sec;
 		} else {
 			/* do it again in 60 s */
@@ -563,7 +563,7 @@ asmlinkage void ll_local_timer_interrupt
  *      b) (optional) calibrate and set the mips_hpt_frequency
  *	    (only needed if you intended to use fixed_rate_gettimeoffset
  *	     or use cpu counter as timer interrupt source)
- * 2) setup xtime based on rtc_get_time().
+ * 2) setup xtime based on rtc_mips_get_time().
  * 3) choose a appropriate gettimeoffset routine.
  * 4) calculate a couple of cached variables for later usage
  * 5) board_timer_setup() -
@@ -631,10 +631,10 @@ void __init time_init(void)
 	if (board_time_init)
 		board_time_init();
 
-	if (!rtc_set_mmss)
-		rtc_set_mmss = rtc_set_time;
+	if (!rtc_mips_set_mmss)
+		rtc_mips_set_mmss = rtc_mips_set_time;
 
-	xtime.tv_sec = rtc_get_time();
+	xtime.tv_sec = rtc_mips_get_time();
 	xtime.tv_nsec = 0;
 
 	set_normalized_timespec(&wall_to_monotonic,
@@ -770,8 +770,8 @@ void to_tm(unsigned long tim, struct rtc
 
 EXPORT_SYMBOL(rtc_lock);
 EXPORT_SYMBOL(to_tm);
-EXPORT_SYMBOL(rtc_set_time);
-EXPORT_SYMBOL(rtc_get_time);
+EXPORT_SYMBOL(rtc_mips_set_time);
+EXPORT_SYMBOL(rtc_mips_get_time);
 
 unsigned long long sched_clock(void)
 {
--- linux-ixp4xx.orig/arch/mips/lasat/setup.c	2006-03-08 01:59:09.000000000 +0100
+++ linux-ixp4xx/arch/mips/lasat/setup.c	2006-03-08 01:59:26.000000000 +0100
@@ -174,8 +174,8 @@ void __init plat_setup(void)
 
 #ifdef CONFIG_DS1603
 	ds1603 = &ds_defs[mips_machtype];
-	rtc_get_time = ds1603_read;
-	rtc_set_time = ds1603_set;
+	rtc_mips_get_time = ds1603_read;
+	rtc_mips_set_time = ds1603_set;
 #endif
 
 #ifdef DYNAMIC_SERIAL_INIT
--- linux-ixp4xx.orig/arch/mips/mips-boards/atlas/atlas_setup.c	2006-03-08 01:59:09.000000000 +0100
+++ linux-ixp4xx/arch/mips/mips-boards/atlas/atlas_setup.c	2006-03-08 01:59:26.000000000 +0100
@@ -65,7 +65,7 @@ void __init plat_setup(void)
 
 	board_time_init = mips_time_init;
 	board_timer_setup = mips_timer_setup;
-	rtc_get_time = mips_rtc_get_time;
+	rtc_mips_get_time = mips_rtc_get_time;
 }
 
 static void __init serial_init(void)
--- linux-ixp4xx.orig/arch/mips/mips-boards/malta/malta_setup.c	2006-03-08 01:59:09.000000000 +0100
+++ linux-ixp4xx/arch/mips/mips-boards/malta/malta_setup.c	2006-03-08 01:59:26.000000000 +0100
@@ -225,5 +225,5 @@ void __init plat_setup(void)
 
 	board_time_init = mips_time_init;
 	board_timer_setup = mips_timer_setup;
-	rtc_get_time = mips_rtc_get_time;
+	rtc_mips_get_time = mips_rtc_get_time;
 }
--- linux-ixp4xx.orig/arch/mips/momentum/jaguar_atx/setup.c	2006-03-08 01:59:09.000000000 +0100
+++ linux-ixp4xx/arch/mips/momentum/jaguar_atx/setup.c	2006-03-08 01:59:26.000000000 +0100
@@ -228,8 +228,8 @@ void momenco_time_init(void)
 	mips_hpt_frequency = cpu_clock / 2;
 	board_timer_setup = momenco_timer_setup;
 
-	rtc_get_time = m48t37y_get_time;
-	rtc_set_time = m48t37y_set_time;
+	rtc_mips_get_time = m48t37y_get_time;
+	rtc_mips_set_time = m48t37y_set_time;
 }
 
 static struct resource mv_pci_io_mem0_resource = {
--- linux-ixp4xx.orig/arch/mips/momentum/ocelot_3/setup.c	2006-03-08 01:59:09.000000000 +0100
+++ linux-ixp4xx/arch/mips/momentum/ocelot_3/setup.c	2006-03-08 01:59:26.000000000 +0100
@@ -215,8 +215,8 @@ void momenco_time_init(void)
 	mips_hpt_frequency = cpu_clock / 2;
 	board_timer_setup = momenco_timer_setup;
 
-	rtc_get_time = m48t37y_get_time;
-	rtc_set_time = m48t37y_set_time;
+	rtc_mips_get_time = m48t37y_get_time;
+	rtc_mips_set_time = m48t37y_set_time;
 }
 
 /*
--- linux-ixp4xx.orig/arch/mips/momentum/ocelot_c/setup.c	2006-03-08 01:59:09.000000000 +0100
+++ linux-ixp4xx/arch/mips/momentum/ocelot_c/setup.c	2006-03-08 01:59:26.000000000 +0100
@@ -226,8 +226,8 @@ void momenco_time_init(void)
 	printk("momenco_time_init cpu_clock=%d\n", cpu_clock);
 	board_timer_setup = momenco_timer_setup;
 
-	rtc_get_time = m48t37y_get_time;
-	rtc_set_time = m48t37y_set_time;
+	rtc_mips_get_time = m48t37y_get_time;
+	rtc_mips_set_time = m48t37y_set_time;
 }
 
 void __init plat_setup(void)
--- linux-ixp4xx.orig/arch/mips/pmc-sierra/yosemite/setup.c	2006-03-08 01:59:09.000000000 +0100
+++ linux-ixp4xx/arch/mips/pmc-sierra/yosemite/setup.c	2006-03-08 01:59:26.000000000 +0100
@@ -198,8 +198,8 @@ static void __init py_rtc_setup(void)
 	if (!m48t37_base)
 		printk(KERN_ERR "Mapping the RTC failed\n");
 
-	rtc_get_time = m48t37y_get_time;
-	rtc_set_time = m48t37y_set_time;
+	rtc_mips_get_time = m48t37y_get_time;
+	rtc_mips_set_time = m48t37y_set_time;
 
 	write_seqlock(&xtime_lock);
 	xtime.tv_sec = m48t37y_get_time();
--- linux-ixp4xx.orig/arch/mips/sgi-ip22/ip22-time.c	2006-03-08 01:59:09.000000000 +0100
+++ linux-ixp4xx/arch/mips/sgi-ip22/ip22-time.c	2006-03-08 01:59:26.000000000 +0100
@@ -212,8 +212,8 @@ static void indy_timer_setup(struct irqa
 void __init ip22_time_init(void)
 {
 	/* setup hookup functions */
-	rtc_get_time = indy_rtc_get_time;
-	rtc_set_time = indy_rtc_set_time;
+	rtc_mips_get_time = indy_rtc_get_time;
+	rtc_mips_set_time = indy_rtc_set_time;
 
 	board_time_init = indy_time_init;
 	board_timer_setup = indy_timer_setup;
--- linux-ixp4xx.orig/arch/mips/sgi-ip32/ip32-setup.c	2006-03-08 01:59:09.000000000 +0100
+++ linux-ixp4xx/arch/mips/sgi-ip32/ip32-setup.c	2006-03-08 01:59:26.000000000 +0100
@@ -91,8 +91,8 @@ void __init plat_setup(void)
 {
 	board_be_init = ip32_be_init;
 
-	rtc_get_time = mc146818_get_cmos_time;
-	rtc_set_mmss = mc146818_set_rtc_mmss;
+	rtc_mips_get_time = mc146818_get_cmos_time;
+	rtc_mips_set_mmss = mc146818_set_rtc_mmss;
 
 	board_time_init = ip32_time_init;
 	board_timer_setup = ip32_timer_setup;
--- linux-ixp4xx.orig/arch/mips/sibyte/swarm/setup.c	2006-03-08 01:59:09.000000000 +0100
+++ linux-ixp4xx/arch/mips/sibyte/swarm/setup.c	2006-03-08 01:59:26.000000000 +0100
@@ -114,14 +114,14 @@ void __init plat_setup(void)
 
 	if (xicor_probe()) {
 		printk("swarm setup: Xicor 1241 RTC detected.\n");
-		rtc_get_time = xicor_get_time;
-		rtc_set_time = xicor_set_time;
+		rtc_mips_get_time = xicor_get_time;
+		rtc_mips_set_time = xicor_set_time;
 	}
 
 	if (m41t81_probe()) {
 		printk("swarm setup: M41T81 RTC detected.\n");
-		rtc_get_time = m41t81_get_time;
-		rtc_set_time = m41t81_set_time;
+		rtc_mips_get_time = m41t81_get_time;
+		rtc_mips_set_time = m41t81_set_time;
 	}
 
 	printk("This kernel optimized for "
--- linux-ixp4xx.orig/arch/mips/sni/setup.c	2006-03-08 01:59:09.000000000 +0100
+++ linux-ixp4xx/arch/mips/sni/setup.c	2006-03-08 01:59:26.000000000 +0100
@@ -164,8 +164,8 @@ static struct pci_controller sni_control
 
 static inline void sni_pcimt_time_init(void)
 {
-	rtc_get_time = mc146818_get_cmos_time;
-	rtc_set_time = mc146818_set_rtc_mmss;
+	rtc_mips_get_time = mc146818_get_cmos_time;
+	rtc_mips_set_time = mc146818_set_rtc_mmss;
 }
 
 void __init plat_setup(void)
--- linux-ixp4xx.orig/arch/mips/tx4927/toshiba_rbtx4927/toshiba_rbtx4927_setup.c	2006-03-08 01:59:09.000000000 +0100
+++ linux-ixp4xx/arch/mips/tx4927/toshiba_rbtx4927/toshiba_rbtx4927_setup.c	2006-03-08 01:59:26.000000000 +0100
@@ -1036,8 +1036,8 @@ toshiba_rbtx4927_time_init(void)
 
 #ifdef CONFIG_RTC_DS1742
 
-	rtc_get_time = rtc_ds1742_get_time;
-	rtc_set_time = rtc_ds1742_set_time;
+	rtc_mips_get_time = rtc_ds1742_get_time;
+	rtc_mips_set_time = rtc_ds1742_set_time;
 
 	TOSHIBA_RBTX4927_SETUP_DPRINTK(TOSHIBA_RBTX4927_SETUP_TIME_INIT,
 				       ":rtc_ds1742_init()-\n");
--- linux-ixp4xx.orig/arch/mips/tx4938/common/rtc_rx5c348.c	2006-03-08 01:59:09.000000000 +0100
+++ linux-ixp4xx/arch/mips/tx4938/common/rtc_rx5c348.c	2006-03-08 01:59:26.000000000 +0100
@@ -197,6 +197,6 @@ rtc_rx5c348_init(int chipid)
 		srtc_24h = 1;
 
 	/* set the function pointers */
-	rtc_get_time = rtc_rx5c348_get_time;
-	rtc_set_time = rtc_rx5c348_set_time;
+	rtc_mips_get_time = rtc_rx5c348_get_time;
+	rtc_mips_set_time = rtc_rx5c348_set_time;
 }
--- linux-ixp4xx.orig/include/asm-mips/time.h	2006-03-08 01:59:09.000000000 +0100
+++ linux-ixp4xx/include/asm-mips/time.h	2006-03-08 01:59:26.000000000 +0100
@@ -26,14 +26,14 @@ extern spinlock_t rtc_lock;
 
 /*
  * RTC ops.  By default, they point to no-RTC functions.
- *	rtc_get_time - mktime(year, mon, day, hour, min, sec) in seconds.
- *	rtc_set_time - reverse the above translation and set time to RTC.
- *	rtc_set_mmss - similar to rtc_set_time, but only min and sec need
+ *	rtc_mips_get_time - mktime(year, mon, day, hour, min, sec) in seconds.
+ *	rtc_mips_set_time - reverse the above translation and set time to RTC.
+ *	rtc_mips_set_mmss - similar to rtc_set_time, but only min and sec need
  *			to be set.  Used by RTC sync-up.
  */
-extern unsigned long (*rtc_get_time)(void);
-extern int (*rtc_set_time)(unsigned long);
-extern int (*rtc_set_mmss)(unsigned long);
+extern unsigned long (*rtc_mips_get_time)(void);
+extern int (*rtc_mips_set_time)(unsigned long);
+extern int (*rtc_mips_set_mmss)(unsigned long);
 
 /*
  * Timer interrupt functions.
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ linux-ixp4xx/drivers/rtc/class.c	2006-03-08 01:59:26.000000000 +0100
@@ -0,0 +1,145 @@
+/*
+ * RTC subsystem, base class
+ *
+ * Copyright (C) 2005 Tower Technologies
+ * Author: Alessandro Zummo <a.zummo@towertech.it>
+ *
+ * class skeleton from drivers/hwmon/hwmon.c
+ *
+ * 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; version 2 of the License.
+*/
+
+#include <linux/module.h>
+#include <linux/rtc.h>
+#include <linux/kdev_t.h>
+#include <linux/idr.h>
+
+static DEFINE_IDR(rtc_idr);
+static DEFINE_MUTEX(idr_lock);
+struct class *rtc_class;
+
+static void rtc_device_release(struct class_device *class_dev)
+{
+	struct rtc_device *rtc = to_rtc_device(class_dev);
+	mutex_lock(&idr_lock);
+	idr_remove(&rtc_idr, rtc->id);
+	mutex_unlock(&idr_lock);
+	kfree(rtc);
+}
+
+/**
+ * rtc_device_register - register w/ RTC class
+ * @dev: the device to register
+ *
+ * rtc_device_unregister() must be called when the class device is no
+ * longer needed.
+ *
+ * Returns the pointer to the new struct class device.
+ */
+struct rtc_device *rtc_device_register(const char *name, struct device *dev,
+					struct rtc_class_ops *ops,
+					struct module *owner)
+{
+	struct rtc_device *rtc;
+	int id, err;
+
+	if (idr_pre_get(&rtc_idr, GFP_KERNEL) == 0) {
+		err = -ENOMEM;
+		goto exit;
+	}
+
+
+	mutex_lock(&idr_lock);
+	err = idr_get_new(&rtc_idr, NULL, &id);
+	mutex_unlock(&idr_lock);
+
+	if (err < 0)
+		goto exit;
+
+	id = id & MAX_ID_MASK;
+
+	rtc = kzalloc(sizeof(struct rtc_device), GFP_KERNEL);
+	if (rtc == NULL) {
+		err = -ENOMEM;
+		goto exit_idr;
+	}
+
+	rtc->id = id;
+	rtc->ops = ops;
+	rtc->owner = owner;
+	rtc->class_dev.dev = dev;
+	rtc->class_dev.class = rtc_class;
+	rtc->class_dev.release = rtc_device_release;
+
+	mutex_init(&rtc->ops_lock);
+	spin_lock_init(&rtc->irq_lock);
+	spin_lock_init(&rtc->irq_task_lock);
+
+	strlcpy(rtc->name, name, RTC_DEVICE_NAME_SIZE);
+	snprintf(rtc->class_dev.class_id, BUS_ID_SIZE, "rtc%d", id);
+
+	err = class_device_register(&rtc->class_dev);
+	if (err)
+		goto exit_kfree;
+
+	dev_info(dev, "rtc core: registered %s as %s\n",
+			rtc->name, rtc->class_dev.class_id);
+
+	return rtc;
+
+exit_kfree:
+	kfree(rtc);
+
+exit_idr:
+	idr_remove(&rtc_idr, id);
+
+exit:
+	return ERR_PTR(err);
+}
+EXPORT_SYMBOL_GPL(rtc_device_register);
+
+
+/**
+ * rtc_device_unregister - removes the previously registered RTC class device
+ *
+ * @rtc: the RTC class device to destroy
+ */
+void rtc_device_unregister(struct rtc_device *rtc)
+{
+	mutex_lock(&rtc->ops_lock);
+	rtc->ops = NULL;
+	mutex_unlock(&rtc->ops_lock);
+	class_device_unregister(&rtc->class_dev);
+}
+EXPORT_SYMBOL_GPL(rtc_device_unregister);
+
+int rtc_interface_register(struct class_interface *intf)
+{
+	intf->class = rtc_class;
+	return class_interface_register(intf);
+}
+EXPORT_SYMBOL_GPL(rtc_interface_register);
+
+static int __init rtc_init(void)
+{
+	rtc_class = class_create(THIS_MODULE, "rtc");
+	if (IS_ERR(rtc_class)) {
+		printk(KERN_ERR "%s: couldn't create class\n", __FILE__);
+		return PTR_ERR(rtc_class);
+	}
+	return 0;
+}
+
+static void __exit rtc_exit(void)
+{
+	class_destroy(rtc_class);
+}
+
+module_init(rtc_init);
+module_exit(rtc_exit);
+
+MODULE_AUTHOR("Alessandro Zummo <a.zummo@towerteh.it>");
+MODULE_DESCRIPTION("RTC class support");
+MODULE_LICENSE("GPL");
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ linux-ixp4xx/drivers/rtc/interface.c	2006-03-08 01:59:26.000000000 +0100
@@ -0,0 +1,277 @@
+/*
+ * RTC subsystem, interface functions
+ *
+ * Copyright (C) 2005 Tower Technologies
+ * Author: Alessandro Zummo <a.zummo@towertech.it>
+ *
+ * based on arch/arm/common/rtctime.c
+ *
+ * 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; version 2 of the License.
+*/
+
+#include <linux/rtc.h>
+
+int rtc_read_time(struct class_device *class_dev, struct rtc_time *tm)
+{
+	int err;
+	struct rtc_device *rtc = to_rtc_device(class_dev);
+
+	err = mutex_lock_interruptible(&rtc->ops_lock);
+	if (err)
+		return -EBUSY;
+
+	if (!rtc->ops)
+		err = -ENODEV;
+	else if (!rtc->ops->read_time)
+		err = -EINVAL;
+	else {
+		memset(tm, 0, sizeof(struct rtc_time));
+		err = rtc->ops->read_time(class_dev->dev, tm);
+	}
+
+	mutex_unlock(&rtc->ops_lock);
+	return err;
+}
+EXPORT_SYMBOL_GPL(rtc_read_time);
+
+int rtc_set_time(struct class_device *class_dev, struct rtc_time *tm)
+{
+	int err;
+	struct rtc_device *rtc = to_rtc_device(class_dev);
+
+	err = rtc_valid_tm(tm);
+	if (err != 0)
+		return err;
+
+	err = mutex_lock_interruptible(&rtc->ops_lock);
+	if (err)
+		return -EBUSY;
+
+	if (!rtc->ops)
+		err = -ENODEV;
+	else if (!rtc->ops->set_time)
+		err = -EINVAL;
+	else
+		err = rtc->ops->set_time(class_dev->dev, tm);
+
+	mutex_unlock(&rtc->ops_lock);
+	return err;
+}
+EXPORT_SYMBOL_GPL(rtc_set_time);
+
+int rtc_set_mmss(struct class_device *class_dev, unsigned long secs)
+{
+	int err;
+	struct rtc_device *rtc = to_rtc_device(class_dev);
+
+	err = mutex_lock_interruptible(&rtc->ops_lock);
+	if (err)
+		return -EBUSY;
+
+	if (!rtc->ops)
+		err = -ENODEV;
+	else if (rtc->ops->set_mmss)
+		err = rtc->ops->set_mmss(class_dev->dev, secs);
+	else if (rtc->ops->read_time && rtc->ops->set_time) {
+		struct rtc_time new, old;
+
+		err = rtc->ops->read_time(class_dev->dev, &old);
+		if (err == 0) {
+			rtc_time_to_tm(secs, &new);
+
+			/*
+			 * avoid writing when we're going to change the day of
+			 * the month. We will retry in the next minute. This
+			 * basically means that if the RTC must not drift
+			 * by more than 1 minute in 11 minutes.
+			 */
+			if (!((old.tm_hour == 23 && old.tm_min == 59) ||
+				(new.tm_hour == 23 && new.tm_min == 59)))
+				err = rtc->ops->set_time(class_dev->dev, &new);
+		}
+	}
+	else
+		err = -EINVAL;
+
+	mutex_unlock(&rtc->ops_lock);
+
+	return err;
+}
+EXPORT_SYMBOL_GPL(rtc_set_mmss);
+
+int rtc_read_alarm(struct class_device *class_dev, struct rtc_wkalrm *alarm)
+{
+	int err;
+	struct rtc_device *rtc = to_rtc_device(class_dev);
+
+	err = mutex_lock_interruptible(&rtc->ops_lock);
+	if (err)
+		return -EBUSY;
+
+	if (rtc->ops == NULL)
+		err = -ENODEV;
+	else if (!rtc->ops->read_alarm)
+		err = -EINVAL;
+	else {
+		memset(alarm, 0, sizeof(struct rtc_wkalrm));
+		err = rtc->ops->read_alarm(class_dev->dev, alarm);
+	}
+
+	mutex_unlock(&rtc->ops_lock);
+	return err;
+}
+EXPORT_SYMBOL_GPL(rtc_read_alarm);
+
+int rtc_set_alarm(struct class_device *class_dev, struct rtc_wkalrm *alarm)
+{
+	int err;
+	struct rtc_device *rtc = to_rtc_device(class_dev);
+
+	err = mutex_lock_interruptible(&rtc->ops_lock);
+	if (err)
+		return -EBUSY;
+
+	if (!rtc->ops)
+		err = -ENODEV;
+	else if (!rtc->ops->set_alarm)
+		err = -EINVAL;
+	else
+		err = rtc->ops->set_alarm(class_dev->dev, alarm);
+
+	mutex_unlock(&rtc->ops_lock);
+	return err;
+}
+EXPORT_SYMBOL_GPL(rtc_set_alarm);
+
+void rtc_update_irq(struct class_device *class_dev,
+		unsigned long num, unsigned long events)
+{
+	struct rtc_device *rtc = to_rtc_device(class_dev);
+
+	spin_lock(&rtc->irq_lock);
+	rtc->irq_data = (rtc->irq_data + (num << 8)) | events;
+	spin_unlock(&rtc->irq_lock);
+
+	spin_lock(&rtc->irq_task_lock);
+	if (rtc->irq_task)
+		rtc->irq_task->func(rtc->irq_task->private_data);
+	spin_unlock(&rtc->irq_task_lock);
+
+	wake_up_interruptible(&rtc->irq_queue);
+	kill_fasync(&rtc->async_queue, SIGIO, POLL_IN);
+}
+EXPORT_SYMBOL_GPL(rtc_update_irq);
+
+struct class_device *rtc_class_open(char *name)
+{
+	struct class_device *class_dev = NULL,
+				*class_dev_tmp;
+
+	down(&rtc_class->sem);
+	list_for_each_entry(class_dev_tmp, &rtc_class->children, node) {
+		if (strncmp(class_dev_tmp->class_id, name, BUS_ID_SIZE) == 0) {
+			class_dev = class_dev_tmp;
+			break;
+		}
+	}
+
+	if (class_dev) {
+		if (!try_module_get(to_rtc_device(class_dev)->owner))
+			class_dev = NULL;
+	}
+	up(&rtc_class->sem);
+
+	return class_dev;
+}
+EXPORT_SYMBOL_GPL(rtc_class_open);
+
+void rtc_class_close(struct class_device *class_dev)
+{
+	module_put(to_rtc_device(class_dev)->owner);
+}
+EXPORT_SYMBOL_GPL(rtc_class_close);
+
+int rtc_irq_register(struct class_device *class_dev, struct rtc_task *task)
+{
+	int retval = -EBUSY;
+	struct rtc_device *rtc = to_rtc_device(class_dev);
+
+	if (task == NULL || task->func == NULL)
+		return -EINVAL;
+
+	spin_lock(&rtc->irq_task_lock);
+	if (rtc->irq_task == NULL) {
+		rtc->irq_task = task;
+		retval = 0;
+	}
+	spin_unlock(&rtc->irq_task_lock);
+
+	return retval;
+}
+EXPORT_SYMBOL_GPL(rtc_irq_register);
+
+void rtc_irq_unregister(struct class_device *class_dev, struct rtc_task *task)
+{
+	struct rtc_device *rtc = to_rtc_device(class_dev);
+
+	spin_lock(&rtc->irq_task_lock);
+	if (rtc->irq_task == task)
+		rtc->irq_task = NULL;
+	spin_unlock(&rtc->irq_task_lock);
+}
+EXPORT_SYMBOL_GPL(rtc_irq_unregister);
+
+int rtc_irq_set_state(struct class_device *class_dev, struct rtc_task *task, int enabled)
+{
+	int err = 0;
+	unsigned long flags;
+	struct rtc_device *rtc = to_rtc_device(class_dev);
+
+	spin_lock_irqsave(&rtc->irq_task_lock, flags);
+	if (rtc->irq_task != task)
+		err = -ENXIO;
+	spin_unlock_irqrestore(&rtc->irq_task_lock, flags);
+
+	if (err == 0)
+		err = rtc->ops->irq_set_state(class_dev->dev, enabled);
+
+	return err;
+}
+EXPORT_SYMBOL_GPL(rtc_irq_set_state);
+
+int rtc_irq_set_freq(struct class_device *class_dev, struct rtc_task *task, int freq)
+{
+	int err = 0, tmp = 0;
+	unsigned long flags;
+	struct rtc_device *rtc = to_rtc_device(class_dev);
+
+	/* allowed range is 2-8192 */
+	if (freq < 2 || freq > 8192)
+		return -EINVAL;
+/*
+	FIXME: this does not belong here, will move where appropriate
+	at a later stage. It cannot hurt right now, trust me :)
+	if ((freq > rtc_max_user_freq) && (!capable(CAP_SYS_RESOURCE)))
+		return -EACCES;
+*/
+	/* check if freq is a power of 2 */
+	while (freq > (1 << tmp))
+		tmp++;
+
+	if (freq != (1 << tmp))
+		return -EINVAL;
+
+	spin_lock_irqsave(&rtc->irq_task_lock, flags);
+	if (rtc->irq_task != task)
+		err = -ENXIO;
+	spin_unlock_irqrestore(&rtc->irq_task_lock, flags);
+
+	if (err == 0) {
+		err = rtc->ops->irq_set_freq(class_dev->dev, freq);
+		if (err == 0)
+			rtc->irq_freq = freq;
+	}
+	return err;
+}
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ linux-ixp4xx/drivers/rtc/hctosys.c	2006-03-08 01:59:26.000000000 +0100
@@ -0,0 +1,69 @@
+/*
+ * RTC subsystem, initialize system time on startup
+ *
+ * Copyright (C) 2005 Tower Technologies
+ * Author: Alessandro Zummo <a.zummo@towertech.it>
+ *
+ * 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; version 2 of the License.
+*/
+
+#include <linux/rtc.h>
+
+/* IMPORTANT: the RTC only stores whole seconds. It is arbitrary
+ * whether it stores the most close value or the value with partial
+ * seconds truncated. However, it is important that we use it to store
+ * the truncated value. This is because otherwise it is necessary,
+ * in an rtc sync function, to read both xtime.tv_sec and
+ * xtime.tv_nsec. On some processors (i.e. ARM), an atomic read
+ * of >32bits is not possible. So storing the most close value would
+ * slow down the sync API. So here we have the truncated value and
+ * the best guess is to add 0.5s.
+ */
+
+static int __init rtc_hctosys(void)
+{
+	int err;
+	struct rtc_time tm;
+	struct class_device *class_dev = rtc_class_open(CONFIG_RTC_HCTOSYS_DEVICE);
+
+	if (class_dev == NULL) {
+		printk("%s: unable to open rtc device (%s)\n",
+			__FILE__, CONFIG_RTC_HCTOSYS_DEVICE);
+		return -ENODEV;
+	}
+
+	err = rtc_read_time(class_dev, &tm);
+	if (err == 0) {
+		err = rtc_valid_tm(&tm);
+		if (err == 0) {
+			struct timespec tv;
+
+			tv.tv_nsec = NSEC_PER_SEC >> 1;
+
+			rtc_tm_to_time(&tm, &tv.tv_sec);
+
+			do_settimeofday(&tv);
+
+			dev_info(class_dev->dev,
+				"setting the system clock to "
+				"%d-%02d-%02d %02d:%02d:%02d (%u)\n",
+				tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday,
+				tm.tm_hour, tm.tm_min, tm.tm_sec,
+				(unsigned int) tv.tv_sec);
+		}
+		else
+			dev_err(class_dev->dev,
+				"hctosys: invalid date/time\n");
+	}
+	else
+		dev_err(class_dev->dev,
+			"hctosys: unable to read the hardware clock\n");
+
+	rtc_class_close(class_dev);
+
+	return 0;
+}
+
+late_initcall(rtc_hctosys);
--- linux-ixp4xx.orig/CREDITS	2006-03-08 01:59:09.000000000 +0100
+++ linux-ixp4xx/CREDITS	2006-03-08 01:59:26.000000000 +0100
@@ -3741,10 +3741,11 @@ D: Mylex DAC960 PCI RAID driver
 D: Miscellaneous kernel fixes
 
 N: Alessandro Zummo
-E: azummo@ita.flashnet.it
-W: http://freepage.logicom.it/azummo/
+E: a.zummo@towertech.it
 D: CMI8330 support is sb_card.c
 D: ISAPnP fixes in sb_card.c
+D: ZyXEL omni.net lcd plus driver
+D: RTC subsystem
 S: Italy
 
 N: Marc Zyngier
--- linux-ixp4xx.orig/MAINTAINERS	2006-03-08 01:59:09.000000000 +0100
+++ linux-ixp4xx/MAINTAINERS	2006-03-08 01:59:26.000000000 +0100
@@ -2193,6 +2193,12 @@ M:	p_gortmaker@yahoo.com
 L:	linux-kernel@vger.kernel.org
 S:	Maintained
 
+REAL TIME CLOCK (RTC) SUBSYSTEM
+P:	Alessandro Zummo
+M:	a.zummo@towertech.it
+L:	linux-kernel@vger.kernel.org
+S:	Maintained
+
 REISERFS FILE SYSTEM
 P:	Hans Reiser
 M:	reiserfs-dev@namesys.com
--- linux-ixp4xx.orig/drivers/i2c/chips/x1205.c	2006-03-08 01:59:09.000000000 +0100
+++ /dev/null	1970-01-01 00:00:00.000000000 +0000
@@ -1,698 +0,0 @@
-/*
- *  x1205.c - An i2c driver for the Xicor X1205 RTC
- *  Copyright 2004 Karen Spearel
- *  Copyright 2005 Alessandro Zummo
- *
- *  please send all reports to:
- *	kas11 at tampabay dot rr dot com
- *      a dot zummo at towertech dot it
- *
- *  based on the other drivers in this same directory.
- *
- *  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/module.h>
-#include <linux/init.h>
-#include <linux/slab.h>
-#include <linux/i2c.h>
-#include <linux/string.h>
-#include <linux/bcd.h>
-#include <linux/rtc.h>
-#include <linux/list.h>
-
-#include <linux/x1205.h>
-
-#define DRV_VERSION "0.9.9"
-
-/* Addresses to scan: none. This chip is located at
- * 0x6f and uses a two bytes register addressing.
- * Two bytes need to be written to read a single register,
- * while most other chips just require one and take the second
- * one as the data to be written. To prevent corrupting
- * unknown chips, the user must explicitely set the probe parameter.
- */
-
-static unsigned short normal_i2c[] = { I2C_CLIENT_END };
-
-/* Insmod parameters */
-I2C_CLIENT_INSMOD;
-I2C_CLIENT_MODULE_PARM(hctosys,
-	"Set the system time from the hardware clock upon initialization");
-
-/* offsets into CCR area */
-
-#define CCR_SEC			0
-#define CCR_MIN			1
-#define CCR_HOUR		2
-#define CCR_MDAY		3
-#define CCR_MONTH		4
-#define CCR_YEAR		5
-#define CCR_WDAY		6
-#define CCR_Y2K			7
-
-#define X1205_REG_SR		0x3F	/* status register */
-#define X1205_REG_Y2K		0x37
-#define X1205_REG_DW		0x36
-#define X1205_REG_YR		0x35
-#define X1205_REG_MO		0x34
-#define X1205_REG_DT		0x33
-#define X1205_REG_HR		0x32
-#define X1205_REG_MN		0x31
-#define X1205_REG_SC		0x30
-#define X1205_REG_DTR		0x13
-#define X1205_REG_ATR		0x12
-#define X1205_REG_INT		0x11
-#define X1205_REG_0		0x10
-#define X1205_REG_Y2K1		0x0F
-#define X1205_REG_DWA1		0x0E
-#define X1205_REG_YRA1		0x0D
-#define X1205_REG_MOA1		0x0C
-#define X1205_REG_DTA1		0x0B
-#define X1205_REG_HRA1		0x0A
-#define X1205_REG_MNA1		0x09
-#define X1205_REG_SCA1		0x08
-#define X1205_REG_Y2K0		0x07
-#define X1205_REG_DWA0		0x06
-#define X1205_REG_YRA0		0x05
-#define X1205_REG_MOA0		0x04
-#define X1205_REG_DTA0		0x03
-#define X1205_REG_HRA0		0x02
-#define X1205_REG_MNA0		0x01
-#define X1205_REG_SCA0		0x00
-
-#define X1205_CCR_BASE		0x30	/* Base address of CCR */
-#define X1205_ALM0_BASE		0x00	/* Base address of ALARM0 */
-
-#define X1205_SR_RTCF		0x01	/* Clock failure */
-#define X1205_SR_WEL		0x02	/* Write Enable Latch */
-#define X1205_SR_RWEL		0x04	/* Register Write Enable */
-
-#define X1205_DTR_DTR0		0x01
-#define X1205_DTR_DTR1		0x02
-#define X1205_DTR_DTR2		0x04
-
-#define X1205_HR_MIL		0x80	/* Set in ccr.hour for 24 hr mode */
-
-/* Prototypes */
-static int x1205_attach(struct i2c_adapter *adapter);
-static int x1205_detach(struct i2c_client *client);
-static int x1205_probe(struct i2c_adapter *adapter, int address, int kind);
-static int x1205_command(struct i2c_client *client, unsigned int cmd,
-	void *arg);
-
-static struct i2c_driver x1205_driver = {
-	.driver = {
-		.name	= "x1205",
-	},
-	.attach_adapter = &x1205_attach,
-	.detach_client	= &x1205_detach,
-};
-
-struct x1205_data {
-	struct i2c_client client;
-	struct list_head list;
-	unsigned int epoch;
-};
-
-static const unsigned char days_in_mo[] =
-	{ 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
-
-static LIST_HEAD(x1205_clients);
-
-/* Workaround until the I2C subsytem will allow to send
- * commands to a specific client. This function will send the command
- * to the first client.
- */
-int x1205_do_command(unsigned int cmd, void *arg)
-{
-	struct list_head *walk;
-	struct list_head *tmp;
-	struct x1205_data *data;
-
-	list_for_each_safe(walk, tmp, &x1205_clients) {
-		data = list_entry(walk, struct x1205_data, list);
-		return x1205_command(&data->client, cmd, arg);
-	}
-
-	return -ENODEV;
-}
-
-#define is_leap(year) \
-	((year) % 4 == 0 && ((year) % 100 != 0 || (year) % 400 == 0))
-
-/* make sure the rtc_time values are in bounds */
-static int x1205_validate_tm(struct rtc_time *tm)
-{
-	int year = tm->tm_year + 1900;
-
-	if ((tm->tm_year < 70) || (tm->tm_year > 255))
-		return -EINVAL;
-
-	if ((tm->tm_mon > 11) || (tm->tm_mday == 0))
-		return -EINVAL;
-
-	if (tm->tm_mday > days_in_mo[tm->tm_mon]
-		+ ((tm->tm_mon == 1) && is_leap(year)))
-		return -EINVAL;
-
-	if ((tm->tm_hour >= 24) || (tm->tm_min >= 60) || (tm->tm_sec >= 60))
-		return -EINVAL;
-
-	return 0;
-}
-
-/*
- * In the routines that deal directly with the x1205 hardware, we use
- * rtc_time -- month 0-11, hour 0-23, yr = calendar year-epoch
- * Epoch is initialized as 2000. Time is set to UTC.
- */
-static int x1205_get_datetime(struct i2c_client *client, struct rtc_time *tm,
-				u8 reg_base)
-{
-	unsigned char dt_addr[2] = { 0, reg_base };
-	static unsigned char sr_addr[2] = { 0, X1205_REG_SR };
-
-	unsigned char buf[8], sr;
-
-	struct i2c_msg msgs[] = {
-		{ client->addr, 0, 2, sr_addr },	/* setup read ptr */
-		{ client->addr, I2C_M_RD, 1, &sr }, 	/* read status */
-		{ client->addr, 0, 2, dt_addr },	/* setup read ptr */
-		{ client->addr, I2C_M_RD, 8, buf },	/* read date */
-	};
-
-	struct x1205_data *data = i2c_get_clientdata(client);
-
-	/* read status register */
-	if ((i2c_transfer(client->adapter, &msgs[0], 2)) != 2) {
-		dev_err(&client->dev, "%s: read error\n", __FUNCTION__);
-		return -EIO;
-	}
-
-	/* check for battery failure */
-	if (sr & X1205_SR_RTCF) {
-		dev_warn(&client->dev,
-			"Clock had a power failure, you must set the date.\n");
-		return -EINVAL;
-	}
-
-	/* read date registers */
-	if ((i2c_transfer(client->adapter, &msgs[2], 2)) != 2) {
-		dev_err(&client->dev, "%s: read error\n", __FUNCTION__);
-		return -EIO;
-	}
-
-	dev_dbg(&client->dev,
-		"%s: raw read data - sec=%02x, min=%02x, hr=%02x, "
-		"mday=%02x, mon=%02x, year=%02x, wday=%02x, y2k=%02x\n",
-		__FUNCTION__,
-		buf[0], buf[1], buf[2], buf[3],
-		buf[4], buf[5], buf[6], buf[7]);
-
-	tm->tm_sec = BCD2BIN(buf[CCR_SEC]);
-	tm->tm_min = BCD2BIN(buf[CCR_MIN]);
-	tm->tm_hour = BCD2BIN(buf[CCR_HOUR] & 0x3F); /* hr is 0-23 */
-	tm->tm_mday = BCD2BIN(buf[CCR_MDAY]);
-	tm->tm_mon = BCD2BIN(buf[CCR_MONTH]);
-	data->epoch = BCD2BIN(buf[CCR_Y2K]) * 100;
-	tm->tm_year = BCD2BIN(buf[CCR_YEAR]) + data->epoch - 1900;
-	tm->tm_wday = buf[CCR_WDAY];
-
-	dev_dbg(&client->dev, "%s: tm is secs=%d, mins=%d, hours=%d, "
-		"mday=%d, mon=%d, year=%d, wday=%d\n",
-		__FUNCTION__,
-		tm->tm_sec, tm->tm_min, tm->tm_hour,
-		tm->tm_mday, tm->tm_mon, tm->tm_year, tm->tm_wday);
-
-	return 0;
-}
-
-static int x1205_set_datetime(struct i2c_client *client, struct rtc_time *tm,
-				int datetoo, u8 reg_base)
-{
-	int i, err, xfer;
-
-	unsigned char buf[8];
-
-	static const unsigned char wel[3] = { 0, X1205_REG_SR,
-						X1205_SR_WEL };
-
-	static const unsigned char rwel[3] = { 0, X1205_REG_SR,
-						X1205_SR_WEL | X1205_SR_RWEL };
-
-	static const unsigned char diswe[3] = { 0, X1205_REG_SR, 0 };
-
-	struct x1205_data *data = i2c_get_clientdata(client);
-
-	/* check if all values in the tm struct are correct */
-	if ((err = x1205_validate_tm(tm)) < 0)
-		return err;
-
-	dev_dbg(&client->dev, "%s: secs=%d, mins=%d, hours=%d, "
-		"mday=%d, mon=%d, year=%d, wday=%d\n",
-		__FUNCTION__,
-		tm->tm_sec, tm->tm_min, tm->tm_hour,
-		tm->tm_mday, tm->tm_mon, tm->tm_year, tm->tm_wday);
-
-	buf[CCR_SEC] = BIN2BCD(tm->tm_sec);
-	buf[CCR_MIN] = BIN2BCD(tm->tm_min);
-
-	/* set hour and 24hr bit */
-	buf[CCR_HOUR] = BIN2BCD(tm->tm_hour) | X1205_HR_MIL;
-
-	/* should we also set the date? */
-	if (datetoo) {
-		buf[CCR_MDAY] = BIN2BCD(tm->tm_mday);
-
-		/* month, 0 - 11 */
-		buf[CCR_MONTH] = BIN2BCD(tm->tm_mon);
-
-		/* year, since 1900 */
-		buf[CCR_YEAR] = BIN2BCD(tm->tm_year + 1900 - data->epoch);
-		buf[CCR_WDAY] = tm->tm_wday & 0x07;
-		buf[CCR_Y2K] = BIN2BCD(data->epoch / 100);
-	}
-
-	/* this sequence is required to unlock the chip */
-	xfer = i2c_master_send(client, wel, 3);
-	if (xfer != 3) {
-		dev_err(&client->dev, "%s: wel - %d\n", __FUNCTION__, xfer);
-		return -EIO;
-	}
-
-	xfer = i2c_master_send(client, rwel, 3);
-	if (xfer != 3) {
-		dev_err(&client->dev, "%s: rwel - %d\n", __FUNCTION__, xfer);
-		return -EIO;
-	}
-
-	/* write register's data */
-	for (i = 0; i < (datetoo ? 8 : 3); i++) {
-		unsigned char rdata[3] = { 0, reg_base + i, buf[i] };
-
-		xfer = i2c_master_send(client, rdata, 3);
-		if (xfer != 3) {
-			dev_err(&client->dev,
-				"%s: xfer=%d addr=%02x, data=%02x\n",
-				__FUNCTION__,
-				 xfer, rdata[1], rdata[2]);
-			return -EIO;
-		}
-	};
-
-	/* disable further writes */
-	xfer = i2c_master_send(client, diswe, 3);
-	if (xfer != 3) {
-		dev_err(&client->dev, "%s: diswe - %d\n", __FUNCTION__, xfer);
-		return -EIO;
-	}
-
-	return 0;
-}
-
-static int x1205_get_dtrim(struct i2c_client *client, int *trim)
-{
-	unsigned char dtr;
-	static unsigned char dtr_addr[2] = { 0, X1205_REG_DTR };
-
-	struct i2c_msg msgs[] = {
-		{ client->addr, 0, 2, dtr_addr },	/* setup read ptr */
-		{ client->addr, I2C_M_RD, 1, &dtr }, 	/* read dtr */
-	};
-
-	/* read dtr register */
-	if ((i2c_transfer(client->adapter, &msgs[0], 2)) != 2) {
-		dev_err(&client->dev, "%s: read error\n", __FUNCTION__);
-		return -EIO;
-	}
-
-	dev_dbg(&client->dev, "%s: raw dtr=%x\n", __FUNCTION__, dtr);
-
-	*trim = 0;
-
-	if (dtr & X1205_DTR_DTR0)
-		*trim += 20;
-
-	if (dtr & X1205_DTR_DTR1)
-		*trim += 10;
-
-	if (dtr & X1205_DTR_DTR2)
-		*trim = -*trim;
-
-	return 0;
-}
-
-static int x1205_get_atrim(struct i2c_client *client, int *trim)
-{
-	s8 atr;
-	static unsigned char atr_addr[2] = { 0, X1205_REG_ATR };
-
-	struct i2c_msg msgs[] = {
-		{ client->addr, 0, 2, atr_addr },	/* setup read ptr */
-		{ client->addr, I2C_M_RD, 1, &atr }, 	/* read atr */
-	};
-
-	/* read atr register */
-	if ((i2c_transfer(client->adapter, &msgs[0], 2)) != 2) {
-		dev_err(&client->dev, "%s: read error\n", __FUNCTION__);
-		return -EIO;
-	}
-
-	dev_dbg(&client->dev, "%s: raw atr=%x\n", __FUNCTION__, atr);
-
-	/* atr is a two's complement value on 6 bits,
-	 * perform sign extension. The formula is
-	 * Catr = (atr * 0.25pF) + 11.00pF.
-	 */
-	if (atr & 0x20)
-		atr |= 0xC0;
-
-	dev_dbg(&client->dev, "%s: raw atr=%x (%d)\n", __FUNCTION__, atr, atr);
-
-	*trim = (atr * 250) + 11000;
-
-	dev_dbg(&client->dev, "%s: real=%d\n", __FUNCTION__, *trim);
-
-	return 0;
-}
-
-static int x1205_hctosys(struct i2c_client *client)
-{
-	int err;
-
-	struct rtc_time tm;
-	struct timespec tv;
-
-	err = x1205_command(client, X1205_CMD_GETDATETIME, &tm);
-
-	if (err) {
-		dev_err(&client->dev,
-			"Unable to set the system clock\n");
-		return err;
-	}
-
-	/* IMPORTANT: the RTC only stores whole seconds. It is arbitrary
-	 * whether it stores the most close value or the value with partial
-	 * seconds truncated. However, it is important that we use it to store
-	 * the truncated value. This is because otherwise it is necessary,
-	 * in an rtc sync function, to read both xtime.tv_sec and
-	 * xtime.tv_nsec. On some processors (i.e. ARM), an atomic read
-	 * of >32bits is not possible. So storing the most close value would
-	 * slow down the sync API. So here we have the truncated value and
-	 * the best guess is to add 0.5s.
-	 */
-
-	tv.tv_nsec = NSEC_PER_SEC >> 1;
-
-	/* WARNING: this is not the C library 'mktime' call, it is a built in
-	 * inline function from include/linux/time.h.  It expects (requires)
-	 * the month to be in the range 1-12
-	 */
-
-	tv.tv_sec  = mktime(tm.tm_year + 1900, tm.tm_mon + 1,
-				tm.tm_mday, tm.tm_hour,
-				tm.tm_min, tm.tm_sec);
-
-	do_settimeofday(&tv);
-
-	dev_info(&client->dev,
-		"setting the system clock to %d-%d-%d %d:%d:%d\n",
-		tm.tm_year + 1900, tm.tm_mon + 1,
-		tm.tm_mday, tm.tm_hour, tm.tm_min,
-		tm.tm_sec);
-
-	return 0;
-}
-
-struct x1205_limit
-{
-	unsigned char reg;
-	unsigned char mask;
-	unsigned char min;
-	unsigned char max;
-};
-
-static int x1205_validate_client(struct i2c_client *client)
-{
-	int i, xfer;
-
-	/* Probe array. We will read the register at the specified
-	 * address and check if the given bits are zero.
-	 */
-	static const unsigned char probe_zero_pattern[] = {
-		/* register, mask */
-		X1205_REG_SR,	0x18,
-		X1205_REG_DTR,	0xF8,
-		X1205_REG_ATR,	0xC0,
-		X1205_REG_INT,	0x18,
-		X1205_REG_0,	0xFF,
-	};
-
-	static const struct x1205_limit probe_limits_pattern[] = {
-		/* register, mask, min, max */
-		{ X1205_REG_Y2K,	0xFF,	19,	20	},
-		{ X1205_REG_DW,		0xFF,	0,	6	},
-		{ X1205_REG_YR,		0xFF,	0,	99	},
-		{ X1205_REG_MO,		0xFF,	0,	12	},
-		{ X1205_REG_DT,		0xFF,	0,	31	},
-		{ X1205_REG_HR,		0x7F,	0,	23	},
-		{ X1205_REG_MN,		0xFF,	0,	59	},
-		{ X1205_REG_SC,		0xFF,	0,	59	},
-		{ X1205_REG_Y2K1,	0xFF,	19,	20	},
-		{ X1205_REG_Y2K0,	0xFF,	19,	20	},
-	};
-
-	/* check that registers have bits a 0 where expected */
-	for (i = 0; i < ARRAY_SIZE(probe_zero_pattern); i += 2) {
-		unsigned char buf;
-
-		unsigned char addr[2] = { 0, probe_zero_pattern[i] };
-
-		struct i2c_msg msgs[2] = {
-			{ client->addr, 0, 2, addr },
-			{ client->addr, I2C_M_RD, 1, &buf },
-		};
-
-		xfer = i2c_transfer(client->adapter, msgs, 2);
-		if (xfer != 2) {
-			dev_err(&client->adapter->dev,
-				"%s: could not read register %x\n",
-				__FUNCTION__, addr[1]);
-
-			return -EIO;
-		}
-
-		if ((buf & probe_zero_pattern[i+1]) != 0) {
-			dev_err(&client->adapter->dev,
-				"%s: register=%02x, zero pattern=%d, value=%x\n",
-				__FUNCTION__, addr[1], i, buf);
-
-			return -ENODEV;
-		}
-	}
-
-	/* check limits (only registers with bcd values) */
-	for (i = 0; i < ARRAY_SIZE(probe_limits_pattern); i++) {
-		unsigned char reg, value;
-
-		unsigned char addr[2] = { 0, probe_limits_pattern[i].reg };
-
-		struct i2c_msg msgs[2] = {
-			{ client->addr, 0, 2, addr },
-			{ client->addr, I2C_M_RD, 1, &reg },
-		};
-
-		xfer = i2c_transfer(client->adapter, msgs, 2);
-
-		if (xfer != 2) {
-			dev_err(&client->adapter->dev,
-				"%s: could not read register %x\n",
-				__FUNCTION__, addr[1]);
-
-			return -EIO;
-		}
-
-		value = BCD2BIN(reg & probe_limits_pattern[i].mask);
-
-		if (value > probe_limits_pattern[i].max ||
-			value < probe_limits_pattern[i].min) {
-			dev_dbg(&client->adapter->dev,
-				"%s: register=%x, lim pattern=%d, value=%d\n",
-				__FUNCTION__, addr[1], i, value);
-
-			return -ENODEV;
-		}
-	}
-
-	return 0;
-}
-
-static int x1205_attach(struct i2c_adapter *adapter)
-{
-	dev_dbg(&adapter->dev, "%s\n", __FUNCTION__);
-
-	return i2c_probe(adapter, &addr_data, x1205_probe);
-}
-
-int x1205_direct_attach(int adapter_id,
-	struct i2c_client_address_data *address_data)
-{
-	int err;
-	struct i2c_adapter *adapter = i2c_get_adapter(adapter_id);
-
-	if (adapter) {
-		err = i2c_probe(adapter,
-			address_data, x1205_probe);
-
-		i2c_put_adapter(adapter);
-
-		return err;
-	}
-
-	return -ENODEV;
-}
-
-static int x1205_probe(struct i2c_adapter *adapter, int address, int kind)
-{
-	struct i2c_client *client;
-	struct x1205_data *data;
-
-	int err = 0;
-
-	dev_dbg(&adapter->dev, "%s\n", __FUNCTION__);
-
-	if (!i2c_check_functionality(adapter, I2C_FUNC_I2C)) {
-		err = -ENODEV;
-		goto exit;
-	}
-
-	if (!(data = kzalloc(sizeof(struct x1205_data), GFP_KERNEL))) {
-		err = -ENOMEM;
-		goto exit;
-	}
-
-	/* Initialize our structures */
-	data->epoch = 2000;
-
-	client = &data->client;
-	client->addr = address;
-	client->driver = &x1205_driver;
-	client->adapter	= adapter;
-
-	strlcpy(client->name, "x1205", I2C_NAME_SIZE);
-
-	i2c_set_clientdata(client, data);
-
-	/* Verify the chip is really an X1205 */
-	if (kind < 0) {
-		if (x1205_validate_client(client) < 0) {
-			err = -ENODEV;
-			goto exit_kfree;
-		}
-	}
-
-	/* Inform the i2c layer */
-	if ((err = i2c_attach_client(client)))
-		goto exit_kfree;
-
-	list_add(&data->list, &x1205_clients);
-
-	dev_info(&client->dev, "chip found, driver version " DRV_VERSION "\n");
-
-	/* If requested, set the system time */
-	if (hctosys)
-		x1205_hctosys(client);
-
-	return 0;
-
-exit_kfree:
-	kfree(data);
-
-exit:
-	return err;
-}
-
-static int x1205_detach(struct i2c_client *client)
-{
-	int err;
-	struct x1205_data *data = i2c_get_clientdata(client);
-
-	dev_dbg(&client->dev, "%s\n", __FUNCTION__);
-
-	if ((err = i2c_detach_client(client)))
-		return err;
-
-	list_del(&data->list);
-
-	kfree(data);
-
-	return 0;
-}
-
-static int x1205_command(struct i2c_client *client, unsigned int cmd,
-	void *param)
-{
-	if (param == NULL)
-		return -EINVAL;
-
-	if (!capable(CAP_SYS_TIME))
-		return -EACCES;
-
-	dev_dbg(&client->dev, "%s: cmd=%d\n", __FUNCTION__, cmd);
-
-	switch (cmd) {
-	case X1205_CMD_GETDATETIME:
-		return x1205_get_datetime(client, param, X1205_CCR_BASE);
-
-	case X1205_CMD_SETTIME:
-		return x1205_set_datetime(client, param, 0,
-				X1205_CCR_BASE);
-
-	case X1205_CMD_SETDATETIME:
-		return x1205_set_datetime(client, param, 1,
-				X1205_CCR_BASE);
-
-	case X1205_CMD_GETALARM:
-		return x1205_get_datetime(client, param, X1205_ALM0_BASE);
-
-	case X1205_CMD_SETALARM:
-		return x1205_set_datetime(client, param, 1,
-				X1205_ALM0_BASE);
-
-	case X1205_CMD_GETDTRIM:
-		return x1205_get_dtrim(client, param);
-
-	case X1205_CMD_GETATRIM:
-		return x1205_get_atrim(client, param);
-
-	default:
-		return -EINVAL;
-	}
-}
-
-static int __init x1205_init(void)
-{
-	return i2c_add_driver(&x1205_driver);
-}
-
-static void __exit x1205_exit(void)
-{
-	i2c_del_driver(&x1205_driver);
-}
-
-MODULE_AUTHOR(
-	"Karen Spearel <kas11@tampabay.rr.com>, "
-	"Alessandro Zummo <a.zummo@towertech.it>");
-MODULE_DESCRIPTION("Xicor X1205 RTC driver");
-MODULE_LICENSE("GPL");
-MODULE_VERSION(DRV_VERSION);
-
-EXPORT_SYMBOL_GPL(x1205_do_command);
-EXPORT_SYMBOL_GPL(x1205_direct_attach);
-
-module_init(x1205_init);
-module_exit(x1205_exit);
--- linux-ixp4xx.orig/drivers/i2c/chips/Makefile	2006-03-08 01:59:09.000000000 +0100
+++ linux-ixp4xx/drivers/i2c/chips/Makefile	2006-03-08 01:59:26.000000000 +0100
@@ -10,10 +10,8 @@ obj-$(CONFIG_SENSORS_M41T00)	+= m41t00.o
 obj-$(CONFIG_SENSORS_PCA9539)	+= pca9539.o
 obj-$(CONFIG_SENSORS_PCF8574)	+= pcf8574.o
 obj-$(CONFIG_SENSORS_PCF8591)	+= pcf8591.o
-obj-$(CONFIG_SENSORS_RTC8564)	+= rtc8564.o
 obj-$(CONFIG_ISP1301_OMAP)	+= isp1301_omap.o
 obj-$(CONFIG_TPS65010)		+= tps65010.o
-obj-$(CONFIG_RTC_X1205_I2C)	+= x1205.o
 
 ifeq ($(CONFIG_I2C_DEBUG_CHIP),y)
 EXTRA_CFLAGS += -DDEBUG
--- linux-ixp4xx.orig/drivers/i2c/chips/rtc8564.c	2006-03-08 01:59:09.000000000 +0100
+++ /dev/null	1970-01-01 00:00:00.000000000 +0000
@@ -1,385 +0,0 @@
-/*
- *  linux/drivers/i2c/chips/rtc8564.c
- *
- *  Copyright (C) 2002-2004 Stefan Eletzhofer
- *
- *	based on linux/drivers/acron/char/pcf8583.c
- *  Copyright (C) 2000 Russell King
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * Driver for system3's EPSON RTC 8564 chip
- */
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/bcd.h>
-#include <linux/i2c.h>
-#include <linux/slab.h>
-#include <linux/string.h>
-#include <linux/rtc.h>		/* get the user-level API */
-#include <linux/init.h>
-
-#include "rtc8564.h"
-
-#ifdef DEBUG
-# define _DBG(x, fmt, args...) do{ if (debug>=x) printk(KERN_DEBUG"%s: " fmt "\n", __FUNCTION__, ##args); } while(0);
-#else
-# define _DBG(x, fmt, args...) do { } while(0);
-#endif
-
-#define _DBGRTCTM(x, rtctm) if (debug>=x) printk("%s: secs=%d, mins=%d, hours=%d, mday=%d, " \
-			"mon=%d, year=%d, wday=%d VL=%d\n", __FUNCTION__, \
-			(rtctm).secs, (rtctm).mins, (rtctm).hours, (rtctm).mday, \
-			(rtctm).mon, (rtctm).year, (rtctm).wday, (rtctm).vl);
-
-struct rtc8564_data {
-	struct i2c_client client;
-	u16 ctrl;
-};
-
-static inline u8 _rtc8564_ctrl1(struct i2c_client *client)
-{
-	struct rtc8564_data *data = i2c_get_clientdata(client);
-	return data->ctrl & 0xff;
-}
-static inline u8 _rtc8564_ctrl2(struct i2c_client *client)
-{
-	struct rtc8564_data *data = i2c_get_clientdata(client);
-	return (data->ctrl & 0xff00) >> 8;
-}
-
-#define CTRL1(c) _rtc8564_ctrl1(c)
-#define CTRL2(c) _rtc8564_ctrl2(c)
-
-static int debug;;
-module_param(debug, int, S_IRUGO | S_IWUSR);
-
-static struct i2c_driver rtc8564_driver;
-
-static unsigned short ignore[] = { I2C_CLIENT_END };
-static unsigned short normal_addr[] = { 0x51, I2C_CLIENT_END };
-
-static struct i2c_client_address_data addr_data = {
-	.normal_i2c		= normal_addr,
-	.probe			= ignore,
-	.ignore			= ignore,
-};
-
-static int rtc8564_read_mem(struct i2c_client *client, struct mem *mem);
-static int rtc8564_write_mem(struct i2c_client *client, struct mem *mem);
-
-static int rtc8564_read(struct i2c_client *client, unsigned char adr,
-			unsigned char *buf, unsigned char len)
-{
-	int ret = -EIO;
-	unsigned char addr[1] = { adr };
-	struct i2c_msg msgs[2] = {
-		{client->addr, 0, 1, addr},
-		{client->addr, I2C_M_RD, len, buf}
-	};
-
-	_DBG(1, "client=%p, adr=%d, buf=%p, len=%d", client, adr, buf, len);
-
-	if (!buf) {
-		ret = -EINVAL;
-		goto done;
-	}
-
-	ret = i2c_transfer(client->adapter, msgs, 2);
-	if (ret == 2) {
-		ret = 0;
-	}
-
-done:
-	return ret;
-}
-
-static int rtc8564_write(struct i2c_client *client, unsigned char adr,
-			 unsigned char *data, unsigned char len)
-{
-	int ret = 0;
-	unsigned char _data[16];
-	struct i2c_msg wr;
-	int i;
-
-	if (!data || len > 15) {
-		ret = -EINVAL;
-		goto done;
-	}
-
-	_DBG(1, "client=%p, adr=%d, buf=%p, len=%d", client, adr, data, len);
-
-	_data[0] = adr;
-	for (i = 0; i < len; i++) {
-		_data[i + 1] = data[i];
-		_DBG(5, "data[%d] = 0x%02x (%d)", i, data[i], data[i]);
-	}
-
-	wr.addr = client->addr;
-	wr.flags = 0;
-	wr.len = len + 1;
-	wr.buf = _data;
-
-	ret = i2c_transfer(client->adapter, &wr, 1);
-	if (ret == 1) {
-		ret = 0;
-	}
-
-done:
-	return ret;
-}
-
-static int rtc8564_attach(struct i2c_adapter *adap, int addr, int kind)
-{
-	int ret;
-	struct i2c_client *new_client;
-	struct rtc8564_data *d;
-	unsigned char data[10];
-	unsigned char ad[1] = { 0 };
-	struct i2c_msg ctrl_wr[1] = {
-		{addr, 0, 2, data}
-	};
-	struct i2c_msg ctrl_rd[2] = {
-		{addr, 0, 1, ad},
-		{addr, I2C_M_RD, 2, data}
-	};
-
-	d = kzalloc(sizeof(struct rtc8564_data), GFP_KERNEL);
-	if (!d) {
-		ret = -ENOMEM;
-		goto done;
-	}
-	new_client = &d->client;
-
-	strlcpy(new_client->name, "RTC8564", I2C_NAME_SIZE);
-	i2c_set_clientdata(new_client, d);
-	new_client->addr = addr;
-	new_client->adapter = adap;
-	new_client->driver = &rtc8564_driver;
-
-	_DBG(1, "client=%p", new_client);
-
-	/* init ctrl1 reg */
-	data[0] = 0;
-	data[1] = 0;
-	ret = i2c_transfer(new_client->adapter, ctrl_wr, 1);
-	if (ret != 1) {
-		printk(KERN_INFO "rtc8564: cant init ctrl1\n");
-		ret = -ENODEV;
-		goto done;
-	}
-
-	/* read back ctrl1 and ctrl2 */
-	ret = i2c_transfer(new_client->adapter, ctrl_rd, 2);
-	if (ret != 2) {
-		printk(KERN_INFO "rtc8564: cant read ctrl\n");
-		ret = -ENODEV;
-		goto done;
-	}
-
-	d->ctrl = data[0] | (data[1] << 8);
-
-	_DBG(1, "RTC8564_REG_CTRL1=%02x, RTC8564_REG_CTRL2=%02x",
-	     data[0], data[1]);
-
-	ret = i2c_attach_client(new_client);
-done:
-	if (ret) {
-		kfree(d);
-	}
-	return ret;
-}
-
-static int rtc8564_probe(struct i2c_adapter *adap)
-{
-	return i2c_probe(adap, &addr_data, rtc8564_attach);
-}
-
-static int rtc8564_detach(struct i2c_client *client)
-{
-	i2c_detach_client(client);
-	kfree(i2c_get_clientdata(client));
-	return 0;
-}
-
-static int rtc8564_get_datetime(struct i2c_client *client, struct rtc_tm *dt)
-{
-	int ret = -EIO;
-	unsigned char buf[15];
-
-	_DBG(1, "client=%p, dt=%p", client, dt);
-
-	if (!dt)
-		return -EINVAL;
-
-	memset(buf, 0, sizeof(buf));
-
-	ret = rtc8564_read(client, 0, buf, 15);
-	if (ret)
-		return ret;
-
-	/* century stored in minute alarm reg */
-	dt->year = BCD2BIN(buf[RTC8564_REG_YEAR]);
-	dt->year += 100 * BCD2BIN(buf[RTC8564_REG_AL_MIN] & 0x3f);
-	dt->mday = BCD2BIN(buf[RTC8564_REG_DAY] & 0x3f);
-	dt->wday = BCD2BIN(buf[RTC8564_REG_WDAY] & 7);
-	dt->mon = BCD2BIN(buf[RTC8564_REG_MON_CENT] & 0x1f);
-
-	dt->secs = BCD2BIN(buf[RTC8564_REG_SEC] & 0x7f);
-	dt->vl = (buf[RTC8564_REG_SEC] & 0x80) == 0x80;
-	dt->mins = BCD2BIN(buf[RTC8564_REG_MIN] & 0x7f);
-	dt->hours = BCD2BIN(buf[RTC8564_REG_HR] & 0x3f);
-
-	_DBGRTCTM(2, *dt);
-
-	return 0;
-}
-
-static int
-rtc8564_set_datetime(struct i2c_client *client, struct rtc_tm *dt, int datetoo)
-{
-	int ret, len = 5;
-	unsigned char buf[15];
-
-	_DBG(1, "client=%p, dt=%p", client, dt);
-
-	if (!dt)
-		return -EINVAL;
-
-	_DBGRTCTM(2, *dt);
-
-	buf[RTC8564_REG_CTRL1] = CTRL1(client) | RTC8564_CTRL1_STOP;
-	buf[RTC8564_REG_CTRL2] = CTRL2(client);
-	buf[RTC8564_REG_SEC] = BIN2BCD(dt->secs);
-	buf[RTC8564_REG_MIN] = BIN2BCD(dt->mins);
-	buf[RTC8564_REG_HR] = BIN2BCD(dt->hours);
-
-	if (datetoo) {
-		len += 5;
-		buf[RTC8564_REG_DAY] = BIN2BCD(dt->mday);
-		buf[RTC8564_REG_WDAY] = BIN2BCD(dt->wday);
-		buf[RTC8564_REG_MON_CENT] = BIN2BCD(dt->mon) & 0x1f;
-		/* century stored in minute alarm reg */
-		buf[RTC8564_REG_YEAR] = BIN2BCD(dt->year % 100);
-		buf[RTC8564_REG_AL_MIN] = BIN2BCD(dt->year / 100);
-	}
-
-	ret = rtc8564_write(client, 0, buf, len);
-	if (ret) {
-		_DBG(1, "error writing data! %d", ret);
-	}
-
-	buf[RTC8564_REG_CTRL1] = CTRL1(client);
-	ret = rtc8564_write(client, 0, buf, 1);
-	if (ret) {
-		_DBG(1, "error writing data! %d", ret);
-	}
-
-	return ret;
-}
-
-static int rtc8564_get_ctrl(struct i2c_client *client, unsigned int *ctrl)
-{
-	struct rtc8564_data *data = i2c_get_clientdata(client);
-
-	if (!ctrl)
-		return -1;
-
-	*ctrl = data->ctrl;
-	return 0;
-}
-
-static int rtc8564_set_ctrl(struct i2c_client *client, unsigned int *ctrl)
-{
-	struct rtc8564_data *data = i2c_get_clientdata(client);
-	unsigned char buf[2];
-
-	if (!ctrl)
-		return -1;
-
-	buf[0] = *ctrl & 0xff;
-	buf[1] = (*ctrl & 0xff00) >> 8;
-	data->ctrl = *ctrl;
-
-	return rtc8564_write(client, 0, buf, 2);
-}
-
-static int rtc8564_read_mem(struct i2c_client *client, struct mem *mem)
-{
-
-	if (!mem)
-		return -EINVAL;
-
-	return rtc8564_read(client, mem->loc, mem->data, mem->nr);
-}
-
-static int rtc8564_write_mem(struct i2c_client *client, struct mem *mem)
-{
-
-	if (!mem)
-		return -EINVAL;
-
-	return rtc8564_write(client, mem->loc, mem->data, mem->nr);
-}
-
-static int
-rtc8564_command(struct i2c_client *client, unsigned int cmd, void *arg)
-{
-
-	_DBG(1, "cmd=%d", cmd);
-
-	switch (cmd) {
-	case RTC_GETDATETIME:
-		return rtc8564_get_datetime(client, arg);
-
-	case RTC_SETTIME:
-		return rtc8564_set_datetime(client, arg, 0);
-
-	case RTC_SETDATETIME:
-		return rtc8564_set_datetime(client, arg, 1);
-
-	case RTC_GETCTRL:
-		return rtc8564_get_ctrl(client, arg);
-
-	case RTC_SETCTRL:
-		return rtc8564_set_ctrl(client, arg);
-
-	case MEM_READ:
-		return rtc8564_read_mem(client, arg);
-
-	case MEM_WRITE:
-		return rtc8564_write_mem(client, arg);
-
-	default:
-		return -EINVAL;
-	}
-}
-
-static struct i2c_driver rtc8564_driver = {
-	.driver = {
-		.name	= "RTC8564",
-	},
-	.id		= I2C_DRIVERID_RTC8564,
-	.attach_adapter = rtc8564_probe,
-	.detach_client	= rtc8564_detach,
-	.command	= rtc8564_command
-};
-
-static __init int rtc8564_init(void)
-{
-	return i2c_add_driver(&rtc8564_driver);
-}
-
-static __exit void rtc8564_exit(void)
-{
-	i2c_del_driver(&rtc8564_driver);
-}
-
-MODULE_AUTHOR("Stefan Eletzhofer <Stefan.Eletzhofer@eletztrick.de>");
-MODULE_DESCRIPTION("EPSON RTC8564 Driver");
-MODULE_LICENSE("GPL");
-
-module_init(rtc8564_init);
-module_exit(rtc8564_exit);
--- linux-ixp4xx.orig/drivers/i2c/chips/rtc8564.h	2006-03-08 01:59:09.000000000 +0100
+++ /dev/null	1970-01-01 00:00:00.000000000 +0000
@@ -1,78 +0,0 @@
-/*
- *  linux/drivers/i2c/chips/rtc8564.h
- *
- *  Copyright (C) 2002-2004 Stefan Eletzhofer
- *
- *	based on linux/drivers/acron/char/pcf8583.h
- *  Copyright (C) 2000 Russell King
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- */
-struct rtc_tm {
-	unsigned char	secs;
-	unsigned char	mins;
-	unsigned char	hours;
-	unsigned char	mday;
-	unsigned char	mon;
-	unsigned short	year; /* xxxx 4 digits :) */
-	unsigned char	wday;
-	unsigned char	vl;
-};
-
-struct mem {
-	unsigned int	loc;
-	unsigned int	nr;
-	unsigned char	*data;
-};
-
-#define RTC_GETDATETIME	0
-#define RTC_SETTIME	1
-#define RTC_SETDATETIME	2
-#define RTC_GETCTRL	3
-#define RTC_SETCTRL	4
-#define MEM_READ	5
-#define MEM_WRITE	6
-
-#define RTC8564_REG_CTRL1		0x0 /* T  0 S 0 | T 0 0 0 */
-#define RTC8564_REG_CTRL2		0x1 /* 0  0 0 TI/TP | AF TF AIE TIE */
-#define RTC8564_REG_SEC			0x2 /* VL 4 2 1 | 8 4 2 1 */
-#define RTC8564_REG_MIN			0x3 /* x  4 2 1 | 8 4 2 1 */
-#define RTC8564_REG_HR			0x4 /* x  x 2 1 | 8 4 2 1 */
-#define RTC8564_REG_DAY			0x5 /* x  x 2 1 | 8 4 2 1 */
-#define RTC8564_REG_WDAY		0x6 /* x  x x x | x 4 2 1 */
-#define RTC8564_REG_MON_CENT	0x7 /* C  x x 1 | 8 4 2 1 */
-#define RTC8564_REG_YEAR		0x8 /* 8  4 2 1 | 8 4 2 1 */
-#define RTC8564_REG_AL_MIN		0x9 /* AE 4 2 1 | 8 4 2 1 */
-#define RTC8564_REG_AL_HR		0xa /* AE 4 2 1 | 8 4 2 1 */
-#define RTC8564_REG_AL_DAY		0xb /* AE x 2 1 | 8 4 2 1 */
-#define RTC8564_REG_AL_WDAY		0xc /* AE x x x | x 4 2 1 */
-#define RTC8564_REG_CLKOUT		0xd /* FE x x x | x x FD1 FD0 */
-#define RTC8564_REG_TCTL		0xe /* TE x x x | x x FD1 FD0 */
-#define RTC8564_REG_TIMER		0xf /* 8 bit binary */
-
-/* Control reg */
-#define RTC8564_CTRL1_TEST1		(1<<3)
-#define RTC8564_CTRL1_STOP		(1<<5)
-#define RTC8564_CTRL1_TEST2		(1<<7)
-
-#define RTC8564_CTRL2_TIE		(1<<0)
-#define RTC8564_CTRL2_AIE		(1<<1)
-#define RTC8564_CTRL2_TF		(1<<2)
-#define RTC8564_CTRL2_AF		(1<<3)
-#define RTC8564_CTRL2_TI_TP		(1<<4)
-
-/* CLKOUT frequencies */
-#define RTC8564_FD_32768HZ		(0x0)
-#define RTC8564_FD_1024HZ		(0x1)
-#define RTC8564_FD_32			(0x2)
-#define RTC8564_FD_1HZ			(0x3)
-
-/* Timer CTRL */
-#define RTC8564_TD_4096HZ		(0x0)
-#define RTC8564_TD_64HZ			(0x1)
-#define RTC8564_TD_1HZ			(0x2)
-#define RTC8564_TD_1_60HZ		(0x3)
-
-#define I2C_DRIVERID_RTC8564 0xf000
--- linux-ixp4xx.orig/include/linux/x1205.h	2006-03-08 01:59:09.000000000 +0100
+++ /dev/null	1970-01-01 00:00:00.000000000 +0000
@@ -1,31 +0,0 @@
-/*
- *  x1205.h - defines for drivers/i2c/chips/x1205.c
- *  Copyright 2004 Karen Spearel
- *  Copyright 2005 Alessandro Zummo
- *
- *  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.
- */
-
-#ifndef __LINUX_X1205_H__
-#define __LINUX_X1205_H__
-
-/* commands */
-
-#define X1205_CMD_GETDATETIME	0
-#define X1205_CMD_SETTIME	1
-#define X1205_CMD_SETDATETIME	2
-#define X1205_CMD_GETALARM	3
-#define X1205_CMD_SETALARM	4
-#define X1205_CMD_GETDTRIM	5
-#define X1205_CMD_SETDTRIM	6
-#define X1205_CMD_GETATRIM	7
-#define X1205_CMD_SETATRIM	8
-
-extern int x1205_do_command(unsigned int cmd, void *arg);
-extern int x1205_direct_attach(int adapter_id,
-	struct i2c_client_address_data *address_data);
-
-#endif /* __LINUX_X1205_H__ */
--- linux-ixp4xx.orig/drivers/i2c/chips/Kconfig	2006-03-08 01:59:09.000000000 +0100
1+++ linux-ixp4xx/drivers/i2c/chips/Kconfig	2006-03-08 01:59:26.000000000 +0100
@@ -74,15 +74,6 @@ config SENSORS_RTC8564
 	  This driver can also be built as a module.  If so, the module
 	  will be called pcf8591.
 
-config SENSORS_RTC8564
-	tristate "Epson 8564 RTC chip"
-	depends on I2C && EXPERIMENTAL
-	help
-	  If you say yes here you get support for the Epson 8564 RTC chip.
-
-	  This driver can also be built as a module.  If so, the module
-	  will be called i2c-rtc8564.
-
 config ISP1301_OMAP
 	tristate "Philips ISP1301 with OMAP OTG"
 	depends on I2C && ARCH_OMAP_OTG
@@ -144,13 +135,4 @@ config RTC_X1205_I2C
 	  This driver can also be built as a module.  If so, the module
 	  will be called max6875.
 
-config RTC_X1205_I2C
-	tristate "Xicor X1205 RTC chip"
-	depends on I2C && EXPERIMENTAL
-	help
-	  If you say yes here you get support for the Xicor X1205 RTC chip.
-
-	  This driver can also be built as a module. If so, the module
-	  will be called x1205.
-
 endmenu
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ linux-ixp4xx/drivers/rtc/rtc-sysfs.c	2006-03-08 01:59:26.000000000 +0100
@@ -0,0 +1,124 @@
+/*
+ * RTC subsystem, sysfs interface
+ *
+ * Copyright (C) 2005 Tower Technologies
+ * Author: Alessandro Zummo <a.zummo@towertech.it>
+ *
+ * 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; version 2 of the License.
+*/
+
+#include <linux/module.h>
+#include <linux/rtc.h>
+
+/* device attributes */
+
+static ssize_t rtc_sysfs_show_name(struct class_device *dev, char *buf)
+{
+	return sprintf(buf, "%s\n", to_rtc_device(dev)->name);
+}
+static CLASS_DEVICE_ATTR(name, S_IRUGO, rtc_sysfs_show_name, NULL);
+
+static ssize_t rtc_sysfs_show_date(struct class_device *dev, char *buf)
+{
+	ssize_t retval;
+	struct rtc_time tm;
+
+	retval = rtc_read_time(dev, &tm);
+	if (retval == 0) {
+		retval = sprintf(buf, "%04d-%02d-%02d\n",
+			tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday);
+	}
+
+	return retval;
+}
+static CLASS_DEVICE_ATTR(date, S_IRUGO, rtc_sysfs_show_date, NULL);
+
+static ssize_t rtc_sysfs_show_time(struct class_device *dev, char *buf)
+{
+	ssize_t retval;
+	struct rtc_time tm;
+
+	retval = rtc_read_time(dev, &tm);
+	if (retval == 0) {
+		retval = sprintf(buf, "%02d:%02d:%02d\n",
+			tm.tm_hour, tm.tm_min, tm.tm_sec);
+	}
+
+	return retval;
+}
+static CLASS_DEVICE_ATTR(time, S_IRUGO, rtc_sysfs_show_time, NULL);
+
+static ssize_t rtc_sysfs_show_since_epoch(struct class_device *dev, char *buf)
+{
+	ssize_t retval;
+	struct rtc_time tm;
+
+	retval = rtc_read_time(dev, &tm);
+	if (retval == 0) {
+		unsigned long time;
+		rtc_tm_to_time(&tm, &time);
+		retval = sprintf(buf, "%lu\n", time);
+	}
+
+	return retval;
+}
+static CLASS_DEVICE_ATTR(since_epoch, S_IRUGO, rtc_sysfs_show_since_epoch, NULL);
+
+static struct attribute *rtc_attrs[] = {
+	&class_device_attr_name.attr,
+	&class_device_attr_date.attr,
+	&class_device_attr_time.attr,
+	&class_device_attr_since_epoch.attr,
+	NULL,
+};
+
+static struct attribute_group rtc_attr_group = {
+	.attrs = rtc_attrs,
+};
+
+static int __devinit rtc_sysfs_add_device(struct class_device *class_dev,
+					struct class_interface *class_intf)
+{
+	int err;
+
+	dev_info(class_dev->dev, "rtc intf: sysfs\n");
+
+	err = sysfs_create_group(&class_dev->kobj, &rtc_attr_group);
+	if (err)
+		dev_err(class_dev->dev,
+			"failed to create sysfs attributes\n");
+
+	return err;
+}
+
+static void rtc_sysfs_remove_device(struct class_device *class_dev,
+				struct class_interface *class_intf)
+{
+	sysfs_remove_group(&class_dev->kobj, &rtc_attr_group);
+}
+
+/* interface registration */
+
+static struct class_interface rtc_sysfs_interface = {
+	.add = &rtc_sysfs_add_device,
+	.remove = &rtc_sysfs_remove_device,
+};
+
+static int __init rtc_sysfs_init(void)
+{
+	return rtc_interface_register(&rtc_sysfs_interface);
+}
+
+static void __exit rtc_sysfs_exit(void)
+{
+	class_interface_unregister(&rtc_sysfs_interface);
+}
+
+module_init(rtc_sysfs_init);
+module_exit(rtc_sysfs_exit);
+
+MODULE_AUTHOR("Alessandro Zummo <a.zummo@towertech.it>");
+MODULE_DESCRIPTION("RTC class sysfs interface");
+MODULE_LICENSE("GPL");
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ linux-ixp4xx/drivers/rtc/rtc-proc.c	2006-03-08 01:59:26.000000000 +0100
@@ -0,0 +1,162 @@
+/*
+ * RTC subsystem, proc interface
+ *
+ * Copyright (C) 2005-06 Tower Technologies
+ * Author: Alessandro Zummo <a.zummo@towertech.it>
+ *
+ * based on arch/arm/common/rtctime.c
+ *
+ * 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; version 2 of the License.
+*/
+
+#include <linux/module.h>
+#include <linux/rtc.h>
+#include <linux/proc_fs.h>
+#include <linux/seq_file.h>
+
+static struct class_device *rtc_dev = NULL;
+static DEFINE_MUTEX(rtc_lock);
+
+static int rtc_proc_show(struct seq_file *seq, void *offset)
+{
+	int err;
+	struct class_device *class_dev = seq->private;
+	struct rtc_class_ops *ops = to_rtc_device(class_dev)->ops;
+	struct rtc_wkalrm alrm;
+	struct rtc_time tm;
+
+	err = rtc_read_time(class_dev, &tm);
+	if (err == 0) {
+		seq_printf(seq,
+			"rtc_time\t: %02d:%02d:%02d\n"
+			"rtc_date\t: %04d-%02d-%02d\n",
+			tm.tm_hour, tm.tm_min, tm.tm_sec,
+			tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday);
+	}
+
+	err = rtc_read_alarm(class_dev, &alrm);
+	if (err == 0) {
+		seq_printf(seq, "alrm_time\t: ");
+		if ((unsigned int)alrm.time.tm_hour <= 24)
+			seq_printf(seq, "%02d:", alrm.time.tm_hour);
+		else
+			seq_printf(seq, "**:");
+		if ((unsigned int)alrm.time.tm_min <= 59)
+			seq_printf(seq, "%02d:", alrm.time.tm_min);
+		else
+			seq_printf(seq, "**:");
+		if ((unsigned int)alrm.time.tm_sec <= 59)
+			seq_printf(seq, "%02d\n", alrm.time.tm_sec);
+		else
+			seq_printf(seq, "**\n");
+
+		seq_printf(seq, "alrm_date\t: ");
+		if ((unsigned int)alrm.time.tm_year <= 200)
+			seq_printf(seq, "%04d-", alrm.time.tm_year + 1900);
+		else
+			seq_printf(seq, "****-");
+		if ((unsigned int)alrm.time.tm_mon <= 11)
+			seq_printf(seq, "%02d-", alrm.time.tm_mon + 1);
+		else
+			seq_printf(seq, "**-");
+		if ((unsigned int)alrm.time.tm_mday <= 31)
+			seq_printf(seq, "%02d\n", alrm.time.tm_mday);
+		else
+			seq_printf(seq, "**\n");
+		seq_printf(seq, "alrm_wakeup\t: %s\n",
+				alrm.enabled ? "yes" : "no");
+		seq_printf(seq, "alrm_pending\t: %s\n",
+				alrm.pending ? "yes" : "no");
+	}
+
+	if (ops->proc)
+		ops->proc(class_dev->dev, seq);
+
+	return 0;
+}
+
+static int rtc_proc_open(struct inode *inode, struct file *file)
+{
+	struct class_device *class_dev = PDE(inode)->data;
+
+	if (!try_module_get(THIS_MODULE))
+		return -ENODEV;
+
+	return single_open(file, rtc_proc_show, class_dev);
+}
+
+static int rtc_proc_release(struct inode *inode, struct file *file)
+{
+	int res = single_release(inode, file);
+	module_put(THIS_MODULE);
+	return res;
+}
+
+static struct file_operations rtc_proc_fops = {
+	.open		= rtc_proc_open,
+	.read		= seq_read,
+	.llseek		= seq_lseek,
+	.release	= rtc_proc_release,
+};
+
+static int rtc_proc_add_device(struct class_device *class_dev,
+					struct class_interface *class_intf)
+{
+	mutex_lock(&rtc_lock);
+	if (rtc_dev == NULL) {
+		struct proc_dir_entry *ent;
+
+		rtc_dev = class_dev;
+
+		ent = create_proc_entry("driver/rtc", 0, NULL);
+		if (ent) {
+			struct rtc_device *rtc = to_rtc_device(class_dev);
+
+			ent->proc_fops = &rtc_proc_fops;
+			ent->owner = rtc->owner;
+			ent->data = class_dev;
+
+			dev_info(class_dev->dev, "rtc intf: proc\n");
+		}
+		else
+			rtc_dev = NULL;
+	}
+	mutex_unlock(&rtc_lock);
+
+	return 0;
+}
+
+static void rtc_proc_remove_device(struct class_device *class_dev,
+					struct class_interface *class_intf)
+{
+	mutex_lock(&rtc_lock);
+	if (rtc_dev == class_dev) {
+		remove_proc_entry("driver/rtc", NULL);
+		rtc_dev = NULL;
+	}
+	mutex_unlock(&rtc_lock);
+}
+
+static struct class_interface rtc_proc_interface = {
+	.add = &rtc_proc_add_device,
+	.remove = &rtc_proc_remove_device,
+};
+
+static int __init rtc_proc_init(void)
+{
+	return rtc_interface_register(&rtc_proc_interface);
+}
+
+static void __exit rtc_proc_exit(void)
+{
+	class_interface_unregister(&rtc_proc_interface);
+}
+
+module_init(rtc_proc_init);
+module_exit(rtc_proc_exit);
+
+MODULE_AUTHOR("Alessandro Zummo <a.zummo@towertech.it>");
+MODULE_DESCRIPTION("RTC class proc interface");
+MODULE_LICENSE("GPL");
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ linux-ixp4xx/drivers/rtc/rtc-dev.c	2006-03-08 01:59:26.000000000 +0100
@@ -0,0 +1,382 @@
+/*
+ * RTC subsystem, dev interface
+ *
+ * Copyright (C) 2005 Tower Technologies
+ * Author: Alessandro Zummo <a.zummo@towertech.it>
+ *
+ * based on arch/arm/common/rtctime.c
+ *
+ * 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; version 2 of the License.
+*/
+
+#include <linux/module.h>
+#include <linux/rtc.h>
+
+static struct class *rtc_dev_class;
+static dev_t rtc_devt;
+
+#define RTC_DEV_MAX 16 /* 16 RTCs should be enough for everyone... */
+
+static int rtc_dev_open(struct inode *inode, struct file *file)
+{
+	int err;
+	struct rtc_device *rtc = container_of(inode->i_cdev,
+					struct rtc_device, char_dev);
+	struct rtc_class_ops *ops = rtc->ops;
+
+	/* We keep the lock as long as the device is in use
+	 * and return immediately if busy
+	 */
+	if (!(mutex_trylock(&rtc->char_lock)))
+		return -EBUSY;
+
+	file->private_data = &rtc->class_dev;
+
+	err = ops->open ? ops->open(rtc->class_dev.dev) : 0;
+	if (err == 0) {
+		spin_lock_irq(&rtc->irq_lock);
+		rtc->irq_data = 0;
+		spin_unlock_irq(&rtc->irq_lock);
+
+		return 0;
+	}
+
+	/* something has gone wrong, release the lock */
+	mutex_unlock(&rtc->char_lock);
+	return err;
+}
+
+
+static ssize_t
+rtc_dev_read(struct file *file, char __user *buf, size_t count, loff_t *ppos)
+{
+	struct rtc_device *rtc = to_rtc_device(file->private_data);
+
+	DECLARE_WAITQUEUE(wait, current);
+	unsigned long data;
+	ssize_t ret;
+
+	if (count < sizeof(unsigned long))
+		return -EINVAL;
+
+	add_wait_queue(&rtc->irq_queue, &wait);
+	do {
+		__set_current_state(TASK_INTERRUPTIBLE);
+
+		spin_lock_irq(&rtc->irq_lock);
+		data = rtc->irq_data;
+		rtc->irq_data = 0;
+		spin_unlock_irq(&rtc->irq_lock);
+
+		if (data != 0) {
+			ret = 0;
+			break;
+		}
+		if (file->f_flags & O_NONBLOCK) {
+			ret = -EAGAIN;
+			break;
+		}
+		if (signal_pending(current)) {
+			ret = -ERESTARTSYS;
+			break;
+		}
+		schedule();
+	} while (1);
+	set_current_state(TASK_RUNNING);
+	remove_wait_queue(&rtc->irq_queue, &wait);
+
+	if (ret == 0) {
+		/* Check for any data updates */
+		if (rtc->ops->read_callback)
+			data = rtc->ops->read_callback(rtc->class_dev.dev, data);
+
+		ret = put_user(data, (unsigned long __user *)buf);
+		if (ret == 0)
+			ret = sizeof(unsigned long);
+	}
+	return ret;
+}
+
+static unsigned int rtc_dev_poll(struct file *file, poll_table *wait)
+{
+	struct rtc_device *rtc = to_rtc_device(file->private_data);
+	unsigned long data;
+
+	poll_wait(file, &rtc->irq_queue, wait);
+
+	data = rtc->irq_data;
+
+	return (data != 0) ? (POLLIN | POLLRDNORM) : 0;
+}
+
+static int rtc_dev_ioctl(struct inode *inode, struct file *file,
+		unsigned int cmd, unsigned long arg)
+{
+	int err = 0;
+	struct class_device *class_dev = file->private_data;
+	struct rtc_device *rtc = to_rtc_device(class_dev);
+	struct rtc_class_ops *ops = rtc->ops;
+	struct rtc_time tm;
+	struct rtc_wkalrm alarm;
+	void __user *uarg = (void __user *) arg;
+
+	/* avoid conflicting IRQ users */
+	if (cmd == RTC_PIE_ON || cmd == RTC_PIE_OFF || cmd == RTC_IRQP_SET) {
+		spin_lock(&rtc->irq_task_lock);
+		if (rtc->irq_task)
+			err = -EBUSY;
+		spin_unlock(&rtc->irq_task_lock);
+
+		if (err < 0)
+			return err;
+	}
+
+	/* try the driver's ioctl interface */
+	if (ops->ioctl) {
+		err = ops->ioctl(class_dev->dev, cmd, arg);
+		if (err != -EINVAL)
+			return err;
+	}
+
+	/* if the driver does not provide the ioctl interface
+	 * or if that particular ioctl was not implemented
+	 * (-EINVAL), we will try to emulate here.
+	 */
+
+	switch (cmd) {
+	case RTC_ALM_READ:
+		err = rtc_read_alarm(class_dev, &alarm);
+		if (err < 0)
+			return err;
+
+		if (copy_to_user(uarg, &alarm.time, sizeof(tm)))
+			return -EFAULT;
+		break;
+
+	case RTC_ALM_SET:
+		if (copy_from_user(&alarm.time, uarg, sizeof(tm)))
+			return -EFAULT;
+
+		alarm.enabled = 0;
+		alarm.pending = 0;
+		alarm.time.tm_mday = -1;
+		alarm.time.tm_mon = -1;
+		alarm.time.tm_year = -1;
+		alarm.time.tm_wday = -1;
+		alarm.time.tm_yday = -1;
+		alarm.time.tm_isdst = -1;
+		err = rtc_set_alarm(class_dev, &alarm);
+		break;
+
+	case RTC_RD_TIME:
+		err = rtc_read_time(class_dev, &tm);
+		if (err < 0)
+			return err;
+
+		if (copy_to_user(uarg, &tm, sizeof(tm)))
+			return -EFAULT;
+		break;
+
+	case RTC_SET_TIME:
+		if (!capable(CAP_SYS_TIME))
+			return -EACCES;
+
+		if (copy_from_user(&tm, uarg, sizeof(tm)))
+			return -EFAULT;
+
+		err = rtc_set_time(class_dev, &tm);
+		break;
+#if 0
+	case RTC_EPOCH_SET:
+#ifndef rtc_epoch
+		/*
+		 * There were no RTC clocks before 1900.
+		 */
+		if (arg < 1900) {
+			err = -EINVAL;
+			break;
+		}
+		if (!capable(CAP_SYS_TIME)) {
+			err = -EACCES;
+			break;
+		}
+		rtc_epoch = arg;
+		err = 0;
+#endif
+		break;
+
+	case RTC_EPOCH_READ:
+		err = put_user(rtc_epoch, (unsigned long __user *)uarg);
+		break;
+#endif
+	case RTC_WKALM_SET:
+		if (copy_from_user(&alarm, uarg, sizeof(alarm)))
+			return -EFAULT;
+
+		err = rtc_set_alarm(class_dev, &alarm);
+		break;
+
+	case RTC_WKALM_RD:
+		err = rtc_read_alarm(class_dev, &alarm);
+		if (err < 0)
+			return err;
+
+		if (copy_to_user(uarg, &alarm, sizeof(alarm)))
+			return -EFAULT;
+		break;
+
+	default:
+		err = -EINVAL;
+		break;
+	}
+
+	return err;
+}
+
+static int rtc_dev_release(struct inode *inode, struct file *file)
+{
+	struct rtc_device *rtc = to_rtc_device(file->private_data);
+
+	if (rtc->ops->release)
+		rtc->ops->release(rtc->class_dev.dev);
+
+	mutex_unlock(&rtc->char_lock);
+	return 0;
+}
+
+static int rtc_dev_fasync(int fd, struct file *file, int on)
+{
+	struct rtc_device *rtc = to_rtc_device(file->private_data);
+	return fasync_helper(fd, file, on, &rtc->async_queue);
+}
+
+static struct file_operations rtc_dev_fops = {
+	.owner		= THIS_MODULE,
+	.llseek		= no_llseek,
+	.read		= rtc_dev_read,
+	.poll		= rtc_dev_poll,
+	.ioctl		= rtc_dev_ioctl,
+	.open		= rtc_dev_open,
+	.release	= rtc_dev_release,
+	.fasync		= rtc_dev_fasync,
+};
+
+/* insertion/removal hooks */
+
+static int rtc_dev_add_device(struct class_device *class_dev,
+				struct class_interface *class_intf)
+{
+	int err = 0;
+	struct rtc_device *rtc = to_rtc_device(class_dev);
+
+	if (rtc->id >= RTC_DEV_MAX) {
+		dev_err(class_dev->dev, "too many RTCs\n");
+		return -EINVAL;
+	}
+
+	mutex_init(&rtc->char_lock);
+	spin_lock_init(&rtc->irq_lock);
+	init_waitqueue_head(&rtc->irq_queue);
+
+	cdev_init(&rtc->char_dev, &rtc_dev_fops);
+	rtc->char_dev.owner = rtc->owner;
+
+	if (cdev_add(&rtc->char_dev, MKDEV(MAJOR(rtc_devt), rtc->id), 1)) {
+		cdev_del(&rtc->char_dev);
+		dev_err(class_dev->dev,
+			"failed to add char device %d:%d\n",
+			MAJOR(rtc_devt), rtc->id);
+		return -ENODEV;
+	}
+
+	rtc->rtc_dev = class_device_create(rtc_dev_class, NULL,
+						MKDEV(MAJOR(rtc_devt), rtc->id),
+						class_dev->dev, "rtc%d", rtc->id);
+	if (IS_ERR(rtc->rtc_dev)) {
+		dev_err(class_dev->dev, "cannot create rtc_dev device\n");
+		err = PTR_ERR(rtc->rtc_dev);
+		goto err_cdev_del;
+	}
+
+	dev_info(class_dev->dev, "rtc intf: dev (%d:%d)\n",
+		MAJOR(rtc->rtc_dev->devt),
+		MINOR(rtc->rtc_dev->devt));
+
+	return 0;
+
+err_cdev_del:
+
+	cdev_del(&rtc->char_dev);
+	return err;
+}
+
+static void rtc_dev_remove_device(struct class_device *class_dev,
+					struct class_interface *class_intf)
+{
+	struct rtc_device *rtc = to_rtc_device(class_dev);
+
+	if (rtc->rtc_dev) {
+		dev_dbg(class_dev->dev, "removing char %d:%d\n",
+			MAJOR(rtc->rtc_dev->devt),
+			MINOR(rtc->rtc_dev->devt));
+
+		class_device_unregister(rtc->rtc_dev);
+		cdev_del(&rtc->char_dev);
+	}
+}
+
+/* interface registration */
+
+static struct class_interface rtc_dev_interface = {
+	.add = &rtc_dev_add_device,
+	.remove = &rtc_dev_remove_device,
+};
+
+static int __init rtc_dev_init(void)
+{
+	int err;
+
+	rtc_dev_class = class_create(THIS_MODULE, "rtc-dev");
+	if (IS_ERR(rtc_dev_class))
+		return PTR_ERR(rtc_dev_class);
+
+	err = alloc_chrdev_region(&rtc_devt, 0, RTC_DEV_MAX, "rtc");
+	if (err < 0) {
+		printk(KERN_ERR "%s: failed to allocate char dev region\n",
+			__FILE__);
+		goto err_destroy_class;
+	}
+
+	err = rtc_interface_register(&rtc_dev_interface);
+	if (err < 0) {
+		printk(KERN_ERR "%s: failed to register the interface\n",
+			__FILE__);
+		goto err_unregister_chrdev;
+	}
+
+	return 0;
+
+err_unregister_chrdev:
+	unregister_chrdev_region(rtc_devt, RTC_DEV_MAX);
+
+err_destroy_class:
+	class_destroy(rtc_dev_class);
+
+	return err;
+}
+
+static void __exit rtc_dev_exit(void)
+{
+	class_interface_unregister(&rtc_dev_interface);
+	class_destroy(rtc_dev_class);
+	unregister_chrdev_region(rtc_devt, RTC_DEV_MAX);
+}
+
+module_init(rtc_dev_init);
+module_exit(rtc_dev_exit);
+
+MODULE_AUTHOR("Alessandro Zummo <a.zummo@towertech.it>");
+MODULE_DESCRIPTION("RTC class dev interface");
+MODULE_LICENSE("GPL");
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ linux-ixp4xx/drivers/rtc/rtc-x1205.c	2006-03-08 01:59:26.000000000 +0100
@@ -0,0 +1,619 @@
+/*
+ * An i2c driver for the Xicor/Intersil X1205 RTC
+ * Copyright 2004 Karen Spearel
+ * Copyright 2005 Alessandro Zummo
+ *
+ * please send all reports to:
+ * 	Karen Spearel <kas111 at gmail dot com>
+ *	Alessandro Zummo <a.zummo@towertech.it>
+ *
+ * based on a lot of other RTC drivers.
+ *
+ * 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/i2c.h>
+#include <linux/bcd.h>
+#include <linux/rtc.h>
+#include <linux/delay.h>
+
+#define DRV_VERSION "1.0.6"
+
+/* Addresses to scan: none. This chip is located at
+ * 0x6f and uses a two bytes register addressing.
+ * Two bytes need to be written to read a single register,
+ * while most other chips just require one and take the second
+ * one as the data to be written. To prevent corrupting
+ * unknown chips, the user must explicitely set the probe parameter.
+ */
+
+static unsigned short normal_i2c[] = { I2C_CLIENT_END };
+
+/* Insmod parameters */
+I2C_CLIENT_INSMOD;
+
+/* offsets into CCR area */
+
+#define CCR_SEC			0
+#define CCR_MIN			1
+#define CCR_HOUR		2
+#define CCR_MDAY		3
+#define CCR_MONTH		4
+#define CCR_YEAR		5
+#define CCR_WDAY		6
+#define CCR_Y2K			7
+
+#define X1205_REG_SR		0x3F	/* status register */
+#define X1205_REG_Y2K		0x37
+#define X1205_REG_DW		0x36
+#define X1205_REG_YR		0x35
+#define X1205_REG_MO		0x34
+#define X1205_REG_DT		0x33
+#define X1205_REG_HR		0x32
+#define X1205_REG_MN		0x31
+#define X1205_REG_SC		0x30
+#define X1205_REG_DTR		0x13
+#define X1205_REG_ATR		0x12
+#define X1205_REG_INT		0x11
+#define X1205_REG_0		0x10
+#define X1205_REG_Y2K1		0x0F
+#define X1205_REG_DWA1		0x0E
+#define X1205_REG_YRA1		0x0D
+#define X1205_REG_MOA1		0x0C
+#define X1205_REG_DTA1		0x0B
+#define X1205_REG_HRA1		0x0A
+#define X1205_REG_MNA1		0x09
+#define X1205_REG_SCA1		0x08
+#define X1205_REG_Y2K0		0x07
+#define X1205_REG_DWA0		0x06
+#define X1205_REG_YRA0		0x05
+#define X1205_REG_MOA0		0x04
+#define X1205_REG_DTA0		0x03
+#define X1205_REG_HRA0		0x02
+#define X1205_REG_MNA0		0x01
+#define X1205_REG_SCA0		0x00
+
+#define X1205_CCR_BASE		0x30	/* Base address of CCR */
+#define X1205_ALM0_BASE		0x00	/* Base address of ALARM0 */
+
+#define X1205_SR_RTCF		0x01	/* Clock failure */
+#define X1205_SR_WEL		0x02	/* Write Enable Latch */
+#define X1205_SR_RWEL		0x04	/* Register Write Enable */
+
+#define X1205_DTR_DTR0		0x01
+#define X1205_DTR_DTR1		0x02
+#define X1205_DTR_DTR2		0x04
+
+#define X1205_HR_MIL		0x80	/* Set in ccr.hour for 24 hr mode */
+
+/* Prototypes */
+static int x1205_attach(struct i2c_adapter *adapter);
+static int x1205_detach(struct i2c_client *client);
+static int x1205_probe(struct i2c_adapter *adapter, int address, int kind);
+
+static struct i2c_driver x1205_driver = {
+	.driver		= {
+		.name	= "x1205",
+	},
+	.attach_adapter = &x1205_attach,
+	.detach_client	= &x1205_detach,
+};
+
+/*
+ * In the routines that deal directly with the x1205 hardware, we use
+ * rtc_time -- month 0-11, hour 0-23, yr = calendar year-epoch
+ * Epoch is initialized as 2000. Time is set to UTC.
+ */
+static int x1205_get_datetime(struct i2c_client *client, struct rtc_time *tm,
+				unsigned char reg_base)
+{
+	unsigned char dt_addr[2] = { 0, reg_base };
+
+	unsigned char buf[8];
+
+	struct i2c_msg msgs[] = {
+		{ client->addr, 0, 2, dt_addr },	/* setup read ptr */
+		{ client->addr, I2C_M_RD, 8, buf },	/* read date */
+	};
+
+	/* read date registers */
+	if ((i2c_transfer(client->adapter, &msgs[0], 2)) != 2) {
+		dev_err(&client->dev, "%s: read error\n", __FUNCTION__);
+		return -EIO;
+	}
+
+	dev_dbg(&client->dev,
+		"%s: raw read data - sec=%02x, min=%02x, hr=%02x, "
+		"mday=%02x, mon=%02x, year=%02x, wday=%02x, y2k=%02x\n",
+		__FUNCTION__,
+		buf[0], buf[1], buf[2], buf[3],
+		buf[4], buf[5], buf[6], buf[7]);
+
+	tm->tm_sec = BCD2BIN(buf[CCR_SEC]);
+	tm->tm_min = BCD2BIN(buf[CCR_MIN]);
+	tm->tm_hour = BCD2BIN(buf[CCR_HOUR] & 0x3F); /* hr is 0-23 */
+	tm->tm_mday = BCD2BIN(buf[CCR_MDAY]);
+	tm->tm_mon = BCD2BIN(buf[CCR_MONTH]) - 1; /* mon is 0-11 */
+	tm->tm_year = BCD2BIN(buf[CCR_YEAR])
+			+ (BCD2BIN(buf[CCR_Y2K]) * 100) - 1900;
+	tm->tm_wday = buf[CCR_WDAY];
+
+	dev_dbg(&client->dev, "%s: tm is secs=%d, mins=%d, hours=%d, "
+		"mday=%d, mon=%d, year=%d, wday=%d\n",
+		__FUNCTION__,
+		tm->tm_sec, tm->tm_min, tm->tm_hour,
+		tm->tm_mday, tm->tm_mon, tm->tm_year, tm->tm_wday);
+
+	return 0;
+}
+
+static int x1205_get_status(struct i2c_client *client, unsigned char *sr)
+{
+	static unsigned char sr_addr[2] = { 0, X1205_REG_SR };
+
+	struct i2c_msg msgs[] = {
+		{ client->addr, 0, 2, sr_addr },	/* setup read ptr */
+		{ client->addr, I2C_M_RD, 1, sr },	/* read status */
+	};
+
+	/* read status register */
+	if ((i2c_transfer(client->adapter, &msgs[0], 2)) != 2) {
+		dev_err(&client->dev, "%s: read error\n", __FUNCTION__);
+		return -EIO;
+	}
+
+	return 0;
+}
+
+static int x1205_set_datetime(struct i2c_client *client, struct rtc_time *tm,
+				int datetoo, u8 reg_base)
+{
+	int i, xfer;
+	unsigned char buf[8];
+
+	static const unsigned char wel[3] = { 0, X1205_REG_SR,
+						X1205_SR_WEL };
+
+	static const unsigned char rwel[3] = { 0, X1205_REG_SR,
+						X1205_SR_WEL | X1205_SR_RWEL };
+
+	static const unsigned char diswe[3] = { 0, X1205_REG_SR, 0 };
+
+	dev_dbg(&client->dev,
+		"%s: secs=%d, mins=%d, hours=%d\n",
+		__FUNCTION__,
+		tm->tm_sec, tm->tm_min, tm->tm_hour);
+
+	buf[CCR_SEC] = BIN2BCD(tm->tm_sec);
+	buf[CCR_MIN] = BIN2BCD(tm->tm_min);
+
+	/* set hour and 24hr bit */
+	buf[CCR_HOUR] = BIN2BCD(tm->tm_hour) | X1205_HR_MIL;
+
+	/* should we also set the date? */
+	if (datetoo) {
+		dev_dbg(&client->dev,
+			"%s: mday=%d, mon=%d, year=%d, wday=%d\n",
+			__FUNCTION__,
+			tm->tm_mday, tm->tm_mon, tm->tm_year, tm->tm_wday);
+
+		buf[CCR_MDAY] = BIN2BCD(tm->tm_mday);
+
+		/* month, 1 - 12 */
+		buf[CCR_MONTH] = BIN2BCD(tm->tm_mon + 1);
+
+		/* year, since the rtc epoch*/
+		buf[CCR_YEAR] = BIN2BCD(tm->tm_year % 100);
+		buf[CCR_WDAY] = tm->tm_wday & 0x07;
+		buf[CCR_Y2K] = BIN2BCD(tm->tm_year / 100);
+	}
+
+	/* this sequence is required to unlock the chip */
+	if ((xfer = i2c_master_send(client, wel, 3)) != 3) {
+		dev_err(&client->dev, "%s: wel - %d\n", __FUNCTION__, xfer);
+		return -EIO;
+	}
+
+	if ((xfer = i2c_master_send(client, rwel, 3)) != 3) {
+		dev_err(&client->dev, "%s: rwel - %d\n", __FUNCTION__, xfer);
+		return -EIO;
+	}
+
+	/* write register's data */
+	for (i = 0; i < (datetoo ? 8 : 3); i++) {
+		unsigned char rdata[3] = { 0, reg_base + i, buf[i] };
+
+		xfer = i2c_master_send(client, rdata, 3);
+		if (xfer != 3) {
+			dev_err(&client->dev,
+				"%s: xfer=%d addr=%02x, data=%02x\n",
+				__FUNCTION__,
+				 xfer, rdata[1], rdata[2]);
+			return -EIO;
+		}
+	};
+
+	/* disable further writes */
+	if ((xfer = i2c_master_send(client, diswe, 3)) != 3) {
+		dev_err(&client->dev, "%s: diswe - %d\n", __FUNCTION__, xfer);
+		return -EIO;
+	}
+
+	return 0;
+}
+
+static int x1205_fix_osc(struct i2c_client *client)
+{
+	int err;
+	struct rtc_time tm;
+
+	tm.tm_hour = tm.tm_min = tm.tm_sec = 0;
+
+	if ((err = x1205_set_datetime(client, &tm, 0, X1205_CCR_BASE)) < 0)
+		dev_err(&client->dev,
+			"unable to restart the oscillator\n");
+
+	return err;
+}
+
+static int x1205_get_dtrim(struct i2c_client *client, int *trim)
+{
+	unsigned char dtr;
+	static unsigned char dtr_addr[2] = { 0, X1205_REG_DTR };
+
+	struct i2c_msg msgs[] = {
+		{ client->addr, 0, 2, dtr_addr },	/* setup read ptr */
+		{ client->addr, I2C_M_RD, 1, &dtr }, 	/* read dtr */
+	};
+
+	/* read dtr register */
+	if ((i2c_transfer(client->adapter, &msgs[0], 2)) != 2) {
+		dev_err(&client->dev, "%s: read error\n", __FUNCTION__);
+		return -EIO;
+	}
+
+	dev_dbg(&client->dev, "%s: raw dtr=%x\n", __FUNCTION__, dtr);
+
+	*trim = 0;
+
+	if (dtr & X1205_DTR_DTR0)
+		*trim += 20;
+
+	if (dtr & X1205_DTR_DTR1)
+		*trim += 10;
+
+	if (dtr & X1205_DTR_DTR2)
+		*trim = -*trim;
+
+	return 0;
+}
+
+static int x1205_get_atrim(struct i2c_client *client, int *trim)
+{
+	s8 atr;
+	static unsigned char atr_addr[2] = { 0, X1205_REG_ATR };
+
+	struct i2c_msg msgs[] = {
+		{ client->addr, 0, 2, atr_addr },	/* setup read ptr */
+		{ client->addr, I2C_M_RD, 1, &atr }, 	/* read atr */
+	};
+
+	/* read atr register */
+	if ((i2c_transfer(client->adapter, &msgs[0], 2)) != 2) {
+		dev_err(&client->dev, "%s: read error\n", __FUNCTION__);
+		return -EIO;
+	}
+
+	dev_dbg(&client->dev, "%s: raw atr=%x\n", __FUNCTION__, atr);
+
+	/* atr is a two's complement value on 6 bits,
+	 * perform sign extension. The formula is
+	 * Catr = (atr * 0.25pF) + 11.00pF.
+	 */
+	if (atr & 0x20)
+		atr |= 0xC0;
+
+	dev_dbg(&client->dev, "%s: raw atr=%x (%d)\n", __FUNCTION__, atr, atr);
+
+	*trim = (atr * 250) + 11000;
+
+	dev_dbg(&client->dev, "%s: real=%d\n", __FUNCTION__, *trim);
+
+	return 0;
+}
+
+struct x1205_limit
+{
+	unsigned char reg, mask, min, max;
+};
+
+static int x1205_validate_client(struct i2c_client *client)
+{
+	int i, xfer;
+
+	/* Probe array. We will read the register at the specified
+	 * address and check if the given bits are zero.
+	 */
+	static const unsigned char probe_zero_pattern[] = {
+		/* register, mask */
+		X1205_REG_SR,	0x18,
+		X1205_REG_DTR,	0xF8,
+		X1205_REG_ATR,	0xC0,
+		X1205_REG_INT,	0x18,
+		X1205_REG_0,	0xFF,
+	};
+
+	static const struct x1205_limit probe_limits_pattern[] = {
+		/* register, mask, min, max */
+		{ X1205_REG_Y2K,	0xFF,	19,	20	},
+		{ X1205_REG_DW,		0xFF,	0,	6	},
+		{ X1205_REG_YR,		0xFF,	0,	99	},
+		{ X1205_REG_MO,		0xFF,	0,	12	},
+		{ X1205_REG_DT,		0xFF,	0,	31	},
+		{ X1205_REG_HR,		0x7F,	0,	23	},
+		{ X1205_REG_MN,		0xFF,	0,	59	},
+		{ X1205_REG_SC,		0xFF,	0,	59	},
+		{ X1205_REG_Y2K1,	0xFF,	19,	20	},
+		{ X1205_REG_Y2K0,	0xFF,	19,	20	},
+	};
+
+	/* check that registers have bits a 0 where expected */
+	for (i = 0; i < ARRAY_SIZE(probe_zero_pattern); i += 2) {
+		unsigned char buf;
+
+		unsigned char addr[2] = { 0, probe_zero_pattern[i] };
+
+		struct i2c_msg msgs[2] = {
+			{ client->addr, 0, 2, addr },
+			{ client->addr, I2C_M_RD, 1, &buf },
+		};
+
+		if ((xfer = i2c_transfer(client->adapter, msgs, 2)) != 2) {
+			dev_err(&client->adapter->dev,
+				"%s: could not read register %x\n",
+				__FUNCTION__, probe_zero_pattern[i]);
+
+			return -EIO;
+		}
+
+		if ((buf & probe_zero_pattern[i+1]) != 0) {
+			dev_err(&client->adapter->dev,
+				"%s: register=%02x, zero pattern=%d, value=%x\n",
+				__FUNCTION__, probe_zero_pattern[i], i, buf);
+
+			return -ENODEV;
+		}
+	}
+
+	/* check limits (only registers with bcd values) */
+	for (i = 0; i < ARRAY_SIZE(probe_limits_pattern); i++) {
+		unsigned char reg, value;
+
+		unsigned char addr[2] = { 0, probe_limits_pattern[i].reg };
+
+		struct i2c_msg msgs[2] = {
+			{ client->addr, 0, 2, addr },
+			{ client->addr, I2C_M_RD, 1, &reg },
+		};
+
+		if ((xfer = i2c_transfer(client->adapter, msgs, 2)) != 2) {
+			dev_err(&client->adapter->dev,
+				"%s: could not read register %x\n",
+				__FUNCTION__, probe_limits_pattern[i].reg);
+
+			return -EIO;
+		}
+
+		value = BCD2BIN(reg & probe_limits_pattern[i].mask);
+
+		if (value > probe_limits_pattern[i].max ||
+			value < probe_limits_pattern[i].min) {
+			dev_dbg(&client->adapter->dev,
+				"%s: register=%x, lim pattern=%d, value=%d\n",
+				__FUNCTION__, probe_limits_pattern[i].reg,
+				i, value);
+
+			return -ENODEV;
+		}
+	}
+
+	return 0;
+}
+
+static int x1205_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm)
+{
+	return x1205_get_datetime(to_i2c_client(dev),
+		&alrm->time, X1205_ALM0_BASE);
+}
+
+static int x1205_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm)
+{
+	return x1205_set_datetime(to_i2c_client(dev),
+		&alrm->time, 1, X1205_ALM0_BASE);
+}
+
+static int x1205_rtc_read_time(struct device *dev, struct rtc_time *tm)
+{
+	return x1205_get_datetime(to_i2c_client(dev),
+		tm, X1205_CCR_BASE);
+}
+
+static int x1205_rtc_set_time(struct device *dev, struct rtc_time *tm)
+{
+	return x1205_set_datetime(to_i2c_client(dev),
+		tm, 1, X1205_CCR_BASE);
+}
+
+static int x1205_rtc_proc(struct device *dev, struct seq_file *seq)
+{
+	int err, dtrim, atrim;
+
+	seq_printf(seq, "24hr\t\t: yes\n");
+
+	if ((err = x1205_get_dtrim(to_i2c_client(dev), &dtrim)) == 0)
+		seq_printf(seq, "digital_trim\t: %d ppm\n", dtrim);
+
+	if ((err = x1205_get_atrim(to_i2c_client(dev), &atrim)) == 0)
+		seq_printf(seq, "analog_trim\t: %d.%02d pF\n",
+			atrim / 1000, atrim % 1000);
+	return 0;
+}
+
+static struct rtc_class_ops x1205_rtc_ops = {
+	.proc		= x1205_rtc_proc,
+	.read_time	= x1205_rtc_read_time,
+	.set_time	= x1205_rtc_set_time,
+	.read_alarm	= x1205_rtc_read_alarm,
+	.set_alarm	= x1205_rtc_set_alarm,
+};
+
+static ssize_t x1205_sysfs_show_atrim(struct device *dev,
+				struct device_attribute *attr, char *buf)
+{
+	int atrim;
+
+	if (x1205_get_atrim(to_i2c_client(dev), &atrim) == 0)
+		return sprintf(buf, "%d.%02d pF\n",
+			atrim / 1000, atrim % 1000);
+	return 0;
+}
+static DEVICE_ATTR(atrim, S_IRUGO, x1205_sysfs_show_atrim, NULL);
+
+static ssize_t x1205_sysfs_show_dtrim(struct device *dev,
+				struct device_attribute *attr, char *buf)
+{
+	int dtrim;
+
+	if (x1205_get_dtrim(to_i2c_client(dev), &dtrim) == 0)
+		return sprintf(buf, "%d ppm\n", dtrim);
+
+	return 0;
+}
+static DEVICE_ATTR(dtrim, S_IRUGO, x1205_sysfs_show_dtrim, NULL);
+
+static int x1205_attach(struct i2c_adapter *adapter)
+{
+	dev_dbg(&adapter->dev, "%s\n", __FUNCTION__);
+	return i2c_probe(adapter, &addr_data, x1205_probe);
+}
+
+static int x1205_probe(struct i2c_adapter *adapter, int address, int kind)
+{
+	int err = 0;
+	unsigned char sr;
+	struct i2c_client *client;
+	struct rtc_device *rtc;
+
+	dev_dbg(&adapter->dev, "%s\n", __FUNCTION__);
+
+	if (!i2c_check_functionality(adapter, I2C_FUNC_I2C)) {
+		err = -ENODEV;
+		goto exit;
+	}
+
+	if (!(client = kzalloc(sizeof(struct i2c_client), GFP_KERNEL))) {
+		err = -ENOMEM;
+		goto exit;
+	}
+
+	/* I2C client */
+	client->addr = address;
+	client->driver = &x1205_driver;
+	client->adapter	= adapter;
+
+	strlcpy(client->name, x1205_driver.driver.name, I2C_NAME_SIZE);
+
+	/* Verify the chip is really an X1205 */
+	if (kind < 0) {
+		if (x1205_validate_client(client) < 0) {
+			err = -ENODEV;
+			goto exit_kfree;
+		}
+	}
+
+	/* Inform the i2c layer */
+	if ((err = i2c_attach_client(client)))
+		goto exit_kfree;
+
+	dev_info(&client->dev, "chip found, driver version " DRV_VERSION "\n");
+
+	rtc = rtc_device_register(x1205_driver.driver.name, &client->dev,
+				&x1205_rtc_ops, THIS_MODULE);
+
+	if (IS_ERR(rtc)) {
+		err = PTR_ERR(rtc);
+		dev_err(&client->dev,
+			"unable to register the class device\n");
+		goto exit_detach;
+	}
+
+	i2c_set_clientdata(client, rtc);
+
+	/* Check for power failures and eventualy enable the osc */
+	if ((err = x1205_get_status(client, &sr)) == 0) {
+		if (sr & X1205_SR_RTCF) {
+			dev_err(&client->dev,
+				"power failure detected, "
+				"please set the clock\n");
+			udelay(50);
+			x1205_fix_osc(client);
+		}
+	}
+	else
+		dev_err(&client->dev, "couldn't read status\n");
+
+	device_create_file(&client->dev, &dev_attr_atrim);
+	device_create_file(&client->dev, &dev_attr_dtrim);
+
+	return 0;
+
+exit_detach:
+	i2c_detach_client(client);
+
+exit_kfree:
+	kfree(client);
+
+exit:
+	return err;
+}
+
+static int x1205_detach(struct i2c_client *client)
+{
+	int err;
+	struct rtc_device *rtc = i2c_get_clientdata(client);
+
+	dev_dbg(&client->dev, "%s\n", __FUNCTION__);
+
+ 	if (rtc)
+		rtc_device_unregister(rtc);
+
+	if ((err = i2c_detach_client(client)))
+		return err;
+
+	kfree(client);
+
+	return 0;
+}
+
+static int __init x1205_init(void)
+{
+	return i2c_add_driver(&x1205_driver);
+}
+
+static void __exit x1205_exit(void)
+{
+	i2c_del_driver(&x1205_driver);
+}
+
+MODULE_AUTHOR(
+	"Karen Spearel <kas111 at gmail dot com>, "
+	"Alessandro Zummo <a.zummo@towertech.it>");
+MODULE_DESCRIPTION("Xicor/Intersil X1205 RTC driver");
+MODULE_LICENSE("GPL");
+MODULE_VERSION(DRV_VERSION);
+
+module_init(x1205_init);
+module_exit(x1205_exit);
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ linux-ixp4xx/drivers/rtc/rtc-test.c	2006-03-08 01:59:26.000000000 +0100
@@ -0,0 +1,205 @@
+/*
+ * An RTC test device/driver
+ * Copyright (C) 2005 Tower Technologies
+ * Author: Alessandro Zummo <a.zummo@towertech.it>
+ *
+ * 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/module.h>
+#include <linux/err.h>
+#include <linux/rtc.h>
+#include <linux/platform_device.h>
+
+static struct platform_device *test0 = NULL, *test1 = NULL;
+
+static int test_rtc_read_alarm(struct device *dev,
+	struct rtc_wkalrm *alrm)
+{
+	return 0;
+}
+
+static int test_rtc_set_alarm(struct device *dev,
+	struct rtc_wkalrm *alrm)
+{
+	return 0;
+}
+
+static int test_rtc_read_time(struct device *dev,
+	struct rtc_time *tm)
+{
+	rtc_time_to_tm(get_seconds(), tm);
+	return 0;
+}
+
+static int test_rtc_set_time(struct device *dev,
+	struct rtc_time *tm)
+{
+	return 0;
+}
+
+static int test_rtc_set_mmss(struct device *dev, unsigned long secs)
+{
+	return 0;
+}
+
+static int test_rtc_proc(struct device *dev, struct seq_file *seq)
+{
+	struct platform_device *plat_dev = to_platform_device(dev);
+
+	seq_printf(seq, "24hr\t\t: yes\n");
+	seq_printf(seq, "test\t\t: yes\n");
+	seq_printf(seq, "id\t\t: %d\n", plat_dev->id);
+
+	return 0;
+}
+
+static int test_rtc_ioctl(struct device *dev, unsigned int cmd,
+	unsigned long arg)
+{
+	/* We do support interrupts, they're generated
+	 * using the sysfs interface.
+	 */
+	switch (cmd) {
+	case RTC_PIE_ON:
+	case RTC_PIE_OFF:
+	case RTC_UIE_ON:
+	case RTC_UIE_OFF:
+	case RTC_AIE_ON:
+	case RTC_AIE_OFF:
+		return 0;
+
+	default:
+		return -EINVAL;
+	}
+}
+
+static struct rtc_class_ops test_rtc_ops = {
+	.proc = test_rtc_proc,
+	.read_time = test_rtc_read_time,
+	.set_time = test_rtc_set_time,
+	.read_alarm = test_rtc_read_alarm,
+	.set_alarm = test_rtc_set_alarm,
+	.set_mmss = test_rtc_set_mmss,
+	.ioctl = test_rtc_ioctl,
+};
+
+static ssize_t test_irq_show(struct device *dev,
+				struct device_attribute *attr, char *buf)
+{
+	return sprintf(buf, "%d\n", 42);
+}
+static ssize_t test_irq_store(struct device *dev,
+				struct device_attribute *attr,
+				const char *buf, size_t count)
+{
+	int retval;
+	struct platform_device *plat_dev = to_platform_device(dev);
+	struct rtc_device *rtc = platform_get_drvdata(plat_dev);
+
+	retval = count;
+	if (strncmp(buf, "tick", 4) == 0)
+		rtc_update_irq(&rtc->class_dev, 1, RTC_PF | RTC_IRQF);
+	else if (strncmp(buf, "alarm", 5) == 0)
+		rtc_update_irq(&rtc->class_dev, 1, RTC_AF | RTC_IRQF);
+	else if (strncmp(buf, "update", 6) == 0)
+		rtc_update_irq(&rtc->class_dev, 1, RTC_UF | RTC_IRQF);
+	else
+		retval = -EINVAL;
+
+	return retval;
+}
+static DEVICE_ATTR(irq, S_IRUGO | S_IWUSR, test_irq_show, test_irq_store);
+
+static int test_probe(struct platform_device *plat_dev)
+{
+	int err;
+	struct rtc_device *rtc = rtc_device_register("test", &plat_dev->dev,
+						&test_rtc_ops, THIS_MODULE);
+	if (IS_ERR(rtc)) {
+		err = PTR_ERR(rtc);
+		dev_err(&plat_dev->dev,
+			"unable to register the class device\n");
+		return err;
+	}
+	device_create_file(&plat_dev->dev, &dev_attr_irq);
+
+	platform_set_drvdata(plat_dev, rtc);
+
+	return 0;
+}
+
+static int __devexit test_remove(struct platform_device *plat_dev)
+{
+	struct rtc_device *rtc = platform_get_drvdata(plat_dev);
+
+	rtc_device_unregister(rtc);
+	device_remove_file(&plat_dev->dev, &dev_attr_irq);
+
+	return 0;
+}
+
+static struct platform_driver test_drv = {
+	.probe	= test_probe,
+	.remove = __devexit_p(test_remove),
+	.driver = {
+		.name = "rtc-test",
+		.owner = THIS_MODULE,
+	},
+};
+
+static int __init test_init(void)
+{
+	int err;
+
+	if ((err = platform_driver_register(&test_drv)))
+		return err;
+
+	if ((test0 = platform_device_alloc("rtc-test", 0)) == NULL) {
+		err = -ENOMEM;
+		goto exit_driver_unregister;
+	}
+
+	if ((test1 = platform_device_alloc("rtc-test", 1)) == NULL) {
+		err = -ENOMEM;
+		goto exit_free_test0;
+	}
+
+	if ((err = platform_device_add(test0)))
+		goto exit_free_test1;
+
+	if ((err = platform_device_add(test1)))
+		goto exit_device_unregister;
+
+	return 0;
+
+exit_device_unregister:
+	platform_device_unregister(test0);
+
+exit_free_test1:
+	platform_device_put(test1);
+
+exit_free_test0:
+	platform_device_put(test0);
+
+exit_driver_unregister:
+	platform_driver_unregister(&test_drv);
+	return err;
+}
+
+static void __exit test_exit(void)
+{
+	platform_device_unregister(test0);
+	platform_device_unregister(test1);
+	platform_driver_unregister(&test_drv);
+}
+
+MODULE_AUTHOR("Alessandro Zummo <a.zummo@towertech.it>");
+MODULE_DESCRIPTION("RTC test driver/device");
+MODULE_LICENSE("GPL");
+
+module_init(test_init);
+module_exit(test_exit);
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ linux-ixp4xx/drivers/rtc/rtc-ds1672.c	2006-03-08 01:59:26.000000000 +0100
@@ -0,0 +1,233 @@
+/*
+ * An rtc/i2c driver for the Dallas DS1672
+ * Copyright 2005 Alessandro Zummo
+ *
+ * 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/module.h>
+#include <linux/i2c.h>
+#include <linux/rtc.h>
+
+#define DRV_VERSION "0.2"
+
+/* Addresses to scan: none. This chip cannot be detected. */
+static unsigned short normal_i2c[] = { I2C_CLIENT_END };
+
+/* Insmod parameters */
+I2C_CLIENT_INSMOD;
+
+/* Registers */
+
+#define DS1672_REG_CNT_BASE	0
+#define DS1672_REG_CONTROL	4
+#define DS1672_REG_TRICKLE	5
+
+
+/* Prototypes */
+static int ds1672_probe(struct i2c_adapter *adapter, int address, int kind);
+
+/*
+ * In the routines that deal directly with the ds1672 hardware, we use
+ * rtc_time -- month 0-11, hour 0-23, yr = calendar year-epoch
+ * Epoch is initialized as 2000. Time is set to UTC.
+ */
+static int ds1672_get_datetime(struct i2c_client *client, struct rtc_time *tm)
+{
+	unsigned long time;
+	unsigned char addr = DS1672_REG_CNT_BASE;
+	unsigned char buf[4];
+
+	struct i2c_msg msgs[] = {
+		{ client->addr, 0, 1, &addr },		/* setup read ptr */
+		{ client->addr, I2C_M_RD, 4, buf },	/* read date */
+	};
+
+	/* read date registers */
+	if ((i2c_transfer(client->adapter, &msgs[0], 2)) != 2) {
+		dev_err(&client->dev, "%s: read error\n", __FUNCTION__);
+		return -EIO;
+	}
+
+	dev_dbg(&client->dev,
+		"%s: raw read data - counters=%02x,%02x,%02x,%02x\n"
+		__FUNCTION__,
+		buf[0], buf[1], buf[2], buf[3]);
+
+	time = (buf[3] << 24) | (buf[2] << 16) | (buf[1] << 8) | buf[0];
+
+	rtc_time_to_tm(time, tm);
+
+	dev_dbg(&client->dev, "%s: tm is secs=%d, mins=%d, hours=%d, "
+		"mday=%d, mon=%d, year=%d, wday=%d\n",
+		__FUNCTION__,
+		tm->tm_sec, tm->tm_min, tm->tm_hour,
+		tm->tm_mday, tm->tm_mon, tm->tm_year, tm->tm_wday);
+
+	return 0;
+}
+
+static int ds1672_set_mmss(struct i2c_client *client, unsigned long secs)
+{
+	int xfer;
+	unsigned char buf[5];
+
+	buf[0] = DS1672_REG_CNT_BASE;
+	buf[1] = secs & 0x000000FF;
+	buf[2] = (secs & 0x0000FF00) >> 8;
+	buf[3] = (secs & 0x00FF0000) >> 16;
+	buf[4] = (secs & 0xFF000000) >> 24;
+
+	xfer = i2c_master_send(client, buf, 5);
+	if (xfer != 5) {
+		dev_err(&client->dev, "%s: send: %d\n", __FUNCTION__, xfer);
+		return -EIO;
+	}
+
+	return 0;
+}
+
+static int ds1672_set_datetime(struct i2c_client *client, struct rtc_time *tm)
+{
+	unsigned long secs;
+
+	dev_dbg(&client->dev,
+		"%s: secs=%d, mins=%d, hours=%d, ",
+		"mday=%d, mon=%d, year=%d, wday=%d\n",
+		__FUNCTION__,
+		tm->tm_sec, tm->tm_min, tm->tm_hour,
+		tm->tm_mday, tm->tm_mon, tm->tm_year, tm->tm_wday);
+
+	rtc_tm_to_time(tm, &secs);
+
+	return ds1672_set_mmss(client, secs);
+}
+
+static int ds1672_rtc_read_time(struct device *dev, struct rtc_time *tm)
+{
+	return ds1672_get_datetime(to_i2c_client(dev), tm);
+}
+
+static int ds1672_rtc_set_time(struct device *dev, struct rtc_time *tm)
+{
+	return ds1672_set_datetime(to_i2c_client(dev), tm);
+}
+
+static int ds1672_rtc_set_mmss(struct device *dev, unsigned long secs)
+{
+	return ds1672_set_mmss(to_i2c_client(dev), secs);
+}
+
+static struct rtc_class_ops ds1672_rtc_ops = {
+	.read_time	= ds1672_rtc_read_time,
+	.set_time	= ds1672_rtc_set_time,
+	.set_mmss	= ds1672_rtc_set_mmss,
+};
+
+static int ds1672_attach(struct i2c_adapter *adapter)
+{
+	dev_dbg(&adapter->dev, "%s\n", __FUNCTION__);
+	return i2c_probe(adapter, &addr_data, ds1672_probe);
+}
+
+static int ds1672_detach(struct i2c_client *client)
+{
+	int err;
+	struct rtc_device *rtc = i2c_get_clientdata(client);
+
+	dev_dbg(&client->dev, "%s\n", __FUNCTION__);
+
+ 	if (rtc)
+		rtc_device_unregister(rtc);
+
+	if ((err = i2c_detach_client(client)))
+		return err;
+
+	kfree(client);
+
+	return 0;
+}
+
+static struct i2c_driver ds1672_driver = {
+	.driver		= {
+		.name	= "ds1672",
+	},
+	.attach_adapter = &ds1672_attach,
+	.detach_client	= &ds1672_detach,
+};
+
+static int ds1672_probe(struct i2c_adapter *adapter, int address, int kind)
+{
+	int err = 0;
+	struct i2c_client *client;
+	struct rtc_device *rtc;
+
+	dev_dbg(&adapter->dev, "%s\n", __FUNCTION__);
+
+	if (!i2c_check_functionality(adapter, I2C_FUNC_I2C)) {
+		err = -ENODEV;
+		goto exit;
+	}
+
+	if (!(client = kzalloc(sizeof(struct i2c_client), GFP_KERNEL))) {
+		err = -ENOMEM;
+		goto exit;
+	}
+
+	/* I2C client */
+	client->addr = address;
+	client->driver = &ds1672_driver;
+	client->adapter	= adapter;
+
+	strlcpy(client->name, ds1672_driver.driver.name, I2C_NAME_SIZE);
+
+	/* Inform the i2c layer */
+	if ((err = i2c_attach_client(client)))
+		goto exit_kfree;
+
+	dev_info(&client->dev, "chip found, driver version " DRV_VERSION "\n");
+
+	rtc = rtc_device_register(ds1672_driver.driver.name, &client->dev,
+				&ds1672_rtc_ops, THIS_MODULE);
+
+	if (IS_ERR(rtc)) {
+		err = PTR_ERR(rtc);
+		dev_err(&client->dev,
+			"unable to register the class device\n");
+		goto exit_detach;
+	}
+
+	i2c_set_clientdata(client, rtc);
+
+	return 0;
+
+exit_detach:
+	i2c_detach_client(client);
+
+exit_kfree:
+	kfree(client);
+
+exit:
+	return err;
+}
+
+static int __init ds1672_init(void)
+{
+	return i2c_add_driver(&ds1672_driver);
+}
+
+static void __exit ds1672_exit(void)
+{
+	i2c_del_driver(&ds1672_driver);
+}
+
+MODULE_AUTHOR("Alessandro Zummo <a.zummo@towertech.it>");
+MODULE_DESCRIPTION("Dallas/Maxim DS1672 timekeeper driver");
+MODULE_LICENSE("GPL");
+MODULE_VERSION(DRV_VERSION);
+
+module_init(ds1672_init);
+module_exit(ds1672_exit);
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ linux-ixp4xx/drivers/rtc/rtc-pcf8563.c	2006-03-08 01:59:26.000000000 +0100
@@ -0,0 +1,355 @@
+/*
+ * An I2C driver for the Philips PCF8563 RTC
+ * Copyright 2005-06 Tower Technologies
+ *
+ * Author: Alessandro Zummo <a.zummo@towertech.it>
+ * Maintainers: http://www.nslu2-linux.org/
+ *
+ * based on the other drivers in this same directory.
+ *
+ * http://www.semiconductors.philips.com/acrobat/datasheets/PCF8563-04.pdf
+ *
+ * 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/i2c.h>
+#include <linux/bcd.h>
+#include <linux/rtc.h>
+
+#define DRV_VERSION "0.4.2"
+
+/* Addresses to scan: none
+ * This chip cannot be reliably autodetected. An empty eeprom
+ * located at 0x51 will pass the validation routine due to
+ * the way the registers are implemented.
+ */
+static unsigned short normal_i2c[] = { I2C_CLIENT_END };
+
+/* Module parameters */
+I2C_CLIENT_INSMOD;
+
+#define PCF8563_REG_ST1		0x00 /* status */
+#define PCF8563_REG_ST2		0x01
+
+#define PCF8563_REG_SC		0x02 /* datetime */
+#define PCF8563_REG_MN		0x03
+#define PCF8563_REG_HR		0x04
+#define PCF8563_REG_DM		0x05
+#define PCF8563_REG_DW		0x06
+#define PCF8563_REG_MO		0x07
+#define PCF8563_REG_YR		0x08
+
+#define PCF8563_REG_AMN		0x09 /* alarm */
+#define PCF8563_REG_AHR		0x0A
+#define PCF8563_REG_ADM		0x0B
+#define PCF8563_REG_ADW		0x0C
+
+#define PCF8563_REG_CLKO	0x0D /* clock out */
+#define PCF8563_REG_TMRC	0x0E /* timer control */
+#define PCF8563_REG_TMR		0x0F /* timer */
+
+#define PCF8563_SC_LV		0x80 /* low voltage */
+#define PCF8563_MO_C		0x80 /* century */
+
+/* Prototypes */
+static int pcf8563_attach(struct i2c_adapter *adapter);
+static int pcf8563_detach(struct i2c_client *client);
+static int pcf8563_probe(struct i2c_adapter *adapter, int address, int kind);
+
+static struct i2c_driver pcf8563_driver = {
+	.driver		= {
+		.name	= "pcf8563",
+	},
+	.attach_adapter = &pcf8563_attach,
+	.detach_client	= &pcf8563_detach,
+};
+
+/*
+ * In the routines that deal directly with the pcf8563 hardware, we use
+ * rtc_time -- month 0-11, hour 0-23, yr = calendar year-epoch.
+ */
+static int pcf8563_get_datetime(struct i2c_client *client, struct rtc_time *tm)
+{
+	unsigned char buf[13] = { PCF8563_REG_ST1 };
+
+	struct i2c_msg msgs[] = {
+		{ client->addr, 0, 1, buf },	/* setup read ptr */
+		{ client->addr, I2C_M_RD, 13, buf },	/* read status + date */
+	};
+
+	/* read registers */
+	if ((i2c_transfer(client->adapter, msgs, 2)) != 2) {
+		dev_err(&client->dev, "%s: read error\n", __FUNCTION__);
+		return -EIO;
+	}
+
+	if (buf[PCF8563_REG_SC] & PCF8563_SC_LV)
+		dev_info(&client->dev,
+			"low voltage detected, date/time is not reliable.\n");
+
+	dev_dbg(&client->dev,
+		"%s: raw data is st1=%02x, st2=%02x, sec=%02x, min=%02x, hr=%02x, "
+		"mday=%02x, wday=%02x, mon=%02x, year=%02x\n",
+		__FUNCTION__,
+		buf[0], buf[1], buf[2], buf[3],
+		buf[4], buf[5], buf[6], buf[7],
+		buf[8]);
+
+
+	tm->tm_sec = BCD2BIN(buf[PCF8563_REG_SC] & 0x7F);
+	tm->tm_min = BCD2BIN(buf[PCF8563_REG_MN] & 0x7F);
+	tm->tm_hour = BCD2BIN(buf[PCF8563_REG_HR] & 0x3F); /* rtc hr 0-23 */
+	tm->tm_mday = BCD2BIN(buf[PCF8563_REG_DM] & 0x3F);
+	tm->tm_wday = buf[PCF8563_REG_DW] & 0x07;
+	tm->tm_mon = BCD2BIN(buf[PCF8563_REG_MO] & 0x1F) - 1; /* rtc mn 1-12 */
+	tm->tm_year = BCD2BIN(buf[PCF8563_REG_YR])
+		+ (buf[PCF8563_REG_MO] & PCF8563_MO_C ? 100 : 0);
+
+	dev_dbg(&client->dev, "%s: tm is secs=%d, mins=%d, hours=%d, "
+		"mday=%d, mon=%d, year=%d, wday=%d\n",
+		__FUNCTION__,
+		tm->tm_sec, tm->tm_min, tm->tm_hour,
+		tm->tm_mday, tm->tm_mon, tm->tm_year, tm->tm_wday);
+
+	/* the clock can give out invalid datetime, but we cannot return
+	 * -EINVAL otherwise hwclock will refuse to set the time on bootup.
+	 */
+	if (rtc_valid_tm(tm) < 0)
+		dev_err(&client->dev, "retrieved date/time is not valid.\n");
+
+	return 0;
+}
+
+static int pcf8563_set_datetime(struct i2c_client *client, struct rtc_time *tm)
+{
+	int i, err;
+	unsigned char buf[9];
+
+	dev_dbg(&client->dev, "%s: secs=%d, mins=%d, hours=%d, "
+		"mday=%d, mon=%d, year=%d, wday=%d\n",
+		__FUNCTION__,
+		tm->tm_sec, tm->tm_min, tm->tm_hour,
+		tm->tm_mday, tm->tm_mon, tm->tm_year, tm->tm_wday);
+
+	/* hours, minutes and seconds */
+	buf[PCF8563_REG_SC] = BIN2BCD(tm->tm_sec);
+	buf[PCF8563_REG_MN] = BIN2BCD(tm->tm_min);
+	buf[PCF8563_REG_HR] = BIN2BCD(tm->tm_hour);
+
+	buf[PCF8563_REG_DM] = BIN2BCD(tm->tm_mday);
+
+	/* month, 1 - 12 */
+	buf[PCF8563_REG_MO] = BIN2BCD(tm->tm_mon + 1);
+
+	/* year and century */
+	buf[PCF8563_REG_YR] = BIN2BCD(tm->tm_year % 100);
+	if (tm->tm_year / 100)
+		buf[PCF8563_REG_MO] |= PCF8563_MO_C;
+
+	buf[PCF8563_REG_DW] = tm->tm_wday & 0x07;
+
+	/* write register's data */
+	for (i = 0; i < 7; i++) {
+		unsigned char data[2] = { PCF8563_REG_SC + i,
+						buf[PCF8563_REG_SC + i] };
+
+		err = i2c_master_send(client, data, sizeof(data));
+		if (err != sizeof(data)) {
+			dev_err(&client->dev,
+				"%s: err=%d addr=%02x, data=%02x\n",
+				__FUNCTION__, err, data[0], data[1]);
+			return -EIO;
+		}
+	};
+
+	return 0;
+}
+
+struct pcf8563_limit
+{
+	unsigned char reg;
+	unsigned char mask;
+	unsigned char min;
+	unsigned char max;
+};
+
+static int pcf8563_validate_client(struct i2c_client *client)
+{
+	int i;
+
+	static const struct pcf8563_limit pattern[] = {
+		/* register, mask, min, max */
+		{ PCF8563_REG_SC,	0x7F,	0,	59	},
+		{ PCF8563_REG_MN,	0x7F,	0,	59	},
+		{ PCF8563_REG_HR,	0x3F,	0,	23	},
+		{ PCF8563_REG_DM,	0x3F,	0,	31	},
+		{ PCF8563_REG_MO,	0x1F,	0,	12	},
+	};
+
+	/* check limits (only registers with bcd values) */
+	for (i = 0; i < ARRAY_SIZE(pattern); i++) {
+		int xfer;
+		unsigned char value;
+		unsigned char buf = pattern[i].reg;
+
+		struct i2c_msg msgs[] = {
+			{ client->addr, 0, 1, &buf },
+			{ client->addr, I2C_M_RD, 1, &buf },
+		};
+
+		xfer = i2c_transfer(client->adapter, msgs, ARRAY_SIZE(msgs));
+
+		if (xfer != ARRAY_SIZE(msgs)) {
+			dev_err(&client->adapter->dev,
+				"%s: could not read register 0x%02X\n",
+				__FUNCTION__, pattern[i].reg);
+
+			return -EIO;
+		}
+
+		value = BCD2BIN(buf & pattern[i].mask);
+
+		if (value > pattern[i].max ||
+			value < pattern[i].min) {
+			dev_dbg(&client->adapter->dev,
+				"%s: pattern=%d, reg=%x, mask=0x%02x, min=%d, "
+				"max=%d, value=%d, raw=0x%02X\n",
+				__FUNCTION__, i, pattern[i].reg, pattern[i].mask,
+				pattern[i].min, pattern[i].max,
+				value, buf);
+
+			return -ENODEV;
+		}
+	}
+
+	return 0;
+}
+
+static int pcf8563_rtc_read_time(struct device *dev, struct rtc_time *tm)
+{
+	return pcf8563_get_datetime(to_i2c_client(dev), tm);
+}
+
+static int pcf8563_rtc_set_time(struct device *dev, struct rtc_time *tm)
+{
+	return pcf8563_set_datetime(to_i2c_client(dev), tm);
+}
+
+static int pcf8563_rtc_proc(struct device *dev, struct seq_file *seq)
+{
+	seq_printf(seq, "24hr\t\t: yes\n");
+	return 0;
+}
+
+static struct rtc_class_ops pcf8563_rtc_ops = {
+	.proc		= pcf8563_rtc_proc,
+	.read_time	= pcf8563_rtc_read_time,
+	.set_time	= pcf8563_rtc_set_time,
+};
+
+static int pcf8563_attach(struct i2c_adapter *adapter)
+{
+	return i2c_probe(adapter, &addr_data, pcf8563_probe);
+}
+
+static int pcf8563_probe(struct i2c_adapter *adapter, int address, int kind)
+{
+	struct i2c_client *client;
+	struct rtc_device *rtc;
+
+	int err = 0;
+
+	dev_dbg(&adapter->dev, "%s\n", __FUNCTION__);
+
+	if (!i2c_check_functionality(adapter, I2C_FUNC_I2C)) {
+		err = -ENODEV;
+		goto exit;
+	}
+
+	if (!(client = kzalloc(sizeof(struct i2c_client), GFP_KERNEL))) {
+		err = -ENOMEM;
+		goto exit;
+	}
+
+	client->addr = address;
+	client->driver = &pcf8563_driver;
+	client->adapter	= adapter;
+
+	strlcpy(client->name, pcf8563_driver.driver.name, I2C_NAME_SIZE);
+
+	/* Verify the chip is really an PCF8563 */
+	if (kind < 0) {
+		if (pcf8563_validate_client(client) < 0) {
+			err = -ENODEV;
+			goto exit_kfree;
+		}
+	}
+
+	/* Inform the i2c layer */
+	if ((err = i2c_attach_client(client)))
+		goto exit_kfree;
+
+	dev_info(&client->dev, "chip found, driver version " DRV_VERSION "\n");
+
+	rtc = rtc_device_register(pcf8563_driver.driver.name, &client->dev,
+				&pcf8563_rtc_ops, THIS_MODULE);
+
+	if (IS_ERR(rtc)) {
+		err = PTR_ERR(rtc);
+		dev_err(&client->dev,
+			"unable to register the class device\n");
+		goto exit_detach;
+	}
+
+	i2c_set_clientdata(client, rtc);
+
+	return 0;
+
+exit_detach:
+	i2c_detach_client(client);
+
+exit_kfree:
+	kfree(client);
+
+exit:
+	return err;
+}
+
+static int pcf8563_detach(struct i2c_client *client)
+{
+	int err;
+	struct rtc_device *rtc = i2c_get_clientdata(client);
+
+	dev_dbg(&client->dev, "%s\n", __FUNCTION__);
+
+	if (rtc)
+		rtc_device_unregister(rtc);
+
+	if ((err = i2c_detach_client(client)))
+		return err;
+
+	kfree(client);
+
+	return 0;
+}
+
+static int __init pcf8563_init(void)
+{
+	return i2c_add_driver(&pcf8563_driver);
+}
+
+static void __exit pcf8563_exit(void)
+{
+	i2c_del_driver(&pcf8563_driver);
+}
+
+MODULE_AUTHOR("Alessandro Zummo <a.zummo@towertech.it>");
+MODULE_DESCRIPTION("Philips PCF8563/Epson RTC8564 RTC driver");
+MODULE_LICENSE("GPL");
+MODULE_VERSION(DRV_VERSION);
+
+module_init(pcf8563_init);
+module_exit(pcf8563_exit);
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ linux-ixp4xx/drivers/rtc/rtc-rs5c372.c	2006-03-08 01:59:26.000000000 +0100
@@ -0,0 +1,295 @@
+/*
+ * An I2C driver for the Ricoh RS5C372 RTC
+ *
+ * Copyright (C) 2005 Pavel Mironchik pmironchik@optifacio.net
+ * Copyright (C) 2006 Tower Technologies
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ */
+
+#include <linux/i2c.h>
+#include <linux/rtc.h>
+#include <linux/bcd.h>
+
+#define DRV_VERSION "0.2"
+
+/* Addresses to scan */
+static unsigned short normal_i2c[] = { /* 0x32,*/ I2C_CLIENT_END };
+
+/* Insmod parameters */
+I2C_CLIENT_INSMOD;
+
+#define RS5C372_REG_SECS	0
+#define RS5C372_REG_MINS	1
+#define RS5C372_REG_HOURS	2
+#define RS5C372_REG_WDAY	3
+#define RS5C372_REG_DAY		4
+#define RS5C372_REG_MONTH	5
+#define RS5C372_REG_YEAR	6
+#define RS5C372_REG_TRIM	7
+
+#define RS5C372_TRIM_XSL	0x80
+#define RS5C372_TRIM_MASK	0x7F
+
+#define RS5C372_REG_BASE	0
+
+static int rs5c372_attach(struct i2c_adapter *adapter);
+static int rs5c372_detach(struct i2c_client *client);
+static int rs5c372_probe(struct i2c_adapter *adapter, int address, int kind);
+
+static struct i2c_driver rs5c372_driver = {
+	.driver		= {
+		.name	= "rs5c372",
+	},
+	.attach_adapter	= &rs5c372_attach,
+	.detach_client	= &rs5c372_detach,
+};
+
+static int rs5c372_get_datetime(struct i2c_client *client, struct rtc_time *tm)
+{
+	unsigned char buf[7] = { RS5C372_REG_BASE };
+
+	/* this implements the 1st reading method, according
+	 * to the datasheet. buf[0] is initialized with
+	 * address ptr and transmission format register.
+	 */
+	struct i2c_msg msgs[] = {
+		{ client->addr, 0, 1, buf },
+		{ client->addr, I2C_M_RD, 7, buf },
+	};
+
+	if ((i2c_transfer(client->adapter, msgs, 2)) != 2) {
+		dev_err(&client->dev, "%s: read error\n", __FUNCTION__);
+		return -EIO;
+	}
+
+	tm->tm_sec = BCD2BIN(buf[RS5C372_REG_SECS] & 0x7f);
+	tm->tm_min = BCD2BIN(buf[RS5C372_REG_MINS] & 0x7f);
+	tm->tm_hour = BCD2BIN(buf[RS5C372_REG_HOURS] & 0x3f);
+	tm->tm_wday = BCD2BIN(buf[RS5C372_REG_WDAY] & 0x07);
+	tm->tm_mday = BCD2BIN(buf[RS5C372_REG_DAY] & 0x3f);
+
+	/* tm->tm_mon is zero-based */
+	tm->tm_mon = BCD2BIN(buf[RS5C372_REG_MONTH] & 0x1f) - 1;
+
+	/* year is 1900 + tm->tm_year */
+	tm->tm_year = BCD2BIN(buf[RS5C372_REG_YEAR]) + 100;
+
+	dev_dbg(&client->dev, "%s: tm is secs=%d, mins=%d, hours=%d, "
+		"mday=%d, mon=%d, year=%d, wday=%d\n",
+		__FUNCTION__,
+		tm->tm_sec, tm->tm_min, tm->tm_hour,
+		tm->tm_mday, tm->tm_mon, tm->tm_year, tm->tm_wday);
+
+	return 0;
+}
+
+static int rs5c372_set_datetime(struct i2c_client *client, struct rtc_time *tm)
+{
+	unsigned char buf[8] = { RS5C372_REG_BASE };
+
+	dev_dbg(&client->dev,
+		"%s: secs=%d, mins=%d, hours=%d ",
+		"mday=%d, mon=%d, year=%d, wday=%d\n",
+		__FUNCTION__, tm->tm_sec, tm->tm_min, tm->tm_hour,
+		tm->tm_mday, tm->tm_mon, tm->tm_year, tm->tm_wday);
+
+	buf[1] = BIN2BCD(tm->tm_sec);
+	buf[2] = BIN2BCD(tm->tm_min);
+	buf[3] = BIN2BCD(tm->tm_hour);
+	buf[4] = BIN2BCD(tm->tm_wday);
+	buf[5] = BIN2BCD(tm->tm_mday);
+	buf[6] = BIN2BCD(tm->tm_mon + 1);
+	buf[7] = BIN2BCD(tm->tm_year - 100);
+
+	if ((i2c_master_send(client, buf, 8)) != 8) {
+		dev_err(&client->dev, "%s: write error\n", __FUNCTION__);
+		return -EIO;
+	}
+
+	return 0;
+}
+
+static int rs5c372_get_trim(struct i2c_client *client, int *osc, int *trim)
+{
+	unsigned char buf = RS5C372_REG_TRIM;
+
+	struct i2c_msg msgs[] = {
+		{ client->addr, 0, 1, &buf },
+		{ client->addr, I2C_M_RD, 1, &buf },
+	};
+
+	if ((i2c_transfer(client->adapter, msgs, 2)) != 2) {
+		dev_err(&client->dev, "%s: read error\n", __FUNCTION__);
+		return -EIO;
+	}
+
+	dev_dbg(&client->dev, "%s: raw trim=%x\n", __FUNCTION__, trim);
+
+	if (osc)
+		*osc = (buf & RS5C372_TRIM_XSL) ? 32000 : 32768;
+
+	if (trim)
+		*trim = buf & RS5C372_TRIM_MASK;
+
+	return 0;
+}
+
+static int rs5c372_rtc_read_time(struct device *dev, struct rtc_time *tm)
+{
+	return rs5c372_get_datetime(to_i2c_client(dev), tm);
+}
+
+static int rs5c372_rtc_set_time(struct device *dev, struct rtc_time *tm)
+{
+	return rs5c372_set_datetime(to_i2c_client(dev), tm);
+}
+
+static int rs5c372_rtc_proc(struct device *dev, struct seq_file *seq)
+{
+	int err, osc, trim;
+
+	seq_printf(seq, "24hr\t\t: yes\n");
+
+	if ((err = rs5c372_get_trim(to_i2c_client(dev), &osc, &trim)) == 0) {
+		seq_printf(seq, "%d.%03d KHz\n", osc / 1000, osc % 1000);
+		seq_printf(seq, "trim\t: %d\n", trim);
+	}
+
+	return 0;
+}
+
+static struct rtc_class_ops rs5c372_rtc_ops = {
+	.proc		= rs5c372_rtc_proc,
+	.read_time	= rs5c372_rtc_read_time,
+	.set_time	= rs5c372_rtc_set_time,
+};
+
+static ssize_t rs5c372_sysfs_show_trim(struct device *dev,
+				struct device_attribute *attr, char *buf)
+{
+	int trim;
+
+	if (rs5c372_get_trim(to_i2c_client(dev), NULL, &trim) == 0)
+		return sprintf(buf, "0x%2x\n", trim);
+
+	return 0;
+}
+static DEVICE_ATTR(trim, S_IRUGO, rs5c372_sysfs_show_trim, NULL);
+
+static ssize_t rs5c372_sysfs_show_osc(struct device *dev,
+				struct device_attribute *attr, char *buf)
+{
+	int osc;
+
+	if (rs5c372_get_trim(to_i2c_client(dev), &osc, NULL) == 0)
+		return sprintf(buf, "%d.%03d KHz\n", osc / 1000, osc % 1000);
+
+	return 0;
+}
+static DEVICE_ATTR(osc, S_IRUGO, rs5c372_sysfs_show_osc, NULL);
+
+static int rs5c372_attach(struct i2c_adapter *adapter)
+{
+	dev_dbg(&adapter->dev, "%s\n", __FUNCTION__);
+	return i2c_probe(adapter, &addr_data, rs5c372_probe);
+}
+
+static int rs5c372_probe(struct i2c_adapter *adapter, int address, int kind)
+{
+	int err = 0;
+	struct i2c_client *client;
+	struct rtc_device *rtc;
+
+	dev_dbg(&adapter->dev, "%s\n", __FUNCTION__);
+
+	if (!i2c_check_functionality(adapter, I2C_FUNC_I2C)) {
+		err = -ENODEV;
+		goto exit;
+	}
+
+	if (!(client = kzalloc(sizeof(struct i2c_client), GFP_KERNEL))) {
+		err = -ENOMEM;
+		goto exit;
+	}
+
+	/* I2C client */
+	client->addr = address;
+	client->driver = &rs5c372_driver;
+	client->adapter = adapter;
+
+	strlcpy(client->name, rs5c372_driver.driver.name, I2C_NAME_SIZE);
+
+	/* Inform the i2c layer */
+	if ((err = i2c_attach_client(client)))
+		goto exit_kfree;
+
+	dev_info(&client->dev, "chip found, driver version " DRV_VERSION "\n");
+
+	rtc = rtc_device_register(rs5c372_driver.driver.name, &client->dev,
+				&rs5c372_rtc_ops, THIS_MODULE);
+
+	if (IS_ERR(rtc)) {
+		err = PTR_ERR(rtc);
+		dev_err(&client->dev,
+			"unable to register the class device\n");
+		goto exit_detach;
+	}
+
+	i2c_set_clientdata(client, rtc);
+
+	device_create_file(&client->dev, &dev_attr_trim);
+	device_create_file(&client->dev, &dev_attr_osc);
+
+	return 0;
+
+exit_detach:
+	i2c_detach_client(client);
+
+exit_kfree:
+	kfree(client);
+
+exit:
+	return err;
+}
+
+static int rs5c372_detach(struct i2c_client *client)
+{
+	int err;
+	struct rtc_device *rtc = i2c_get_clientdata(client);
+
+	dev_dbg(&client->dev, "%s\n", __FUNCTION__);
+
+	if (rtc)
+		rtc_device_unregister(rtc);
+
+	if ((err = i2c_detach_client(client)))
+		return err;
+
+	kfree(client);
+
+	return 0;
+}
+
+static __init int rs5c372_init(void)
+{
+	return i2c_add_driver(&rs5c372_driver);
+}
+
+static __exit void rs5c372_exit(void)
+{
+	i2c_del_driver(&rs5c372_driver);
+}
+
+module_init(rs5c372_init);
+module_exit(rs5c372_exit);
+
+MODULE_AUTHOR(
+		"Pavel Mironchik <pmironchik@optifacio.net>, "
+		"Alessandro Zummo <a.zummo@towertech.it>");
+MODULE_DESCRIPTION("Ricoh RS5C372 RTC driver");
+MODULE_LICENSE("GPL");
+MODULE_VERSION(DRV_VERSION);
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ linux-ixp4xx/drivers/rtc/rtc-ep93xx.c	2006-03-08 01:59:26.000000000 +0100
@@ -0,0 +1,163 @@
+/*
+ * A driver for the RTC embedded in the Cirrus Logic EP93XX processors
+ * Copyright (c) 2006 Tower Technologies
+ *
+ * Author: Alessandro Zummo <a.zummo@towertech.it>
+ *
+ * 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/module.h>
+#include <linux/rtc.h>
+#include <linux/platform_device.h>
+#include <asm/hardware.h>
+
+#define EP93XX_RTC_REG(x)	(EP93XX_RTC_BASE + (x))
+#define EP93XX_RTC_DATA		EP93XX_RTC_REG(0x0000)
+#define EP93XX_RTC_LOAD		EP93XX_RTC_REG(0x000C)
+#define EP93XX_RTC_SWCOMP	EP93XX_RTC_REG(0x0108)
+
+#define DRV_VERSION "0.2"
+
+static int ep93xx_get_swcomp(struct device *dev, unsigned short *preload,
+				unsigned short *delete)
+{
+	unsigned short comp = __raw_readl(EP93XX_RTC_SWCOMP);
+
+	if (preload)
+		*preload = comp & 0xffff;
+
+	if (delete)
+		*delete = (comp >> 16) & 0x1f;
+
+	return 0;
+}
+
+static int ep93xx_rtc_read_time(struct device *dev, struct rtc_time *tm)
+{
+	unsigned long time = __raw_readl(EP93XX_RTC_DATA);
+
+	rtc_time_to_tm(time, tm);
+	return 0;
+}
+
+static int ep93xx_rtc_set_mmss(struct device *dev, unsigned long secs)
+{
+	__raw_writel(secs + 1, EP93XX_RTC_LOAD);
+	return 0;
+}
+
+static int ep93xx_rtc_set_time(struct device *dev, struct rtc_time *tm)
+{
+	int err;
+	unsigned long secs;
+
+	err = rtc_tm_to_time(tm, &secs);
+	if (err != 0)
+		return err;
+
+	return ep93xx_rtc_set_mmss(dev, secs);
+}
+
+static int ep93xx_rtc_proc(struct device *dev, struct seq_file *seq)
+{
+	unsigned short preload, delete;
+
+	ep93xx_get_swcomp(dev, &preload, &delete);
+
+	seq_printf(seq, "24hr\t\t: yes\n");
+	seq_printf(seq, "preload\t\t: %d\n", preload);
+	seq_printf(seq, "delete\t\t: %d\n", delete);
+
+	return 0;
+}
+
+static struct rtc_class_ops ep93xx_rtc_ops = {
+	.read_time	= ep93xx_rtc_read_time,
+	.set_time	= ep93xx_rtc_set_time,
+	.set_mmss	= ep93xx_rtc_set_mmss,
+	.proc		= ep93xx_rtc_proc,
+};
+
+static ssize_t ep93xx_sysfs_show_comp_preload(struct device *dev,
+			struct device_attribute *attr, char *buf)
+{
+	unsigned short preload;
+
+	ep93xx_get_swcomp(dev, &preload, NULL);
+
+	return sprintf(buf, "%d\n", preload);
+}
+static DEVICE_ATTR(comp_preload, S_IRUGO, ep93xx_sysfs_show_comp_preload, NULL);
+
+static ssize_t ep93xx_sysfs_show_comp_delete(struct device *dev,
+			struct device_attribute *attr, char *buf)
+{
+	unsigned short delete;
+
+	ep93xx_get_swcomp(dev, NULL, &delete);
+
+	return sprintf(buf, "%d\n", delete);
+}
+static DEVICE_ATTR(comp_delete, S_IRUGO, ep93xx_sysfs_show_comp_delete, NULL);
+
+
+static int __devinit ep93xx_rtc_probe(struct platform_device *dev)
+{
+	struct rtc_device *rtc = rtc_device_register("ep93xx",
+				&dev->dev, &ep93xx_rtc_ops, THIS_MODULE);
+
+	if (IS_ERR(rtc)) {
+		dev_err(&dev->dev, "unable to register\n");
+		return PTR_ERR(rtc);
+	}
+
+	platform_set_drvdata(dev, rtc);
+
+	device_create_file(&dev->dev, &dev_attr_comp_preload);
+	device_create_file(&dev->dev, &dev_attr_comp_delete);
+
+	return 0;
+}
+
+static int __devexit ep93xx_rtc_remove(struct platform_device *dev)
+{
+	struct rtc_device *rtc = platform_get_drvdata(dev);
+
+ 	if (rtc)
+		rtc_device_unregister(rtc);
+
+	platform_set_drvdata(dev, NULL);
+
+	return 0;
+}
+
+static struct platform_driver ep93xx_rtc_platform_driver = {
+	.driver		= {
+		.name	= "ep93xx-rtc",
+		.owner	= THIS_MODULE,
+	},
+	.probe		= ep93xx_rtc_probe,
+	.remove		= __devexit_p(ep93xx_rtc_remove),
+};
+
+static int __init ep93xx_rtc_init(void)
+{
+	return platform_driver_register(&ep93xx_rtc_platform_driver);
+}
+
+static void __exit ep93xx_rtc_exit(void)
+{
+	platform_driver_unregister(&ep93xx_rtc_platform_driver);
+}
+
+MODULE_AUTHOR("Alessandro Zummo <a.zummo@towertech.it>");
+MODULE_DESCRIPTION("EP93XX RTC driver");
+MODULE_LICENSE("GPL");
+MODULE_VERSION(DRV_VERSION);
+
+module_init(ep93xx_rtc_init);
+module_exit(ep93xx_rtc_exit);
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ linux-ixp4xx/drivers/rtc/rtc-sa1100.c	2006-03-08 01:59:26.000000000 +0100
@@ -0,0 +1,392 @@
+/*
+ * Real Time Clock interface for StrongARM SA1x00 and XScale PXA2xx
+ *
+ * Copyright (c) 2000 Nils Faerber
+ *
+ * Based on rtc.c by Paul Gortmaker
+ *
+ * Original Driver by Nils Faerber <nils@kernelconcepts.de>
+ *
+ * Modifications from:
+ *   CIH <cih@coventive.com>
+ *   Nicolas Pitre <nico@cam.org>
+ *   Andrew Christian <andrew.christian@hp.com>
+ *
+ * Converted to the RTC subsystem and Driver Model
+ *   by Richard Purdie <rpurdie@rpsys.net>
+ *
+ * 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. *
+ * 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/platform_device.h>
+#include <linux/module.h>
+#include <linux/rtc.h>
+#include <linux/init.h>
+#include <linux/fs.h>
+#include <linux/interrupt.h>
+#include <linux/string.h>
+#include <linux/pm.h>
+
+#include <asm/bitops.h>
+#include <asm/hardware.h>
+#include <asm/irq.h>
+#include <asm/rtc.h>
+
+#ifdef CONFIG_ARCH_PXA
+#include <asm/arch/pxa-regs.h>
+#endif
+
+#define TIMER_FREQ		CLOCK_TICK_RATE
+#define RTC_DEF_DIVIDER		32768 - 1
+#define RTC_DEF_TRIM		0
+
+static unsigned long rtc_freq = 1024;
+static struct rtc_time rtc_alarm;
+static spinlock_t sa1100_rtc_lock = SPIN_LOCK_UNLOCKED;
+
+static int rtc_update_alarm(struct rtc_time *alrm)
+{
+	struct rtc_time alarm_tm, now_tm;
+	unsigned long now, time;
+	int ret;
+
+	do {
+		now = RCNR;
+		rtc_time_to_tm(now, &now_tm);
+		rtc_next_alarm_time(&alarm_tm, &now_tm, alrm);
+		ret = rtc_tm_to_time(&alarm_tm, &time);
+		if (ret != 0)
+			break;
+
+		RTSR = RTSR & (RTSR_HZE|RTSR_ALE|RTSR_AL);
+		RTAR = time;
+	} while (now != RCNR);
+
+	return ret;
+}
+
+static irqreturn_t sa1100_rtc_interrupt(int irq, void *dev_id,
+		struct pt_regs *regs)
+{
+	struct platform_device *pdev = to_platform_device(dev_id);
+	struct rtc_device *rtc = platform_get_drvdata(pdev);
+	unsigned int rtsr;
+	unsigned long events = 0;
+
+	spin_lock(&sa1100_rtc_lock);
+
+	rtsr = RTSR;
+	/* clear interrupt sources */
+	RTSR = 0;
+	RTSR = (RTSR_AL | RTSR_HZ) & (rtsr >> 2);
+
+	/* clear alarm interrupt if it has occurred */
+	if (rtsr & RTSR_AL)
+		rtsr &= ~RTSR_ALE;
+	RTSR = rtsr & (RTSR_ALE | RTSR_HZE);
+
+	/* update irq data & counter */
+	if (rtsr & RTSR_AL)
+		events |= RTC_AF | RTC_IRQF;
+	if (rtsr & RTSR_HZ)
+		events |= RTC_UF | RTC_IRQF;
+
+	rtc_update_irq(&rtc->class_dev, 1, events);
+
+	if (rtsr & RTSR_AL && rtc_periodic_alarm(&rtc_alarm))
+		rtc_update_alarm(&rtc_alarm);
+
+	spin_unlock(&sa1100_rtc_lock);
+
+	return IRQ_HANDLED;
+}
+
+static int rtc_timer1_count;
+
+static irqreturn_t timer1_interrupt(int irq, void *dev_id,
+		struct pt_regs *regs)
+{
+	struct platform_device *pdev = to_platform_device(dev_id);
+	struct rtc_device *rtc = platform_get_drvdata(pdev);
+
+	/*
+	 * If we match for the first time, rtc_timer1_count will be 1.
+	 * Otherwise, we wrapped around (very unlikely but
+	 * still possible) so compute the amount of missed periods.
+	 * The match reg is updated only when the data is actually retrieved
+	 * to avoid unnecessary interrupts.
+	 */
+	OSSR = OSSR_M1;	/* clear match on timer1 */
+
+	rtc_update_irq(&rtc->class_dev, rtc_timer1_count, RTC_PF | RTC_IRQF);
+
+	if (rtc_timer1_count == 1)
+		rtc_timer1_count = (rtc_freq * ((1<<30)/(TIMER_FREQ>>2)));
+
+	return IRQ_HANDLED;
+}
+
+static int sa1100_rtc_read_callback(struct device *dev, int data)
+{
+	if (data & RTC_PF) {
+		/* interpolate missed periods and set match for the next */
+		unsigned long period = TIMER_FREQ/rtc_freq;
+		unsigned long oscr = OSCR;
+		unsigned long osmr1 = OSMR1;
+		unsigned long missed = (oscr - osmr1)/period;
+		data += missed << 8;
+		OSSR = OSSR_M1;	/* clear match on timer 1 */
+		OSMR1 = osmr1 + (missed + 1)*period;
+		/* Ensure we didn't miss another match in the mean time.
+		 * Here we compare (match - OSCR) 8 instead of 0 --
+		 * see comment in pxa_timer_interrupt() for explanation.
+		 */
+		while( (signed long)((osmr1 = OSMR1) - OSCR) <= 8 ) {
+			data += 0x100;
+			OSSR = OSSR_M1;	/* clear match on timer 1 */
+			OSMR1 = osmr1 + period;
+		}
+	}
+	return data;
+}
+
+static int sa1100_rtc_open(struct device *dev)
+{
+	int ret;
+
+	ret = request_irq(IRQ_RTC1Hz, sa1100_rtc_interrupt, SA_INTERRUPT,
+				"rtc 1Hz", dev);
+	if (ret) {
+		printk(KERN_ERR "rtc: IRQ%d already in use.\n", IRQ_RTC1Hz);
+		goto fail_ui;
+	}
+	ret = request_irq(IRQ_RTCAlrm, sa1100_rtc_interrupt, SA_INTERRUPT,
+				"rtc Alrm", dev);
+	if (ret) {
+		printk(KERN_ERR "rtc: IRQ%d already in use.\n", IRQ_RTCAlrm);
+		goto fail_ai;
+	}
+	ret = request_irq(IRQ_OST1, timer1_interrupt, SA_INTERRUPT,
+				"rtc timer", dev);
+	if (ret) {
+		printk(KERN_ERR "rtc: IRQ%d already in use.\n", IRQ_OST1);
+		goto fail_pi;
+	}
+	return 0;
+
+ fail_pi:
+	free_irq(IRQ_RTCAlrm, NULL);
+ fail_ai:
+	free_irq(IRQ_RTC1Hz, NULL);
+ fail_ui:
+	return ret;
+}
+
+static void sa1100_rtc_release(struct device *dev)
+{
+	spin_lock_irq(&sa1100_rtc_lock);
+	RTSR = 0;
+	OIER &= ~OIER_E1;
+	OSSR = OSSR_M1;
+	spin_unlock_irq(&sa1100_rtc_lock);
+
+	free_irq(IRQ_OST1, dev);
+	free_irq(IRQ_RTCAlrm, dev);
+	free_irq(IRQ_RTC1Hz, dev);
+}
+
+
+static int sa1100_rtc_ioctl(struct device *dev, unsigned int cmd,
+		unsigned long arg)
+{
+	switch(cmd) {
+	case RTC_AIE_OFF:
+		spin_lock_irq(&sa1100_rtc_lock);
+		RTSR &= ~RTSR_ALE;
+		spin_unlock_irq(&sa1100_rtc_lock);
+		return 0;
+	case RTC_AIE_ON:
+		spin_lock_irq(&sa1100_rtc_lock);
+		RTSR |= RTSR_ALE;
+		spin_unlock_irq(&sa1100_rtc_lock);
+		return 0;
+	case RTC_UIE_OFF:
+		spin_lock_irq(&sa1100_rtc_lock);
+		RTSR &= ~RTSR_HZE;
+		spin_unlock_irq(&sa1100_rtc_lock);
+		return 0;
+	case RTC_UIE_ON:
+		spin_lock_irq(&sa1100_rtc_lock);
+		RTSR |= RTSR_HZE;
+		spin_unlock_irq(&sa1100_rtc_lock);
+		return 0;
+	case RTC_PIE_OFF:
+		spin_lock_irq(&sa1100_rtc_lock);
+		OIER &= ~OIER_E1;
+		spin_unlock_irq(&sa1100_rtc_lock);
+		return 0;
+	case RTC_PIE_ON:
+		if ((rtc_freq > 64) && !capable(CAP_SYS_RESOURCE))
+			return -EACCES;
+		spin_lock_irq(&sa1100_rtc_lock);
+		OSMR1 = TIMER_FREQ/rtc_freq + OSCR;
+		OIER |= OIER_E1;
+		rtc_timer1_count = 1;
+		spin_unlock_irq(&sa1100_rtc_lock);
+		return 0;
+	case RTC_IRQP_READ:
+		return put_user(rtc_freq, (unsigned long *)arg);
+	case RTC_IRQP_SET:
+		if (arg < 1 || arg > TIMER_FREQ)
+			return -EINVAL;
+		if ((arg > 64) && (!capable(CAP_SYS_RESOURCE)))
+			return -EACCES;
+		rtc_freq = arg;
+		return 0;
+	}
+	return -EINVAL;
+}
+
+static int sa1100_rtc_read_time(struct device *dev, struct rtc_time *tm)
+{
+	rtc_time_to_tm(RCNR, tm);
+	return 0;
+}
+
+static int sa1100_rtc_set_time(struct device *dev, struct rtc_time *tm)
+{
+	unsigned long time;
+	int ret;
+
+	ret = rtc_tm_to_time(tm, &time);
+	if (ret == 0)
+		RCNR = time;
+	return ret;
+}
+
+static int sa1100_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alrm)
+{
+	memcpy(&alrm->time, &rtc_alarm, sizeof(struct rtc_time));
+	alrm->pending = RTSR & RTSR_AL ? 1 : 0;
+	return 0;
+}
+
+static int sa1100_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alrm)
+{
+	int ret;
+
+	spin_lock_irq(&sa1100_rtc_lock);
+	ret = rtc_update_alarm(&alrm->time);
+	if (ret == 0) {
+		memcpy(&rtc_alarm, &alrm->time, sizeof(struct rtc_time));
+
+		if (alrm->enabled)
+			enable_irq_wake(IRQ_RTCAlrm);
+		else
+			disable_irq_wake(IRQ_RTCAlrm);
+	}
+	spin_unlock_irq(&sa1100_rtc_lock);
+
+	return ret;
+}
+
+static int sa1100_rtc_proc(struct device *dev, struct seq_file *seq)
+{
+	seq_printf(seq, "trim/divider\t: 0x%08x\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",
+			(OIER & OIER_E1) ? "yes" : "no");
+	seq_printf(seq, "periodic_freq\t: %ld\n", rtc_freq);
+
+	return 0;
+}
+
+static struct rtc_class_ops sa1100_rtc_ops = {
+	.open = sa1100_rtc_open,
+	.read_callback = sa1100_rtc_read_callback,
+	.release = sa1100_rtc_release,
+	.ioctl = sa1100_rtc_ioctl,
+	.read_time = sa1100_rtc_read_time,
+	.set_time = sa1100_rtc_set_time,
+	.read_alarm = sa1100_rtc_read_alarm,
+	.set_alarm = sa1100_rtc_set_alarm,
+	.proc = sa1100_rtc_proc,
+};
+
+static int sa1100_rtc_probe(struct platform_device *pdev)
+{
+	struct rtc_device *rtc;
+
+	/*
+	 * According to the manual we should be able to let RTTR be zero
+	 * and then a default diviser for a 32.768KHz clock is used.
+	 * Apparently this doesn't work, at least for my SA1110 rev 5.
+	 * If the clock divider is uninitialized then reset it to the
+	 * default value to get the 1Hz clock.
+	 */
+	if (RTTR == 0) {
+		RTTR = RTC_DEF_DIVIDER + (RTC_DEF_TRIM << 16);
+		printk(KERN_WARNING "rtc: warning: initializing default clock divider/trim value\n");
+		/* The current RTC value probably doesn't make sense either */
+		RCNR = 0;
+	}
+
+	rtc = rtc_device_register(pdev->name, &pdev->dev, &sa1100_rtc_ops,
+				THIS_MODULE);
+
+	if (IS_ERR(rtc)) {
+		dev_err(&pdev->dev, "Unable to register the RTC device\n");
+		return PTR_ERR(rtc);
+	}
+
+	platform_set_drvdata(pdev, rtc);
+
+	dev_info(&pdev->dev, "SA11xx/PXA2xx RTC Registered\n");
+
+	return 0;
+}
+
+static int sa1100_rtc_remove(struct platform_device *pdev)
+{
+	struct rtc_device *rtc = platform_get_drvdata(pdev);
+
+ 	if (rtc)
+		rtc_device_unregister(rtc);
+
+	return 0;
+}
+
+static struct platform_driver sa1100_rtc_driver = {
+	.probe		= sa1100_rtc_probe,
+	.remove		= sa1100_rtc_remove,
+	.driver		= {
+		.name		= "sa1100-rtc",
+	},
+};
+
+static int __init sa1100_rtc_init(void)
+{
+	return platform_driver_register(&sa1100_rtc_driver);
+}
+
+static void __exit sa1100_rtc_exit(void)
+{
+	platform_driver_unregister(&sa1100_rtc_driver);
+}
+
+module_init(sa1100_rtc_init);
+module_exit(sa1100_rtc_exit);
+
+MODULE_AUTHOR("Richard Purdie <rpurdie@rpsys.net>");
+MODULE_DESCRIPTION("SA11x0/PXA2xx Realtime Clock Driver (RTC)");
+MODULE_LICENSE("GPL");
--- linux-ixp4xx.orig/arch/arm/mach-pxa/generic.c	2006-03-08 01:59:09.000000000 +0100
+++ linux-ixp4xx/arch/arm/mach-pxa/generic.c	2006-03-08 01:59:26.000000000 +0100
@@ -319,6 +319,11 @@ void __init pxa_set_ficp_info(struct pxa
 	pxaficp_device.dev.platform_data = info;
 }
 
+static struct platform_device pxartc_device = {
+	.name		= "sa1100-rtc",
+	.id		= -1,
+};
+
 static struct platform_device *devices[] __initdata = {
 	&pxamci_device,
 	&udc_device,
@@ -329,6 +334,7 @@ static struct platform_device *devices[]
 	&pxaficp_device,
 	&i2c_device,
 	&i2s_device,
+	&pxartc_device,
 };
 
 static int __init pxa_init(void)
--- linux-ixp4xx.orig/arch/arm/mach-sa1100/generic.c	2006-03-08 01:59:09.000000000 +0100
+++ linux-ixp4xx/arch/arm/mach-sa1100/generic.c	2006-03-08 01:59:26.000000000 +0100
@@ -324,6 +324,11 @@ void sa11x0_set_irda_data(struct irda_pl
 	sa11x0ir_device.dev.platform_data = irda;
 }
 
+static struct platform_device sa11x0rtc_device = {
+	.name		= "sa1100-rtc",
+	.id		= -1,
+};
+
 static struct platform_device *sa11x0_devices[] __initdata = {
 	&sa11x0udc_device,
 	&sa11x0uart1_device,
@@ -333,6 +338,7 @@ static struct platform_device *sa11x0_de
 	&sa11x0pcmcia_device,
 	&sa11x0fb_device,
 	&sa11x0mtd_device,
+	&sa11x0rtc_device,
 };
 
 static int __init sa1100_init(void)