summaryrefslogtreecommitdiff
path: root/packages/linux/ixp4xx-kernel/2.6.16/40-rtc-class.patch
diff options
context:
space:
mode:
Diffstat (limited to 'packages/linux/ixp4xx-kernel/2.6.16/40-rtc-class.patch')
-rw-r--r--packages/linux/ixp4xx-kernel/2.6.16/40-rtc-class.patch2076
1 files changed, 1804 insertions, 272 deletions
diff --git a/packages/linux/ixp4xx-kernel/2.6.16/40-rtc-class.patch b/packages/linux/ixp4xx-kernel/2.6.16/40-rtc-class.patch
index 38359a1bc0..3cc84b2a9b 100644
--- a/packages/linux/ixp4xx-kernel/2.6.16/40-rtc-class.patch
+++ b/packages/linux/ixp4xx-kernel/2.6.16/40-rtc-class.patch
@@ -1,6 +1,6 @@
---- linux-nslu2.orig/include/linux/rtc.h 2006-02-06 20:37:43.000000000 +0100
-+++ linux-nslu2/include/linux/rtc.h 2006-02-06 21:41:39.000000000 +0100
-@@ -93,8 +93,91 @@ struct rtc_pll_info {
+--- linux-rtc.orig/include/linux/rtc.h 2006-02-19 23:33:10.000000000 +0100
++++ linux-rtc/include/linux/rtc.h 2006-02-19 23:33:15.000000000 +0100
+@@ -93,8 +93,97 @@ 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 */
@@ -16,6 +16,7 @@
+#include <linux/seq_file.h>
+#include <linux/cdev.h>
+#include <linux/poll.h>
++#include <linux/mutex.h>
+
+struct rtc_class_ops {
+ int (*open)(struct device *);
@@ -29,6 +30,7 @@
+ 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
@@ -36,23 +38,25 @@
+
+struct rtc_device
+{
-+ int id;
-+ struct module *owner;
+ struct class_device class_dev;
-+ struct semaphore ops_lock;
-+ struct rtc_class_ops *ops;
++ struct module *owner;
++
++ int id;
+ char name[RTC_DEVICE_NAME_SIZE];
+
++ struct rtc_class_ops *ops;
++ struct mutex ops_lock;
++
+ struct cdev char_dev;
-+ struct semaphore char_sem;
++ struct mutex char_lock;
+
+ unsigned long irq_data;
+ spinlock_t irq_lock;
+ wait_queue_head_t irq_queue;
+ struct fasync_struct *async_queue;
+
-+ spinlock_t irq_task_lock;
+ 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)
@@ -71,15 +75,17 @@
+
+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);
++ 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_open(char *name);
-+extern void rtc_close(struct class_device *class_dev);
++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,
@@ -92,8 +98,8 @@
typedef struct rtc_task {
void (*func)(void *private_data);
void *private_data;
---- linux-nslu2.orig/drivers/Kconfig 2006-02-06 20:37:14.000000000 +0100
-+++ linux-nslu2/drivers/Kconfig 2006-02-06 21:11:33.000000000 +0100
+--- linux-rtc.orig/drivers/Kconfig 2006-02-19 23:33:10.000000000 +0100
++++ linux-rtc/drivers/Kconfig 2006-02-19 23:33:15.000000000 +0100
@@ -70,4 +70,6 @@ source "drivers/sn/Kconfig"
source "drivers/edac/Kconfig"
@@ -101,8 +107,8 @@
+source "drivers/rtc/Kconfig"
+
endmenu
---- linux-nslu2.orig/drivers/Makefile 2006-02-06 20:37:14.000000000 +0100
-+++ linux-nslu2/drivers/Makefile 2006-02-06 21:11:33.000000000 +0100
+--- linux-rtc.orig/drivers/Makefile 2006-02-19 23:33:10.000000000 +0100
++++ linux-rtc/drivers/Makefile 2006-02-19 23:33:15.000000000 +0100
@@ -56,6 +56,7 @@ obj-$(CONFIG_USB_GADGET) += usb/gadget/
obj-$(CONFIG_GAMEPORT) += input/gameport/
obj-$(CONFIG_INPUT) += input/
@@ -112,7 +118,7 @@
obj-$(CONFIG_W1) += w1/
obj-$(CONFIG_HWMON) += hwmon/
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
-+++ linux-nslu2/drivers/rtc/class.c 2006-02-06 21:41:25.000000000 +0100
++++ linux-rtc/drivers/rtc/class.c 2006-02-19 23:33:15.000000000 +0100
@@ -0,0 +1,143 @@
+/*
+ * RTC subsystem, base class
@@ -133,15 +139,15 @@
+#include <linux/idr.h>
+
+static DEFINE_IDR(rtc_idr);
-+static DECLARE_MUTEX(idr_lock);
++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);
-+ down(&idr_lock);
++ mutex_lock(&idr_lock);
+ idr_remove(&rtc_idr, rtc->id);
-+ up(&idr_lock);
++ mutex_unlock(&idr_lock);
+ kfree(rtc);
+}
+
@@ -167,9 +173,9 @@
+ }
+
+
-+ down(&idr_lock);
++ mutex_lock(&idr_lock);
+ err = idr_get_new(&rtc_idr, NULL, &id);
-+ up(&idr_lock);
++ mutex_unlock(&idr_lock);
+
+ if (err < 0)
+ goto exit;
@@ -188,7 +194,7 @@
+ rtc->class_dev.class = rtc_class;
+ rtc->class_dev.release = rtc_device_release;
+
-+ init_MUTEX(&rtc->ops_lock);
++ mutex_init(&rtc->ops_lock);
+ spin_lock_init(&rtc->irq_lock);
+ spin_lock_init(&rtc->irq_task_lock);
+
@@ -222,9 +228,9 @@
+ */
+void rtc_device_unregister(struct rtc_device *rtc)
+{
-+ down(&rtc->ops_lock);
++ mutex_lock(&rtc->ops_lock);
+ rtc->ops = NULL;
-+ up(&rtc->ops_lock);
++ mutex_unlock(&rtc->ops_lock);
+ class_device_unregister(&rtc->class_dev);
+}
+EXPORT_SYMBOL_GPL(rtc_device_unregister);
@@ -258,8 +264,8 @@
+MODULE_DESCRIPTION("RTC class support");
+MODULE_LICENSE("GPL");
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
-+++ linux-nslu2/drivers/rtc/Kconfig 2006-02-06 23:58:32.000000000 +0100
-@@ -0,0 +1,121 @@
++++ linux-rtc/drivers/rtc/Kconfig 2006-02-21 00:36:43.000000000 +0100
+@@ -0,0 +1,131 @@
+#
+# RTC class/drivers configuration
+#
@@ -365,6 +371,16 @@
+ 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_TEST
+ tristate "Test driver/device"
+ depends on RTC_CLASS
@@ -382,8 +398,8 @@
+
+endmenu
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
-+++ linux-nslu2/drivers/rtc/Makefile 2006-02-06 23:58:32.000000000 +0100
-@@ -0,0 +1,17 @@
++++ linux-rtc/drivers/rtc/Makefile 2006-02-21 00:36:43.000000000 +0100
+@@ -0,0 +1,18 @@
+#
+# Makefile for RTC class/drivers.
+#
@@ -400,10 +416,11 @@
+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
+
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
-+++ linux-nslu2/drivers/rtc/interface.c 2006-02-07 01:32:10.000000000 +0100
-@@ -0,0 +1,232 @@
++++ linux-rtc/drivers/rtc/interface.c 2006-02-19 23:33:15.000000000 +0100
+@@ -0,0 +1,274 @@
+/*
+ * RTC subsystem, interface functions
+ *
@@ -426,7 +443,7 @@
+ int err;
+ struct rtc_device *rtc = to_rtc_device(class_dev);
+
-+ if ((err = down_interruptible(&rtc->ops_lock)))
++ if ((err = mutex_lock_interruptible(&rtc->ops_lock)))
+ return err;
+
+ if (!rtc->ops)
@@ -438,7 +455,7 @@
+ err = rtc->ops->read_time(class_dev->dev, tm);
+ }
+
-+ up(&rtc->ops_lock);
++ mutex_unlock(&rtc->ops_lock);
+ return err;
+}
+EXPORT_SYMBOL(rtc_read_time);
@@ -451,7 +468,7 @@
+ if ((err = rtc_valid_tm(tm)) != 0)
+ return err;
+
-+ if ((err = down_interruptible(&rtc->ops_lock)))
++ if ((err = mutex_lock_interruptible(&rtc->ops_lock)))
+ return err;
+
+ if (!rtc->ops)
@@ -461,17 +478,59 @@
+ else
+ err = rtc->ops->set_time(class_dev->dev, tm);
+
-+ up(&rtc->ops_lock);
++ mutex_unlock(&rtc->ops_lock);
+ return err;
+}
+EXPORT_SYMBOL(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);
++
++ if ((err = mutex_lock_interruptible(&rtc->ops_lock)))
++ return err;
++
++ if (!rtc->ops)
++ err = -ENODEV;
++ else if (!rtc->ops->set_mmss) {
++ if (rtc->ops->read_time && rtc->ops->set_time) {
++ struct rtc_time new, old;
++
++ new.tm_sec = secs % 60;
++ secs /= 60;
++ new.tm_min = secs % 60;
++ secs /= 60;
++ new.tm_hour = secs % 24;
++
++ /*
++ * 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;
++ }
++ else
++ err = rtc->ops->set_mmss(class_dev->dev, secs);
++
++ mutex_unlock(&rtc->ops_lock);
++
++ return err;
++}
++EXPORT_SYMBOL(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);
+
-+ if ((err = down_interruptible(&rtc->ops_lock)))
++ if ((err = mutex_lock_interruptible(&rtc->ops_lock)))
+ return err;
+
+ if (rtc->ops == NULL)
@@ -483,7 +542,7 @@
+ err = rtc->ops->read_alarm(class_dev->dev, alarm);
+ }
+
-+ up(&rtc->ops_lock);
++ mutex_unlock(&rtc->ops_lock);
+ return err;
+}
+EXPORT_SYMBOL(rtc_read_alarm);
@@ -493,7 +552,7 @@
+ int err;
+ struct rtc_device *rtc = to_rtc_device(class_dev);
+
-+ if ((err = down_interruptible(&rtc->ops_lock)))
++ if ((err = mutex_lock_interruptible(&rtc->ops_lock)))
+ return err;
+
+ if (!rtc->ops)
@@ -503,7 +562,7 @@
+ else
+ err = rtc->ops->set_alarm(class_dev->dev, alarm);
+
-+ up(&rtc->ops_lock);
++ mutex_unlock(&rtc->ops_lock);
+ return err;
+}
+EXPORT_SYMBOL(rtc_set_alarm);
@@ -527,7 +586,7 @@
+}
+EXPORT_SYMBOL(rtc_update_irq);
+
-+struct class_device *rtc_open(char *name)
++struct class_device *rtc_class_open(char *name)
+{
+ struct class_device *class_dev = NULL,
+ *class_dev_tmp;
@@ -548,13 +607,13 @@
+
+ return class_dev;
+}
-+EXPORT_SYMBOL(rtc_open);
++EXPORT_SYMBOL(rtc_class_open);
+
-+void rtc_close(struct class_device *class_dev)
++void rtc_class_close(struct class_device *class_dev)
+{
+ module_put(to_rtc_device(class_dev)->owner);
+}
-+EXPORT_SYMBOL(rtc_close);
++EXPORT_SYMBOL(rtc_class_close);
+
+int rtc_irq_register(struct class_device *class_dev, struct rtc_task *task)
+{
@@ -637,7 +696,7 @@
+
+}
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
-+++ linux-nslu2/drivers/rtc/utils.c 2006-02-06 21:11:33.000000000 +0100
++++ linux-rtc/drivers/rtc/utils.c 2006-02-19 23:33:15.000000000 +0100
@@ -0,0 +1,97 @@
+/*
+ * RTC subsystem, utility functions
@@ -737,8 +796,8 @@
+}
+EXPORT_SYMBOL(rtc_tm_to_time);
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
-+++ linux-nslu2/drivers/rtc/hctosys.c 2006-02-06 21:11:33.000000000 +0100
-@@ -0,0 +1,62 @@
++++ linux-rtc/drivers/rtc/hctosys.c 2006-02-21 00:34:57.000000000 +0100
+@@ -0,0 +1,67 @@
+/*
+ * RTC subsystem, initialize system time on startup
+ *
@@ -766,12 +825,17 @@
+static int __init rtc_hctosys(void)
+{
+ int err;
-+ struct class_device *class_dev = rtc_open(CONFIG_RTC_HCTOSYS_DEVICE);
++ struct rtc_time tm;
++ struct class_device *class_dev = rtc_class_open(CONFIG_RTC_HCTOSYS_DEVICE);
+
-+ if (class_dev) {
-+ struct rtc_time tm;
++ if (class_dev == NULL) {
++ printk("%s: unable to open rtc device (%s)\n",
++ __FILE__, CONFIG_RTC_HCTOSYS_DEVICE);
++ return -ENODEV;
++ }
+
-+ if ((err = rtc_read_time(class_dev, &tm)) == 0) {
++ if ((err = rtc_read_time(class_dev, &tm)) == 0) {
++ if (rtc_valid_tm(&tm) == 0) {
+ struct timespec tv;
+
+ tv.tv_nsec = NSEC_PER_SEC >> 1;
@@ -789,21 +853,21 @@
+ }
+ else
+ dev_err(class_dev->dev,
-+ "unable to set the system clock\n");
-+
-+ rtc_close(class_dev);
++ "hctosys: invalid date/time\n");
+ }
+ else
-+ printk("%s: unable to open rtc device (%s)\n",
-+ __FILE__, CONFIG_RTC_HCTOSYS_DEVICE);
++ 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-nslu2.orig/arch/arm/Kconfig 2006-02-06 23:52:28.000000000 +0100
-+++ linux-nslu2/arch/arm/Kconfig 2006-02-06 23:53:25.000000000 +0100
-@@ -784,6 +784,8 @@ source "drivers/usb/Kconfig"
+--- linux-rtc.orig/arch/arm/Kconfig 2006-02-21 00:34:27.000000000 +0100
++++ linux-rtc/arch/arm/Kconfig 2006-02-21 00:36:42.000000000 +0100
+@@ -817,6 +817,8 @@ source "drivers/usb/Kconfig"
source "drivers/mmc/Kconfig"
@@ -812,8 +876,8 @@
endmenu
source "fs/Kconfig"
---- linux-nslu2.orig/arch/arm/common/rtctime.c 2006-02-06 23:52:28.000000000 +0100
-+++ linux-nslu2/arch/arm/common/rtctime.c 2006-02-06 23:53:25.000000000 +0100
+--- linux-rtc.orig/arch/arm/common/rtctime.c 2006-02-21 00:34:27.000000000 +0100
++++ linux-rtc/arch/arm/common/rtctime.c 2006-02-21 00:36:42.000000000 +0100
@@ -42,89 +42,6 @@ static struct rtc_ops *rtc_ops;
#define rtc_epoch 1900UL
@@ -984,24 +1048,6 @@
if (ret)
break;
ret = copy_to_user(uarg, &alrm, sizeof(alrm));
-@@ -353,7 +270,7 @@ static int rtc_ioctl(struct inode *inode
- return ret;
- }
-
--static int rtc_open(struct inode *inode, struct file *file)
-+static int rtc_arm_open(struct inode *inode, struct file *file)
- {
- int ret;
-
-@@ -408,7 +325,7 @@ static struct file_operations rtc_fops =
- .read = rtc_read,
- .poll = rtc_poll,
- .ioctl = rtc_ioctl,
-- .open = rtc_open,
-+ .open = rtc_arm_open,
- .release = rtc_release,
- .fasync = rtc_fasync,
- };
@@ -427,7 +344,7 @@ static int rtc_read_proc(char *page, cha
struct rtc_time tm;
char *p = page;
@@ -1020,8 +1066,8 @@
p += sprintf(p, "alrm_time\t: ");
if ((unsigned int)alrm.time.tm_hour <= 24)
p += sprintf(p, "%02d:", alrm.time.tm_hour);
---- linux-nslu2.orig/include/asm-arm/rtc.h 2006-02-06 23:52:28.000000000 +0100
-+++ linux-nslu2/include/asm-arm/rtc.h 2006-02-06 23:53:25.000000000 +0100
+--- linux-rtc.orig/include/asm-arm/rtc.h 2006-02-21 00:34:27.000000000 +0100
++++ linux-rtc/include/asm-arm/rtc.h 2006-02-21 00:36:42.000000000 +0100
@@ -25,9 +25,6 @@ struct rtc_ops {
int (*proc)(char *buf);
};
@@ -1032,9 +1078,1269 @@
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-rtc.orig/drivers/char/Kconfig 2006-02-21 00:34:27.000000000 +0100
++++ linux-rtc/drivers/char/Kconfig 2006-02-21 00:36:42.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-rtc.orig/drivers/i2c/chips/x1205.c 2006-02-21 00:34:27.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-rtc.orig/drivers/i2c/chips/Makefile 2006-02-21 00:34:27.000000000 +0100
++++ linux-rtc/drivers/i2c/chips/Makefile 2006-02-21 00:36:43.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-rtc.orig/drivers/i2c/chips/rtc8564.c 2006-02-21 00:34:27.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-rtc.orig/drivers/i2c/chips/rtc8564.h 2006-02-21 00:34:27.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-rtc.orig/include/linux/x1205.h 2006-02-21 00:34:27.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-rtc.orig/drivers/i2c/chips/Kconfig 2006-02-21 00:34:27.000000000 +0100
++++ linux-rtc/drivers/i2c/chips/Kconfig 2006-02-21 00:36:43.000000000 +0100
+@@ -65,15 +65,6 @@ config SENSORS_PCF8591
+ 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
+@@ -126,13 +117,4 @@ config SENSORS_MAX6875
+ 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-nslu2/drivers/rtc/rtc-sysfs.c 2006-02-06 23:56:37.000000000 +0100
-@@ -0,0 +1,113 @@
++++ linux-rtc/drivers/rtc/rtc-sysfs.c 2006-02-21 00:36:43.000000000 +0100
+@@ -0,0 +1,120 @@
+/*
+ * RTC subsystem, sysfs interface
+ *
@@ -1059,8 +2365,7 @@
+
+static ssize_t rtc_sysfs_show_date(struct class_device *dev, char *buf)
+{
-+ ssize_t retval = -ENODEV;
-+ struct rtc_device *rtc = to_rtc_device(dev);
++ ssize_t retval;
+ struct rtc_time tm;
+
+ if ((retval = rtc_read_time(dev, &tm)) == 0) {
@@ -1074,8 +2379,7 @@
+
+static ssize_t rtc_sysfs_show_time(struct class_device *dev, char *buf)
+{
-+ ssize_t retval = -ENODEV;
-+ struct rtc_device *rtc = to_rtc_device(dev);
++ ssize_t retval;
+ struct rtc_time tm;
+
+ if ((retval = rtc_read_time(dev, &tm)) == 0) {
@@ -1089,8 +2393,7 @@
+
+static ssize_t rtc_sysfs_show_since_epoch(struct class_device *dev, char *buf)
+{
-+ ssize_t retval = -ENODEV;
-+ struct rtc_device *rtc = to_rtc_device(dev);
++ ssize_t retval;
+ struct rtc_time tm;
+
+ if ((retval = rtc_read_time(dev, &tm)) == 0) {
@@ -1103,26 +2406,36 @@
+}
+static CLASS_DEVICE_ATTR(since_epoch, S_IRUGO, rtc_sysfs_show_since_epoch, NULL);
+
-+/* insertion/removal hooks */
++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)
+{
-+ class_device_create_file(class_dev, &class_device_attr_name);
-+ class_device_create_file(class_dev, &class_device_attr_date);
-+ class_device_create_file(class_dev, &class_device_attr_time);
-+ class_device_create_file(class_dev, &class_device_attr_since_epoch);
++ int err;
++
+ dev_info(class_dev->dev, "rtc intf: sysfs\n");
-+ return 0;
++
++ if ((err = sysfs_create_group(&class_dev->kobj, &rtc_attr_group)) != 0)
++ 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)
+{
-+ class_device_remove_file(class_dev, &class_device_attr_name);
-+ class_device_remove_file(class_dev, &class_device_attr_date);
-+ class_device_remove_file(class_dev, &class_device_attr_time);
-+ class_device_remove_file(class_dev, &class_device_attr_since_epoch);
++ sysfs_remove_group(&class_dev->kobj, &rtc_attr_group);
+}
+
+/* interface registration */
@@ -1149,7 +2462,7 @@
+MODULE_DESCRIPTION("RTC class sysfs interface");
+MODULE_LICENSE("GPL");
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
-+++ linux-nslu2/drivers/rtc/rtc-proc.c 2006-02-06 23:58:32.000000000 +0100
++++ linux-rtc/drivers/rtc/rtc-proc.c 2006-02-21 00:36:43.000000000 +0100
@@ -0,0 +1,158 @@
+/*
+ * RTC subsystem, proc interface
@@ -1170,7 +2483,7 @@
+#include <linux/seq_file.h>
+
+static struct class_device *rtc_dev = NULL;
-+static DECLARE_MUTEX(rtc_sem);
++static DEFINE_MUTEX(rtc_lock);
+
+static int rtc_proc_show(struct seq_file *seq, void *offset)
+{
@@ -1254,7 +2567,7 @@
+static int rtc_proc_add_device(struct class_device *class_dev,
+ struct class_interface *class_intf)
+{
-+ down(&rtc_sem);
++ mutex_lock(&rtc_lock);
+ if (rtc_dev == NULL) {
+ struct proc_dir_entry *ent;
+
@@ -1272,7 +2585,7 @@
+ else
+ rtc_dev = NULL;
+ }
-+ up(&rtc_sem);
++ mutex_unlock(&rtc_lock);
+
+ return 0;
+}
@@ -1280,12 +2593,12 @@
+static void rtc_proc_remove_device(struct class_device *class_dev,
+ struct class_interface *class_intf)
+{
-+ down(&rtc_sem);
++ mutex_lock(&rtc_lock);
+ if (rtc_dev == class_dev) {
+ remove_proc_entry("driver/rtc", NULL);
+ rtc_dev = NULL;
+ }
-+ up(&rtc_sem);
++ mutex_unlock(&rtc_lock);
+}
+
+struct class_interface rtc_proc_interface = {
@@ -1310,8 +2623,8 @@
+MODULE_DESCRIPTION("RTC class proc interface");
+MODULE_LICENSE("GPL");
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
-+++ linux-nslu2/drivers/rtc/rtc-dev.c 2006-02-06 23:58:32.000000000 +0100
-@@ -0,0 +1,366 @@
++++ linux-rtc/drivers/rtc/rtc-dev.c 2006-02-21 00:36:43.000000000 +0100
+@@ -0,0 +1,370 @@
+/*
+ * RTC subsystem, dev interface
+ *
@@ -1342,7 +2655,7 @@
+ /* We keep the lock as long as the device is in use
+ * and return immediately if busy
+ */
-+ if (down_trylock(&rtc->char_sem))
++ if (!(mutex_trylock(&rtc->char_lock)))
+ return -EBUSY;
+
+ file->private_data = &rtc->class_dev;
@@ -1358,7 +2671,7 @@
+ }
+
+ /* something has gone wrong, release the lock */
-+ up(&rtc->char_sem);
++ mutex_unlock(&rtc->char_lock);
+ return err;
+}
+
@@ -1402,6 +2715,10 @@
+ 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);
@@ -1549,7 +2866,7 @@
+ if (rtc->ops->release)
+ rtc->ops->release(rtc->class_dev.dev);
+
-+ up(&rtc->char_sem);
++ mutex_unlock(&rtc->char_lock);
+ return 0;
+}
+
@@ -1588,7 +2905,7 @@
+ return -EINVAL;
+ }
+
-+ init_MUTEX(&rtc->char_sem);
++ mutex_init(&rtc->char_lock);
+ spin_lock_init(&rtc->irq_lock);
+ init_waitqueue_head(&rtc->irq_queue);
+
@@ -1679,16 +2996,16 @@
+MODULE_DESCRIPTION("RTC class dev interface");
+MODULE_LICENSE("GPL");
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
-+++ linux-nslu2/drivers/rtc/rtc-x1205.c 2006-02-06 23:58:32.000000000 +0100
-@@ -0,0 +1,672 @@
++++ linux-rtc/drivers/rtc/rtc-x1205.c 2006-02-21 00:36:43.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:
-+ * kas11 at tampabay dot rr dot com
-+ * a dot zummo at towertech dot it
++ * Karen Spearel <kas111 at gmail dot com>
++ * Alessandro Zummo <a.zummo@towertech.it>
+ *
+ * based on a lot of other RTC drivers.
+ *
@@ -1698,17 +3015,12 @@
+ * (at your option) any later version.
+ */
+
-+#include <linux/module.h>
-+#include <linux/init.h>
-+#include <linux/slab.h>
-+#include <linux/err.h>
+#include <linux/i2c.h>
-+#include <linux/string.h>
+#include <linux/bcd.h>
+#include <linux/rtc.h>
+#include <linux/delay.h>
+
-+#define DRV_VERSION "1.0.5"
++#define DRV_VERSION "1.0.6"
+
+/* Addresses to scan: none. This chip is located at
+ * 0x6f and uses a two bytes register addressing.
@@ -1900,14 +3212,12 @@
+ }
+
+ /* this sequence is required to unlock the chip */
-+ xfer = i2c_master_send(client, wel, 3);
-+ if (xfer != 3) {
++ if ((xfer = i2c_master_send(client, wel, 3)) != 3) {
+ dev_err(&client->dev, "%s: wel - %d\n", __FUNCTION__, xfer);
+ return -EIO;
+ }
+
-+ xfer = i2c_master_send(client, rwel, 3);
-+ if (xfer != 3) {
++ if ((xfer = i2c_master_send(client, rwel, 3)) != 3) {
+ dev_err(&client->dev, "%s: rwel - %d\n", __FUNCTION__, xfer);
+ return -EIO;
+ }
@@ -1927,8 +3237,7 @@
+ };
+
+ /* disable further writes */
-+ xfer = i2c_master_send(client, diswe, 3);
-+ if (xfer != 3) {
++ if ((xfer = i2c_master_send(client, diswe, 3)) != 3) {
+ dev_err(&client->dev, "%s: diswe - %d\n", __FUNCTION__, xfer);
+ return -EIO;
+ }
@@ -1941,13 +3250,11 @@
+ int err;
+ struct rtc_time tm;
+
-+ tm.tm_hour = 0;
-+ tm.tm_min = 0;
-+ tm.tm_sec = 0;
++ 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 clock\n");
++ "unable to restart the oscillator\n");
+
+ return err;
+}
@@ -2020,10 +3327,7 @@
+
+struct x1205_limit
+{
-+ unsigned char reg;
-+ unsigned char mask;
-+ unsigned char min;
-+ unsigned char max;
++ unsigned char reg, mask, min, max;
+};
+
+static int x1205_validate_client(struct i2c_client *client)
@@ -2067,11 +3371,10 @@
+ { client->addr, I2C_M_RD, 1, &buf },
+ };
+
-+ xfer = i2c_transfer(client->adapter, msgs, 2);
-+ if (xfer != 2) {
++ if ((xfer = i2c_transfer(client->adapter, msgs, 2)) != 2) {
+ dev_err(&client->adapter->dev,
+ "%s: could not read register %x\n",
-+ __FUNCTION__, addr[1]);
++ __FUNCTION__, probe_zero_pattern[i]);
+
+ return -EIO;
+ }
@@ -2079,7 +3382,7 @@
+ 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);
++ __FUNCTION__, probe_zero_pattern[i], i, buf);
+
+ return -ENODEV;
+ }
@@ -2096,12 +3399,10 @@
+ { client->addr, I2C_M_RD, 1, &reg },
+ };
+
-+ xfer = i2c_transfer(client->adapter, msgs, 2);
-+
-+ if (xfer != 2) {
++ if ((xfer = i2c_transfer(client->adapter, msgs, 2)) != 2) {
+ dev_err(&client->adapter->dev,
+ "%s: could not read register %x\n",
-+ __FUNCTION__, addr[1]);
++ __FUNCTION__, probe_limits_pattern[i].reg);
+
+ return -EIO;
+ }
@@ -2112,7 +3413,8 @@
+ 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);
++ __FUNCTION__, probe_limits_pattern[i].reg,
++ i, value);
+
+ return -ENODEV;
+ }
@@ -2121,87 +3423,51 @@
+ return 0;
+}
+
-+static int x1205_rtc_read_alarm(struct device *dev,
-+ struct rtc_wkalrm *alrm)
++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)
++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)
++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)
++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_set_mmss(struct device *dev, unsigned long secs)
-+{
-+ int err;
-+
-+ struct rtc_time new_tm, old_tm;
-+
-+ if ((err = x1205_rtc_read_time(dev, &old_tm) == 0))
-+ return err;
-+
-+ /* FIXME xtime.tv_nsec = old_tm.tm_sec * 10000000; */
-+ new_tm.tm_sec = secs % 60;
-+ secs /= 60;
-+ new_tm.tm_min = secs % 60;
-+ secs /= 60;
-+ new_tm.tm_hour = secs % 24;
-+
-+ /*
-+ * 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.tm_hour == 23 && old_tm.tm_min == 59) ||
-+ (new_tm.tm_hour == 23 && new_tm.tm_min == 59))
-+ return 1;
-+
-+ return x1205_rtc_set_time(dev, &new_tm);
-+}
-+
+static int x1205_rtc_proc(struct device *dev, struct seq_file *seq)
+{
+ int err, dtrim, atrim;
+
+ seq_printf(seq, "24hr\t\t: yes\n");
+
-+ err = x1205_get_dtrim(to_i2c_client(dev), &dtrim);
-+ if (err == 0)
++ if ((err = x1205_get_dtrim(to_i2c_client(dev), &dtrim)) == 0)
+ seq_printf(seq, "digital_trim\t: %d ppm\n", dtrim);
+
-+ err = x1205_get_atrim(to_i2c_client(dev), &atrim);
-+ if (err == 0)
++ 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,
-+ .set_mmss = x1205_rtc_set_mmss,
++ .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,
@@ -2209,10 +3475,10 @@
+{
+ 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;
++ 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);
+
@@ -2221,18 +3487,16 @@
+{
+ int dtrim;
+
-+ if (x1205_get_dtrim(to_i2c_client(dev), &dtrim) == 0) {
-+ return sprintf(buf, "%d ppm\n", dtrim);
-+ }
-+ return 0;
++ 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);
+}
+
@@ -2345,7 +3609,7 @@
+}
+
+MODULE_AUTHOR(
-+ "Karen Spearel <kas11@tampabay.rr.com>, "
++ "Karen Spearel <kas111 at gmail dot com>, "
+ "Alessandro Zummo <a.zummo@towertech.it>");
+MODULE_DESCRIPTION("Xicor/Intersil X1205 RTC driver");
+MODULE_LICENSE("GPL");
@@ -2354,7 +3618,7 @@
+module_init(x1205_init);
+module_exit(x1205_exit);
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
-+++ linux-nslu2/drivers/rtc/rtc-test.c 2006-02-06 23:58:32.000000000 +0100
++++ linux-rtc/drivers/rtc/rtc-test.c 2006-02-21 00:36:43.000000000 +0100
@@ -0,0 +1,206 @@
+/*
+ * An RTC test device/driver
@@ -2563,8 +3827,8 @@
+module_init(test_init);
+module_exit(test_exit);
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
-+++ linux-nslu2/drivers/rtc/rtc-ds1672.c 2006-02-06 23:58:32.000000000 +0100
-@@ -0,0 +1,234 @@
++++ linux-rtc/drivers/rtc/rtc-ds1672.c 2006-02-21 00:36:43.000000000 +0100
+@@ -0,0 +1,233 @@
+/*
+ * An rtc/i2c driver for the Dallas DS1672
+ * Copyright 2005 Alessandro Zummo
@@ -2689,15 +3953,14 @@
+}
+
+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,
++ .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);
+}
+
@@ -2800,8 +4063,8 @@
+module_init(ds1672_init);
+module_exit(ds1672_exit);
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
-+++ linux-nslu2/drivers/rtc/rtc-pcf8563.c 2006-02-06 23:58:32.000000000 +0100
-@@ -0,0 +1,384 @@
++++ linux-rtc/drivers/rtc/rtc-pcf8563.c 2006-02-21 00:36:43.000000000 +0100
+@@ -0,0 +1,355 @@
+/*
+ * An I2C driver for the Philips PCF8563 RTC
+ * Copyright 2005-06 Tower Technologies
@@ -2819,15 +4082,18 @@
+ * (at your option) any later version.
+ */
+
-+#include <linux/module.h>
+#include <linux/i2c.h>
+#include <linux/bcd.h>
+#include <linux/rtc.h>
+
-+#define DRV_VERSION "0.4.0"
++#define DRV_VERSION "0.4.2"
+
-+/* Addresses to scan */
-+static unsigned short normal_i2c[] = { 0x51, I2C_CLIENT_END };
++/* 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;
@@ -2874,11 +4140,10 @@
+ */
+static int pcf8563_get_datetime(struct i2c_client *client, struct rtc_time *tm)
+{
-+ unsigned char buf[13];
-+ unsigned char addr = PCF8563_REG_ST1;
++ unsigned char buf[13] = { PCF8563_REG_ST1 };
+
+ struct i2c_msg msgs[] = {
-+ { client->addr, 0, 1, &addr }, /* setup read ptr */
++ { client->addr, 0, 1, buf }, /* setup read ptr */
+ { client->addr, I2C_M_RD, 13, buf }, /* read status + date */
+ };
+
@@ -2980,46 +4245,48 @@
+
+static int pcf8563_validate_client(struct i2c_client *client)
+{
-+ int i, xfer;
++ int i;
+
-+ static const struct pcf8563_limit probe_limits_pattern[] = {
++ 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 },
-+ { PCF8563_REG_YR, 0xFF, 0, 99 },
+ };
+
+ /* check limits (only registers with bcd values) */
-+ for (i = 0; i < ARRAY_SIZE(probe_limits_pattern); i++) {
-+ unsigned char addr, buf, value;
++ for (i = 0; i < ARRAY_SIZE(pattern); i++) {
++ int xfer;
++ unsigned char value;
++ unsigned char buf = pattern[i].reg;
+
-+ addr = probe_limits_pattern[i].reg;
-+
-+ struct i2c_msg msgs[2] = {
-+ { client->addr, 0, 2, &addr },
++ struct i2c_msg msgs[] = {
++ { client->addr, 0, 1, &buf },
+ { client->addr, I2C_M_RD, 1, &buf },
+ };
+
-+ xfer = i2c_transfer(client->adapter, msgs, 2);
++ xfer = i2c_transfer(client->adapter, msgs, ARRAY_SIZE(msgs));
+
-+ if (xfer != 2) {
++ if (xfer != ARRAY_SIZE(msgs)) {
+ dev_err(&client->adapter->dev,
-+ "%s: could not read register %x\n",
-+ __FUNCTION__, probe_limits_pattern[i].reg);
++ "%s: could not read register 0x%02X\n",
++ __FUNCTION__, pattern[i].reg);
+
+ return -EIO;
+ }
+
-+ value = BCD2BIN(buf & probe_limits_pattern[i].mask);
++ value = BCD2BIN(buf & pattern[i].mask);
+
-+ if (value > probe_limits_pattern[i].max ||
-+ value < probe_limits_pattern[i].min) {
++ if (value > pattern[i].max ||
++ value < 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);
++ "%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;
+ }
@@ -3028,47 +4295,16 @@
+ return 0;
+}
+
-+static int pcf8563_rtc_read_time(struct device *dev,
-+ struct rtc_time *tm)
++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)
++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_set_mmss(struct device *dev, unsigned long secs)
-+{
-+ int err;
-+
-+ struct rtc_time new_tm, old_tm;
-+
-+ if ((err = pcf8563_rtc_read_time(dev, &old_tm) == 0))
-+ return err;
-+
-+ /* FIXME xtime.tv_nsec = old_tm.tm_sec * 10000000; */
-+ new_tm.tm_sec = secs % 60;
-+ secs /= 60;
-+ new_tm.tm_min = secs % 60;
-+ secs /= 60;
-+ new_tm.tm_hour = secs % 24;
-+
-+ /*
-+ * 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.tm_hour == 23 && old_tm.tm_min == 59) ||
-+ (new_tm.tm_hour == 23 && new_tm.tm_min == 59))
-+ return 1;
-+
-+ return pcf8563_rtc_set_time(dev, &new_tm);
-+}
-+
+static int pcf8563_rtc_proc(struct device *dev, struct seq_file *seq)
+{
+ seq_printf(seq, "24hr\t\t: yes\n");
@@ -3076,10 +4312,9 @@
+}
+
+static struct rtc_class_ops pcf8563_rtc_ops = {
-+ .proc = pcf8563_rtc_proc,
-+ .read_time = pcf8563_rtc_read_time,
-+ .set_time = pcf8563_rtc_set_time,
-+ .set_mmss = pcf8563_rtc_set_mmss,
++ .proc = pcf8563_rtc_proc,
++ .read_time = pcf8563_rtc_read_time,
++ .set_time = pcf8563_rtc_set_time,
+};
+
+static int pcf8563_attach(struct i2c_adapter *adapter)
@@ -3185,4 +4420,301 @@
+
+module_init(pcf8563_init);
+module_exit(pcf8563_exit);
+--- /dev/null 1970-01-01 00:00:00.000000000 +0000
++++ linux-rtc/drivers/rtc/rtc-rs5c372.c 2006-02-21 00:36:43.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);