--- CREDITS | 5 MAINTAINERS | 6 arch/arm/Kconfig | 3 arch/arm/common/rtctime.c | 108 -- arch/arm/mach-integrator/time.c | 16 arch/arm/mach-pxa/generic.c | 6 arch/arm/mach-sa1100/generic.c | 6 arch/mips/ddb5xxx/common/rtc_ds1386.c | 4 arch/mips/dec/time.c | 4 arch/mips/ite-boards/generic/time.c | 4 arch/mips/jmr3927/common/rtc_ds1742.c | 4 arch/mips/kernel/time.c | 22 arch/mips/lasat/setup.c | 4 arch/mips/mips-boards/atlas/atlas_setup.c | 2 arch/mips/mips-boards/malta/malta_setup.c | 2 arch/mips/momentum/jaguar_atx/setup.c | 4 arch/mips/momentum/ocelot_3/setup.c | 4 arch/mips/momentum/ocelot_c/setup.c | 4 arch/mips/pmc-sierra/yosemite/setup.c | 4 arch/mips/sgi-ip22/ip22-time.c | 4 arch/mips/sgi-ip32/ip32-setup.c | 4 arch/mips/sibyte/swarm/setup.c | 8 arch/mips/sni/setup.c | 4 arch/mips/tx4927/toshiba_rbtx4927/toshiba_rbtx4927_setup.c | 4 arch/mips/tx4938/common/rtc_rx5c348.c | 4 drivers/Kconfig | 2 drivers/Makefile | 1 drivers/char/Kconfig | 2 drivers/i2c/chips/Kconfig | 18 drivers/i2c/chips/Makefile | 2 drivers/i2c/chips/rtc8564.c | 385 ------- drivers/i2c/chips/rtc8564.h | 78 - drivers/i2c/chips/x1205.c | 698 ------------- drivers/rtc/Kconfig | 156 ++ drivers/rtc/Makefile | 20 drivers/rtc/class.c | 145 ++ drivers/rtc/hctosys.c | 69 + drivers/rtc/interface.c | 277 +++++ drivers/rtc/rtc-dev.c | 382 +++++++ drivers/rtc/rtc-ds1672.c | 233 ++++ drivers/rtc/rtc-ep93xx.c | 163 +++ drivers/rtc/rtc-lib.c | 99 + drivers/rtc/rtc-pcf8563.c | 355 ++++++ drivers/rtc/rtc-proc.c | 162 +++ drivers/rtc/rtc-rs5c372.c | 295 +++++ drivers/rtc/rtc-sa1100.c | 392 +++++++ drivers/rtc/rtc-sysfs.c | 124 ++ drivers/rtc/rtc-test.c | 205 +++ drivers/rtc/rtc-x1205.c | 619 +++++++++++ include/asm-arm/rtc.h | 3 include/asm-mips/time.h | 12 include/linux/rtc.h | 92 + include/linux/x1205.h | 31 53 files changed, 3888 insertions(+), 1372 deletions(-) --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ linux-ixp4xx/drivers/rtc/rtc-lib.c 2006-03-08 01:59:26.000000000 +0100 @@ -0,0 +1,99 @@ +/* + * rtc and date/time utility functions + * + * Copyright (C) 2005-06 Tower Technologies + * Author: Alessandro Zummo + * + * based on arch/arm/common/rtctime.c and other bits + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. +*/ + +#include +#include + +static const unsigned char rtc_days_in_month[] = { + 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 +}; + +#define LEAPS_THRU_END_OF(y) ((y)/4 - (y)/100 + (y)/400) +#define LEAP_YEAR(year) ((!(year % 4) && (year % 100)) || !(year % 400)) + +int rtc_month_days(unsigned int month, unsigned int year) +{ + return rtc_days_in_month[month] + (LEAP_YEAR(year) && month == 1); +} +EXPORT_SYMBOL(rtc_month_days); + +/* + * Convert seconds since 01-01-1970 00:00:00 to Gregorian date. + */ +void rtc_time_to_tm(unsigned long time, struct rtc_time *tm) +{ + register int days, month, year; + + days = time / 86400; + time -= days * 86400; + + /* day of the week, 1970-01-01 was a Thursday */ + tm->tm_wday = (days + 4) % 7; + + year = 1970 + days / 365; + days -= (year - 1970) * 365 + + LEAPS_THRU_END_OF(year - 1) + - LEAPS_THRU_END_OF(1970 - 1); + if (days < 0) { + year -= 1; + days += 365 + LEAP_YEAR(year); + } + tm->tm_year = year - 1900; + tm->tm_yday = days + 1; + + for (month = 0; month < 11; month++) { + int newdays; + + newdays = days - rtc_month_days(month, year); + if (newdays < 0) + break; + days = newdays; + } + tm->tm_mon = month; + tm->tm_mday = days + 1; + + tm->tm_hour = time / 3600; + time -= tm->tm_hour * 3600; + tm->tm_min = time / 60; + tm->tm_sec = time - tm->tm_min * 60; +} +EXPORT_SYMBOL(rtc_time_to_tm); + +/* + * Does the rtc_time represent a valid date/time? + */ +int rtc_valid_tm(struct rtc_time *tm) +{ + if (tm->tm_year < 70 + || tm->tm_mon >= 12 + || tm->tm_mday < 1 + || tm->tm_mday > rtc_month_days(tm->tm_mon, tm->tm_year + 1900) + || tm->tm_hour >= 24 + || tm->tm_min >= 60 + || tm->tm_sec >= 60) + return -EINVAL; + + return 0; +} +EXPORT_SYMBOL(rtc_valid_tm); + +/* + * Convert Gregorian date to seconds since 01-01-1970 00:00:00. + */ +int rtc_tm_to_time(struct rtc_time *tm, unsigned long *time) +{ + *time = mktime(tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday, + tm->tm_hour, tm->tm_min, tm->tm_sec); + return 0; +} +EXPORT_SYMBOL(rtc_tm_to_time); --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ linux-ixp4xx/drivers/rtc/Makefile 2006-03-08 01:59:26.000000000 +0100 @@ -0,0 +1,20 @@ +# +# Makefile for RTC class/drivers. +# + +obj-$(CONFIG_RTC_LIB) += rtc-lib.o +obj-$(CONFIG_RTC_HCTOSYS) += hctosys.o +obj-$(CONFIG_RTC_CLASS) += rtc-core.o +rtc-core-y := class.o interface.o + +obj-$(CONFIG_RTC_INTF_SYSFS) += rtc-sysfs.o +obj-$(CONFIG_RTC_INTF_PROC) += rtc-proc.o +obj-$(CONFIG_RTC_INTF_DEV) += rtc-dev.o + +obj-$(CONFIG_RTC_DRV_X1205) += rtc-x1205.o +obj-$(CONFIG_RTC_DRV_TEST) += rtc-test.o +obj-$(CONFIG_RTC_DRV_DS1672) += rtc-ds1672.o +obj-$(CONFIG_RTC_DRV_PCF8563) += rtc-pcf8563.o +obj-$(CONFIG_RTC_DRV_RS5C372) += rtc-rs5c372.o +obj-$(CONFIG_RTC_DRV_EP93XX) += rtc-ep93xx.o +obj-$(CONFIG_RTC_DRV_SA1100) += rtc-sa1100.o --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ linux-ixp4xx/drivers/rtc/Kconfig 2006-03-08 01:59:26.000000000 +0100 @@ -0,0 +1,156 @@ +\# +# RTC class/drivers configuration +# + +menu "Real Time Clock" + +config RTC_LIB + bool + +config RTC_CLASS + tristate "RTC class" + depends on EXPERIMENTAL + default n + select RTC_LIB + help + Generic RTC class support. If you say yes here, you will + be allowed to plug one or more RTCs to your system. You will + probably want to enable one of more of the interfaces below. + + This driver can also be built as a module. If so, the module + will be called rtc-class. + +config RTC_HCTOSYS + bool "Set system time from RTC on startup" + depends on RTC_CLASS = y + default y + help + If you say yes here, the system time will be set using + the value read from the specified RTC device. This is useful + in order to avoid unnecessary fschk runs. + +config RTC_HCTOSYS_DEVICE + string "The RTC to read the time from" + depends on RTC_HCTOSYS = y + default "rtc0" + help + The RTC device that will be used as the source for + the system time, usually rtc0. + +comment "RTC interfaces" + depends on RTC_CLASS + +config RTC_INTF_SYSFS + tristate "sysfs" + depends on RTC_CLASS && SYSFS + default RTC_CLASS + help + Say yes here if you want to use your RTC using the sysfs + interface, /sys/class/rtc/rtcX . + + This driver can also be built as a module. If so, the module + will be called rtc-sysfs. + +config RTC_INTF_PROC + tristate "proc" + depends on RTC_CLASS && PROC_FS + default RTC_CLASS + help + Say yes here if you want to use your RTC using the proc + interface, /proc/driver/rtc . + + This driver can also be built as a module. If so, the module + will be called rtc-proc. + +config RTC_INTF_DEV + tristate "dev" + depends on RTC_CLASS + default RTC_CLASS + help + Say yes here if you want to use your RTC using the dev + interface, /dev/rtc . + + This driver can also be built as a module. If so, the module + will be called rtc-dev. + +comment "RTC drivers" + depends on RTC_CLASS + +config RTC_DRV_X1205 + tristate "Xicor/Intersil X1205 RTC chip" + depends on RTC_CLASS && I2C + help + If you say yes here you get support for the + Xicor/Intersil X1205 RTC chip. + + This driver can also be built as a module. If so, the module + will be called rtc-x1205. + +config RTC_DRV_DS1672 + tristate "Dallas/Maxim DS1672" + depends on RTC_CLASS && I2C + help + If you say yes here you get support for the + Dallas/Maxim DS1672 timekeeping chip. + + This driver can also be built as a module. If so, the module + will be called rtc-ds1672. + +config RTC_DRV_PCF8563 + tristate "Philips PCF8563/Epson RTC8564" + depends on RTC_CLASS && I2C + help + If you say yes here you get support for the + Philips PCF8563 RTC chip. The Epson RTC8564 + should work as well. + + This driver can also be built as a module. If so, the module + will be called rtc-pcf8563. + +config RTC_DRV_RS5C372 + tristate "Ricoh RS5C372A/B" + depends on RTC_CLASS && I2C + help + If you say yes here you get support for the + Ricoh RS5C372A and RS5C372B RTC chips. + + This driver can also be built as a module. If so, the module + will be called rtc-rs5c372. + +config RTC_DRV_EP93XX + tristate "Cirrus Logic EP93XX" + depends on RTC_CLASS && ARCH_EP93XX + help + If you say yes here you get support for the + RTC embedded in the Cirrus Logic EP93XX processors. + + This driver can also be built as a module. If so, the module + will be called rtc-ep93xx. + + +config RTC_DRV_SA1100 + bool "SA11x0/PXA2xx RTC support" + depends on ARCH_SA1100 || ARCH_PXA + help + If you say Y here you will get access to the real time clock + built into your SA11x0 or PXA2xx CPU. + + To compile this driver as a module, choose M here: the + module will be called rtc-sa1100. + +config RTC_DRV_TEST + tristate "Test driver/device" + depends on RTC_CLASS + help + If you say yes here you get support for the + RTC test driver. It's a software RTC which can be + used to test the RTC subsystem APIs. It gets + the time from the system clock. + You want this driver only if you are doing development + on the RTC subsystem. Please read the source code + for further details. + + This driver can also be built as a module. If so, the module + will be called rtc-test. + +endmenu --- linux-ixp4xx.orig/drivers/Kconfig 2006-03-08 01:59:18.000000000 +0100 +++ linux-ixp4xx/drivers/Kconfig 2006-03-08 01:59:26.000000000 +0100 @@ -72,4 +72,6 @@ source "drivers/sn/Kconfig" source "drivers/edac/Kconfig" +source "drivers/rtc/Kconfig" + endmenu --- linux-ixp4xx.orig/drivers/Makefile 2006-03-08 01:59:18.000000000 +0100 +++ linux-ixp4xx/drivers/Makefile 2006-03-08 01:59:26.000000000 +0100 @@ -56,6 +56,7 @@ obj-$(CONFIG_USB_GADGET) += usb/gadget/ obj-$(CONFIG_GAMEPORT) += input/gameport/ obj-$(CONFIG_INPUT) += input/ obj-$(CONFIG_I2O) += message/ +obj-$(CONFIG_RTC_LIB) += rtc/ obj-$(CONFIG_I2C) += i2c/ obj-$(CONFIG_W1) += w1/ obj-$(CONFIG_HWMON) += hwmon/ --- linux-ixp4xx.orig/include/linux/rtc.h 2006-03-08 01:59:09.000000000 +0100 +++ linux-ixp4xx/include/linux/rtc.h 2006-03-08 01:59:26.000000000 +0100 @@ -93,8 +93,100 @@ struct rtc_pll_info { #define RTC_PLL_GET _IOR('p', 0x11, struct rtc_pll_info) /* Get PLL correction */ #define RTC_PLL_SET _IOW('p', 0x12, struct rtc_pll_info) /* Set PLL correction */ +/* interrupt flags */ +#define RTC_IRQF 0x80 /* any of the following is active */ +#define RTC_PF 0x40 +#define RTC_AF 0x20 +#define RTC_UF 0x10 + #ifdef __KERNEL__ +extern int rtc_month_days(unsigned int month, unsigned int year); +extern int rtc_valid_tm(struct rtc_time *tm); +extern int rtc_tm_to_time(struct rtc_time *tm, unsigned long *time); +extern void rtc_time_to_tm(unsigned long time, struct rtc_time *tm); + +#include +#include +#include +#include +#include + +extern struct class *rtc_class; + +struct rtc_class_ops { + int (*open)(struct device *); + void (*release)(struct device *); + int (*ioctl)(struct device *, unsigned int, unsigned long); + int (*read_time)(struct device *, struct rtc_time *); + int (*set_time)(struct device *, struct rtc_time *); + int (*read_alarm)(struct device *, struct rtc_wkalrm *); + int (*set_alarm)(struct device *, struct rtc_wkalrm *); + int (*proc)(struct device *, struct seq_file *); + int (*set_mmss)(struct device *, unsigned long secs); + int (*irq_set_state)(struct device *, int enabled); + int (*irq_set_freq)(struct device *, int freq); + int (*read_callback)(struct device *, int data); +}; + +#define RTC_DEVICE_NAME_SIZE 20 +struct rtc_task; + +struct rtc_device +{ + struct class_device class_dev; + struct module *owner; + + int id; + char name[RTC_DEVICE_NAME_SIZE]; + + struct rtc_class_ops *ops; + struct mutex ops_lock; + + struct class_device *rtc_dev; + struct cdev char_dev; + struct mutex char_lock; + + unsigned long irq_data; + spinlock_t irq_lock; + wait_queue_head_t irq_queue; + struct fasync_struct *async_queue; + + struct rtc_task *irq_task; + spinlock_t irq_task_lock; + int irq_freq; +}; +#define to_rtc_device(d) container_of(d, struct rtc_device, class_dev) + +extern struct rtc_device *rtc_device_register(const char *name, + struct device *dev, + struct rtc_class_ops *ops, + struct module *owner); +extern void rtc_device_unregister(struct rtc_device *rdev); +extern int rtc_interface_register(struct class_interface *intf); + +extern int rtc_read_time(struct class_device *class_dev, struct rtc_time *tm); +extern int rtc_set_time(struct class_device *class_dev, struct rtc_time *tm); +extern int rtc_set_mmss(struct class_device *class_dev, unsigned long secs); +extern int rtc_read_alarm(struct class_device *class_dev, + struct rtc_wkalrm *alrm); +extern int rtc_set_alarm(struct class_device *class_dev, + struct rtc_wkalrm *alrm); +extern void rtc_update_irq(struct class_device *class_dev, + unsigned long num, unsigned long events); + +extern struct class_device *rtc_class_open(char *name); +extern void rtc_class_close(struct class_device *class_dev); + +extern int rtc_irq_register(struct class_device *class_dev, + struct rtc_task *task); +extern void rtc_irq_unregister(struct class_device *class_dev, + struct rtc_task *task); +extern int rtc_irq_set_state(struct class_device *class_dev, + struct rtc_task *task, int enabled); +extern int rtc_irq_set_freq(struct class_device *class_dev, + struct rtc_task *task, int freq); + typedef struct rtc_task { void (*func)(void *private_data); void *private_data; --- linux-ixp4xx.orig/arch/arm/common/rtctime.c 2006-03-08 01:59:09.000000000 +0100 +++ linux-ixp4xx/arch/arm/common/rtctime.c 2006-03-08 01:59:26.000000000 +0100 @@ -20,6 +20,7 @@ #include #include #include +#include #include #include @@ -42,89 +43,6 @@ static struct rtc_ops *rtc_ops; #define rtc_epoch 1900UL -static const unsigned char days_in_month[] = { - 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 -}; - -#define LEAPS_THRU_END_OF(y) ((y)/4 - (y)/100 + (y)/400) -#define LEAP_YEAR(year) ((!(year % 4) && (year % 100)) || !(year % 400)) - -static int month_days(unsigned int month, unsigned int year) -{ - return days_in_month[month] + (LEAP_YEAR(year) && month == 1); -} - -/* - * Convert seconds since 01-01-1970 00:00:00 to Gregorian date. - */ -void rtc_time_to_tm(unsigned long time, struct rtc_time *tm) -{ - int days, month, year; - - days = time / 86400; - time -= days * 86400; - - tm->tm_wday = (days + 4) % 7; - - year = 1970 + days / 365; - days -= (year - 1970) * 365 - + LEAPS_THRU_END_OF(year - 1) - - LEAPS_THRU_END_OF(1970 - 1); - if (days < 0) { - year -= 1; - days += 365 + LEAP_YEAR(year); - } - tm->tm_year = year - 1900; - tm->tm_yday = days + 1; - - for (month = 0; month < 11; month++) { - int newdays; - - newdays = days - month_days(month, year); - if (newdays < 0) - break; - days = newdays; - } - tm->tm_mon = month; - tm->tm_mday = days + 1; - - tm->tm_hour = time / 3600; - time -= tm->tm_hour * 3600; - tm->tm_min = time / 60; - tm->tm_sec = time - tm->tm_min * 60; -} -EXPORT_SYMBOL(rtc_time_to_tm); - -/* - * Does the rtc_time represent a valid date/time? - */ -int rtc_valid_tm(struct rtc_time *tm) -{ - if (tm->tm_year < 70 || - tm->tm_mon >= 12 || - tm->tm_mday < 1 || - tm->tm_mday > month_days(tm->tm_mon, tm->tm_year + 1900) || - tm->tm_hour >= 24 || - tm->tm_min >= 60 || - tm->tm_sec >= 60) - return -EINVAL; - - return 0; -} -EXPORT_SYMBOL(rtc_valid_tm); - -/* - * Convert Gregorian date to seconds since 01-01-1970 00:00:00. - */ -int rtc_tm_to_time(struct rtc_time *tm, unsigned long *time) -{ - *time = mktime(tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday, - tm->tm_hour, tm->tm_min, tm->tm_sec); - - return 0; -} -EXPORT_SYMBOL(rtc_tm_to_time); - /* * Calculate the next alarm time given the requested alarm time mask * and the current time. @@ -151,13 +69,13 @@ void rtc_next_alarm_time(struct rtc_time } } -static inline int rtc_read_time(struct rtc_ops *ops, struct rtc_time *tm) +static inline int rtc_arm_read_time(struct rtc_ops *ops, struct rtc_time *tm) { memset(tm, 0, sizeof(struct rtc_time)); return ops->read_time(tm); } -static inline int rtc_set_time(struct rtc_ops *ops, struct rtc_time *tm) +static inline int rtc_arm_set_time(struct rtc_ops *ops, struct rtc_time *tm) { int ret; @@ -168,7 +86,7 @@ static inline int rtc_set_time(struct rt return ret; } -static inline int rtc_read_alarm(struct rtc_ops *ops, struct rtc_wkalrm *alrm) +static inline int rtc_arm_read_alarm(struct rtc_ops *ops, struct rtc_wkalrm *alrm) { int ret = -EINVAL; if (ops->read_alarm) { @@ -178,7 +96,7 @@ static inline int rtc_read_alarm(struct return ret; } -static inline int rtc_set_alarm(struct rtc_ops *ops, struct rtc_wkalrm *alrm) +static inline int rtc_arm_set_alarm(struct rtc_ops *ops, struct rtc_wkalrm *alrm) { int ret = -EINVAL; if (ops->set_alarm) @@ -266,7 +184,7 @@ static int rtc_ioctl(struct inode *inode switch (cmd) { case RTC_ALM_READ: - ret = rtc_read_alarm(ops, &alrm); + ret = rtc_arm_read_alarm(ops, &alrm); if (ret) break; ret = copy_to_user(uarg, &alrm.time, sizeof(tm)); @@ -288,11 +206,11 @@ static int rtc_ioctl(struct inode *inode alrm.time.tm_wday = -1; alrm.time.tm_yday = -1; alrm.time.tm_isdst = -1; - ret = rtc_set_alarm(ops, &alrm); + ret = rtc_arm_set_alarm(ops, &alrm); break; case RTC_RD_TIME: - ret = rtc_read_time(ops, &tm); + ret = rtc_arm_read_time(ops, &tm); if (ret) break; ret = copy_to_user(uarg, &tm, sizeof(tm)); @@ -310,7 +228,7 @@ static int rtc_ioctl(struct inode *inode ret = -EFAULT; break; } - ret = rtc_set_time(ops, &tm); + ret = rtc_arm_set_time(ops, &tm); break; case RTC_EPOCH_SET: @@ -341,11 +259,11 @@ static int rtc_ioctl(struct inode *inode ret = -EFAULT; break; } - ret = rtc_set_alarm(ops, &alrm); + ret = rtc_arm_set_alarm(ops, &alrm); break; case RTC_WKALM_RD: - ret = rtc_read_alarm(ops, &alrm); + ret = rtc_arm_read_alarm(ops, &alrm); if (ret) break; ret = copy_to_user(uarg, &alrm, sizeof(alrm)); @@ -435,7 +353,7 @@ static int rtc_read_proc(char *page, cha struct rtc_time tm; char *p = page; - if (rtc_read_time(ops, &tm) == 0) { + if (rtc_arm_read_time(ops, &tm) == 0) { p += sprintf(p, "rtc_time\t: %02d:%02d:%02d\n" "rtc_date\t: %04d-%02d-%02d\n" @@ -445,7 +363,7 @@ static int rtc_read_proc(char *page, cha rtc_epoch); } - if (rtc_read_alarm(ops, &alrm) == 0) { + if (rtc_arm_read_alarm(ops, &alrm) == 0) { p += sprintf(p, "alrm_time\t: "); if ((unsigned int)alrm.time.tm_hour <= 24) p += sprintf(p, "%02d:", alrm.time.tm_hour); --- linux-ixp4xx.orig/include/asm-arm/rtc.h 2006-03-08 01:59:09.000000000 +0100 +++ linux-ixp4xx/include/asm-arm/rtc.h 2006-03-08 01:59:26.000000000 +0100 @@ -25,9 +25,6 @@ struct rtc_ops { int (*proc)(char *buf); }; -void rtc_time_to_tm(unsigned long, struct rtc_time *); -int rtc_tm_to_time(struct rtc_time *, unsigned long *); -int rtc_valid_tm(struct rtc_time *); void rtc_next_alarm_time(struct rtc_time *, struct rtc_time *, struct rtc_time *); void rtc_update(unsigned long, unsigned long); int register_rtc(struct rtc_ops *); --- linux-ixp4xx.orig/drivers/char/Kconfig 2006-03-08 01:59:09.000000000 +0100 +++ linux-ixp4xx/drivers/char/Kconfig 2006-03-08 01:59:26.000000000 +0100 @@ -695,7 +695,7 @@ config NVRAM config RTC tristate "Enhanced Real Time Clock Support" - depends on !PPC32 && !PARISC && !IA64 && !M68K && (!SPARC || PCI) && !FRV + depends on !PPC32 && !PARISC && !IA64 && !M68K && (!SPARC || PCI) && !FRV && !ARM ---help--- If you say Y here and create a character special file /dev/rtc with major number 10 and minor number 135 using mknod ("man mknod"), you --- linux-ixp4xx.orig/arch/arm/Kconfig 2006-03-08 01:59:18.000000000 +0100 +++ linux-ixp4xx/arch/arm/Kconfig 2006-03-08 01:59:26.000000000 +0100 @@ -8,6 +8,7 @@ mainmenu "Linux Kernel Configuration" config ARM bool default y + select RTC_LIB help The ARM series is a line of low-power-consumption RISC chip designs licensed by ARM Ltd and targeted at embedded applications and @@ -819,6 +820,8 @@ source "drivers/usb/Kconfig" source "drivers/mmc/Kconfig" +source "drivers/rtc/Kconfig" + endmenu source "fs/Kconfig" --- linux-ixp4xx.orig/arch/arm/mach-integrator/time.c 2006-03-08 01:59:09.000000000 +0100 +++ linux-ixp4xx/arch/arm/mach-integrator/time.c 2006-03-08 01:59:26.000000000 +0100 @@ -40,13 +40,13 @@ static int integrator_set_rtc(void) return 1; } -static int rtc_read_alarm(struct rtc_wkalrm *alrm) +static int integrator_rtc_read_alarm(struct rtc_wkalrm *alrm) { rtc_time_to_tm(readl(rtc_base + RTC_MR), &alrm->time); return 0; } -static inline int rtc_set_alarm(struct rtc_wkalrm *alrm) +static inline int integrator_rtc_set_alarm(struct rtc_wkalrm *alrm) { unsigned long time; int ret; @@ -62,7 +62,7 @@ static inline int rtc_set_alarm(struct r return ret; } -static int rtc_read_time(struct rtc_time *tm) +static int integrator_rtc_read_time(struct rtc_time *tm) { rtc_time_to_tm(readl(rtc_base + RTC_DR), tm); return 0; @@ -76,7 +76,7 @@ static int rtc_read_time(struct rtc_time * edge of the 1Hz clock, we must write the time one second * in advance. */ -static inline int rtc_set_time(struct rtc_time *tm) +static inline int integrator_rtc_set_time(struct rtc_time *tm) { unsigned long time; int ret; @@ -90,10 +90,10 @@ static inline int rtc_set_time(struct rt static struct rtc_ops rtc_ops = { .owner = THIS_MODULE, - .read_time = rtc_read_time, - .set_time = rtc_set_time, - .read_alarm = rtc_read_alarm, - .set_alarm = rtc_set_alarm, + .read_time = integrator_rtc_read_time, + .set_time = integrator_rtc_set_time, + .read_alarm = integrator_rtc_read_alarm, + .set_alarm = integrator_rtc_set_alarm, }; static irqreturn_t arm_rtc_interrupt(int irq, void *dev_id, --- linux-ixp4xx.orig/arch/mips/ddb5xxx/common/rtc_ds1386.c 2006-03-08 01:59:09.000000000 +0100 +++ linux-ixp4xx/arch/mips/ddb5xxx/common/rtc_ds1386.c 2006-03-08 01:59:26.000000000 +0100 @@ -165,6 +165,6 @@ rtc_ds1386_init(unsigned long base) WRITE_RTC(0xB, byte); /* set the function pointers */ - rtc_get_time = rtc_ds1386_get_time; - rtc_set_time = rtc_ds1386_set_time; + rtc_mips_get_time = rtc_ds1386_get_time; + rtc_mips_set_time = rtc_ds1386_set_time; } --- linux-ixp4xx.orig/arch/mips/dec/time.c 2006-03-08 01:59:09.000000000 +0100 +++ linux-ixp4xx/arch/mips/dec/time.c 2006-03-08 01:59:26.000000000 +0100 @@ -193,8 +193,8 @@ static void dec_ioasic_hpt_init(unsigned void __init dec_time_init(void) { - rtc_get_time = dec_rtc_get_time; - rtc_set_mmss = dec_rtc_set_mmss; + rtc_mips_get_time = dec_rtc_get_time; + rtc_mips_set_mmss = dec_rtc_set_mmss; mips_timer_state = dec_timer_state; mips_timer_ack = dec_timer_ack; --- linux-ixp4xx.orig/arch/mips/ite-boards/generic/time.c 2006-03-08 01:59:09.000000000 +0100 +++ linux-ixp4xx/arch/mips/ite-boards/generic/time.c 2006-03-08 01:59:26.000000000 +0100 @@ -227,8 +227,8 @@ void __init it8172_time_init(void) local_irq_restore(flags); - rtc_get_time = it8172_rtc_get_time; - rtc_set_time = it8172_rtc_set_time; + rtc_mips_get_time = it8172_rtc_get_time; + rtc_mips_set_time = it8172_rtc_set_time; } #define ALLINTS (IE_IRQ0 | IE_IRQ1 | IE_IRQ2 | IE_IRQ3 | IE_IRQ4 | IE_IRQ5) --- linux-ixp4xx.orig/arch/mips/jmr3927/common/rtc_ds1742.c 2006-03-08 01:59:09.000000000 +0100 +++ linux-ixp4xx/arch/mips/jmr3927/common/rtc_ds1742.c 2006-03-08 01:59:26.000000000 +0100 @@ -159,8 +159,8 @@ rtc_ds1742_init(unsigned long base) db_assert((rtc_base & 0xe0000000) == KSEG1); /* set the function pointers */ - rtc_get_time = rtc_ds1742_get_time; - rtc_set_time = rtc_ds1742_set_time; + rtc_mips_get_time = rtc_ds1742_get_time; + rtc_mips_set_time = rtc_ds1742_set_time; /* clear oscillator stop bit */ CMOS_WRITE(RTC_READ, RTC_CONTROL); --- linux-ixp4xx.orig/arch/mips/kernel/time.c 2006-03-08 01:59:09.000000000 +0100 +++ linux-ixp4xx/arch/mips/kernel/time.c 2006-03-08 01:59:26.000000000 +0100 @@ -65,9 +65,9 @@ static int null_rtc_set_time(unsigned lo return 0; } -unsigned long (*rtc_get_time)(void) = null_rtc_get_time; -int (*rtc_set_time)(unsigned long) = null_rtc_set_time; -int (*rtc_set_mmss)(unsigned long); +unsigned long (*rtc_mips_get_time)(void) = null_rtc_get_time; +int (*rtc_mips_set_time)(unsigned long) = null_rtc_set_time; +int (*rtc_mips_set_mmss)(unsigned long); /* usecs per counter cycle, shifted to left by 32 bits */ @@ -438,7 +438,7 @@ irqreturn_t timer_interrupt(int irq, voi /* * If we have an externally synchronized Linux clock, then update - * CMOS clock accordingly every ~11 minutes. rtc_set_time() has to be + * CMOS clock accordingly every ~11 minutes. rtc_mips_set_time() has to be * called as close as possible to 500 ms before the new second starts. */ write_seqlock(&xtime_lock); @@ -446,7 +446,7 @@ irqreturn_t timer_interrupt(int irq, voi xtime.tv_sec > last_rtc_update + 660 && (xtime.tv_nsec / 1000) >= 500000 - ((unsigned) TICK_SIZE) / 2 && (xtime.tv_nsec / 1000) <= 500000 + ((unsigned) TICK_SIZE) / 2) { - if (rtc_set_mmss(xtime.tv_sec) == 0) { + if (rtc_mips_set_mmss(xtime.tv_sec) == 0) { last_rtc_update = xtime.tv_sec; } else { /* do it again in 60 s */ @@ -563,7 +563,7 @@ asmlinkage void ll_local_timer_interrupt * b) (optional) calibrate and set the mips_hpt_frequency * (only needed if you intended to use fixed_rate_gettimeoffset * or use cpu counter as timer interrupt source) - * 2) setup xtime based on rtc_get_time(). + * 2) setup xtime based on rtc_mips_get_time(). * 3) choose a appropriate gettimeoffset routine. * 4) calculate a couple of cached variables for later usage * 5) board_timer_setup() - @@ -631,10 +631,10 @@ void __init time_init(void) if (board_time_init) board_time_init(); - if (!rtc_set_mmss) - rtc_set_mmss = rtc_set_time; + if (!rtc_mips_set_mmss) + rtc_mips_set_mmss = rtc_mips_set_time; - xtime.tv_sec = rtc_get_time(); + xtime.tv_sec = rtc_mips_get_time(); xtime.tv_nsec = 0; set_normalized_timespec(&wall_to_monotonic, @@ -770,8 +770,8 @@ void to_tm(unsigned long tim, struct rtc EXPORT_SYMBOL(rtc_lock); EXPORT_SYMBOL(to_tm); -EXPORT_SYMBOL(rtc_set_time); -EXPORT_SYMBOL(rtc_get_time); +EXPORT_SYMBOL(rtc_mips_set_time); +EXPORT_SYMBOL(rtc_mips_get_time); unsigned long long sched_clock(void) { --- linux-ixp4xx.orig/arch/mips/lasat/setup.c 2006-03-08 01:59:09.000000000 +0100 +++ linux-ixp4xx/arch/mips/lasat/setup.c 2006-03-08 01:59:26.000000000 +0100 @@ -174,8 +174,8 @@ void __init plat_setup(void) #ifdef CONFIG_DS1603 ds1603 = &ds_defs[mips_machtype]; - rtc_get_time = ds1603_read; - rtc_set_time = ds1603_set; + rtc_mips_get_time = ds1603_read; + rtc_mips_set_time = ds1603_set; #endif #ifdef DYNAMIC_SERIAL_INIT --- linux-ixp4xx.orig/arch/mips/mips-boards/atlas/atlas_setup.c 2006-03-08 01:59:09.000000000 +0100 +++ linux-ixp4xx/arch/mips/mips-boards/atlas/atlas_setup.c 2006-03-08 01:59:26.000000000 +0100 @@ -65,7 +65,7 @@ void __init plat_setup(void) board_time_init = mips_time_init; board_timer_setup = mips_timer_setup; - rtc_get_time = mips_rtc_get_time; + rtc_mips_get_time = mips_rtc_get_time; } static void __init serial_init(void) --- linux-ixp4xx.orig/arch/mips/mips-boards/malta/malta_setup.c 2006-03-08 01:59:09.000000000 +0100 +++ linux-ixp4xx/arch/mips/mips-boards/malta/malta_setup.c 2006-03-08 01:59:26.000000000 +0100 @@ -225,5 +225,5 @@ void __init plat_setup(void) board_time_init = mips_time_init; board_timer_setup = mips_timer_setup; - rtc_get_time = mips_rtc_get_time; + rtc_mips_get_time = mips_rtc_get_time; } --- linux-ixp4xx.orig/arch/mips/momentum/jaguar_atx/setup.c 2006-03-08 01:59:09.000000000 +0100 +++ linux-ixp4xx/arch/mips/momentum/jaguar_atx/setup.c 2006-03-08 01:59:26.000000000 +0100 @@ -228,8 +228,8 @@ void momenco_time_init(void) mips_hpt_frequency = cpu_clock / 2; board_timer_setup = momenco_timer_setup; - rtc_get_time = m48t37y_get_time; - rtc_set_time = m48t37y_set_time; + rtc_mips_get_time = m48t37y_get_time; + rtc_mips_set_time = m48t37y_set_time; } static struct resource mv_pci_io_mem0_resource = { --- linux-ixp4xx.orig/arch/mips/momentum/ocelot_3/setup.c 2006-03-08 01:59:09.000000000 +0100 +++ linux-ixp4xx/arch/mips/momentum/ocelot_3/setup.c 2006-03-08 01:59:26.000000000 +0100 @@ -215,8 +215,8 @@ void momenco_time_init(void) mips_hpt_frequency = cpu_clock / 2; board_timer_setup = momenco_timer_setup; - rtc_get_time = m48t37y_get_time; - rtc_set_time = m48t37y_set_time; + rtc_mips_get_time = m48t37y_get_time; + rtc_mips_set_time = m48t37y_set_time; } /* --- linux-ixp4xx.orig/arch/mips/momentum/ocelot_c/setup.c 2006-03-08 01:59:09.000000000 +0100 +++ linux-ixp4xx/arch/mips/momentum/ocelot_c/setup.c 2006-03-08 01:59:26.000000000 +0100 @@ -226,8 +226,8 @@ void momenco_time_init(void) printk("momenco_time_init cpu_clock=%d\n", cpu_clock); board_timer_setup = momenco_timer_setup; - rtc_get_time = m48t37y_get_time; - rtc_set_time = m48t37y_set_time; + rtc_mips_get_time = m48t37y_get_time; + rtc_mips_set_time = m48t37y_set_time; } void __init plat_setup(void) --- linux-ixp4xx.orig/arch/mips/pmc-sierra/yosemite/setup.c 2006-03-08 01:59:09.000000000 +0100 +++ linux-ixp4xx/arch/mips/pmc-sierra/yosemite/setup.c 2006-03-08 01:59:26.000000000 +0100 @@ -198,8 +198,8 @@ static void __init py_rtc_setup(void) if (!m48t37_base) printk(KERN_ERR "Mapping the RTC failed\n"); - rtc_get_time = m48t37y_get_time; - rtc_set_time = m48t37y_set_time; + rtc_mips_get_time = m48t37y_get_time; + rtc_mips_set_time = m48t37y_set_time; write_seqlock(&xtime_lock); xtime.tv_sec = m48t37y_get_time(); --- linux-ixp4xx.orig/arch/mips/sgi-ip22/ip22-time.c 2006-03-08 01:59:09.000000000 +0100 +++ linux-ixp4xx/arch/mips/sgi-ip22/ip22-time.c 2006-03-08 01:59:26.000000000 +0100 @@ -212,8 +212,8 @@ static void indy_timer_setup(struct irqa void __init ip22_time_init(void) { /* setup hookup functions */ - rtc_get_time = indy_rtc_get_time; - rtc_set_time = indy_rtc_set_time; + rtc_mips_get_time = indy_rtc_get_time; + rtc_mips_set_time = indy_rtc_set_time; board_time_init = indy_time_init; board_timer_setup = indy_timer_setup; --- linux-ixp4xx.orig/arch/mips/sgi-ip32/ip32-setup.c 2006-03-08 01:59:09.000000000 +0100 +++ linux-ixp4xx/arch/mips/sgi-ip32/ip32-setup.c 2006-03-08 01:59:26.000000000 +0100 @@ -91,8 +91,8 @@ void __init plat_setup(void) { board_be_init = ip32_be_init; - rtc_get_time = mc146818_get_cmos_time; - rtc_set_mmss = mc146818_set_rtc_mmss; + rtc_mips_get_time = mc146818_get_cmos_time; + rtc_mips_set_mmss = mc146818_set_rtc_mmss; board_time_init = ip32_time_init; board_timer_setup = ip32_timer_setup; --- linux-ixp4xx.orig/arch/mips/sibyte/swarm/setup.c 2006-03-08 01:59:09.000000000 +0100 +++ linux-ixp4xx/arch/mips/sibyte/swarm/setup.c 2006-03-08 01:59:26.000000000 +0100 @@ -114,14 +114,14 @@ void __init plat_setup(void) if (xicor_probe()) { printk("swarm setup: Xicor 1241 RTC detected.\n"); - rtc_get_time = xicor_get_time; - rtc_set_time = xicor_set_time; + rtc_mips_get_time = xicor_get_time; + rtc_mips_set_time = xicor_set_time; } if (m41t81_probe()) { printk("swarm setup: M41T81 RTC detected.\n"); - rtc_get_time = m41t81_get_time; - rtc_set_time = m41t81_set_time; + rtc_mips_get_time = m41t81_get_time; + rtc_mips_set_time = m41t81_set_time; } printk("This kernel optimized for " --- linux-ixp4xx.orig/arch/mips/sni/setup.c 2006-03-08 01:59:09.000000000 +0100 +++ linux-ixp4xx/arch/mips/sni/setup.c 2006-03-08 01:59:26.000000000 +0100 @@ -164,8 +164,8 @@ static struct pci_controller sni_control static inline void sni_pcimt_time_init(void) { - rtc_get_time = mc146818_get_cmos_time; - rtc_set_time = mc146818_set_rtc_mmss; + rtc_mips_get_time = mc146818_get_cmos_time; + rtc_mips_set_time = mc146818_set_rtc_mmss; } void __init plat_setup(void) --- linux-ixp4xx.orig/arch/mips/tx4927/toshiba_rbtx4927/toshiba_rbtx4927_setup.c 2006-03-08 01:59:09.000000000 +0100 +++ linux-ixp4xx/arch/mips/tx4927/toshiba_rbtx4927/toshiba_rbtx4927_setup.c 2006-03-08 01:59:26.000000000 +0100 @@ -1036,8 +1036,8 @@ toshiba_rbtx4927_time_init(void) #ifdef CONFIG_RTC_DS1742 - rtc_get_time = rtc_ds1742_get_time; - rtc_set_time = rtc_ds1742_set_time; + rtc_mips_get_time = rtc_ds1742_get_time; + rtc_mips_set_time = rtc_ds1742_set_time; TOSHIBA_RBTX4927_SETUP_DPRINTK(TOSHIBA_RBTX4927_SETUP_TIME_INIT, ":rtc_ds1742_init()-\n"); --- linux-ixp4xx.orig/arch/mips/tx4938/common/rtc_rx5c348.c 2006-03-08 01:59:09.000000000 +0100 +++ linux-ixp4xx/arch/mips/tx4938/common/rtc_rx5c348.c 2006-03-08 01:59:26.000000000 +0100 @@ -197,6 +197,6 @@ rtc_rx5c348_init(int chipid) srtc_24h = 1; /* set the function pointers */ - rtc_get_time = rtc_rx5c348_get_time; - rtc_set_time = rtc_rx5c348_set_time; + rtc_mips_get_time = rtc_rx5c348_get_time; + rtc_mips_set_time = rtc_rx5c348_set_time; } --- linux-ixp4xx.orig/include/asm-mips/time.h 2006-03-08 01:59:09.000000000 +0100 +++ linux-ixp4xx/include/asm-mips/time.h 2006-03-08 01:59:26.000000000 +0100 @@ -26,14 +26,14 @@ extern spinlock_t rtc_lock; /* * RTC ops. By default, they point to no-RTC functions. - * rtc_get_time - mktime(year, mon, day, hour, min, sec) in seconds. - * rtc_set_time - reverse the above translation and set time to RTC. - * rtc_set_mmss - similar to rtc_set_time, but only min and sec need + * rtc_mips_get_time - mktime(year, mon, day, hour, min, sec) in seconds. + * rtc_mips_set_time - reverse the above translation and set time to RTC. + * rtc_mips_set_mmss - similar to rtc_set_time, but only min and sec need * to be set. Used by RTC sync-up. */ -extern unsigned long (*rtc_get_time)(void); -extern int (*rtc_set_time)(unsigned long); -extern int (*rtc_set_mmss)(unsigned long); +extern unsigned long (*rtc_mips_get_time)(void); +extern int (*rtc_mips_set_time)(unsigned long); +extern int (*rtc_mips_set_mmss)(unsigned long); /* * Timer interrupt functions. --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ linux-ixp4xx/drivers/rtc/class.c 2006-03-08 01:59:26.000000000 +0100 @@ -0,0 +1,145 @@ +/* + * RTC subsystem, base class + * + * Copyright (C) 2005 Tower Technologies + * Author: Alessandro Zummo + * + * class skeleton from drivers/hwmon/hwmon.c + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. +*/ + +#include +#include +#include +#include + +static DEFINE_IDR(rtc_idr); +static DEFINE_MUTEX(idr_lock); +struct class *rtc_class; + +static void rtc_device_release(struct class_device *class_dev) +{ + struct rtc_device *rtc = to_rtc_device(class_dev); + mutex_lock(&idr_lock); + idr_remove(&rtc_idr, rtc->id); + mutex_unlock(&idr_lock); + kfree(rtc); +} + +/** + * rtc_device_register - register w/ RTC class + * @dev: the device to register + * + * rtc_device_unregister() must be called when the class device is no + * longer needed. + * + * Returns the pointer to the new struct class device. + */ +struct rtc_device *rtc_device_register(const char *name, struct device *dev, + struct rtc_class_ops *ops, + struct module *owner) +{ + struct rtc_device *rtc; + int id, err; + + if (idr_pre_get(&rtc_idr, GFP_KERNEL) == 0) { + err = -ENOMEM; + goto exit; + } + + + mutex_lock(&idr_lock); + err = idr_get_new(&rtc_idr, NULL, &id); + mutex_unlock(&idr_lock); + + if (err < 0) + goto exit; + + id = id & MAX_ID_MASK; + + rtc = kzalloc(sizeof(struct rtc_device), GFP_KERNEL); + if (rtc == NULL) { + err = -ENOMEM; + goto exit_idr; + } + + rtc->id = id; + rtc->ops = ops; + rtc->owner = owner; + rtc->class_dev.dev = dev; + rtc->class_dev.class = rtc_class; + rtc->class_dev.release = rtc_device_release; + + mutex_init(&rtc->ops_lock); + spin_lock_init(&rtc->irq_lock); + spin_lock_init(&rtc->irq_task_lock); + + strlcpy(rtc->name, name, RTC_DEVICE_NAME_SIZE); + snprintf(rtc->class_dev.class_id, BUS_ID_SIZE, "rtc%d", id); + + err = class_device_register(&rtc->class_dev); + if (err) + goto exit_kfree; + + dev_info(dev, "rtc core: registered %s as %s\n", + rtc->name, rtc->class_dev.class_id); + + return rtc; + +exit_kfree: + kfree(rtc); + +exit_idr: + idr_remove(&rtc_idr, id); + +exit: + return ERR_PTR(err); +} +EXPORT_SYMBOL_GPL(rtc_device_register); + + +/** + * rtc_device_unregister - removes the previously registered RTC class device + * + * @rtc: the RTC class device to destroy + */ +void rtc_device_unregister(struct rtc_device *rtc) +{ + mutex_lock(&rtc->ops_lock); + rtc->ops = NULL; + mutex_unlock(&rtc->ops_lock); + class_device_unregister(&rtc->class_dev); +} +EXPORT_SYMBOL_GPL(rtc_device_unregister); + +int rtc_interface_register(struct class_interface *intf) +{ + intf->class = rtc_class; + return class_interface_register(intf); +} +EXPORT_SYMBOL_GPL(rtc_interface_register); + +static int __init rtc_init(void) +{ + rtc_class = class_create(THIS_MODULE, "rtc"); + if (IS_ERR(rtc_class)) { + printk(KERN_ERR "%s: couldn't create class\n", __FILE__); + return PTR_ERR(rtc_class); + } + return 0; +} + +static void __exit rtc_exit(void) +{ + class_destroy(rtc_class); +} + +module_init(rtc_init); +module_exit(rtc_exit); + +MODULE_AUTHOR("Alessandro Zummo "); +MODULE_DESCRIPTION("RTC class support"); +MODULE_LICENSE("GPL"); --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ linux-ixp4xx/drivers/rtc/interface.c 2006-03-08 01:59:26.000000000 +0100 @@ -0,0 +1,277 @@ +/* + * RTC subsystem, interface functions + * + * Copyright (C) 2005 Tower Technologies + * Author: Alessandro Zummo + * + * based on arch/arm/common/rtctime.c + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. +*/ + +#include + +int rtc_read_time(struct class_device *class_dev, struct rtc_time *tm) +{ + int err; + struct rtc_device *rtc = to_rtc_device(class_dev); + + err = mutex_lock_interruptible(&rtc->ops_lock); + if (err) + return -EBUSY; + + if (!rtc->ops) + err = -ENODEV; + else if (!rtc->ops->read_time) + err = -EINVAL; + else { + memset(tm, 0, sizeof(struct rtc_time)); + err = rtc->ops->read_time(class_dev->dev, tm); + } + + mutex_unlock(&rtc->ops_lock); + return err; +} +EXPORT_SYMBOL_GPL(rtc_read_time); + +int rtc_set_time(struct class_device *class_dev, struct rtc_time *tm) +{ + int err; + struct rtc_device *rtc = to_rtc_device(class_dev); + + err = rtc_valid_tm(tm); + if (err != 0) + return err; + + err = mutex_lock_interruptible(&rtc->ops_lock); + if (err) + return -EBUSY; + + if (!rtc->ops) + err = -ENODEV; + else if (!rtc->ops->set_time) + err = -EINVAL; + else + err = rtc->ops->set_time(class_dev->dev, tm); + + mutex_unlock(&rtc->ops_lock); + return err; +} +EXPORT_SYMBOL_GPL(rtc_set_time); + +int rtc_set_mmss(struct class_device *class_dev, unsigned long secs) +{ + int err; + struct rtc_device *rtc = to_rtc_device(class_dev); + + err = mutex_lock_interruptible(&rtc->ops_lock); + if (err) + return -EBUSY; + + if (!rtc->ops) + err = -ENODEV; + else if (rtc->ops->set_mmss) + err = rtc->ops->set_mmss(class_dev->dev, secs); + else if (rtc->ops->read_time && rtc->ops->set_time) { + struct rtc_time new, old; + + err = rtc->ops->read_time(class_dev->dev, &old); + if (err == 0) { + rtc_time_to_tm(secs, &new); + + /* + * avoid writing when we're going to change the day of + * the month. We will retry in the next minute. This + * basically means that if the RTC must not drift + * by more than 1 minute in 11 minutes. + */ + if (!((old.tm_hour == 23 && old.tm_min == 59) || + (new.tm_hour == 23 && new.tm_min == 59))) + err = rtc->ops->set_time(class_dev->dev, &new); + } + } + else + err = -EINVAL; + + mutex_unlock(&rtc->ops_lock); + + return err; +} +EXPORT_SYMBOL_GPL(rtc_set_mmss); + +int rtc_read_alarm(struct class_device *class_dev, struct rtc_wkalrm *alarm) +{ + int err; + struct rtc_device *rtc = to_rtc_device(class_dev); + + err = mutex_lock_interruptible(&rtc->ops_lock); + if (err) + return -EBUSY; + + if (rtc->ops == NULL) + err = -ENODEV; + else if (!rtc->ops->read_alarm) + err = -EINVAL; + else { + memset(alarm, 0, sizeof(struct rtc_wkalrm)); + err = rtc->ops->read_alarm(class_dev->dev, alarm); + } + + mutex_unlock(&rtc->ops_lock); + return err; +} +EXPORT_SYMBOL_GPL(rtc_read_alarm); + +int rtc_set_alarm(struct class_device *class_dev, struct rtc_wkalrm *alarm) +{ + int err; + struct rtc_device *rtc = to_rtc_device(class_dev); + + err = mutex_lock_interruptible(&rtc->ops_lock); + if (err) + return -EBUSY; + + if (!rtc->ops) + err = -ENODEV; + else if (!rtc->ops->set_alarm) + err = -EINVAL; + else + err = rtc->ops->set_alarm(class_dev->dev, alarm); + + mutex_unlock(&rtc->ops_lock); + return err; +} +EXPORT_SYMBOL_GPL(rtc_set_alarm); + +void rtc_update_irq(struct class_device *class_dev, + unsigned long num, unsigned long events) +{ + struct rtc_device *rtc = to_rtc_device(class_dev); + + spin_lock(&rtc->irq_lock); + rtc->irq_data = (rtc->irq_data + (num << 8)) | events; + spin_unlock(&rtc->irq_lock); + + spin_lock(&rtc->irq_task_lock); + if (rtc->irq_task) + rtc->irq_task->func(rtc->irq_task->private_data); + spin_unlock(&rtc->irq_task_lock); + + wake_up_interruptible(&rtc->irq_queue); + kill_fasync(&rtc->async_queue, SIGIO, POLL_IN); +} +EXPORT_SYMBOL_GPL(rtc_update_irq); + +struct class_device *rtc_class_open(char *name) +{ + struct class_device *class_dev = NULL, + *class_dev_tmp; + + down(&rtc_class->sem); + list_for_each_entry(class_dev_tmp, &rtc_class->children, node) { + if (strncmp(class_dev_tmp->class_id, name, BUS_ID_SIZE) == 0) { + class_dev = class_dev_tmp; + break; + } + } + + if (class_dev) { + if (!try_module_get(to_rtc_device(class_dev)->owner)) + class_dev = NULL; + } + up(&rtc_class->sem); + + return class_dev; +} +EXPORT_SYMBOL_GPL(rtc_class_open); + +void rtc_class_close(struct class_device *class_dev) +{ + module_put(to_rtc_device(class_dev)->owner); +} +EXPORT_SYMBOL_GPL(rtc_class_close); + +int rtc_irq_register(struct class_device *class_dev, struct rtc_task *task) +{ + int retval = -EBUSY; + struct rtc_device *rtc = to_rtc_device(class_dev); + + if (task == NULL || task->func == NULL) + return -EINVAL; + + spin_lock(&rtc->irq_task_lock); + if (rtc->irq_task == NULL) { + rtc->irq_task = task; + retval = 0; + } + spin_unlock(&rtc->irq_task_lock); + + return retval; +} +EXPORT_SYMBOL_GPL(rtc_irq_register); + +void rtc_irq_unregister(struct class_device *class_dev, struct rtc_task *task) +{ + struct rtc_device *rtc = to_rtc_device(class_dev); + + spin_lock(&rtc->irq_task_lock); + if (rtc->irq_task == task) + rtc->irq_task = NULL; + spin_unlock(&rtc->irq_task_lock); +} +EXPORT_SYMBOL_GPL(rtc_irq_unregister); + +int rtc_irq_set_state(struct class_device *class_dev, struct rtc_task *task, int enabled) +{ + int err = 0; + unsigned long flags; + struct rtc_device *rtc = to_rtc_device(class_dev); + + spin_lock_irqsave(&rtc->irq_task_lock, flags); + if (rtc->irq_task != task) + err = -ENXIO; + spin_unlock_irqrestore(&rtc->irq_task_lock, flags); + + if (err == 0) + err = rtc->ops->irq_set_state(class_dev->dev, enabled); + + return err; +} +EXPORT_SYMBOL_GPL(rtc_irq_set_state); + +int rtc_irq_set_freq(struct class_device *class_dev, struct rtc_task *task, int freq) +{ + int err = 0, tmp = 0; + unsigned long flags; + struct rtc_device *rtc = to_rtc_device(class_dev); + + /* allowed range is 2-8192 */ + if (freq < 2 || freq > 8192) + return -EINVAL; +/* + FIXME: this does not belong here, will move where appropriate + at a later stage. It cannot hurt right now, trust me :) + if ((freq > rtc_max_user_freq) && (!capable(CAP_SYS_RESOURCE))) + return -EACCES; +*/ + /* check if freq is a power of 2 */ + while (freq > (1 << tmp)) + tmp++; + + if (freq != (1 << tmp)) + return -EINVAL; + + spin_lock_irqsave(&rtc->irq_task_lock, flags); + if (rtc->irq_task != task) + err = -ENXIO; + spin_unlock_irqrestore(&rtc->irq_task_lock, flags); + + if (err == 0) { + err = rtc->ops->irq_set_freq(class_dev->dev, freq); + if (err == 0) + rtc->irq_freq = freq; + } + return err; +} --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ linux-ixp4xx/drivers/rtc/hctosys.c 2006-03-08 01:59:26.000000000 +0100 @@ -0,0 +1,69 @@ +/* + * RTC subsystem, initialize system time on startup + * + * Copyright (C) 2005 Tower Technologies + * Author: Alessandro Zummo + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. +*/ + +#include + +/* IMPORTANT: the RTC only stores whole seconds. It is arbitrary + * whether it stores the most close value or the value with partial + * seconds truncated. However, it is important that we use it to store + * the truncated value. This is because otherwise it is necessary, + * in an rtc sync function, to read both xtime.tv_sec and + * xtime.tv_nsec. On some processors (i.e. ARM), an atomic read + * of >32bits is not possible. So storing the most close value would + * slow down the sync API. So here we have the truncated value and + * the best guess is to add 0.5s. + */ + +static int __init rtc_hctosys(void) +{ + int err; + struct rtc_time tm; + struct class_device *class_dev = rtc_class_open(CONFIG_RTC_HCTOSYS_DEVICE); + + if (class_dev == NULL) { + printk("%s: unable to open rtc device (%s)\n", + __FILE__, CONFIG_RTC_HCTOSYS_DEVICE); + return -ENODEV; + } + + err = rtc_read_time(class_dev, &tm); + if (err == 0) { + err = rtc_valid_tm(&tm); + if (err == 0) { + struct timespec tv; + + tv.tv_nsec = NSEC_PER_SEC >> 1; + + rtc_tm_to_time(&tm, &tv.tv_sec); + + do_settimeofday(&tv); + + dev_info(class_dev->dev, + "setting the system clock to " + "%d-%02d-%02d %02d:%02d:%02d (%u)\n", + tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday, + tm.tm_hour, tm.tm_min, tm.tm_sec, + (unsigned int) tv.tv_sec); + } + else + dev_err(class_dev->dev, + "hctosys: invalid date/time\n"); + } + else + dev_err(class_dev->dev, + "hctosys: unable to read the hardware clock\n"); + + rtc_class_close(class_dev); + + return 0; +} + +late_initcall(rtc_hctosys); --- linux-ixp4xx.orig/CREDITS 2006-03-08 01:59:09.000000000 +0100 +++ linux-ixp4xx/CREDITS 2006-03-08 01:59:26.000000000 +0100 @@ -3741,10 +3741,11 @@ D: Mylex DAC960 PCI RAID driver D: Miscellaneous kernel fixes N: Alessandro Zummo -E: azummo@ita.flashnet.it -W: http://freepage.logicom.it/azummo/ +E: a.zummo@towertech.it D: CMI8330 support is sb_card.c D: ISAPnP fixes in sb_card.c +D: ZyXEL omni.net lcd plus driver +D: RTC subsystem S: Italy N: Marc Zyngier --- linux-ixp4xx.orig/MAINTAINERS 2006-03-08 01:59:09.000000000 +0100 +++ linux-ixp4xx/MAINTAINERS 2006-03-08 01:59:26.000000000 +0100 @@ -2193,6 +2193,12 @@ M: p_gortmaker@yahoo.com L: linux-kernel@vger.kernel.org S: Maintained +REAL TIME CLOCK (RTC) SUBSYSTEM +P: Alessandro Zummo +M: a.zummo@towertech.it +L: linux-kernel@vger.kernel.org +S: Maintained + REISERFS FILE SYSTEM P: Hans Reiser M: reiserfs-dev@namesys.com --- linux-ixp4xx.orig/drivers/i2c/chips/x1205.c 2006-03-08 01:59:09.000000000 +0100 +++ /dev/null 1970-01-01 00:00:00.000000000 +0000 @@ -1,698 +0,0 @@ -/* - * x1205.c - An i2c driver for the Xicor X1205 RTC - * Copyright 2004 Karen Spearel - * Copyright 2005 Alessandro Zummo - * - * please send all reports to: - * kas11 at tampabay dot rr dot com - * a dot zummo at towertech dot it - * - * based on the other drivers in this same directory. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - */ - -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -#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