nas100d-kernel: Corrected the location of the mac address in the RedBoot config parti...
authorRod Whitby <rod@whitby.id.au>
Wed, 4 Jan 2006 11:53:06 +0000 (11:53 +0000)
committerOpenEmbedded Project <openembedded-devel@lists.openembedded.org>
Wed, 4 Jan 2006 11:53:06 +0000 (11:53 +0000)
15 files changed:
packages/linux/nas100d-kernel/2.6.15/00-memory-h-page-shift.patch
packages/linux/nas100d-kernel/2.6.15/01-i2c-ixp4xx.patch [deleted file]
packages/linux/nas100d-kernel/2.6.15/40-rtc-class.patch [new file with mode: 0644]
packages/linux/nas100d-kernel/2.6.15/50-nas100d-arch.patch
packages/linux/nas100d-kernel/2.6.15/55-nas100d-arch.patch [deleted file]
packages/linux/nas100d-kernel/2.6.15/85-timer.patch [new file with mode: 0644]
packages/linux/nas100d-kernel/2.6.15/90-ixp4xx-nslu2.patch [deleted file]
packages/linux/nas100d-kernel/2.6.15/91-maclist.patch [new file with mode: 0644]
packages/linux/nas100d-kernel/2.6.15/92-nas100d-maclist.patch [new file with mode: 0644]
packages/linux/nas100d-kernel/2.6.15/anonymiser.patch [new file with mode: 0644]
packages/linux/nas100d-kernel/2.6.15/nas100d-pci.c [deleted file]
packages/linux/nas100d-kernel/2.6.15/nas100d-power.c [deleted file]
packages/linux/nas100d-kernel/2.6.15/nas100d-setup.c [deleted file]
packages/linux/nas100d-kernel/2.6.15/nas100d.h [deleted file]
packages/linux/nas100d-kernel_2.6.15.bb [new file with mode: 0644]

index 29b048e..4ec8f04 100644 (file)
@@ -1,10 +1,68 @@
---- linux-2.6.15/include/asm-arm/arch-ixp4xx/memory.h  1970-01-01 00:00:00.000000000 +0000
-+++ linux-2.6.15/include/asm-arm/arch-ixp4xx/memory.h  1970-01-01 00:00:00.000000000 +0000
-@@ -8,6 +8,7 @@
- #define __ASM_ARCH_MEMORY_H
+--- linux-2.6.15-rc7/include/asm-arm/arch-ixp4xx/memory.h~     2005-12-30 05:18:27.000000000 +1030
++++ linux-2.6.15-rc7/include/asm-arm/arch-ixp4xx/memory.h      2005-12-30 05:36:04.000000000 +1030
+@@ -16,31 +16,10 @@
  
- #include <asm/sizes.h>
-+#include <asm/page.h>
+ #ifndef __ASSEMBLY__
  
- /*
-  * Physical DRAM offset.
+-/*
+- * Only first 64MB of memory can be accessed via PCI.
+- * We use GFP_DMA to allocate safe buffers to do map/unmap.
+- * This is really ugly and we need a better way of specifying
+- * DMA-capable regions of memory.
+- */
+-static inline void __arch_adjust_zones(int node, unsigned long *zone_size, 
+-      unsigned long *zhole_size) 
+-{
+-      unsigned int sz = SZ_64M >> PAGE_SHIFT;
+-
+-      /*
+-       * Only adjust if > 64M on current system
+-       */
+-      if (node || (zone_size[0] <= sz))
+-              return;
+-
+-      zone_size[1] = zone_size[0] - sz;
+-      zone_size[0] = sz;
+-      zhole_size[1] = zhole_size[0];
+-      zhole_size[0] = 0;
+-}
++void ixp4xx_adjust_zones(int node, unsigned long *size, unsigned long *holes);
+ #define arch_adjust_zones(node, size, holes) \
+-      __arch_adjust_zones(node, size, holes)
++      ixp4xx_adjust_zones(node, size, holes)
+ #define ISA_DMA_THRESHOLD (SZ_64M - 1)
+--- linux-2.6.15-rc7/arch/arm/mach-ixp4xx/common-pci.c~        2005-12-30 05:16:03.000000000 +1030
++++ linux-2.6.15-rc7/arch/arm/mach-ixp4xx/common-pci.c 2005-12-30 05:43:55.000000000 +1030
+@@ -341,6 +341,29 @@ int dma_needs_bounce(struct device *dev,
+       return (dev->bus == &pci_bus_type ) && ((dma_addr + size) >= SZ_64M);
+ }
++/*
++ * Only first 64MB of memory can be accessed via PCI.
++ * We use GFP_DMA to allocate safe buffers to do map/unmap.
++ * This is really ugly and we need a better way of specifying
++ * DMA-capable regions of memory.
++ */
++void __init ixp4xx_adjust_zones(int node, unsigned long *zone_size, 
++      unsigned long *zhole_size) 
++{
++      unsigned int sz = SZ_64M >> PAGE_SHIFT;
++
++      /*
++       * Only adjust if > 64M on current system
++       */
++      if (node || (zone_size[0] <= sz))
++              return;
++
++      zone_size[1] = zone_size[0] - sz;
++      zone_size[0] = sz;
++      zhole_size[1] = zhole_size[0];
++      zhole_size[0] = 0;
++}
++
+ void __init ixp4xx_pci_preinit(void)
+ {  
+       unsigned long processor_id;
diff --git a/packages/linux/nas100d-kernel/2.6.15/01-i2c-ixp4xx.patch b/packages/linux/nas100d-kernel/2.6.15/01-i2c-ixp4xx.patch
deleted file mode 100644 (file)
index 16426bd..0000000
+++ /dev/null
@@ -1,29 +0,0 @@
---- linux-2.6.15/drivers/i2c/busses/i2c-ixp4xx.c       1970-01-01 00:00:00.000000000 +0000
-+++ linux-2.6.15/drivers/i2c/busses/i2c-ixp4xx.c       1970-01-01 00:00:00.000000000 +0000
-@@ -35,7 +35,7 @@
- #include <asm/hardware.h>     /* Pick up IXP4xx-specific bits */
--static struct device_driver ixp4xx_i2c_driver;
-+static struct platform_driver ixp4xx_i2c_driver;
- static inline int ixp4xx_scl_pin(void *data)
- {
-@@ -128,7 +128,7 @@ static int ixp4xx_i2c_probe(struct platf
-       drv_data->algo_data.timeout = 100;
-       drv_data->adapter.id = I2C_HW_B_IXP4XX;
--      strlcpy(drv_data->adapter.name, ixp4xx_i2c_driver.name,
-+      strlcpy(drv_data->adapter.name, ixp4xx_i2c_driver.driver.name,
-               I2C_NAME_SIZE);
-       drv_data->adapter.algo_data = &drv_data->algo_data;
-@@ -140,7 +140,7 @@ static int ixp4xx_i2c_probe(struct platf
-       gpio_line_set(gpio->sda_pin, 0);
-       if ((err = i2c_bit_add_bus(&drv_data->adapter) != 0)) {
--              printk(KERN_ERR "ERROR: Could not install %s\n", dev->bus_id);
-+              printk(KERN_ERR "ERROR: Could not install %s\n", ixp4xx_i2c_driver.driver.name);
-               kfree(drv_data);
-               return err;
diff --git a/packages/linux/nas100d-kernel/2.6.15/40-rtc-class.patch b/packages/linux/nas100d-kernel/2.6.15/40-rtc-class.patch
new file mode 100644 (file)
index 0000000..feea3f2
--- /dev/null
@@ -0,0 +1,2719 @@
+--- linux-nslu2.orig/include/linux/rtc.h       2006-01-03 15:31:18.000000000 +0100
++++ linux-nslu2/include/linux/rtc.h    2006-01-03 15:34:24.000000000 +0100
+@@ -91,8 +91,81 @@ 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__
++#include <linux/device.h>
++#include <linux/seq_file.h>
++#include <linux/cdev.h>
++#include <linux/poll.h>
++
++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);
++};
++
++#define RTC_DEVICE_NAME_SIZE 20
++struct rtc_task;
++
++struct rtc_device
++{
++      int id;
++      struct module *owner;
++      struct rw_semaphore lock;
++      struct class_device class_dev;
++      struct rtc_class_ops *ops;
++      char name[RTC_DEVICE_NAME_SIZE];
++
++      struct cdev char_dev;
++      struct semaphore char_sem;
++
++      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;
++      int irq_freq;
++};
++#define to_rtc_device(d) container_of(d, struct rtc_device, class_dev)
++
++extern struct rtc_device *rtc_device_register(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_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);
++
++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_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);
++
+ typedef struct rtc_task {
+       void (*func)(void *private_data);
+       void *private_data;
+--- linux-nslu2.orig/drivers/Kconfig   2006-01-03 15:31:19.000000000 +0100
++++ linux-nslu2/drivers/Kconfig        2006-01-04 01:27:31.000000000 +0100
+@@ -66,4 +66,6 @@ source "drivers/infiniband/Kconfig"
+ source "drivers/sn/Kconfig"
++source "drivers/rtc/Kconfig"
++
+ endmenu
+--- linux-nslu2.orig/drivers/Makefile  2006-01-03 15:33:32.000000000 +0100
++++ linux-nslu2/drivers/Makefile       2006-01-04 01:27:31.000000000 +0100
+@@ -54,6 +54,7 @@ obj-$(CONFIG_USB_GADGET)     += usb/gadget/
+ obj-$(CONFIG_GAMEPORT)                += input/gameport/
+ obj-$(CONFIG_INPUT)           += input/
+ obj-$(CONFIG_I2O)             += message/
++obj-y                         += rtc/
+ obj-$(CONFIG_I2C)             += i2c/
+ 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-01-03 15:45:19.000000000 +0100
+@@ -0,0 +1,141 @@
++/*
++ * RTC subsystem, base class
++ *
++ * Copyright (C) 2005 Tower Technologies
++ * Author: Alessandro Zummo <a.zummo@towertech.it>
++ *
++ * class skeleton from drivers/hwmon/hwmon.c
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; version 2 of the License.
++*/
++
++#include <linux/module.h>
++#include <linux/rtc.h>
++#include <linux/kdev_t.h>
++#include <linux/idr.h>
++
++static DEFINE_IDR(rtc_idr);
++static DECLARE_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);
++      idr_remove(&rtc_idr, rtc->id);
++      up(&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(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;
++      }
++
++
++      down(&idr_lock);
++      err = idr_get_new(&rtc_idr, NULL, &id);
++      up(&idr_lock);
++
++      if (err < 0)
++              goto exit;
++
++      id = id & MAX_ID_MASK;
++
++      if ((rtc = kzalloc(sizeof(struct rtc_device), GFP_KERNEL)) == 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;
++
++      init_rwsem(&rtc->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);
++
++      if ((err = class_device_register(&rtc->class_dev)))
++              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)
++{
++      down_write(&rtc->lock);
++      class_device_unregister(&rtc->class_dev);
++}
++EXPORT_SYMBOL_GPL(rtc_device_unregister);
++
++int rtc_interface_register(struct class_interface *intf)
++{
++      intf->class = rtc_class;
++      return class_interface_register(intf);
++}
++EXPORT_SYMBOL_GPL(rtc_interface_register);
++
++static int __init rtc_init(void)
++{
++      rtc_class = class_create(THIS_MODULE, "rtc");
++      if (IS_ERR(rtc_class)) {
++              printk(KERN_ERR "%s: couldn't create class\n", __FILE__);
++              return PTR_ERR(rtc_class);
++      }
++      return 0;
++}
++
++static void __exit rtc_exit(void)
++{
++      class_destroy(rtc_class);
++}
++
++module_init(rtc_init);
++module_exit(rtc_exit);
++
++MODULE_AUTHOR("Alessandro Zummo <a.zummo@towerteh.it>");
++MODULE_DESCRIPTION("RTC class support");
++MODULE_LICENSE("GPL");
+--- /dev/null  1970-01-01 00:00:00.000000000 +0000
++++ linux-nslu2/drivers/rtc/Kconfig    2006-01-04 01:27:21.000000000 +0100
+@@ -0,0 +1,93 @@
++#
++# RTC class/drivers configuration
++#
++
++menu "Real Time Clock"
++
++config RTC_CLASS
++      tristate "RTC class"
++      depends on EXPERIMENTAL
++      default y
++      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.
++
++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_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
+--- /dev/null  1970-01-01 00:00:00.000000000 +0000
++++ linux-nslu2/drivers/rtc/Makefile   2006-01-04 01:27:21.000000000 +0100
+@@ -0,0 +1,15 @@
++#
++# Makefile for RTC class/drivers.
++#
++
++obj-y                         += utils.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
++
+--- /dev/null  1970-01-01 00:00:00.000000000 +0000
++++ linux-nslu2/drivers/rtc/interface.c        2006-01-03 15:34:24.000000000 +0100
+@@ -0,0 +1,189 @@
++/*
++ * RTC subsystem, interface functions
++ *
++ * Copyright (C) 2005 Tower Technologies
++ * Author: Alessandro Zummo <a.zummo@towertech.it>
++ *
++ * based on arch/arm/common/rtctime.c
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; version 2 of the License.
++*/
++
++#include <linux/rtc.h>
++
++extern struct class *rtc_class;
++
++int rtc_read_time(struct class_device *class_dev, struct rtc_time *tm)
++{
++      int err = -EINVAL;
++      struct rtc_class_ops *ops = to_rtc_device(class_dev)->ops;
++
++      if (ops->read_time) {
++              memset(tm, 0, sizeof(struct rtc_time));
++              err = ops->read_time(class_dev->dev, tm);
++      }
++      return err;
++}
++EXPORT_SYMBOL(rtc_read_time);
++
++int rtc_set_time(struct class_device *class_dev, struct rtc_time *tm)
++{
++      int err;
++      struct rtc_class_ops *ops = to_rtc_device(class_dev)->ops;
++
++      err = rtc_valid_tm(tm);
++      if (err == 0 && ops->set_time)
++              err = ops->set_time(class_dev->dev, tm);
++
++      return err;
++}
++EXPORT_SYMBOL(rtc_set_time);
++
++int rtc_read_alarm(struct class_device *class_dev, struct rtc_wkalrm *alarm)
++{
++      struct rtc_class_ops *ops = to_rtc_device(class_dev)->ops;
++      int err = -EINVAL;
++
++      if (ops->read_alarm) {
++              memset(alarm, 0, sizeof(struct rtc_wkalrm));
++              err = ops->read_alarm(class_dev->dev, alarm);
++      }
++      return err;
++}
++EXPORT_SYMBOL(rtc_read_alarm);
++
++int rtc_set_alarm(struct class_device *class_dev, struct rtc_wkalrm *alarm)
++{
++      int err = -EINVAL;
++      struct rtc_class_ops *ops = to_rtc_device(class_dev)->ops;
++
++      if (ops->set_alarm)
++              err = ops->set_alarm(class_dev->dev, alarm);
++      return err;
++}
++EXPORT_SYMBOL(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(rtc_update_irq);
++
++struct class_device *rtc_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;
++              }
++      }
++      up(&rtc_class->sem);
++
++      return class_dev;
++}
++EXPORT_SYMBOL(rtc_open);
++
++void rtc_close(struct class_device *class_dev)
++{
++}
++EXPORT_SYMBOL(rtc_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(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(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(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;
++
++/*    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) {
++              if ((err = rtc->ops->irq_set_freq(class_dev->dev, freq)) == 0)
++                      rtc->irq_freq = freq;
++      }
++      return err;
++
++}
+--- /dev/null  1970-01-01 00:00:00.000000000 +0000
++++ linux-nslu2/drivers/rtc/utils.c    2006-01-03 15:34:24.000000000 +0100
+@@ -0,0 +1,97 @@
++/*
++ * RTC subsystem, utility functions
++ *
++ * Copyright (C) 2005 Tower Technologies
++ * Author: Alessandro Zummo <a.zummo@towertech.it>
++ *
++ * based on arch/arm/common/rtctime.c
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; version 2 of the License.
++*/
++
++#include <linux/rtc.h>
++
++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)
++{
++      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 - 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);
+--- linux-nslu2.orig/arch/arm/Kconfig  2006-01-04 01:27:04.000000000 +0100
++++ linux-nslu2/arch/arm/Kconfig       2006-01-04 01:27:31.000000000 +0100
+@@ -750,6 +750,8 @@ source "drivers/usb/Kconfig"
+ source "drivers/mmc/Kconfig"
++source "drivers/rtc/Kconfig"
++
+ endmenu
+ source "fs/Kconfig"
+--- linux-nslu2.orig/arch/arm/common/rtctime.c 2006-01-04 01:27:04.000000000 +0100
++++ linux-nslu2/arch/arm/common/rtctime.c      2006-01-04 01:27:09.000000000 +0100
+@@ -40,89 +40,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.
+@@ -141,13 +58,13 @@ void rtc_next_alarm_time(struct rtc_time
+       next->tm_sec = alrm->tm_sec;
+ }
+-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;
+@@ -158,7 +75,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) {
+@@ -168,7 +85,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)
+@@ -256,7 +173,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));
+@@ -278,11 +195,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));
+@@ -300,7 +217,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:
+@@ -331,11 +248,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));
+@@ -425,7 +342,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"
+@@ -435,7 +352,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-nslu2.orig/include/asm-arm/rtc.h     2006-01-04 01:27:04.000000000 +0100
++++ linux-nslu2/include/asm-arm/rtc.h  2006-01-04 01:27:09.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 *);
+--- /dev/null  1970-01-01 00:00:00.000000000 +0000
++++ linux-nslu2/drivers/rtc/rtc-sysfs.c        2006-01-04 01:27:12.000000000 +0100
+@@ -0,0 +1,125 @@
++/*
++ * RTC subsystem, sysfs interface
++ *
++ * Copyright (C) 2005 Tower Technologies
++ * Author: Alessandro Zummo <a.zummo@towertech.it>
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; version 2 of the License.
++*/
++
++#include <linux/module.h>
++#include <linux/rtc.h>
++
++/* device attributes */
++
++static ssize_t rtc_sysfs_show_name(struct class_device *dev, char *buf)
++{
++      return sprintf(buf, "%s\n", to_rtc_device(dev)->name);
++}
++static CLASS_DEVICE_ATTR(name, S_IRUGO, rtc_sysfs_show_name, NULL);
++
++static ssize_t rtc_sysfs_show_date(struct class_device *dev, char *buf)
++{
++      ssize_t retval = 0;
++      struct rtc_device *rtc = to_rtc_device(dev);
++      struct rtc_time tm;
++
++      if (down_read_trylock(&rtc->lock) == 0)
++              return -ENODEV;
++
++      if (rtc_read_time(dev, &tm) == 0) {
++              retval = sprintf(buf, "%04d-%02d-%02d\n",
++                      tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday);
++      }
++
++      up_read(&rtc->lock);
++      return retval;
++}
++static CLASS_DEVICE_ATTR(date, S_IRUGO, rtc_sysfs_show_date, NULL);
++
++static ssize_t rtc_sysfs_show_time(struct class_device *dev, char *buf)
++{
++      ssize_t retval = 0;
++      struct rtc_device *rtc = to_rtc_device(dev);
++      struct rtc_time tm;
++
++      if (down_read_trylock(&rtc->lock) == 0)
++              return -ENODEV;
++
++      if (rtc_read_time(dev, &tm) == 0) {
++              retval = sprintf(buf, "%02d:%02d:%02d\n",
++                      tm.tm_hour, tm.tm_min, tm.tm_sec);
++      }
++
++      up_read(&rtc->lock);
++      return retval;
++}
++static CLASS_DEVICE_ATTR(time, S_IRUGO, rtc_sysfs_show_time, NULL);
++
++static ssize_t rtc_sysfs_show_since_epoch(struct class_device *dev, char *buf)
++{
++      ssize_t retval = 0;
++      struct rtc_device *rtc = to_rtc_device(dev);
++      struct rtc_time tm;
++
++      if (down_read_trylock(&rtc->lock) == 0)
++              return -ENODEV;
++
++      if (rtc_read_time(dev, &tm) == 0) {
++              unsigned long time;
++              rtc_tm_to_time(&tm, &time);
++              retval = sprintf(buf, "%lu\n", time);
++      }
++
++      up_read(&rtc->lock);
++      return retval;
++}
++static CLASS_DEVICE_ATTR(since_epoch, S_IRUGO, rtc_sysfs_show_since_epoch, NULL);
++
++/* insertion/removal hooks */
++
++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);
++      dev_info(class_dev->dev, "rtc intf: sysfs\n");
++      return 0;
++}
++
++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);
++}
++
++/* interface registration */
++
++struct class_interface rtc_sysfs_interface = {
++      .add = &rtc_sysfs_add_device,
++      .remove = &rtc_sysfs_remove_device,
++};
++
++static int __init rtc_sysfs_init(void)
++{
++      return rtc_interface_register(&rtc_sysfs_interface);
++}
++
++static void __exit rtc_sysfs_exit(void)
++{
++      class_interface_unregister(&rtc_sysfs_interface);
++}
++
++module_init(rtc_sysfs_init);
++module_exit(rtc_sysfs_exit);
++
++MODULE_AUTHOR("Alessandro Zummo <a.zummo@towertech.it>");
++MODULE_DESCRIPTION("RTC class sysfs interface");
++MODULE_LICENSE("GPL");
+--- /dev/null  1970-01-01 00:00:00.000000000 +0000
++++ linux-nslu2/drivers/rtc/rtc-proc.c 2006-01-04 01:27:14.000000000 +0100
+@@ -0,0 +1,158 @@
++/*
++ * RTC subsystem, proc interface
++ *
++ * Copyright (C) 2005 Tower Technologies
++ * Author: Alessandro Zummo <a.zummo@towertech.it>
++ *
++ * based on arch/arm/common/rtctime.c
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; version 2 of the License.
++*/
++
++#include <linux/module.h>
++#include <linux/rtc.h>
++#include <linux/proc_fs.h>
++#include <linux/seq_file.h>
++
++static struct class_device *rtc_dev = NULL;
++static DECLARE_MUTEX(rtc_sem);
++
++static int rtc_proc_show(struct seq_file *seq, void *offset)
++{
++      struct class_device *class_dev = seq->private;
++      struct rtc_class_ops *ops = to_rtc_device(class_dev)->ops;
++      struct rtc_wkalrm alrm;
++      struct rtc_time tm;
++
++      if (rtc_read_time(class_dev, &tm) == 0) {
++              seq_printf(seq,
++                      "rtc_time\t: %02d:%02d:%02d\n"
++                      "rtc_date\t: %04d-%02d-%02d\n",
++                      tm.tm_hour, tm.tm_min, tm.tm_sec,
++                      tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday);
++      }
++
++      if (rtc_read_alarm(class_dev, &alrm) == 0) {
++              seq_printf(seq, "alrm_time\t: ");
++              if ((unsigned int)alrm.time.tm_hour <= 24)
++                      seq_printf(seq, "%02d:", alrm.time.tm_hour);
++              else
++                      seq_printf(seq, "**:");
++              if ((unsigned int)alrm.time.tm_min <= 59)
++                      seq_printf(seq, "%02d:", alrm.time.tm_min);
++              else
++                      seq_printf(seq, "**:");
++              if ((unsigned int)alrm.time.tm_sec <= 59)
++                      seq_printf(seq, "%02d\n", alrm.time.tm_sec);
++              else
++                      seq_printf(seq, "**\n");
++
++              seq_printf(seq, "alrm_date\t: ");
++              if ((unsigned int)alrm.time.tm_year <= 200)
++                      seq_printf(seq, "%04d-", alrm.time.tm_year + 1900);
++              else
++                      seq_printf(seq, "****-");
++              if ((unsigned int)alrm.time.tm_mon <= 11)
++                      seq_printf(seq, "%02d-", alrm.time.tm_mon + 1);
++              else
++                      seq_printf(seq, "**-");
++              if ((unsigned int)alrm.time.tm_mday <= 31)
++                      seq_printf(seq, "%02d\n", alrm.time.tm_mday);
++              else
++                      seq_printf(seq, "**\n");
++              seq_printf(seq, "alrm_wakeup\t: %s\n",
++                           alrm.enabled ? "yes" : "no");
++              seq_printf(seq, "alrm_pending\t: %s\n",
++                           alrm.pending ? "yes" : "no");
++      }
++
++      if (ops->proc)
++              ops->proc(class_dev->dev, seq);
++
++      return 0;
++}
++
++static int rtc_proc_open(struct inode *inode, struct file *file)
++{
++      struct class_device *class_dev = PDE(inode)->data;
++
++      if (!try_module_get(THIS_MODULE))
++              return -ENODEV;
++
++      return single_open(file, rtc_proc_show, class_dev);
++}
++
++static int rtc_proc_release(struct inode *inode, struct file *file)
++{
++      int res = single_release(inode, file);
++      module_put(THIS_MODULE);
++      return res;
++}
++
++static struct file_operations rtc_proc_fops = {
++      .open           = rtc_proc_open,
++      .read           = seq_read,
++      .llseek         = seq_lseek,
++      .release        = rtc_proc_release,
++};
++
++static int rtc_proc_add_device(struct class_device *class_dev,
++                                         struct class_interface *class_intf)
++{
++      down(&rtc_sem);
++      if (rtc_dev == NULL) {
++              struct proc_dir_entry *ent;
++
++              rtc_dev = class_dev;
++
++              if ((ent = create_proc_entry("driver/rtc", 0, NULL))) {
++                      struct rtc_device *rtc = to_rtc_device(class_dev);
++
++                      ent->proc_fops = &rtc_proc_fops;
++                      ent->owner = rtc->owner;
++                      ent->data = class_dev;
++
++                      dev_info(class_dev->dev, "rtc intf: proc\n");
++              }
++              else
++                      rtc_dev = NULL;
++      }
++      up(&rtc_sem);
++
++      return 0;
++}
++
++static void rtc_proc_remove_device(struct class_device *class_dev,
++                                            struct class_interface *class_intf)
++{
++      down(&rtc_sem);
++      if (rtc_dev == class_dev) {
++              remove_proc_entry("driver/rtc", NULL);
++              rtc_dev = NULL;
++      }
++      up(&rtc_sem);
++}
++
++struct class_interface rtc_proc_interface = {
++      .add = &rtc_proc_add_device,
++      .remove = &rtc_proc_remove_device,
++};
++
++static int __init rtc_proc_init(void)
++{
++      return rtc_interface_register(&rtc_proc_interface);
++}
++
++static void __exit rtc_proc_exit(void)
++{
++      class_interface_unregister(&rtc_proc_interface);
++}
++
++module_init(rtc_proc_init);
++module_exit(rtc_proc_exit);
++
++MODULE_AUTHOR("Alessandro Zummo <a.zummo@towertech.it>");
++MODULE_DESCRIPTION("RTC class proc interface");
++MODULE_LICENSE("GPL");
+--- /dev/null  1970-01-01 00:00:00.000000000 +0000
++++ linux-nslu2/drivers/rtc/rtc-dev.c  2006-01-04 01:27:15.000000000 +0100
+@@ -0,0 +1,372 @@
++/*
++ * RTC subsystem, dev interface
++ *
++ * Copyright (C) 2005 Tower Technologies
++ * Author: Alessandro Zummo <a.zummo@towertech.it>
++ *
++ * based on arch/arm/common/rtctime.c
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; version 2 of the License.
++*/
++
++#include <linux/module.h>
++#include <linux/rtc.h>
++
++static dev_t rtc_devt;
++
++#define RTC_DEV_MAX 16 /* 16 RTCs should be enough for everyone... */
++
++static int rtc_dev_open(struct inode *inode, struct file *file)
++{
++      int err;
++      struct rtc_device *rtc = container_of(inode->i_cdev,
++                                      struct rtc_device, char_dev);
++      struct rtc_class_ops *ops = rtc->ops;
++
++      /* We keep the lock as long as the device is in use
++       * and return immediately if busy
++       */
++      if (down_trylock(&rtc->char_sem))
++              return -EBUSY;
++
++      file->private_data = &rtc->class_dev;
++
++      err = ops->open ? ops->open(rtc->class_dev.dev) : 0;
++      if (err == 0) {
++
++              spin_lock_irq(&rtc->irq_lock);
++              rtc->irq_data = 0;
++              spin_unlock_irq(&rtc->irq_lock);
++
++              return 0;
++      }
++
++      /* something has gone wrong, release the lock */
++      up(&rtc->char_sem);
++      return err;
++}
++
++
++static ssize_t
++rtc_dev_read(struct file *file, char __user *buf, size_t count, loff_t *ppos)
++{
++      struct rtc_device *rtc = to_rtc_device(file->private_data);
++
++      DECLARE_WAITQUEUE(wait, current);
++      unsigned long data;
++      ssize_t ret;
++
++      if (count < sizeof(unsigned long))
++              return -EINVAL;
++
++      add_wait_queue(&rtc->irq_queue, &wait);
++      do {
++              __set_current_state(TASK_INTERRUPTIBLE);
++
++              spin_lock_irq(&rtc->irq_lock);
++              data = rtc->irq_data;
++              rtc->irq_data = 0;
++              spin_unlock_irq(&rtc->irq_lock);
++
++              if (data != 0) {
++                      ret = 0;
++                      break;
++              }
++              if (file->f_flags & O_NONBLOCK) {
++                      ret = -EAGAIN;
++                      break;
++              }
++              if (signal_pending(current)) {
++                      ret = -ERESTARTSYS;
++                      break;
++              }
++              schedule();
++      } while (1);
++      set_current_state(TASK_RUNNING);
++      remove_wait_queue(&rtc->irq_queue, &wait);
++
++      if (ret == 0) {
++              ret = put_user(data, (unsigned long __user *)buf);
++              if (ret == 0)
++                      ret = sizeof(unsigned long);
++      }
++      return ret;
++}
++
++static unsigned int rtc_dev_poll(struct file *file, poll_table *wait)
++{
++      struct rtc_device *rtc = to_rtc_device(file->private_data);
++      unsigned long data;
++
++      poll_wait(file, &rtc->irq_queue, wait);
++
++      spin_lock_irq(&rtc->irq_lock);
++      data = rtc->irq_data;
++      spin_unlock_irq(&rtc->irq_lock);
++
++      return data != 0 ? POLLIN | POLLRDNORM : 0;
++}
++
++static int rtc_dev_ioctl(struct inode *inode, struct file *file, unsigned int cmd,
++                   unsigned long arg)
++{
++      int err = 0;
++      struct class_device *class_dev = file->private_data;
++      struct rtc_device *rtc = to_rtc_device(class_dev);
++      struct rtc_class_ops *ops = rtc->ops;
++      struct rtc_time tm;
++      struct rtc_wkalrm alarm;
++      void __user *uarg = (void __user *) arg;
++
++      /* avoid conflicting IRQ users */
++      if (cmd == RTC_PIE_ON || cmd == RTC_PIE_OFF || cmd == RTC_IRQP_SET) {
++              spin_lock(&rtc->irq_task_lock);
++              if (rtc->irq_task)
++                      err = -EBUSY;
++              spin_unlock(&rtc->irq_task_lock);
++
++              if (err < 0)
++                      return err;
++      }
++
++      /* try the driver's ioctl interface */
++      if (ops->ioctl) {
++              err = ops->ioctl(class_dev->dev, cmd, arg);
++              if (err < 0 && err != -EINVAL)
++                      return err;
++      }
++
++      /* if the driver does not provide the ioctl interface
++       * or if that particular ioctl was not implemented
++       * (-EINVAL), we will try to emulate here.
++       */
++
++      switch (cmd) {
++      case RTC_ALM_READ:
++              if ((err = rtc_read_alarm(class_dev, &alarm)) < 0)
++                      return err;
++
++              if ((err = copy_to_user(uarg, &alarm.time, sizeof(tm))))
++                      return -EFAULT;
++              break;
++
++      case RTC_ALM_SET:
++              if ((err = copy_from_user(&alarm.time, uarg, sizeof(tm))))
++                      return -EFAULT;
++
++              alarm.enabled = 0;
++              alarm.pending = 0;
++              alarm.time.tm_mday = -1;
++              alarm.time.tm_mon = -1;
++              alarm.time.tm_year = -1;
++              alarm.time.tm_wday = -1;
++              alarm.time.tm_yday = -1;
++              alarm.time.tm_isdst = -1;
++              err = rtc_set_alarm(class_dev, &alarm);
++              break;
++
++      case RTC_RD_TIME:
++              if ((err = rtc_read_time(class_dev, &tm)) < 0)
++                      return err;
++
++              if ((err = copy_to_user(uarg, &tm, sizeof(tm))))
++                      return -EFAULT;
++              break;
++
++      case RTC_SET_TIME:
++              if (!capable(CAP_SYS_TIME))
++                      return -EACCES;
++
++              if ((err = copy_from_user(&tm, uarg, sizeof(tm))))
++                      return -EFAULT;
++
++              err = rtc_set_time(class_dev, &tm);
++              break;
++#if 0
++      case RTC_EPOCH_SET:
++#ifndef rtc_epoch
++              /*
++               * There were no RTC clocks before 1900.
++               */
++              if (arg < 1900) {
++                      err = -EINVAL;
++                      break;
++              }
++              if (!capable(CAP_SYS_TIME)) {
++                      err = -EACCES;
++                      break;
++              }
++              rtc_epoch = arg;
++              err = 0;
++#endif
++              break;
++
++      case RTC_EPOCH_READ:
++              err = put_user(rtc_epoch, (unsigned long __user *)uarg);
++              break;
++#endif
++      case RTC_WKALM_SET:
++              if ((err = copy_from_user(&alarm, uarg, sizeof(alarm))))
++                      return -EFAULT;
++
++              err = rtc_set_alarm(class_dev, &alarm);
++              break;
++
++      case RTC_WKALM_RD:
++              if ((err = rtc_read_alarm(class_dev, &alarm)) < 0)
++                      return err;
++
++              if ((err = copy_to_user(uarg, &alarm, sizeof(alarm))))
++                      return -EFAULT;
++              break;
++
++      default:
++              err = -EINVAL;
++              break;
++      }
++
++      return err;
++}
++
++static int rtc_dev_release(struct inode *inode, struct file *file)
++{
++      struct rtc_device *rtc = to_rtc_device(file->private_data);
++
++      if (rtc->ops->release)
++              rtc->ops->release(rtc->class_dev.dev);
++
++      spin_lock_irq(&rtc->irq_lock);
++      rtc->irq_data = 0;
++      spin_unlock_irq(&rtc->irq_lock);
++
++      up(&rtc->char_sem);
++      return 0;
++}
++
++static int rtc_dev_fasync(int fd, struct file *file, int on)
++{
++      struct rtc_device *rtc = to_rtc_device(file->private_data);
++      return fasync_helper(fd, file, on, &rtc->async_queue);
++}
++
++static struct file_operations rtc_dev_fops = {
++      .owner          = THIS_MODULE,
++      .llseek         = no_llseek,
++      .read           = rtc_dev_read,
++      .poll           = rtc_dev_poll,
++      .ioctl          = rtc_dev_ioctl,
++      .open           = rtc_dev_open,
++      .release        = rtc_dev_release,
++      .fasync         = rtc_dev_fasync,
++};
++
++static ssize_t rtc_dev_show_dev(struct class_device *class_dev, char *buf)
++{
++        return print_dev_t(buf, class_dev->devt);
++}
++static CLASS_DEVICE_ATTR(dev, S_IRUGO, rtc_dev_show_dev, NULL);
++
++/* insertion/removal hooks */
++
++static int rtc_dev_add_device(struct class_device *class_dev,
++                              struct class_interface *class_intf)
++{
++      struct rtc_device *rtc = to_rtc_device(class_dev);
++
++      if (rtc->id >= RTC_DEV_MAX) {
++              dev_err(class_dev->dev, "too many RTCs\n");
++              return -EINVAL;
++      }
++
++      init_MUTEX(&rtc->char_sem);
++      spin_lock_init(&rtc->irq_lock);
++      init_waitqueue_head(&rtc->irq_queue);
++
++      cdev_init(&rtc->char_dev, &rtc_dev_fops);
++      rtc->char_dev.owner = rtc->owner;
++      class_dev->devt = MKDEV(MAJOR(rtc_devt), rtc->id);
++
++      if (cdev_add(&rtc->char_dev, class_dev->devt, 1)) {
++              cdev_del(&rtc->char_dev);
++
++              dev_err(class_dev->dev,
++                      "failed to add char device %d:%d\n",
++                      MAJOR(class_dev->devt),
++                      MINOR(class_dev->devt));
++
++              class_dev->devt = MKDEV(0, 0);
++              return -ENODEV;
++      }
++
++      class_device_create_file(class_dev, &class_device_attr_dev);
++
++      dev_info(class_dev->dev, "rtc intf: dev (%d:%d)\n",
++              MAJOR(class_dev->devt),
++              MINOR(class_dev->devt));
++
++      kobject_hotplug(&class_dev->kobj, KOBJ_ADD);
++
++      return 0;
++}
++
++static void rtc_dev_remove_device(struct class_device *class_dev,
++                                      struct class_interface *class_intf)
++{
++      struct rtc_device *rtc = to_rtc_device(class_dev);
++
++      class_device_remove_file(class_dev, &class_device_attr_dev);
++
++      if (MAJOR(class_dev->devt)) {
++              dev_dbg(class_dev->dev, "removing char %d:%d\n",
++                      MAJOR(class_dev->devt),
++                      MINOR(class_dev->devt));
++              cdev_del(&rtc->char_dev);
++
++              kobject_hotplug(&class_dev->kobj, KOBJ_REMOVE);
++
++              class_dev->devt = MKDEV(0, 0);
++      }
++}
++
++/* interface registration */
++
++struct class_interface rtc_dev_interface = {
++      .add = &rtc_dev_add_device,
++      .remove = &rtc_dev_remove_device,
++};
++
++static int __init rtc_dev_init(void)
++{
++      int err;
++
++      if ((err = alloc_chrdev_region(&rtc_devt, 0, RTC_DEV_MAX, "rtc")) < 0) {
++              printk(KERN_ERR "%s: failed to allocate char dev region\n",
++                      __FILE__);
++              return err;
++      }
++
++      if ((err = rtc_interface_register(&rtc_dev_interface)) < 0) {
++              printk(KERN_ERR "%s: failed to register the interface\n",
++                      __FILE__);
++              unregister_chrdev_region(rtc_devt, RTC_DEV_MAX);
++              return err;
++      }
++
++      return 0;
++}
++
++static void __exit rtc_dev_exit(void)
++{
++      class_interface_unregister(&rtc_dev_interface);
++
++      unregister_chrdev_region(rtc_devt, RTC_DEV_MAX);
++}
++
++module_init(rtc_dev_init);
++module_exit(rtc_dev_exit);
++
++MODULE_AUTHOR("Alessandro Zummo <a.zummo@towertech.it>");
++MODULE_DESCRIPTION("RTC class dev interface");
++MODULE_LICENSE("GPL");
+--- /dev/null  1970-01-01 00:00:00.000000000 +0000
++++ linux-nslu2/drivers/rtc/rtc-x1205.c        2006-01-04 01:27:17.000000000 +0100
+@@ -0,0 +1,725 @@
++/*
++ * 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
++ *
++ * based on a lot of other RTC drivers.
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; either version 2 of the License, or
++ * (at your option) any later version.
++ */
++
++#include <linux/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"
++
++/* 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 struct i2c_driver x1205_driver = {
++      .owner          = THIS_MODULE,
++      .name           = "x1205",
++      .flags          = I2C_DF_NOTIFY,
++      .attach_adapter = &x1205_attach,
++      .detach_client  = &x1205_detach,
++};
++
++/*
++ * In the routines that deal directly with the x1205 hardware, we use
++ * rtc_time -- month 0-11, hour 0-23, yr = calendar year-epoch
++ * Epoch is initialized as 2000. Time is set to UTC.
++ */
++static int x1205_get_datetime(struct i2c_client *client, struct rtc_time *tm,
++                              unsigned char reg_base)
++{
++      unsigned char dt_addr[2] = { 0, reg_base };
++
++      unsigned char buf[8];
++
++      struct i2c_msg msgs[] = {
++              { client->addr, 0, 2, dt_addr },        /* setup read ptr */
++              { client->addr, I2C_M_RD, 8, buf },     /* read date */
++      };
++
++      /* read date registers */
++      if ((i2c_transfer(client->adapter, &msgs[0], 2)) != 2) {
++              dev_err(&client->dev, "%s: read error\n", __FUNCTION__);
++              return -EIO;
++      }
++
++      dev_dbg(&client->dev,
++              "%s: raw read data - sec=%02x, min=%02x, hr=%02x, "
++              "mday=%02x, mon=%02x, year=%02x, wday=%02x, y2k=%02x\n",
++              __FUNCTION__,
++              buf[0], buf[1], buf[2], buf[3],
++              buf[4], buf[5], buf[6], buf[7]);
++
++      tm->tm_sec = BCD2BIN(buf[CCR_SEC]);
++      tm->tm_min = BCD2BIN(buf[CCR_MIN]);
++      tm->tm_hour = BCD2BIN(buf[CCR_HOUR] & 0x3F); /* hr is 0-23 */
++      tm->tm_mday = BCD2BIN(buf[CCR_MDAY]);
++      tm->tm_mon = BCD2BIN(buf[CCR_MONTH]) - 1; /* mon is 0-11 */
++      tm->tm_year = BCD2BIN(buf[CCR_YEAR])
++                      + (BCD2BIN(buf[CCR_Y2K]) * 100) - 1900;
++      tm->tm_wday = buf[CCR_WDAY];
++
++      dev_dbg(&client->dev, "%s: tm is secs=%d, mins=%d, hours=%d, "
++              "mday=%d, mon=%d, year=%d, wday=%d\n",
++              __FUNCTION__,
++              tm->tm_sec, tm->tm_min, tm->tm_hour,
++              tm->tm_mday, tm->tm_mon, tm->tm_year, tm->tm_wday);
++
++      return 0;
++}
++
++static int x1205_get_status(struct i2c_client *client, unsigned char *sr)
++{
++      static unsigned char sr_addr[2] = { 0, X1205_REG_SR };
++
++      struct i2c_msg msgs[] = {
++              { client->addr, 0, 2, sr_addr },        /* setup read ptr */
++              { client->addr, I2C_M_RD, 1, sr },      /* read status */
++      };
++
++      /* read status register */
++      if ((i2c_transfer(client->adapter, &msgs[0], 2)) != 2) {
++              dev_err(&client->dev, "%s: read error\n", __FUNCTION__);
++              return -EIO;
++      }
++
++      return 0;
++}
++
++static int x1205_set_datetime(struct i2c_client *client, struct rtc_time *tm,
++                              int datetoo, u8 reg_base)
++{
++      int i, xfer;
++      unsigned char buf[8];
++
++      static const unsigned char wel[3] = { 0, X1205_REG_SR,
++                                              X1205_SR_WEL };
++
++      static const unsigned char rwel[3] = { 0, X1205_REG_SR,
++                                              X1205_SR_WEL | X1205_SR_RWEL };
++
++      static const unsigned char diswe[3] = { 0, X1205_REG_SR, 0 };
++
++      dev_dbg(&client->dev,
++              "%s: secs=%d, mins=%d, hours=%d\n",
++              __FUNCTION__,
++              tm->tm_sec, tm->tm_min, tm->tm_hour);
++
++      buf[CCR_SEC] = BIN2BCD(tm->tm_sec);
++      buf[CCR_MIN] = BIN2BCD(tm->tm_min);
++
++      /* set hour and 24hr bit */
++      buf[CCR_HOUR] = BIN2BCD(tm->tm_hour) | X1205_HR_MIL;
++
++      /* should we also set the date? */
++      if (datetoo) {
++              dev_dbg(&client->dev,
++                      "%s: mday=%d, mon=%d, year=%d, wday=%d\n",
++                      __FUNCTION__,
++                      tm->tm_mday, tm->tm_mon, tm->tm_year, tm->tm_wday);
++
++              buf[CCR_MDAY] = BIN2BCD(tm->tm_mday);
++
++              /* month, 1 - 12 */
++              buf[CCR_MONTH] = BIN2BCD(tm->tm_mon + 1);
++
++              /* year, since the rtc epoch*/
++              buf[CCR_YEAR] = BIN2BCD(tm->tm_year % 100);
++              buf[CCR_WDAY] = tm->tm_wday & 0x07;
++              buf[CCR_Y2K] = BIN2BCD(tm->tm_year / 100);
++      }
++
++      /* this sequence is required to unlock the chip */
++      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_fix_osc(struct i2c_client *client)
++{
++      int err;
++      struct rtc_time tm;
++
++      tm.tm_hour = 0;
++      tm.tm_min = 0;
++      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");
++
++      return err;
++}
++
++static int x1205_get_dtrim(struct i2c_client *client, int *trim)
++{
++      unsigned char dtr;
++      static unsigned char dtr_addr[2] = { 0, X1205_REG_DTR };
++
++      struct i2c_msg msgs[] = {
++              { client->addr, 0, 2, dtr_addr },       /* setup read ptr */
++              { client->addr, I2C_M_RD, 1, &dtr },    /* read dtr */
++      };
++
++      /* read dtr register */
++      if ((i2c_transfer(client->adapter, &msgs[0], 2)) != 2) {
++              dev_err(&client->dev, "%s: read error\n", __FUNCTION__);
++              return -EIO;
++      }
++
++      dev_dbg(&client->dev, "%s: raw dtr=%x\n", __FUNCTION__, dtr);
++
++      *trim = 0;
++
++      if (dtr & X1205_DTR_DTR0)
++              *trim += 20;
++
++      if (dtr & X1205_DTR_DTR1)
++              *trim += 10;
++
++      if (dtr & X1205_DTR_DTR2)
++              *trim = -*trim;
++
++      return 0;
++}
++
++static int x1205_get_atrim(struct i2c_client *client, int *trim)
++{
++      s8 atr;
++      static unsigned char atr_addr[2] = { 0, X1205_REG_ATR };
++
++      struct i2c_msg msgs[] = {
++              { client->addr, 0, 2, atr_addr },       /* setup read ptr */
++              { client->addr, I2C_M_RD, 1, &atr },    /* read atr */
++      };
++
++      /* read atr register */
++      if ((i2c_transfer(client->adapter, &msgs[0], 2)) != 2) {
++              dev_err(&client->dev, "%s: read error\n", __FUNCTION__);
++              return -EIO;
++      }
++
++      dev_dbg(&client->dev, "%s: raw atr=%x\n", __FUNCTION__, atr);
++
++      /* atr is a two's complement value on 6 bits,
++       * perform sign extension. The formula is
++       * Catr = (atr * 0.25pF) + 11.00pF.
++       */
++      if (atr & 0x20)
++              atr |= 0xC0;
++
++      dev_dbg(&client->dev, "%s: raw atr=%x (%d)\n", __FUNCTION__, atr, atr);
++
++      *trim = (atr * 250) + 11000;
++
++      dev_dbg(&client->dev, "%s: real=%d\n", __FUNCTION__, *trim);
++
++      return 0;
++}
++
++static int x1205_hctosys(struct i2c_client *client)
++{
++      int err;
++
++      struct rtc_time tm;
++      struct timespec tv;
++      unsigned char sr;
++
++      if ((err = x1205_get_status(client, &sr)) < 0)
++              return err;
++
++      /* Don't set if we had a power failure */
++      if (sr & X1205_SR_RTCF)
++              return -EINVAL;
++
++      if ((err = x1205_get_datetime(client, &tm, X1205_CCR_BASE)) < 0)
++              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;
++
++      rtc_tm_to_time(&tm, &tv.tv_sec);
++
++      do_settimeofday(&tv);
++
++      dev_info(&client->dev,
++              "setting the system clock to %d-%d-%d %d:%d:%d\n",
++              tm.tm_year + 1900, tm.tm_mon + 1,
++              tm.tm_mday, tm.tm_hour, tm.tm_min,
++              tm.tm_sec);
++
++      return 0;
++}
++
++struct x1205_limit
++{
++      unsigned char reg;
++      unsigned char mask;
++      unsigned char min;
++      unsigned char max;
++};
++
++static int x1205_validate_client(struct i2c_client *client)
++{
++      int i, xfer;
++
++      /* Probe array. We will read the register at the specified
++       * address and check if the given bits are zero.
++       */
++      static const unsigned char probe_zero_pattern[] = {
++              /* register, mask */
++              X1205_REG_SR,   0x18,
++              X1205_REG_DTR,  0xF8,
++              X1205_REG_ATR,  0xC0,
++              X1205_REG_INT,  0x18,
++              X1205_REG_0,    0xFF,
++      };
++
++      static const struct x1205_limit probe_limits_pattern[] = {
++              /* register, mask, min, max */
++              { X1205_REG_Y2K,        0xFF,   19,     20      },
++              { X1205_REG_DW,         0xFF,   0,      6       },
++              { X1205_REG_YR,         0xFF,   0,      99      },
++              { X1205_REG_MO,         0xFF,   0,      12      },
++              { X1205_REG_DT,         0xFF,   0,      31      },
++              { X1205_REG_HR,         0x7F,   0,      23      },
++              { X1205_REG_MN,         0xFF,   0,      59      },
++              { X1205_REG_SC,         0xFF,   0,      59      },
++              { X1205_REG_Y2K1,       0xFF,   19,     20      },
++              { X1205_REG_Y2K0,       0xFF,   19,     20      },
++      };
++
++      /* check that registers have bits a 0 where expected */
++      for (i = 0; i < ARRAY_SIZE(probe_zero_pattern); i += 2) {
++              unsigned char buf;
++
++              unsigned char addr[2] = { 0, probe_zero_pattern[i] };
++
++              struct i2c_msg msgs[2] = {
++                      { client->addr, 0, 2, addr },
++                      { client->addr, I2C_M_RD, 1, &buf },
++              };
++
++              xfer = i2c_transfer(client->adapter, msgs, 2);
++              if (xfer != 2) {
++                      dev_err(&client->adapter->dev,
++                              "%s: could not read register %x\n",
++                              __FUNCTION__, addr[1]);
++
++                      return -EIO;
++              }
++
++              if ((buf & probe_zero_pattern[i+1]) != 0) {
++                      dev_err(&client->adapter->dev,
++                              "%s: register=%02x, zero pattern=%d, value=%x\n",
++                              __FUNCTION__, addr[1], i, buf);
++
++                      return -ENODEV;
++              }
++      }
++
++      /* check limits (only registers with bcd values) */
++      for (i = 0; i < ARRAY_SIZE(probe_limits_pattern); i++) {
++              unsigned char reg, value;
++
++              unsigned char addr[2] = { 0, probe_limits_pattern[i].reg };
++
++              struct i2c_msg msgs[2] = {
++                      { client->addr, 0, 2, addr },
++                      { client->addr, I2C_M_RD, 1, &reg },
++              };
++
++              xfer = i2c_transfer(client->adapter, msgs, 2);
++
++              if (xfer != 2) {
++                      dev_err(&client->adapter->dev,
++                              "%s: could not read register %x\n",
++                              __FUNCTION__, addr[1]);
++
++                      return -EIO;
++              }
++
++              value = BCD2BIN(reg & probe_limits_pattern[i].mask);
++
++              if (value > probe_limits_pattern[i].max ||
++                      value < probe_limits_pattern[i].min) {
++                      dev_dbg(&client->adapter->dev,
++                              "%s: register=%x, lim pattern=%d, value=%d\n",
++                              __FUNCTION__, addr[1], i, value);
++
++                      return -ENODEV;
++              }
++      }
++
++      return 0;
++}
++
++static int x1205_rtc_read_alarm(struct device *dev,
++      struct rtc_wkalrm *alrm)
++{
++      return x1205_get_datetime(to_i2c_client(dev),
++              &alrm->time, X1205_ALM0_BASE);
++}
++
++static int x1205_rtc_set_alarm(struct device *dev,
++      struct rtc_wkalrm *alrm)
++{
++      return x1205_set_datetime(to_i2c_client(dev),
++              &alrm->time, 1, X1205_ALM0_BASE);
++}
++
++static int x1205_rtc_read_time(struct device *dev,
++      struct rtc_time *tm)
++{
++      return x1205_get_datetime(to_i2c_client(dev),
++              tm, X1205_CCR_BASE);
++}
++
++static int x1205_rtc_set_time(struct device *dev,
++      struct rtc_time *tm)
++{
++      return x1205_set_datetime(to_i2c_client(dev),
++              tm, 1, X1205_CCR_BASE);
++}
++
++static int x1205_rtc_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)
++              seq_printf(seq, "digital_trim\t: %d ppm\n", dtrim);
++
++      err = x1205_get_atrim(to_i2c_client(dev), &atrim);
++      if (err == 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,
++};
++
++static ssize_t x1205_sysfs_show_atrim(struct device *dev,
++                              struct device_attribute *attr, char *buf)
++{
++      int atrim;
++
++        if (x1205_get_atrim(to_i2c_client(dev), &atrim) == 0) {
++                return sprintf(buf, "%d.%02d pF\n",
++                        atrim / 1000, atrim % 1000);        }
++        return 0;
++}
++static DEVICE_ATTR(atrim, S_IRUGO, x1205_sysfs_show_atrim, NULL);
++
++static ssize_t x1205_sysfs_show_dtrim(struct device *dev,
++                              struct device_attribute *attr, char *buf)
++{
++      int dtrim;
++
++        if (x1205_get_dtrim(to_i2c_client(dev), &dtrim) == 0) {
++                return sprintf(buf, "%d ppm\n", dtrim);
++        }
++        return 0;
++}
++static DEVICE_ATTR(dtrim, S_IRUGO, x1205_sysfs_show_dtrim, NULL);
++
++
++static int x1205_attach(struct i2c_adapter *adapter)
++{
++      dev_dbg(&adapter->dev, "%s\n", __FUNCTION__);
++
++      return i2c_probe(adapter, &addr_data, x1205_probe);
++}
++
++static int x1205_probe(struct i2c_adapter *adapter, int address, int kind)
++{
++      int err = 0;
++      unsigned char sr;
++      struct i2c_client *client;
++      struct rtc_device *rtc;
++
++      dev_dbg(&adapter->dev, "%s\n", __FUNCTION__);
++
++      if (!i2c_check_functionality(adapter, I2C_FUNC_I2C)) {
++              err = -ENODEV;
++              goto exit;
++      }
++
++      if (!(client = kzalloc(sizeof(struct i2c_client), GFP_KERNEL))) {
++              err = -ENOMEM;
++              goto exit;
++      }
++
++      /* I2C client */
++      client->addr = address;
++      client->driver = &x1205_driver;
++      client->adapter = adapter;
++
++      strlcpy(client->name, x1205_driver.name, I2C_NAME_SIZE);
++
++      /* Verify the chip is really an X1205 */
++      if (kind < 0) {
++              if (x1205_validate_client(client) < 0) {
++                      err = -ENODEV;
++                      goto exit_kfree;
++              }
++      }
++
++      /* Inform the i2c layer */
++      if ((err = i2c_attach_client(client)))
++              goto exit_kfree;
++
++      dev_info(&client->dev, "chip found, driver version " DRV_VERSION "\n");
++
++      rtc = rtc_device_register(x1205_driver.name, &client->dev,
++                              &x1205_rtc_ops, THIS_MODULE);
++
++      if (IS_ERR(rtc)) {
++              err = PTR_ERR(rtc);
++              dev_err(&client->dev,
++                      "unable to register the class device\n");
++              goto exit_detach;
++      }
++
++      i2c_set_clientdata(client, rtc);
++
++      /* Check for power failures and eventualy enable the osc */
++      if ((err = x1205_get_status(client, &sr)) == 0) {
++              if (sr & X1205_SR_RTCF) {
++                      dev_err(&client->dev,
++                              "power failure detected, "
++                              "please set the clock\n");
++                      udelay(50);
++                      x1205_fix_osc(client);
++              }
++      }
++      else
++              dev_err(&client->dev, "couldn't read status\n");
++
++      /* If requested, set the system time */
++      if (hctosys) {
++              if ((err = x1205_hctosys(client)) < 0)
++                      dev_err(&client->dev,
++                              "unable to set the system clock\n");
++      }
++
++      device_create_file(&client->dev, &dev_attr_atrim);
++      device_create_file(&client->dev, &dev_attr_dtrim);
++
++      return 0;
++
++exit_detach:
++      i2c_detach_client(client);
++
++exit_kfree:
++      kfree(client);
++
++exit:
++      return err;
++}
++
++static int x1205_detach(struct i2c_client *client)
++{
++      int err;
++      struct rtc_device *rtc = i2c_get_clientdata(client);
++
++      dev_dbg(&client->dev, "%s\n", __FUNCTION__);
++
++      if (rtc)
++              rtc_device_unregister(rtc);
++
++      if ((err = i2c_detach_client(client)))
++              return err;
++
++      kfree(client);
++
++      return 0;
++}
++
++static int __init x1205_init(void)
++{
++      return i2c_add_driver(&x1205_driver);
++}
++
++static void __exit x1205_exit(void)
++{
++      i2c_del_driver(&x1205_driver);
++}
++
++MODULE_AUTHOR(
++      "Karen Spearel <kas11@tampabay.rr.com>, "
++      "Alessandro Zummo <a.zummo@towertech.it>");
++MODULE_DESCRIPTION("Xicor/Intersil X1205 RTC driver");
++MODULE_LICENSE("GPL");
++MODULE_VERSION(DRV_VERSION);
++
++module_init(x1205_init);
++module_exit(x1205_exit);
+--- /dev/null  1970-01-01 00:00:00.000000000 +0000
++++ linux-nslu2/drivers/rtc/rtc-test.c 2006-01-04 01:27:19.000000000 +0100
+@@ -0,0 +1,189 @@
++/*
++ * An RTC test device/driver
++ * Copyright (C) 2005 Tower Technologies
++ * Author: Alessandro Zummo <a.zummo@towertech.it>
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; either version 2 of the License, or
++ * (at your option) any later version.
++ */
++
++#include <linux/module.h>
++#include <linux/err.h>
++#include <linux/rtc.h>
++#include <linux/platform_device.h>
++
++static int test_rtc_read_alarm(struct device *dev,
++      struct rtc_wkalrm *alrm)
++{
++      return 0;
++}
++
++static int test_rtc_set_alarm(struct device *dev,
++      struct rtc_wkalrm *alrm)
++{
++      return 0;
++}
++
++static int test_rtc_read_time(struct device *dev,
++      struct rtc_time *tm)
++{
++      rtc_time_to_tm(get_seconds(), tm);
++      return 0;
++}
++
++static int test_rtc_set_time(struct device *dev,
++      struct rtc_time *tm)
++{
++      return 0;
++}
++
++static int test_rtc_set_mmss(struct device *dev, unsigned long secs)
++{
++      return 0;
++}
++
++static int test_rtc_proc(struct device *dev, struct seq_file *seq)
++{
++      struct platform_device *plat_dev = to_platform_device(dev);
++
++      seq_printf(seq, "24hr\t\t: yes\n");
++      seq_printf(seq, "test\t\t: yes\n");
++      seq_printf(seq, "id\t\t: %d\n", plat_dev->id);
++
++      return 0;
++}
++
++static int test_rtc_ioctl(struct device *dev, unsigned int cmd,
++      unsigned long arg)
++{
++      /* We do support interrupts, they're generated
++       * using the sysfs interface.
++       */
++      switch (cmd) {
++      case RTC_PIE_ON:
++      case RTC_PIE_OFF:
++      case RTC_UIE_ON:
++      case RTC_UIE_OFF:
++      case RTC_AIE_ON:
++      case RTC_AIE_OFF:
++              return 0;
++
++      default:
++              return -EINVAL;
++      }
++}
++
++static struct rtc_class_ops test_rtc_ops = {
++      .proc = test_rtc_proc,
++      .read_time = test_rtc_read_time,
++      .set_time = test_rtc_set_time,
++      .read_alarm = test_rtc_read_alarm,
++      .set_alarm = test_rtc_set_alarm,
++      .set_mmss = test_rtc_set_mmss,
++      .ioctl = test_rtc_ioctl,
++};
++
++static ssize_t test_irq_show(struct device *dev,
++                              struct device_attribute *attr, char *buf)
++{
++      return sprintf(buf, "%d\n", 42);
++}
++static ssize_t test_irq_store(struct device *dev,
++                              struct device_attribute *attr,
++                              const char *buf, size_t count)
++{
++      int retval;
++      struct platform_device *plat_dev = to_platform_device(dev);
++      struct rtc_device *rtc = platform_get_drvdata(plat_dev);
++
++      retval = count;
++      if (strncmp(buf, "tick", 4) == 0)
++              rtc_update_irq(&rtc->class_dev, 1, RTC_PF | RTC_IRQF);
++      else if (strncmp(buf, "alarm", 5) == 0)
++              rtc_update_irq(&rtc->class_dev, 1, RTC_AF | RTC_IRQF);
++      else if (strncmp(buf, "update", 6) == 0)
++              rtc_update_irq(&rtc->class_dev, 1, RTC_UF | RTC_IRQF);
++      else
++              retval = -EINVAL;
++
++      return retval;
++}
++static DEVICE_ATTR(irq, S_IRUGO | S_IWUSR, test_irq_show, test_irq_store);
++
++static int test_probe(struct platform_device *plat_dev)
++{
++      int err;
++      struct rtc_device *rtc = rtc_device_register("test", &plat_dev->dev,
++                                              &test_rtc_ops, THIS_MODULE);
++      if (IS_ERR(rtc)) {
++              err = PTR_ERR(rtc);
++              dev_err(&plat_dev->dev,
++                      "unable to register the class device\n");
++              return err;
++      }
++      device_create_file(&plat_dev->dev, &dev_attr_irq);
++
++      platform_set_drvdata(plat_dev, rtc);
++
++      return 0;
++}
++
++static int test_remove(struct platform_device *plat_dev)
++{
++      struct rtc_device *rtc = platform_get_drvdata(plat_dev);
++
++      rtc_device_unregister(rtc);
++      device_remove_file(&plat_dev->dev, &dev_attr_irq);
++
++      return 0;
++}
++
++static void test_release(struct device * dev)
++{
++}
++
++struct platform_device test_dev_zero = {
++      .name   = "rtc-test",
++      .id     = 0,
++      .dev.release = test_release,
++};
++
++struct platform_device test_dev_one = {
++      .name   = "rtc-test",
++      .id     = 1,
++      .dev.release = test_release,
++};
++
++struct platform_driver test_drv = {
++      .probe  = test_probe,
++      .remove = test_remove,
++      .driver = {
++              .name = "rtc-test",
++              .owner = THIS_MODULE,
++      },
++};
++
++static int __init test_init(void)
++{
++      platform_device_register(&test_dev_zero);
++      platform_device_register(&test_dev_one);
++      platform_driver_register(&test_drv);
++
++      return 0;
++}
++
++static void __exit test_exit(void)
++{
++      platform_driver_unregister(&test_drv);
++      platform_device_unregister(&test_dev_zero);
++      platform_device_unregister(&test_dev_one);
++}
++
++MODULE_AUTHOR("Alessandro Zummo <a.zummo@towertech.it>");
++MODULE_DESCRIPTION("RTC test driver/device");
++MODULE_LICENSE("GPL");
++
++module_init(test_init);
++module_exit(test_exit);
+--- /dev/null  1970-01-01 00:00:00.000000000 +0000
++++ linux-nslu2/drivers/rtc/rtc-ds1672.c       2006-01-04 01:27:21.000000000 +0100
+@@ -0,0 +1,266 @@
++/*
++ * An rtc/i2c driver for the Dallas DS1672
++ * Copyright 2005 Alessandro Zummo
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License as published by
++ * the Free Software Foundation; either version 2 of the License, or
++ * (at your option) any later version.
++ */
++
++#include <linux/module.h>
++#include <linux/i2c.h>
++#include <linux/rtc.h>
++
++#define DRV_VERSION "0.1"
++
++/* Addresses to scan: none. This chip cannot be detected. */
++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");
++
++/* Registers */
++
++#define DS1672_REG_CNT_BASE   0
++#define DS1672_REG_CONTROL    4
++#define DS1672_REG_TRICKLE    5
++
++
++/* Prototypes */
++static int ds1672_probe(struct i2c_adapter *adapter, int address, int kind);
++
++/*
++ * In the routines that deal directly with the ds1672 hardware, we use
++ * rtc_time -- month 0-11, hour 0-23, yr = calendar year-epoch
++ * Epoch is initialized as 2000. Time is set to UTC.
++ */
++static int ds1672_get_datetime(struct i2c_client *client, struct rtc_time *tm)
++{
++      unsigned long time;
++      unsigned char buf[4];
++
++      dev_dbg(&client->dev,
++              "%s: raw read data - counters=%02x,%02x,%02x,%02x\n"
++              __FUNCTION__,
++              buf[0], buf[1], buf[2], buf[3]);
++
++      time = (buf[3] << 24) | (buf[2] << 16) | (buf[1] << 8) | buf[0];
++
++      rtc_time_to_tm(time, tm);
++
++      dev_dbg(&client->dev, "%s: tm is secs=%d, mins=%d, hours=%d, "
++              "mday=%d, mon=%d, year=%d, wday=%d\n",
++              __FUNCTION__,
++              tm->tm_sec, tm->tm_min, tm->tm_hour,
++              tm->tm_mday, tm->tm_mon, tm->tm_year, tm->tm_wday);
++
++      return 0;
++}
++
++static int ds1672_set_mmss(struct i2c_client *client, unsigned long secs)
++{
++      int xfer;
++      unsigned char buf[5];
++
++      buf[0] = DS1672_REG_CNT_BASE;
++      buf[1] = secs & 0x000000FF;
++      buf[2] = (secs & 0x0000FF00) >> 8;
++      buf[3] = (secs & 0x00FF0000) >> 16;
++      buf[4] = (secs & 0xFF000000) >> 24;
++
++      xfer = i2c_master_send(client, buf, 5);
++      if (xfer != 5) {
++              dev_err(&client->dev, "%s: send: %d\n", __FUNCTION__, xfer);
++              return -EIO;
++      }
++
++      return 0;
++}
++
++static int ds1672_set_datetime(struct i2c_client *client, struct rtc_time *tm)
++{
++      unsigned long secs;
++
++      dev_dbg(&client->dev,
++              "%s: secs=%d, mins=%d, hours=%d, ",
++              "mday=%d, mon=%d, year=%d, wday=%d\n",
++              __FUNCTION__,
++              tm->tm_sec, tm->tm_min, tm->tm_hour,
++              tm->tm_mday, tm->tm_mon, tm->tm_year, tm->tm_wday);
++
++      rtc_tm_to_time(tm, &secs);
++
++      return ds1672_set_mmss(client, secs);
++}
++
++static int ds1672_hctosys(struct i2c_client *client)
++{
++      int err;
++      struct rtc_time tm;
++      struct timespec tv;
++
++      if ((err = ds1672_get_datetime(client, &tm)) != 0)
++              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;
++
++      rtc_tm_to_time(&tm, &tv.tv_sec);
++
++      do_settimeofday(&tv);
++
++      dev_info(&client->dev,
++              "setting the system clock to %d-%02d-%02d %02d:%02d:%02d\n",
++              tm.tm_year + 1900, tm.tm_mon + 1,
++              tm.tm_mday, tm.tm_hour, tm.tm_min,
++              tm.tm_sec);
++
++      return 0;
++}
++
++static int ds1672_rtc_read_time(struct device *dev, struct rtc_time *tm)
++{
++      return ds1672_get_datetime(to_i2c_client(dev), tm);
++}
++
++static int ds1672_rtc_set_time(struct device *dev, struct rtc_time *tm)
++{
++      return ds1672_set_datetime(to_i2c_client(dev), tm);
++}
++
++static int ds1672_rtc_set_mmss(struct device *dev, unsigned long secs)
++{
++      return ds1672_set_mmss(to_i2c_client(dev), secs);
++}
++
++static struct rtc_class_ops ds1672_rtc_ops = {
++      .read_time = ds1672_rtc_read_time,
++      .set_time = ds1672_rtc_set_time,
++      .set_mmss = ds1672_rtc_set_mmss,
++};
++
++static int ds1672_attach(struct i2c_adapter *adapter)
++{
++      dev_dbg(&adapter->dev, "%s\n", __FUNCTION__);
++
++      return i2c_probe(adapter, &addr_data, ds1672_probe);
++}
++
++static int ds1672_detach(struct i2c_client *client)
++{
++      int err;
++      struct rtc_device *rtc = i2c_get_clientdata(client);
++
++      dev_dbg(&client->dev, "%s\n", __FUNCTION__);
++
++      if (rtc)
++              rtc_device_unregister(rtc);
++
++      if ((err = i2c_detach_client(client)))
++              return err;
++
++      kfree(client);
++
++      return 0;
++}
++
++static struct i2c_driver ds1672_driver = {
++      .owner          = THIS_MODULE,
++      .name           = "ds1672",
++      .flags          = I2C_DF_NOTIFY,
++      .attach_adapter = &ds1672_attach,
++      .detach_client  = &ds1672_detach,
++};
++
++static int ds1672_probe(struct i2c_adapter *adapter, int address, int kind)
++{
++      int err = 0;
++      struct i2c_client *client;
++      struct rtc_device *rtc;
++
++      dev_dbg(&adapter->dev, "%s\n", __FUNCTION__);
++
++      if (!i2c_check_functionality(adapter, I2C_FUNC_I2C)) {
++              err = -ENODEV;
++              goto exit;
++      }
++
++      if (!(client = kzalloc(sizeof(struct i2c_client), GFP_KERNEL))) {
++              err = -ENOMEM;
++              goto exit;
++      }
++
++      /* I2C client */
++      client->addr = address;
++      client->driver = &ds1672_driver;
++      client->adapter = adapter;
++
++      strlcpy(client->name, ds1672_driver.name, I2C_NAME_SIZE);
++
++      /* Inform the i2c layer */
++      if ((err = i2c_attach_client(client)))
++              goto exit_kfree;
++
++      dev_info(&client->dev, "chip found, driver version " DRV_VERSION "\n");
++
++      rtc = rtc_device_register(ds1672_driver.name, &client->dev,
++                              &ds1672_rtc_ops, THIS_MODULE);
++
++      if (IS_ERR(rtc)) {
++              err = PTR_ERR(rtc);
++              dev_err(&client->dev,
++                      "unable to register the class device\n");
++              goto exit_detach;
++      }
++
++      i2c_set_clientdata(client, rtc);
++
++      /* If requested, set the system time */
++      if (hctosys) {
++              if ((err = ds1672_hctosys(client)) < 0)
++                      dev_err(&client->dev,
++                              "unable to set the system clock\n");
++      }
++
++      return 0;
++
++exit_detach:
++      i2c_detach_client(client);
++
++exit_kfree:
++      kfree(client);
++
++exit:
++      return err;
++}
++
++static int __init ds1672_init(void)
++{
++      return i2c_add_driver(&ds1672_driver);
++}
++
++static void __exit ds1672_exit(void)
++{
++      i2c_del_driver(&ds1672_driver);
++}
++
++MODULE_AUTHOR("Alessandro Zummo <a.zummo@towertech.it>");
++MODULE_DESCRIPTION("Dallas/Maxim DS1672 timekeeper driver");
++MODULE_LICENSE("GPL");
++MODULE_VERSION(DRV_VERSION);
++
++module_init(ds1672_init);
++module_exit(ds1672_exit);
index eed275f..028e504 100644 (file)
@@ -1,11 +1,5 @@
- arch/arm/mach-ixp4xx/Kconfig           |    8 ++++++++
- arch/arm/mach-ixp4xx/Makefile          |    1 +
- include/asm-arm/arch-ixp4xx/hardware.h |    1 +
- include/asm-arm/arch-ixp4xx/irqs.h     |    9 +++++++++
- 4 files changed, 19 insertions(+)
-
---- linux-nas100d.orig/arch/arm/mach-ixp4xx/Kconfig    2005-11-16 22:29:00.000000000 +0100
-+++ linux-nas100d/arch/arm/mach-ixp4xx/Kconfig 2005-11-16 22:29:52.000000000 +0100
+--- linux-2.6.15-rc7/arch/arm/mach-ixp4xx/Kconfig      2005-12-27 22:29:00.000000000 +0100
++++ linux-2.6.15-rc7/arch/arm/mach-ixp4xx/Kconfig      2005-12-27 22:29:52.000000000 +0100
 @@ -71,6 +71,14 @@ config ARCH_PRPMC1100
          PrPCM1100 Processor Mezanine Module. For more information on
          this platform, see <file:Documentation/arm/IXP4xx>.
  #
  # Avila and IXDP share the same source for now. Will change in future
  #
---- linux-nas100d.orig/arch/arm/mach-ixp4xx/Makefile   2005-11-16 22:29:00.000000000 +0100
-+++ linux-nas100d/arch/arm/mach-ixp4xx/Makefile        2005-11-16 22:30:37.000000000 +0100
+--- linux-2.6.15-rc7/arch/arm/mach-ixp4xx/Makefile     2005-12-27 22:29:00.000000000 +0100
++++ linux-2.6.15-rc7/arch/arm/mach-ixp4xx/Makefile     2005-12-27 22:30:37.000000000 +0100
 @@ -9,4 +9,5 @@ obj-$(CONFIG_MACH_IXDPG425)    += ixdpg425-
  obj-$(CONFIG_ARCH_ADI_COYOTE) += coyote-pci.o coyote-setup.o
  obj-$(CONFIG_MACH_GTWX5715)   += gtwx5715-pci.o gtwx5715-setup.o
  obj-$(CONFIG_MACH_NSLU2)      += nslu2-pci.o nslu2-setup.o nslu2-power.o
 +obj-$(CONFIG_MACH_NAS100D)    += nas100d-pci.o nas100d-setup.o nas100d-power.o
  
---- linux-nas100d.orig/include/asm-arm/arch-ixp4xx/hardware.h  2005-11-16 22:29:18.000000000 +0100
-+++ linux-nas100d/include/asm-arm/arch-ixp4xx/hardware.h       2005-11-16 22:31:08.000000000 +0100
+--- linux-2.6.15-rc7/include/asm-arm/arch-ixp4xx/hardware.h    2005-12-27 22:29:18.000000000 +0100
++++ linux-2.6.15-rc7/include/asm-arm/arch-ixp4xx/hardware.h    2005-12-27 22:31:08.000000000 +0100
 @@ -45,5 +45,6 @@ extern unsigned int processor_id;
  #include "coyote.h"
  #include "prpmc1100.h"
@@ -38,8 +32,8 @@
 +#include "nas100d.h"
  
  #endif  /* _ASM_ARCH_HARDWARE_H */
---- linux-nas100d.orig/include/asm-arm/arch-ixp4xx/irqs.h      2005-11-16 22:29:18.000000000 +0100
-+++ linux-nas100d/include/asm-arm/arch-ixp4xx/irqs.h   2005-11-16 22:29:52.000000000 +0100
+--- linux-2.6.15-rc7/include/asm-arm/arch-ixp4xx/irqs.h        2005-12-27 22:29:18.000000000 +0100
++++ linux-2.6.15-rc7/include/asm-arm/arch-ixp4xx/irqs.h        2005-12-27 22:29:52.000000000 +0100
 @@ -100,4 +100,13 @@
  #define        IRQ_NSLU2_PCI_INTB      IRQ_IXP4XX_GPIO10
  #define        IRQ_NSLU2_PCI_INTC      IRQ_IXP4XX_GPIO9
 +/*
 + * NAS100D board IRQs
 + */
-+#define        IRQ_NAS100D_PCI_INTA      IRQ_IXP4XX_GPIO11
-+#define        IRQ_NAS100D_PCI_INTB      IRQ_IXP4XX_GPIO10
-+#define        IRQ_NAS100D_PCI_INTC      IRQ_IXP4XX_GPIO9
-+#define        IRQ_NAS100D_PCI_INTD      IRQ_IXP4XX_GPIO8
-+#define        IRQ_NAS100D_PCI_INTE      IRQ_IXP4XX_GPIO7
++#define        IRQ_NAS100D_PCI_INTA    IRQ_IXP4XX_GPIO11
++#define        IRQ_NAS100D_PCI_INTB    IRQ_IXP4XX_GPIO10
++#define        IRQ_NAS100D_PCI_INTC    IRQ_IXP4XX_GPIO9
++#define        IRQ_NAS100D_PCI_INTD    IRQ_IXP4XX_GPIO8
++#define        IRQ_NAS100D_PCI_INTE    IRQ_IXP4XX_GPIO7
 +
  #endif
+--- /dev/null  1970-01-01 00:00:00.000000000 +0000
++++ linux-2.6.15-rc7/include/asm-arm/arch-ixp4xx/nas100d.h     2005-11-12 14:24:14.000000000 +0100
+@@ -0,0 +1,75 @@
++/*
++ * include/asm-arm/arch-ixp4xx/nas100d.h
++ *
++ * NAS100D platform specific definitions
++ *
++ * Copyright (c) 2005 Tower Technologies
++ *
++ * Author: Alessandro Zummo <a.zummo@towertech.it>
++ *
++ * based on ixdp425.h:
++ *    Copyright 2004 (c) MontaVista, Software, Inc.
++ *
++ * This file is licensed under  the terms of the GNU General Public
++ * License version 2. This program is licensed "as is" without any
++ * warranty of any kind, whether express or implied.
++ */
++
++#ifndef __ASM_ARCH_HARDWARE_H__
++#error "Do not include this directly, instead #include <asm/hardware.h>"
++#endif
++
++#define NAS100D_FLASH_BASE    IXP4XX_EXP_BUS_CS0_BASE_PHYS
++#define NAS100D_FLASH_SIZE    IXP4XX_EXP_BUS_CSX_REGION_SIZE
++
++#define NAS100D_SDA_PIN               6
++#define NAS100D_SCL_PIN               5
++
++/*
++ * NAS100D PCI IRQs
++ */
++#define NAS100D_PCI_MAX_DEV   3
++#define NAS100D_PCI_IRQ_LINES 3
++
++
++/* PCI controller GPIO to IRQ pin mappings */
++#define NAS100D_PCI_INTA_PIN  11
++#define NAS100D_PCI_INTB_PIN  10
++#define NAS100D_PCI_INTC_PIN  9
++#define NAS100D_PCI_INTD_PIN  8
++#define NAS100D_PCI_INTE_PIN  7
++
++/* GPIO */
++
++#define NAS100D_GPIO0           0
++#define NAS100D_GPIO1           1
++#define NAS100D_GPIO2           2
++#define NAS100D_GPIO3           3
++#define NAS100D_GPIO4           4
++#define NAS100D_GPIO5           5
++#define NAS100D_GPIO6           6
++#define NAS100D_GPIO7           7
++#define NAS100D_GPIO8           8
++#define NAS100D_GPIO9           9
++#define NAS100D_GPIO10          10
++#define NAS100D_GPIO11          11
++#define NAS100D_GPIO12          12
++#define NAS100D_GPIO13          13
++#define NAS100D_GPIO14          14
++#define NAS100D_GPIO15          15
++
++
++/* Buttons */
++
++#define NAS100D_PB_GPIO         NAS100D_GPIO14
++#define NAS100D_RB_GPIO         NAS100D_GPIO4
++#define NAS100D_PO_GPIO         NAS100D_GPIO12   /* power off */
++
++#define NAS100D_PB_IRQ          IRQ_IXP4XX_GPIO14
++#define NAS100D_RB_IRQ          IRQ_IXP4XX_GPIO4
++
++/*
++#define NAS100D_PB_BM           (1L << NAS100D_PB_GPIO)
++#define NAS100D_PO_BM           (1L << NAS100D_PO_GPIO)
++#define NAS100D_RB_BM           (1L << NAS100D_RB_GPIO)
++*/
+--- /dev/null  1970-01-01 00:00:00.000000000 +0000
++++ linux-2.6.15-rc7/arch/arm/mach-ixp4xx/nas100d-pci.c        2005-11-12 14:24:14.000000000 +0100
+@@ -0,0 +1,77 @@
++/*
++ * arch/arm/mach-ixp4xx/nas100d-pci.c
++ *
++ * NAS 100d board-level PCI initialization
++ *
++ * based on ixdp425-pci.c:
++ *    Copyright (C) 2002 Intel Corporation.
++ *    Copyright (C) 2003-2004 MontaVista Software, Inc.
++ *
++ * Maintainer: http://www.nslu2-linux.org/
++ *
++ * 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/config.h>
++#include <linux/pci.h>
++#include <linux/init.h>
++
++#include <asm/mach/pci.h>
++#include <asm/mach-types.h>
++
++void __init nas100d_pci_preinit(void)
++{
++      set_irq_type(IRQ_NAS100D_PCI_INTA, IRQT_LOW);
++      set_irq_type(IRQ_NAS100D_PCI_INTB, IRQT_LOW);
++      set_irq_type(IRQ_NAS100D_PCI_INTC, IRQT_LOW);
++      set_irq_type(IRQ_NAS100D_PCI_INTD, IRQT_LOW);
++      set_irq_type(IRQ_NAS100D_PCI_INTE, IRQT_LOW);
++
++      gpio_line_isr_clear(NAS100D_PCI_INTA_PIN);
++      gpio_line_isr_clear(NAS100D_PCI_INTB_PIN);
++      gpio_line_isr_clear(NAS100D_PCI_INTC_PIN);
++      gpio_line_isr_clear(NAS100D_PCI_INTD_PIN);
++      gpio_line_isr_clear(NAS100D_PCI_INTE_PIN);
++
++      ixp4xx_pci_preinit();
++}
++
++static int __init nas100d_map_irq(struct pci_dev *dev, u8 slot, u8 pin)
++{
++      static int pci_irq_table[NAS100D_PCI_MAX_DEV][NAS100D_PCI_IRQ_LINES] =
++      {
++              { IRQ_NAS100D_PCI_INTA, -1, -1 },
++              { IRQ_NAS100D_PCI_INTB, -1, -1 },
++              { IRQ_NAS100D_PCI_INTC, IRQ_NAS100D_PCI_INTD, IRQ_NAS100D_PCI_INTE },
++      };
++
++      int irq = -1;
++
++      if (slot >= 1 && slot <= NAS100D_PCI_MAX_DEV &&
++              pin >= 1 && pin <= NAS100D_PCI_IRQ_LINES)
++              irq = pci_irq_table[slot-1][pin-1];
++
++      return irq;
++}
++
++struct hw_pci __initdata nas100d_pci = {
++      .nr_controllers = 1,
++      .preinit        = nas100d_pci_preinit,
++      .swizzle        = pci_std_swizzle,
++      .setup          = ixp4xx_setup,
++      .scan           = ixp4xx_scan_bus,
++      .map_irq        = nas100d_map_irq,
++};
++
++int __init nas100d_pci_init(void)
++{
++      if (machine_is_nas100d())
++              pci_common_init(&nas100d_pci);
++
++      return 0;
++}
++
++subsys_initcall(nas100d_pci_init);
+--- /dev/null  1970-01-01 00:00:00.000000000 +0000
++++ linux-2.6.15-rc7/arch/arm/mach-ixp4xx/nas100d-power.c      2005-11-12 14:24:14.000000000 +0100
+@@ -0,0 +1,69 @@
++/*
++ * arch/arm/mach-ixp4xx/nas100d-power.c
++ *
++ * NAS 100d Power/Reset driver
++ *
++ * Copyright (C) 2005 Tower Technologies
++ *
++ * based on nas100d-io.c
++ *  Copyright (C) 2004 Karen Spearel
++ *
++ * Author: Alessandro Zummo <a.zummo@towertech.it>
++ * Maintainers: http://www.nslu2-linux.org/
++ *
++ * 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/module.h>
++#include <linux/reboot.h>
++#include <linux/interrupt.h>
++
++#include <asm/mach-types.h>
++
++extern void ctrl_alt_del(void);
++
++static irqreturn_t nas100d_reset_handler(int irq, void *dev_id, struct pt_regs *regs)
++{
++      /* Signal init to do the ctrlaltdel action, this will bypass init if
++       * it hasn't started and do a kernel_restart.
++       */
++      ctrl_alt_del();
++
++      return IRQ_HANDLED;
++}
++
++static int __init nas100d_power_init(void)
++{
++      if (!(machine_is_nas100d()))
++              return 0;
++
++      set_irq_type(NAS100D_RB_IRQ, IRQT_LOW);
++
++      gpio_line_isr_clear(NAS100D_RB_GPIO);
++
++      if (request_irq(NAS100D_RB_IRQ, &nas100d_reset_handler,
++              SA_INTERRUPT, "NAS100D reset button", NULL) < 0) {
++
++              printk(KERN_DEBUG "Reset Button IRQ %d not available\n",
++                      NAS100D_RB_IRQ);
++
++              return -EIO;
++      }
++
++      return 0;
++}
++
++static void __exit nas100d_power_exit(void)
++{
++      free_irq(NAS100D_RB_IRQ, NULL);
++}
++
++module_init(nas100d_power_init);
++module_exit(nas100d_power_exit);
++
++MODULE_AUTHOR("Alessandro Zummo <a.zummo@towertech.it>");
++MODULE_DESCRIPTION("NAS100D Power/Reset driver");
++MODULE_LICENSE("GPL");
+--- /dev/null  1970-01-01 00:00:00.000000000 +0000
++++ linux-2.6.15-rc7/arch/arm/mach-ixp4xx/nas100d-setup.c      2005-11-12 14:24:14.000000000 +0100
+@@ -0,0 +1,133 @@
++/*
++ * arch/arm/mach-ixp4xx/nas100d-setup.c
++ *
++ * NAS 100d board-setup
++ *
++ * based ixdp425-setup.c:
++ *      Copyright (C) 2003-2004 MontaVista Software, Inc.
++ *
++ * Author: Alessandro Zummo <a.zummo@towertech.it>
++ * Author: Rod Whitby <rod@whitby.id.au>
++ * Maintainers: http://www.nslu2-linux.org/
++ *
++ */
++
++#include <linux/kernel.h>
++#include <linux/serial.h>
++#include <linux/serial_8250.h>
++
++#include <asm/mach-types.h>
++#include <asm/mach/arch.h>
++#include <asm/mach/flash.h>
++
++static struct flash_platform_data nas100d_flash_data = {
++      .map_name               = "cfi_probe",
++      .width                  = 2,
++};
++
++static struct resource nas100d_flash_resource = {
++      .start                  = NAS100D_FLASH_BASE,
++      .end                    = NAS100D_FLASH_BASE + NAS100D_FLASH_SIZE,
++      .flags                  = IORESOURCE_MEM,
++};
++
++static struct platform_device nas100d_flash = {
++      .name                   = "IXP4XX-Flash",
++      .id                     = 0,
++      .dev.platform_data      = &nas100d_flash_data,
++      .num_resources          = 1,
++      .resource               = &nas100d_flash_resource,
++};
++
++static struct ixp4xx_i2c_pins nas100d_i2c_gpio_pins = {
++      .sda_pin                = NAS100D_SDA_PIN,
++      .scl_pin                = NAS100D_SCL_PIN,
++};
++
++static struct platform_device nas100d_i2c_controller = {
++      .name                   = "IXP4XX-I2C",
++      .id                     = 0,
++      .dev.platform_data      = &nas100d_i2c_gpio_pins,
++      .num_resources          = 0,
++};
++
++static struct resource nas100d_uart_resources[] = {
++      {
++              .start          = IXP4XX_UART1_BASE_PHYS,
++              .end            = IXP4XX_UART1_BASE_PHYS + 0x0fff,
++              .flags          = IORESOURCE_MEM,
++      },
++      {
++              .start          = IXP4XX_UART2_BASE_PHYS,
++              .end            = IXP4XX_UART2_BASE_PHYS + 0x0fff,
++              .flags          = IORESOURCE_MEM,
++      }
++};
++
++static struct plat_serial8250_port nas100d_uart_data[] = {
++      {
++              .mapbase        = IXP4XX_UART1_BASE_PHYS,
++              .membase        = (char *)IXP4XX_UART1_BASE_VIRT + REG_OFFSET,
++              .irq            = IRQ_IXP4XX_UART1,
++              .flags          = UPF_BOOT_AUTOCONF,
++              .iotype         = UPIO_MEM,
++              .regshift       = 2,
++              .uartclk        = IXP4XX_UART_XTAL,
++      },
++      {
++              .mapbase        = IXP4XX_UART2_BASE_PHYS,
++              .membase        = (char *)IXP4XX_UART2_BASE_VIRT + REG_OFFSET,
++              .irq            = IRQ_IXP4XX_UART2,
++              .flags          = UPF_BOOT_AUTOCONF,
++              .iotype         = UPIO_MEM,
++              .regshift       = 2,
++              .uartclk        = IXP4XX_UART_XTAL,
++      },
++      { }
++};
++
++static struct platform_device nas100d_uart = {
++      .name                   = "serial8250",
++      .id                     = PLAT8250_DEV_PLATFORM,
++      .dev.platform_data      = nas100d_uart_data,
++      .num_resources          = 2,
++      .resource               = nas100d_uart_resources,
++};
++
++static struct platform_device *nas100d_devices[] __initdata = {
++      &nas100d_i2c_controller,
++      &nas100d_flash,
++      &nas100d_uart,
++};
++
++static void nas100d_power_off(void)
++{
++      /* This causes the box to drop the power and go dead. */
++
++      /* enable the pwr cntl gpio */
++      gpio_line_config(NAS100D_PO_GPIO, IXP4XX_GPIO_OUT);
++
++      /* do the deed */
++      gpio_line_set(NAS100D_PO_GPIO, IXP4XX_GPIO_HIGH);
++}
++
++static void __init nas100d_init(void)
++{
++      ixp4xx_sys_init();
++
++      pm_power_off = nas100d_power_off;
++
++      platform_add_devices(nas100d_devices, ARRAY_SIZE(nas100d_devices));
++}
++
++MACHINE_START(NAS100D, "Iomega NAS 100d")
++      /* Maintainer: www.nslu2-linux.org */
++      .phys_ram       = PHYS_OFFSET,
++      .phys_io        = IXP4XX_PERIPHERAL_BASE_PHYS,
++      .io_pg_offst    = ((IXP4XX_PERIPHERAL_BASE_VIRT) >> 18) & 0xFFFC,
++      .boot_params    = 0x00000100,
++      .map_io         = ixp4xx_map_io,
++      .init_irq       = ixp4xx_init_irq,
++      .timer          = &ixp4xx_timer,
++      .init_machine   = nas100d_init,
++MACHINE_END
diff --git a/packages/linux/nas100d-kernel/2.6.15/55-nas100d-arch.patch b/packages/linux/nas100d-kernel/2.6.15/55-nas100d-arch.patch
deleted file mode 100644 (file)
index 4b40047..0000000
+++ /dev/null
@@ -1,395 +0,0 @@
- arch/arm/mach-ixp4xx/nas100d-pci.c    |   77 +++++++++++++++++++
- arch/arm/mach-ixp4xx/nas100d-power.c  |   92 +++++++++++++++++++++++
- arch/arm/mach-ixp4xx/nas100d-setup.c  |  132 ++++++++++++++++++++++++++++++++++
- drivers/ide/pci/aec62xx.c             |   11 ++
- include/asm-arm/arch-ixp4xx/nas100d.h |   75 +++++++++++++++++++
- 5 files changed, 387 insertions(+)
-
---- /dev/null  1970-01-01 00:00:00.000000000 +0000
-+++ linux-2.6.14/include/asm-arm/arch-ixp4xx/nas100d.h 2005-11-12 14:24:14.000000000 +0100
-@@ -0,0 +1,75 @@
-+/*
-+ * include/asm-arm/arch-ixp4xx/nas100d.h
-+ *
-+ * NAS100D platform specific definitions
-+ *
-+ * Copyright (c) 2005 Tower Technologies
-+ *
-+ * Author: Alessandro Zummo <a.zummo@towertech.it>
-+ *
-+ * based on ixdp425.h:
-+ *    Copyright 2004 (c) MontaVista, Software, Inc.
-+ *
-+ * This file is licensed under  the terms of the GNU General Public
-+ * License version 2. This program is licensed "as is" without any
-+ * warranty of any kind, whether express or implied.
-+ */
-+
-+#ifndef __ASM_ARCH_HARDWARE_H__
-+#error "Do not include this directly, instead #include <asm/hardware.h>"
-+#endif
-+
-+#define       NAS100D_FLASH_BASE      IXP4XX_EXP_BUS_CS0_BASE_PHYS
-+#define       NAS100D_FLASH_SIZE      IXP4XX_EXP_BUS_CSX_REGION_SIZE
-+
-+#define       NAS100D_SDA_PIN         6
-+#define       NAS100D_SCL_PIN         5
-+
-+/*
-+ * NAS100D PCI IRQs
-+ */
-+#define NAS100D_PCI_MAX_DEV   3
-+#define NAS100D_PCI_IRQ_LINES 3
-+
-+
-+/* PCI controller GPIO to IRQ pin mappings */
-+#define NAS100D_PCI_INTA_PIN  11
-+#define NAS100D_PCI_INTB_PIN  10
-+#define       NAS100D_PCI_INTC_PIN    9
-+#define       NAS100D_PCI_INTD_PIN    8
-+#define       NAS100D_PCI_INTE_PIN    7
-+
-+/* GPIO */
-+
-+#define NAS100D_GPIO0           0
-+#define NAS100D_GPIO1           1
-+#define NAS100D_GPIO2           2
-+#define NAS100D_GPIO3           3
-+#define NAS100D_GPIO4           4
-+#define NAS100D_GPIO5           5
-+#define NAS100D_GPIO6           6
-+#define NAS100D_GPIO7           7
-+#define NAS100D_GPIO8           8
-+#define NAS100D_GPIO9           9
-+#define NAS100D_GPIO10          10
-+#define NAS100D_GPIO11          11
-+#define NAS100D_GPIO12          12
-+#define NAS100D_GPIO13          13
-+#define NAS100D_GPIO14          14
-+#define NAS100D_GPIO15          15
-+
-+
-+/* Buttons */
-+
-+#define NAS100D_PB_GPIO         NAS100D_GPIO14
-+#define NAS100D_RB_GPIO         NAS100D_GPIO4
-+#define NAS100D_PO_GPIO         NAS100D_GPIO12   /* power off */
-+
-+#define NAS100D_PB_IRQ          IRQ_IXP4XX_GPIO14
-+#define NAS100D_RB_IRQ          IRQ_IXP4XX_GPIO4
-+
-+/*
-+#define NAS100D_PB_BM           (1L << NAS100D_PB_GPIO)
-+#define NAS100D_PO_BM           (1L << NAS100D_PO_GPIO)
-+#define NAS100D_RB_BM           (1L << NAS100D_RB_GPIO)
-+*/
---- /dev/null  1970-01-01 00:00:00.000000000 +0000
-+++ linux-2.6.14/arch/arm/mach-ixp4xx/nas100d-pci.c    2005-11-12 14:24:14.000000000 +0100
-@@ -0,0 +1,77 @@
-+/*
-+ * arch/arm/mach-ixp4xx/nas100d-pci.c
-+ *
-+ * NAS 100d board-level PCI initialization
-+ *
-+ * based on ixdp425-pci.c:
-+ *    Copyright (C) 2002 Intel Corporation.
-+ *    Copyright (C) 2003-2004 MontaVista Software, Inc.
-+ *
-+ * Maintainer: http://www.nslu2-linux.org/
-+ *
-+ * 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/config.h>
-+#include <linux/pci.h>
-+#include <linux/init.h>
-+
-+#include <asm/mach/pci.h>
-+#include <asm/mach-types.h>
-+
-+void __init nas100d_pci_preinit(void)
-+{
-+      set_irq_type(IRQ_NAS100D_PCI_INTA, IRQT_LOW);
-+      set_irq_type(IRQ_NAS100D_PCI_INTB, IRQT_LOW);
-+      set_irq_type(IRQ_NAS100D_PCI_INTC, IRQT_LOW);
-+      set_irq_type(IRQ_NAS100D_PCI_INTD, IRQT_LOW);
-+      set_irq_type(IRQ_NAS100D_PCI_INTE, IRQT_LOW);
-+
-+      gpio_line_isr_clear(NAS100D_PCI_INTA_PIN);
-+      gpio_line_isr_clear(NAS100D_PCI_INTB_PIN);
-+      gpio_line_isr_clear(NAS100D_PCI_INTC_PIN);
-+      gpio_line_isr_clear(NAS100D_PCI_INTD_PIN);
-+      gpio_line_isr_clear(NAS100D_PCI_INTE_PIN);
-+
-+      ixp4xx_pci_preinit();
-+}
-+
-+static int __init nas100d_map_irq(struct pci_dev *dev, u8 slot, u8 pin)
-+{
-+      static int pci_irq_table[NAS100D_PCI_MAX_DEV][NAS100D_PCI_IRQ_LINES] =
-+      {
-+              { IRQ_NAS100D_PCI_INTA, -1, -1 },
-+              { IRQ_NAS100D_PCI_INTB, -1, -1 },
-+              { IRQ_NAS100D_PCI_INTC, IRQ_NAS100D_PCI_INTD, IRQ_NAS100D_PCI_INTE },
-+      };
-+
-+      int irq = -1;
-+
-+      if (slot >= 1 && slot <= NAS100D_PCI_MAX_DEV &&
-+              pin >= 1 && pin <= NAS100D_PCI_IRQ_LINES)
-+              irq = pci_irq_table[slot-1][pin-1];
-+
-+      return irq;
-+}
-+
-+struct hw_pci __initdata nas100d_pci = {
-+      .nr_controllers = 1,
-+      .preinit        = nas100d_pci_preinit,
-+      .swizzle        = pci_std_swizzle,
-+      .setup          = ixp4xx_setup,
-+      .scan           = ixp4xx_scan_bus,
-+      .map_irq        = nas100d_map_irq,
-+};
-+
-+int __init nas100d_pci_init(void)
-+{
-+      if (machine_is_nas100d())
-+              pci_common_init(&nas100d_pci);
-+
-+      return 0;
-+}
-+
-+subsys_initcall(nas100d_pci_init);
---- /dev/null  1970-01-01 00:00:00.000000000 +0000
-+++ linux-2.6.14/arch/arm/mach-ixp4xx/nas100d-power.c  2005-11-12 14:24:14.000000000 +0100
-@@ -0,0 +1,92 @@
-+/*
-+ * arch/arm/mach-ixp4xx/nas100d-power.c
-+ *
-+ * NAS 100d Power/Reset driver
-+ *
-+ * Copyright (C) 2005 Tower Technologies
-+ *
-+ * based on nas100d-io.c
-+ *  Copyright (C) 2004 Karen Spearel
-+ *
-+ * Author: Alessandro Zummo <a.zummo@towertech.it>
-+ * Maintainers: http://www.nslu2-linux.org/
-+ *
-+ * 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/module.h>
-+#include <linux/reboot.h>
-+#include <linux/interrupt.h>
-+
-+#include <asm/mach-types.h>
-+
-+extern void ctrl_alt_del(void);
-+
-+static irqreturn_t nas100d_power_handler(int irq, void *dev_id, struct pt_regs *regs)
-+{
-+      /* Signal init to do the ctrlaltdel action, this will bypass init if
-+       * it hasn't started and do a kernel_restart.
-+       */
-+      ctrl_alt_del();
-+
-+      return IRQ_HANDLED;
-+}
-+
-+static irqreturn_t nas100d_reset_handler(int irq, void *dev_id, struct pt_regs *regs)
-+{
-+      /* This is the paper-clip reset, it shuts the machine down directly.
-+       */
-+      machine_power_off();
-+
-+      return IRQ_HANDLED;
-+}
-+
-+static int __init nas100d_power_init(void)
-+{
-+      if (!(machine_is_nas100d()))
-+              return 0;
-+
-+      // *IXP4XX_GPIO_GPISR = 0x20400000;     /* read the 2 irqs to clr */
-+
-+      set_irq_type(NAS100D_RB_IRQ, IRQT_LOW);
-+//    set_irq_type(NAS100D_PB_IRQ, IRQT_HIGH);
-+
-+      gpio_line_isr_clear(NAS100D_RB_GPIO);
-+//    gpio_line_isr_clear(NAS100D_PB_GPIO);
-+
-+      if (request_irq(NAS100D_RB_IRQ, &nas100d_reset_handler,
-+              SA_INTERRUPT, "NAS100D reset button", NULL) < 0) {
-+
-+              printk(KERN_DEBUG "Reset Button IRQ %d not available\n",
-+                      NAS100D_RB_IRQ);
-+
-+              return -EIO;
-+      }
-+/*
-+      if (request_irq(NAS100D_PB_IRQ, &nas100d_power_handler,
-+              SA_INTERRUPT, "NAS100D power button", NULL) < 0) {
-+
-+              printk(KERN_DEBUG "Power Button IRQ %d not available\n",
-+                      NAS100D_PB_IRQ);
-+
-+              return -EIO;
-+      }
-+*/
-+      return 0;
-+}
-+
-+static void __exit nas100d_power_exit(void)
-+{
-+      free_irq(NAS100D_RB_IRQ, NULL);
-+//    free_irq(NAS100D_PB_IRQ, NULL);
-+}
-+
-+module_init(nas100d_power_init);
-+module_exit(nas100d_power_exit);
-+
-+MODULE_AUTHOR("Alessandro Zummo <a.zummo@towertech.it>");
-+MODULE_DESCRIPTION("NAS100D Power/Reset driver");
-+MODULE_LICENSE("GPL");
---- /dev/null  1970-01-01 00:00:00.000000000 +0000
-+++ linux-2.6.14/arch/arm/mach-ixp4xx/nas100d-setup.c  2005-11-12 14:24:14.000000000 +0100
-@@ -0,0 +1,132 @@
-+/*
-+ * arch/arm/mach-ixp4xx/nas100d-setup.c
-+ *
-+ * NAS 100d board-setup
-+ *
-+ * based ixdp425-setup.c:
-+ *      Copyright (C) 2003-2004 MontaVista Software, Inc.
-+ *
-+ * Author: Mark Rakes <mrakes at mac.com>
-+ * Maintainers: http://www.nslu2-linux.org/
-+ *
-+ */
-+
-+#include <linux/kernel.h>
-+#include <linux/serial.h>
-+#include <linux/serial_8250.h>
-+
-+#include <asm/mach-types.h>
-+#include <asm/mach/arch.h>
-+#include <asm/mach/flash.h>
-+
-+static struct flash_platform_data nas100d_flash_data = {
-+      .map_name               = "cfi_probe",
-+      .width                  = 2,
-+};
-+
-+static struct resource nas100d_flash_resource = {
-+      .start                  = NAS100D_FLASH_BASE,
-+      .end                    = NAS100D_FLASH_BASE + NAS100D_FLASH_SIZE,
-+      .flags                  = IORESOURCE_MEM,
-+};
-+
-+static struct platform_device nas100d_flash = {
-+      .name                   = "IXP4XX-Flash",
-+      .id                     = 0,
-+      .dev.platform_data      = &nas100d_flash_data,
-+      .num_resources          = 1,
-+      .resource               = &nas100d_flash_resource,
-+};
-+
-+static struct ixp4xx_i2c_pins nas100d_i2c_gpio_pins = {
-+      .sda_pin                = NAS100D_SDA_PIN,
-+      .scl_pin                = NAS100D_SCL_PIN,
-+};
-+
-+static struct platform_device nas100d_i2c_controller = {
-+      .name                   = "IXP4XX-I2C",
-+      .id                     = 0,
-+      .dev.platform_data      = &nas100d_i2c_gpio_pins,
-+      .num_resources          = 0,
-+};
-+
-+static struct resource nas100d_uart_resources[] = {
-+      {
-+              .start          = IXP4XX_UART1_BASE_PHYS,
-+              .end            = IXP4XX_UART1_BASE_PHYS + 0x0fff,
-+              .flags          = IORESOURCE_MEM,
-+      },
-+      {
-+              .start          = IXP4XX_UART2_BASE_PHYS,
-+              .end            = IXP4XX_UART2_BASE_PHYS + 0x0fff,
-+              .flags          = IORESOURCE_MEM,
-+      }
-+};
-+
-+static struct plat_serial8250_port nas100d_uart_data[] = {
-+      {
-+              .mapbase        = IXP4XX_UART1_BASE_PHYS,
-+              .membase        = (char *)IXP4XX_UART1_BASE_VIRT + REG_OFFSET,
-+              .irq            = IRQ_IXP4XX_UART1,
-+              .flags          = UPF_BOOT_AUTOCONF,
-+              .iotype         = UPIO_MEM,
-+              .regshift       = 2,
-+              .uartclk        = IXP4XX_UART_XTAL,
-+      },
-+      {
-+              .mapbase        = IXP4XX_UART2_BASE_PHYS,
-+              .membase        = (char *)IXP4XX_UART2_BASE_VIRT + REG_OFFSET,
-+              .irq            = IRQ_IXP4XX_UART2,
-+              .flags          = UPF_BOOT_AUTOCONF,
-+              .iotype         = UPIO_MEM,
-+              .regshift       = 2,
-+              .uartclk        = IXP4XX_UART_XTAL,
-+      },
-+      { }
-+};
-+
-+static struct platform_device nas100d_uart = {
-+      .name                   = "serial8250",
-+      .id                     = PLAT8250_DEV_PLATFORM,
-+      .dev.platform_data      = nas100d_uart_data,
-+      .num_resources          = 2,
-+      .resource               = nas100d_uart_resources,
-+};
-+
-+static struct platform_device *nas100d_devices[] __initdata = {
-+      &nas100d_i2c_controller,
-+      &nas100d_flash,
-+      &nas100d_uart,
-+};
-+
-+static void nas100d_power_off(void)
-+{
-+      /* This causes the box to drop the power and go dead. */
-+
-+      /* enable the pwr cntl gpio */
-+      gpio_line_config(NAS100D_PO_GPIO, IXP4XX_GPIO_OUT);
-+
-+      /* do the deed */
-+      gpio_line_set(NAS100D_PO_GPIO, IXP4XX_GPIO_HIGH);
-+}
-+
-+static void __init nas100d_init(void)
-+{
-+      ixp4xx_sys_init();
-+
-+      pm_power_off = nas100d_power_off;
-+
-+      platform_add_devices(nas100d_devices, ARRAY_SIZE(nas100d_devices));
-+}
-+
-+MACHINE_START(NAS100D, "Iomega NAS 100d")
-+      /* Maintainer: www.nslu2-linux.org */
-+      .phys_ram       = PHYS_OFFSET,
-+      .phys_io        = IXP4XX_PERIPHERAL_BASE_PHYS,
-+      .io_pg_offst    = ((IXP4XX_PERIPHERAL_BASE_VIRT) >> 18) & 0xFFFC,
-+      .boot_params    = 0x00000100,
-+      .map_io         = ixp4xx_map_io,
-+      .init_irq       = ixp4xx_init_irq,
-+      .timer          = &ixp4xx_timer,
-+      .init_machine   = nas100d_init,
-+MACHINE_END
diff --git a/packages/linux/nas100d-kernel/2.6.15/85-timer.patch b/packages/linux/nas100d-kernel/2.6.15/85-timer.patch
new file mode 100644 (file)
index 0000000..e83120c
--- /dev/null
@@ -0,0 +1,246 @@
+--- linux-2.6.15/arch/arm/mach-ixp4xx/common.c 1970-01-01 00:00:00.000000000 +0000
++++ linux-2.6.15/arch/arm/mach-ixp4xx/common.c 1970-01-01 00:00:00.000000000 +0000
+@@ -239,36 +239,165 @@ void __init ixp4xx_init_irq(void)
+  * IXP4xx timer tick
+  * We use OS timer1 on the CPU for the timer tick and the timestamp 
+  * counter as a source of real clock ticks to account for missed jiffies.
++ *
++ * 'CLOCK_TICK_RATE' is the nominal number of internal ticks per second,
++ * this is significantly greater than the actual number on any ixp4xx
++ * board.  Neither this nor 'LATCH' are required by this code because
++ * the only requirement is to generate HZ timer_tick calls per second.
+  *************************************************************************/
++#if TICK_NSEC * HZ != 1000000000
++      /* This will cause the jiffies to drift unnecessarily. */
++#     error CLOCK_TICK_RATE should be a multiple of HZ for this code
++#endif
++
++/* These are the control registers for the interrupt handler, they must
++ * only be read and written by the interrupt handler and by the init
++ * method (which sets them to 0).
++ */
++static volatile u32 last_timer_time;
++static volatile int accumulated_error;
++
++/* Most ixp4xx boards have 66.6666MHz crystals, so default to this, reset
++ * this from the board level code if required.  The following variables
++ * must be *written* only by set_board_tick_rate
++ */
++static u32 board_tick_rate;
++static u32 board_tick_per_1000; /* board_tick_rate/1000 */
++static u32 timer_count;
++
++/* The following symbol may be written to change the current tick rate,
++ * it is read by the interrupt handler and used to reload the timer.
++ * The 'real' value (the one in use) is 'board_tick_rate' above.
++ * NOTE: this can be tweaked to match the actual crystal on a particular
++ * machine.
++ */
++volatile u32 ixp4xx_board_tick_rate = 66666600;
++EXPORT_SYMBOL(ixp4xx_board_tick_rate);
++
++/* The set API may run asynchronously in the presence of interrupts,
++ * everything it does it is both atomic and complete (notice that it
++ * doesn't change any of the 'volatile' values).  The mathematics in
++ * here require the following values.  Changing the board tick rate
++ * implies an unknown error in the current timestamp tick count.
++ */
++#if IXP4XX_OST_RELOAD_MASK != 3 || IXP4XX_OST_ENABLE != 1
++#     error unexpected value for timer reload mask
++#endif
++static void set_board_tick_rate(u32 rate) {
++      u32 reload;
++
++      /* Store the two effectively informational rate values, the
++       * error calculation is (rate - count*HZ) (above), and rate
++       * is changed first, this can cause a temporary error which
++       * will be corrected on the next interrupt.
++       */
++      board_tick_rate = rate;
++      board_tick_per_1000 = (rate+500)/1000;
++
++      /* Calculate the correct value to load into the timer countdown
++       * register, the low two bits must be b01 (to enable the timer).
++       * Select the top bits to be as close to the desired value as
++       * possible.
++       *
++       * First find the best value, regardless of the low two bits -
++       * this is the value used in the interrupt calculation even though
++       * it cannot necessarily be set into the register.
++       */
++      timer_count = (rate + (HZ/2))/HZ;
++
++      /* Now the timer_ticks are being generated at this rate, calculate
++       * an appropriate value for the register.  This stores a 30 bit
++       * value which gives a period of 4*x+1, we want:
++       *
++       *   4*x+1 = board_tick_rate/HZ
++       *
++       * This needs to be rounded to the closest 4*HZ value:
++       * 
++       *   x = ((board_tick_rate-HZ) + (4*HZ)/2) / 4*HZ
++       *   x = (board_tick_rate+HZ) / (4*HZ);
++       */
++      reload = (board_tick_rate + HZ) / HZ;
++      reload = (reload & ~IXP4XX_OST_RELOAD_MASK) | IXP4XX_OST_ENABLE;
++      *IXP4XX_OSRT1 = reload;
+-static unsigned volatile last_jiffy_time;
++      /* If the clock is drifing, look in syslog: */
++      printk(KERN_INFO "IXP4xx: FREQ=%d COUNT=%d\n", rate, reload);
++}
+-#define CLOCK_TICKS_PER_USEC  ((CLOCK_TICK_RATE + USEC_PER_SEC/2) / USEC_PER_SEC)
++/* This returns the time in timer ticks since the 'last_timer_time'
++ * recorded above.  Use this to avoid arithmetic errors because of
++ * the overflow when the timer wraps.
++ */
++static inline u32 ixp4xx_timer_delta(void)
++{
++      return *IXP4XX_OSTS - last_timer_time;
++}
+ /* IRQs are disabled before entering here from do_gettimeofday() */
+ static unsigned long ixp4xx_gettimeoffset(void)
+ {
+-      u32 elapsed;
+-
+-      elapsed = *IXP4XX_OSTS - last_jiffy_time;
++      /* Return the offset of the current time from the last time
++       * timer tick in microseconds.  This is only used for the
++       * gettimeofday call.
++       *
++       * The result of this API is at most about 20000 (for a 50Hz
++       * HZ - 20000 uS/tick), the input delta is at most about
++       * 1.3M - 21 bits.
++       */
++      u32 delta = ixp4xx_timer_delta(); /* About 21 bits max */
++      /* return delta * 1000000 / board_tick_rate; */
++      return (delta * 1000 + board_tick_per_1000/2) / board_tick_per_1000;
++}
+-      return elapsed / CLOCK_TICKS_PER_USEC;
++/* This is the correct adjustment to the counter to compensate for an
++ * error iff timer_count-1 <= exact_count <= timer_count+1
++ */
++static inline int adjustment(int error) {
++      if (error >= HZ)
++              return 1;
++      else if (error <= -HZ)
++              return -1;
++      return 0;
+ }
+ static irqreturn_t ixp4xx_timer_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+ {
++      u32 rate;
++      u32 count;
++      int error;
++
+       write_seqlock(&xtime_lock);
+       /* Clear Pending Interrupt by writing '1' to it */
+       *IXP4XX_OSST = IXP4XX_OSST_TIMER_1_PEND;
++      /* If the board tick rate has been changed update the cached
++       * value.
++       */
++      if (ixp4xx_board_tick_rate != board_tick_rate) {
++              set_board_tick_rate(ixp4xx_board_tick_rate);
++              accumulated_error = 0;
++      }
++
+       /*
+        * Catch up with the real idea of time
++       *
++       * board_tick_rate: actual ixp4xx ticks/second, read-only
++       * accumulated_error: aggregate error/tick * HZ, read/write
++       * timer_count: best ixp4xx ticks per timer_tick, read-only
+        */
+-      while ((*IXP4XX_OSTS - last_jiffy_time) > LATCH) {
++      rate = board_tick_rate;
++      error = accumulated_error;
++      count = timer_count;
++      do {
++              u32 adjusted_count = count + adjustment(error);
++              if (ixp4xx_timer_delta() < adjusted_count)
++                      break;
+               timer_tick(regs);
+-              last_jiffy_time += LATCH;
+-      }
++              last_timer_time += adjusted_count;
++              error += rate - adjusted_count*HZ;
++      } while (1);
++      accumulated_error = error;
+       write_sequnlock(&xtime_lock);
+@@ -281,17 +410,30 @@ static struct irqaction ixp4xx_timer_irq
+       .handler        = ixp4xx_timer_interrupt,
+ };
++u32 ixp4xx_get_board_tick_rate(void) {
++      return board_tick_rate;
++}
++
++EXPORT_SYMBOL(ixp4xx_get_board_tick_rate);
++
++void ixp4xx_set_board_tick_rate(u32 rate) {
++      ixp4xx_board_tick_rate = rate;
++}
++
++EXPORT_SYMBOL(ixp4xx_set_board_tick_rate);
++
+ static void __init ixp4xx_timer_init(void)
+ {
+       /* Clear Pending Interrupt by writing '1' to it */
+       *IXP4XX_OSST = IXP4XX_OSST_TIMER_1_PEND;
+       /* Setup the Timer counter value */
+-      *IXP4XX_OSRT1 = (LATCH & ~IXP4XX_OST_RELOAD_MASK) | IXP4XX_OST_ENABLE;
++      set_board_tick_rate(ixp4xx_board_tick_rate);
+       /* Reset time-stamp counter */
+       *IXP4XX_OSTS = 0;
+-      last_jiffy_time = 0;
++      last_timer_time = 0;
++      accumulated_error = 0;
+       /* Connect the interrupt handler and enable the interrupt */
+       setup_irq(IRQ_IXP4XX_TIMER1, &ixp4xx_timer_irq);
+@@ -337,4 +479,3 @@ void __init ixp4xx_sys_init(void)
+                               ARRAY_SIZE(ixp46x_devices));
+       }
+ }
+-
+--- linux-2.6.15/include/asm-arm/arch-ixp4xx/timex.h   1970-01-01 00:00:00.000000000 +0000
++++ linux-2.6.15/include/asm-arm/arch-ixp4xx/timex.h   1970-01-01 00:00:00.000000000 +0000
+@@ -6,10 +6,23 @@
+ #include <asm/hardware.h>
+ /*
+- * We use IXP425 General purpose timer for our timer needs, it runs at 
+- * 66.66... MHz. We do a convulted calculation of CLOCK_TICK_RATE b/c the
+- * timer register ignores the bottom 2 bits of the LATCH value.
++ * In linux/timex.h 'LATCH' is defined as CLOCK_TICK_RATE/HZ and
++ * is the number of internal counts per timer interrupt.  Thus
++ * CLOCK_TICK_RATE is LATCH*HZ.
++ *
++ * The actual values of these numbers do not matter, because they
++ * are only used to calculate ACTHZ (rate/latch as a 24.8 fixed
++ * point number), so the value here gives a LATCH of 1 and pretty
++ * much guarantees to flush out any off-by-one errors.
++ *
++ * ACTHZ is equal to HZ, because CLOCK_TICK_RATE is a multiple of
++ * HZ, this is checked in the ixp4xx/common.c code.
+  */
+-#define FREQ 66666666
+-#define CLOCK_TICK_RATE (((FREQ / HZ & ~IXP4XX_OST_RELOAD_MASK) + 1) * HZ)
++#define CLOCK_TICK_RATE HZ
++/* The following allow the exact board tick rate to be set and
++ * discovered.  The value should be exactly twice the frequency
++ * (in Hz) of the onboard crystal.
++ */
++extern u32 ixp4xx_get_board_tick_rate(void);
++extern void ixp4xx_set_board_tick_rate(u32 new_rate);
diff --git a/packages/linux/nas100d-kernel/2.6.15/90-ixp4xx-nslu2.patch b/packages/linux/nas100d-kernel/2.6.15/90-ixp4xx-nslu2.patch
deleted file mode 100644 (file)
index c106f7c..0000000
+++ /dev/null
@@ -1,132 +0,0 @@
-ixp4xx updates:
-  - Handle reads that don't start on a half-word boundary.
-  - Make it work when CPU is in little-endian mode.
-    
-Signed-off-by: John Bowler <jbowler@acm.org>
-Signed-off-by: Alessandro Zummo <a.zummo@towertech.it>
-Signed-off-by: David Vrabel <dvrabel@arcom.com>
-
-Index: linux-2.6-working/drivers/mtd/maps/ixp4xx.c
-===================================================================
---- linux-2.6-working.orig/drivers/mtd/maps/ixp4xx.c   2005-11-16 15:19:34.000000000 +0000
-+++ linux-2.6-working/drivers/mtd/maps/ixp4xx.c        2005-11-16 16:06:54.000000000 +0000
-@@ -34,10 +34,55 @@
- #include <linux/reboot.h>
-+/*
-+ * Read/write a 16 bit word from flash address 'addr'.
-+ *
-+ * When the cpu is in little-endian mode it swizzles the address lines
-+ * ('address coherency') so we need to undo the swizzling to ensure commands
-+ * and the like end up on the correct flash address.
-+ *
-+ * To further complicate matters, due to the way the expansion bus controller
-+ * handles 32 bit reads, the byte stream ABCD is stored on the flash as:
-+ *     D15    D0
-+ *     +---+---+
-+ *     | A | B | 0
-+ *     +---+---+
-+ *     | C | D | 2
-+ *     +---+---+
-+ * This means that on LE systems each 16 bit word must be swapped. Note that
-+ * this requires CONFIG_MTD_CFI_BE_BYTE_SWAP to be enabled to 'unswap' the CFI
-+ * data and other flash commands which are always in D7-D0.
-+ */
- #ifndef __ARMEB__
-+#ifndef CONFIG_MTD_CFI_BE_BYTE_SWAP
-+#  error CONFIG_MTD_CFI_BE_BYTE_SWAP required
-+#endif
-+
-+static inline u16 flash_read16(void __iomem *addr)
-+{
-+      return be16_to_cpu(__raw_readw((void __iomem *)((unsigned long)addr ^ 0x2)));
-+}
-+
-+static inline void flash_write16(u16 d, void __iomem *addr)
-+{
-+      __raw_writew(cpu_to_be16(d), (void __iomem *)((unsigned long)addr ^ 0x2));
-+}
-+
- #define       BYTE0(h)        ((h) & 0xFF)
- #define       BYTE1(h)        (((h) >> 8) & 0xFF)
-+
- #else
-+
-+static inline u16 flash_read16(const void __iomem *addr)
-+{
-+      return __raw_readw(addr);
-+}
-+
-+static inline void flash_write16(u16 d, void __iomem *addr)
-+{
-+      __raw_writew(d, addr);
-+}
-+
- #define       BYTE0(h)        (((h) >> 8) & 0xFF)
- #define       BYTE1(h)        ((h) & 0xFF)
- #endif
-@@ -45,7 +90,7 @@
- static map_word ixp4xx_read16(struct map_info *map, unsigned long ofs)
- {
-       map_word val;
--      val.x[0] = le16_to_cpu(readw(map->virt + ofs));
-+      val.x[0] = flash_read16(map->virt + ofs);
-       return val;
- }
-@@ -57,19 +102,28 @@
- static void ixp4xx_copy_from(struct map_info *map, void *to,
-                            unsigned long from, ssize_t len)
- {
--      int i;
-       u8 *dest = (u8 *) to;
-       void __iomem *src = map->virt + from;
--      u16 data;
--      for (i = 0; i < (len / 2); i++) {
--              data = le16_to_cpu(readw(src + 2*i));
--              dest[i * 2] = BYTE0(data);
--              dest[i * 2 + 1] = BYTE1(data);
-+      if (len <= 0)
-+              return;
-+
-+      if (from & 1) {
-+              *dest++ = BYTE1(flash_read16(src));
-+                src++;
-+              --len;
-       }
--      if (len & 1)
--              dest[len - 1] = BYTE0(le16_to_cpu(readw(src + 2*i)));
-+      while (len >= 2) {
-+              u16 data = flash_read16(src);
-+              *dest++ = BYTE0(data);
-+              *dest++ = BYTE1(data);
-+              src += 2;
-+              len -= 2;
-+        }
-+
-+      if (len > 0)
-+              *dest++ = BYTE0(flash_read16(src));
- }
- /*
-@@ -79,7 +133,7 @@
- static void ixp4xx_probe_write16(struct map_info *map, map_word d, unsigned long adr)
- {
-       if (!(adr & 1))
--              writew(cpu_to_le16(d.x[0]), map->virt + adr);
-+              flash_write16(d.x[0], map->virt + adr);
- }
- /*
-@@ -87,7 +141,7 @@
-  */
- static void ixp4xx_write16(struct map_info *map, map_word d, unsigned long adr)
- {
--      writew(cpu_to_le16(d.x[0]), map->virt + adr);
-+      flash_write16(d.x[0], map->virt + adr);
- }
- struct ixp4xx_flash_info {
diff --git a/packages/linux/nas100d-kernel/2.6.15/91-maclist.patch b/packages/linux/nas100d-kernel/2.6.15/91-maclist.patch
new file mode 100644 (file)
index 0000000..27af1ea
--- /dev/null
@@ -0,0 +1,377 @@
+--- linux-2.6.15/include/net/maclist.h 1970-01-01 00:00:00.000000000 +0000
++++ linux-2.6.15/include/net/maclist.h 1970-01-01 00:00:00.000000000 +0000
+@@ -0,0 +1,23 @@
++#ifndef _MACLIST_H
++#define _MACLIST_H 1
++/*
++ * Interfaces to the MAC repository
++ */
++/*
++ * Add a single entry, returns 0 on success else an error
++ * code.  Must *not* be called from an interrupt handler.
++ */
++extern int maclist_add(const u8 id_to_add[6]);
++
++/*
++ * Return the current entry count (valid in any context).
++ */
++extern int maclist_count(void);
++
++/*
++ * Return the ID from the n'th entry (valid in any context),
++ * returns 0 on success, -EINVAL if 'n' is out of range.
++ */
++extern int maclist_read(u8 (*buffer_for_id)[6], int index_of_id_to_return);
++
++#endif /*_MACLIST_H*/
+--- linux-2.6.15/drivers/net/maclist.c 1970-01-01 00:00:00.000000000 +0000
++++ linux-2.6.15/drivers/net/maclist.c 1970-01-01 00:00:00.000000000 +0000
+@@ -0,0 +1,314 @@
++/*
++ * drivers/net/maclist.c
++ *
++ * a simple driver to remember ethernet MAC values
++ *
++ * Some Ethernet hardware implementations have no built-in
++ * storage for allocated MAC values - an example is the Intel
++ * IXP420 chip which has support for Ethernet but no defined
++ * way of storing allocated MAC values.  With such hardware
++ * different board level implementations store the allocated
++ * MAC (or MACs) in different ways.  Rather than put board
++ * level code into a specific Ethernet driver this driver
++ * provides a generally accessible repository for the MACs
++ * which can be written by board level code and read by the
++ * driver.
++ *
++ * The implementation also allows user level programs to
++ * access the MAC information in /proc/net/maclist.  This is
++ * useful as it allows user space code to use the MAC if it
++ * is not used by a built-in driver.
++ *
++ * Copyright (C) 2005 John Bowler
++ * Author: John Bowler <jbowler@acm.org>
++ * Maintainers: http://www.nslu2-linux.org/
++ *
++ * 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.
++ *
++ * External interfaces:
++ *  Interfaces to linux kernel (and modules)
++ *   maclist_add:   add a single MAC
++ *   maclist_count: total number of MACs stored
++ *   maclist_read:  read a MAC 0..(maclist_count-1)
++ */
++#include <linux/module.h>
++#include <linux/moduleparam.h>
++#include <linux/etherdevice.h>
++#include <linux/proc_fs.h>
++#include <linux/errno.h>
++
++#include <net/maclist.h>
++
++#define MACLIST_NAME "maclist"
++
++MODULE_AUTHOR("John Bowler <jbowler@acm.org>");
++MODULE_DESCRIPTION("MAC list repository");
++MODULE_LICENSE("GPL");
++
++typedef struct maclist_entry {
++      struct maclist_entry *next;  /* Linked list, first first */
++      u8                    id[6]; /* 6 byte Ethernet MAC */
++} maclist_entry_t;
++
++/* Access to this list is possible at any time - entries in
++ * the list are never destroyed.  Modification of the list is
++ * safe only from the init code (i.e. modification must be
++ * single threaded), but read from an interrupt at the same
++ * time is possible and safe.
++ */
++static maclist_entry_t *maclist_list = 0;
++
++/*
++ * External interfaces.
++ *
++ * Add a single entry, returns 0 on success else an error
++ * code.  Must be single threaded.
++ */
++int maclist_add(const u8 new_id[6]) {
++      maclist_entry_t *new_entry, **tail;
++
++      if (new_id == 0 || !is_valid_ether_addr(new_id)) {
++              printk(KERN_ERR MACLIST_NAME ": invalid ethernet address\n");
++              return -EINVAL;
++      }
++      new_entry = kmalloc(sizeof *new_entry, GFP_KERNEL);
++      if (new_entry == 0)
++              return -ENOMEM;
++      new_entry->next = 0;
++      memcpy(new_entry->id, new_id, sizeof new_entry->id);
++
++      tail = &maclist_list;
++      while (*tail != 0)
++              tail = &(*tail)->next;
++      *tail = new_entry;
++      return 0;
++}
++EXPORT_SYMBOL(maclist_add);
++
++/*
++ * Return the current entry count (valid in any context).
++ */
++int maclist_count(void) {
++      maclist_entry_t *tail = maclist_list;
++      int count = 0;
++
++      while (tail != 0) {
++              tail = tail->next;
++              ++count;
++      }
++
++      return count;
++}
++EXPORT_SYMBOL(maclist_count);
++
++/*
++ * Return the ID from the n'th entry (valid in any context),
++ * returns 0 on success, -EINVAL if 'n' is out of range.
++ */
++int maclist_read(u8 (*id)[6], int n) {
++      maclist_entry_t *entry = maclist_list;
++
++      while (n > 0 && entry != 0) {
++              --n;
++              entry = entry->next;
++      }
++
++      if (n == 0 && entry != 0) {
++              memcpy(id, entry->id, sizeof *id);
++              return 0;
++      }
++
++      printk(KERN_ERR MACLIST_NAME ": id does not exist\n");
++      return -EINVAL;
++}
++EXPORT_SYMBOL(maclist_read);
++
++/*
++ * Parameter parsing.  The option string is a list of MAC
++ * addresses, comma separated.  (The parsing really should
++ * be somewhere central...)
++ */
++static int __init maclist_setup(char *param) {
++      int bytes = 0, seen_a_digit = 0;
++      u8 id[6];
++
++      memset(id, 0, sizeof id);
++
++      if (param) do {
++              int digit = -1;
++              switch (*param) {
++              case '0': digit = 0; break;
++              case '1': digit = 1; break;
++              case '2': digit = 2; break;
++              case '3': digit = 3; break;
++              case '4': digit = 4; break;
++              case '5': digit = 5; break;
++              case '6': digit = 6; break;
++              case '7': digit = 7; break;
++              case '8': digit = 8; break;
++              case '9': digit = 9; break;
++              case 'a': case 'A': digit = 10; break;
++              case 'b': case 'B': digit = 11; break;
++              case 'c': case 'C': digit = 12; break;
++              case 'd': case 'D': digit = 13; break;
++              case 'e': case 'E': digit = 14; break;
++              case 'f': case 'F': digit = 15; break;
++              case ':':
++                      if (seen_a_digit)
++                              bytes = (bytes+1) & ~1;
++                      else
++                              bytes += 2; /* i.e. ff::ff is ff:00:ff */
++                      seen_a_digit = 0;
++                      break;
++              case 0:
++                      if (bytes == 0) /* nothing new seen so far */
++                              return 0;
++                      /*fall through*/
++              case ',': case ';':
++                      if (bytes > 0)
++                              bytes = 12; /* i.e. all trailing bytes 0 */
++                      break;
++              default:
++                      printk(KERN_ERR MACLIST_NAME ": invalid character <%c[%d]>\n",
++                                      *param, *param);
++                      return -EINVAL;
++              }
++
++              if (digit >= 0) {
++                      id[bytes>>1] = (id[bytes>>1] << 4) + digit; break;
++                      ++bytes;
++                      seen_a_digit = 1;
++              }
++
++              if (bytes >= 12) {
++                      int rc = maclist_add(id);
++                      if (rc)
++                              return rc;
++                      bytes = 0;
++                      seen_a_digit = 0;
++                      memset(id, 0, sizeof id);
++                      if (*param == 0)
++                              return 0;
++              }
++              ++param;
++      } while (1);
++
++      return 0;
++}
++
++/*
++ * procfs support, if compiled in.
++ */
++#ifdef CONFIG_PROC_FS
++/*
++ * Character device read
++ */
++static int maclist_getchar(off_t n) {
++      static char xdigit[16] = "0123456789abcdef";
++      maclist_entry_t *head = maclist_list;
++      int b;
++
++      do {
++              if (head == 0)
++                      return -1;
++              if (n < 18)
++                      break;
++              head = head->next;
++              n -= 18;
++      } while (1);
++
++      if (n == 17)
++              return '\n';
++
++      b = n/3;
++      switch (n - b*3) {
++      case 0: return xdigit[head->id[b] >> 4];
++      case 1: return xdigit[head->id[b] & 0xf];
++      default: return ':';
++      }
++}
++
++/*
++ * The extensively undocumented proc_read_t callback is implemented here.
++ * Go look in fs/proc/generic.c:
++ *
++ * Prototype:
++ *    int f(char *buffer, char **start, off_t offset,
++ *          int count, int *peof, void *dat)
++ *
++ * Assume that the buffer is "count" bytes in size.
++ *
++ * 2) Set *start = an address within the buffer.
++ *    Put the data of the requested offset at *start.
++ *    Return the number of bytes of data placed there.
++ *    If this number is greater than zero and you
++ *    didn't signal eof and the reader is prepared to
++ *    take more data you will be called again with the
++ *    requested offset advanced by the number of bytes
++ *    absorbed.
++ */
++static int maclist_proc_read(char *buffer, char **start, off_t offset,
++              int count, int *peof, void *dat) {
++      int total;
++
++      *start = buffer;
++      total = 0;
++
++      while (total < count) {
++              int ch = maclist_getchar(offset++);
++              if (ch == -1) {
++                      *peof = 1;
++                      break;
++              }
++              *buffer++ = ch;
++              ++total;
++      }
++
++      return total;
++}
++#endif
++
++/*
++ * Finally, the init/exit functions.
++ */
++static void __exit maclist_exit(void)
++{
++      maclist_entry_t *list;
++
++      remove_proc_entry(MACLIST_NAME, proc_net);
++
++      list = maclist_list;
++      maclist_list = 0;
++
++      while (list != 0) {
++              maclist_entry_t *head = list;
++              list = head->next;
++              kfree(head);
++      }
++}
++
++#ifdef MODULE
++static char ids[256];
++module_param_string(ids, ids, sizeof ids, 0);
++MODULE_PARM_DESC(ids, "comma separated list of MAC ids\n");
++#else
++__setup("maclist_ids=", maclist_setup);
++#endif
++
++static int __init maclist_init(void)
++{
++#     ifdef MODULE
++              if (ids[0])
++                      maclist_setup(ids);
++#     endif
++
++      /* Ignore failure, the module will still work. */
++      (void)create_proc_read_entry(MACLIST_NAME, S_IRUGO, proc_net, maclist_proc_read, NULL);
++
++      return 0;
++}
++
++module_init(maclist_init);
++module_exit(maclist_exit);
+--- linux-2.6.15/drivers/net/Makefile  1970-01-01 00:00:00.000000000 +0000
++++ linux-2.6.15/drivers/net/Makefile  1970-01-01 00:00:00.000000000 +0000
+@@ -70,6 +70,7 @@ obj-$(CONFIG_RIONET) += rionet.o
+ # end link order section
+ #
++obj-$(CONFIG_MACLIST) += maclist.o
+ obj-$(CONFIG_MII) += mii.o
+ obj-$(CONFIG_PHYLIB) += phy/
+--- linux-2.6.15/drivers/net/Kconfig   1970-01-01 00:00:00.000000000 +0000
++++ linux-2.6.15/drivers/net/Kconfig   1970-01-01 00:00:00.000000000 +0000
+@@ -166,6 +166,21 @@ config NET_ETHERNET
+         kernel: saying N will just cause the configurator to skip all
+         the questions about Ethernet network cards. If unsure, say N.
++config MACLIST
++      tristate "Ethernet MAC repository"
++      depends on NET_ETHERNET
++      help
++        Some ethernet controllers have no built-in way of obtaining an
++        appropriate Ethernet MAC address.  Such controllers have to be
++        initialised in a board-specific way, depending on how the allocated
++        MAC is stored.  The MAC repository provides a set of APIs and a
++        proc entry (/proc/net/maclist) to store MAC values from the board
++        so that such drivers can obtain a MAC address without board-specific
++        code.  You do not need to enable this device - it will be selected
++        automatically by any device which requires it.  It is only useful
++        to enable it manually when building a device driver independently
++        of the kernel build.
++
+ config MII
+       tristate "Generic Media Independent Interface device support"
+       depends on NET_ETHERNET
diff --git a/packages/linux/nas100d-kernel/2.6.15/92-nas100d-maclist.patch b/packages/linux/nas100d-kernel/2.6.15/92-nas100d-maclist.patch
new file mode 100644 (file)
index 0000000..3143850
--- /dev/null
@@ -0,0 +1,72 @@
+--- linux-2.6.15/arch/arm/mach-ixp4xx/Kconfig  1970-01-01 00:00:00.000000000 +0000
++++ linux-2.6.15/arch/arm/mach-ixp4xx/Kconfig  1970-01-01 00:00:00.000000000 +0000
+@@ -74,6 +74,7 @@ comment "IXP4xx Platforms"
+ config MACH_NAS100D
+       bool
+       prompt "NAS100D"
++      select MACLIST
+       help
+         Say 'Y' here if you want your kernel to support Iomega's
+         NAS 100d device. For more information on this platform,
+--- linux-2.6.15/arch/arm/mach-ixp4xx/nas100d-setup.c  1970-01-01 00:00:00.000000000 +0000
++++ linux-2.6.15/arch/arm/mach-ixp4xx/nas100d-setup.c  1970-01-01 00:00:00.000000000 +0000
+@@ -14,11 +14,14 @@
+ #include <linux/kernel.h>
+ #include <linux/serial.h>
+ #include <linux/serial_8250.h>
++#include <linux/mtd/mtd.h>
+ #include <asm/mach-types.h>
+ #include <asm/mach/arch.h>
+ #include <asm/mach/flash.h>
++#include <net/maclist.h>
++
+ static struct flash_platform_data nas100d_flash_data = {
+       .map_name               = "cfi_probe",
+       .width                  = 2,
+@@ -110,8 +113,44 @@
+       gpio_line_set(NAS100D_PO_GPIO, IXP4XX_GPIO_HIGH);
+ }
++/*
++ * When the RedBoot config partition is added the MAC address is read from
++ * it.
++ */
++void flash_add(struct mtd_info *mtd) {
++      if (strcmp(mtd->name, "RedBoot config") == 0) {
++              size_t retlen;
++              u_char mac[6];
++
++              /* The MAC is at a known offset... */
++              if (mtd->read(mtd, 0x0FD8, 6, &retlen, mac) == 0 && retlen == 6) {
++                      printk(KERN_INFO "NAS100D MAC: %.2x:%.2x:%.2x:%.2x:%.2x:%.2x\n",
++                              mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
++                      maclist_add(mac);
++              } else {
++                      printk(KERN_ERR "NAS100D MAC: read failed\n");
++              }
++      }
++}
++
++/*
++ * Nothing to do on remove at present.
++ */
++void flash_remove(struct mtd_info *mtd) {
++}
++
++struct mtd_notifier flash_notifier = {
++      .add = flash_add,
++      .remove = flash_remove,
++};
++
+ static void __init nas100d_init(void)
+ {
++      /* The flash has an ethernet MAC embedded in it which we need,
++       * that is all this notifier does.
++       */
++      register_mtd_user(&flash_notifier);
++
+       ixp4xx_sys_init();
+       pm_power_off = nas100d_power_off;
diff --git a/packages/linux/nas100d-kernel/2.6.15/anonymiser.patch b/packages/linux/nas100d-kernel/2.6.15/anonymiser.patch
new file mode 100644 (file)
index 0000000..3384b15
--- /dev/null
@@ -0,0 +1,22 @@
+--- linux-2.6.11.2/scripts/mkcompile_h.orig    2005-05-07 05:27:02.440000000 +0000
++++ linux-2.6.11.2/scripts/mkcompile_h 2005-05-07 05:28:30.360000000 +0000
+@@ -43,16 +43,9 @@
+   echo \#define UTS_VERSION \"`echo $UTS_VERSION | $UTS_TRUNCATE`\"
+   echo \#define LINUX_COMPILE_TIME \"`LC_ALL=C LANG=C date +%T`\"
+-  echo \#define LINUX_COMPILE_BY \"`whoami`\"
+-  echo \#define LINUX_COMPILE_HOST \"`hostname | $UTS_TRUNCATE`\"
+-
+-  if [ -x /bin/dnsdomainname ]; then
+-    echo \#define LINUX_COMPILE_DOMAIN \"`dnsdomainname | $UTS_TRUNCATE`\"
+-  elif [ -x /bin/domainname ]; then
+-    echo \#define LINUX_COMPILE_DOMAIN \"`domainname | $UTS_TRUNCATE`\"
+-  else
+-    echo \#define LINUX_COMPILE_DOMAIN
+-  fi
++  echo \#define LINUX_COMPILE_BY \"openslug\"
++  echo \#define LINUX_COMPILE_HOST \"openslug.org\"
++  echo \#define LINUX_COMPILE_DOMAIN \"openslug.org\"
+   echo \#define LINUX_COMPILER \"`$CC -v 2>&1 | tail -n 1`\"
+ ) > .tmpcompile
diff --git a/packages/linux/nas100d-kernel/2.6.15/nas100d-pci.c b/packages/linux/nas100d-kernel/2.6.15/nas100d-pci.c
deleted file mode 100644 (file)
index 1f93406..0000000
+++ /dev/null
@@ -1,87 +0,0 @@
-/*
- * arch/arm/mach-ixp4xx/nas100d-pci.c
- *
- * NAS 100d board-level PCI initialization
- *
- * based on ixdp425-pci.c:
- *     Copyright (C) 2002 Intel Corporation.
- *     Copyright (C) 2003-2004 MontaVista Software, Inc.
- *
- * Maintainer: http://www.nslu2-linux.org/
- *
- * 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/config.h>
-#include <linux/pci.h>
-#include <linux/init.h>
-
-#include <asm/mach/pci.h>
-#include <asm/mach-types.h>
-
-void __init nas100d_pci_preinit(void)
-{
-       set_irq_type(IRQ_NAS100D_PCI_INTA, IRQT_LOW);
-       set_irq_type(IRQ_NAS100D_PCI_INTB, IRQT_LOW);
-       set_irq_type(IRQ_NAS100D_PCI_INTC, IRQT_LOW);
-       set_irq_type(IRQ_NAS100D_PCI_INTD, IRQT_LOW);
-       set_irq_type(IRQ_NAS100D_PCI_INTE, IRQT_LOW);
-
-       gpio_line_isr_clear(NAS100D_PCI_INTA_PIN);
-       gpio_line_isr_clear(NAS100D_PCI_INTB_PIN);
-       gpio_line_isr_clear(NAS100D_PCI_INTC_PIN);
-       gpio_line_isr_clear(NAS100D_PCI_INTD_PIN);
-       gpio_line_isr_clear(NAS100D_PCI_INTE_PIN);
-
-       ixp4xx_pci_preinit();
-}
-
-static int __init nas100d_map_irq(struct pci_dev *dev, u8 slot, u8 pin)
-{
-       if (slot < 1 || slot > 3 || pin < 1 || pin > 3)
-               return -1;
-
-       switch (slot)
-       {
-       case 1:
-               if (pin == 1)
-                       return IRQ_NAS100D_PCI_INTA;
-               break;
-       case 2:
-               if (pin == 1)
-                       return IRQ_NAS100D_PCI_INTB;
-               break;
-       case 3:
-               if (pin == 1)
-                       return IRQ_NAS100D_PCI_INTC;
-               if (pin == 2)
-                       return IRQ_NAS100D_PCI_INTD;
-               if (pin == 3)
-                       return IRQ_NAS100D_PCI_INTE;
-               break;
-       }
-
-       return -1;
-}
-
-struct hw_pci __initdata nas100d_pci = {
-       .nr_controllers = 1,
-       .preinit        = nas100d_pci_preinit,
-       .swizzle        = pci_std_swizzle,
-       .setup          = ixp4xx_setup,
-       .scan           = ixp4xx_scan_bus,
-       .map_irq        = nas100d_map_irq,
-};
-
-int __init nas100d_pci_init(void)
-{
-       if (machine_is_nas100d())
-               pci_common_init(&nas100d_pci);
-
-       return 0;
-}
-
-subsys_initcall(nas100d_pci_init);
diff --git a/packages/linux/nas100d-kernel/2.6.15/nas100d-power.c b/packages/linux/nas100d-kernel/2.6.15/nas100d-power.c
deleted file mode 100644 (file)
index 94ce5d1..0000000
+++ /dev/null
@@ -1,92 +0,0 @@
-/*
- * arch/arm/mach-ixp4xx/nas100d-power.c
- *
- * NAS 100d Power/Reset driver
- *
- * Copyright (C) 2005 Tower Technologies
- *
- * based on nas100d-io.c
- *  Copyright (C) 2004 Karen Spearel
- *
- * Author: Alessandro Zummo <a.zummo@towertech.it>
- * Maintainers: http://www.nslu2-linux.org/
- *
- * 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/module.h>
-#include <linux/reboot.h>
-#include <linux/interrupt.h>
-
-#include <asm/mach-types.h>
-
-extern void ctrl_alt_del(void);
-
-static irqreturn_t nas100d_power_handler(int irq, void *dev_id, struct pt_regs *regs)
-{
-       /* Signal init to do the ctrlaltdel action, this will bypass init if
-        * it hasn't started and do a kernel_restart.
-        */
-       ctrl_alt_del();
-
-       return IRQ_HANDLED;
-}
-
-static irqreturn_t nas100d_reset_handler(int irq, void *dev_id, struct pt_regs *regs)
-{
-       /* This is the paper-clip reset, it shuts the machine down directly.
-        */
-       machine_power_off();
-
-       return IRQ_HANDLED;
-}
-
-static int __init nas100d_power_init(void)
-{
-       if (!(machine_is_nas100d()))
-               return 0;
-
-       // *IXP4XX_GPIO_GPISR = 0x20400000;     /* read the 2 irqs to clr */
-
-       set_irq_type(NAS100D_RB_IRQ, IRQT_LOW);
-//     set_irq_type(NAS100D_PB_IRQ, IRQT_HIGH);
-
-       gpio_line_isr_clear(NAS100D_RB_GPIO);
-//     gpio_line_isr_clear(NAS100D_PB_GPIO);
-
-       if (request_irq(NAS100D_RB_IRQ, &nas100d_reset_handler,
-               SA_INTERRUPT, "NAS100D reset button", NULL) < 0) {
-
-               printk(KERN_DEBUG "Reset Button IRQ %d not available\n",
-                       NAS100D_RB_IRQ);
-
-               return -EIO;
-       }
-/*
-       if (request_irq(NAS100D_PB_IRQ, &nas100d_power_handler,
-               SA_INTERRUPT, "NAS100D power button", NULL) < 0) {
-
-               printk(KERN_DEBUG "Power Button IRQ %d not available\n",
-                       NAS100D_PB_IRQ);
-
-               return -EIO;
-       }
-*/
-       return 0;
-}
-
-static void __exit nas100d_power_exit(void)
-{
-       free_irq(NAS100D_RB_IRQ, NULL);
-//     free_irq(NAS100D_PB_IRQ, NULL);
-}
-
-module_init(nas100d_power_init);
-module_exit(nas100d_power_exit);
-
-MODULE_AUTHOR("Alessandro Zummo <a.zummo@towertech.it>");
-MODULE_DESCRIPTION("NAS100D Power/Reset driver");
-MODULE_LICENSE("GPL");
diff --git a/packages/linux/nas100d-kernel/2.6.15/nas100d-setup.c b/packages/linux/nas100d-kernel/2.6.15/nas100d-setup.c
deleted file mode 100644 (file)
index 0dbb0b4..0000000
+++ /dev/null
@@ -1,132 +0,0 @@
-/*
- * arch/arm/mach-ixp4xx/nas100d-setup.c
- *
- * NAS 100d board-setup
- *
- * based ixdp425-setup.c:
- *      Copyright (C) 2003-2004 MontaVista Software, Inc.
- *
- * Author: Mark Rakes <mrakes at mac.com>
- * Maintainers: http://www.nslu2-linux.org/
- *
- */
-
-#include <linux/kernel.h>
-#include <linux/serial.h>
-#include <linux/serial_8250.h>
-
-#include <asm/mach-types.h>
-#include <asm/mach/arch.h>
-#include <asm/mach/flash.h>
-
-static struct flash_platform_data nas100d_flash_data = {
-       .map_name               = "cfi_probe",
-       .width                  = 2,
-};
-
-static struct resource nas100d_flash_resource = {
-       .start                  = NAS100D_FLASH_BASE,
-       .end                    = NAS100D_FLASH_BASE + NAS100D_FLASH_SIZE,
-       .flags                  = IORESOURCE_MEM,
-};
-
-static struct platform_device nas100d_flash = {
-       .name                   = "IXP4XX-Flash",
-       .id                     = 0,
-       .dev.platform_data      = &nas100d_flash_data,
-       .num_resources          = 1,
-       .resource               = &nas100d_flash_resource,
-};
-
-static struct ixp4xx_i2c_pins nas100d_i2c_gpio_pins = {
-       .sda_pin                = NAS100D_SDA_PIN,
-       .scl_pin                = NAS100D_SCL_PIN,
-};
-
-static struct platform_device nas100d_i2c_controller = {
-       .name                   = "IXP4XX-I2C",
-       .id                     = 0,
-       .dev.platform_data      = &nas100d_i2c_gpio_pins,
-       .num_resources          = 0,
-};
-
-static struct resource nas100d_uart_resources[] = {
-       {
-               .start          = IXP4XX_UART1_BASE_PHYS,
-               .end            = IXP4XX_UART1_BASE_PHYS + 0x0fff,
-               .flags          = IORESOURCE_MEM,
-       },
-       {
-               .start          = IXP4XX_UART2_BASE_PHYS,
-               .end            = IXP4XX_UART2_BASE_PHYS + 0x0fff,
-               .flags          = IORESOURCE_MEM,
-       }
-};
-
-static struct plat_serial8250_port nas100d_uart_data[] = {
-       {
-               .mapbase        = IXP4XX_UART1_BASE_PHYS,
-               .membase        = (char *)IXP4XX_UART1_BASE_VIRT + REG_OFFSET,
-               .irq            = IRQ_IXP4XX_UART1,
-               .flags          = UPF_BOOT_AUTOCONF,
-               .iotype         = UPIO_MEM,
-               .regshift       = 2,
-               .uartclk        = IXP4XX_UART_XTAL,
-       },
-       {
-               .mapbase        = IXP4XX_UART2_BASE_PHYS,
-               .membase        = (char *)IXP4XX_UART2_BASE_VIRT + REG_OFFSET,
-               .irq            = IRQ_IXP4XX_UART2,
-               .flags          = UPF_BOOT_AUTOCONF,
-               .iotype         = UPIO_MEM,
-               .regshift       = 2,
-               .uartclk        = IXP4XX_UART_XTAL,
-       },
-       { }
-};
-
-static struct platform_device nas100d_uart = {
-       .name                   = "serial8250",
-       .id                     = PLAT8250_DEV_PLATFORM,
-       .dev.platform_data      = nas100d_uart_data,
-       .num_resources          = 2,
-       .resource               = nas100d_uart_resources,
-};
-
-static struct platform_device *nas100d_devices[] __initdata = {
-       &nas100d_i2c_controller,
-       &nas100d_flash,
-       &nas100d_uart,
-};
-
-static void nas100d_power_off(void)
-{
-       /* This causes the box to drop the power and go dead. */
-
-       /* enable the pwr cntl gpio */
-       gpio_line_config(NAS100D_PO_GPIO, IXP4XX_GPIO_OUT);
-
-       /* do the deed */
-       gpio_line_set(NAS100D_PO_GPIO, IXP4XX_GPIO_HIGH);
-}
-
-static void __init nas100d_init(void)
-{
-       ixp4xx_sys_init();
-
-       pm_power_off = nas100d_power_off;
-
-       platform_add_devices(nas100d_devices, ARRAY_SIZE(nas100d_devices));
-}
-
-MACHINE_START(NAS100D, "Iomega NAS 100d")
-       /* Maintainer: www.nslu2-linux.org */
-       .phys_ram       = PHYS_OFFSET,
-       .phys_io        = IXP4XX_PERIPHERAL_BASE_PHYS,
-       .io_pg_offst    = ((IXP4XX_PERIPHERAL_BASE_VIRT) >> 18) & 0xFFFC,
-       .boot_params    = 0x00000100,
-       .map_io         = ixp4xx_map_io,
-       .init_irq       = ixp4xx_init_irq,
-       .timer          = &ixp4xx_timer,
-       .init_machine   = nas100d_init,
-MACHINE_END
diff --git a/packages/linux/nas100d-kernel/2.6.15/nas100d.h b/packages/linux/nas100d-kernel/2.6.15/nas100d.h
deleted file mode 100644 (file)
index 1623712..0000000
+++ /dev/null
@@ -1,75 +0,0 @@
-/*
- * include/asm-arm/arch-ixp4xx/nas100d.h
- *
- * NAS100D platform specific definitions
- *
- * Copyright (c) 2005 Tower Technologies
- *
- * Author: Alessandro Zummo <a.zummo@towertech.it>
- *  
- * based on ixdp425.h:
- *     Copyright 2004 (c) MontaVista, Software, Inc. 
- * 
- * This file is licensed under  the terms of the GNU General Public 
- * License version 2. This program is licensed "as is" without any 
- * warranty of any kind, whether express or implied.
- */
-
-#ifndef __ASM_ARCH_HARDWARE_H__
-#error "Do not include this directly, instead #include <asm/hardware.h>"
-#endif
-
-#define        NAS100D_FLASH_BASE      IXP4XX_EXP_BUS_CS0_BASE_PHYS
-#define        NAS100D_FLASH_SIZE      IXP4XX_EXP_BUS_CSX_REGION_SIZE
-
-#define        NAS100D_SDA_PIN         5
-#define        NAS100D_SCL_PIN         6
-
-/*
- * NAS100D PCI IRQs
- */
-#define NAS100D_PCI_MAX_DEV    5
-#define NAS100D_PCI_IRQ_LINES  5
-
-
-/* PCI controller GPIO to IRQ pin mappings */
-#define NAS100D_PCI_INTA_PIN   11
-#define NAS100D_PCI_INTB_PIN   10
-#define        NAS100D_PCI_INTC_PIN    9
-#define        NAS100D_PCI_INTD_PIN    8
-#define        NAS100D_PCI_INTE_PIN    7
-
-/* GPIO */
-
-#define NAS100D_GPIO0           0
-#define NAS100D_GPIO1           1
-#define NAS100D_GPIO2           2
-#define NAS100D_GPIO3           3
-#define NAS100D_GPIO4           4
-#define NAS100D_GPIO5           5
-#define NAS100D_GPIO6           6
-#define NAS100D_GPIO7           7
-#define NAS100D_GPIO8           8
-#define NAS100D_GPIO9           9
-#define NAS100D_GPIO10          10
-#define NAS100D_GPIO11          11
-#define NAS100D_GPIO12          12
-#define NAS100D_GPIO13          13
-#define NAS100D_GPIO14          14
-#define NAS100D_GPIO15          15
-
-
-/* Buttons */
-
-#define NAS100D_PB_GPIO         NAS100D_GPIO14
-#define NAS100D_RB_GPIO         NAS100D_GPIO4
-#define NAS100D_PO_GPIO         NAS100D_GPIO12   /* power off */
-
-#define NAS100D_PB_IRQ          IRQ_IXP4XX_GPIO14
-#define NAS100D_RB_IRQ          IRQ_IXP4XX_GPIO4
-
-/*
-#define NAS100D_PB_BM           (1L << NAS100D_PB_GPIO)
-#define NAS100D_PO_BM           (1L << NAS100D_PO_GPIO)
-#define NAS100D_RB_BM           (1L << NAS100D_RB_GPIO)
-*/
diff --git a/packages/linux/nas100d-kernel_2.6.15.bb b/packages/linux/nas100d-kernel_2.6.15.bb
new file mode 100644 (file)
index 0000000..337763b
--- /dev/null
@@ -0,0 +1,34 @@
+# Kernel for Iomega NAS 100d
+#
+# Increment PR_CONFIG for changes to the nas100d-kernel specific
+# defconfig (do *NOT* increment anything in here for changes
+# to other kernel configs!)
+PR_CONFIG = "0"
+#
+# Increment the number below (i.e. the digits after PR) when
+# making changes within this file or for changes to the patches
+# applied to the kernel.
+PR = "r1.${PR_CONFIG}"
+
+include nas100d-kernel.inc
+
+# N1K_PATCHES - full list of patches to apply
+N1K_PATCHES = "\
+       file://00-memory-h-page-shift.patch;patch=1 \
+       file://10-mtdpart-redboot-fis-byteswap.patch;patch=1 \
+       file://19-jffs2-force-be.patch;patch=1 \
+       file://40-rtc-class.patch;patch=1 \
+       file://50-nas100d-arch.patch;patch=1 \
+       file://60-nas100d-ide.patch;patch=1 \
+       file://60-nas100d-i2c.patch;patch=1 \
+       file://85-timer.patch;patch=1 \
+       file://91-maclist.patch;patch=1 \
+       file://92-nas100d-maclist.patch;patch=1 \
+       file://anonymiser.patch;patch=1 \
+"
+
+# These options get added to the kernel command line, only put things
+# specific to the bootstrap of *this* kernel in here - DISTRO specfic
+# config must be in CMDLINE_ROOT (see the full definition of CMDLINE
+# in nas100d-kernel.inc)
+CMDLINE_KERNEL_OPTIONS = "pcf8563.hctosys=1"