diff options
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.patch | 2076 |
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, ® }, +- }; +- +- 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, ® }, + }; + -+ 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); |