diff options
Diffstat (limited to 'packages/linux')
18 files changed, 23258 insertions, 780 deletions
diff --git a/packages/linux/ixp4xx-kernel/2.6.16/06-remove-extraversion.patch b/packages/linux/ixp4xx-kernel/2.6.16/06-remove-extraversion.patch index 65aba13703..8f2ce831b2 100644 --- a/packages/linux/ixp4xx-kernel/2.6.16/06-remove-extraversion.patch +++ b/packages/linux/ixp4xx-kernel/2.6.16/06-remove-extraversion.patch @@ -4,7 +4,7 @@ VERSION = 2 PATCHLEVEL = 6 SUBLEVEL = 16 --EXTRAVERSION =-rc2 +-EXTRAVERSION =-rc4 +EXTRAVERSION = NAME=Sliding Snow Leopard 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 }, |
