linux-kexecboot: support tosa
authorDmitry Baryshkov <dbaryshkov@gmail.com>
Mon, 8 Dec 2008 21:35:08 +0000 (00:35 +0300)
committerGraeme Gregory <dp@xora.org.uk>
Thu, 29 Jan 2009 01:46:20 +0000 (01:46 +0000)
port patches from linux-rp-2.6.24 to linux-kexecboot to enable booting
on tosa.

Signed-off-by: Dmitry Baryshkov <dbaryshkov@gmail.com>
73 files changed:
packages/kexecboot/linux-kexecboot-2.6.24/tosa/0001-Allow-runtime-registration-of-regions-of-memory-that.patch [new file with mode: 0644]
packages/kexecboot/linux-kexecboot-2.6.24/tosa/0001-pxa2xx-ac97-switch-AC-unit-to-correct-state-before.patch [new file with mode: 0644]
packages/kexecboot/linux-kexecboot-2.6.24/tosa/0002-Modify-dma_alloc_coherent-on-ARM-so-that-it-supports.patch [new file with mode: 0644]
packages/kexecboot/linux-kexecboot-2.6.24/tosa/0003-Core-MFD-support.patch [new file with mode: 0644]
packages/kexecboot/linux-kexecboot-2.6.24/tosa/0004-Add-support-for-tc6393xb-MFD-core.patch [new file with mode: 0644]
packages/kexecboot/linux-kexecboot-2.6.24/tosa/0005-Add-support-for-tc6387xb-MFD-core.patch [new file with mode: 0644]
packages/kexecboot/linux-kexecboot-2.6.24/tosa/0006-Add-support-for-t7l66xb-MFD-core.patch [new file with mode: 0644]
packages/kexecboot/linux-kexecboot-2.6.24/tosa/0007-Common-headers-for-TMIO-MFD-subdevices.patch [new file with mode: 0644]
packages/kexecboot/linux-kexecboot-2.6.24/tosa/0008-Nand-driver-for-TMIO-devices.patch [new file with mode: 0644]
packages/kexecboot/linux-kexecboot-2.6.24/tosa/0009-FB-driver-for-TMIO-devices.patch [new file with mode: 0644]
packages/kexecboot/linux-kexecboot-2.6.24/tosa/0010-OHCI-driver-for-TMIO-devices.patch [new file with mode: 0644]
packages/kexecboot/linux-kexecboot-2.6.24/tosa/0011-MMC-driver-for-TMIO-devices.patch [new file with mode: 0644]
packages/kexecboot/linux-kexecboot-2.6.24/tosa/0012-Tosa-keyboard-support.patch [new file with mode: 0644]
packages/kexecboot/linux-kexecboot-2.6.24/tosa/0013-USB-gadget-pxa2xx_udc-supports-inverted-vbus.patch [new file with mode: 0644]
packages/kexecboot/linux-kexecboot-2.6.24/tosa/0014-tosa_udc_use_gpio_vbus.patch.patch [new file with mode: 0644]
packages/kexecboot/linux-kexecboot-2.6.24/tosa/0015-sharpsl-export-params.patch [new file with mode: 0644]
packages/kexecboot/linux-kexecboot-2.6.24/tosa/0016-This-patch-fixes-the-pxa25x-clocks-definitions-to-ad.patch [new file with mode: 0644]
packages/kexecboot/linux-kexecboot-2.6.24/tosa/0017-Convert-pxa2xx-UDC-to-use-debugfs.patch [new file with mode: 0644]
packages/kexecboot/linux-kexecboot-2.6.24/tosa/0018-Fix-the-pxa2xx_udc-to-balance-calls-to-clk_enable-cl.patch [new file with mode: 0644]
packages/kexecboot/linux-kexecboot-2.6.24/tosa/0019-pxa-remove-periodic-mode-emulation-support.patch [new file with mode: 0644]
packages/kexecboot/linux-kexecboot-2.6.24/tosa/0020-Provide-dew-device-clock-backports-from-2.6.24-git.patch [new file with mode: 0644]
packages/kexecboot/linux-kexecboot-2.6.24/tosa/0021-Add-an-empty-drivers-gpio-directory-for-gpiolib-infr.patch [new file with mode: 0644]
packages/kexecboot/linux-kexecboot-2.6.24/tosa/0022-Provide-new-implementation-infrastructure-that-platf.patch [new file with mode: 0644]
packages/kexecboot/linux-kexecboot-2.6.24/tosa/0023-This-adds-gpiolib-support-for-the-PXA-architecture.patch [new file with mode: 0644]
packages/kexecboot/linux-kexecboot-2.6.24/tosa/0024-Update-Documentation-gpio.txt-primarily-to-include.patch [new file with mode: 0644]
packages/kexecboot/linux-kexecboot-2.6.24/tosa/0025-Signed-off-by-Dmitry-Baryshkov-dbaryshkov-gmail.co.patch [new file with mode: 0644]
packages/kexecboot/linux-kexecboot-2.6.24/tosa/0026-I-don-t-think-we-should-check-for-IRQs-when-determin.patch [new file with mode: 0644]
packages/kexecboot/linux-kexecboot-2.6.24/tosa/0027-Add-LiMn-one-of-the-most-common-for-small-non-recha.patch [new file with mode: 0644]
packages/kexecboot/linux-kexecboot-2.6.24/tosa/0028-Add-suspend-resume-wakeup-support-for-pda_power.patch [new file with mode: 0644]
packages/kexecboot/linux-kexecboot-2.6.24/tosa/0029-Support-using-VOLTAGE_-properties-for-apm-calculati.patch [new file with mode: 0644]
packages/kexecboot/linux-kexecboot-2.6.24/tosa/0030-Core-driver-for-WM97xx-touchscreens.patch [new file with mode: 0644]
packages/kexecboot/linux-kexecboot-2.6.24/tosa/0031-Add-chip-driver-for-WM9705-touchscreen.patch [new file with mode: 0644]
packages/kexecboot/linux-kexecboot-2.6.24/tosa/0032-Add-chip-driver-for-WM9712-touchscreen.patch [new file with mode: 0644]
packages/kexecboot/linux-kexecboot-2.6.24/tosa/0033-Add-chip-driver-for-WM9713-touchscreen.patch [new file with mode: 0644]
packages/kexecboot/linux-kexecboot-2.6.24/tosa/0034-Driver-for-WM97xx-touchscreens-in-streaming-mode-on.patch [new file with mode: 0644]
packages/kexecboot/linux-kexecboot-2.6.24/tosa/0035-Build-system-and-MAINTAINERS-entry-for-WM97xx-touchs.patch [new file with mode: 0644]
packages/kexecboot/linux-kexecboot-2.6.24/tosa/0036-Set-id-to-1-for-wm97xx-subdevices.patch [new file with mode: 0644]
packages/kexecboot/linux-kexecboot-2.6.24/tosa/0037-Don-t-lock-the-codec-list-in-snd_soc_dapm_new_widget.patch [new file with mode: 0644]
packages/kexecboot/linux-kexecboot-2.6.24/tosa/0038-Don-t-lock-the-codec-list-in-snd_soc_dapm_new_widget.patch [new file with mode: 0644]
packages/kexecboot/linux-kexecboot-2.6.24/tosa/0039-Add-generic-framework-for-managing-clocks.patch [new file with mode: 0644]
packages/kexecboot/linux-kexecboot-2.6.24/tosa/0040-Clocklib-debugfs-support.patch [new file with mode: 0644]
packages/kexecboot/linux-kexecboot-2.6.24/tosa/0041-From-80a359e60c2aec59ccf4fca0a7fd20495f82b1d2-Mon-Se.patch [new file with mode: 0644]
packages/kexecboot/linux-kexecboot-2.6.24/tosa/0042-Use-correct-clock-for-IrDA-on-pxa.patch [new file with mode: 0644]
packages/kexecboot/linux-kexecboot-2.6.24/tosa/0043-Use-clocklib-for-sa1100-sub-arch.patch [new file with mode: 0644]
packages/kexecboot/linux-kexecboot-2.6.24/tosa/0044-fix-tmio_mmc-debug-compilation.patch [new file with mode: 0644]
packages/kexecboot/linux-kexecboot-2.6.24/tosa/0045-Update-tmio_ohci.patch [new file with mode: 0644]
packages/kexecboot/linux-kexecboot-2.6.24/tosa/0046-patch-tc6393xb-cleanup.patch [new file with mode: 0644]
packages/kexecboot/linux-kexecboot-2.6.24/tosa/0047-tc6393xb-use-bitmasks-instead-of-bit-field-structs.patch [new file with mode: 0644]
packages/kexecboot/linux-kexecboot-2.6.24/tosa/0048-tc6393xb-GPIO-support.patch [new file with mode: 0644]
packages/kexecboot/linux-kexecboot-2.6.24/tosa/0049-platform-support-for-TMIO-on-tosa.patch [new file with mode: 0644]
packages/kexecboot/linux-kexecboot-2.6.24/tosa/0050-tosa-update-for-tc6393xb-gpio.patch [new file with mode: 0644]
packages/kexecboot/linux-kexecboot-2.6.24/tosa/0051-fix-sound-soc-pxa-tosa.c-to-new-gpio-api.patch [new file with mode: 0644]
packages/kexecboot/linux-kexecboot-2.6.24/tosa/0052-tosa-platform-backlight-support.patch [new file with mode: 0644]
packages/kexecboot/linux-kexecboot-2.6.24/tosa/0053-sound-soc-codecs-wm9712.c-28.patch [new file with mode: 0644]
packages/kexecboot/linux-kexecboot-2.6.24/tosa/0054-sound-soc-codecs-wm9712.c-2.patch [new file with mode: 0644]
packages/kexecboot/linux-kexecboot-2.6.24/tosa/0055-Add-GPIO_POWERON-to-the-list-of-devices-that-we-supp.patch [new file with mode: 0644]
packages/kexecboot/linux-kexecboot-2.6.24/tosa/0056-Support-resetting-by-asserting-GPIO-pin.patch [new file with mode: 0644]
packages/kexecboot/linux-kexecboot-2.6.24/tosa/0057-Clean-up-tosa-resetting.patch [new file with mode: 0644]
packages/kexecboot/linux-kexecboot-2.6.24/tosa/0058-Fix-tosakbd-suspend.patch [new file with mode: 0644]
packages/kexecboot/linux-kexecboot-2.6.24/tosa/0059-patch-tosa-wakeup-test.patch [new file with mode: 0644]
packages/kexecboot/linux-kexecboot-2.6.24/tosa/0060-Add-support-for-power_supply-on-tosa.patch [new file with mode: 0644]
packages/kexecboot/linux-kexecboot-2.6.24/tosa/0061-tosa-bat-unify.patch [new file with mode: 0644]
packages/kexecboot/linux-kexecboot-2.6.24/tosa/0062-tosa-bat-fix-charging.patch [new file with mode: 0644]
packages/kexecboot/linux-kexecboot-2.6.24/tosa/0063-patch-tosa-bat-jacket-detect.patch [new file with mode: 0644]
packages/kexecboot/linux-kexecboot-2.6.24/tosa/0064-Export-modes-via-sysfs.patch [new file with mode: 0644]
packages/kexecboot/linux-kexecboot-2.6.24/tosa/0065-wm97xx-core-fixes.patch [new file with mode: 0644]
packages/kexecboot/linux-kexecboot-2.6.24/tosa/0066-tmiofb_probe-should-be-__devinit.patch [new file with mode: 0644]
packages/kexecboot/linux-kexecboot-2.6.24/tosa/0067-modeswitching.patch [new file with mode: 0644]
packages/kexecboot/linux-kexecboot-2.6.24/tosa/0068-Preliminary-tosa-denoiser.patch [new file with mode: 0644]
packages/kexecboot/linux-kexecboot-2.6.24/tosa/defconfig
packages/kexecboot/linux-kexecboot-2.6.24/tosa/tmiofb-fix-unaccel.patch [new file with mode: 0644]
packages/kexecboot/linux-kexecboot-2.6.24/tosa/tosa-bl-fixup.diff [new file with mode: 0644]
packages/kexecboot/linux-kexecboot_2.6.24.bb

diff --git a/packages/kexecboot/linux-kexecboot-2.6.24/tosa/0001-Allow-runtime-registration-of-regions-of-memory-that.patch b/packages/kexecboot/linux-kexecboot-2.6.24/tosa/0001-Allow-runtime-registration-of-regions-of-memory-that.patch
new file mode 100644 (file)
index 0000000..ba79b4a
--- /dev/null
@@ -0,0 +1,201 @@
+From d48a09b301d9a460d5ce027433e8cb8872e7b5c3 Mon Sep 17 00:00:00 2001
+From: Ian Molton <spyro@f2s.com>
+Date: Fri, 4 Jan 2008 18:26:38 +0000
+Subject: [PATCH 01/64] Allow runtime registration of regions of memory that require dma bouncing.
+
+---
+ arch/arm/common/Kconfig           |    4 ++
+ arch/arm/common/dmabounce.c       |   82 ++++++++++++++++++++++++++++++++++++-
+ arch/arm/common/sa1111.c          |    2 +-
+ arch/arm/mach-ixp4xx/Kconfig      |    1 +
+ arch/arm/mach-ixp4xx/common-pci.c |    2 +-
+ 5 files changed, 87 insertions(+), 4 deletions(-)
+
+diff --git a/arch/arm/common/Kconfig b/arch/arm/common/Kconfig
+index 3e07346..5f357fb 100644
+--- a/arch/arm/common/Kconfig
++++ b/arch/arm/common/Kconfig
+@@ -13,10 +13,14 @@ config ICST307
+ config SA1111
+       bool
+       select DMABOUNCE
++      select PLATFORM_DMABOUNCE
+ config DMABOUNCE
+       bool
++config PLATFORM_DMABOUNCE
++      bool
++
+ config TIMER_ACORN
+       bool
+diff --git a/arch/arm/common/dmabounce.c b/arch/arm/common/dmabounce.c
+index 52fc6a8..ed80abe 100644
+--- a/arch/arm/common/dmabounce.c
++++ b/arch/arm/common/dmabounce.c
+@@ -16,6 +16,7 @@
+  *
+  *  Copyright (C) 2002 Hewlett Packard Company.
+  *  Copyright (C) 2004 MontaVista Software, Inc.
++ *  Copyright (C) 2007 Dmitry Baryshkov <dbaryshkov@gmail.com>
+  *
+  *  This program is free software; you can redistribute it and/or
+  *  modify it under the terms of the GNU General Public License
+@@ -24,6 +25,7 @@
+ #include <linux/module.h>
+ #include <linux/init.h>
++#include <linux/rwsem.h>
+ #include <linux/slab.h>
+ #include <linux/device.h>
+ #include <linux/dma-mapping.h>
+@@ -80,6 +82,80 @@ struct dmabounce_device_info {
+       rwlock_t lock;
+ };
++struct dmabounce_check_entry {
++      struct list_head        list;
++      dmabounce_check         checker;
++      void                    *data;
++};
++
++static struct list_head checkers = LIST_HEAD_INIT(checkers);
++static rwlock_t checkers_lock = RW_LOCK_UNLOCKED;
++
++int
++dmabounce_register_checker(dmabounce_check function, void *data)
++{
++      unsigned long flags;
++      struct dmabounce_check_entry *entry =
++              kzalloc(sizeof(struct dmabounce_check_entry), GFP_ATOMIC);
++
++      if (!entry)
++              return ENOMEM;
++
++      INIT_LIST_HEAD(&entry->list);
++      entry->checker = function;
++      entry->data = data;
++
++      write_lock_irqsave(&checkers_lock, flags);
++      list_add(&entry->list, &checkers);
++      write_unlock_irqrestore(&checkers_lock, flags);
++
++      return 0;
++}
++
++void
++dmabounce_remove_checker(dmabounce_check function, void *data)
++{
++      unsigned long flags;
++      struct list_head *pos;
++
++      write_lock_irqsave(&checkers_lock, flags);
++      __list_for_each(pos, &checkers) {
++              struct dmabounce_check_entry *entry = container_of(pos,
++                              struct dmabounce_check_entry, list);
++              if (entry->checker == function && entry->data == data) {
++                      list_del(pos);
++                      write_unlock_irqrestore(&checkers_lock, flags);
++                      kfree(entry);
++                      return;
++              }
++      }
++
++      write_unlock_irqrestore(&checkers_lock, flags);
++      printk(KERN_WARNING "dmabounce checker not found: %p\n", function);
++}
++
++static int dma_needs_bounce(struct device *dev, dma_addr_t dma, size_t size)
++{
++      unsigned long flags;
++      struct list_head *pos;
++
++      read_lock_irqsave(&checkers_lock, flags);
++      __list_for_each(pos, &checkers) {
++              struct dmabounce_check_entry *entry = container_of(pos,
++                              struct dmabounce_check_entry, list);
++              if (entry->checker(dev, dma, size, entry->data)) {
++                      read_unlock_irqrestore(&checkers_lock, flags);
++                      return 1;
++              }
++      }
++
++      read_unlock_irqrestore(&checkers_lock, flags);
++#ifdef CONFIG_PLATFORM_DMABOUNCE
++      return platform_dma_needs_bounce(dev, dma, size);
++#else
++      return 0;
++#endif
++}
+ #ifdef STATS
+ static ssize_t dmabounce_show(struct device *dev, struct device_attribute *attr,
+                             char *buf)
+@@ -239,7 +315,7 @@ map_single(struct device *dev, void *ptr, size_t size,
+               struct safe_buffer *buf;
+               buf = alloc_safe_buffer(device_info, ptr, size, dir);
+-              if (buf == 0) {
++              if (buf == NULL) {
+                       dev_err(dev, "%s: unable to map unsafe buffer %p!\n",
+                              __func__, ptr);
+                       return 0;
+@@ -643,7 +719,6 @@ dmabounce_unregister_dev(struct device *dev)
+               dev->bus_id, dev->bus->name);
+ }
+-
+ EXPORT_SYMBOL(dma_map_single);
+ EXPORT_SYMBOL(dma_unmap_single);
+ EXPORT_SYMBOL(dma_map_sg);
+@@ -653,6 +728,9 @@ EXPORT_SYMBOL(dma_sync_single_for_device);
+ EXPORT_SYMBOL(dma_sync_sg);
+ EXPORT_SYMBOL(dmabounce_register_dev);
+ EXPORT_SYMBOL(dmabounce_unregister_dev);
++EXPORT_SYMBOL(dmabounce_register_checker);
++EXPORT_SYMBOL(dmabounce_remove_checker);
++
+ MODULE_AUTHOR("Christopher Hoover <ch@hpl.hp.com>, Deepak Saxena <dsaxena@plexity.net>");
+ MODULE_DESCRIPTION("Special dma_{map/unmap/dma_sync}_* routines for systems with limited DMA windows");
+diff --git a/arch/arm/common/sa1111.c b/arch/arm/common/sa1111.c
+index eb06d0b..3b8fbdd 100644
+--- a/arch/arm/common/sa1111.c
++++ b/arch/arm/common/sa1111.c
+@@ -778,7 +778,7 @@ static void __sa1111_remove(struct sa1111 *sachip)
+  * This should only get called for sa1111_device types due to the
+  * way we configure our device dma_masks.
+  */
+-int dma_needs_bounce(struct device *dev, dma_addr_t addr, size_t size)
++int platform_dma_needs_bounce(struct device *dev, dma_addr_t addr, size_t size)
+ {
+       /*
+        * Section 4.6 of the "Intel StrongARM SA-1111 Development Module
+diff --git a/arch/arm/mach-ixp4xx/Kconfig b/arch/arm/mach-ixp4xx/Kconfig
+index 61b2dfc..5870371 100644
+--- a/arch/arm/mach-ixp4xx/Kconfig
++++ b/arch/arm/mach-ixp4xx/Kconfig
+@@ -161,6 +161,7 @@ comment "IXP4xx Options"
+ config DMABOUNCE
+       bool
+       default y
++      select PLATFORM_DMABOUNCE
+       depends on PCI
+ config IXP4XX_INDIRECT_PCI
+diff --git a/arch/arm/mach-ixp4xx/common-pci.c b/arch/arm/mach-ixp4xx/common-pci.c
+index bf04121..ac46492 100644
+--- a/arch/arm/mach-ixp4xx/common-pci.c
++++ b/arch/arm/mach-ixp4xx/common-pci.c
+@@ -336,7 +336,7 @@ static int ixp4xx_pci_platform_notify_remove(struct device *dev)
+       return 0;
+ }
+-int dma_needs_bounce(struct device *dev, dma_addr_t dma_addr, size_t size)
++int platform_dma_needs_bounce(struct device *dev, dma_addr_t dma_addr, size_t size)
+ {
+       return (dev->bus == &pci_bus_type ) && ((dma_addr + size) >= SZ_64M);
+ }
+-- 
+1.5.3.8
+
diff --git a/packages/kexecboot/linux-kexecboot-2.6.24/tosa/0001-pxa2xx-ac97-switch-AC-unit-to-correct-state-before.patch b/packages/kexecboot/linux-kexecboot-2.6.24/tosa/0001-pxa2xx-ac97-switch-AC-unit-to-correct-state-before.patch
new file mode 100644 (file)
index 0000000..09f0cb9
--- /dev/null
@@ -0,0 +1,56 @@
+From 688df15bb534519e0698cc8e4a4d9234afd32105 Mon Sep 17 00:00:00 2001
+From: Dmitry Baryshkov <dbaryshkov@gmail.com>
+Date: Fri, 7 Nov 2008 15:50:39 +0300
+Subject: [PATCH] pxa2xx-ac97: switch AC unit to correct state before probing
+
+If AC97 unit is in partially enabled state, early request_irq can trigger
+IRQ storm or even full hang up. Workaround this by forcibly switching ACLINK off
+at the start of the probe.
+
+Signed-off-by: Dmitry Baryshkov <dbaryshkov@gmail.com>
+---
+ sound/soc/pxa/pxa2xx-ac97.c |   30 +++++++++++++++++-------------
+ 1 files changed, 17 insertions(+), 13 deletions(-)
+
+Index: linux-2.6.24/sound/soc/pxa/pxa2xx-ac97.c
+===================================================================
+--- linux-2.6.24.orig/sound/soc/pxa/pxa2xx-ac97.c      2008-01-25 01:58:37.000000000 +0300
++++ linux-2.6.24/sound/soc/pxa/pxa2xx-ac97.c   2008-11-15 20:02:45.396976363 +0300
+@@ -284,10 +284,6 @@ static int pxa2xx_ac97_probe(struct plat
+ {
+       int ret;
+
+-      ret = request_irq(IRQ_AC97, pxa2xx_ac97_irq, IRQF_DISABLED, "AC97", NULL);
+-      if (ret < 0)
+-              goto err;
+-
+       pxa_gpio_mode(GPIO31_SYNC_AC97_MD);
+       pxa_gpio_mode(GPIO30_SDATA_OUT_AC97_MD);
+       pxa_gpio_mode(GPIO28_BITCLK_AC97_MD);
+@@ -296,15 +292,23 @@ static int pxa2xx_ac97_probe(struct plat
+       /* Use GPIO 113 as AC97 Reset on Bulverde */
+       pxa_gpio_mode(113 | GPIO_ALT_FN_2_OUT);
+ #endif
++      GCR = GCR_ACLINK_OFF;
++
+       pxa_set_cken(CKEN_AC97, 1);
++
++      ret = request_irq(IRQ_AC97, pxa2xx_ac97_irq, IRQF_DISABLED, "AC97", NULL);
++      if (ret < 0)
++              goto err;
++
++
+       return 0;
+
+- err:
+-      if (CKEN & (1 << CKEN_AC97)) {
++err:
++/*    if (CKEN & (1 << CKEN_AC97)) {*/
+               GCR |= GCR_ACLINK_OFF;
+               free_irq(IRQ_AC97, NULL);
+               pxa_set_cken(CKEN_AC97, 0);
+-      }
++/*    }*/
+       return ret;
+ }
+
diff --git a/packages/kexecboot/linux-kexecboot-2.6.24/tosa/0002-Modify-dma_alloc_coherent-on-ARM-so-that-it-supports.patch b/packages/kexecboot/linux-kexecboot-2.6.24/tosa/0002-Modify-dma_alloc_coherent-on-ARM-so-that-it-supports.patch
new file mode 100644 (file)
index 0000000..a562ef9
--- /dev/null
@@ -0,0 +1,260 @@
+From 8e95f90487d2fb46fd862744ddb34f47c30b0c5a Mon Sep 17 00:00:00 2001
+From: Ian Molton <spyro@f2s.com>
+Date: Fri, 4 Jan 2008 18:27:50 +0000
+Subject: [PATCH 02/64] Modify dma_alloc_coherent on ARM so that it supports device local DMA.
+
+---
+ arch/arm/mm/consistent.c      |  125 +++++++++++++++++++++++++++++++++++++++++
+ include/asm-arm/dma-mapping.h |   37 +++++++------
+ 2 files changed, 145 insertions(+), 17 deletions(-)
+
+diff --git a/arch/arm/mm/consistent.c b/arch/arm/mm/consistent.c
+index 333a82a..3da0f94 100644
+--- a/arch/arm/mm/consistent.c
++++ b/arch/arm/mm/consistent.c
+@@ -3,6 +3,8 @@
+  *
+  *  Copyright (C) 2000-2004 Russell King
+  *
++ *  Device local coherent memory support added by Ian Molton (spyro@f2s.com)
++ *
+  * 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.
+@@ -20,6 +22,7 @@
+ #include <asm/memory.h>
+ #include <asm/cacheflush.h>
++#include <asm/io.h>
+ #include <asm/tlbflush.h>
+ #include <asm/sizes.h>
+@@ -35,6 +38,13 @@
+ #define CONSISTENT_PTE_INDEX(x) (((unsigned long)(x) - CONSISTENT_BASE) >> PGDIR_SHIFT)
+ #define NUM_CONSISTENT_PTES (CONSISTENT_DMA_SIZE >> PGDIR_SHIFT)
++struct dma_coherent_mem {
++      void            *virt_base;
++      u32             device_base;
++      int             size;
++      int             flags;
++      unsigned long   *bitmap;
++};
+ /*
+  * These are the page tables (2MB each) covering uncached, DMA consistent allocations
+@@ -153,6 +163,13 @@ __dma_alloc(struct device *dev, size_t size, dma_addr_t *handle, gfp_t gfp,
+       unsigned long order;
+       u64 mask = ISA_DMA_THRESHOLD, limit;
++      /* Following is a work-around (a.k.a. hack) to prevent pages
++       * with __GFP_COMP being passed to split_page() which cannot
++       * handle them.  The real problem is that this flag probably
++       * should be 0 on ARM as it is not supported on this
++       * platform--see CONFIG_HUGETLB_PAGE. */
++      gfp &= ~(__GFP_COMP);
++
+       if (!consistent_pte[0]) {
+               printk(KERN_ERR "%s: not initialised\n", __func__);
+               dump_stack();
+@@ -160,6 +177,26 @@ __dma_alloc(struct device *dev, size_t size, dma_addr_t *handle, gfp_t gfp,
+       }
+       if (dev) {
++
++              if (dev->dma_mem) {
++                      unsigned long flags;
++                      int pgnum;
++                      void *ret;
++
++                      spin_lock_irqsave(&consistent_lock, flags);
++                      pgnum = bitmap_find_free_region(dev->dma_mem->bitmap,
++                                                     dev->dma_mem->size,
++                                                     get_order(size));
++                      spin_unlock_irqrestore(&consistent_lock, flags);
++
++                      if (pgnum >= 0) {
++                              *handle = dev->dma_mem->device_base + (pgnum << PAGE_SHIFT);
++                              ret = dev->dma_mem->virt_base + (pgnum << PAGE_SHIFT);
++                              memset(ret, 0, size);
++                              return ret;
++                      }
++              }
++
+               mask = dev->coherent_dma_mask;
+               /*
+@@ -177,6 +214,9 @@ __dma_alloc(struct device *dev, size_t size, dma_addr_t *handle, gfp_t gfp,
+                                mask, (unsigned long long)ISA_DMA_THRESHOLD);
+                       goto no_page;
+               }
++
++              if (dev->dma_mem && dev->dma_mem->flags & DMA_MEMORY_EXCLUSIVE)
++                      return NULL;
+       }
+       /*
+@@ -359,6 +399,8 @@ void dma_free_coherent(struct device *dev, size_t size, void *cpu_addr, dma_addr
+       pte_t *ptep;
+       int idx;
+       u32 off;
++      struct dma_coherent_mem *mem = dev ? dev->dma_mem : NULL;
++      unsigned long order;
+       WARN_ON(irqs_disabled());
+@@ -368,6 +410,15 @@ void dma_free_coherent(struct device *dev, size_t size, void *cpu_addr, dma_addr
+       }
+       size = PAGE_ALIGN(size);
++      order = get_order(size);
++
++      /* What if mem is valid and the range is not? */
++      if (mem && cpu_addr >= mem->virt_base && cpu_addr < (mem->virt_base + (mem->size << PAGE_SHIFT))) {
++              int page = (cpu_addr - mem->virt_base) >> PAGE_SHIFT;
++
++              bitmap_release_region(mem->bitmap, page, order);
++              return;
++      }
+       spin_lock_irqsave(&consistent_lock, flags);
+       c = vm_region_find(&consistent_head, (unsigned long)cpu_addr);
+@@ -437,6 +488,80 @@ void dma_free_coherent(struct device *dev, size_t size, void *cpu_addr, dma_addr
+ }
+ EXPORT_SYMBOL(dma_free_coherent);
++int dma_declare_coherent_memory(struct device *dev, dma_addr_t bus_addr,
++                              dma_addr_t device_addr, size_t size, int flags)
++{
++      void __iomem *mem_base;
++      int pages = size >> PAGE_SHIFT;
++      int bitmap_size = (pages + 31)/32;
++
++      if ((flags & (DMA_MEMORY_MAP | DMA_MEMORY_IO)) == 0)
++              goto out;
++      if (!size)
++              goto out;
++      if (dev->dma_mem)
++              goto out;
++
++      /* FIXME: this routine just ignores DMA_MEMORY_INCLUDES_CHILDREN */
++      mem_base = ioremap_nocache(bus_addr, size);
++      if (!mem_base)
++              goto out;
++
++      dev->dma_mem = kzalloc(sizeof(struct dma_coherent_mem), GFP_KERNEL);
++      if (!dev->dma_mem)
++              goto out;
++      memset(dev->dma_mem, 0, sizeof(struct dma_coherent_mem));
++      dev->dma_mem->bitmap = kzalloc(bitmap_size, GFP_KERNEL);
++      if (!dev->dma_mem->bitmap)
++              goto free1_out;
++
++      dev->dma_mem->virt_base = mem_base;
++      dev->dma_mem->device_base = device_addr;
++      dev->dma_mem->size = pages;
++      dev->dma_mem->flags = flags;
++
++      if (flags & DMA_MEMORY_MAP)
++              return DMA_MEMORY_MAP;
++
++      return DMA_MEMORY_IO;
++
++ free1_out:
++      kfree(dev->dma_mem->bitmap);
++ out:
++      return 0;
++}
++EXPORT_SYMBOL(dma_declare_coherent_memory);
++
++void dma_release_declared_memory(struct device *dev)
++{
++      struct dma_coherent_mem *mem = dev->dma_mem;
++
++      if (!mem)
++              return;
++      dev->dma_mem = NULL;
++      kfree(mem->bitmap);
++      kfree(mem);
++}
++EXPORT_SYMBOL(dma_release_declared_memory);
++
++void *dma_mark_declared_memory_occupied(struct device *dev,
++                                      dma_addr_t device_addr, size_t size)
++{
++      struct dma_coherent_mem *mem = dev->dma_mem;
++      int pages = (size + PAGE_SIZE - 1) >> PAGE_SHIFT;
++      int pos, err;
++
++      if (!mem)
++              return ERR_PTR(-EINVAL);
++
++      pos = (device_addr - mem->device_base) >> PAGE_SHIFT;
++      err = bitmap_allocate_region(mem->bitmap, pos, get_order(pages));
++      if (err != 0)
++              return ERR_PTR(err);
++      return mem->virt_base + (pos << PAGE_SHIFT);
++}
++EXPORT_SYMBOL(dma_mark_declared_memory_occupied);
++
+ /*
+  * Initialise the consistent memory allocation.
+  */
+diff --git a/include/asm-arm/dma-mapping.h b/include/asm-arm/dma-mapping.h
+index e99406a..f18ba05 100644
+--- a/include/asm-arm/dma-mapping.h
++++ b/include/asm-arm/dma-mapping.h
+@@ -7,6 +7,19 @@
+ #include <linux/scatterlist.h>
++#define ARCH_HAS_DMA_DECLARE_COHERENT_MEMORY
++extern int
++dma_declare_coherent_memory(struct device *dev, dma_addr_t bus_addr,
++                            dma_addr_t device_addr, size_t size, int flags);
++
++extern void
++dma_release_declared_memory(struct device *dev);
++
++extern void *
++dma_mark_declared_memory_occupied(struct device *dev,
++                                  dma_addr_t device_addr, size_t size);
++
++
+ /*
+  * DMA-consistent mapping functions.  These allocate/free a region of
+  * uncached, unwrite-buffered mapped memory space for use with DMA
+@@ -433,23 +446,13 @@ extern int dmabounce_register_dev(struct device *, unsigned long, unsigned long)
+  */
+ extern void dmabounce_unregister_dev(struct device *);
+-/**
+- * dma_needs_bounce
+- *
+- * @dev: valid struct device pointer
+- * @dma_handle: dma_handle of unbounced buffer
+- * @size: size of region being mapped
+- *
+- * Platforms that utilize the dmabounce mechanism must implement
+- * this function.
+- *
+- * The dmabounce routines call this function whenever a dma-mapping
+- * is requested to determine whether a given buffer needs to be bounced
+- * or not. The function must return 0 if the buffer is OK for
+- * DMA access and 1 if the buffer needs to be bounced.
+- *
+- */
+-extern int dma_needs_bounce(struct device*, dma_addr_t, size_t);
++typedef int (*dmabounce_check)(struct device *dev, dma_addr_t dma, size_t size, void *data);
++extern int dmabounce_register_checker(dmabounce_check, void *data);
++extern void dmabounce_remove_checker(dmabounce_check, void *data);
++#ifdef CONFIG_PLATFORM_DMABOUNCE
++extern int platform_dma_needs_bounce(struct device *dev, dma_addr_t dma, size_t size, void *data);
++#endif
++
+ #endif /* CONFIG_DMABOUNCE */
+ #endif /* __KERNEL__ */
+-- 
+1.5.3.8
+
diff --git a/packages/kexecboot/linux-kexecboot-2.6.24/tosa/0003-Core-MFD-support.patch b/packages/kexecboot/linux-kexecboot-2.6.24/tosa/0003-Core-MFD-support.patch
new file mode 100644 (file)
index 0000000..d84a4f7
--- /dev/null
@@ -0,0 +1,243 @@
+From a07910753f9965842b6647f0561db125b538f5ed Mon Sep 17 00:00:00 2001
+From: Ian Molton <spyro@f2s.com>
+Date: Fri, 4 Jan 2008 18:32:44 +0000
+Subject: [PATCH 03/64] Core MFD support
+
+This patch provides a common subdevice registration system for MFD type
+chips, using platfrom device.
+
+It also provides a new resource type for IRQs such that a subdevices IRQ may
+be computed based on the MFD cores IRQ handler, since many MFDs provide an IRQ
+multiplex.
+---
+ drivers/mfd/Kconfig      |    4 ++
+ drivers/mfd/Makefile     |    2 +
+ drivers/mfd/mfd-core.c   |  116 ++++++++++++++++++++++++++++++++++++++++++++++
+ include/linux/ioport.h   |    1 +
+ include/linux/mfd-core.h |   51 ++++++++++++++++++++
+ 5 files changed, 174 insertions(+), 0 deletions(-)
+ create mode 100644 drivers/mfd/mfd-core.c
+ create mode 100644 include/linux/mfd-core.h
+
+diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig
+index 2571619..1205c89 100644
+--- a/drivers/mfd/Kconfig
++++ b/drivers/mfd/Kconfig
+@@ -5,6 +5,10 @@
+ menu "Multifunction device drivers"
+       depends on HAS_IOMEM
++config MFD_CORE
++      tristate
++      default n
++
+ config MFD_SM501
+       tristate "Support for Silicon Motion SM501"
+        ---help---
+diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile
+index 5143209..6c20064 100644
+--- a/drivers/mfd/Makefile
++++ b/drivers/mfd/Makefile
+@@ -4,6 +4,8 @@
+ obj-$(CONFIG_MFD_SM501)               += sm501.o
++obj-$(CONFIG_MFD_CORE)                += mfd-core.o
++
+ obj-$(CONFIG_MCP)             += mcp-core.o
+ obj-$(CONFIG_MCP_SA11X0)      += mcp-sa11x0.o
+ obj-$(CONFIG_MCP_UCB1200)     += ucb1x00-core.o
+diff --git a/drivers/mfd/mfd-core.c b/drivers/mfd/mfd-core.c
+new file mode 100644
+index 0000000..88874e1
+--- /dev/null
++++ b/drivers/mfd/mfd-core.c
+@@ -0,0 +1,116 @@
++/*
++ * drivers/mfd/mfd-core.c
++ *
++ * core MFD support
++ * Copyright (c) 2006 Ian Molton
++ * Copyright (c) 2007 Dmitry Baryshkov
++ *
++ * 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/kernel.h>
++#include <linux/platform_device.h>
++#include <linux/mfd-core.h>
++
++#define SIGNED_SHIFT(val, shift) ((shift) >= 0 ?      \
++                      ((val) << (shift)) :            \
++                      ((val) >> -(shift)))
++
++int mfd_add_devices(
++              struct platform_device *parent,
++              const struct mfd_cell *cells, int n_devs,
++              struct resource *mem,
++              int relative_addr_shift,
++              int irq_base)
++{
++      int i;
++
++      for (i = 0; i < n_devs; i++) {
++              struct resource *res = NULL;
++              const struct mfd_cell *cell = cells + i;
++              struct platform_device *pdev;
++              int ret = -ENOMEM;
++              int r;
++
++              pdev = platform_device_alloc(cell->name, -1);
++              if (!pdev)
++                      goto fail_alloc;
++
++              pdev->dev.uevent_suppress = 0;
++              pdev->dev.parent = &parent->dev;
++
++              ret = platform_device_add_data(pdev, &cell, sizeof(struct mfd_cell *));
++              if (ret)
++                      goto fail_device;
++
++              res = kzalloc(cell->num_resources * sizeof(struct resource),
++                                                      GFP_KERNEL);
++              if (!res)
++                      goto fail_device;
++
++              for (r = 0; r < cell->num_resources; r++) {
++                      res[r].name = cell->resources[r].name;
++
++                      /* Find out base to use */
++                      if (cell->resources[r].flags & IORESOURCE_MEM) {
++                              res[r].parent = mem;
++                              res[r].start = mem->start +
++                                      SIGNED_SHIFT(cell->resources[r].start,
++                                                      relative_addr_shift);
++                              res[r].end   = mem->start +
++                                      SIGNED_SHIFT(cell->resources[r].end,
++                                                      relative_addr_shift);
++                      } else if ((cell->resources[r].flags & IORESOURCE_IRQ) &&
++                              (cell->resources[r].flags & IORESOURCE_IRQ_MFD_SUBDEVICE)) {
++                              res[r].start = irq_base +
++                                      cell->resources[r].start;
++                              res[r].end   = irq_base +
++                                      cell->resources[r].end;
++                      } else {
++                              res[r].start = cell->resources[r].start;
++                              res[r].end   = cell->resources[r].end;
++                      }
++
++                      res[r].flags = cell->resources[r].flags;
++              }
++
++              ret = platform_device_add_resources(pdev,
++                              res,
++                              cell->num_resources);
++              kfree(res);
++
++              if (ret)
++                      goto fail_device;
++
++              ret = platform_device_add(pdev);
++
++              if (ret) {
++                      platform_device_del(pdev);
++fail_device:
++                      platform_device_put(pdev);
++fail_alloc:
++                      mfd_remove_devices(parent);
++                      return ret;
++              }
++      }
++      return 0;
++}
++EXPORT_SYMBOL(mfd_add_devices);
++
++static int mfd_remove_devices_fn(struct device *dev, void *unused)
++{
++      platform_device_unregister(container_of(dev, struct platform_device, dev));
++      return 0;
++}
++
++void mfd_remove_devices(struct platform_device *parent)
++{
++      device_for_each_child(&parent->dev, NULL, mfd_remove_devices_fn);
++}
++EXPORT_SYMBOL(mfd_remove_devices);
++
++MODULE_LICENSE("GPL");
++MODULE_AUTHOR("Ian Molton, Dmitry Baryshkov");
+diff --git a/include/linux/ioport.h b/include/linux/ioport.h
+index 6187a85..0348c71 100644
+--- a/include/linux/ioport.h
++++ b/include/linux/ioport.h
+@@ -56,6 +56,7 @@ struct resource_list {
+ #define IORESOURCE_IRQ_HIGHLEVEL      (1<<2)
+ #define IORESOURCE_IRQ_LOWLEVEL               (1<<3)
+ #define IORESOURCE_IRQ_SHAREABLE      (1<<4)
++#define IORESOURCE_IRQ_MFD_SUBDEVICE  (1<<5)
+ /* ISA PnP DMA specific bits (IORESOURCE_BITS) */
+ #define IORESOURCE_DMA_TYPE_MASK      (3<<0)
+diff --git a/include/linux/mfd-core.h b/include/linux/mfd-core.h
+new file mode 100644
+index 0000000..0e9de78
+--- /dev/null
++++ b/include/linux/mfd-core.h
+@@ -0,0 +1,51 @@
++#ifndef MFD_CORE_H
++#define MFD_CORE_H
++/*
++ * drivers/mfd/mfd-core.h
++ *
++ * core MFD support
++ * Copyright (c) 2006 Ian Molton
++ * Copyright (c) 2007 Dmitry Baryshkov
++ *
++ * 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/platform_device.h>
++
++struct mfd_cell {
++      const char              *name;
++
++      int                     (*enable)(struct platform_device *dev);
++      int                     (*disable)(struct platform_device *dev);
++      int                     (*suspend)(struct platform_device *dev);
++      int                     (*resume)(struct platform_device *dev);
++
++      void                    *driver_data; /* data passed to drivers */
++
++      /*
++       * This resources can be specified relatievly to the parent device.
++       * For accessing device you should use resources from device
++       */
++      int                     num_resources;
++      const struct resource   *resources;
++};
++
++static inline __maybe_unused struct mfd_cell *
++mfd_get_cell(struct platform_device *pdev)
++{
++      return *((struct mfd_cell **)(pdev->dev.platform_data));
++}
++
++extern int mfd_add_devices(
++              struct platform_device *parent,
++              const struct mfd_cell *cells, int n_devs,
++              struct resource *mem,
++              int relative_addr_shift,
++              int irq_base);
++
++extern void mfd_remove_devices(struct platform_device *parent);
++
++#endif
+-- 
+1.5.3.8
+
diff --git a/packages/kexecboot/linux-kexecboot-2.6.24/tosa/0004-Add-support-for-tc6393xb-MFD-core.patch b/packages/kexecboot/linux-kexecboot-2.6.24/tosa/0004-Add-support-for-tc6393xb-MFD-core.patch
new file mode 100644 (file)
index 0000000..a78c0f3
--- /dev/null
@@ -0,0 +1,907 @@
+From 3f56cac281fb407b7d8e574d18ee7d72aa7e7c28 Mon Sep 17 00:00:00 2001
+From: Ian Molton <spyro@f2s.com>
+Date: Sat, 29 Dec 2007 15:02:30 +0000
+Subject: [PATCH 04/64] Add support for tc6393xb MFD core
+
+---
+ drivers/mfd/Kconfig          |    6 +
+ drivers/mfd/Makefile         |    2 +
+ drivers/mfd/tc6393xb.c       |  740 ++++++++++++++++++++++++++++++++++++++++++
+ include/linux/mfd/tc6393xb.h |  108 ++++++
+ 4 files changed, 856 insertions(+), 0 deletions(-)
+ create mode 100644 drivers/mfd/tc6393xb.c
+ create mode 100644 include/linux/mfd/tc6393xb.h
+
+diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig
+index 1205c89..9903d0a 100644
+--- a/drivers/mfd/Kconfig
++++ b/drivers/mfd/Kconfig
+@@ -9,6 +9,12 @@ config MFD_CORE
+       tristate
+       default n
++config MFD_TC6393XB
++      bool "Support Toshiba TC6393XB"
++      select MFD_CORE
++      help
++        Support for Toshiba Mobile IO Controller TC6393XB
++
+ config MFD_SM501
+       tristate "Support for Silicon Motion SM501"
+        ---help---
+diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile
+index 6c20064..ffd342e 100644
+--- a/drivers/mfd/Makefile
++++ b/drivers/mfd/Makefile
+@@ -6,6 +6,8 @@ obj-$(CONFIG_MFD_SM501)                += sm501.o
+ obj-$(CONFIG_MFD_CORE)                += mfd-core.o
++obj-$(CONFIG_MFD_TC6393XB)    += tc6393xb.o
++
+ obj-$(CONFIG_MCP)             += mcp-core.o
+ obj-$(CONFIG_MCP_SA11X0)      += mcp-sa11x0.o
+ obj-$(CONFIG_MCP_UCB1200)     += ucb1x00-core.o
+diff --git a/drivers/mfd/tc6393xb.c b/drivers/mfd/tc6393xb.c
+new file mode 100644
+index 0000000..9439f39
+--- /dev/null
++++ b/drivers/mfd/tc6393xb.c
+@@ -0,0 +1,740 @@
++/*
++ * Toshiba TC6393XB SoC support
++ *
++ * Copyright(c) 2005-2006 Chris Humbert
++ * Copyright(c) 2005 Dirk Opfer
++ * Copyright(c) 2005 Ian Molton <spyro@f2s.com>
++ * Copyright(c) 2007 Dmitry Baryshkov
++ *
++ * Based on code written by Sharp/Lineo for 2.4 kernels
++ * Based on locomo.c
++ *
++ * 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/kernel.h>
++#include <linux/module.h>
++#include <linux/io.h>
++#include <linux/irq.h>
++#include <linux/platform_device.h>
++#include <linux/fb.h>
++#include <linux/mfd-core.h>
++#include <linux/mfd/tmio.h>
++#include <linux/mfd/tc6393xb.h>
++
++struct tc6393xb_scr {
++      u8 x00[8];
++      u8      revid;          /* 0x08 Revision ID                     */
++      u8 x01[0x47];
++      u8      isr;            /* 0x50 Interrupt Status                */
++      u8 x02;
++      u8      imr;            /* 0x52 Interrupt Mask                  */
++      u8 x03;
++      u8      irr;            /* 0x54 Interrupt Routing               */
++      u8 x04[0x0b];
++      u16     gper;           /* 0x60 GP Enable                       */
++      u8 x05[2];
++      u16     gpi_sr[2];      /* 0x64 GPI Status                      */
++      u16     gpi_imr[2];     /* 0x68 GPI INT Mask                    */
++      u16     gpi_eder[2];    /* 0x6c GPI Edge Detect Enable          */
++      u16     gpi_lir[4];     /* 0x70 GPI Level Invert                */
++      u16     gpo_dsr[2];     /* 0x78 GPO Data Set                    */
++      u16     gpo_doecr[2];   /* 0x7c GPO Data OE Control             */
++      u16     gp_iarcr[2];    /* 0x80 GP Internal Active Reg Control  */
++      u16     gp_iarlcr[2];   /* 0x84 GP Internal Active Reg Level Con*/
++      u8      gpi_bcr[4];     /* 0x88 GPI Buffer Control              */
++      u16     gpa_iarcr;      /* 0x8c GPa Internal Active Reg Control */
++      u8 x06[2];
++      u16     gpa_iarlcr;     /* 0x90 GPa Internal Active Reg Level Co*/
++      u8 x07[2];
++      u16     gpa_bcr;        /* 0x94 GPa Buffer Control              */
++      u8 x08[2];
++      u16     ccr;            /* 0x98 Clock Control                   */
++      u16     pll2cr;         /* 0x9a PLL2 Control                    */
++      u16     pll1cr[2];      /* 0x9c PLL1 Control                    */
++      u8      diarcr;         /* 0xa0 Device Internal Active Reg Contr*/
++      u8      dbocr;          /* 0xa1 Device Buffer Off Control       */
++      u8 x09[0x3e];
++      u8      fer;            /* 0xe0 Function Enable                 */
++      u8 x10[3];
++      u16     mcr;            /* 0xe4 Mode Control                    */
++      u8 x11[0x14];
++      u8      config;         /* 0xfc Configuration Control           */
++      u8 x12[2];
++      u8      debug;          /* 0xff Debug                           */
++} __attribute__ ((packed));
++
++/*--------------------------------------------------------------------------*/
++
++struct tc6393xb {
++      struct tc6393xb_scr __iomem     *scr;
++
++      spinlock_t                      lock; /* protects RMW cycles */
++
++      struct {
++              union tc6393xb_scr_fer  fer;
++              union tc6393xb_scr_ccr  ccr;
++              u8                      gpi_bcr[4];
++      } suspend_state;
++
++      struct resource                 rscr;
++      struct resource                 *iomem;
++      int                             irq;
++};
++
++/*--------------------------------------------------------------------------*/
++
++static int tc6393xb_mmc_enable(struct platform_device *mmc) {
++      struct platform_device          *dev    = to_platform_device(mmc->dev.parent);
++      struct tc6393xb                 *tc6393xb = platform_get_drvdata(dev);
++      struct tc6393xb_scr __iomem     *scr = tc6393xb->scr;
++      union tc6393xb_scr_ccr          ccr;
++      unsigned long                   flags;
++
++      spin_lock_irqsave(&tc6393xb->lock, flags);
++      ccr.raw = ioread16(&scr->ccr);
++      ccr.bits.ck32ken = 1;
++      iowrite16(ccr.raw, &scr->ccr);
++      spin_unlock_irqrestore(&tc6393xb->lock, flags);
++
++      return 0;
++}
++
++static int tc6393xb_mmc_disable(struct platform_device *mmc) {
++      struct platform_device          *dev    = to_platform_device(mmc->dev.parent);
++      struct tc6393xb                 *tc6393xb = platform_get_drvdata(dev);
++      struct tc6393xb_scr __iomem     *scr    = tc6393xb->scr;
++      union tc6393xb_scr_ccr          ccr;
++      unsigned long                   flags;
++
++      spin_lock_irqsave(&tc6393xb->lock, flags);
++      ccr.raw = ioread16(&scr->ccr);
++      ccr.bits.ck32ken = 0;
++      iowrite16(ccr.raw, &scr->ccr);
++      spin_unlock_irqrestore(&tc6393xb->lock, flags);
++
++      return 0;
++}
++
++/*--------------------------------------------------------------------------*/
++
++static int tc6393xb_nand_disable(struct platform_device *nand)
++{
++      return 0;
++}
++
++static int tc6393xb_nand_enable(struct platform_device *nand)
++{
++      struct platform_device          *dev    = to_platform_device(nand->dev.parent);
++      struct tc6393xb                 *tc6393xb = platform_get_drvdata(dev);
++      struct tc6393xb_scr __iomem     *scr    = tc6393xb->scr;
++      unsigned long                   flags;
++
++      spin_lock_irqsave(&tc6393xb->lock, flags);
++
++      /* SMD buffer on */
++      dev_dbg(&dev->dev, "SMD buffer on\n");
++      iowrite8(0xff, scr->gpi_bcr + 1);
++
++      spin_unlock_irqrestore(&tc6393xb->lock, flags);
++
++      return 0;
++}
++
++int tc6393xb_lcd_set_power(struct platform_device *fb, bool on)
++{
++      struct platform_device          *dev    = to_platform_device(fb->dev.parent);
++      struct tc6393xb                 *tc6393xb = platform_get_drvdata(dev);
++      struct tc6393xb_scr __iomem     *scr    = tc6393xb->scr;
++      union tc6393xb_scr_fer          fer;
++      unsigned long                   flags;
++
++      spin_lock_irqsave(&tc6393xb->lock, flags);
++
++      fer.raw = ioread8(&scr->fer);
++      fer.bits.slcden = on ? 1 : 0;
++      iowrite8(fer.raw, &scr->fer);
++
++      spin_unlock_irqrestore(&tc6393xb->lock, flags);
++
++      return 0;
++}
++EXPORT_SYMBOL(tc6393xb_lcd_set_power);
++
++int tc6393xb_lcd_mode(struct platform_device *fb_dev,
++                                      struct fb_videomode *mode) {
++      struct tc6393xb                 *tc6393xb =
++              platform_get_drvdata(to_platform_device(fb_dev->dev.parent));
++      struct tc6393xb_scr __iomem     *scr    = tc6393xb->scr;
++
++      iowrite16(mode->pixclock,               scr->pll1cr + 0);
++      iowrite16(mode->pixclock >> 16,         scr->pll1cr + 1);
++
++      return 0;
++}
++EXPORT_SYMBOL(tc6393xb_lcd_mode);
++
++static int tc6393xb_ohci_disable(struct platform_device *ohci)
++{
++      struct platform_device          *dev    = to_platform_device(ohci->dev.parent);
++      struct tc6393xb                 *tc6393xb = platform_get_drvdata(dev);
++      struct tc6393xb_scr __iomem     *scr    = tc6393xb->scr;
++      union tc6393xb_scr_ccr          ccr;
++      union tc6393xb_scr_fer          fer;
++      unsigned long                   flags;
++
++      spin_lock_irqsave(&tc6393xb->lock, flags);
++
++      fer.raw = ioread8(&scr->fer);
++      fer.bits.usben = 0;
++      iowrite8(fer.raw, &scr->fer);
++
++      ccr.raw = ioread16(&scr->ccr);
++      ccr.bits.usbcken = 0;
++      iowrite16(ccr.raw, &scr->ccr);
++
++      spin_unlock_irqrestore(&tc6393xb->lock, flags);
++
++      return 0;
++}
++
++static int tc6393xb_ohci_enable(struct platform_device *ohci)
++{
++      struct platform_device          *dev    = to_platform_device(ohci->dev.parent);
++      struct tc6393xb                 *tc6393xb = platform_get_drvdata(dev);
++      struct tc6393xb_scr __iomem     *scr    = tc6393xb->scr;
++      union tc6393xb_scr_ccr          ccr;
++      union tc6393xb_scr_fer          fer;
++      unsigned long                   flags;
++
++      spin_lock_irqsave(&tc6393xb->lock, flags);
++
++      ccr.raw = ioread16(&scr->ccr);
++      ccr.bits.usbcken = 1;
++      iowrite16(ccr.raw, &scr->ccr);
++
++      fer.raw = ioread8(&scr->fer);
++      fer.bits.usben = 1;
++      iowrite8(fer.raw, &scr->fer);
++
++      spin_unlock_irqrestore(&tc6393xb->lock, flags);
++
++      return 0;
++}
++
++static int tc6393xb_fb_disable(struct platform_device *fb)
++{
++      struct platform_device          *dev    = to_platform_device(fb->dev.parent);
++      struct tc6393xb                 *tc6393xb = platform_get_drvdata(dev);
++      struct tc6393xb_scr __iomem     *scr    = tc6393xb->scr;
++      union tc6393xb_scr_ccr          ccr;
++      union tc6393xb_scr_fer          fer;
++      unsigned long                   flags;
++
++      spin_lock_irqsave(&tc6393xb->lock, flags);
++
++      /*
++       * FIXME: is this correct or it should be moved to other _disable?
++       */
++      fer.raw = ioread8(&scr->fer);
++      fer.bits.slcden = 0;
++/*    fer.bits.lcdcven = 0; */
++      iowrite8(fer.raw, &scr->fer);
++
++      ccr.raw = ioread16(&scr->ccr);
++      ccr.bits.mclksel = disable;
++      iowrite16(ccr.raw, &scr->ccr);
++
++      spin_unlock_irqrestore(&tc6393xb->lock, flags);
++
++      return 0;
++}
++
++static int tc6393xb_fb_enable(struct platform_device *fb)
++{
++      struct platform_device          *dev    = to_platform_device(fb->dev.parent);
++      struct tc6393xb                 *tc6393xb = platform_get_drvdata(dev);
++      struct tc6393xb_scr __iomem     *scr    = tc6393xb->scr;
++      union tc6393xb_scr_ccr          ccr;
++      unsigned long                   flags;
++
++      spin_lock_irqsave(&tc6393xb->lock, flags);
++
++      ccr.raw = ioread16(&scr->ccr);
++      ccr.bits.mclksel = m48MHz;
++      iowrite16(ccr.raw, &scr->ccr);
++
++      spin_unlock_irqrestore(&tc6393xb->lock, flags);
++
++      return 0;
++}
++
++static int tc6393xb_fb_suspend(struct platform_device *fb)
++{
++      struct platform_device          *dev    = to_platform_device(fb->dev.parent);
++      struct tc6393xb                 *tc6393xb = platform_get_drvdata(dev);
++      struct tc6393xb_scr __iomem     *scr    = tc6393xb->scr;
++      union tc6393xb_scr_ccr          ccr;
++      unsigned long                   flags;
++
++      spin_lock_irqsave(&tc6393xb->lock, flags);
++
++      ccr.raw = ioread16(&scr->ccr);
++      ccr.bits.mclksel = disable;
++      iowrite16(ccr.raw, &scr->ccr);
++
++      spin_unlock_irqrestore(&tc6393xb->lock, flags);
++
++      return 0;
++}
++
++static int tc6393xb_fb_resume(struct platform_device *fb)
++{
++      struct platform_device          *dev    = to_platform_device(fb->dev.parent);
++      struct tc6393xb                 *tc6393xb = platform_get_drvdata(dev);
++      struct tc6393xb_scr __iomem     *scr    = tc6393xb->scr;
++      union tc6393xb_scr_ccr          ccr;
++      unsigned long                   flags;
++
++      spin_lock_irqsave(&tc6393xb->lock, flags);
++
++      ccr.raw = ioread16(&scr->ccr);
++      ccr.bits.mclksel = m48MHz;
++      iowrite16(ccr.raw, &scr->ccr);
++
++      spin_unlock_irqrestore(&tc6393xb->lock, flags);
++
++      return 0;
++}
++
++static struct resource tc6393xb_mmc_resources[] = {
++      {
++              .name   = TMIO_MMC_CONTROL,
++              .start  = 0x800,
++              .end    = 0x9ff,
++              .flags  = IORESOURCE_MEM,
++      },
++      {
++              .name   = TMIO_MMC_CONFIG,
++              .start  = 0x200,
++              .end    = 0x2ff,
++              .flags  = IORESOURCE_MEM,
++      },
++      {
++              .name   = TMIO_MMC_IRQ,
++              .start  = IRQ_TC6393_MMC,
++              .end    = IRQ_TC6393_MMC,
++              .flags  = IORESOURCE_IRQ | IORESOURCE_IRQ_MFD_SUBDEVICE,
++      },
++};
++
++const static struct resource tc6393xb_nand_resources[] = {
++      {
++              .name   = TMIO_NAND_CONFIG,
++              .start  = 0x0100,
++              .end    = 0x01ff,
++              .flags  = IORESOURCE_MEM,
++      },
++      {
++              .name   = TMIO_NAND_CONTROL,
++              .start  = 0x1000,
++              .end    = 0x1007,
++              .flags  = IORESOURCE_MEM,
++      },
++      {
++              .name   = TMIO_NAND_IRQ,
++              .start  = IRQ_TC6393_NAND,
++              .end    = IRQ_TC6393_NAND,
++              .flags  = IORESOURCE_IRQ | IORESOURCE_IRQ_MFD_SUBDEVICE,
++      },
++};
++
++const static struct resource tc6393xb_ohci_resources[] = {
++      {
++              .name   = TMIO_OHCI_CONFIG,
++              .start  = 0x0300,
++              .end    = 0x03ff,
++              .flags  = IORESOURCE_MEM,
++      },
++      {
++              .name   = TMIO_OHCI_CONTROL,
++              .start  = 0x3000,
++              .end    = 0x31ff,
++              .flags  = IORESOURCE_MEM,
++      },
++      {
++              .name   = TMIO_OHCI_SRAM,
++              .start  = 0x010000,
++              .end    = 0x017fff,
++              .flags  = IORESOURCE_MEM,
++      },
++      {
++              .name   = TMIO_OHCI_SRAM_ALIAS,
++              .start  = 0x018000,
++              .end    = 0x01ffff,
++              .flags  = IORESOURCE_MEM,
++      },
++      {
++              .name   = TMIO_OHCI_IRQ,
++              .start  = IRQ_TC6393_OHCI,
++              .end    = IRQ_TC6393_OHCI,
++              .flags  = IORESOURCE_IRQ | IORESOURCE_IRQ_MFD_SUBDEVICE,
++      },
++};
++
++const static struct resource tc6393xb_fb_resources[] = {
++      {
++              .name   = TMIO_FB_CONFIG,
++              .start  = 0x0500,
++              .end    = 0x05ff,
++              .flags  = IORESOURCE_MEM,
++      },
++      {
++              .name   = TMIO_FB_CONTROL,
++              .start  = 0x5000,
++              .end    = 0x51ff,
++              .flags  = IORESOURCE_MEM,
++      },
++      {
++              .name   = TMIO_FB_VRAM,
++              .start  = 0x100000,
++              .end    = 0x1fffff,
++              .flags  = IORESOURCE_MEM,
++      },
++      {
++              .name   = TMIO_FB_IRQ,
++              .start  = IRQ_TC6393_FB,
++              .end    = IRQ_TC6393_FB,
++              .flags  = IORESOURCE_IRQ | IORESOURCE_IRQ_MFD_SUBDEVICE,
++      },
++};
++
++static struct mfd_cell tc6393xb_cells[] = {
++      {
++              .name = "tmio-nand",
++              .enable = tc6393xb_nand_enable,
++              .disable = tc6393xb_nand_disable,
++              .num_resources = ARRAY_SIZE(tc6393xb_nand_resources),
++              .resources = tc6393xb_nand_resources,
++      },
++      {
++              .name = "tmio-ohci",
++              .enable = tc6393xb_ohci_enable,
++              .disable = tc6393xb_ohci_disable,
++              .num_resources = ARRAY_SIZE(tc6393xb_ohci_resources),
++              .resources = tc6393xb_ohci_resources,
++      },
++      {
++              .name = "tmio-fb",
++              .enable = tc6393xb_fb_enable,
++              .disable = tc6393xb_fb_disable,
++              .suspend = tc6393xb_fb_suspend,
++              .resume = tc6393xb_fb_resume,
++              .num_resources = ARRAY_SIZE(tc6393xb_fb_resources),
++              .resources = tc6393xb_fb_resources,
++      },
++      {
++              .name = "tmio-mmc",
++              .enable = tc6393xb_mmc_enable,
++              .disable = tc6393xb_mmc_disable,
++              .num_resources = ARRAY_SIZE(tc6393xb_mmc_resources),
++              .resources = tc6393xb_mmc_resources,
++      },
++};
++
++/*--------------------------------------------------------------------------*/
++
++static void
++tc6393xb_irq(unsigned int irq, struct irq_desc *desc)
++{
++      struct platform_device          *dev    = get_irq_chip_data(irq);
++      struct tc6393xb_platform_data   *tcpd   = dev->dev.platform_data;
++      struct tc6393xb                 *tc6393xb = platform_get_drvdata(dev);
++      struct tc6393xb_scr __iomem     *scr    = tc6393xb->scr;
++      unsigned int                    isr;
++      unsigned int                    i;
++
++      desc->chip->ack(irq);
++
++      while ((isr = ioread8(&scr->isr) & ~ioread8(&scr->imr)))
++              for (i = 0; i < TC6393XB_NR_IRQS; i++) {
++                      if (isr & (1 << i))
++                              desc_handle_irq(tcpd->irq_base + i,
++                                      irq_desc + tcpd->irq_base + i);
++              }
++}
++
++static void tc6393xb_irq_ack(unsigned int irq)
++{
++}
++
++static void tc6393xb_irq_mask(unsigned int irq)
++{
++      struct platform_device          *dev    = get_irq_chip_data(irq);
++      struct tc6393xb_platform_data   *tcpd   = dev->dev.platform_data;
++      struct tc6393xb                 *tc6393xb = platform_get_drvdata(dev);
++      struct tc6393xb_scr __iomem     *scr    = tc6393xb->scr;
++      unsigned long                   flags;
++
++      spin_lock_irqsave(&tc6393xb->lock, flags);
++      iowrite8(ioread8(&scr->imr) | (1 << (irq - tcpd->irq_base)),
++                                                              &scr->imr);
++      spin_unlock_irqrestore(&tc6393xb->lock, flags);
++}
++
++static void tc6393xb_irq_unmask(unsigned int irq)
++{
++      struct platform_device          *dev    = get_irq_chip_data(irq);
++      struct tc6393xb_platform_data   *tcpd   = dev->dev.platform_data;
++      struct tc6393xb                 *tc6393xb = platform_get_drvdata(dev);
++      struct tc6393xb_scr __iomem     *scr    = tc6393xb->scr;
++      unsigned long                   flags;
++
++      spin_lock_irqsave(&tc6393xb->lock, flags);
++      iowrite8(ioread8(&scr->imr) & ~(1 << (irq - tcpd->irq_base)),
++                                                              &scr->imr);
++      spin_unlock_irqrestore(&tc6393xb->lock, flags);
++}
++
++static struct irq_chip tc6393xb_chip = {
++      .name   = "tc6393xb",
++      .ack    = tc6393xb_irq_ack,
++      .mask   = tc6393xb_irq_mask,
++      .unmask = tc6393xb_irq_unmask,
++};
++
++static void tc6393xb_attach_irq(struct platform_device *dev)
++{
++      struct tc6393xb_platform_data   *tcpd   = dev->dev.platform_data;
++      struct tc6393xb                 *tc6393xb = platform_get_drvdata(dev);
++      unsigned int                    irq;
++
++      for (
++                      irq = tcpd->irq_base;
++                      irq <= tcpd->irq_base + TC6393XB_NR_IRQS;
++                      irq++) {
++              set_irq_chip(irq, &tc6393xb_chip);
++              set_irq_chip_data(irq, dev);
++              set_irq_handler(irq, handle_edge_irq);
++              set_irq_flags(irq, IRQF_VALID | IRQF_PROBE);
++      }
++
++      set_irq_type(tc6393xb->irq, IRQT_FALLING);
++      set_irq_chip_data(tc6393xb->irq, dev);
++      set_irq_chained_handler(tc6393xb->irq, tc6393xb_irq);
++}
++
++static void tc6393xb_detach_irq(struct platform_device *dev)
++{
++      struct tc6393xb_platform_data   *tcpd   = dev->dev.platform_data;
++      struct tc6393xb                 *tc6393xb = platform_get_drvdata(dev);
++      unsigned int                    irq;
++
++      set_irq_chained_handler(tc6393xb->irq, NULL);
++      set_irq_chip_data(tc6393xb->irq, NULL);
++
++      for (
++                      irq = tcpd->irq_base;
++                      irq <= tcpd->irq_base + TC6393XB_NR_IRQS;
++                      irq++) {
++              set_irq_flags(irq, 0);
++              set_irq_chip(irq, NULL);
++              set_irq_chip_data(irq, NULL);
++      }
++}
++
++static int tc6393xb_hw_init(struct platform_device *dev, int resume)
++{
++      struct tc6393xb_platform_data   *tcpd   = dev->dev.platform_data;
++      struct tc6393xb                 *tc6393xb = platform_get_drvdata(dev);
++      struct tc6393xb_scr __iomem     *scr    = tc6393xb->scr;
++      int                             ret;
++      int                             i;
++
++      if (resume)
++              ret = tcpd->resume(dev);
++      else
++              ret = tcpd->enable(dev);
++      if (ret)
++              return ret;
++
++      iowrite8(resume ?
++              tc6393xb->suspend_state.fer.raw :
++              0,                              &scr->fer);
++      iowrite16(tcpd->scr_pll2cr,             &scr->pll2cr);
++      iowrite16(resume?
++              tc6393xb->suspend_state.ccr.raw :
++              tcpd->scr_ccr.raw,              &scr->ccr);
++      iowrite16(tcpd->scr_mcr.raw,            &scr->mcr);
++      iowrite16(tcpd->scr_gper,               &scr->gper);
++      iowrite8(0,                             &scr->irr);
++      iowrite8(0xbf,                          &scr->imr);
++      iowrite16(tcpd->scr_gpo_dsr,            scr->gpo_dsr + 0);
++      iowrite16(tcpd->scr_gpo_dsr >> 16,      scr->gpo_dsr + 1);
++      iowrite16(tcpd->scr_gpo_doecr,          scr->gpo_doecr + 0);
++      iowrite16(tcpd->scr_gpo_doecr >> 16,    scr->gpo_doecr + 1);
++
++      if (resume)
++              for (i = 0; i < 4; i++)
++                      iowrite8(tc6393xb->suspend_state.gpi_bcr[i],
++                                              scr->gpi_bcr + i);
++
++      return 0;
++}
++
++static int __devinit tc6393xb_probe(struct platform_device *dev)
++{
++      struct tc6393xb_platform_data *tcpd     = dev->dev.platform_data;
++      struct tc6393xb         *tc6393xb;
++      struct resource         *iomem;
++      struct resource         *rscr;
++      int                     retval;
++
++      iomem = platform_get_resource(dev, IORESOURCE_MEM, 0);
++      if (!iomem)
++              return -EINVAL;
++
++      tc6393xb = kzalloc(sizeof *tc6393xb, GFP_KERNEL);
++      if (!tc6393xb) {
++              retval = -ENOMEM;
++              goto err_kzalloc;
++      }
++
++      spin_lock_init(&tc6393xb->lock);
++
++      platform_set_drvdata(dev, tc6393xb);
++      tc6393xb->iomem = iomem;
++      tc6393xb->irq   = platform_get_irq(dev, 0);
++
++      rscr            = &tc6393xb->rscr;
++      rscr->name      = "tc6393xb-core";
++      rscr->start     = iomem->start;
++      rscr->end       = iomem->start + 0xff;
++      rscr->flags     = IORESOURCE_MEM;
++
++      retval = request_resource(iomem, rscr);
++      if (retval)
++              goto err_request_scr;
++
++      tc6393xb->scr   = ioremap(rscr->start, rscr->end - rscr->start + 1);
++      if (!tc6393xb->scr) {
++              retval = -ENOMEM;
++              goto err_ioremap;
++      }
++
++      retval = tc6393xb_hw_init(dev, 0);
++      if (retval)
++              goto err_hw_init;
++
++      printk(KERN_INFO "Toshiba tc6393xb revision %d at 0x%08lx, irq %d\n",
++                      ioread8(&tc6393xb->scr->revid),
++                      (unsigned long) iomem->start, tc6393xb->irq);
++
++      if (tc6393xb->irq)
++              tc6393xb_attach_irq(dev);
++
++      tc6393xb_cells[0].driver_data = tcpd->nand_data;
++      tc6393xb_cells[1].driver_data = NULL; /* tcpd->ohci_data; */
++      tc6393xb_cells[2].driver_data = tcpd->fb_data;
++
++      retval = mfd_add_devices(dev,
++                      tc6393xb_cells, ARRAY_SIZE(tc6393xb_cells),
++                      iomem, 0, tcpd->irq_base);
++
++      if (retval == 0)
++              return 0;
++
++      if (tc6393xb->irq)
++              tc6393xb_detach_irq(dev);
++
++err_hw_init:
++      iounmap(tc6393xb->scr);
++err_ioremap:
++      release_resource(rscr);
++err_request_scr:
++      kfree(tc6393xb);
++err_kzalloc:
++      release_resource(iomem);
++      return retval;
++}
++
++static int __devexit tc6393xb_remove(struct platform_device *dev) {
++      struct tc6393xb_platform_data   *tcpd   = dev->dev.platform_data;
++      struct tc6393xb                 *tc6393xb = platform_get_drvdata(dev);
++      int ret;
++
++      if (tc6393xb->irq)
++              tc6393xb_detach_irq(dev);
++
++      ret = tcpd->disable(dev);
++
++      iounmap(tc6393xb->scr);
++      release_resource(&tc6393xb->rscr);
++      release_resource(tc6393xb->iomem);
++
++      mfd_remove_devices(dev);
++
++      platform_set_drvdata(dev, NULL);
++
++      kfree(tc6393xb);
++
++      return ret;
++}
++
++#ifdef CONFIG_PM
++static int tc6393xb_suspend(struct platform_device *dev, pm_message_t state)
++{
++      struct tc6393xb_platform_data   *tcpd   = dev->dev.platform_data;
++      struct tc6393xb                 *tc6393xb = platform_get_drvdata(dev);
++      struct tc6393xb_scr __iomem     *scr = tc6393xb->scr;
++      int i;
++
++
++      tc6393xb->suspend_state.ccr.raw         = ioread16(&scr->ccr);
++      tc6393xb->suspend_state.fer.raw         = ioread8(&scr->fer);
++      for (i = 0; i < 4; i++)
++              tc6393xb->suspend_state.gpi_bcr[i] =
++                      ioread8(scr->gpi_bcr + i);
++
++      return tcpd->suspend(dev);
++}
++
++static int tc6393xb_resume(struct platform_device *dev)
++{
++      return tc6393xb_hw_init(dev, 1);
++}
++#else
++#define tc6393xb_suspend NULL
++#define tc6393xb_resume NULL
++#endif
++
++static struct platform_driver tc6393xb_driver = {
++      .probe = tc6393xb_probe,
++      .remove = __devexit_p(tc6393xb_remove),
++      .suspend = tc6393xb_suspend,
++      .resume = tc6393xb_resume,
++
++      .driver = {
++              .name = "tc6393xb",
++              .owner          = THIS_MODULE,
++      },
++};
++
++static int __init tc6393xb_init(void)
++{
++      return platform_driver_register(&tc6393xb_driver);
++}
++
++static void __exit tc6393xb_exit(void)
++{
++      platform_driver_unregister(&tc6393xb_driver);
++}
++
++module_init(tc6393xb_init);
++module_exit(tc6393xb_exit);
++
++MODULE_LICENSE("GPL");
++MODULE_AUTHOR("Ian Molton, Dmitry Baryshkov and Dirk Opfer");
++MODULE_DESCRIPTION("tc6393xb Toshiba Mobile IO Controller");
+diff --git a/include/linux/mfd/tc6393xb.h b/include/linux/mfd/tc6393xb.h
+new file mode 100644
+index 0000000..e699294
+--- /dev/null
++++ b/include/linux/mfd/tc6393xb.h
+@@ -0,0 +1,108 @@
++/*
++ * Toshiba TC6393XB SoC support
++ *
++ * Copyright(c) 2005-2006 Chris Humbert
++ * Copyright(c) 2005 Dirk Opfer
++ * Copyright(c) 2005 Ian Molton <spyro@f2s.com>
++ * Copyright(c) 2007 Dmitry Baryshkov
++ *
++ * Based on code written by Sharp/Lineo for 2.4 kernels
++ * Based on locomo.c
++ *
++ * 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.
++ */
++
++#ifndef TC6393XB_H
++#define TC6393XB_H
++
++#include <linux/mfd-core.h>
++#include <linux/mfd/tmio.h>
++
++union tc6393xb_scr_fer {
++      u8              raw;
++struct {
++      unsigned        usben:1;        /* D0   USB enable              */
++      unsigned        lcdcven:1;      /* D1   polysylicon TFT enable  */
++      unsigned        slcden:1;       /* D2   SLCD enable             */
++} __attribute__ ((packed)) bits;
++} __attribute__ ((packed));
++
++union tc6393xb_scr_ccr {
++      u16             raw;
++struct {
++      unsigned        ck32ken:1;      /* D0   SD host clock enable    */
++      unsigned        usbcken:1;      /* D1   USB host clock enable   */
++      unsigned        x00:2;
++      unsigned        sharp:1;        /* D4   ??? set in Sharp's code */
++      unsigned        x01:3;
++      enum {                          disable = 0,
++                                      m12MHz  = 1,
++                                      m24MHz  = 2,
++                                      m48MHz  = 3,
++      }               mclksel:3;      /* D10-D8  LCD controller clock */
++      unsigned        x02:1;
++      enum {                          h24MHz  = 0,
++                                      h48MHz  = 1,
++      }               hclksel:2;      /* D13-D12 host bus clock       */
++      unsigned        x03:2;
++} __attribute__ ((packed)) bits;
++} __attribute__ ((packed));
++
++enum pincontrol {
++      opendrain       = 0,
++      tristate        = 1,
++      pushpull        = 2,
++      /* reserved     = 3, */
++};
++
++union tc6393xb_scr_mcr {
++      u16             raw;
++struct {
++      enum pincontrol rdyst:2;        /* D1-D0   HRDY control         */
++      unsigned        x00:1;
++      unsigned        aren:1;         /* D3      HRDY pull up resistance cut off */
++      enum pincontrol intst:2;        /* D5-D4   #HINT control        */
++      unsigned        x01:1;
++      unsigned        aien:1;         /* D7      #HINT pull up resitance cut off */
++      unsigned        x02:8;
++} __attribute__ ((packed)) bits;
++} __attribute__ ((packed));
++
++struct tc6393xb_platform_data {
++      u16     scr_pll2cr;     /* PLL2 Control */
++      union tc6393xb_scr_ccr  scr_ccr;        /* Clock Control */
++      union tc6393xb_scr_mcr  scr_mcr;        /* Mode Control */
++      u16     scr_gper;       /* GP Enable */
++      u32     scr_gpo_doecr;  /* GPO Data OE Control */
++      u32     scr_gpo_dsr;    /* GPO Data Set */
++
++      int     (*enable)(struct platform_device *dev);
++      int     (*disable)(struct platform_device *dev);
++      int     (*suspend)(struct platform_device *dev);
++      int     (*resume)(struct platform_device *dev);
++
++      int     irq_base;       /* a base for cascaded irq */
++
++      struct tmio_nand_data   *nand_data;
++      struct tmio_fb_data     *fb_data;
++};
++
++extern int tc6393xb_lcd_set_power(struct platform_device *fb_dev, bool on);
++extern int tc6393xb_lcd_mode(struct platform_device *fb_dev,
++                                      struct fb_videomode *mode);
++
++
++/*
++ * Relative to irq_base
++ */
++#define       IRQ_TC6393_NAND         0
++#define       IRQ_TC6393_MMC          1
++#define       IRQ_TC6393_OHCI         2
++#define       IRQ_TC6393_SERIAL       3
++#define       IRQ_TC6393_FB           4
++
++#define       TC6393XB_NR_IRQS        8
++
++#endif
+-- 
+1.5.3.8
+
diff --git a/packages/kexecboot/linux-kexecboot-2.6.24/tosa/0005-Add-support-for-tc6387xb-MFD-core.patch b/packages/kexecboot/linux-kexecboot-2.6.24/tosa/0005-Add-support-for-tc6387xb-MFD-core.patch
new file mode 100644 (file)
index 0000000..7183e3a
--- /dev/null
@@ -0,0 +1,249 @@
+From a6a6faf1dbb90c950fe55a1719720457bfb5830a Mon Sep 17 00:00:00 2001
+From: Ian Molton <spyro@f2s.com>
+Date: Sun, 16 Dec 2007 02:19:49 +0000
+Subject: [PATCH 05/64] Add support for tc6387xb MFD core
+
+---
+ drivers/mfd/Kconfig          |    6 ++
+ drivers/mfd/Makefile         |    1 +
+ drivers/mfd/tc6387xb.c       |  163 ++++++++++++++++++++++++++++++++++++++++++
+ include/linux/mfd/tc6387xb.h |   28 +++++++
+ 4 files changed, 198 insertions(+), 0 deletions(-)
+ create mode 100644 drivers/mfd/tc6387xb.c
+ create mode 100644 include/linux/mfd/tc6387xb.h
+
+diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig
+index 9903d0a..1575323 100644
+--- a/drivers/mfd/Kconfig
++++ b/drivers/mfd/Kconfig
+@@ -9,6 +9,12 @@ config MFD_CORE
+       tristate
+       default n
++config MFD_TC6387XB
++      bool "Support Toshiba TC6387XB"
++      select MFD_CORE
++      help
++        Support for Toshiba Mobile IO Controller TC6387XB
++
+ config MFD_TC6393XB
+       bool "Support Toshiba TC6393XB"
+       select MFD_CORE
+diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile
+index ffd342e..41b2190 100644
+--- a/drivers/mfd/Makefile
++++ b/drivers/mfd/Makefile
+@@ -6,6 +6,7 @@ obj-$(CONFIG_MFD_SM501)                += sm501.o
+ obj-$(CONFIG_MFD_CORE)                += mfd-core.o
++obj-$(CONFIG_MFD_TC6387XB)    += tc6387xb.o
+ obj-$(CONFIG_MFD_TC6393XB)    += tc6393xb.o
+ obj-$(CONFIG_MCP)             += mcp-core.o
+diff --git a/drivers/mfd/tc6387xb.c b/drivers/mfd/tc6387xb.c
+new file mode 100644
+index 0000000..c81fca2
+--- /dev/null
++++ b/drivers/mfd/tc6387xb.c
+@@ -0,0 +1,163 @@
++/*
++ * Toshiba TC6387XB support
++ * Copyright (c) 2005 Ian Molton
++ *
++ * 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.
++ *
++ * This file contains TC6387XB base support.
++ *
++ */
++
++#include <linux/module.h>
++#include <linux/init.h>
++#include <linux/delay.h>
++#include <linux/platform_device.h>
++
++#include <asm/hardware.h>
++#include <asm/mach-types.h>
++
++#include <linux/mfd-core.h>
++#include <linux/mfd/tc6387xb.h>
++
++#ifdef CONFIG_PM
++static int tc6387xb_suspend(struct platform_device *dev, pm_message_t state)
++{
++      struct tc6387xb_platform_data *pdata = platform_get_drvdata(dev);
++
++      if (pdata && pdata->suspend)
++              pdata->suspend(dev);
++
++      return 0;
++}
++
++static int tc6387xb_resume(struct platform_device *dev)
++{
++      struct tc6387xb_platform_data *pdata = platform_get_drvdata(dev);
++
++      if (pdata && pdata->resume)
++              pdata->resume(dev);
++
++      return 0;
++}
++#else
++#define tc6387xb_suspend  NULL
++#define tc6387xb_resume   NULL
++#endif
++
++/*--------------------------------------------------------------------------*/
++
++static int tc6387xb_mmc_enable(struct platform_device *mmc) {
++      struct platform_device *dev      = to_platform_device(mmc->dev.parent);
++      struct tc6387xb_platform_data *tc6387xb = dev->dev.platform_data;
++
++      if(tc6387xb->enable_mmc_clock)
++              tc6387xb->enable_mmc_clock(dev);
++
++      return 0;
++}
++
++static int tc6387xb_mmc_disable(struct platform_device *mmc) {
++      struct platform_device *dev      = to_platform_device(mmc->dev.parent);
++      struct tc6387xb_platform_data *tc6387xb = dev->dev.platform_data;
++
++      if(tc6387xb->disable_mmc_clock)
++              tc6387xb->disable_mmc_clock(dev);
++
++      return 0;
++}
++
++
++/*--------------------------------------------------------------------------*/
++
++static struct resource tc6387xb_mmc_resources[] = {
++      {
++              .name = TMIO_MMC_CONTROL,
++              .start = 0x800,
++              .end   = 0x9ff,
++              .flags = IORESOURCE_MEM,
++      },
++      {
++              .name = TMIO_MMC_CONFIG,
++              .start = 0x200,
++              .end   = 0x2ff,
++              .flags = IORESOURCE_MEM,
++      },
++      {
++              .name  = TMIO_MMC_IRQ,
++              .start = 0,
++              .end   = 0,
++              .flags = IORESOURCE_IRQ | IORESOURCE_IRQ_MFD_SUBDEVICE,
++      },
++};
++
++static struct mfd_cell tc6387xb_cells[] = {
++      {
++              .name = "tmio-mmc",
++              .enable = tc6387xb_mmc_enable,
++              .disable = tc6387xb_mmc_disable,
++              .num_resources = ARRAY_SIZE(tc6387xb_mmc_resources),
++              .resources = tc6387xb_mmc_resources,
++      },
++};
++
++static int tc6387xb_probe(struct platform_device *dev)
++{
++      struct tc6387xb_platform_data *data = platform_get_drvdata(dev);
++      struct resource *iomem;
++      int irq;
++
++      iomem = platform_get_resource(dev, IORESOURCE_MEM, 0);
++      if (!iomem)
++              return -EINVAL;
++
++      irq   = platform_get_irq(dev, 0);
++
++      if(data && data->enable)
++              data->enable(dev);
++
++      printk(KERN_INFO "Toshiba tc6393xb initialised\n");
++
++      return mfd_add_devices(dev, tc6387xb_cells, ARRAY_SIZE(tc6387xb_cells),
++                             iomem, 0, irq);
++}
++
++static int tc6387xb_remove(struct platform_device *dev)
++{
++      struct tc6387xb_platform_data *data = platform_get_drvdata(dev);
++
++      if(data && data->disable)
++              data->disable(dev);
++
++      return 0;
++}
++
++
++static struct platform_driver tc6387xb_platform_driver = {
++      .driver = {
++              .name           = "tc6387xb",
++      },
++      .probe          = tc6387xb_probe,
++      .remove         = tc6387xb_remove,
++      .suspend        = tc6387xb_suspend,
++      .resume         = tc6387xb_resume,
++};
++
++
++static int __init tc6387xb_init(void)
++{
++      return platform_driver_register (&tc6387xb_platform_driver);
++}
++
++static void __exit tc6387xb_exit(void)
++{
++      platform_driver_unregister(&tc6387xb_platform_driver);
++}
++
++module_init(tc6387xb_init);
++module_exit(tc6387xb_exit);
++
++MODULE_DESCRIPTION("Toshiba TC6387XB core driver");
++MODULE_LICENSE("GPLv2");
++MODULE_AUTHOR("Ian Molton");
+diff --git a/include/linux/mfd/tc6387xb.h b/include/linux/mfd/tc6387xb.h
+new file mode 100644
+index 0000000..496770b
+--- /dev/null
++++ b/include/linux/mfd/tc6387xb.h
+@@ -0,0 +1,28 @@
++/*
++ * linux/include/asm-arm/hardware/tc6387xb.h
++ *
++ * This file contains the definitions for the TC6393XB
++ *
++ * (C) Copyright 2005 Ian Molton <spyro@f2s.com>
++ *
++ * May be copied or modified under the terms of the GNU General Public
++ * License.  See linux/COPYING for more information.
++ *
++ */
++#ifndef MFD_T7L66XB_H
++#define MFD_T7L66XB_H
++
++#include <linux/mfd-core.h>
++#include <linux/mfd/tmio.h>
++
++struct tc6387xb_platform_data
++{
++      int (*enable_mmc_clock)(struct platform_device *dev);
++      int (*disable_mmc_clock)(struct platform_device *dev);
++      int (*enable)(struct platform_device *dev);
++      int (*disable)(struct platform_device *dev);
++      int (*suspend)(struct platform_device *dev);
++      int (*resume)(struct platform_device *dev);
++};
++
++#endif
+-- 
+1.5.3.8
+
diff --git a/packages/kexecboot/linux-kexecboot-2.6.24/tosa/0006-Add-support-for-t7l66xb-MFD-core.patch b/packages/kexecboot/linux-kexecboot-2.6.24/tosa/0006-Add-support-for-t7l66xb-MFD-core.patch
new file mode 100644 (file)
index 0000000..e7aff24
--- /dev/null
@@ -0,0 +1,653 @@
+From 2e31fea352ca97988452f1f2c94809de2977ce40 Mon Sep 17 00:00:00 2001
+From: Ian Molton <spyro@f2s.com>
+Date: Sat, 29 Dec 2007 15:08:52 +0000
+Subject: [PATCH 06/64] Add support for t7l66xb MFD core
+
+---
+ drivers/mfd/Kconfig         |    6 +
+ drivers/mfd/Makefile        |    1 +
+ drivers/mfd/t7l66xb.c       |  550 +++++++++++++++++++++++++++++++++++++++++++
+ include/linux/mfd/t7l66xb.h |   45 ++++
+ 4 files changed, 602 insertions(+), 0 deletions(-)
+ create mode 100644 drivers/mfd/t7l66xb.c
+ create mode 100644 include/linux/mfd/t7l66xb.h
+
+diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig
+index 1575323..f79a969 100644
+--- a/drivers/mfd/Kconfig
++++ b/drivers/mfd/Kconfig
+@@ -9,6 +9,12 @@ config MFD_CORE
+       tristate
+       default n
++config MFD_T7L66XB
++      bool "Support Toshiba T7L66XB"
++      select MFD_CORE
++      help
++        Support for Toshiba Mobile IO Controller T7L66XB
++
+ config MFD_TC6387XB
+       bool "Support Toshiba TC6387XB"
+       select MFD_CORE
+diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile
+index 41b2190..b2037ae 100644
+--- a/drivers/mfd/Makefile
++++ b/drivers/mfd/Makefile
+@@ -6,6 +6,7 @@ obj-$(CONFIG_MFD_SM501)                += sm501.o
+ obj-$(CONFIG_MFD_CORE)                += mfd-core.o
++obj-$(CONFIG_MFD_T7L66XB)     += t7l66xb.o
+ obj-$(CONFIG_MFD_TC6387XB)    += tc6387xb.o
+ obj-$(CONFIG_MFD_TC6393XB)    += tc6393xb.o
+diff --git a/drivers/mfd/t7l66xb.c b/drivers/mfd/t7l66xb.c
+new file mode 100644
+index 0000000..308776a
+--- /dev/null
++++ b/drivers/mfd/t7l66xb.c
+@@ -0,0 +1,550 @@
++/*
++ *
++ * Toshiba T7L66XB core mfd support
++ *
++ * Copyright (c) 2005 Ian Molton
++ * Copyright (c) 2007 Ian Molton
++ *
++ * 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.
++ *
++ * T7L66 features:
++ *
++ * Supported in this driver:
++ * SD/MMC
++ * SM/NAND flash controller
++ * OHCI controller
++ *
++ * As yet not supported
++ * GPIO interface (on NAND pins)
++ * Serial interface
++ * TFT 'interface converter'
++ * PCMCIA interface logic
++ */
++
++#include <linux/kernel.h>
++#include <linux/module.h>
++#include <linux/io.h>
++#include <linux/irq.h>
++#include <linux/platform_device.h>
++#include <linux/fb.h>
++#include <linux/mfd-core.h>
++#include <linux/mfd/tmio.h>
++#include <linux/mfd/t7l66xb.h>
++
++union t7l66xb_dev_ctl {
++        u8             raw;
++struct {
++        unsigned        usb_en:1;      /* D0   USB enable   */
++        unsigned        mmc_en:1;      /* D1   MMC enable   */
++} __attribute__ ((packed));
++} __attribute__ ((packed));
++
++
++struct t7l66xb_scr {
++        u8 x00[8];
++        u8      revid;          /* 0x08 Revision ID                     */
++        u8 x01[57];
++        u8      imr;            /* 0x42 Interrupt Mask                  */
++      u8 x03[157];
++        union t7l66xb_dev_ctl     dev_ctl; /* 0xe0 Device control       */
++        u8      isr;            /* 0xe1 Interrupt Status                */
++        u8 x04[14];
++        u8      gpio_output_ctl;    /* 0xf0 */
++        u8      gpio_output_status; /* 0xf1 */
++        u16     gpio_input_status;  /* 0xf2 */
++        u8 x05[4];
++        u8      active_pullup_down_ctl; /* 0xf8 */
++        u8 x06[7];
++} __attribute__ ((packed));
++
++
++/*--------------------------------------------------------------------------*/
++
++struct t7l66xb
++{
++      struct t7l66xb_scr __iomem     *scr;
++      spinlock_t                      lock;
++
++      struct resource                 rscr;
++      struct resource                 *iomem;
++      int                             irq;
++};
++
++/*--------------------------------------------------------------------------*/
++
++static int t7l66xb_ohci_enable(struct platform_device *ohci)
++{
++        struct platform_device          *dev    = to_platform_device(ohci->dev.parent);
++        struct t7l66xb                  *t7l66xb = platform_get_drvdata(dev);
++        struct t7l66xb_scr __iomem      *scr    = t7l66xb->scr;
++        unsigned long                   flags;
++      union t7l66xb_dev_ctl           dev_ctl;
++
++        spin_lock_irqsave(&t7l66xb->lock, flags);
++
++        dev_ctl.raw = readb(&scr->dev_ctl);
++        dev_ctl.usb_en = 1;
++        writeb(dev_ctl.raw, &scr->dev_ctl);
++
++        spin_unlock_irqrestore(&t7l66xb->lock, flags);
++
++        return 0;
++}
++
++static int t7l66xb_ohci_disable(struct platform_device *ohci)
++{
++        struct platform_device          *dev    = to_platform_device(ohci->dev.parent);
++        struct t7l66xb                  *t7l66xb = platform_get_drvdata(dev);
++        struct t7l66xb_scr __iomem      *scr    = t7l66xb->scr;
++        unsigned long                   flags;
++        union t7l66xb_dev_ctl           dev_ctl;
++
++        spin_lock_irqsave(&t7l66xb->lock, flags);
++
++        dev_ctl.raw = readb(&scr->dev_ctl);
++        dev_ctl.usb_en = 0;
++        writeb(dev_ctl.raw, &scr->dev_ctl);
++
++        spin_unlock_irqrestore(&t7l66xb->lock, flags);
++
++        return 0;
++}
++
++/*--------------------------------------------------------------------------*/
++
++static int t7l66xb_mmc_enable(struct platform_device *ohci)
++{
++        struct platform_device          *dev    = to_platform_device(ohci->dev.parent);
++        struct t7l66xb_platform_data   *pdata = dev->dev.platform_data;
++        struct t7l66xb                  *t7l66xb = platform_get_drvdata(dev);
++        struct t7l66xb_scr __iomem      *scr    = t7l66xb->scr;
++        unsigned long                   flags;
++      union t7l66xb_dev_ctl           dev_ctl;
++
++        spin_lock_irqsave(&t7l66xb->lock, flags);
++
++        if(pdata->enable_clk32k)
++                pdata->enable_clk32k(dev);
++        dev_ctl.raw = readb(&scr->dev_ctl);
++        dev_ctl.mmc_en = 1;
++        writeb(dev_ctl.raw, &scr->dev_ctl);
++
++        spin_unlock_irqrestore(&t7l66xb->lock, flags);
++
++        return 0;
++}
++
++static int t7l66xb_mmc_disable(struct platform_device *ohci)
++{
++        struct platform_device          *dev    = to_platform_device(ohci->dev.parent);
++        struct t7l66xb_platform_data   *pdata = dev->dev.platform_data;
++        struct t7l66xb                  *t7l66xb = platform_get_drvdata(dev);
++        struct t7l66xb_scr __iomem      *scr    = t7l66xb->scr;
++        unsigned long                   flags;
++        union t7l66xb_dev_ctl           dev_ctl;
++
++        spin_lock_irqsave(&t7l66xb->lock, flags);
++
++        dev_ctl.raw = readb(&scr->dev_ctl);
++        dev_ctl.mmc_en = 0;
++        writeb(dev_ctl.raw, &scr->dev_ctl);
++        if(pdata->disable_clk32k)
++                pdata->disable_clk32k(dev);
++
++        spin_unlock_irqrestore(&t7l66xb->lock, flags);
++
++        return 0;
++}
++
++/*--------------------------------------------------------------------------*/
++
++static int t7l66xb_nand_disable(struct platform_device *nand)
++{
++        struct platform_device          *dev    = to_platform_device(nand->dev.parent);
++        struct t7l66xb                  *t7l66xb = platform_get_drvdata(dev);
++        struct t7l66xb_scr __iomem      *scr    = t7l66xb->scr;
++        unsigned long                   flags;
++        union t7l66xb_dev_ctl           dev_ctl;
++
++        spin_lock_irqsave(&t7l66xb->lock, flags);
++
++        dev_ctl.raw = readb(&scr->dev_ctl);
++//        dev_ctl.nand_en = 0;
++        writeb(dev_ctl.raw, &scr->dev_ctl);
++
++        spin_unlock_irqrestore(&t7l66xb->lock, flags);
++
++      return 0;
++}
++
++static int t7l66xb_nand_enable(struct platform_device *nand)
++{
++        struct platform_device          *dev    = to_platform_device(nand->dev.parent);
++        struct t7l66xb                  *t7l66xb = platform_get_drvdata(dev);
++        struct t7l66xb_scr __iomem      *scr    = t7l66xb->scr;
++        unsigned long                   flags;
++        union t7l66xb_dev_ctl           dev_ctl;
++
++        spin_lock_irqsave(&t7l66xb->lock, flags);
++
++        dev_ctl.raw = readb(&scr->dev_ctl);
++ //       dev_ctl.nand_en = 1;
++        writeb(dev_ctl.raw, &scr->dev_ctl);
++
++        spin_unlock_irqrestore(&t7l66xb->lock, flags);
++
++      return 0;
++}
++
++/*--------------------------------------------------------------------------*/
++
++const static struct resource t7l66xb_mmc_resources[] = {
++      {
++              .name = TMIO_MMC_CONTROL,
++              .start = 0x800,
++              .end   = 0x9ff,
++              .flags = IORESOURCE_MEM,
++      },
++      {
++              .name = TMIO_MMC_CONFIG,
++              .start = 0x200,
++              .end   = 0x2ff,
++              .flags = IORESOURCE_MEM,
++      },
++      {
++              .name  = TMIO_MMC_IRQ,
++              .start = IRQ_T7L66XB_MMC,
++              .end   = IRQ_T7L66XB_MMC,
++              .flags = IORESOURCE_IRQ | IORESOURCE_IRQ_MFD_SUBDEVICE,
++      },
++};
++
++const static struct resource t7l66xb_ohci_resources[] = {
++        {
++                .name   = TMIO_OHCI_CONFIG,
++                .start  = 0x0300,
++                .end    = 0x03ff,
++                .flags  = IORESOURCE_MEM,
++        },
++        {
++                .name   = TMIO_OHCI_CONTROL,
++                .start  = 0xa00,
++                .end    = 0xbff,
++                .flags  = IORESOURCE_MEM,
++        },
++        {
++                .name   = TMIO_OHCI_SRAM,
++                .start  = 0x01000,
++                .end    = 0x02fff,
++                .flags  = IORESOURCE_MEM,
++        },
++        {
++                .name   = TMIO_OHCI_IRQ,
++                .start  = IRQ_T7L66XB_OHCI,
++                .end    = IRQ_T7L66XB_OHCI,
++                .flags  = IORESOURCE_IRQ | IORESOURCE_IRQ_MFD_SUBDEVICE,
++        },
++};
++
++const static struct resource t7l66xb_nand_resources[] = {
++        {
++                .name   = TMIO_NAND_CONFIG,
++                .start  = 0x0100,
++                .end    = 0x01ff,
++                .flags  = IORESOURCE_MEM,
++        },
++        {
++                .name   = TMIO_NAND_CONTROL,
++                .start  = 0xc00,
++                .end    = 0xc07,
++                .flags  = IORESOURCE_MEM,
++        },
++        {
++                .name   = TMIO_NAND_IRQ,
++                .start  = IRQ_T7L66XB_NAND,
++                .end    = IRQ_T7L66XB_NAND,
++                .flags  = IORESOURCE_IRQ | IORESOURCE_IRQ_MFD_SUBDEVICE,
++        },
++};
++
++static struct mfd_cell t7l66xb_cells[] = {
++      {
++              .name = "tmio-mmc",
++              .enable = t7l66xb_mmc_enable,
++              .disable = t7l66xb_mmc_disable,
++              .num_resources = ARRAY_SIZE(t7l66xb_mmc_resources),
++              .resources = t7l66xb_mmc_resources,
++      },
++        {
++                .name = "tmio-ohci",
++                .enable = t7l66xb_ohci_enable,
++                .disable = t7l66xb_ohci_disable,
++                .num_resources = ARRAY_SIZE(t7l66xb_ohci_resources),
++                .resources = t7l66xb_ohci_resources,
++        },
++        {
++                .name = "tmio-nand",
++                .enable = t7l66xb_nand_enable,
++                .disable = t7l66xb_nand_disable,
++                .num_resources = ARRAY_SIZE(t7l66xb_nand_resources),
++                .resources = t7l66xb_nand_resources,
++        },
++};
++
++/*--------------------------------------------------------------------------*/
++
++/* Handle the T7L66XB interrupt mux */
++static void t7l66xb_irq(unsigned int irq, struct irq_desc *desc)
++{
++      struct platform_device         *dev    = get_irq_chip_data(irq);
++      struct t7l66xb_platform_data   *tcpd   = dev->dev.platform_data;
++      struct t7l66xb                 *t7l66xb = platform_get_drvdata(dev);
++      struct t7l66xb_scr __iomem     *scr    = t7l66xb->scr;
++      unsigned int                   isr;
++      unsigned int                   i;
++
++      desc->chip->ack(irq);
++      while ((isr = readb(&scr->isr) & ~readb(&scr->imr)))
++              for (i = 0; i < T7L66XB_NR_IRQS; i++)
++                      if (isr & (1 << i))
++                              desc_handle_irq(tcpd->irq_base + i,
++                                              irq_desc + tcpd->irq_base + i);
++}
++
++static void t7l66xb_irq_mask(unsigned int irq)
++{
++        struct platform_device          *dev    = get_irq_chip_data(irq);
++        struct t7l66xb_platform_data   *tcpd   = dev->dev.platform_data;
++        struct t7l66xb                 *t7l66xb = platform_get_drvdata(dev);
++        struct t7l66xb_scr __iomem     *scr    = t7l66xb->scr;
++        unsigned long                   flags;
++
++        spin_lock_irqsave(&t7l66xb->lock, flags);
++        iowrite8(ioread8(&scr->imr) | (1 << (irq - tcpd->irq_base)),
++                                                                &scr->imr);
++        spin_unlock_irqrestore(&t7l66xb->lock, flags);
++}
++
++static void t7l66xb_irq_unmask(unsigned int irq)
++{
++        struct platform_device          *dev    = get_irq_chip_data(irq);
++        struct t7l66xb_platform_data   *tcpd   = dev->dev.platform_data;
++        struct t7l66xb                 *t7l66xb = platform_get_drvdata(dev);
++        struct t7l66xb_scr __iomem     *scr    = t7l66xb->scr;
++        unsigned long                   flags;
++
++        spin_lock_irqsave(&t7l66xb->lock, flags);
++        iowrite8(ioread8(&scr->imr) & ~(1 << (irq - tcpd->irq_base)),
++                                                               &scr->imr);
++        spin_unlock_irqrestore(&t7l66xb->lock, flags);
++}
++
++static struct irq_chip t7l66xb_chip = {
++      .name   = "t7l66xb",
++      .ack    = t7l66xb_irq_mask,
++      .mask   = t7l66xb_irq_mask,
++      .unmask = t7l66xb_irq_unmask,
++};
++
++/*--------------------------------------------------------------------------*/
++
++/* Install the IRQ handler */
++static void t7l66xb_attach_irq(struct platform_device *dev)
++{
++      struct t7l66xb_platform_data   *tcpd   = dev->dev.platform_data;
++        struct t7l66xb                 *t7l66xb = platform_get_drvdata(dev);
++        unsigned int                    irq;
++
++        for (
++                        irq = tcpd->irq_base;
++                        irq <= tcpd->irq_base + T7L66XB_NR_IRQS;
++                        irq++) {
++              set_irq_chip (irq, &t7l66xb_chip);
++              set_irq_chip_data (irq, dev);
++              set_irq_handler(irq, handle_level_irq);
++              set_irq_flags(irq, IRQF_VALID | IRQF_PROBE);
++      }
++
++      set_irq_type (t7l66xb->irq, IRQT_FALLING);
++      set_irq_chip_data (t7l66xb->irq, dev);
++        set_irq_chained_handler (t7l66xb->irq, t7l66xb_irq);
++}
++
++static void t7l66xb_detach_irq(struct platform_device *dev)
++{
++        struct t7l66xb_platform_data   *tcpd   = dev->dev.platform_data;
++        struct t7l66xb                 *t7l66xb = platform_get_drvdata(dev);
++        unsigned int                    irq;
++
++        set_irq_chained_handler(t7l66xb->irq, NULL);
++        set_irq_chip_data(t7l66xb->irq, NULL);
++
++        for (
++                        irq = tcpd->irq_base;
++                        irq <= tcpd->irq_base + T7L66XB_NR_IRQS;
++                        irq++) {
++                set_irq_flags(irq, 0);
++                set_irq_chip(irq, NULL);
++                set_irq_chip_data(irq, NULL);
++        }
++}
++
++/*--------------------------------------------------------------------------*/
++
++#ifdef CONFIG_PM
++static int t7l66xb_suspend(struct platform_device *dev, pm_message_t state)
++{
++      struct t7l66xb_platform_data *pdata = dev->dev.platform_data;
++
++
++      if (pdata && pdata->suspend)
++              pdata->suspend(dev);
++
++      return 0;
++}
++
++static int t7l66xb_resume(struct platform_device *dev)
++{
++      struct t7l66xb_platform_data *pdata = dev->dev.platform_data;
++
++      if (pdata && pdata->resume)
++              pdata->resume(dev);
++
++      return 0;
++}
++#else
++#define t7l66xb_suspend NULL
++#define t7l66xb_resume  NULL
++#endif
++
++/*--------------------------------------------------------------------------*/
++
++static int t7l66xb_probe(struct platform_device *dev)
++{
++      struct t7l66xb_platform_data *pdata = dev->dev.platform_data;
++      struct t7l66xb *t7l66xb;
++      struct resource *iomem;
++      struct resource *rscr;
++      int retval = -ENOMEM;
++      
++      iomem = platform_get_resource(dev, IORESOURCE_MEM, 0);
++        if (!iomem)
++                return -EINVAL;
++
++      t7l66xb = kzalloc (sizeof *t7l66xb, GFP_KERNEL);
++      if (!t7l66xb)
++              goto err_kzalloc;
++
++      spin_lock_init(&t7l66xb->lock);
++
++      platform_set_drvdata(dev, t7l66xb);
++      t7l66xb->iomem = iomem;
++        t7l66xb->irq   = platform_get_irq(dev, 0);
++
++      rscr            = &t7l66xb->rscr;
++        rscr->name      = "t7l66xb-core";
++        rscr->start     = iomem->start;
++        rscr->end       = iomem->start + 0xff;
++        rscr->flags     = IORESOURCE_MEM;
++
++        if((retval = request_resource(iomem, rscr)))
++                goto err_request_scr;
++
++      t7l66xb->scr   = ioremap(rscr->start, rscr->end - rscr->start + 1);
++        if (!t7l66xb->scr) {
++                retval = -ENOMEM;
++                goto err_ioremap;
++        }
++
++        if (pdata && pdata->enable)
++                pdata->enable(dev);
++
++      writeb(0xbf, &t7l66xb->scr->imr); /* Mask all interrupts */
++
++      printk(KERN_INFO "%s rev %d @ 0x%08lx, irq %d\n",
++             dev->name,  readb(&t7l66xb->scr->revid),
++             (unsigned long)t7l66xb->scr, t7l66xb->irq);
++
++      if(t7l66xb->irq)
++              t7l66xb_attach_irq(dev);
++
++      t7l66xb_cells[2].driver_data = pdata->nand_data;
++
++      if(!(retval = mfd_add_devices(dev, t7l66xb_cells,
++                                    ARRAY_SIZE(t7l66xb_cells),
++                                    iomem, 0, pdata->irq_base)))
++              return 0;
++
++      if(t7l66xb->irq)
++              t7l66xb_detach_irq(dev);
++
++        iounmap(t7l66xb->scr);
++err_ioremap:
++        release_resource(rscr);
++err_request_scr:
++        kfree(t7l66xb);
++err_kzalloc:
++        release_resource(iomem);
++        return retval;
++}
++
++static int t7l66xb_remove(struct platform_device *dev)
++{
++      struct t7l66xb_platform_data   *pdata   = dev->dev.platform_data;
++        struct t7l66xb                 *t7l66xb = platform_get_drvdata(dev);
++        int ret;
++
++        if (t7l66xb->irq)
++                t7l66xb_detach_irq(dev);
++
++        ret = pdata->disable(dev);
++
++        iounmap(t7l66xb->scr);
++        release_resource(&t7l66xb->rscr);
++        release_resource(t7l66xb->iomem);
++
++        mfd_remove_devices(dev);
++
++        platform_set_drvdata(dev, NULL);
++
++        kfree(t7l66xb);
++
++        return ret;
++
++}
++
++static struct platform_driver t7l66xb_platform_driver = {
++      .driver = {
++              .name    = "t7l66xb",
++              .owner   = THIS_MODULE,
++      },
++      .suspend        = t7l66xb_suspend,
++      .resume         = t7l66xb_resume,
++      .probe          = t7l66xb_probe,
++      .remove         = t7l66xb_remove,
++};
++
++/*--------------------------------------------------------------------------*/
++
++static int __init t7l66xb_init(void)
++{
++      int retval = 0;
++              
++      retval = platform_driver_register (&t7l66xb_platform_driver);
++      return retval;
++}
++
++static void __exit t7l66xb_exit(void)
++{
++      platform_driver_unregister(&t7l66xb_platform_driver);
++}
++
++module_init(t7l66xb_init);
++module_exit(t7l66xb_exit);
++
++MODULE_DESCRIPTION("Toshiba T7L66XB core driver");
++MODULE_LICENSE("GPLv2");
++MODULE_AUTHOR("Ian Molton");
++
+diff --git a/include/linux/mfd/t7l66xb.h b/include/linux/mfd/t7l66xb.h
+new file mode 100644
+index 0000000..06b8de5
+--- /dev/null
++++ b/include/linux/mfd/t7l66xb.h
+@@ -0,0 +1,45 @@
++/*
++ * linux/include/asm-arm/hardware/t7l66xb.h
++ *
++ * This file contains the definitions for the T7L66XB
++ *
++ * (C) Copyright 2005 Ian Molton <spyro@f2s.com>
++ *
++ * 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.
++ *
++ */
++#ifndef _ASM_ARCH_T7L66XB_SOC
++#define _ASM_ARCH_T7L66XB_SOC
++
++#include <linux/mfd-core.h>
++#include <linux/mfd/tmio.h>
++
++
++struct t7l66xb_platform_data
++{
++        int (*enable_clk32k)(struct platform_device *dev);
++        int (*disable_clk32k)(struct platform_device *dev);
++
++      int     (*enable)(struct platform_device *dev);
++      int     (*disable)(struct platform_device *dev);
++      int     (*suspend)(struct platform_device *dev);
++      int     (*resume)(struct platform_device *dev);
++
++      int     irq_base;       /* a base for cascaded irq */
++
++      struct tmio_nand_data   *nand_data;
++};
++
++
++#define T7L66XB_NAND_CNF_BASE  (0x000100)
++#define T7L66XB_NAND_CTL_BASE  (0x001000)
++
++#define IRQ_T7L66XB_NAND       (3)
++#define IRQ_T7L66XB_MMC        (1)
++#define IRQ_T7L66XB_OHCI       (2)
++
++#define T7L66XB_NR_IRQS       8
++
++#endif
+-- 
+1.5.3.8
+
diff --git a/packages/kexecboot/linux-kexecboot-2.6.24/tosa/0007-Common-headers-for-TMIO-MFD-subdevices.patch b/packages/kexecboot/linux-kexecboot-2.6.24/tosa/0007-Common-headers-for-TMIO-MFD-subdevices.patch
new file mode 100644 (file)
index 0000000..2f5f114
--- /dev/null
@@ -0,0 +1,81 @@
+From d6e8b347dbcce9e0e8d2204b774c1c33cfcb483e Mon Sep 17 00:00:00 2001
+From: Ian Molton <spyro@f2s.com>
+Date: Sat, 29 Dec 2007 15:27:43 +0000
+Subject: [PATCH 07/64] Common headers for TMIO MFD subdevices
+
+---
+ include/linux/mfd/tmio.h |   62 ++++++++++++++++++++++++++++++++++++++++++++++
+ 1 files changed, 62 insertions(+), 0 deletions(-)
+ create mode 100644 include/linux/mfd/tmio.h
+
+diff --git a/include/linux/mfd/tmio.h b/include/linux/mfd/tmio.h
+new file mode 100644
+index 0000000..b42a4c3
+--- /dev/null
++++ b/include/linux/mfd/tmio.h
+@@ -0,0 +1,62 @@
++#ifndef MFD_TMIO_H
++#define MFD_TMIO_H
++
++#include <linux/io.h>
++#include <linux/platform_device.h>
++
++struct fb_videomode;
++
++/*
++ * data for the NAND controller
++ */
++struct tmio_nand_data {
++      struct nand_bbt_descr   *badblock_pattern;
++      struct mtd_partition    *partition;
++      unsigned int            num_partitions;
++};
++
++struct tmio_fb_data {
++      int                     (*lcd_set_power)(struct platform_device *fb_dev,
++                                                              bool on);
++      int                     (*lcd_mode)(struct platform_device *fb_dev,
++                                              struct fb_videomode *mode);
++      int                     num_modes;
++      struct fb_videomode     *modes;
++};
++
++static u32 __maybe_unused tmio_ioread32(const void __iomem *addr)
++{
++      return ((u32) ioread16(addr)) | (((u32) ioread16(addr + 2)) << 16);
++}
++
++static u32 __maybe_unused tmio_iowrite32(u32 val, const void __iomem *addr)
++{
++      iowrite16(val,          addr);
++      iowrite16(val >> 16,    addr + 2);
++      return val;
++}
++
++#define FBIO_TMIO_ACC_WRITE   0x7C639300
++#define FBIO_TMIO_ACC_SYNC    0x7C639301
++
++#define TMIO_MMC_CONFIG         "tmio-mmc-config"
++#define TMIO_MMC_CONTROL        "tmio-mmc-control"
++#define TMIO_MMC_IRQ            "tmio-mmc"
++
++#define TMIO_NAND_CONFIG      "tmio-nand-config"
++#define TMIO_NAND_CONTROL     "tmio-nand-control"
++#define TMIO_NAND_IRQ         "tmio-nand"
++
++#define TMIO_FB_CONFIG                "tmio-fb-config"
++#define TMIO_FB_CONTROL               "tmio-fb-control"
++#define TMIO_FB_VRAM          "tmio-fb-vram"
++#define TMIO_FB_IRQ           "tmio-fb"
++
++#define TMIO_OHCI_CONFIG      "tmio-ohci-config"
++#define TMIO_OHCI_CONTROL     "tmio-ohci-control"
++#define TMIO_OHCI_SRAM                "tmio-ohci-sram"
++#define TMIO_OHCI_SRAM_ALIAS  "tmio-ohci-sram-alias"
++#define TMIO_OHCI_IRQ         "tmio-ohci"
++
++#endif
++
+-- 
+1.5.3.8
+
diff --git a/packages/kexecboot/linux-kexecboot-2.6.24/tosa/0008-Nand-driver-for-TMIO-devices.patch b/packages/kexecboot/linux-kexecboot-2.6.24/tosa/0008-Nand-driver-for-TMIO-devices.patch
new file mode 100644 (file)
index 0000000..48b8000
--- /dev/null
@@ -0,0 +1,608 @@
+From 917b3997a39396f5f51418930de7b933ad053bad Mon Sep 17 00:00:00 2001
+From: Ian Molton <spyro@f2s.com>
+Date: Sat, 29 Dec 2007 15:14:23 +0000
+Subject: [PATCH 08/64] Nand driver for TMIO devices
+
+---
+ drivers/mtd/nand/Kconfig     |    7 +
+ drivers/mtd/nand/Makefile    |    1 +
+ drivers/mtd/nand/tmio_nand.c |  557 ++++++++++++++++++++++++++++++++++++++++++
+ 3 files changed, 565 insertions(+), 0 deletions(-)
+ create mode 100644 drivers/mtd/nand/tmio_nand.c
+
+diff --git a/drivers/mtd/nand/Kconfig b/drivers/mtd/nand/Kconfig
+index 246d451..43e489a 100644
+--- a/drivers/mtd/nand/Kconfig
++++ b/drivers/mtd/nand/Kconfig
+@@ -284,6 +284,13 @@ config MTD_NAND_CM_X270
+       depends on MTD_NAND && MACH_ARMCORE
++config MTD_NAND_TMIO
++      tristate "NAND Flash device on Toshiba Mobile IO Controller"
++      depends on MTD_NAND && MFD_CORE
++      help
++        Support for NAND flash connected to a Toshiba Mobile IO
++        Controller in some PDAs, including the Sharp SL6000x.
++
+ config MTD_NAND_NANDSIM
+       tristate "Support for NAND Flash Simulator"
+       depends on MTD_PARTITIONS
+diff --git a/drivers/mtd/nand/Makefile b/drivers/mtd/nand/Makefile
+index 3ad6c01..d839ebd 100644
+--- a/drivers/mtd/nand/Makefile
++++ b/drivers/mtd/nand/Makefile
+@@ -27,6 +27,7 @@ obj-$(CONFIG_MTD_NAND_NDFC)          += ndfc.o
+ obj-$(CONFIG_MTD_NAND_AT91)           += at91_nand.o
+ obj-$(CONFIG_MTD_NAND_CM_X270)                += cmx270_nand.o
+ obj-$(CONFIG_MTD_NAND_BASLER_EXCITE)  += excite_nandflash.o
++obj-$(CONFIG_MTD_NAND_TMIO)           += tmio_nand.o
+ obj-$(CONFIG_MTD_NAND_PLATFORM)               += plat_nand.o
+ obj-$(CONFIG_MTD_ALAUDA)              += alauda.o
+diff --git a/drivers/mtd/nand/tmio_nand.c b/drivers/mtd/nand/tmio_nand.c
+new file mode 100644
+index 0000000..450b4ec
+--- /dev/null
++++ b/drivers/mtd/nand/tmio_nand.c
+@@ -0,0 +1,557 @@
++#include <linux/kernel.h>
++#include <linux/module.h>
++#include <linux/platform_device.h>
++#include <linux/mfd-core.h>
++#include <linux/mfd/tmio.h>
++#include <linux/delay.h>
++#include <linux/io.h>
++#include <linux/irq.h>
++#include <linux/interrupt.h>
++#include <linux/ioport.h>
++#include <linux/mtd/mtd.h>
++#include <linux/mtd/nand.h>
++#include <linux/mtd/nand_ecc.h>
++#include <linux/mtd/partitions.h>
++
++/*--------------------------------------------------------------------------*/
++
++/* tmio_nfcr.mode Register Command List */
++#define FCR_MODE_DATA         0x94    /* Data Data_Mode */
++#define FCR_MODE_COMMAND      0x95    /* Data Command_Mode */
++#define FCR_MODE_ADDRESS      0x96    /* Data Address_Mode */
++
++#define FCR_MODE_HWECC_CALC   0xB4    /* HW-ECC Data */
++#define FCR_MODE_HWECC_RESULT 0xD4    /* HW-ECC Calculation Result Read_Mode */
++#define FCR_MODE_HWECC_RESET  0xF4    /* HW-ECC Reset */
++
++#define FCR_MODE_POWER_ON     0x0C    /* Power Supply ON  to SSFDC card */
++#define FCR_MODE_POWER_OFF    0x08    /* Power Supply OFF to SSFDC card */
++
++#define FCR_MODE_LED_OFF      0x00    /* LED OFF */
++#define FCR_MODE_LED_ON               0x04    /* LED ON */
++
++#define FCR_MODE_EJECT_ON     0x68    /* Ejection Demand from Penguin is Advanced */
++#define FCR_MODE_EJECT_OFF    0x08    /* Ejection Demand from Penguin is Not Advanced */
++
++#define FCR_MODE_LOCK         0x6C    /* Operates By Lock_Mode. Ejection Switch is Invalid */
++#define FCR_MODE_UNLOCK               0x0C    /* Operates By UnLock_Mode.Ejection Switch is Effective */
++
++#define FCR_MODE_CONTROLLER_ID        0x40    /* Controller ID Read */
++#define FCR_MODE_STANDBY      0x00    /* SSFDC card Changes Standby State */
++
++#define FCR_MODE_WE           0x80
++#define FCR_MODE_ECC1         0x40
++#define FCR_MODE_ECC0         0x20
++#define FCR_MODE_CE           0x10
++#define FCR_MODE_PCNT1                0x08
++#define FCR_MODE_PCNT0                0x04
++#define FCR_MODE_ALE          0x02
++#define FCR_MODE_CLE          0x01
++
++#define FCR_STATUS_BUSY               0x80
++
++/*
++  *NAND Flash Host Controller Configuration Register
++ */
++struct tmio_nfhccr {
++      u8 x00[4];
++      u16     command;        /* 0x04 Command                         */
++      u8 x01[0x0a];
++      u16     base[2];        /* 0x10 NAND Flash Control Reg Base Addr*/
++      u8 x02[0x29];
++      u8      intp;           /* 0x3d Interrupt Pin                   */
++      u8 x03[0x0a];
++      u8      inte;           /* 0x48 Interrupt Enable                */
++      u8 x04;
++      u8      ec;             /* 0x4a Event Control                   */
++      u8 x05;
++      u8      icc;            /* 0x4c Internal Clock Control          */
++      u8 x06[0x0e];
++      u8      eccc;           /* 0x5b ECC Control                     */
++      u8 x07[4];
++      u8      nftc;           /* 0x60 NAND Flash Transaction Control  */
++      u8      nfm;            /* 0x61 NAND Flash Monitor              */
++      u8      nfpsc;          /* 0x62 NAND Flash Power Supply Control */
++      u8      nfdc;           /* 0x63 NAND Flash Detect Control       */
++      u8 x08[0x9c];
++} __attribute__ ((packed));
++
++/*
++  *NAND Flash Control Register
++ */
++struct tmio_nfcr {
++union {
++      u8      u8;             /* 0x00 Data Register                   */
++      u16     u16;
++      u32     u32;
++} __attribute__ ((packed));
++      u8      mode;           /* 0x04 Mode Register                   */
++      u8      status;         /* 0x05 Status Register                 */
++      u8      isr;            /* 0x06 Interrupt Status Register       */
++      u8      imr;            /* 0x07 Interrupt Mask Register         */
++} __attribute__ ((packed));
++
++struct tmio_nand {
++      struct mtd_info                 mtd;
++      struct nand_chip                chip;
++
++      struct platform_device          *dev;
++
++      struct tmio_nfhccr __iomem      *ccr;
++      struct tmio_nfcr __iomem        *fcr;
++
++      unsigned int                    irq;
++
++      /* for tmio_nand_read_byte */
++      u8                              read;
++      unsigned                        read_good:1;
++};
++
++#define mtd_to_tmio(m)                        container_of(m, struct tmio_nand, mtd)
++
++#ifdef CONFIG_MTD_CMDLINE_PARTS
++static const char *part_probes[] = { "cmdlinepart", NULL };
++#endif
++
++/*--------------------------------------------------------------------------*/
++
++static void tmio_nand_hwcontrol(struct mtd_info *mtd, int cmd,
++                                 unsigned int ctrl)
++{
++      struct tmio_nand *tmio = mtd_to_tmio(mtd);
++      struct tmio_nfcr __iomem *fcr = tmio->fcr;
++      struct nand_chip *chip = mtd->priv;
++
++      if (ctrl & NAND_CTRL_CHANGE) {
++              u8 mode;
++
++              if (ctrl & NAND_NCE) {
++                      mode = FCR_MODE_DATA;
++
++                      if (ctrl & NAND_CLE)
++                              mode |=  FCR_MODE_CLE;
++                      else
++                              mode &= ~FCR_MODE_CLE;
++
++                      if (ctrl & NAND_ALE)
++                              mode |=  FCR_MODE_ALE;
++                      else
++                              mode &= ~FCR_MODE_ALE;
++              } else {
++                      mode = FCR_MODE_STANDBY;
++              }
++
++              iowrite8(mode, &fcr->mode);
++              tmio->read_good = 0;
++      }
++
++      if (cmd != NAND_CMD_NONE)
++              writeb(cmd, chip->IO_ADDR_W);
++}
++
++static int tmio_nand_dev_ready(struct mtd_info *mtd)
++{
++      struct tmio_nand                *tmio   = mtd_to_tmio(mtd);
++      struct tmio_nfcr __iomem        *fcr    = tmio->fcr;
++
++      return !(ioread8(&fcr->status) & FCR_STATUS_BUSY);
++}
++
++static irqreturn_t tmio_irq(int irq, void *__dev)
++{
++      struct platform_device          *dev    = __dev;
++      struct tmio_nand                *tmio   = platform_get_drvdata(dev);
++      struct nand_chip                *nand_chip      = &tmio->chip;
++      struct tmio_nfcr __iomem        *fcr    = tmio->fcr;
++
++      /* disable RDYREQ interrupt */
++      iowrite8(0x00,  &fcr->imr);
++
++      if (unlikely(!waitqueue_active(&nand_chip->controller->wq)))
++              dev_warn(&dev->dev, "spurious interrupt\n");
++
++      wake_up(&nand_chip->controller->wq);
++      return IRQ_HANDLED;
++}
++
++/*
++  *The TMIO core has a RDYREQ interrupt on the posedge of #SMRB.
++  *This interrupt is normally disabled, but for long operations like
++  *erase and write, we enable it to wake us up.  The irq handler
++  *disables the interrupt.
++ */
++static int
++tmio_nand_wait(struct mtd_info *mtd, struct nand_chip *nand_chip)
++{
++      struct tmio_nand                *tmio   = mtd_to_tmio(mtd);
++      struct tmio_nfcr __iomem        *fcr    = tmio->fcr;
++      long                            timeout;
++
++      /* enable RDYREQ interrupt */
++      iowrite8(0x0f,  &fcr->isr);
++      iowrite8(0x81,  &fcr->imr);
++
++      timeout = wait_event_timeout(nand_chip->controller->wq, tmio_nand_dev_ready(mtd),
++                      msecs_to_jiffies(nand_chip->state == FL_ERASING ? 400 : 20));
++
++      if (unlikely(!tmio_nand_dev_ready(mtd))) {
++              iowrite8(0x00,  &fcr->imr);
++              dev_warn(&tmio->dev->dev, "still busy with %s after %d ms\n",
++                              nand_chip->state == FL_ERASING ? "erase" : "program",
++                              nand_chip->state == FL_ERASING ? 400 : 20);
++
++      } else if (unlikely(!timeout)) {
++              iowrite8(0x00,  &fcr->imr);
++              dev_warn(&tmio->dev->dev, "timeout waiting for interrupt\n");
++      }
++
++      nand_chip->cmdfunc(mtd, NAND_CMD_STATUS, -1, -1);
++      return nand_chip->read_byte(mtd);
++}
++
++/*
++  *The TMIO controller combines two 8-bit data bytes into one 16-bit
++  *word. This function separates them so nand_base.c works as expected,
++  *especially its NAND_CMD_READID routines.
++ *
++  *To prevent stale data from being read, tmio_nand_hwcontrol() clears
++  *tmio->read_good.
++ */
++static u_char tmio_nand_read_byte(struct mtd_info *mtd)
++{
++      struct tmio_nand                *tmio   = mtd_to_tmio(mtd);
++      struct tmio_nfcr __iomem        *fcr    = tmio->fcr;
++      unsigned int                    data;
++
++      if (tmio->read_good--)
++              return tmio->read;
++
++      data            = ioread16(&fcr->u16);
++      tmio->read      = data >> 8;
++      return data;
++}
++
++/*
++  *The TMIO controller converts an 8-bit NAND interface to a 16-bit
++  *bus interface, so all data reads and writes must be 16-bit wide.
++  *Thus, we implement 16-bit versions of the read, write, and verify
++  *buffer functions.
++ */
++static void
++tmio_nand_write_buf(struct mtd_info *mtd, const u_char *buf, int len)
++{
++      struct tmio_nand                *tmio   = mtd_to_tmio(mtd);
++      struct tmio_nfcr __iomem        *fcr    = tmio->fcr;
++
++      iowrite16_rep(&fcr->u16, buf, len >> 1);
++}
++
++static void tmio_nand_read_buf(struct mtd_info *mtd, u_char *buf, int len)
++{
++      struct tmio_nand                *tmio   = mtd_to_tmio(mtd);
++      struct tmio_nfcr __iomem        *fcr    = tmio->fcr;
++
++      ioread16_rep(&fcr->u16, buf, len >> 1);
++}
++
++static int
++tmio_nand_verify_buf(struct mtd_info *mtd, const u_char *buf, int len)
++{
++      struct tmio_nand                *tmio   = mtd_to_tmio(mtd);
++      struct tmio_nfcr __iomem        *fcr    = tmio->fcr;
++      u16                             *p      = (u16 *) buf;
++
++      for (len >>= 1; len; len--)
++              if (*(p++) != ioread16(&fcr->u16))
++                      return -EFAULT;
++      return 0;
++}
++
++static void tmio_nand_enable_hwecc(struct mtd_info *mtd, int mode)
++{
++      struct tmio_nand                *tmio   = mtd_to_tmio(mtd);
++      struct tmio_nfcr __iomem        *fcr    = tmio->fcr;
++
++      iowrite8(FCR_MODE_HWECC_RESET, &fcr->mode);
++      ioread8(&fcr->u8);      /* dummy read */
++      iowrite8(FCR_MODE_HWECC_CALC, &fcr->mode);
++}
++
++static int tmio_nand_calculate_ecc(struct mtd_info *mtd, const u_char *dat,
++                                                      u_char *ecc_code)
++{
++      struct tmio_nand                *tmio   = mtd_to_tmio(mtd);
++      struct tmio_nfcr __iomem        *fcr    = tmio->fcr;
++      unsigned int                    ecc;
++
++      iowrite8(FCR_MODE_HWECC_RESULT, &fcr->mode);
++
++      ecc = ioread16(&fcr->u16);
++      ecc_code[1] = ecc;      /* 000-255 LP7-0 */
++      ecc_code[0] = ecc >> 8; /* 000-255 LP15-8 */
++      ecc = ioread16(&fcr->u16);
++      ecc_code[2] = ecc;      /* 000-255 CP5-0,11b */
++      ecc_code[4] = ecc >> 8; /* 256-511 LP7-0 */
++      ecc = ioread16(&fcr->u16);
++      ecc_code[3] = ecc;      /* 256-511 LP15-8 */
++      ecc_code[5] = ecc >> 8; /* 256-511 CP5-0,11b */
++
++      iowrite8(FCR_MODE_DATA, &fcr->mode);
++      return 0;
++}
++
++static int tmio_hw_init(struct platform_device *dev, struct tmio_nand *tmio)
++{
++      struct mfd_cell                 *cell   = mfd_get_cell(dev);
++      const struct resource           *nfcr   = NULL;
++      struct tmio_nfhccr __iomem      *ccr    = tmio->ccr;
++      struct tmio_nfcr __iomem        *fcr    = tmio->fcr;
++      unsigned long                   base;
++      int                             i;
++
++      for (i = 0; i < cell->num_resources; i++)
++              if (!strcmp((cell->resources+i)->name, TMIO_NAND_CONTROL))
++                      nfcr = &cell->resources[i];
++
++      if (nfcr == NULL)
++              return -ENOMEM;
++
++      if (!cell->enable) {
++              printk(KERN_ERR "null cell enable!");
++              return -EINVAL;
++      }
++
++      cell->enable(dev);
++
++      /* (4Ch) CLKRUN Enable    1st spcrunc */
++      iowrite8(0x81,                  &ccr->icc);
++
++      /* (10h)BaseAddress    0x1000 spba.spba2 */
++      base = nfcr->start;
++      iowrite16(base,                 ccr->base + 0);
++      iowrite16(base >> 16,           ccr->base + 1);
++
++      /* (04h)Command Register I/O spcmd */
++      iowrite8(0x02,                  &ccr->command);
++
++      /* (62h) Power Supply Control ssmpwc */
++      /* HardPowerOFF - SuspendOFF - PowerSupplyWait_4MS */
++      iowrite8(0x02,                  &ccr->nfpsc);
++
++      /* (63h) Detect Control ssmdtc */
++      iowrite8(0x02,                  &ccr->nfdc);
++
++      /* Interrupt status register clear sintst */
++      iowrite8(0x0f,                  &fcr->isr);
++
++      /* After power supply, Media are reset smode */
++      iowrite8(FCR_MODE_POWER_ON,     &fcr->mode);
++      iowrite8(FCR_MODE_COMMAND,      &fcr->mode);
++      iowrite8(NAND_CMD_RESET,        &fcr->u8);
++
++      /* Standby Mode smode */
++      iowrite8(FCR_MODE_STANDBY,      &fcr->mode);
++
++      mdelay(5);
++
++      return 0;
++}
++
++static void tmio_hw_stop(struct platform_device *dev, struct tmio_nand *tmio)
++{
++      struct mfd_cell                 *cell   = mfd_get_cell(dev);
++      struct tmio_nfcr __iomem        *fcr    = tmio->fcr;
++
++      iowrite8(FCR_MODE_POWER_OFF,    &fcr->mode);
++      cell->disable(dev);
++}
++
++static int tmio_probe(struct platform_device *dev)
++{
++      struct mfd_cell                 *cell   = mfd_get_cell(dev);
++      struct tmio_nand_data           *data   = cell->driver_data;
++      struct resource                 *ccr    = platform_get_resource_byname(dev, IORESOURCE_MEM, TMIO_NAND_CONFIG);
++      struct resource                 *fcr    = platform_get_resource_byname(dev, IORESOURCE_MEM, TMIO_NAND_CONTROL);
++      int                             irq     = platform_get_irq(dev, 0);
++      struct tmio_nand                *tmio;
++      struct mtd_info                 *mtd;
++      struct nand_chip                *nand_chip;
++      struct mtd_partition            *parts;
++      int                             nbparts = 0;
++      int                             retval;
++
++      if (data == NULL) {
++              dev_err(&dev->dev, "NULL platform data!\n");
++              return -EINVAL;
++      }
++
++      tmio = kzalloc(sizeof *tmio, GFP_KERNEL);
++      if (!tmio) {
++              retval = -ENOMEM;
++              goto err_kzalloc;
++      }
++
++      tmio->dev       = dev;
++
++      platform_set_drvdata(dev, tmio);
++      mtd             = &tmio->mtd;
++      nand_chip       = &tmio->chip;
++      mtd->priv       = nand_chip;
++      mtd->name       = "tmio-nand";
++
++      tmio->ccr = ioremap(ccr->start, ccr->end - ccr->start + 1);
++      if (!tmio->ccr) {
++              retval = -EIO;
++              goto err_iomap_ccr;
++      }
++
++      tmio->fcr = ioremap(fcr->start, fcr->end - fcr->start + 1);
++      if (!tmio->fcr) {
++              retval = -EIO;
++              goto err_iomap_fcr;
++      }
++
++      retval = tmio_hw_init(dev, tmio);
++      if (retval)
++              goto err_hwinit;
++
++      /* Set address of NAND IO lines */
++      nand_chip->IO_ADDR_R            = tmio->fcr;
++      nand_chip->IO_ADDR_W            = tmio->fcr;
++
++      /* Set address of hardware control function */
++      nand_chip->cmd_ctrl             = tmio_nand_hwcontrol;
++      nand_chip->dev_ready            = tmio_nand_dev_ready;
++      nand_chip->read_byte            = tmio_nand_read_byte;
++      nand_chip->write_buf            = tmio_nand_write_buf;
++      nand_chip->read_buf             = tmio_nand_read_buf;
++      nand_chip->verify_buf           = tmio_nand_verify_buf;
++
++      /* set eccmode using hardware ECC */
++      nand_chip->ecc.mode             = NAND_ECC_HW;
++      nand_chip->ecc.size             = 512;
++      nand_chip->ecc.bytes            = 6;
++      nand_chip->ecc.hwctl            = tmio_nand_enable_hwecc;
++      nand_chip->ecc.calculate        = tmio_nand_calculate_ecc;
++      nand_chip->ecc.correct          = nand_correct_data;
++      nand_chip->badblock_pattern     = data->badblock_pattern;
++
++      /* 15 us command delay time */
++      nand_chip->chip_delay   = 15;
++
++      retval = request_irq(irq, &tmio_irq,
++                              IRQF_DISABLED, dev->dev.bus_id, dev);
++      if (retval) {
++              dev_err(&dev->dev, "request_irq error %d\n", retval);
++              goto err_irq;
++      }
++
++      tmio->irq               = irq;
++      nand_chip->waitfunc     = tmio_nand_wait;
++
++      /* Scan to find existence of the device */
++      if (nand_scan(mtd, 1)) {
++              retval = -ENODEV;
++              goto err_scan;
++      }
++      /* Register the partitions */
++#ifdef CONFIG_MTD_PARTITIONS
++#ifdef CONFIG_MTD_CMDLINE_PARTS
++      nbparts = parse_mtd_partitions(mtd, part_probes, &parts, 0);
++#endif
++      if (nbparts <= 0) {
++              parts   = data->partition;
++              nbparts = data->num_partitions;
++      }
++
++      retval = add_mtd_partitions(mtd, parts, nbparts);
++#else
++      retval = add_mtd_device(mtd);
++#endif
++
++      if (!retval)
++              return retval;
++
++      nand_release(mtd);
++
++err_scan:
++      if (tmio->irq)
++              free_irq(tmio->irq, dev);
++err_irq:
++      tmio_hw_stop(dev, tmio);
++err_hwinit:
++      iounmap(tmio->fcr);
++err_iomap_fcr:
++      iounmap(tmio->ccr);
++err_iomap_ccr:
++      kfree(tmio);
++err_kzalloc:
++      return retval;
++}
++
++static int tmio_remove(struct platform_device *dev)
++{
++      struct tmio_nand                *tmio   = platform_get_drvdata(dev);
++
++      nand_release(&tmio->mtd);
++      if (tmio->irq)
++              free_irq(tmio->irq, tmio);
++      tmio_hw_stop(dev, tmio);
++      iounmap(tmio->fcr);
++      iounmap(tmio->ccr);
++      kfree(tmio);
++      return 0;
++}
++
++#ifdef CONFIG_PM
++static int tmio_suspend(struct platform_device *dev, pm_message_t state)
++{
++      struct mfd_cell                 *cell   = mfd_get_cell(dev);
++
++      if (cell->suspend)
++              cell->suspend(dev);
++
++      tmio_hw_stop(dev, platform_get_drvdata(dev));
++      return 0;
++}
++
++static int tmio_resume(struct platform_device *dev)
++{
++      struct mfd_cell                 *cell   = mfd_get_cell(dev);
++
++      tmio_hw_init(dev, platform_get_drvdata(dev));
++
++      if (cell->resume)
++              cell->resume(dev);
++
++      return 0;
++}
++#endif
++
++static struct platform_driver tmio_driver = {
++      .driver.name    = "tmio-nand",
++      .driver.owner   = THIS_MODULE,
++      .probe          = tmio_probe,
++      .remove         = tmio_remove,
++#ifdef CONFIG_PM
++      .suspend        = tmio_suspend,
++      .resume         = tmio_resume,
++#endif
++};
++
++static int __init tmio_init(void)
++{
++      return platform_driver_register(&tmio_driver);
++}
++
++static void __exit tmio_exit(void)
++{
++      platform_driver_unregister(&tmio_driver);
++}
++
++module_init(tmio_init);
++module_exit(tmio_exit);
++
++MODULE_LICENSE("GPL");
++MODULE_AUTHOR("Dirk Opfer, Chris Humbert, Dmitry Baryshkov");
++MODULE_DESCRIPTION("NAND flash driver on Toshiba Mobile IO controller");
+-- 
+1.5.3.8
+
diff --git a/packages/kexecboot/linux-kexecboot-2.6.24/tosa/0009-FB-driver-for-TMIO-devices.patch b/packages/kexecboot/linux-kexecboot-2.6.24/tosa/0009-FB-driver-for-TMIO-devices.patch
new file mode 100644 (file)
index 0000000..5fc96f8
--- /dev/null
@@ -0,0 +1,1128 @@
+From 519d015892ab0a7cad1f6b26fcd38117171384ce Mon Sep 17 00:00:00 2001
+From: Ian Molton <spyro@f2s.com>
+Date: Tue, 1 Jan 2008 21:22:23 +0000
+Subject: [PATCH 09/64] FB driver for TMIO devices
+
+---
+ drivers/video/Kconfig  |   22 +
+ drivers/video/Makefile |    1 +
+ drivers/video/tmiofb.c | 1062 ++++++++++++++++++++++++++++++++++++++++++++++++
+ 3 files changed, 1085 insertions(+), 0 deletions(-)
+ create mode 100644 drivers/video/tmiofb.c
+
+diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig
+index 5b3dbcf..6d0df58 100644
+--- a/drivers/video/Kconfig
++++ b/drivers/video/Kconfig
+@@ -1782,6 +1782,28 @@ config FB_W100
+         If unsure, say N.
++config FB_TMIO
++      tristate "Toshiba Mobice IO FrameBuffer support"
++      depends on FB && MFD_CORE
++      select FB_CFB_FILLRECT
++      select FB_CFB_COPYAREA
++      select FB_CFB_IMAGEBLIT
++      ---help---
++        Frame buffer driver for the Toshiba Mobile IO integrated as found
++        on the Sharp SL-6000 series
++
++        This driver is also available as a module ( = code which can be
++        inserted and removed from the running kernel whenever you want). The
++        module will be called tmiofb. If you want to compile it as a module,
++        say M here and read <file:Documentation/kbuild/modules.txt>.
++
++        If unsure, say N.
++
++config FB_TMIO_ACCELL
++      bool "tmiofb acceleration"
++      depends on FB_TMIO
++      default y
++
+ config FB_S3C2410
+       tristate "S3C2410 LCD framebuffer support"
+       depends on FB && ARCH_S3C2410
+diff --git a/drivers/video/Makefile b/drivers/video/Makefile
+index 83e02b3..74e9384 100644
+--- a/drivers/video/Makefile
++++ b/drivers/video/Makefile
+@@ -97,6 +97,7 @@ obj-$(CONFIG_FB_CIRRUS)                += cirrusfb.o
+ obj-$(CONFIG_FB_ASILIANT)       += asiliantfb.o
+ obj-$(CONFIG_FB_PXA)            += pxafb.o
+ obj-$(CONFIG_FB_W100)           += w100fb.o
++obj-$(CONFIG_FB_TMIO)           += tmiofb.o
+ obj-$(CONFIG_FB_AU1100)                 += au1100fb.o
+ obj-$(CONFIG_FB_AU1200)                 += au1200fb.o
+ obj-$(CONFIG_FB_PMAG_AA)        += pmag-aa-fb.o
+diff --git a/drivers/video/tmiofb.c b/drivers/video/tmiofb.c
+new file mode 100644
+index 0000000..6b963a1
+--- /dev/null
++++ b/drivers/video/tmiofb.c
+@@ -0,0 +1,1062 @@
++/*
++ * Frame Buffer Device for Toshiba Mobile IO(TMIO) controller
++ *
++ * Copyright(C) 2005-2006 Chris Humbert
++ * Copyright(C) 2005 Dirk Opfer
++ *
++ * Based on:
++ *    drivers/video/w100fb.c
++ *    code written by Sharp/Lineo for 2.4 kernels
++ *
++ * 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.
++ *
++ * This program is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
++ * GNU General Public License for more details.
++ */
++
++#include <linux/kernel.h>
++#include <linux/module.h>
++#include <linux/platform_device.h>
++#include <linux/mfd-core.h>
++#include <linux/mfd/tmio.h>
++#include <linux/fb.h>
++#include <linux/interrupt.h>
++#include <linux/delay.h>
++/* Why should fb driver call console functions? because acquire_console_sem() */
++#include <linux/console.h>
++#include <linux/uaccess.h>
++#include <linux/vmalloc.h>
++
++/*
++ * accelerator commands
++ */
++#define TMIOFB_ACC_CSADR(x)   (0x00000000 | ((x) & 0x001ffffe))
++#define TMIOFB_ACC_CHPIX(x)   (0x01000000 | ((x) & 0x000003ff))
++#define TMIOFB_ACC_CVPIX(x)   (0x02000000 | ((x) & 0x000003ff))
++#define TMIOFB_ACC_PSADR(x)   (0x03000000 | ((x) & 0x00fffffe))
++#define TMIOFB_ACC_PHPIX(x)   (0x04000000 | ((x) & 0x000003ff))
++#define TMIOFB_ACC_PVPIX(x)   (0x05000000 | ((x) & 0x000003ff))
++#define TMIOFB_ACC_PHOFS(x)   (0x06000000 | ((x) & 0x000003ff))
++#define TMIOFB_ACC_PVOFS(x)   (0x07000000 | ((x) & 0x000003ff))
++#define TMIOFB_ACC_POADR(x)   (0x08000000 | ((x) & 0x00fffffe))
++#define TMIOFB_ACC_RSTR(x)    (0x09000000 | ((x) & 0x000000ff))
++#define TMIOFB_ACC_TCLOR(x)   (0x0A000000 | ((x) & 0x0000ffff))
++#define TMIOFB_ACC_FILL(x)    (0x0B000000 | ((x) & 0x0000ffff))
++#define TMIOFB_ACC_DSADR(x)   (0x0C000000 | ((x) & 0x00fffffe))
++#define TMIOFB_ACC_SSADR(x)   (0x0D000000 | ((x) & 0x00fffffe))
++#define TMIOFB_ACC_DHPIX(x)   (0x0E000000 | ((x) & 0x000003ff))
++#define TMIOFB_ACC_DVPIX(x)   (0x0F000000 | ((x) & 0x000003ff))
++#define TMIOFB_ACC_SHPIX(x)   (0x10000000 | ((x) & 0x000003ff))
++#define TMIOFB_ACC_SVPIX(x)   (0x11000000 | ((x) & 0x000003ff))
++#define TMIOFB_ACC_LBINI(x)   (0x12000000 | ((x) & 0x0000ffff))
++#define TMIOFB_ACC_LBK2(x)    (0x13000000 | ((x) & 0x0000ffff))
++#define TMIOFB_ACC_SHBINI(x)  (0x14000000 | ((x) & 0x0000ffff))
++#define TMIOFB_ACC_SHBK2(x)   (0x15000000 | ((x) & 0x0000ffff))
++#define TMIOFB_ACC_SVBINI(x)  (0x16000000 | ((x) & 0x0000ffff))
++#define TMIOFB_ACC_SVBK2(x)   (0x17000000 | ((x) & 0x0000ffff))
++
++#define       TMIOFB_ACC_CMGO         0x20000000
++#define       TMIOFB_ACC_CMGO_CEND    0x00000001
++#define       TMIOFB_ACC_CMGO_INT     0x00000002
++#define       TMIOFB_ACC_CMGO_CMOD    0x00000010
++#define       TMIOFB_ACC_CMGO_CDVRV   0x00000020
++#define       TMIOFB_ACC_CMGO_CDHRV   0x00000040
++#define       TMIOFB_ACC_CMGO_RUND    0x00008000
++#define       TMIOFB_ACC_SCGO         0x21000000
++#define       TMIOFB_ACC_SCGO_CEND    0x00000001
++#define       TMIOFB_ACC_SCGO_INT     0x00000002
++#define       TMIOFB_ACC_SCGO_ROP3    0x00000004
++#define       TMIOFB_ACC_SCGO_TRNS    0x00000008
++#define       TMIOFB_ACC_SCGO_DVRV    0x00000010
++#define       TMIOFB_ACC_SCGO_DHRV    0x00000020
++#define       TMIOFB_ACC_SCGO_SVRV    0x00000040
++#define       TMIOFB_ACC_SCGO_SHRV    0x00000080
++#define       TMIOFB_ACC_SCGO_DSTXY   0x00008000
++#define       TMIOFB_ACC_SBGO         0x22000000
++#define       TMIOFB_ACC_SBGO_CEND    0x00000001
++#define       TMIOFB_ACC_SBGO_INT     0x00000002
++#define       TMIOFB_ACC_SBGO_DVRV    0x00000010
++#define       TMIOFB_ACC_SBGO_DHRV    0x00000020
++#define       TMIOFB_ACC_SBGO_SVRV    0x00000040
++#define       TMIOFB_ACC_SBGO_SHRV    0x00000080
++#define       TMIOFB_ACC_SBGO_SBMD    0x00000100
++#define       TMIOFB_ACC_FLGO         0x23000000
++#define       TMIOFB_ACC_FLGO_CEND    0x00000001
++#define       TMIOFB_ACC_FLGO_INT     0x00000002
++#define       TMIOFB_ACC_FLGO_ROP3    0x00000004
++#define       TMIOFB_ACC_LDGO         0x24000000
++#define       TMIOFB_ACC_LDGO_CEND    0x00000001
++#define       TMIOFB_ACC_LDGO_INT     0x00000002
++#define       TMIOFB_ACC_LDGO_ROP3    0x00000004
++#define       TMIOFB_ACC_LDGO_ENDPX   0x00000008
++#define       TMIOFB_ACC_LDGO_LVRV    0x00000010
++#define       TMIOFB_ACC_LDGO_LHRV    0x00000020
++#define       TMIOFB_ACC_LDGO_LDMOD   0x00000040
++
++/* a FIFO is always allocated, even if acceleration is not used */
++#define TMIOFB_FIFO_SIZE      512
++
++/*
++ * LCD Host Controller Configuration Register
++ *
++ * This iomem area supports only 16-bit IO.
++ */
++struct tmio_lhccr {
++      u16 x00[2];
++      u16     cmd;            /* 0x04 Command                         */
++      u16 x01;
++      u16     revid;          /* 0x08 Revision ID                     */
++      u16 x02[3];
++      u16     basel;          /* 0x10 LCD Control Reg Base Addr Low   */
++      u16     baseh;          /* 0x12 LCD Control Reg Base Addr High  */
++      u16 x03[0x16];
++      u16     ugcc;           /* 0x40 Unified Gated Clock Control     */
++      u16     gcc;            /* 0x42 Gated Clock Control             */
++      u16 x04[6];
++      u16     usc;            /* 0x50 Unified Software Clear          */
++      u16 x05[7];
++      u16     vramrtc;        /* 0x60 VRAM Timing Control             */
++                              /* 0x61 VRAM Refresh Control            */
++      u16     vramsac;        /* 0x62 VRAM Access Control             */
++                              /* 0x63 VRAM Status                     */
++      u16     vrambc;         /* 0x64 VRAM Block Control              */
++      u16 x06[0x4d];
++};
++
++/*
++ * LCD Control Register
++ *
++ * This iomem area supports only 16-bit IO.
++ */
++struct tmio_lcr {
++      u16     uis;    /* 0x000 Unified Interrupt Status               */
++      u16 x00[3];
++      u16     vhpn;   /* 0x008 VRAM Horizontal Pixel Number           */
++      u16     cfsal;  /* 0x00a Command FIFO Start Address Low         */
++      u16     cfsah;  /* 0x00c Command FIFO Start Address High        */
++      u16     cfs;    /* 0x00e Command FIFO Size                      */
++      u16     cfws;   /* 0x010 Command FIFO Writeable Size            */
++      u16     bbie;   /* 0x012 BitBLT Interrupt Enable                */
++      u16     bbisc;  /* 0x014 BitBLT Interrupt Status and Clear      */
++      u16     ccs;    /* 0x016 Command Count Status                   */
++      u16     bbes;   /* 0x018 BitBLT Execution Status                */
++      u16 x01;
++      u16     cmdl;   /* 0x01c Command Low                            */
++      u16     cmdh;   /* 0x01e Command High                           */
++      u16 x02;
++      u16     cfc;    /* 0x022 Command FIFO Clear                     */
++      u16     ccifc;  /* 0x024 CMOS Camera IF Control                 */
++      u16     hwt;    /* 0x026 Hardware Test                          */
++      u16 x03[0x6c];
++      u16     lcdccrc;/* 0x100 LCDC Clock and Reset Control           */
++      u16     lcdcc;  /* 0x102 LCDC Control                           */
++      u16     lcdcopc;/* 0x104 LCDC Output Pin Control                */
++      u16 x04;
++      u16     lcdis;  /* 0x108 LCD Interrupt Status                   */
++      u16     lcdim;  /* 0x10a LCD Interrupt Mask                     */
++      u16     lcdie;  /* 0x10c LCD Interrupt Enable                   */
++      u16 x05[10];
++      u16     gdsal;  /* 0x122 Graphics Display Start Address Low     */
++      u16     gdsah;  /* 0x124 Graphics Display Start Address High    */
++      u16 x06[2];
++      u16     vhpcl;  /* 0x12a VRAM Horizontal Pixel Count Low        */
++      u16     vhpch;  /* 0x12c VRAM Horizontal Pixel Count High       */
++      u16     gm;     /* 0x12e Graphic Mode(VRAM access enable)       */
++      u16 x07[8];
++      u16     ht;     /* 0x140 Horizontal Total                       */
++      u16     hds;    /* 0x142 Horizontal Display Start               */
++      u16     hss;    /* 0x144 H-Sync Start                           */
++      u16     hse;    /* 0x146 H-Sync End                             */
++      u16 x08[2];
++      u16     hnp;    /* 0x14c Horizontal Number of Pixels            */
++      u16 x09;
++      u16     vt;     /* 0x150 Vertical Total                         */
++      u16     vds;    /* 0x152 Vertical Display Start                 */
++      u16     vss;    /* 0x154 V-Sync Start                           */
++      u16     vse;    /* 0x156 V-Sync End                             */
++      u16 x0a[4];
++      u16     cdln;   /* 0x160 Current Display Line Number            */
++      u16     iln;    /* 0x162 Interrupt Line Number                  */
++      u16     sp;     /* 0x164 Sync Polarity                          */
++      u16     misc;   /* 0x166 MISC(RGB565 mode)                      */
++      u16 x0b;
++      u16     vihss;  /* 0x16a Video Interface H-Sync Start           */
++      u16     vivs;   /* 0x16c Video Interface Vertical Start         */
++      u16     vive;   /* 0x16e Video Interface Vertical End           */
++      u16     vivss;  /* 0x170 Video Interface V-Sync Start           */
++      u16 x0c[6];
++      u16     vccis;  /* 0x17e Video / CMOS Camera Interface Select   */
++      u16     vidwsal;/* 0x180 VI Data Write Start Address Low        */
++      u16     vidwsah;/* 0x182 VI Data Write Start Address High       */
++      u16     vidrsal;/* 0x184 VI Data Read Start Address Low         */
++      u16     vidrsah;/* 0x186 VI Data Read Start Address High        */
++      u16     vipddst;/* 0x188 VI Picture Data Display Start Timing   */
++      u16     vipddet;/* 0x186 VI Picture Data Display End Timing     */
++      u16     vie;    /* 0x18c Video Interface Enable                 */
++      u16     vcs;    /* 0x18e Video/Camera Select                    */
++      u16 x0d[2];
++      u16     vphwc;  /* 0x194 Video Picture Horizontal Wait Count    */
++      u16     vphs;   /* 0x196 Video Picture Horizontal Size          */
++      u16     vpvwc;  /* 0x198 Video Picture Vertical Wait Count      */
++      u16     vpvs;   /* 0x19a Video Picture Vertical Size            */
++      u16 x0e[2];
++      u16     plhpix; /* 0x1a0 PLHPIX                                 */
++      u16     xs;     /* 0x1a2 XStart                                 */
++      u16     xckhw;  /* 0x1a4 XCK High Width                         */
++      u16 x0f;
++      u16     sths;   /* 0x1a8 STH Start                              */
++      u16     vt2;    /* 0x1aa Vertical Total                         */
++      u16     ycksw;  /* 0x1ac YCK Start Wait                         */
++      u16     ysts;   /* 0x1ae YST Start                              */
++      u16     ppols;  /* 0x1b0 #PPOL Start                            */
++      u16     precw;  /* 0x1b2 PREC Width                             */
++      u16     vclkhw; /* 0x1b4 VCLK High Width                        */
++      u16     oc;     /* 0x1b6 Output Control                         */
++      u16 x10[0x24];
++};
++static char *mode_option __devinitdata;
++
++struct tmiofb_par {
++      u32                             pseudo_palette[16];
++
++#ifdef CONFIG_FB_TMIO_ACCELL
++      wait_queue_head_t               wait_acc;
++      bool                            use_polling;
++#endif
++
++      struct tmio_lhccr __iomem       *ccr;
++      struct tmio_lcr __iomem         *lcr;
++      void __iomem                    *vram;
++};
++
++/*--------------------------------------------------------------------------*/
++
++static irqreturn_t tmiofb_irq(int irq, void *__info);
++
++/*--------------------------------------------------------------------------*/
++
++
++/*
++ * Turns off the LCD controller and LCD host controller.
++ */
++static int tmiofb_hw_stop(struct platform_device *dev)
++{
++      struct mfd_cell                 *cell   = mfd_get_cell(dev);
++      struct tmio_fb_data             *data   = cell->driver_data;
++      struct fb_info                  *info   = platform_get_drvdata(dev);
++      struct tmiofb_par               *par    = info->par;
++      struct tmio_lhccr __iomem       *ccr    = par->ccr;
++      struct tmio_lcr __iomem         *lcr    = par->lcr;
++
++      iowrite16(0,            &ccr->ugcc);
++      iowrite16(0,            &lcr->gm);
++      data->lcd_set_power(dev, 0);
++      iowrite16(0x0010,       &lcr->lcdccrc);
++
++      return 0;
++}
++
++/*
++ * Initializes the LCD host controller.
++ */
++static int tmiofb_hw_init(struct platform_device *dev)
++{
++      struct mfd_cell                 *cell   = mfd_get_cell(dev);
++      struct tmio_fb_data             *data   = cell->driver_data;
++      struct fb_info                  *info   = platform_get_drvdata(dev);
++      struct tmiofb_par               *par    = info->par;
++      struct tmio_lhccr __iomem       *ccr    = par->ccr;
++      struct tmio_lcr __iomem         *lcr    = par->lcr;
++      const struct resource           *nlcr   = NULL;
++      const struct resource           *vram   = NULL;
++      unsigned long                   base;
++      int                             i;
++
++      for (i = 0; i < cell->num_resources; i++) {
++              if (!strcmp((cell->resources+i)->name, TMIO_FB_CONTROL))
++                      nlcr = &cell->resources[i];
++              if (!strcmp((cell->resources+i)->name, TMIO_FB_VRAM))
++                      vram = &cell->resources[i];
++      }
++
++      if (nlcr == NULL || vram == NULL)
++              return -EINVAL;
++
++      base = nlcr->start;
++
++      if (info->mode == NULL) {
++              printk(KERN_ERR "tmio-fb: null info->mode\n");
++              info->mode = data->modes;
++      }
++
++      data->lcd_mode(dev, info->mode);
++
++      iowrite16(0x003a,       &ccr->ugcc);
++      iowrite16(0x003a,       &ccr->gcc);
++      iowrite16(0x3f00,       &ccr->usc);
++
++      data->lcd_set_power(dev, 1);
++      mdelay(2);
++
++      iowrite16(0x0000,       &ccr->usc);
++      iowrite16(base >> 16,   &ccr->baseh);
++      iowrite16(base, &ccr->basel);
++      iowrite16(0x0002,       &ccr->cmd);     /* base address enable  */
++      iowrite16(0x40a8,       &ccr->vramrtc); /* VRAMRC, VRAMTC       */
++      iowrite16(0x0018,       &ccr->vramsac); /* VRAMSTS, VRAMAC      */
++      iowrite16(0x0002,       &ccr->vrambc);
++      mdelay(2);
++      iowrite16(0x000b,       &ccr->vrambc);
++
++      base = vram->start + info->screen_size;
++      iowrite16(base >> 16,                   &lcr->cfsah);
++      iowrite16(base,                         &lcr->cfsal);
++      iowrite16(TMIOFB_FIFO_SIZE - 1,         &lcr->cfs);
++      iowrite16(1,                            &lcr->cfc);
++      iowrite16(1,                            &lcr->bbie);
++      iowrite16(0,                            &lcr->cfws);
++
++      return 0;
++}
++
++/*
++ * Sets the LCD controller's output resolution and pixel clock
++ */
++static void tmiofb_hw_mode(struct platform_device *dev)
++{
++      struct mfd_cell                 *cell   = mfd_get_cell(dev);
++      struct tmio_fb_data             *data   = cell->driver_data;
++      struct fb_info                  *info   = platform_get_drvdata(dev);
++      struct fb_videomode             *mode   = info->mode;
++      struct tmiofb_par               *par    = info->par;
++      struct tmio_lcr __iomem         *lcr    = par->lcr;
++      unsigned int                    i;
++
++      iowrite16(0,                            &lcr->gm);
++      data->lcd_set_power(dev, 0);
++      iowrite16(0x0010,                       &lcr->lcdccrc);
++      data->lcd_mode(dev, mode);
++      data->lcd_set_power(dev, 1);
++
++      iowrite16(i = mode->xres * 2,           &lcr->vhpn);
++      iowrite16(0,                            &lcr->gdsah);
++      iowrite16(0,                            &lcr->gdsal);
++      iowrite16(i >> 16,                      &lcr->vhpch);
++      iowrite16(i,                            &lcr->vhpcl);
++      iowrite16(i = 0,                        &lcr->hss);
++      iowrite16(i += mode->hsync_len, &lcr->hse);
++      iowrite16(i += mode->left_margin,       &lcr->hds);
++      iowrite16(i += mode->xres + mode->right_margin, &lcr->ht);
++      iowrite16(mode->xres,                   &lcr->hnp);
++      iowrite16(i = 0,                        &lcr->vss);
++      iowrite16(i += mode->vsync_len, &lcr->vse);
++      iowrite16(i += mode->upper_margin,      &lcr->vds);
++      iowrite16(i += mode->yres,              &lcr->iln);
++      iowrite16(i += mode->lower_margin,      &lcr->vt);
++      iowrite16(3,    /* RGB565 mode */       &lcr->misc);
++      iowrite16(1,    /* VRAM enable */       &lcr->gm);
++      iowrite16(0x4007,                       &lcr->lcdcc);
++      iowrite16(3,     /* sync polarity */    &lcr->sp);
++
++      iowrite16(0x0010,       &lcr->lcdccrc);
++      mdelay(5);
++      iowrite16(0x0014,       &lcr->lcdccrc); /* STOP_CKP */
++      mdelay(5);
++      iowrite16(0x0015,       &lcr->lcdccrc); /* STOP_CKP | SOFT_RESET */
++      iowrite16(0xfffa,       &lcr->vcs);
++}
++
++/*--------------------------------------------------------------------------*/
++
++#ifdef CONFIG_FB_TMIO_ACCELL
++static int __must_check
++tmiofb_acc_wait(struct fb_info *info, unsigned int ccs)
++{
++      struct tmiofb_par               *par    = info->par;
++      struct tmio_lcr __iomem         *lcr    = par->lcr;
++      if (in_atomic() || par->use_polling) {
++              int i = 0;
++              while (ioread16(&lcr->ccs) > ccs) {
++                      udelay(1);
++                      i++;
++                      if (i > 10000) {
++                              printk(KERN_ERR "tmiofb: timeout waiting for %d\n", ccs);
++                              return -ETIMEDOUT;
++                      }
++                      tmiofb_irq(-1, info);
++              }
++      } else {
++              if (!wait_event_interruptible_timeout(par->wait_acc,
++                              ioread16(&par->lcr->ccs) <= ccs, 1000)) {
++                      printk(KERN_ERR "tmiofb: timeout waiting for %d\n", ccs);
++                      return -ETIMEDOUT;
++              }
++      }
++
++      return 0;
++}
++
++/*
++ * Writes an accelerator command to the accelerator's FIFO.
++ */
++static int
++tmiofb_acc_write(struct fb_info *info, const u32 *cmd, unsigned int count)
++{
++      struct tmiofb_par               *par    = info->par;
++      struct tmio_lcr __iomem         *lcr    = par->lcr;
++      int ret;
++
++      ret = tmiofb_acc_wait(info, TMIOFB_FIFO_SIZE - count);
++      if (ret)
++              return ret;
++
++      for (; count; count--, cmd++) {
++              iowrite16(*cmd >> 16,   &lcr->cmdh);
++              iowrite16(*cmd, &lcr->cmdl);
++      }
++
++      return ret;
++}
++
++/*
++ * Wait for the accelerator to finish its operations before writing
++ * to the framebuffer for consistent display output.
++ */
++static int tmiofb_sync(struct fb_info *fbi)
++{
++      struct tmiofb_par               *par    = fbi->par;
++
++      int ret;
++      int i = 0;
++
++      ret = tmiofb_acc_wait(fbi, 0);
++
++      while (ioread16(&par->lcr->bbes) & 2) { /* blit active */
++              udelay(1);
++              i++ ;
++              if (i > 10000) {
++                      printk(KERN_ERR "timeout waiting for blit to end!\n");
++                      return -ETIMEDOUT;
++              }
++      }
++
++      return ret;
++}
++
++static void
++tmiofb_fillrect(struct fb_info *fbi, const struct fb_fillrect *rect)
++{
++      const u32 cmd [] = {
++              TMIOFB_ACC_DSADR((rect->dy * fbi->mode->xres + rect->dx) * 2),
++              TMIOFB_ACC_DHPIX(rect->width    - 1),
++              TMIOFB_ACC_DVPIX(rect->height   - 1),
++              TMIOFB_ACC_FILL(rect->color),
++              TMIOFB_ACC_FLGO,
++      };
++
++      if (fbi->state != FBINFO_STATE_RUNNING ||
++          fbi->flags & FBINFO_HWACCEL_DISABLED) {
++              cfb_fillrect(fbi, rect);
++              return;
++      }
++
++      tmiofb_acc_write(fbi, cmd, ARRAY_SIZE(cmd));
++}
++
++static void
++tmiofb_copyarea(struct fb_info *fbi, const struct fb_copyarea *area)
++{
++      const u32 cmd [] = {
++              TMIOFB_ACC_DSADR((area->dy * fbi->mode->xres + area->dx) * 2),
++              TMIOFB_ACC_DHPIX(area->width    - 1),
++              TMIOFB_ACC_DVPIX(area->height   - 1),
++              TMIOFB_ACC_SSADR((area->sy * fbi->mode->xres + area->sx) * 2),
++              TMIOFB_ACC_SCGO,
++      };
++
++      if (fbi->state != FBINFO_STATE_RUNNING ||
++          fbi->flags & FBINFO_HWACCEL_DISABLED) {
++              cfb_copyarea(fbi, area);
++              return;
++      }
++
++      tmiofb_acc_write(fbi, cmd, ARRAY_SIZE(cmd));
++}
++#endif
++
++static void tmiofb_clearscreen(struct fb_info *info)
++{
++      const struct fb_fillrect rect = {
++              .dx     = 0,
++              .dy     = 0,
++              .width  = info->mode->xres,
++              .height = info->mode->yres,
++              .color  = 0,
++      };
++
++      info->fbops->fb_fillrect(info, &rect);
++}
++
++static int tmiofb_vblank(struct fb_info *fbi, struct fb_vblank *vblank)
++{
++      struct tmiofb_par       *par    = fbi->par;
++      struct fb_videomode     *mode   = fbi->mode;
++      unsigned int            vcount  = ioread16(&par->lcr->cdln);
++      unsigned int            vds     = mode->vsync_len + mode->upper_margin;
++
++      vblank->vcount  = vcount;
++      vblank->flags   = FB_VBLANK_HAVE_VBLANK | FB_VBLANK_HAVE_VCOUNT
++                                              | FB_VBLANK_HAVE_VSYNC;
++
++      if (vcount < mode->vsync_len)
++              vblank->flags |= FB_VBLANK_VSYNCING;
++
++      if (vcount < vds || vcount > vds + mode->yres)
++              vblank->flags |= FB_VBLANK_VBLANKING;
++
++      return 0;
++}
++
++
++static int tmiofb_ioctl(struct fb_info *fbi,
++              unsigned int cmd, unsigned long arg)
++{
++      switch (cmd) {
++      case FBIOGET_VBLANK: {
++              struct fb_vblank        vblank  = {0};
++              void __user             *argp   = (void __user *) arg;
++
++              tmiofb_vblank(fbi, &vblank);
++              if (copy_to_user(argp, &vblank, sizeof vblank))
++                              return -EFAULT;
++              return 0;
++      }
++
++#ifdef CONFIG_FB_TMIO_ACCELL
++      case FBIO_TMIO_ACC_SYNC:
++              tmiofb_sync(fbi);
++              return 0;
++
++      case FBIO_TMIO_ACC_WRITE: {
++              u32 __user      *argp   = (void __user *) arg;
++              u32             len;
++              u32             acc [16];
++
++              if (copy_from_user(&len, argp, sizeof(u32)))
++                      return -EFAULT;
++              if (len > ARRAY_SIZE(acc))
++                      return -EINVAL;
++              if (copy_from_user(acc, argp + 1, sizeof(u32) * len))
++                      return -EFAULT;
++
++              return tmiofb_acc_write(fbi, acc, len);
++      }
++#endif
++      }
++
++      return -EINVAL;
++}
++
++/*--------------------------------------------------------------------------*/
++
++/* Select the smallest mode that allows the desired resolution to be
++ * displayed.  If desired, the x and y parameters can be rounded up to
++ * match the selected mode.
++ */
++static struct fb_videomode*
++tmiofb_find_mode(struct fb_info *info, struct fb_var_screeninfo *var)
++{
++      struct mfd_cell                 *cell   = mfd_get_cell(to_platform_device(info->device));
++      struct tmio_fb_data             *data   = cell->driver_data;
++      struct fb_videomode             *best   = NULL;
++      int                             i;
++
++      for (i = 0; i < data->num_modes; i++) {
++              struct fb_videomode *mode = data->modes + i;
++
++              if (mode->xres >= var->xres && mode->yres >= var->yres
++                              && (!best || (mode->xres < best->xres
++                                         && mode->yres < best->yres)))
++                      best = mode;
++      }
++
++      return best;
++}
++
++static int tmiofb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
++{
++
++      struct fb_videomode     *mode;
++
++      mode = tmiofb_find_mode(info, var);
++      if (!mode || var->bits_per_pixel > 16)
++              return -EINVAL;
++
++      fb_videomode_to_var(var, mode);
++
++      var->xres_virtual       = mode->xres;
++      var->yres_virtual       = info->screen_size / (mode->xres * 2);
++      var->xoffset            = 0;
++      var->yoffset            = 0;
++      var->bits_per_pixel     = 16;
++      var->grayscale          = 0;
++      var->red.offset         = 11;   var->red.length         = 5;
++      var->green.offset       = 5;    var->green.length       = 6;
++      var->blue.offset        = 0;    var->blue.length        = 5;
++      var->transp.offset      = 0;    var->transp.length      = 0;
++      var->nonstd             = 0;
++      var->height             = 82;   /* mm */
++      var->width              = 60;   /* mm */
++      var->rotate             = 0;
++      return 0;
++}
++
++static int tmiofb_set_par(struct fb_info *info)
++{
++/*    struct fb_var_screeninfo        *var    = &info->var;
++      struct fb_videomode             *mode;
++
++      mode = tmiofb_find_mode(info, var);
++      if (!mode)
++              return -EINVAL;
++
++      if (info->mode == mode)
++              return 0;
++
++      info->mode              = mode; */
++      info->fix.line_length   = info->mode->xres * 2;
++
++      tmiofb_hw_mode(to_platform_device(info->device));
++      tmiofb_clearscreen(info);
++      return 0;
++}
++
++static int tmiofb_setcolreg(unsigned regno, unsigned red, unsigned green,
++                         unsigned blue, unsigned transp,
++                         struct fb_info *info)
++{
++      struct tmiofb_par       *par    = info->par;
++
++      if (regno < ARRAY_SIZE(par->pseudo_palette)) {
++              par->pseudo_palette [regno] =
++                      ((red   & 0xf800))              |
++                      ((green & 0xfc00) >>  5)        |
++                      ((blue  & 0xf800) >> 11);
++              return 0;
++      }
++
++      return 1;
++}
++
++static struct fb_ops tmiofb_ops = {
++      .owner          = THIS_MODULE,
++
++      .fb_ioctl       = tmiofb_ioctl,
++      .fb_check_var   = tmiofb_check_var,
++      .fb_set_par     = tmiofb_set_par,
++      .fb_setcolreg   = tmiofb_setcolreg,
++      .fb_imageblit   = cfb_imageblit,
++#ifdef CONFIG_FB_TMIO_ACCELL
++      .fb_sync        = tmiofb_sync,
++      .fb_fillrect    = tmiofb_fillrect,
++      .fb_copyarea    = tmiofb_copyarea,
++#else
++      .fb_fillrect    = cfb_fillrect,
++      .fb_copyarea    = cfb_copyarea,
++#endif
++};
++
++/*--------------------------------------------------------------------------*/
++
++/*
++ * reasons for an interrupt:
++ *    uis     bbisc   lcdis
++ *    0100    0001            accelerator command completed
++ *    2000            0001    vsync start
++ *    2000            0002    display start
++ *    2000            0004    line number match(0x1ff mask???)
++ */
++static irqreturn_t tmiofb_irq(int irq, void *__info)
++{
++      struct fb_info                  *info   = __info;
++      struct tmiofb_par               *par    = info->par;
++      struct tmio_lcr __iomem         *lcr    = par->lcr;
++      unsigned int                    bbisc   = ioread16(&lcr->bbisc);
++
++
++      if (unlikely(par->use_polling && irq != -1)) {
++              printk(KERN_INFO "tmiofb: switching to waitq\n");
++              par->use_polling = false;
++      }
++
++      iowrite16(bbisc, &lcr->bbisc);
++
++#ifdef CONFIG_FB_TMIO_ACCELL
++      if (bbisc & 1)
++              wake_up(&par->wait_acc);
++#endif
++
++      return IRQ_HANDLED;
++}
++
++static int tmiofb_probe(struct platform_device *dev)
++{
++      struct mfd_cell                 *cell   = mfd_get_cell(dev);
++      struct tmio_fb_data             *data   = cell->driver_data;
++      struct resource                 *ccr    = platform_get_resource_byname(dev, IORESOURCE_MEM, TMIO_FB_CONFIG);
++      struct resource                 *lcr    = platform_get_resource_byname(dev, IORESOURCE_MEM, TMIO_FB_CONTROL);
++      struct resource                 *vram   = platform_get_resource_byname(dev, IORESOURCE_MEM, TMIO_FB_VRAM);
++      int                             irq     = platform_get_irq(dev, 0);
++      struct fb_info                  *info;
++      struct tmiofb_par               *par;
++      int                             retval;
++
++      if (data == NULL) {
++              dev_err(&dev->dev, "NULL platform data!\n");
++              return -EINVAL;
++      }
++
++      info = framebuffer_alloc(sizeof(struct tmiofb_par), &dev->dev);
++
++      if (!info) {
++              retval = -ENOMEM;
++              goto err_framebuffer_alloc;
++      }
++
++      par = info->par;
++      platform_set_drvdata(dev, info);
++
++#ifdef CONFIG_FB_TMIO_ACCELL
++      init_waitqueue_head(&par->wait_acc);
++
++      par->use_polling        = true;
++
++      info->flags             = FBINFO_DEFAULT | FBINFO_HWACCEL_COPYAREA
++                                               | FBINFO_HWACCEL_FILLRECT;
++#else
++      info->flags             = FBINFO_DEFAULT;
++#endif
++
++      info->fbops             = &tmiofb_ops;
++
++      strcpy(info->fix.id, "tmio-fb");
++      info->fix.smem_start    = vram->start;
++      info->fix.smem_len      = vram->end - vram->start + 1;
++      info->fix.type          = FB_TYPE_PACKED_PIXELS;
++      info->fix.visual        = FB_VISUAL_TRUECOLOR;
++      info->fix.mmio_start    = lcr->start;
++      info->fix.mmio_len      = lcr->end - lcr->start + 1;
++      info->fix.accel         = FB_ACCEL_NONE;
++      info->screen_size       = info->fix.smem_len - (4 * TMIOFB_FIFO_SIZE);
++      info->pseudo_palette    = par->pseudo_palette;
++
++      par->ccr = ioremap(ccr->start, ccr->end - ccr->start + 1);
++      if (!par->ccr) {
++              retval = -ENOMEM;
++              goto err_ioremap_ccr;
++      }
++
++      par->lcr = ioremap(info->fix.mmio_start, info->fix.mmio_len);
++      if (!par->lcr) {
++              retval = -ENOMEM;
++              goto err_ioremap_lcr;
++      }
++
++      par->vram = ioremap(info->fix.smem_start, info->fix.smem_len);
++      if (!par->vram) {
++              retval = -ENOMEM;
++              goto err_ioremap_vram;
++      }
++      info->screen_base = par->vram;
++
++      retval = request_irq(irq, &tmiofb_irq, IRQF_DISABLED,
++                                      dev->dev.bus_id, info);
++
++      if (retval)
++              goto err_request_irq;
++
++      retval = fb_find_mode(&info->var, info, mode_option,
++                      data->modes, data->num_modes,
++                      data->modes, 16);
++      if (!retval) {
++              retval = -EINVAL;
++              goto err_find_mode;
++      }
++
++      retval = cell->enable(dev);
++      if (retval)
++              goto err_enable;
++
++      retval = tmiofb_hw_init(dev);
++      if (retval)
++              goto err_hw_init;
++
++/*    retval = tmiofb_set_par(info);
++      if (retval)
++              goto err_set_par;*/
++
++      retval = register_framebuffer(info);
++      if (retval < 0)
++              goto err_register_framebuffer;
++
++      printk(KERN_INFO "fb%d: %s frame buffer device\n",
++                              info->node, info->fix.id);
++
++      return 0;
++
++err_register_framebuffer:
++/*err_set_par:*/
++      tmiofb_hw_stop(dev);
++err_hw_init:
++      cell->disable(dev);
++err_enable:
++err_find_mode:
++      free_irq(irq, info);
++err_request_irq:
++      iounmap(par->vram);
++err_ioremap_vram:
++      iounmap(par->lcr);
++err_ioremap_lcr:
++      iounmap(par->ccr);
++err_ioremap_ccr:
++      platform_set_drvdata(dev, NULL);
++      framebuffer_release(info);
++err_framebuffer_alloc:
++      return retval;
++}
++
++static int __devexit tmiofb_remove(struct platform_device *dev)
++{
++      struct mfd_cell                 *cell   = mfd_get_cell(dev);
++      struct fb_info                  *info   = platform_get_drvdata(dev);
++      int                             irq     = platform_get_irq(dev, 0);
++      struct tmiofb_par               *par;
++
++      if (info) {
++              par = info->par;
++              unregister_framebuffer(info);
++
++              tmiofb_hw_stop(dev);
++
++              cell->disable(dev);
++
++              free_irq(irq, info);
++
++              iounmap(par->vram);
++              iounmap(par->lcr);
++              iounmap(par->ccr);
++
++              framebuffer_release(info);
++              platform_set_drvdata(dev, NULL);
++      }
++
++      return 0;
++}
++
++#if 0
++static void tmiofb_dump_regs(struct platform_device *dev)
++{
++      struct fb_info                  *info   = platform_get_drvdata(dev);
++      struct tmiofb_par               *par    = info->par;
++      struct tmio_lhccr __iomem       *ccr    = par->ccr;
++      struct tmio_lcr __iomem         *lcr    = par->lcr;
++
++      printk("lhccr:\n");
++#define CCR_PR(n)     printk("\t" #n " = \t%04x\n", ioread16(&ccr->n));
++      CCR_PR(cmd);
++      CCR_PR(revid);
++      CCR_PR(basel);
++      CCR_PR(baseh);
++      CCR_PR(ugcc);
++      CCR_PR(gcc);
++      CCR_PR(usc);
++      CCR_PR(vramrtc);
++      CCR_PR(vramsac);
++      CCR_PR(vrambc);
++#undef CCR_PR
++
++      printk("lcr: \n");
++#define LCR_PR(n)     printk("\t" #n " = \t%04x\n", ioread16(&lcr->n));
++      LCR_PR(uis);
++      LCR_PR(vhpn);
++      LCR_PR(cfsal);
++      LCR_PR(cfsah);
++      LCR_PR(cfs);
++      LCR_PR(cfws);
++      LCR_PR(bbie);
++      LCR_PR(bbisc);
++      LCR_PR(ccs);
++      LCR_PR(bbes);
++      LCR_PR(cmdl);
++      LCR_PR(cmdh);
++      LCR_PR(cfc);
++      LCR_PR(ccifc);
++      LCR_PR(hwt);
++      LCR_PR(lcdccrc);
++      LCR_PR(lcdcc);
++      LCR_PR(lcdcopc);
++      LCR_PR(lcdis);
++      LCR_PR(lcdim);
++      LCR_PR(lcdie);
++      LCR_PR(gdsal);
++      LCR_PR(gdsah);
++      LCR_PR(vhpcl);
++      LCR_PR(vhpch);
++      LCR_PR(gm);
++      LCR_PR(ht);
++      LCR_PR(hds);
++      LCR_PR(hss);
++      LCR_PR(hse);
++      LCR_PR(hnp);
++      LCR_PR(vt);
++      LCR_PR(vds);
++      LCR_PR(vss);
++      LCR_PR(vse);
++      LCR_PR(cdln);
++      LCR_PR(iln);
++      LCR_PR(sp);
++      LCR_PR(misc);
++      LCR_PR(vihss);
++      LCR_PR(vivs);
++      LCR_PR(vive);
++      LCR_PR(vivss);
++      LCR_PR(vccis);
++      LCR_PR(vidwsal);
++      LCR_PR(vidwsah);
++      LCR_PR(vidrsal);
++      LCR_PR(vidrsah);
++      LCR_PR(vipddst);
++      LCR_PR(vipddet);
++      LCR_PR(vie);
++      LCR_PR(vcs);
++      LCR_PR(vphwc);
++      LCR_PR(vphs);
++      LCR_PR(vpvwc);
++      LCR_PR(vpvs);
++      LCR_PR(plhpix);
++      LCR_PR(xs);
++      LCR_PR(xckhw);
++      LCR_PR(sths);
++      LCR_PR(vt2);
++      LCR_PR(ycksw);
++      LCR_PR(ysts);
++      LCR_PR(ppols);
++      LCR_PR(precw);
++      LCR_PR(vclkhw);
++      LCR_PR(oc);
++#undef LCR_PR
++}
++#endif
++
++#ifdef CONFIG_PM
++static int tmiofb_suspend(struct platform_device *dev, pm_message_t state)
++{
++      struct fb_info                  *info   = platform_get_drvdata(dev);
++      struct tmiofb_par               *par    = info->par;
++      struct mfd_cell                 *cell   = mfd_get_cell(dev);
++      int                             retval  = 0;
++
++      acquire_console_sem();
++
++      fb_set_suspend(info, 1);
++
++      if (info->fbops->fb_sync)
++              info->fbops->fb_sync(info);
++
++
++      printk(KERN_INFO "tmiofb: switching to polling\n");
++      par->use_polling = true;
++      tmiofb_hw_stop(dev);
++
++      if (cell->suspend)
++              retval = cell->suspend(dev);
++
++      release_console_sem();
++
++      return retval;
++}
++
++static int tmiofb_resume(struct platform_device *dev)
++{
++      struct fb_info                  *info   = platform_get_drvdata(dev);
++      struct mfd_cell                 *cell   = mfd_get_cell(dev);
++      int                             retval;
++
++      acquire_console_sem();
++
++      if (cell->resume) {
++              retval = cell->resume(dev);
++              if (retval)
++                      return retval;
++      }
++
++      tmiofb_irq(-1, info);
++
++      tmiofb_hw_init(dev);
++
++      tmiofb_hw_mode(dev);
++
++      fb_set_suspend(info, 0);
++      release_console_sem();
++      return 0;
++}
++#endif
++
++static struct platform_driver tmiofb_driver = {
++      .driver.name    = "tmio-fb",
++      .driver.owner   = THIS_MODULE,
++      .probe          = tmiofb_probe,
++      .remove         = __devexit_p(tmiofb_remove),
++#ifdef CONFIG_PM
++      .suspend        = tmiofb_suspend,
++      .resume         = tmiofb_resume,
++#endif
++};
++
++/*--------------------------------------------------------------------------*/
++
++#ifndef MODULE
++static void __init tmiofb_setup(char *options)
++{
++      char *this_opt;
++
++      if (!options || !*options)
++              return;
++
++      while ((this_opt = strsep(&options, ",")) != NULL) {
++              if (!*this_opt) continue;
++              /*
++               * FIXME
++               */
++      }
++}
++#endif
++
++static int __init tmiofb_init(void)
++{
++#ifndef MODULE
++      char *option = NULL;
++
++      if (fb_get_options("tmiofb", &option))
++              return -ENODEV;
++      tmiofb_setup(option);
++#endif
++      return platform_driver_register(&tmiofb_driver);
++}
++
++static void __exit tmiofb_cleanup(void)
++{
++      platform_driver_unregister(&tmiofb_driver);
++}
++
++module_init(tmiofb_init);
++module_exit(tmiofb_cleanup);
++
++MODULE_DESCRIPTION("TMIO framebuffer driver");
++MODULE_AUTHOR("Chris Humbert, Dirk Opfer, Dmitry Baryshkov");
++MODULE_LICENSE("GPL");
+-- 
+1.5.3.8
+
diff --git a/packages/kexecboot/linux-kexecboot-2.6.24/tosa/0010-OHCI-driver-for-TMIO-devices.patch b/packages/kexecboot/linux-kexecboot-2.6.24/tosa/0010-OHCI-driver-for-TMIO-devices.patch
new file mode 100644 (file)
index 0000000..f358c06
--- /dev/null
@@ -0,0 +1,431 @@
+From e5f06830bc8d3ef4792c9c0569825d0347b39852 Mon Sep 17 00:00:00 2001
+From: Ian Molton <spyro@f2s.com>
+Date: Fri, 4 Jan 2008 18:43:31 +0000
+Subject: [PATCH 10/64] OHCI driver for TMIO devices
+
+---
+ drivers/usb/Kconfig          |    1 +
+ drivers/usb/host/Kconfig     |    1 +
+ drivers/usb/host/ohci-hcd.c  |    5 +
+ drivers/usb/host/ohci-tmio.c |  369 ++++++++++++++++++++++++++++++++++++++++++
+ 4 files changed, 376 insertions(+), 0 deletions(-)
+ create mode 100644 drivers/usb/host/ohci-tmio.c
+
+diff --git a/drivers/usb/Kconfig b/drivers/usb/Kconfig
+index 7580aa5..8912042 100644
+--- a/drivers/usb/Kconfig
++++ b/drivers/usb/Kconfig
+@@ -36,6 +36,7 @@ config USB_ARCH_HAS_OHCI
+       default y if ARCH_EP93XX
+       default y if ARCH_AT91
+       default y if ARCH_PNX4008
++      default y if MFD_TC6393XB
+       # PPC:
+       default y if STB03xxx
+       default y if PPC_MPC52xx
+diff --git a/drivers/usb/host/Kconfig b/drivers/usb/host/Kconfig
+index 49a91c5..5ae3589 100644
+--- a/drivers/usb/host/Kconfig
++++ b/drivers/usb/host/Kconfig
+@@ -101,6 +101,7 @@ config USB_OHCI_HCD
+       depends on USB && USB_ARCH_HAS_OHCI
+       select ISP1301_OMAP if MACH_OMAP_H2 || MACH_OMAP_H3
+       select I2C if ARCH_PNX4008
++      select DMABOUNCE if MFD_TC6393XB
+       ---help---
+         The Open Host Controller Interface (OHCI) is a standard for accessing
+         USB 1.1 host controller hardware.  It does more in hardware than Intel's
+diff --git a/drivers/usb/host/ohci-hcd.c b/drivers/usb/host/ohci-hcd.c
+index ecfe800..77abf3e 100644
+--- a/drivers/usb/host/ohci-hcd.c
++++ b/drivers/usb/host/ohci-hcd.c
+@@ -1043,6 +1043,11 @@ MODULE_LICENSE ("GPL");
+ #define PS3_SYSTEM_BUS_DRIVER ps3_ohci_driver
+ #endif
++#ifdef CONFIG_MFD_TC6393XB
++#include "ohci-tmio.c"
++#define PLATFORM_DRIVER               ohci_hcd_tmio_driver
++#endif
++
+ #ifdef CONFIG_USB_OHCI_HCD_SSB
+ #include "ohci-ssb.c"
+ #define SSB_OHCI_DRIVER               ssb_ohci_driver
+diff --git a/drivers/usb/host/ohci-tmio.c b/drivers/usb/host/ohci-tmio.c
+new file mode 100644
+index 0000000..be609f3
+--- /dev/null
++++ b/drivers/usb/host/ohci-tmio.c
+@@ -0,0 +1,369 @@
++/*
++ * OHCI HCD(Host Controller Driver) for USB.
++ *
++ *(C) Copyright 1999 Roman Weissgaerber <weissg@vienna.at>
++ *(C) Copyright 2000-2002 David Brownell <dbrownell@users.sourceforge.net>
++ *(C) Copyright 2002 Hewlett-Packard Company
++ *
++ * Bus glue for Toshiba Mobile IO(TMIO) Controller's OHCI core
++ *(C) Copyright 2005 Chris Humbert <mahadri-usb@drigon.com>
++ *
++ * This is known to work with the following variants:
++ *    TC6393XB revision 3     (32kB SRAM)
++ *
++ * The TMIO's OHCI core DMAs through a small internal buffer that
++ * is directly addressable by the CPU.  dma_declare_coherent_memory
++ * and DMA bounce buffers allow the higher-level OHCI host driver to
++ * work.  However, the dma API doesn't handle dma mapping failures
++ * well(dma_sg_map() is a prime example), so it is unusable.
++ *
++ * This HC pretends be a PIO-ish controller and uses the kernel's
++ * generic allocator for the entire SRAM.  Using the USB core's
++ * usb_operations, we provide hcd_buffer_alloc/free.  Using the OHCI's
++ * ohci_ops, we provide memory management for OHCI's TDs and EDs.  We
++ * internally queue a URB's TDs until enough dma memory is available
++ * to enqueue them with the HC.
++ *
++ * Written from sparse documentation from Toshiba and Sharp's driver
++ * for the 2.4 kernel,
++ *    usb-ohci-tc6393.c(C) Copyright 2004 Lineo Solutions, Inc.
++ *
++ * 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/fs.h>
++#include <linux/mount.h>
++#include <linux/pagemap.h>
++#include <linux/init.h>
++#include <linux/namei.h>
++#include <linux/sched.h>*/
++#include <linux/platform_device.h>
++#include <linux/mfd-core.h>
++#include <linux/mfd/tmio.h>
++#include <linux/dma-mapping.h>
++
++/*-------------------------------------------------------------------------*/
++
++/*
++ * USB Host Controller Configuration Register
++ */
++struct tmio_uhccr {
++      u8 x00[8];
++      u8      revid;  /* 0x08 Revision ID                             */
++      u8 x01[7];
++      u16     basel;  /* 0x10 USB Control Register Base Address Low   */
++      u16     baseh;  /* 0x12 USB Control Register Base Address High  */
++      u8 x02[0x2c];
++      u8      ilme;   /* 0x40 Internal Local Memory Enable            */
++      u8 x03[0x0b];
++      u16     pm;     /* 0x4c Power Management                        */
++      u8 x04[2];
++      u8      intc;   /* 0x50 INT Control                             */
++      u8 x05[3];
++      u16     lmw1l;  /* 0x54 Local Memory Window 1 LMADRS Low        */
++      u16     lmw1h;  /* 0x56 Local Memory Window 1 LMADRS High       */
++      u16     lmw1bl; /* 0x58 Local Memory Window 1 Base Address Low  */
++      u16     lmw1bh; /* 0x5A Local Memory Window 1 Base Address High */
++      u16     lmw2l;  /* 0x5C Local Memory Window 2 LMADRS Low        */
++      u16     lmw2h;  /* 0x5E Local Memory Window 2 LMADRS High       */
++      u16     lmw2bl; /* 0x60 Local Memory Window 2 Base Address Low  */
++      u16     lmw2bh; /* 0x62 Local Memory Window 2 Base Address High */
++      u8 x06[0x98];
++      u8      misc;   /* 0xFC MISC                                    */
++      u8 x07[3];
++} __attribute__((packed));
++
++#define UHCCR_PM_GKEN      0x0001
++#define UHCCR_PM_CKRNEN    0x0002
++#define UHCCR_PM_USBPW1    0x0004
++#define UHCCR_PM_USBPW2    0x0008
++#define UHCCR_PM_PMEE      0x0100
++#define UHCCR_PM_PMES      0x8000
++
++/*-------------------------------------------------------------------------*/
++
++struct tmio_hcd {
++      struct tmio_uhccr __iomem *ccr;
++};
++
++#define hcd_to_tmio(hcd)      ((struct tmio_hcd *)(hcd_to_ohci(hcd) + 1))
++#define ohci_to_tmio(ohci)    ((struct tmio_hcd *)(ohci + 1))
++
++/*-------------------------------------------------------------------------*/
++
++static void tmio_stop_hc(struct platform_device *dev)
++{
++      struct mfd_cell                 *cell   = mfd_get_cell(dev);
++      struct usb_hcd                  *hcd    = platform_get_drvdata(dev);
++      struct tmio_hcd                 *tmio   = hcd_to_tmio(hcd);
++      struct tmio_uhccr __iomem       *ccr    = tmio->ccr;
++      u16                             pm;
++
++      pm = UHCCR_PM_GKEN | UHCCR_PM_CKRNEN | UHCCR_PM_USBPW1 | UHCCR_PM_USBPW2;
++      iowrite8(0,             &ccr->intc);
++      iowrite8(0,             &ccr->ilme);
++      iowrite16(0,            &ccr->basel);
++      iowrite16(0,            &ccr->baseh);
++      iowrite16(pm,   &ccr->pm);
++
++      cell->disable(dev);
++}
++
++static void tmio_start_hc(struct platform_device *dev)
++{
++      struct mfd_cell                 *cell   = mfd_get_cell(dev);
++      struct usb_hcd                  *hcd    = platform_get_drvdata(dev);
++      struct tmio_hcd                 *tmio   = hcd_to_tmio(hcd);
++      struct tmio_uhccr __iomem       *ccr    = tmio->ccr;
++      u16                             pm;
++      unsigned long                   base    = hcd->rsrc_start;
++
++      pm = UHCCR_PM_CKRNEN | UHCCR_PM_GKEN | UHCCR_PM_PMEE | UHCCR_PM_PMES;
++      cell->enable(dev);
++
++      iowrite16(pm,   &ccr->pm);
++      iowrite16(base,         &ccr->basel);
++      iowrite16(base >> 16,   &ccr->baseh);
++      iowrite8(1,             &ccr->ilme);
++      iowrite8(2,             &ccr->intc);
++
++      dev_info(&dev->dev, "revision %d @ 0x%08llx, irq %d\n",
++                      ioread8(&ccr->revid), hcd->rsrc_start, hcd->irq);
++}
++
++static int usb_hcd_tmio_probe(const struct hc_driver *driver,
++              struct platform_device *dev)
++{
++      struct resource         *config = platform_get_resource_byname(dev, IORESOURCE_MEM, TMIO_OHCI_CONFIG);
++      struct resource         *regs   = platform_get_resource_byname(dev, IORESOURCE_MEM, TMIO_OHCI_CONTROL);
++      struct resource         *sram   = platform_get_resource_byname(dev, IORESOURCE_MEM, TMIO_OHCI_SRAM);
++      int                     irq     = platform_get_irq(dev, 0);
++      struct tmio_hcd         *tmio;
++      struct ohci_hcd         *ohci;
++      struct usb_hcd          *hcd;
++      int                     retval;
++
++      if (usb_disabled())
++              return -ENODEV;
++
++      hcd = usb_create_hcd(driver, &dev->dev, dev->dev.bus_id);
++      if (!hcd) {
++              retval = -ENOMEM;
++              goto err_usb_create_hcd;
++      }
++
++      hcd->rsrc_start = regs->start;
++      hcd->rsrc_len   = regs->end - regs->start + 1;
++
++      tmio            = hcd_to_tmio(hcd);
++
++      tmio->ccr = ioremap(config->start, config->end - config->start + 1);
++      if (!tmio->ccr) {
++              retval = -ENOMEM;
++              goto err_ioremap_ccr;
++      }
++
++      hcd->regs = ioremap(hcd->rsrc_start, hcd->rsrc_len);
++      if (!hcd->regs) {
++              retval = -ENOMEM;
++              goto err_ioremap_regs;
++      }
++
++      if (dma_declare_coherent_memory(&dev->dev, sram->start,
++                              sram->start,
++                              sram->end - sram->start + 1,
++                              DMA_MEMORY_MAP) != DMA_MEMORY_MAP) {
++              retval = -EBUSY;
++              goto err_dma_declare;
++      }
++
++      retval = dmabounce_register_dev(&dev->dev, 512, 4096);
++      if (retval)
++              goto err_dmabounce_register_dev;
++
++      tmio_start_hc(dev);
++      ohci = hcd_to_ohci(hcd);
++      ohci_hcd_init(ohci);
++
++      retval = usb_add_hcd(hcd, irq, IRQF_DISABLED);
++
++      if (retval == 0)
++              return retval;
++
++      tmio_stop_hc(dev);
++
++      dmabounce_unregister_dev(&dev->dev);
++err_dmabounce_register_dev:
++      dma_release_declared_memory(&dev->dev);
++err_dma_declare:
++      iounmap(hcd->regs);
++err_ioremap_regs:
++      iounmap(tmio->ccr);
++err_ioremap_ccr:
++      usb_put_hcd(hcd);
++err_usb_create_hcd:
++
++      return retval;
++}
++
++static void usb_hcd_tmio_remove(struct usb_hcd *hcd, struct platform_device *dev)
++{
++      struct tmio_hcd         *tmio   = hcd_to_tmio(hcd);
++
++      usb_remove_hcd(hcd);
++      tmio_stop_hc(dev);
++      dmabounce_unregister_dev(&dev->dev);
++      dma_release_declared_memory(&dev->dev);
++      iounmap(hcd->regs);
++      iounmap(tmio->ccr);
++      usb_put_hcd(hcd);
++}
++
++static int __devinit
++ohci_tmio_start(struct usb_hcd *hcd)
++{
++      struct ohci_hcd         *ohci   = hcd_to_ohci(hcd);
++      int                     retval;
++
++      if ((retval = ohci_init(ohci)) < 0)
++              return retval;
++
++      if ((retval = ohci_run(ohci)) < 0) {
++              err("can't start %s", hcd->self.bus_name);
++              ohci_stop(hcd);
++              return retval;
++      }
++
++      return 0;
++}
++
++static const struct hc_driver ohci_tmio_hc_driver = {
++      .description =          hcd_name,
++      .product_desc =         "TMIO OHCI USB Host Controller",
++      .hcd_priv_size =        sizeof(struct ohci_hcd) + sizeof (struct tmio_hcd),
++
++      /* generic hardware linkage */
++      .irq =                  ohci_irq,
++      .flags =                HCD_USB11 | HCD_MEMORY,
++
++      /* basic lifecycle operations */
++      .start =                ohci_tmio_start,
++      .stop =                 ohci_stop,
++      .shutdown =             ohci_shutdown,
++
++      /* managing i/o requests and associated device resources */
++      .urb_enqueue =          ohci_urb_enqueue,
++      .urb_dequeue =          ohci_urb_dequeue,
++      .endpoint_disable =     ohci_endpoint_disable,
++
++      /* scheduling support */
++      .get_frame_number =     ohci_get_frame,
++
++      /* root hub support */
++      .hub_status_data =      ohci_hub_status_data,
++      .hub_control =          ohci_hub_control,
++      .hub_irq_enable =       ohci_rhsc_enable,
++#ifdef        CONFIG_PM
++      .bus_suspend =          ohci_bus_suspend,
++      .bus_resume =           ohci_bus_resume,
++#endif
++      .start_port_reset =     ohci_start_port_reset,
++};
++
++/*-------------------------------------------------------------------------*/
++static struct platform_driver ohci_hcd_tmio_driver;
++
++static int
++tmio_dmabounce_check(struct device *dev, dma_addr_t dma, size_t size, void *data)
++{
++      struct resource         *sram   = data;
++#ifdef DEBUG
++      printk(KERN_ERR "tmio_dmabounce_check: %08x %d\n", dma, size);
++#endif
++
++      if (dev->driver != &ohci_hcd_tmio_driver.driver)
++              return 0;
++
++      if (sram->start <= dma && dma + size <= sram->end)
++              return 0;
++
++      return 1;
++}
++
++static u64 dma_mask = DMA_32BIT_MASK;
++
++static int ohci_hcd_tmio_drv_probe(struct platform_device *dev)
++{
++      struct resource         *sram   = platform_get_resource_byname(dev, IORESOURCE_MEM, TMIO_OHCI_SRAM);
++
++      dev->dev.dma_mask = &dma_mask;
++      dev->dev.coherent_dma_mask = DMA_32BIT_MASK;
++
++      dmabounce_register_checker(tmio_dmabounce_check, sram);
++
++      return usb_hcd_tmio_probe(&ohci_tmio_hc_driver, dev);
++}
++
++static int ohci_hcd_tmio_drv_remove(struct platform_device *dev)
++{
++      struct usb_hcd          *hcd    = platform_get_drvdata(dev);
++      struct resource         *sram   = platform_get_resource_byname(dev, IORESOURCE_MEM, TMIO_OHCI_SRAM);
++
++      usb_hcd_tmio_remove(hcd, dev);
++
++      platform_set_drvdata(dev, NULL);
++
++      dmabounce_remove_checker(tmio_dmabounce_check, sram);
++
++      return 0;
++}
++
++#ifdef        CONFIG_PM
++static int ohci_hcd_tmio_drv_suspend(struct platform_device *dev, pm_message_t state)
++{
++      struct usb_hcd          *hcd    = platform_get_drvdata(dev);
++      struct ohci_hcd         *ohci   = hcd_to_ohci(hcd);
++
++      if (time_before(jiffies, ohci->next_statechange))
++              msleep(5);
++      ohci->next_statechange = jiffies;
++
++      tmio_stop_hc(dev);
++      hcd->state = HC_STATE_SUSPENDED;
++      dev->dev.power.power_state = PMSG_SUSPEND;
++
++      return 0;
++}
++
++static int ohci_hcd_tmio_drv_resume(struct platform_device *dev)
++{
++      struct usb_hcd          *hcd    = platform_get_drvdata(dev);
++      struct ohci_hcd         *ohci   = hcd_to_ohci(hcd);
++
++      if (time_before(jiffies, ohci->next_statechange))
++              msleep(5);
++      ohci->next_statechange = jiffies;
++
++      tmio_start_hc(dev);
++
++      dev->dev.power.power_state = PMSG_ON;
++      usb_hcd_resume_root_hub(hcd);
++
++      return 0;
++}
++#endif
++
++static struct platform_driver ohci_hcd_tmio_driver = {
++      .probe          = ohci_hcd_tmio_drv_probe,
++      .remove         = ohci_hcd_tmio_drv_remove,
++      .shutdown       = usb_hcd_platform_shutdown,
++#ifdef CONFIG_PM
++      .suspend        = ohci_hcd_tmio_drv_suspend,
++      .resume         = ohci_hcd_tmio_drv_resume,
++#endif
++      .driver         = {
++              .name   = "tmio-ohci",
++      },
++};
+-- 
+1.5.3.8
+
diff --git a/packages/kexecboot/linux-kexecboot-2.6.24/tosa/0011-MMC-driver-for-TMIO-devices.patch b/packages/kexecboot/linux-kexecboot-2.6.24/tosa/0011-MMC-driver-for-TMIO-devices.patch
new file mode 100644 (file)
index 0000000..6ff752d
--- /dev/null
@@ -0,0 +1,891 @@
+From b358a64c1fdd1eb80da57f919c893d910db95e37 Mon Sep 17 00:00:00 2001
+From: Ian Molton <spyro@f2s.com>
+Date: Sat, 29 Dec 2007 15:26:19 +0000
+Subject: [PATCH 11/64] MMC driver for TMIO devices
+
+---
+ drivers/mmc/host/Kconfig    |    6 +
+ drivers/mmc/host/Makefile   |    1 +
+ drivers/mmc/host/tmio_mmc.c |  633 +++++++++++++++++++++++++++++++++++++++++++
+ drivers/mmc/host/tmio_mmc.h |  205 ++++++++++++++
+ 4 files changed, 845 insertions(+), 0 deletions(-)
+ create mode 100644 drivers/mmc/host/tmio_mmc.c
+ create mode 100644 drivers/mmc/host/tmio_mmc.h
+
+diff --git a/drivers/mmc/host/Kconfig b/drivers/mmc/host/Kconfig
+index 5fef678..f8f9b7e 100644
+--- a/drivers/mmc/host/Kconfig
++++ b/drivers/mmc/host/Kconfig
+@@ -130,3 +130,9 @@ config MMC_SPI
+         If unsure, or if your system has no SPI master driver, say N.
++config MMC_TMIO
++      tristate "Toshiba Mobile IO Controller (TMIO) MMC/SD function support"
++      depends on MMC
++      help
++        This provides support for the SD/MMC cell found in TC6393XB,
++        T7L66XB and also ipaq ASIC3
+diff --git a/drivers/mmc/host/Makefile b/drivers/mmc/host/Makefile
+index 3877c87..7ac956b 100644
+--- a/drivers/mmc/host/Makefile
++++ b/drivers/mmc/host/Makefile
+@@ -17,4 +17,5 @@ obj-$(CONFIG_MMC_OMAP)               += omap.o
+ obj-$(CONFIG_MMC_AT91)                += at91_mci.o
+ obj-$(CONFIG_MMC_TIFM_SD)     += tifm_sd.o
+ obj-$(CONFIG_MMC_SPI)         += mmc_spi.o
++obj-$(CONFIG_MMC_TMIO)                += tmio_mmc.o
+diff --git a/drivers/mmc/host/tmio_mmc.c b/drivers/mmc/host/tmio_mmc.c
+new file mode 100644
+index 0000000..735c386
+--- /dev/null
++++ b/drivers/mmc/host/tmio_mmc.c
+@@ -0,0 +1,633 @@
++/*
++ *  linux/drivers/mmc/tmio_mmc.c
++ *
++ *  Copyright (C) 2004 Ian Molton
++ *  Copyright (C) 2007 Ian Molton
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ *
++ * Driver for the MMC / SD / SDIO cell found in:
++ *
++ * TC6393XB TC6391XB TC6387XB T7L66XB
++ *
++ * This driver draws mainly on scattered spec sheets, Reverse engineering
++ * of the toshiba e800  SD driver and some parts of the 2.4 ASIC3 driver (4 bit
++ * support). (Further 4 bit support from a later datasheet).
++ *
++ * TODO:
++ *   Investigate using a workqueue for PIO transfers
++ *   Eliminate FIXMEs
++ *   SDIO support
++ *   Better Power management
++ *   Handle MMC errors better
++ *   double buffer support
++ *
++ */
++#include <linux/module.h>
++#include <linux/irq.h>
++#include <linux/device.h>
++#include <linux/delay.h>
++#include <linux/mmc/mmc.h>
++#include <linux/mmc/host.h>
++#include <linux/mfd-core.h>
++#include <linux/mfd/tmio.h>
++
++#include "tmio_mmc.h"
++
++/*
++ * Fixme - documentation conflicts on what the clock values are for the
++ * various dividers.
++ * One document I have says that its a divisor of a 24MHz clock, another 33.
++ * This probably depends on HCLK for a given platform, so we may need to
++ * require HCLK be passed to us from the MFD core.
++ *
++ */
++
++static void tmio_mmc_set_clock (struct tmio_mmc_host *host, int new_clock) {
++      struct tmio_mmc_cnf __iomem *cnf = host->cnf;
++      struct tmio_mmc_ctl __iomem *ctl = host->ctl;
++      u32 clk = 0, clock;
++
++      if (new_clock) {
++              for(clock = 46875, clk = 0x100; new_clock >= (clock<<1); ){
++                      clock <<= 1;
++                      clk >>= 1;
++              }
++              if(clk & 0x1)
++                      clk = 0x20000;
++
++              clk >>= 2;
++              if(clk & 0x8000) /* For full speed we disable the divider. */
++                      writeb(0, &cnf->sd_clk_mode);
++              else
++                      writeb(1, &cnf->sd_clk_mode);
++              clk |= 0x100;
++      }
++
++      writew(clk, &ctl->sd_card_clk_ctl);
++}
++
++static void tmio_mmc_clk_stop (struct tmio_mmc_host *host) {
++      struct tmio_mmc_ctl __iomem *ctl = host->ctl;
++
++      writew(0x0000, &ctl->clk_and_wait_ctl);
++      msleep(10);
++      writew(readw(&ctl->sd_card_clk_ctl) & ~0x0100, &ctl->sd_card_clk_ctl);
++      msleep(10);
++}
++
++static void tmio_mmc_clk_start (struct tmio_mmc_host *host) {
++      struct tmio_mmc_ctl __iomem *ctl = host->ctl;
++
++      writew(readw(&ctl->sd_card_clk_ctl) | 0x0100, &ctl->sd_card_clk_ctl);
++      msleep(10);
++      writew(0x0100, &ctl->clk_and_wait_ctl);
++      msleep(10);
++}
++
++static void reset(struct tmio_mmc_host *host) {
++      struct tmio_mmc_ctl __iomem *ctl = host->ctl;
++
++      /* FIXME - should we set stop clock reg here */
++      writew(0x0000, &ctl->reset_sd);
++      writew(0x0000, &ctl->reset_sdio);
++      msleep(10);
++      writew(0x0001, &ctl->reset_sd);
++      writew(0x0001, &ctl->reset_sdio);
++      msleep(10);
++}
++
++static void
++tmio_mmc_finish_request(struct tmio_mmc_host *host)
++{
++      struct mmc_request *mrq = host->mrq;
++
++      host->mrq = NULL;
++      host->cmd = NULL;
++      host->data = NULL;
++
++      mmc_request_done(host->mmc, mrq);
++}
++
++/* These are the bitmasks the tmio chip requires to implement the MMC response
++ * types. Note that R1 and R6 are the same in this scheme. */
++#define APP_CMD        0x0040
++#define RESP_NONE      0x0300
++#define RESP_R1        0x0400
++#define RESP_R1B       0x0500
++#define RESP_R2        0x0600
++#define RESP_R3        0x0700
++#define DATA_PRESENT   0x0800
++#define TRANSFER_READ  0x1000
++#define TRANSFER_MULTI 0x2000
++#define SECURITY_CMD   0x4000
++
++static void
++tmio_mmc_start_command(struct tmio_mmc_host *host, struct mmc_command *cmd)
++{
++        struct tmio_mmc_ctl __iomem *ctl = host->ctl;
++      struct mmc_data *data = host->data;
++      int c = cmd->opcode;
++
++      if(cmd->opcode == MMC_STOP_TRANSMISSION) {
++              writew(0x001, &ctl->stop_internal_action);
++              return;
++      }
++
++      switch(mmc_resp_type(cmd)) {
++              case MMC_RSP_NONE: c |= RESP_NONE; break;
++              case MMC_RSP_R1:   c |= RESP_R1;   break;
++              case MMC_RSP_R1B:  c |= RESP_R1B;  break;
++              case MMC_RSP_R2:   c |= RESP_R2;   break;
++              case MMC_RSP_R3:   c |= RESP_R3;   break;
++              default:
++                      DBG("Unknown response type %d\n", mmc_resp_type(cmd));
++      }
++
++      host->cmd = cmd;
++
++/* FIXME - this seems to be ok comented out but the spec suggest this bit should
++ *         be set when issuing app commands.
++ *    if(cmd->flags & MMC_FLAG_ACMD)
++ *            c |= APP_CMD;
++ */
++      if(data) {
++              c |= DATA_PRESENT;
++              if(data->blocks > 1) {
++                      writew(0x100, &ctl->stop_internal_action);
++                      c |= TRANSFER_MULTI;
++              }
++              if(data->flags & MMC_DATA_READ)
++                      c |= TRANSFER_READ;
++      }
++
++      enable_mmc_irqs(ctl, TMIO_MASK_CMD);
++
++      /* Fire off the command */
++      tmio_iowrite32(cmd->arg, ctl->arg_reg);
++      writew(c, &ctl->sd_cmd);
++}
++
++/* This chip always returns (at least?) as much data as you ask for.
++ * Im unsure what happens if you ask for less than a block. This should be
++ * looked into to ensure that a funny length read doesnt hose the controller.
++ *
++ * FIXME - this chip cannot do 1 and 2 byte data requests in 4 bit mode
++ */
++static inline void tmio_mmc_pio_irq(struct tmio_mmc_host *host) {
++        struct tmio_mmc_ctl __iomem *ctl = host->ctl;
++      struct mmc_data *data = host->data;
++        unsigned short *buf;
++        unsigned int count;
++        unsigned long flags;
++
++        if(!data){
++              DBG("Spurious PIO IRQ\n");
++                return;
++        }
++
++      buf = (unsigned short *)(tmio_mmc_kmap_atomic(host, &flags) +
++            host->sg_off);
++
++      /* Ensure we dont read more than one block. The chip will interrupt us
++       * When the next block is available.
++       * FIXME - this is probably not true now IRQ handling is fixed
++       */
++      count = host->sg_ptr->length - host->sg_off;
++      if(count > data->blksz)
++              count = data->blksz;
++
++      DBG("count: %08x offset: %08x flags %08x\n",
++          count, host->sg_off, data->flags);
++
++      /* Transfer the data */
++      if(data->flags & MMC_DATA_READ)
++              readsw(&ctl->sd_data_port[0], buf, count >> 1);
++      else
++              writesw(&ctl->sd_data_port[0], buf, count >> 1);
++
++      host->sg_off += count;
++
++      tmio_mmc_kunmap_atomic(host, &flags);
++
++      if(host->sg_off == host->sg_ptr->length)
++              tmio_mmc_next_sg(host);
++
++      return;
++}
++
++static inline void tmio_mmc_data_irq(struct tmio_mmc_host *host) {
++      struct tmio_mmc_ctl __iomem *ctl = host->ctl;
++      struct mmc_data *data = host->data;
++
++      host->data = NULL;
++
++      if(!data){
++              DBG("Spurious data end IRQ\n");
++              return;
++      }
++
++      /* FIXME - return correct transfer count on errors */
++      if (!data->error)
++              data->bytes_xfered = data->blocks * data->blksz;
++      else
++              data->bytes_xfered = 0;
++
++      DBG("Completed data request\n");
++
++      /*FIXME - other drivers allow an optional stop command of any given type
++       *        which we dont do, as the chip can auto generate them.
++       *        Perhaps we can be smarter about when to use auto CMD12 and
++       *        only issue the auto request when we know this is the desired
++       *        stop command, allowing fallback to the stop command the
++       *        upper layers expect. For now, we do what works.
++       */
++
++      writew(0x000, &ctl->stop_internal_action);
++
++      if(data->flags & MMC_DATA_READ)
++              disable_mmc_irqs(ctl, TMIO_MASK_READOP);
++      else
++              disable_mmc_irqs(ctl, TMIO_MASK_WRITEOP);
++
++      tmio_mmc_finish_request(host);
++}
++
++static inline void tmio_mmc_cmd_irq(struct tmio_mmc_host *host, unsigned int stat) {
++      struct tmio_mmc_ctl __iomem *ctl = host->ctl;
++      struct mmc_command *cmd = host->cmd;
++
++      if(!host->cmd) {
++              DBG("Spurious CMD irq\n");
++              return;
++      }
++
++      host->cmd = NULL;
++
++      /* This controller is sicker than the PXA one. not only do we need to
++       * drop the top 8 bits of the first response word, we also need to
++       * modify the order of the response for short response command types.
++       */
++
++      /* FIXME - this works but readl is wrong and will break on asic3... */
++      cmd->resp[3] = tmio_ioread32(&ctl->response[0]);
++      cmd->resp[2] = tmio_ioread32(&ctl->response[2]);
++      cmd->resp[1] = tmio_ioread32(&ctl->response[4]);
++      cmd->resp[0] = tmio_ioread32(&ctl->response[6]);
++
++      if(cmd->flags &  MMC_RSP_136) {
++              cmd->resp[0] = (cmd->resp[0] <<8) | (cmd->resp[1] >>24);
++              cmd->resp[1] = (cmd->resp[1] <<8) | (cmd->resp[2] >>24);
++              cmd->resp[2] = (cmd->resp[2] <<8) | (cmd->resp[3] >>24);
++              cmd->resp[3] <<= 8;
++      }
++      else if(cmd->flags & MMC_RSP_R3) {
++              cmd->resp[0] = cmd->resp[3];
++      }
++
++      if (stat & TMIO_STAT_CMDTIMEOUT)
++              cmd->error = -ETIMEDOUT;
++      else if (stat & TMIO_STAT_CRCFAIL && cmd->flags & MMC_RSP_CRC)
++              cmd->error = -EILSEQ;
++
++      /* If there is data to handle we enable data IRQs here, and
++       * we will ultimatley finish the request in the data_end handler.
++       * If theres no data or we encountered an error, finish now.
++       */
++      if(host->data && !cmd->error){
++              if(host->data->flags & MMC_DATA_READ)
++                      enable_mmc_irqs(ctl, TMIO_MASK_READOP);
++              else
++                      enable_mmc_irqs(ctl, TMIO_MASK_WRITEOP);
++      }
++      else {
++              tmio_mmc_finish_request(host);
++      }
++
++      return;
++}
++
++
++static irqreturn_t tmio_mmc_irq(int irq, void *devid)
++{
++      struct tmio_mmc_host *host = devid;
++      struct tmio_mmc_ctl __iomem *ctl = host->ctl;
++      unsigned int ireg, irq_mask, status;
++
++      DBG("MMC IRQ begin\n");
++
++      status = tmio_ioread32(ctl->status);
++      irq_mask   = tmio_ioread32(ctl->irq_mask);
++      ireg   = status & TMIO_MASK_IRQ & ~irq_mask;
++
++#ifdef CONFIG_MMC_DEBUG
++      debug_status(status);
++      debug_status(ireg);
++#endif
++      if (!ireg) {
++              disable_mmc_irqs(ctl, status & ~irq_mask);
++#ifdef CONFIG_MMC_DEBUG
++              WARN("tmio_mmc: Spurious MMC irq, disabling! 0x%08x 0x%08x 0x%08x\n", status, irq_mask, ireg);
++              debug_status(status);
++#endif
++              goto out;
++      }
++
++      while (ireg) {
++              /* Card insert / remove attempts */
++              if (ireg & (TMIO_STAT_CARD_INSERT | TMIO_STAT_CARD_REMOVE)){
++                      ack_mmc_irqs(ctl, TMIO_STAT_CARD_INSERT | TMIO_STAT_CARD_REMOVE);
++                      mmc_detect_change(host->mmc,0);
++              }
++
++              /* CRC and other errors */
++/*            if (ireg & TMIO_STAT_ERR_IRQ)
++ *                    handled |= tmio_error_irq(host, irq, stat);
++ */
++
++              /* Command completion */
++                      if (ireg & TMIO_MASK_CMD) {
++                      tmio_mmc_cmd_irq(host, status);
++                      ack_mmc_irqs(ctl, TMIO_MASK_CMD);
++              }
++
++              /* Data transfer */
++              if (ireg & (TMIO_STAT_RXRDY | TMIO_STAT_TXRQ)) {
++                      ack_mmc_irqs(ctl, TMIO_STAT_RXRDY | TMIO_STAT_TXRQ);
++                      tmio_mmc_pio_irq(host);
++              }
++
++              /* Data transfer completion */
++              if (ireg & TMIO_STAT_DATAEND) {
++                      tmio_mmc_data_irq(host);
++                      ack_mmc_irqs(ctl, TMIO_STAT_DATAEND);
++              }
++
++              /* Check status - keep going until we've handled it all */
++              status = tmio_ioread32(ctl->status);
++              irq_mask   = tmio_ioread32(ctl->irq_mask);
++              ireg   = status & TMIO_MASK_IRQ & ~irq_mask;
++
++#ifdef CONFIG_MMC_DEBUG
++              DBG("Status at end of loop: %08x\n", status);
++              debug_status(status);
++#endif
++      }
++      DBG("MMC IRQ end\n");
++
++out:
++      return IRQ_HANDLED;
++}
++
++static void tmio_mmc_start_data(struct tmio_mmc_host *host, struct mmc_data *data)
++{
++      struct tmio_mmc_ctl __iomem *ctl = host->ctl;
++
++      DBG("setup data transfer: blocksize %08x  nr_blocks %d\n",
++          data->blksz, data->blocks);
++
++      tmio_mmc_init_sg(host, data);
++      host->data = data;
++
++      /* Set transfer length / blocksize */
++      writew(data->blksz,  &ctl->sd_xfer_len);
++        writew(data->blocks, &ctl->xfer_blk_count);
++}
++
++/* Process requests from the MMC layer */
++static void tmio_mmc_request(struct mmc_host *mmc, struct mmc_request *mrq)
++{
++      struct tmio_mmc_host *host = mmc_priv(mmc);
++
++      WARN_ON(host->mrq != NULL);
++
++      host->mrq = mrq;
++
++      /* If we're performing a data request we need to setup some
++         extra information */
++      if (mrq->data)
++              tmio_mmc_start_data(host, mrq->data);
++
++      tmio_mmc_start_command(host, mrq->cmd);
++}
++
++/* Set MMC clock / power.
++ * Note: This controller uses a simple divider scheme therefore it cannot
++ * run a MMC card at full speed (20MHz). The max clock is 24MHz on SD, but as
++ * MMC wont run that fast, it has to be clocked at 12MHz which is the next
++ * slowest setting.
++ */
++static void tmio_mmc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
++{
++      struct tmio_mmc_host *host = mmc_priv(mmc);
++      struct tmio_mmc_cnf __iomem *cnf = host->cnf;
++        struct tmio_mmc_ctl __iomem *ctl = host->ctl;
++
++      if(ios->clock)
++              tmio_mmc_set_clock (host, ios->clock);
++
++      /* Power sequence - OFF -> ON -> UP */
++      switch (ios->power_mode) {
++      case MMC_POWER_OFF:
++              writeb(0x00, &cnf->pwr_ctl[1]);  /* power down SD bus */
++              tmio_mmc_clk_stop(host);
++              break;
++      case MMC_POWER_ON:
++              writeb(0x02, &cnf->pwr_ctl[1]);  /* power up SD bus */
++              break;
++      case MMC_POWER_UP:
++              tmio_mmc_clk_start(host);         /* start bus clock */
++              break;
++      }
++
++      switch (ios->bus_width) {
++      case MMC_BUS_WIDTH_1:
++              writew(0x80e0, &ctl->sd_mem_card_opt);
++      break;
++      case MMC_BUS_WIDTH_4:
++              writew(0x00e0, &ctl->sd_mem_card_opt);
++      break;
++      }
++
++      /* Potentially we may need a 140us pause here. FIXME */
++      udelay(140);
++}
++
++static int tmio_mmc_get_ro(struct mmc_host *mmc) {
++      struct tmio_mmc_host *host = mmc_priv(mmc);
++        struct tmio_mmc_ctl __iomem *ctl = host->ctl;
++
++      return (readw(&ctl->status[0]) & TMIO_STAT_WRPROTECT)?0:1;
++}
++
++static struct mmc_host_ops tmio_mmc_ops = {
++      .request        = tmio_mmc_request,
++      .set_ios        = tmio_mmc_set_ios,
++      .get_ro         = tmio_mmc_get_ro,
++};
++
++static int tmio_mmc_suspend(struct platform_device *dev, pm_message_t state) {
++      struct mfd_cell *cell   = mfd_get_cell(dev);
++      struct mmc_host *mmc = platform_get_drvdata(dev);
++      int ret;
++
++      ret = mmc_suspend_host(mmc, state);
++
++        /* Tell MFD core it can disable us now.*/
++      if(!ret && cell->disable)
++              cell->disable(dev);
++
++      return ret;
++}
++
++static int tmio_mmc_resume(struct platform_device *dev) {
++      struct mfd_cell *cell   = mfd_get_cell(dev);
++      struct mmc_host *mmc = platform_get_drvdata(dev);
++      struct tmio_mmc_host *host = mmc_priv(mmc);
++      struct tmio_mmc_cnf __iomem *cnf = host->cnf;
++
++      /* Enable the MMC/SD Control registers */
++      writew(SDCREN, &cnf->cmd);
++      writel(dev->resource[0].start & 0xfffe, &cnf->ctl_base);
++
++      /* Tell the MFD core we are ready to be enabled */
++      if(cell->enable)
++              cell->enable(dev);
++
++      mmc_resume_host(mmc);
++
++      return 0;
++}
++
++static int __devinit tmio_mmc_probe(struct platform_device *dev)
++{
++      struct mfd_cell *cell   = mfd_get_cell(dev);
++      struct tmio_mmc_cnf __iomem *cnf;
++      struct tmio_mmc_ctl __iomem *ctl;
++      struct tmio_mmc_host *host;
++      struct mmc_host *mmc;
++      int ret = -ENOMEM;
++
++      mmc = mmc_alloc_host(sizeof(struct tmio_mmc_host), &dev->dev);
++      if (!mmc) {
++              goto out;
++      }
++
++      host = mmc_priv(mmc);
++      host->mmc = mmc;
++      platform_set_drvdata(dev, mmc); /* Used so we can de-init safely. */
++
++      host->cnf = cnf = ioremap((unsigned long)dev->resource[1].start,
++                                (unsigned long)dev->resource[1].end -
++                                (unsigned long)dev->resource[1].start);
++      if(!host->cnf)
++              goto host_free;
++
++      host->ctl = ctl = ioremap((unsigned long)dev->resource[0].start,
++                                (unsigned long)dev->resource[0].end -
++                                (unsigned long)dev->resource[0].start);
++      if (!host->ctl) {
++              goto unmap_cnf;
++      }
++
++      mmc->ops = &tmio_mmc_ops;
++      mmc->caps = MMC_CAP_4_BIT_DATA;
++      mmc->f_min = 46875;
++      mmc->f_max = 24000000;
++      mmc->ocr_avail = MMC_VDD_32_33 | MMC_VDD_33_34;
++
++      /* Enable the MMC/SD Control registers */
++      writew(SDCREN, &cnf->cmd);
++      writel(dev->resource[0].start & 0xfffe, &cnf->ctl_base);
++
++      /* Tell the MFD core we are ready to be enabled */
++      if(cell->enable)
++              cell->enable(dev);
++
++      writeb(0x01,&cnf->pwr_ctl[2]);    /* Disable SD power during suspend */
++      writeb(0x1f, &cnf->stop_clk_ctl); /* Route clock to SDIO??? FIXME */
++      writeb(0x0, &cnf->pwr_ctl[1]);    /* Power down SD bus*/
++      tmio_mmc_clk_stop(host);          /* Stop bus clock */
++      reset(host);                      /* Reset MMC HC */
++
++      host->irq = (unsigned long)dev->resource[2].start;
++      ret = request_irq(host->irq, tmio_mmc_irq, IRQF_DISABLED, "tmio-mmc", host);
++      if (ret){
++              ret = -ENODEV;
++              DBG("Failed to allocate IRQ.\n");
++              goto unmap_ctl;
++      }
++      set_irq_type(host->irq, IRQT_FALLING);
++
++      mmc_add_host(mmc);
++
++      printk(KERN_INFO "%s at 0x%08lx irq %d\n", mmc_hostname(host->mmc),
++           (unsigned long)host->ctl, host->irq);
++
++      /* Lets unmask the IRQs we want to know about */
++      disable_mmc_irqs(ctl, TMIO_MASK_ALL);
++      enable_mmc_irqs(ctl,  TMIO_MASK_IRQ);
++
++      return 0;
++
++unmap_ctl:
++      iounmap(host->ctl);
++unmap_cnf:
++      iounmap(host->cnf);
++host_free:
++      mmc_free_host(mmc);
++out:
++      return ret;
++}
++
++static int __devexit tmio_mmc_remove(struct platform_device *dev)
++{
++      struct mmc_host *mmc = platform_get_drvdata(dev);
++
++      platform_set_drvdata(dev, NULL);
++
++      if (mmc) {
++              struct tmio_mmc_host *host = mmc_priv(mmc);
++              mmc_remove_host(mmc);
++              free_irq(host->irq, host);
++              /* FIXME - we might want to consider stopping the chip here. */
++              iounmap(host->ctl);
++              iounmap(host->cnf);
++              mmc_free_host(mmc); /* FIXME - why does this call hang ? */
++      }
++      return 0;
++}
++
++/* ------------------- device registration ----------------------- */
++
++static struct platform_driver tmio_mmc_driver = {
++      .driver = {
++              .name = "tmio-mmc",
++      },
++      .probe = tmio_mmc_probe,
++      .remove = __devexit_p(tmio_mmc_remove),
++#ifdef CONFIG_PM
++      .suspend = tmio_mmc_suspend,
++      .resume = tmio_mmc_resume,
++#endif
++};
++
++
++static int __init tmio_mmc_init(void)
++{
++      return platform_driver_register (&tmio_mmc_driver);
++}
++
++static void __exit tmio_mmc_exit(void)
++{
++      platform_driver_unregister (&tmio_mmc_driver);
++}
++
++module_init(tmio_mmc_init);
++module_exit(tmio_mmc_exit);
++
++MODULE_DESCRIPTION("Toshiba TMIO SD/MMC driver");
++MODULE_AUTHOR("Ian Molton <spyro@f2s.com>");
++MODULE_LICENSE("GPLv2");
+diff --git a/drivers/mmc/host/tmio_mmc.h b/drivers/mmc/host/tmio_mmc.h
+new file mode 100644
+index 0000000..d4d9f8f
+--- /dev/null
++++ b/drivers/mmc/host/tmio_mmc.h
+@@ -0,0 +1,205 @@
++/* Definitons for use with the tmio_mmc.c
++ *
++ * (c) 2005 Ian Molton <spyro@f2s.com>
++ * (c) 2007 Ian Molton <spyro@f2s.com>
++ *
++ * This program is free software; you can redistribute it and/or modify
++ * it under the terms of the GNU General Public License version 2 as
++ * published by the Free Software Foundation.
++ *
++ */
++
++struct tmio_mmc_cnf {
++      u8 x00[4];
++      u16     cmd;
++      u8 x01[10];
++      u32     ctl_base;
++      u8 x02[41];
++      u8      int_pin;
++      u8 x03[2];
++      u8      stop_clk_ctl;
++      u8      gclk_ctl;     /* Gated Clock Control */
++      u8      sd_clk_mode;  /* 0x42 */
++      u8 x04;
++      u16     pin_status;
++      u8 x05[2];
++      u8      pwr_ctl[3];
++      u8 x06;
++      u8      card_detect_mode;
++      u8 x07[3];
++      u8      sd_slot;
++      u8 x08[159];
++      u8      ext_gclk_ctl_1; /* Extended Gated Clock Control 1 */
++      u8      ext_gclk_ctl_2; /* Extended Gated Clock Control 2 */
++      u8 x09[7];
++      u8      ext_gclk_ctl_3; /* Extended Gated Clock Control 3 */
++      u8      sd_led_en_1;
++      u8 x10[3];
++      u8      sd_led_en_2;
++      u8 x11;
++} __attribute__ ((packed));
++
++#define   SDCREN 0x2   /* Enable access to MMC CTL regs. (flag in COMMAND_REG)*/
++
++struct tmio_mmc_ctl {
++      u16     sd_cmd;
++      u16     x00;
++      u16     arg_reg[2];
++      u16     stop_internal_action;
++      u16     xfer_blk_count;
++      u16     response[8];
++      u16     status[2];
++      u16     irq_mask[2];
++      u16     sd_card_clk_ctl;
++      u16     sd_xfer_len;
++      u16     sd_mem_card_opt;
++      u16     x01;
++      u16     sd_error_detail_status[2];
++      u16     sd_data_port[2];
++      u16     transaction_ctl;
++      u16     x02[85];
++      u16     reset_sd;
++      u16     x03[15];
++      u16     sdio_regs[28];
++      u16     clk_and_wait_ctl;
++      u16     x04[83];
++      u16     reset_sdio;
++      u16     x05[15];
++} __attribute__ ((packed));
++
++/* Definitions for values the CTRL_STATUS register can take. */
++#define TMIO_STAT_CMDRESPEND    0x00000001
++#define TMIO_STAT_DATAEND       0x00000004
++#define TMIO_STAT_CARD_REMOVE   0x00000008
++#define TMIO_STAT_CARD_INSERT   0x00000010
++#define TMIO_STAT_SIGSTATE      0x00000020
++#define TMIO_STAT_WRPROTECT     0x00000080
++#define TMIO_STAT_CARD_REMOVE_A 0x00000100
++#define TMIO_STAT_CARD_INSERT_A 0x00000200
++#define TMIO_STAT_SIGSTATE_A    0x00000400
++#define TMIO_STAT_CMD_IDX_ERR   0x00010000
++#define TMIO_STAT_CRCFAIL       0x00020000
++#define TMIO_STAT_STOPBIT_ERR   0x00040000
++#define TMIO_STAT_DATATIMEOUT   0x00080000
++#define TMIO_STAT_RXOVERFLOW    0x00100000
++#define TMIO_STAT_TXUNDERRUN    0x00200000
++#define TMIO_STAT_CMDTIMEOUT    0x00400000
++#define TMIO_STAT_RXRDY         0x01000000
++#define TMIO_STAT_TXRQ          0x02000000
++#define TMIO_STAT_ILL_FUNC      0x20000000
++#define TMIO_STAT_CMD_BUSY      0x40000000
++#define TMIO_STAT_ILL_ACCESS    0x80000000
++
++/* Define some IRQ masks */
++/* This is the mask used at reset by the chip */
++#define TMIO_MASK_ALL           0x837f031d
++#define TMIO_MASK_READOP  (TMIO_STAT_RXRDY | TMIO_STAT_DATAEND | \
++                           TMIO_STAT_CARD_REMOVE | TMIO_STAT_CARD_INSERT)
++#define TMIO_MASK_WRITEOP (TMIO_STAT_TXRQ | TMIO_STAT_DATAEND | \
++                           TMIO_STAT_CARD_REMOVE | TMIO_STAT_CARD_INSERT)
++#define TMIO_MASK_CMD     (TMIO_STAT_CMDRESPEND | TMIO_STAT_CMDTIMEOUT | \
++                           TMIO_STAT_CARD_REMOVE | TMIO_STAT_CARD_INSERT)
++#define TMIO_MASK_IRQ     (TMIO_MASK_READOP | TMIO_MASK_WRITEOP | TMIO_MASK_CMD)
++
++#define enable_mmc_irqs(ctl, i) \
++      do { \
++              u32 mask;\
++              mask  = tmio_ioread32((ctl)->irq_mask); \
++              mask &= ~((i) & TMIO_MASK_IRQ); \
++              tmio_iowrite32(mask, (ctl)->irq_mask); \
++      } while (0)
++
++#define disable_mmc_irqs(ctl, i) \
++      do { \
++              u32 mask;\
++              mask  = tmio_ioread32((ctl)->irq_mask); \
++              mask |= ((i) & TMIO_MASK_IRQ); \
++              tmio_iowrite32(mask, (ctl)->irq_mask); \
++      } while (0)
++
++#define ack_mmc_irqs(ctl, i) \
++      do { \
++              u32 mask;\
++              mask  = tmio_ioread32((ctl)->status); \
++              mask &= ~((i) & TMIO_MASK_IRQ); \
++              tmio_iowrite32(mask, (ctl)->status); \
++      } while (0)
++
++
++struct tmio_mmc_host {
++      struct tmio_mmc_cnf __iomem *cnf;
++      struct tmio_mmc_ctl __iomem *ctl;
++      struct mmc_command      *cmd;
++      struct mmc_request      *mrq;
++      struct mmc_data         *data;
++      struct mmc_host         *mmc;
++      int                     irq;
++
++      /* pio related stuff */
++      struct scatterlist      *sg_ptr;
++      unsigned int            sg_len;
++      unsigned int            sg_off;
++};
++
++#include <linux/scatterlist.h>
++#include <linux/blkdev.h>
++
++static inline void tmio_mmc_init_sg(struct tmio_mmc_host *host, struct mmc_data *data)
++{
++      host->sg_len = data->sg_len;
++      host->sg_ptr = data->sg;
++      host->sg_off = 0;
++}
++
++static inline int tmio_mmc_next_sg(struct tmio_mmc_host *host)
++{
++      host->sg_ptr++;
++      host->sg_off = 0;
++      return --host->sg_len;
++}
++
++static inline char *tmio_mmc_kmap_atomic(struct tmio_mmc_host *host, unsigned long *flags)
++{
++      struct scatterlist *sg = host->sg_ptr;
++
++      local_irq_save(*flags);
++      return kmap_atomic(sg_page(sg), KM_BIO_SRC_IRQ) + sg->offset;
++}
++
++static inline void tmio_mmc_kunmap_atomic(struct tmio_mmc_host *host, unsigned long *flags)
++{
++      kunmap_atomic(sg_page(host->sg_ptr), KM_BIO_SRC_IRQ);
++      local_irq_restore(*flags);
++}
++
++#ifdef CONFIG_MMC_DEBUG
++#define DBG(args...)    printk(args)
++
++void debug_status(u32 status){
++      printk("status: %08x = ", status);
++      if(status & TMIO_STAT_CARD_REMOVE) printk("Card_removed ");
++      if(status & TMIO_STAT_CARD_INSERT) printk("Card_insert ");
++      if(status & TMIO_STAT_SIGSTATE) printk("Sigstate ");
++      if(status & TMIO_STAT_WRPROTECT) printk("Write_protect ");
++      if(status & TMIO_STAT_CARD_REMOVE_A) printk("Card_remove_A ");
++      if(status & TMIO_STAT_CARD_INSERT_A) printk("Card_insert_A ");
++      if(status & TMIO_STAT_SIGSTATE_A) printk("Sigstate_A ");
++      if(status & TMIO_STAT_CMD_IDX_ERR) printk("Cmd_IDX_Err ");
++      if(status & TMIO_STAT_STOPBIT_ERR) printk("Stopbit_ERR ");
++      if(status & TMIO_STAT_ILL_FUNC) printk("ILLEGAL_FUNC ");
++      if(status & TMIO_STAT_CMD_BUSY) printk("CMD_BUSY ");
++      if(status & TMIO_STAT_CMDRESPEND)  printk("Response_end ");
++      if(status & TMIO_STAT_DATAEND)     printk("Data_end ");
++      if(status & TMIO_STAT_CRCFAIL)     printk("CRC_failure ");
++      if(status & TMIO_STAT_DATATIMEOUT) printk("Data_timeout ");
++      if(status & TMIO_STAT_CMDTIMEOUT)  printk("Command_timeout ");
++      if(status & TMIO_STAT_RXOVERFLOW)  printk("RX_OVF ");
++      if(status & TMIO_STAT_TXUNDERRUN)  printk("TX_UND ");
++      if(status & TMIO_STAT_RXRDY)       printk("RX_rdy ");
++      if(status & TMIO_STAT_TXRQ)        printk("TX_req ");
++      if(status & TMIO_STAT_ILL_ACCESS)  printk("ILLEGAL_ACCESS ");
++      printk("\n");
++}
++#else
++#define DBG(fmt,args...)        do { } while (0)
++#endif
+-- 
+1.5.3.8
+
diff --git a/packages/kexecboot/linux-kexecboot-2.6.24/tosa/0012-Tosa-keyboard-support.patch b/packages/kexecboot/linux-kexecboot-2.6.24/tosa/0012-Tosa-keyboard-support.patch
new file mode 100644 (file)
index 0000000..0fa10eb
--- /dev/null
@@ -0,0 +1,593 @@
+From 6d377e8f80ce421e6842ac5f42081345fbc70002 Mon Sep 17 00:00:00 2001
+From: Dmitry Baryshkov <dbaryshkov@gmail.com>
+Date: Wed, 9 Jan 2008 01:27:41 +0300
+Subject: [PATCH 12/64] Tosa keyboard support
+
+Support keyboard on tosa (Sharp Zaurus SL-6000x).
+Largely based on patches by Dirk Opfer.
+
+Signed-off-by: Dmitry Baryshkov <dbaryshkov@gmail.com>
+---
+ arch/arm/mach-pxa/tosa.c         |   43 ++++
+ drivers/input/keyboard/Kconfig   |   21 ++
+ drivers/input/keyboard/Makefile  |    1 +
+ drivers/input/keyboard/tosakbd.c |  415 ++++++++++++++++++++++++++++++++++++++
+ include/asm-arm/arch-pxa/tosa.h  |   30 +++
+ 5 files changed, 510 insertions(+), 0 deletions(-)
+ create mode 100644 drivers/input/keyboard/tosakbd.c
+
+diff --git a/arch/arm/mach-pxa/tosa.c b/arch/arm/mach-pxa/tosa.c
+index 240fd04..e7e0f52 100644
+--- a/arch/arm/mach-pxa/tosa.c
++++ b/arch/arm/mach-pxa/tosa.c
+@@ -21,6 +21,8 @@
+ #include <linux/mmc/host.h>
+ #include <linux/pm.h>
+ #include <linux/delay.h>
++#include <linux/gpio_keys.h>
++#include <linux/input.h>
+ #include <asm/setup.h>
+ #include <asm/memory.h>
+@@ -253,6 +255,46 @@ static struct platform_device tosakbd_device = {
+       .id             = -1,
+ };
++static struct gpio_keys_button tosa_gpio_keys[] = {
++      {
++              .type   = EV_PWR,
++              .code   = KEY_SUSPEND,
++              .gpio   = TOSA_GPIO_ON_KEY,
++              .desc   = "On key",
++              .wakeup = 1,
++              .active_low = 1,
++      },
++      {
++              .type   = EV_KEY,
++              .code   = TOSA_KEY_RECORD,
++              .gpio   = TOSA_GPIO_RECORD_BTN,
++              .desc   = "Record Button",
++              .wakeup = 1,
++              .active_low = 1,
++      },
++      {
++              .type   = EV_KEY,
++              .code   = TOSA_KEY_SYNC,
++              .gpio   = TOSA_GPIO_SYNC,
++              .desc   = "Sync Button",
++              .wakeup = 1,
++              .active_low = 1,
++      },
++};
++
++static struct gpio_keys_platform_data tosa_gpio_keys_platform_data = {
++      .buttons        = tosa_gpio_keys,
++      .nbuttons       = ARRAY_SIZE(tosa_gpio_keys),
++};
++
++static struct platform_device tosa_gpio_keys_device = {
++      .name   = "gpio-keys",
++      .id     = -1,
++      .dev    = {
++              .platform_data  = &tosa_gpio_keys_platform_data,
++      },
++};
++
+ /*
+  * Tosa LEDs
+  */
+@@ -265,6 +307,7 @@ static struct platform_device *devices[] __initdata = {
+       &tosascoop_device,
+       &tosascoop_jc_device,
+       &tosakbd_device,
++      &tosa_gpio_keys_device,
+       &tosaled_device,
+ };
+diff --git a/drivers/input/keyboard/Kconfig b/drivers/input/keyboard/Kconfig
+index 086d58c..0c32762 100644
+--- a/drivers/input/keyboard/Kconfig
++++ b/drivers/input/keyboard/Kconfig
+@@ -154,6 +154,27 @@ config KEYBOARD_SPITZ
+         To compile this driver as a module, choose M here: the
+         module will be called spitzkbd.
++config KEYBOARD_TOSA
++      tristate "Tosa keyboard"
++      depends on MACH_TOSA
++      default y
++      help
++        Say Y here to enable the keyboard on the Sharp Zaurus SL-6000x (Tosa)
++
++        To compile this driver as a module, choose M here: the
++        module will be called tosakbd.
++
++config KEYBOARD_TOSA_USE_EXT_KEYCODES
++      bool "Tosa keyboard: use extended keycodes"
++      depends on KEYBOARD_TOSA
++      default n
++      help
++        Say Y here to enable the tosa keyboard driver to generate extended
++        (>= 127) keycodes. Be aware, that they can't be correctly interpreted
++        by either console keyboard driver or by Kdrive keybd driver.
++
++        Say Y only if you know, what you are doing!
++
+ config KEYBOARD_AMIGA
+       tristate "Amiga keyboard"
+       depends on AMIGA
+diff --git a/drivers/input/keyboard/Makefile b/drivers/input/keyboard/Makefile
+index e97455f..6caa065 100644
+--- a/drivers/input/keyboard/Makefile
++++ b/drivers/input/keyboard/Makefile
+@@ -15,6 +15,7 @@ obj-$(CONFIG_KEYBOARD_NEWTON)                += newtonkbd.o
+ obj-$(CONFIG_KEYBOARD_STOWAWAY)               += stowaway.o
+ obj-$(CONFIG_KEYBOARD_CORGI)          += corgikbd.o
+ obj-$(CONFIG_KEYBOARD_SPITZ)          += spitzkbd.o
++obj-$(CONFIG_KEYBOARD_TOSA)           += tosakbd.o
+ obj-$(CONFIG_KEYBOARD_HIL)            += hil_kbd.o
+ obj-$(CONFIG_KEYBOARD_HIL_OLD)                += hilkbd.o
+ obj-$(CONFIG_KEYBOARD_OMAP)           += omap-keypad.o
+diff --git a/drivers/input/keyboard/tosakbd.c b/drivers/input/keyboard/tosakbd.c
+new file mode 100644
+index 0000000..3884d1e
+--- /dev/null
++++ b/drivers/input/keyboard/tosakbd.c
+@@ -0,0 +1,415 @@
++/*
++ *  Keyboard driver for Sharp Tosa models (SL-6000x)
++ *
++ *  Copyright (c) 2005 Dirk Opfer
++ *  Copyright (c) 2007 Dmitry Baryshkov
++ *
++ *  Based on xtkbd.c/locomkbd.c/corgikbd.c
++ *
++ *  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/kernel.h>
++#include <linux/module.h>
++#include <linux/platform_device.h>
++#include <linux/input.h>
++#include <linux/delay.h>
++#include <linux/interrupt.h>
++
++#include <asm/arch/gpio.h>
++#include <asm/arch/tosa.h>
++
++#define KB_ROWMASK(r)         (1 << (r))
++#define SCANCODE(r, c)                (((r)<<4) + (c) + 1)
++#define NR_SCANCODES          SCANCODE(TOSA_KEY_SENSE_NUM - 1, TOSA_KEY_STROBE_NUM - 1) + 1
++
++#define SCAN_INTERVAL         (HZ/10)
++
++#define KB_DISCHARGE_DELAY    10
++#define KB_ACTIVATE_DELAY     10
++
++static unsigned int tosakbd_keycode[NR_SCANCODES] = {
++0,
++0, KEY_W, 0, 0, 0, KEY_K, KEY_BACKSPACE, KEY_P,
++0, 0, 0, 0, 0, 0, 0, 0,
++KEY_Q, KEY_E, KEY_T, KEY_Y, 0, KEY_O, KEY_I, KEY_COMMA,
++0, 0, 0, 0, 0, 0, 0, 0,
++KEY_A, KEY_D, KEY_G, KEY_U, 0, KEY_L, KEY_ENTER, KEY_DOT,
++0, 0, 0, 0, 0, 0, 0, 0,
++KEY_Z, KEY_C, KEY_V, KEY_J, TOSA_KEY_ADDRESSBOOK, TOSA_KEY_CANCEL, TOSA_KEY_CENTER, TOSA_KEY_OK,
++KEY_LEFTSHIFT, 0, 0, 0, 0, 0, 0, 0,
++KEY_S, KEY_R, KEY_B, KEY_N, TOSA_KEY_CALENDAR, TOSA_KEY_HOMEPAGE, KEY_LEFTCTRL, TOSA_KEY_LIGHT,
++0, KEY_RIGHTSHIFT, 0, 0, 0, 0, 0, 0,
++KEY_TAB, KEY_SLASH, KEY_H, KEY_M, TOSA_KEY_MENU, 0, KEY_UP, 0,
++0, 0, TOSA_KEY_FN, 0, 0, 0, 0, 0,
++KEY_X, KEY_F, KEY_SPACE, KEY_APOSTROPHE, TOSA_KEY_MAIL, KEY_LEFT, KEY_DOWN, KEY_RIGHT,
++0, 0, 0,
++};
++
++struct tosakbd {
++      unsigned int keycode[ARRAY_SIZE(tosakbd_keycode)];
++      struct input_dev *input;
++
++      spinlock_t lock; /* protect kbd scanning */
++      struct timer_list timer;
++};
++
++
++/* Helper functions for reading the keyboard matrix
++ * Note: We should really be using pxa_gpio_mode to alter GPDR but it
++ *       requires a function call per GPIO bit which is excessive
++ *       when we need to access 12 bits at once, multiple times.
++ * These functions must be called within local_irq_save()/local_irq_restore()
++ * or similar.
++ */
++#define GET_ROWS_STATUS(c)    ((GPLR2 & TOSA_GPIO_ALL_SENSE_BIT) >> TOSA_GPIO_ALL_SENSE_RSHIFT)
++
++static inline void tosakbd_discharge_all(void)
++{
++      /* STROBE All HiZ */
++      GPCR1  = TOSA_GPIO_HIGH_STROBE_BIT;
++      GPDR1 &= ~TOSA_GPIO_HIGH_STROBE_BIT;
++      GPCR2  = TOSA_GPIO_LOW_STROBE_BIT;
++      GPDR2 &= ~TOSA_GPIO_LOW_STROBE_BIT;
++}
++
++static inline void tosakbd_activate_all(void)
++{
++      /* STROBE ALL -> High */
++      GPSR1  = TOSA_GPIO_HIGH_STROBE_BIT;
++      GPDR1 |= TOSA_GPIO_HIGH_STROBE_BIT;
++      GPSR2  = TOSA_GPIO_LOW_STROBE_BIT;
++      GPDR2 |= TOSA_GPIO_LOW_STROBE_BIT;
++
++      udelay(KB_DISCHARGE_DELAY);
++
++      /* STATE CLEAR */
++      GEDR2 |= TOSA_GPIO_ALL_SENSE_BIT;
++}
++
++static inline void tosakbd_activate_col(int col)
++{
++      if (col <= 5) {
++              /* STROBE col -> High, not col -> HiZ */
++              GPSR1 = TOSA_GPIO_STROBE_BIT(col);
++              GPDR1 = (GPDR1 & ~TOSA_GPIO_HIGH_STROBE_BIT) | TOSA_GPIO_STROBE_BIT(col);
++      } else {
++              /* STROBE col -> High, not col -> HiZ */
++              GPSR2 = TOSA_GPIO_STROBE_BIT(col);
++              GPDR2 = (GPDR2 & ~TOSA_GPIO_LOW_STROBE_BIT) | TOSA_GPIO_STROBE_BIT(col);
++      }
++}
++
++static inline void tosakbd_reset_col(int col)
++{
++      if (col <= 5) {
++              /* STROBE col -> Low */
++              GPCR1 = TOSA_GPIO_STROBE_BIT(col);
++              /* STROBE col -> out, not col -> HiZ */
++              GPDR1 = (GPDR1 & ~TOSA_GPIO_HIGH_STROBE_BIT) | TOSA_GPIO_STROBE_BIT(col);
++      } else {
++              /* STROBE col -> Low */
++              GPCR2 = TOSA_GPIO_STROBE_BIT(col);
++              /* STROBE col -> out, not col -> HiZ */
++              GPDR2 = (GPDR2 & ~TOSA_GPIO_LOW_STROBE_BIT) | TOSA_GPIO_STROBE_BIT(col);
++      }
++}
++/*
++ * The tosa keyboard only generates interrupts when a key is pressed.
++ * So when a key is pressed, we enable a timer.  This timer scans the
++ * keyboard, and this is how we detect when the key is released.
++ */
++
++/* Scan the hardware keyboard and push any changes up through the input layer */
++static void tosakbd_scankeyboard(struct platform_device *dev)
++{
++      struct tosakbd *tosakbd = platform_get_drvdata(dev);
++      unsigned int row, col, rowd;
++      unsigned long flags;
++      unsigned int num_pressed = 0;
++
++      spin_lock_irqsave(&tosakbd->lock, flags);
++
++      for (col = 0; col < TOSA_KEY_STROBE_NUM; col++) {
++              /*
++               * Discharge the output driver capacitatance
++               * in the keyboard matrix. (Yes it is significant..)
++               */
++              tosakbd_discharge_all();
++              udelay(KB_DISCHARGE_DELAY);
++
++              tosakbd_activate_col(col);
++              udelay(KB_ACTIVATE_DELAY);
++
++              rowd = GET_ROWS_STATUS(col);
++
++              for (row = 0; row < TOSA_KEY_SENSE_NUM; row++) {
++                      unsigned int scancode, pressed;
++                      scancode = SCANCODE(row, col);
++                      pressed = rowd & KB_ROWMASK(row);
++
++                      if (pressed && !tosakbd->keycode[scancode])
++                              dev_warn(&dev->dev,
++                                              "unhandled scancode: 0x%02x\n",
++                                              scancode);
++
++                      input_report_key(tosakbd->input,
++                                      tosakbd->keycode[scancode],
++                                      pressed);
++                      if (pressed)
++                              num_pressed++;
++              }
++
++              tosakbd_reset_col(col);
++      }
++
++      tosakbd_activate_all();
++
++      input_sync(tosakbd->input);
++
++      /* if any keys are pressed, enable the timer */
++      if (num_pressed)
++              mod_timer(&tosakbd->timer, jiffies + SCAN_INTERVAL);
++
++      spin_unlock_irqrestore(&tosakbd->lock, flags);
++}
++
++/*
++ * tosa keyboard interrupt handler.
++ */
++static irqreturn_t tosakbd_interrupt(int irq, void *__dev)
++{
++      struct platform_device *dev = __dev;
++      struct tosakbd *tosakbd = platform_get_drvdata(dev);
++
++      if (!timer_pending(&tosakbd->timer)) {
++              /** wait chattering delay **/
++              udelay(20);
++              tosakbd_scankeyboard(dev);
++      }
++
++      return IRQ_HANDLED;
++}
++
++/*
++ * tosa timer checking for released keys
++ */
++static void tosakbd_timer_callback(unsigned long __dev)
++{
++      struct platform_device *dev = (struct platform_device *)__dev;
++      tosakbd_scankeyboard(dev);
++}
++
++#ifdef CONFIG_PM
++static int tosakbd_suspend(struct platform_device *dev, pm_message_t state)
++{
++      struct tosakbd *tosakbd = platform_get_drvdata(dev);
++
++      del_timer_sync(&tosakbd->timer);
++
++      return 0;
++}
++
++static int tosakbd_resume(struct platform_device *dev)
++{
++      tosakbd_scankeyboard(dev);
++
++      return 0;
++}
++#else
++#define tosakbd_suspend               NULL
++#define tosakbd_resume                NULL
++#endif
++
++static int __devinit tosakbd_probe(struct platform_device *pdev) {
++
++      int i;
++      struct tosakbd *tosakbd;
++      struct input_dev *input_dev;
++      int error;
++
++      tosakbd = kzalloc(sizeof(struct tosakbd), GFP_KERNEL);
++      if (!tosakbd)
++              return -ENOMEM;
++
++      input_dev = input_allocate_device();
++      if (!input_dev) {
++              kfree(tosakbd);
++              return -ENOMEM;
++      }
++
++      platform_set_drvdata(pdev, tosakbd);
++
++      spin_lock_init(&tosakbd->lock);
++
++      /* Init Keyboard rescan timer */
++      init_timer(&tosakbd->timer);
++      tosakbd->timer.function = tosakbd_timer_callback;
++      tosakbd->timer.data = (unsigned long) pdev;
++
++      tosakbd->input = input_dev;
++
++      input_set_drvdata(input_dev, tosakbd);
++      input_dev->name = "Tosa Keyboard";
++      input_dev->phys = "tosakbd/input0";
++      input_dev->dev.parent = &pdev->dev;
++
++      input_dev->id.bustype = BUS_HOST;
++      input_dev->id.vendor = 0x0001;
++      input_dev->id.product = 0x0001;
++      input_dev->id.version = 0x0100;
++
++      input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_REP);
++      input_dev->keycode = tosakbd->keycode;
++      input_dev->keycodesize = sizeof(unsigned int);
++      input_dev->keycodemax = ARRAY_SIZE(tosakbd_keycode);
++
++      memcpy(tosakbd->keycode, tosakbd_keycode, sizeof(tosakbd_keycode));
++
++      for (i = 0; i < ARRAY_SIZE(tosakbd_keycode); i++)
++              __set_bit(tosakbd->keycode[i], input_dev->keybit);
++      clear_bit(0, input_dev->keybit);
++
++      /* Setup sense interrupts - RisingEdge Detect, sense lines as inputs */
++      for (i = 0; i < TOSA_KEY_SENSE_NUM; i++) {
++              int gpio = TOSA_GPIO_KEY_SENSE(i);
++              int irq;
++              error = gpio_request(gpio, "tosakbd");
++              if (error < 0) {
++                      printk(KERN_ERR "tosakbd: failed to request GPIO %d, "
++                              " error %d\n", gpio, error);
++                      goto fail;
++              }
++
++              error = gpio_direction_input(TOSA_GPIO_KEY_SENSE(i));
++              if (error < 0) {
++                      printk(KERN_ERR "tosakbd: failed to configure input"
++                              " direction for GPIO %d, error %d\n",
++                              gpio, error);
++                      gpio_free(gpio);
++                      goto fail;
++              }
++
++              irq = gpio_to_irq(gpio);
++              if (irq < 0) {
++                      error = irq;
++                      printk(KERN_ERR "gpio-keys: Unable to get irq number"
++                              " for GPIO %d, error %d\n",
++                              gpio, error);
++                      gpio_free(gpio);
++                      goto fail;
++              }
++
++              error = request_irq(irq, tosakbd_interrupt,
++                                      IRQF_DISABLED | IRQF_TRIGGER_RISING,
++                                      "tosakbd", pdev);
++
++              if (error) {
++                      printk("tosakbd: Can't get IRQ: %d: error %d!\n",
++                                      irq, error);
++                      gpio_free(gpio);
++                      goto fail;
++              }
++      }
++
++      /* Set Strobe lines as outputs - set high */
++      for (i = 0; i < TOSA_KEY_STROBE_NUM; i++) {
++              int gpio = TOSA_GPIO_KEY_STROBE(i);
++              error = gpio_request(gpio, "tosakbd");
++              if (error < 0) {
++                      printk(KERN_ERR "tosakbd: failed to request GPIO %d, "
++                              " error %d\n", gpio, error);
++                      goto fail2;
++              }
++
++              error = gpio_direction_output(gpio, 1);
++              if (error < 0) {
++                      printk(KERN_ERR "tosakbd: failed to configure input"
++                              " direction for GPIO %d, error %d\n",
++                              gpio, error);
++                      gpio_free(gpio);
++                      goto fail;
++              }
++
++      }
++
++      error = input_register_device(input_dev);
++      if (error) {
++              printk(KERN_ERR "tosakbd: Unable to register input device, "
++                      "error: %d\n", error);
++              goto fail;
++      }
++
++      printk(KERN_INFO "input: Tosa Keyboard Registered\n");
++
++      return 0;
++
++fail2:
++      while (--i >= 0)
++              gpio_free(TOSA_GPIO_KEY_STROBE(i));
++
++      i = TOSA_KEY_SENSE_NUM;
++fail:
++      while (--i >= 0) {
++              free_irq(gpio_to_irq(TOSA_GPIO_KEY_SENSE(i)), pdev);
++              gpio_free(TOSA_GPIO_KEY_SENSE(i));
++      }
++
++      platform_set_drvdata(pdev, NULL);
++      input_free_device(input_dev);
++      kfree(tosakbd);
++
++      return error;
++}
++
++static int __devexit tosakbd_remove(struct platform_device *dev) {
++
++      int i;
++      struct tosakbd *tosakbd = platform_get_drvdata(dev);
++
++      for (i = 0; i < TOSA_KEY_STROBE_NUM; i++)
++              gpio_free(TOSA_GPIO_KEY_STROBE(i));
++
++      for (i = 0; i < TOSA_KEY_SENSE_NUM; i++) {
++              free_irq(gpio_to_irq(TOSA_GPIO_KEY_SENSE(i)), dev);
++              gpio_free(TOSA_GPIO_KEY_SENSE(i));
++      }
++
++      del_timer_sync(&tosakbd->timer);
++
++      input_unregister_device(tosakbd->input);
++
++      kfree(tosakbd);
++
++      return 0;
++}
++
++static struct platform_driver tosakbd_driver = {
++      .probe          = tosakbd_probe,
++      .remove         = __devexit_p(tosakbd_remove),
++      .suspend        = tosakbd_suspend,
++      .resume         = tosakbd_resume,
++      .driver         = {
++              .name   = "tosa-keyboard",
++      },
++};
++
++static int __devinit tosakbd_init(void)
++{
++      return platform_driver_register(&tosakbd_driver);
++}
++
++static void __exit tosakbd_exit(void)
++{
++      platform_driver_unregister(&tosakbd_driver);
++}
++
++module_init(tosakbd_init);
++module_exit(tosakbd_exit);
++
++MODULE_AUTHOR("Dirk Opfer <Dirk@Opfer-Online.de>");
++MODULE_DESCRIPTION("Tosa Keyboard Driver");
++MODULE_LICENSE("GPL v2");
+diff --git a/include/asm-arm/arch-pxa/tosa.h b/include/asm-arm/arch-pxa/tosa.h
+index c3364a2..c05e4fa 100644
+--- a/include/asm-arm/arch-pxa/tosa.h
++++ b/include/asm-arm/arch-pxa/tosa.h
+@@ -163,4 +163,34 @@
+ extern struct platform_device tosascoop_jc_device;
+ extern struct platform_device tosascoop_device;
++
++#define TOSA_KEY_SYNC         KEY_102ND /* ??? */
++
++
++#ifndef CONFIG_KEYBOARD_TOSA_USE_EXT_KEYCODES
++#define TOSA_KEY_RECORD               KEY_YEN
++#define TOSA_KEY_ADDRESSBOOK  KEY_KATAKANA
++#define TOSA_KEY_CANCEL               KEY_ESC
++#define TOSA_KEY_CENTER               KEY_HIRAGANA
++#define TOSA_KEY_OK           KEY_HENKAN
++#define TOSA_KEY_CALENDAR     KEY_KATAKANAHIRAGANA
++#define TOSA_KEY_HOMEPAGE     KEY_HANGEUL
++#define TOSA_KEY_LIGHT                KEY_MUHENKAN
++#define TOSA_KEY_MENU         KEY_HANJA
++#define TOSA_KEY_FN           KEY_RIGHTALT
++#define TOSA_KEY_MAIL         KEY_ZENKAKUHANKAKU
++#else
++#define TOSA_KEY_RECORD               KEY_RECORD
++#define TOSA_KEY_ADDRESSBOOK  KEY_ADDRESSBOOK
++#define TOSA_KEY_CANCEL               KEY_CANCEL
++#define TOSA_KEY_CENTER               KEY_SELECT /* ??? */
++#define TOSA_KEY_OK           KEY_OK
++#define TOSA_KEY_CALENDAR     KEY_CALENDAR
++#define TOSA_KEY_HOMEPAGE     KEY_HOMEPAGE
++#define TOSA_KEY_LIGHT                KEY_KBDILLUMTOGGLE
++#define TOSA_KEY_MENU         KEY_MENU
++#define TOSA_KEY_FN           KEY_FN
++#define TOSA_KEY_MAIL         KEY_MAIL
++#endif
++
+ #endif /* _ASM_ARCH_TOSA_H_ */
+-- 
+1.5.3.8
+
diff --git a/packages/kexecboot/linux-kexecboot-2.6.24/tosa/0013-USB-gadget-pxa2xx_udc-supports-inverted-vbus.patch b/packages/kexecboot/linux-kexecboot-2.6.24/tosa/0013-USB-gadget-pxa2xx_udc-supports-inverted-vbus.patch
new file mode 100644 (file)
index 0000000..082a2c7
--- /dev/null
@@ -0,0 +1,61 @@
+From 18c1a92a09faf75ebdac7ac471c741a6622cf3e2 Mon Sep 17 00:00:00 2001
+From: Dmitry Baryshkov <dbaryshkov@gmail.com>
+Date: Wed, 9 Jan 2008 01:27:49 +0300
+Subject: [PATCH 13/64] USB: gadget: pxa2xx_udc supports inverted vbus
+
+Some boards (like e.g. Tosa) invert the VBUS-detection signal:
+it's low when a host is supplying VBUS, and high otherwise.
+Allow specifying whether gpio_vbus value is inverted.
+
+Signed-off-by: Dmitry Baryshkov <dbaryshkov@gmail.com>
+Signed-off-by: David Brownell <dbrownell@users.sourceforge.net>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+---
+ drivers/usb/gadget/pxa2xx_udc.c   |    9 +++++++--
+ include/asm-arm/mach/udc_pxa2xx.h |    2 ++
+ 2 files changed, 9 insertions(+), 2 deletions(-)
+
+diff --git a/drivers/usb/gadget/pxa2xx_udc.c b/drivers/usb/gadget/pxa2xx_udc.c
+index 3173b39..4f7d4ef 100644
+--- a/drivers/usb/gadget/pxa2xx_udc.c
++++ b/drivers/usb/gadget/pxa2xx_udc.c
+@@ -127,8 +127,10 @@ static int is_vbus_present(void)
+ {
+       struct pxa2xx_udc_mach_info             *mach = the_controller->mach;
+-      if (mach->gpio_vbus)
+-              return gpio_get_value(mach->gpio_vbus);
++      if (mach->gpio_vbus) {
++              int value = gpio_get_value(mach->gpio_vbus);
++              return mach->gpio_vbus_inverted ? !value : value;
++      }
+       if (mach->udc_is_connected)
+               return mach->udc_is_connected();
+       return 1;
+@@ -1397,6 +1399,9 @@ static irqreturn_t udc_vbus_irq(int irq, void *_dev)
+       struct pxa2xx_udc       *dev = _dev;
+       int                     vbus = gpio_get_value(dev->mach->gpio_vbus);
++      if (dev->mach->gpio_vbus_inverted)
++              vbus = !vbus;
++
+       pxa2xx_udc_vbus_session(&dev->gadget, vbus);
+       return IRQ_HANDLED;
+ }
+diff --git a/include/asm-arm/mach/udc_pxa2xx.h b/include/asm-arm/mach/udc_pxa2xx.h
+index ff0a957..f191e14 100644
+--- a/include/asm-arm/mach/udc_pxa2xx.h
++++ b/include/asm-arm/mach/udc_pxa2xx.h
+@@ -19,7 +19,9 @@ struct pxa2xx_udc_mach_info {
+        * with on-chip GPIOs not Lubbock's wierd hardware, can have a sane
+        * VBUS IRQ and omit the methods above.  Store the GPIO number
+        * here; for GPIO 0, also mask in one of the pxa_gpio_mode() bits.
++       * Note that sometimes the signals go through inverters...
+        */
++      bool    gpio_vbus_inverted;
+       u16     gpio_vbus;                      /* high == vbus present */
+       u16     gpio_pullup;                    /* high == pullup activated */
+ };
+-- 
+1.5.3.8
+
diff --git a/packages/kexecboot/linux-kexecboot-2.6.24/tosa/0014-tosa_udc_use_gpio_vbus.patch.patch b/packages/kexecboot/linux-kexecboot-2.6.24/tosa/0014-tosa_udc_use_gpio_vbus.patch.patch
new file mode 100644 (file)
index 0000000..98783ef
--- /dev/null
@@ -0,0 +1,38 @@
+From 932ff38b17c7847c43e2bad01b510b64c27f9810 Mon Sep 17 00:00:00 2001
+From: Dmitry Baryshkov <dbaryshkov@gmail.com>
+Date: Wed, 9 Jan 2008 01:27:59 +0300
+Subject: [PATCH 14/64] tosa_udc_use_gpio_vbus.patch
+
+Use gpio_vbus instead of udc_is_connected for udc on tosa.
+
+Signed-off-by: Dmitry Baryshkov <dbaryshkov@gmail.com>
+Acked-by: Russell King <rmk+kernel@arm.linux.org.uk>
+---
+ arch/arm/mach-pxa/tosa.c |    9 ++-------
+ 1 files changed, 2 insertions(+), 7 deletions(-)
+
+diff --git a/arch/arm/mach-pxa/tosa.c b/arch/arm/mach-pxa/tosa.c
+index e7e0f52..5268e94 100644
+--- a/arch/arm/mach-pxa/tosa.c
++++ b/arch/arm/mach-pxa/tosa.c
+@@ -159,15 +159,10 @@ static void tosa_udc_command(int cmd)
+       }
+ }
+-static int tosa_udc_is_connected(void)
+-{
+-      return ((GPLR(TOSA_GPIO_USB_IN) & GPIO_bit(TOSA_GPIO_USB_IN)) == 0);
+-}
+-
+-
+ static struct pxa2xx_udc_mach_info udc_info __initdata = {
+       .udc_command            = tosa_udc_command,
+-      .udc_is_connected       = tosa_udc_is_connected,
++      .gpio_vbus              = TOSA_GPIO_USB_IN,
++      .gpio_vbus_inverted     = 1,
+ };
+ /*
+-- 
+1.5.3.8
+
diff --git a/packages/kexecboot/linux-kexecboot-2.6.24/tosa/0015-sharpsl-export-params.patch b/packages/kexecboot/linux-kexecboot-2.6.24/tosa/0015-sharpsl-export-params.patch
new file mode 100644 (file)
index 0000000..f8e57e8
--- /dev/null
@@ -0,0 +1,32 @@
+From bba216220d17d1091413e82c9924ac5614402c05 Mon Sep 17 00:00:00 2001
+From: Ian Molton <spyro@f2s.com>
+Date: Wed, 9 Jan 2008 01:28:06 +0300
+Subject: [PATCH 15/64] sharpsl export params
+
+---
+ arch/arm/common/sharpsl_param.c |    2 ++
+ 1 files changed, 2 insertions(+), 0 deletions(-)
+
+diff --git a/arch/arm/common/sharpsl_param.c b/arch/arm/common/sharpsl_param.c
+index aad4d94..d56c932 100644
+--- a/arch/arm/common/sharpsl_param.c
++++ b/arch/arm/common/sharpsl_param.c
+@@ -12,6 +12,7 @@
+  */
+ #include <linux/kernel.h>
++#include <linux/module.h>
+ #include <linux/string.h>
+ #include <asm/mach/sharpsl_param.h>
+@@ -36,6 +37,7 @@
+ #define PHAD_MAGIC    MAGIC_CHG('P','H','A','D')
+ struct sharpsl_param_info sharpsl_param;
++EXPORT_SYMBOL(sharpsl_param);
+ void sharpsl_save_param(void)
+ {
+-- 
+1.5.3.8
+
diff --git a/packages/kexecboot/linux-kexecboot-2.6.24/tosa/0016-This-patch-fixes-the-pxa25x-clocks-definitions-to-ad.patch b/packages/kexecboot/linux-kexecboot-2.6.24/tosa/0016-This-patch-fixes-the-pxa25x-clocks-definitions-to-ad.patch
new file mode 100644 (file)
index 0000000..d73de06
--- /dev/null
@@ -0,0 +1,44 @@
+From 0fe7b491b70efafbd41185f8e95a3eada65984a1 Mon Sep 17 00:00:00 2001
+From: Dmitry Baryshkov <dbaryshkov@gmail.com>
+Date: Mon, 28 Jan 2008 01:49:28 +0300
+Subject: [PATCH 16/64] This patch fixes the pxa25x clocks definitions to add hwuart.
+
+Signed-off-by: Dmitry Baryshkov <dbaryshkov@gmail.com>
+---
+ arch/arm/mach-pxa/pxa25x.c |    9 ++++++++-
+ 1 files changed, 8 insertions(+), 1 deletions(-)
+
+diff --git a/arch/arm/mach-pxa/pxa25x.c b/arch/arm/mach-pxa/pxa25x.c
+index 9732d5d..006a6e0 100644
+--- a/arch/arm/mach-pxa/pxa25x.c
++++ b/arch/arm/mach-pxa/pxa25x.c
+@@ -111,11 +111,14 @@ static const struct clkops clk_pxa25x_lcd_ops = {
+  * 95.842MHz -> MMC 19.169MHz, I2C 31.949MHz, FICP 47.923MHz, USB 47.923MHz
+  * 147.456MHz -> UART 14.7456MHz, AC97 12.288MHz, I2S 5.672MHz (allegedly)
+  */
++static struct clk pxa25x_hwuart_clk =
++      INIT_CKEN("UARTCLK", HWUART, 14745600, 1, &pxa_device_hwuart.dev)
++;
++
+ static struct clk pxa25x_clks[] = {
+       INIT_CK("LCDCLK", LCD, &clk_pxa25x_lcd_ops, &pxa_device_fb.dev),
+       INIT_CKEN("UARTCLK", FFUART, 14745600, 1, &pxa_device_ffuart.dev),
+       INIT_CKEN("UARTCLK", BTUART, 14745600, 1, &pxa_device_btuart.dev),
+-      INIT_CKEN("UARTCLK", BTUART, 14745600, 1, &pxa_device_btuart.dev),
+       INIT_CKEN("UARTCLK", STUART, 14745600, 1, NULL),
+       INIT_CKEN("UDCCLK", USB, 47923000, 5, &pxa_device_udc.dev),
+       INIT_CKEN("MMCCLK", MMC, 19169000, 0, &pxa_device_mci.dev),
+@@ -303,6 +306,10 @@ static int __init pxa25x_init(void)
+ {
+       int ret = 0;
++      /* Only add HWUART for PXA255/26x; PXA210/250/27x do not have it. */
++      if (cpu_is_pxa25x())
++              clks_register(&pxa25x_hwuart_clk, 1);
++
+       if (cpu_is_pxa21x() || cpu_is_pxa25x()) {
+               clks_register(pxa25x_clks, ARRAY_SIZE(pxa25x_clks));
+-- 
+1.5.3.8
+
diff --git a/packages/kexecboot/linux-kexecboot-2.6.24/tosa/0017-Convert-pxa2xx-UDC-to-use-debugfs.patch b/packages/kexecboot/linux-kexecboot-2.6.24/tosa/0017-Convert-pxa2xx-UDC-to-use-debugfs.patch
new file mode 100644 (file)
index 0000000..5163361
--- /dev/null
@@ -0,0 +1,280 @@
+From 71857e8f6c4a8d2d3eac3037f02e0c30c6fdb37e Mon Sep 17 00:00:00 2001
+From: Dmitry Baryshkov <dbaryshkov@gmail.com>
+Date: Wed, 9 Jan 2008 01:43:28 +0300
+Subject: [PATCH 17/64] Convert pxa2xx UDC to use debugfs
+
+Use debugfs instead of /proc/driver/udc
+
+Signed-off-by: Dmitry Baryshkov <dbaryshkov@gmail.com>
+---
+ drivers/usb/gadget/pxa2xx_udc.c |  100 +++++++++++++++++----------------------
+ drivers/usb/gadget/pxa2xx_udc.h |   10 +++-
+ 2 files changed, 51 insertions(+), 59 deletions(-)
+
+diff --git a/drivers/usb/gadget/pxa2xx_udc.c b/drivers/usb/gadget/pxa2xx_udc.c
+index 4f7d4ef..2900556 100644
+--- a/drivers/usb/gadget/pxa2xx_udc.c
++++ b/drivers/usb/gadget/pxa2xx_udc.c
+@@ -38,13 +38,14 @@
+ #include <linux/timer.h>
+ #include <linux/list.h>
+ #include <linux/interrupt.h>
+-#include <linux/proc_fs.h>
+ #include <linux/mm.h>
+ #include <linux/platform_device.h>
+ #include <linux/dma-mapping.h>
+ #include <linux/irq.h>
+ #include <linux/clk.h>
+ #include <linux/err.h>
++#include <linux/seq_file.h>
++#include <linux/debugfs.h>
+ #include <asm/byteorder.h>
+ #include <asm/dma.h>
+@@ -993,45 +994,36 @@ static const struct usb_gadget_ops pxa2xx_udc_ops = {
+ /*-------------------------------------------------------------------------*/
+-#ifdef CONFIG_USB_GADGET_DEBUG_FILES
+-
+-static const char proc_node_name [] = "driver/udc";
++#ifdef CONFIG_USB_GADGET_DEBUG_FS
++static struct pxa2xx_udc memory;
+ static int
+-udc_proc_read(char *page, char **start, off_t off, int count,
+-              int *eof, void *_dev)
++udc_seq_show(struct seq_file *m, void *d)
+ {
+-      char                    *buf = page;
+-      struct pxa2xx_udc       *dev = _dev;
+-      char                    *next = buf;
+-      unsigned                size = count;
++      struct pxa2xx_udc       *dev = m->private;
+       unsigned long           flags;
+-      int                     i, t;
++      int                     i;
+       u32                     tmp;
+-      if (off != 0)
+-              return 0;
++
++      BUG_ON(dev == NULL);
+       local_irq_save(flags);
+       /* basic device status */
+-      t = scnprintf(next, size, DRIVER_DESC "\n"
++      seq_printf(m, DRIVER_DESC "\n"
+               "%s version: %s\nGadget driver: %s\nHost %s\n\n",
+               driver_name, DRIVER_VERSION SIZE_STR "(pio)",
+               dev->driver ? dev->driver->driver.name : "(none)",
+               is_vbus_present() ? "full speed" : "disconnected");
+-      size -= t;
+-      next += t;
+       /* registers for device and ep0 */
+-      t = scnprintf(next, size,
++      seq_printf(m,
+               "uicr %02X.%02X, usir %02X.%02x, ufnr %02X.%02X\n",
+               UICR1, UICR0, USIR1, USIR0, UFNRH, UFNRL);
+-      size -= t;
+-      next += t;
+       tmp = UDCCR;
+-      t = scnprintf(next, size,
++      seq_printf(m,
+               "udccr %02X =%s%s%s%s%s%s%s%s\n", tmp,
+               (tmp & UDCCR_REM) ? " rem" : "",
+               (tmp & UDCCR_RSTIR) ? " rstir" : "",
+@@ -1041,11 +1033,9 @@ udc_proc_read(char *page, char **start, off_t off, int count,
+               (tmp & UDCCR_RSM) ? " rsm" : "",
+               (tmp & UDCCR_UDA) ? " uda" : "",
+               (tmp & UDCCR_UDE) ? " ude" : "");
+-      size -= t;
+-      next += t;
+       tmp = UDCCS0;
+-      t = scnprintf(next, size,
++      seq_printf(m,
+               "udccs0 %02X =%s%s%s%s%s%s%s%s\n", tmp,
+               (tmp & UDCCS0_SA) ? " sa" : "",
+               (tmp & UDCCS0_RNE) ? " rne" : "",
+@@ -1055,28 +1045,22 @@ udc_proc_read(char *page, char **start, off_t off, int count,
+               (tmp & UDCCS0_FTF) ? " ftf" : "",
+               (tmp & UDCCS0_IPR) ? " ipr" : "",
+               (tmp & UDCCS0_OPR) ? " opr" : "");
+-      size -= t;
+-      next += t;
+       if (dev->has_cfr) {
+               tmp = UDCCFR;
+-              t = scnprintf(next, size,
++              seq_printf(m,
+                       "udccfr %02X =%s%s\n", tmp,
+                       (tmp & UDCCFR_AREN) ? " aren" : "",
+                       (tmp & UDCCFR_ACM) ? " acm" : "");
+-              size -= t;
+-              next += t;
+       }
+       if (!is_vbus_present() || !dev->driver)
+               goto done;
+-      t = scnprintf(next, size, "ep0 IN %lu/%lu, OUT %lu/%lu\nirqs %lu\n\n",
++      seq_printf(m, "ep0 IN %lu/%lu, OUT %lu/%lu\nirqs %lu\n\n",
+               dev->stats.write.bytes, dev->stats.write.ops,
+               dev->stats.read.bytes, dev->stats.read.ops,
+               dev->stats.irqs);
+-      size -= t;
+-      next += t;
+       /* dump endpoint queues */
+       for (i = 0; i < PXA_UDC_NUM_ENDPOINTS; i++) {
+@@ -1090,55 +1074,57 @@ udc_proc_read(char *page, char **start, off_t off, int count,
+                       if (!d)
+                               continue;
+                       tmp = *dev->ep [i].reg_udccs;
+-                      t = scnprintf(next, size,
++                      seq_printf(m,
+                               "%s max %d %s udccs %02x irqs %lu\n",
+                               ep->ep.name, le16_to_cpu (d->wMaxPacketSize),
+                               "pio", tmp, ep->pio_irqs);
+                       /* TODO translate all five groups of udccs bits! */
+               } else /* ep0 should only have one transfer queued */
+-                      t = scnprintf(next, size, "ep0 max 16 pio irqs %lu\n",
++                      seq_printf(m, "ep0 max 16 pio irqs %lu\n",
+                               ep->pio_irqs);
+-              if (t <= 0 || t > size)
+-                      goto done;
+-              size -= t;
+-              next += t;
+               if (list_empty(&ep->queue)) {
+-                      t = scnprintf(next, size, "\t(nothing queued)\n");
+-                      if (t <= 0 || t > size)
+-                              goto done;
+-                      size -= t;
+-                      next += t;
++                      seq_printf(m, "\t(nothing queued)\n");
+                       continue;
+               }
+               list_for_each_entry(req, &ep->queue, queue) {
+-                      t = scnprintf(next, size,
++                      seq_printf(m,
+                                       "\treq %p len %d/%d buf %p\n",
+                                       &req->req, req->req.actual,
+                                       req->req.length, req->req.buf);
+-                      if (t <= 0 || t > size)
+-                              goto done;
+-                      size -= t;
+-                      next += t;
+               }
+       }
+ done:
+       local_irq_restore(flags);
+-      *eof = 1;
+-      return count - size;
++      return 0;
+ }
+-#define create_proc_files() \
+-      create_proc_read_entry(proc_node_name, 0, NULL, udc_proc_read, dev)
+-#define remove_proc_files() \
+-      remove_proc_entry(proc_node_name, NULL)
++static int
++udc_debugfs_open(struct inode *inode, struct file *file)
++{
++      return single_open(file, udc_seq_show, inode->i_private);
++}
++
++static const struct file_operations debug_fops = {
++      .open           = udc_debugfs_open,
++      .read           = seq_read,
++      .llseek         = seq_lseek,
++      .release        = single_release,
++      .owner          = THIS_MODULE,
++};
++
++#define create_debug_files(dev) \
++      dev->debugfs_udc = debugfs_create_file(dev->gadget.name, S_IRUGO, \
++                      NULL, dev, &debug_fops)
++#define remove_debug_files(dev) \
++      if (dev->debugfs_udc) debugfs_remove(dev->debugfs_udc)
+ #else /* !CONFIG_USB_GADGET_DEBUG_FILES */
+-#define create_proc_files() do {} while (0)
+-#define remove_proc_files() do {} while (0)
++#define create_debug_files(dev) do {} while (0)
++#define remove_debug_files(dev) do {} while (0)
+ #endif        /* CONFIG_USB_GADGET_DEBUG_FILES */
+@@ -2245,7 +2231,7 @@ lubbock_fail0:
+                       goto err_vbus_irq;
+               }
+       }
+-      create_proc_files();
++      create_debug_files(dev);
+       return 0;
+@@ -2282,7 +2268,7 @@ static int __exit pxa2xx_udc_remove(struct platform_device *pdev)
+               return -EBUSY;
+       udc_disable(dev);
+-      remove_proc_files();
++      remove_debug_files(dev);
+       if (dev->got_irq) {
+               free_irq(platform_get_irq(pdev, 0), dev);
+diff --git a/drivers/usb/gadget/pxa2xx_udc.h b/drivers/usb/gadget/pxa2xx_udc.h
+index 1db46d7..c08b1a2 100644
+--- a/drivers/usb/gadget/pxa2xx_udc.h
++++ b/drivers/usb/gadget/pxa2xx_udc.h
+@@ -129,6 +129,10 @@ struct pxa2xx_udc {
+       struct pxa2xx_udc_mach_info             *mach;
+       u64                                     dma_mask;
+       struct pxa2xx_ep                        ep [PXA_UDC_NUM_ENDPOINTS];
++
++#ifdef CONFIG_USB_GADGET_DEBUG_FS
++      struct dentry                           *debugfs_udc;
++#endif
+ };
+ /*-------------------------------------------------------------------------*/
+@@ -153,6 +157,8 @@ static struct pxa2xx_udc *the_controller;
+ #ifdef DEBUG
++static int is_vbus_present(void);
++
+ static const char *state_name[] = {
+       "EP0_IDLE",
+       "EP0_IN_DATA_PHASE", "EP0_OUT_DATA_PHASE",
+@@ -207,8 +213,7 @@ dump_state(struct pxa2xx_udc *dev)
+       unsigned        i;
+       DMSG("%s %s, uicr %02X.%02X, usir %02X.%02x, ufnr %02X.%02X\n",
+-              //is_usb_connected() ? "host " : "disconnected",
+-              "host ",
++              is_vbus_present() ? "host " : "disconnected",
+               state_name[dev->ep0state],
+               UICR1, UICR0, USIR1, USIR0, UFNRH, UFNRL);
+       dump_udccr("udccr");
+@@ -224,7 +230,7 @@ dump_state(struct pxa2xx_udc *dev)
+       } else
+               DMSG("ep0 driver '%s'\n", dev->driver->driver.name);
+-      //if (!is_usb_connected())
+-      //      return;
++      if (!is_vbus_present())
++              return;
+       dump_udccs0 ("udccs0");
+-- 
+1.5.3.8
+
diff --git a/packages/kexecboot/linux-kexecboot-2.6.24/tosa/0018-Fix-the-pxa2xx_udc-to-balance-calls-to-clk_enable-cl.patch b/packages/kexecboot/linux-kexecboot-2.6.24/tosa/0018-Fix-the-pxa2xx_udc-to-balance-calls-to-clk_enable-cl.patch
new file mode 100644 (file)
index 0000000..7bf4ad0
--- /dev/null
@@ -0,0 +1,225 @@
+From b9a0fdbf333b461682d5da8b9aaa42f4de91ffcf Mon Sep 17 00:00:00 2001
+From: Dmitry Baryshkov <dbaryshkov@gmail.com>
+Date: Sun, 10 Feb 2008 03:29:17 +0300
+Subject: [PATCH 18/64] Fix the pxa2xx_udc to balance calls to clk_enable/clk_disable
+
+Signed-off-by: Dmitry Baryshkov dbaryshkov@gmail.com
+---
+ drivers/usb/gadget/pxa2xx_udc.c |   84 +++++++++++++++++++++++----------------
+ drivers/usb/gadget/pxa2xx_udc.h |    6 ++-
+ 2 files changed, 54 insertions(+), 36 deletions(-)
+
+diff --git a/drivers/usb/gadget/pxa2xx_udc.c b/drivers/usb/gadget/pxa2xx_udc.c
+index 2900556..8e32d07 100644
+--- a/drivers/usb/gadget/pxa2xx_udc.c
++++ b/drivers/usb/gadget/pxa2xx_udc.c
+@@ -680,7 +680,7 @@ pxa2xx_ep_queue(struct usb_ep *_ep, struct usb_request *_req, gfp_t gfp_flags)
+       /* kickstart this i/o queue? */
+       if (list_empty(&ep->queue) && !ep->stopped) {
+-              if (ep->desc == 0 /* ep0 */) {
++              if (ep->desc == NULL /* ep0 */) {
+                       unsigned        length = _req->length;
+                       switch (dev->ep0state) {
+@@ -734,7 +734,7 @@ pxa2xx_ep_queue(struct usb_ep *_ep, struct usb_request *_req, gfp_t gfp_flags)
+       }
+       /* pio or dma irq handler advances the queue. */
+-      if (likely (req != 0))
++      if (likely (req != NULL))
+               list_add_tail(&req->queue, &ep->queue);
+       local_irq_restore(flags);
+@@ -934,20 +934,35 @@ static void udc_disable(struct pxa2xx_udc *);
+ /* We disable the UDC -- and its 48 MHz clock -- whenever it's not
+  * in active use.
+  */
+-static int pullup(struct pxa2xx_udc *udc, int is_active)
++static int pullup(struct pxa2xx_udc *udc)
+ {
+-      is_active = is_active && udc->vbus && udc->pullup;
++      int is_active = udc->vbus && udc->pullup && ! udc->suspended;
+       DMSG("%s\n", is_active ? "active" : "inactive");
+-      if (is_active)
+-              udc_enable(udc);
+-      else {
+-              if (udc->gadget.speed != USB_SPEED_UNKNOWN) {
+-                      DMSG("disconnect %s\n", udc->driver
+-                              ? udc->driver->driver.name
+-                              : "(no driver)");
+-                      stop_activity(udc, udc->driver);
++      if (is_active) {
++              if (!udc->active) {
++                      udc->active = 1;
++#ifdef        CONFIG_ARCH_PXA
++                      /* Enable clock for USB device */
++                      clk_enable(udc->clk);
++#endif
++                      udc_enable(udc);
+               }
+-              udc_disable(udc);
++      } else {
++              if (udc->active) {
++                      if (udc->gadget.speed != USB_SPEED_UNKNOWN) {
++                              DMSG("disconnect %s\n", udc->driver
++                                      ? udc->driver->driver.name
++                                      : "(no driver)");
++                              stop_activity(udc, udc->driver);
++                      }
++                      udc_disable(udc);
++#ifdef        CONFIG_ARCH_PXA
++                      /* Disable clock for USB device */
++                      clk_disable(udc->clk);
++#endif
++                      udc->active = 0;
++              }
++
+       }
+       return 0;
+ }
+@@ -958,9 +973,9 @@ static int pxa2xx_udc_vbus_session(struct usb_gadget *_gadget, int is_active)
+       struct pxa2xx_udc       *udc;
+       udc = container_of(_gadget, struct pxa2xx_udc, gadget);
+-      udc->vbus = is_active = (is_active != 0);
++      udc->vbus = (is_active != 0);
+       DMSG("vbus %s\n", is_active ? "supplied" : "inactive");
+-      pullup(udc, is_active);
++      pullup(udc);
+       return 0;
+ }
+@@ -975,9 +990,8 @@ static int pxa2xx_udc_pullup(struct usb_gadget *_gadget, int is_active)
+       if (!udc->mach->gpio_pullup && !udc->mach->udc_command)
+               return -EOPNOTSUPP;
+-      is_active = (is_active != 0);
+-      udc->pullup = is_active;
+-      pullup(udc, is_active);
++      udc->pullup = (is_active != 0);
++      pullup(udc);
+       return 0;
+ }
+@@ -998,7 +1012,7 @@ static const struct usb_gadget_ops pxa2xx_udc_ops = {
+ static struct pxa2xx_udc memory;
+ static int
+-udc_seq_show(struct seq_file *m, void *d)
++udc_seq_show(struct seq_file *m, void *_d)
+ {
+       struct pxa2xx_udc       *dev = m->private;
+       unsigned long           flags;
+@@ -1145,11 +1159,6 @@ static void udc_disable(struct pxa2xx_udc *dev)
+       udc_clear_mask_UDCCR(UDCCR_UDE);
+-#ifdef        CONFIG_ARCH_PXA
+-        /* Disable clock for USB device */
+-      clk_disable(dev->clk);
+-#endif
+-
+       ep0_idle (dev);
+       dev->gadget.speed = USB_SPEED_UNKNOWN;
+ }
+@@ -1190,11 +1199,6 @@ static void udc_enable (struct pxa2xx_udc *dev)
+ {
+       udc_clear_mask_UDCCR(UDCCR_UDE);
+-#ifdef        CONFIG_ARCH_PXA
+-        /* Enable clock for USB device */
+-      clk_enable(dev->clk);
+-#endif
+-
+       /* try to clear these bits before we enable the udc */
+       udc_ack_int_UDCCR(UDCCR_SUSIR|/*UDCCR_RSTIR|*/UDCCR_RESIR);
+@@ -1285,7 +1289,7 @@ fail:
+        * for set_configuration as well as eventual disconnect.
+        */
+       DMSG("registered gadget driver '%s'\n", driver->driver.name);
+-      pullup(dev, 1);
++      pullup(dev);
+       dump_state(dev);
+       return 0;
+ }
+@@ -1328,7 +1332,8 @@ int usb_gadget_unregister_driver(struct usb_gadget_driver *driver)
+               return -EINVAL;
+       local_irq_disable();
+-      pullup(dev, 0);
++      dev->pullup = 0;
++      pullup(dev);
+       stop_activity(dev, driver);
+       local_irq_enable();
+@@ -2267,7 +2272,9 @@ static int __exit pxa2xx_udc_remove(struct platform_device *pdev)
+       if (dev->driver)
+               return -EBUSY;
+-      udc_disable(dev);
++      dev->pullup = 0;
++      pullup(dev);
++
+       remove_debug_files(dev);
+       if (dev->got_irq) {
+@@ -2315,10 +2322,15 @@ static int __exit pxa2xx_udc_remove(struct platform_device *pdev)
+ static int pxa2xx_udc_suspend(struct platform_device *dev, pm_message_t state)
+ {
+       struct pxa2xx_udc       *udc = platform_get_drvdata(dev);
++      unsigned long flags;
+       if (!udc->mach->gpio_pullup && !udc->mach->udc_command)
+               WARN("USB host won't detect disconnect!\n");
+-      pullup(udc, 0);
++      udc->suspended = 1;
++
++      local_irq_save(flags);
++      pullup(udc);
++      local_irq_restore(flags);
+       return 0;
+ }
+@@ -2326,8 +2338,12 @@ static int pxa2xx_udc_suspend(struct platform_device *dev, pm_message_t state)
+ static int pxa2xx_udc_resume(struct platform_device *dev)
+ {
+       struct pxa2xx_udc       *udc = platform_get_drvdata(dev);
++      unsigned long flags;
+-      pullup(udc, 1);
++      udc->suspended = 0;
++      local_irq_save(flags);
++      pullup(udc);
++      local_irq_restore(flags);
+       return 0;
+ }
+diff --git a/drivers/usb/gadget/pxa2xx_udc.h b/drivers/usb/gadget/pxa2xx_udc.h
+index c08b1a2..93586b2 100644
+--- a/drivers/usb/gadget/pxa2xx_udc.h
++++ b/drivers/usb/gadget/pxa2xx_udc.h
+@@ -119,7 +119,9 @@ struct pxa2xx_udc {
+                                               has_cfr : 1,
+                                               req_pending : 1,
+                                               req_std : 1,
+-                                              req_config : 1;
++                                              req_config : 1,
++                                              suspended : 1,
++                                              active : 1;
+ #define start_watchdog(dev) mod_timer(&dev->timer, jiffies + (HZ/200))
+       struct timer_list                       timer;
+@@ -239,7 +241,7 @@ dump_state(struct pxa2xx_udc *dev)
+               dev->stats.read.bytes, dev->stats.read.ops);
+       for (i = 1; i < PXA_UDC_NUM_ENDPOINTS; i++) {
+-              if (dev->ep [i].desc == 0)
++              if (dev->ep [i].desc == NULL)
+                       continue;
+               DMSG ("udccs%d = %02x\n", i, *dev->ep->reg_udccs);
+       }
+-- 
+1.5.3.8
+
diff --git a/packages/kexecboot/linux-kexecboot-2.6.24/tosa/0019-pxa-remove-periodic-mode-emulation-support.patch b/packages/kexecboot/linux-kexecboot-2.6.24/tosa/0019-pxa-remove-periodic-mode-emulation-support.patch
new file mode 100644 (file)
index 0000000..4b4107d
--- /dev/null
@@ -0,0 +1,128 @@
+From bda65817167cce5294e1d84670f36815262ed550 Mon Sep 17 00:00:00 2001
+From: Russell King <rmk@dyn-67.arm.linux.org.uk>
+Date: Sun, 3 Feb 2008 21:58:12 +0300
+Subject: [PATCH 19/64] pxa: remove periodic mode emulation support
+
+Apparantly, the generic time subsystem can accurately emulate periodic
+mode via the one-shot support code, so we don't need our own periodic
+emulation code anymore.  Just ensure that we build support for one shot
+into the generic time subsystem.
+
+Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
+---
+ arch/arm/Kconfig         |    1 +
+ arch/arm/mach-pxa/time.c |   61 ++++++----------------------------------------
+ 2 files changed, 9 insertions(+), 53 deletions(-)
+
+diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
+index a04f507..1be7182 100644
+--- a/arch/arm/Kconfig
++++ b/arch/arm/Kconfig
+@@ -345,6 +345,7 @@ config ARCH_PXA
+       select GENERIC_GPIO
+       select GENERIC_TIME
+       select GENERIC_CLOCKEVENTS
++      select TICK_ONESHOT
+       help
+         Support for Intel/Marvell's PXA2xx/PXA3xx processor line.
+diff --git a/arch/arm/mach-pxa/time.c b/arch/arm/mach-pxa/time.c
+index fbfa192..3c4abbf 100644
+--- a/arch/arm/mach-pxa/time.c
++++ b/arch/arm/mach-pxa/time.c
+@@ -59,55 +59,17 @@ unsigned long long sched_clock(void)
+ }
++#define MIN_OSCR_DELTA 16
++
+ static irqreturn_t
+ pxa_ost0_interrupt(int irq, void *dev_id)
+ {
+-      int next_match;
+       struct clock_event_device *c = dev_id;
+-      if (c->mode == CLOCK_EVT_MODE_ONESHOT) {
+-              /* Disarm the compare/match, signal the event. */
+-              OIER &= ~OIER_E0;
+-              OSSR = OSSR_M0;
+-              c->event_handler(c);
+-      } else if (c->mode == CLOCK_EVT_MODE_PERIODIC) {
+-              /* Call the event handler as many times as necessary
+-               * to recover missed events, if any (if we update
+-               * OSMR0 and OSCR0 is still ahead of us, we've missed
+-               * the event).  As we're dealing with that, re-arm the
+-               * compare/match for the next event.
+-               *
+-               * HACK ALERT:
+-               *
+-               * There's a latency between the instruction that
+-               * writes to OSMR0 and the actual commit to the
+-               * physical hardware, because the CPU doesn't (have
+-               * to) run at bus speed, there's a write buffer
+-               * between the CPU and the bus, etc. etc.  So if the
+-               * target OSCR0 is "very close", to the OSMR0 load
+-               * value, the update to OSMR0 might not get to the
+-               * hardware in time and we'll miss that interrupt.
+-               *
+-               * To be safe, if the new OSMR0 is "very close" to the
+-               * target OSCR0 value, we call the event_handler as
+-               * though the event actually happened.  According to
+-               * Nico's comment in the previous version of this
+-               * code, experience has shown that 6 OSCR ticks is
+-               * "very close" but he went with 8.  We will use 16,
+-               * based on the results of testing on PXA270.
+-               *
+-               * To be doubly sure, we also tell clkevt via
+-               * clockevents_register_device() not to ask for
+-               * anything that might put us "very close".
+-       */
+-#define MIN_OSCR_DELTA 16
+-              do {
+-                      OSSR = OSSR_M0;
+-                      next_match = (OSMR0 += LATCH);
+-                      c->event_handler(c);
+-              } while (((signed long)(next_match - OSCR) <= MIN_OSCR_DELTA)
+-                       && (c->mode == CLOCK_EVT_MODE_PERIODIC));
+-      }
++      /* Disarm the compare/match, signal the event. */
++      OIER &= ~OIER_E0;
++      OSSR = OSSR_M0;
++      c->event_handler(c);
+       return IRQ_HANDLED;
+ }
+@@ -133,14 +95,6 @@ pxa_osmr0_set_mode(enum clock_event_mode mode, struct clock_event_device *dev)
+       unsigned long irqflags;
+       switch (mode) {
+-      case CLOCK_EVT_MODE_PERIODIC:
+-              raw_local_irq_save(irqflags);
+-              OSSR = OSSR_M0;
+-              OIER |= OIER_E0;
+-              OSMR0 = OSCR + LATCH;
+-              raw_local_irq_restore(irqflags);
+-              break;
+-
+       case CLOCK_EVT_MODE_ONESHOT:
+               raw_local_irq_save(irqflags);
+               OIER &= ~OIER_E0;
+@@ -158,13 +112,14 @@ pxa_osmr0_set_mode(enum clock_event_mode mode, struct clock_event_device *dev)
+               break;
+       case CLOCK_EVT_MODE_RESUME:
++      case CLOCK_EVT_MODE_PERIODIC:
+               break;
+       }
+ }
+ static struct clock_event_device ckevt_pxa_osmr0 = {
+       .name           = "osmr0",
+-      .features       = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT,
++      .features       = CLOCK_EVT_FEAT_ONESHOT,
+       .shift          = 32,
+       .rating         = 200,
+       .cpumask        = CPU_MASK_CPU0,
+-- 
+1.5.3.8
+
diff --git a/packages/kexecboot/linux-kexecboot-2.6.24/tosa/0020-Provide-dew-device-clock-backports-from-2.6.24-git.patch b/packages/kexecboot/linux-kexecboot-2.6.24/tosa/0020-Provide-dew-device-clock-backports-from-2.6.24-git.patch
new file mode 100644 (file)
index 0000000..0a42bc5
--- /dev/null
@@ -0,0 +1,257 @@
+From ee8ca5742e0000dd2369ef4d328c2c1117276a3b Mon Sep 17 00:00:00 2001
+From: Dmitry Baryshkov <dbaryshkov@gmail.com>
+Date: Mon, 4 Feb 2008 02:56:28 +0300
+Subject: [PATCH 20/64] Provide dew device/clock backports from 2.6.24-git
+
+Signed-off-by: Dmitry Baryshkov <dbaryshkov@gmail.com>
+---
+ arch/arm/Kconfig            |    1 +
+ arch/arm/mach-pxa/devices.h |   12 ++++++++++++
+ arch/arm/mach-pxa/pxa25x.c  |   18 ++++++++++++------
+ arch/arm/mach-pxa/pxa27x.c  |   22 ++++++++++++++++------
+ arch/arm/mach-pxa/pxa3xx.c  |   30 ++++++++++++++++++++++++++++++
+ kernel/Makefile             |    1 +
+ 6 files changed, 72 insertions(+), 12 deletions(-)
+
+diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
+index 1be7182..10faf9c 100644
+--- a/arch/arm/Kconfig
++++ b/arch/arm/Kconfig
+@@ -367,6 +367,7 @@ config ARCH_SA1100
+       select ARCH_DISCONTIGMEM_ENABLE
+       select ARCH_MTD_XIP
+       select GENERIC_GPIO
++      select GENERIC_TIME
+       help
+         Support for StrongARM 11x0 based boards.
+diff --git a/arch/arm/mach-pxa/devices.h b/arch/arm/mach-pxa/devices.h
+index 94c8d5c..96c7c89 100644
+--- a/arch/arm/mach-pxa/devices.h
++++ b/arch/arm/mach-pxa/devices.h
+@@ -1,4 +1,6 @@
+ extern struct platform_device pxa_device_mci;
++extern struct platform_device pxa3xx_device_mci2;
++extern struct platform_device pxa3xx_device_mci3;
+ extern struct platform_device pxa_device_udc;
+ extern struct platform_device pxa_device_fb;
+ extern struct platform_device pxa_device_ffuart;
+@@ -12,3 +14,13 @@ extern struct platform_device pxa_device_rtc;
+ extern struct platform_device pxa27x_device_i2c_power;
+ extern struct platform_device pxa27x_device_ohci;
++
++extern struct platform_device pxa25x_device_ssp;
++extern struct platform_device pxa25x_device_nssp;
++extern struct platform_device pxa25x_device_assp;
++extern struct platform_device pxa27x_device_ssp1;
++extern struct platform_device pxa27x_device_ssp2;
++extern struct platform_device pxa27x_device_ssp3;
++extern struct platform_device pxa3xx_device_ssp4;
++
++void __init pxa_register_device(struct platform_device *dev, void *data);
+diff --git a/arch/arm/mach-pxa/pxa25x.c b/arch/arm/mach-pxa/pxa25x.c
+index 006a6e0..5988d99 100644
+--- a/arch/arm/mach-pxa/pxa25x.c
++++ b/arch/arm/mach-pxa/pxa25x.c
+@@ -123,12 +123,15 @@ static struct clk pxa25x_clks[] = {
+       INIT_CKEN("UDCCLK", USB, 47923000, 5, &pxa_device_udc.dev),
+       INIT_CKEN("MMCCLK", MMC, 19169000, 0, &pxa_device_mci.dev),
+       INIT_CKEN("I2CCLK", I2C, 31949000, 0, &pxa_device_i2c.dev),
++
++      INIT_CKEN("SSPCLK",  SSP, 3686400, 0, &pxa25x_device_ssp.dev),
++      INIT_CKEN("SSPCLK", NSSP, 3686400, 0, &pxa25x_device_nssp.dev),
++      INIT_CKEN("SSPCLK", ASSP, 3686400, 0, &pxa25x_device_assp.dev),
++
+       /*
+       INIT_CKEN("PWMCLK",  PWM0, 3686400,  0, NULL),
+       INIT_CKEN("PWMCLK",  PWM0, 3686400,  0, NULL),
+-      INIT_CKEN("SSPCLK",  SSP,  3686400,  0, NULL),
+       INIT_CKEN("I2SCLK",  I2S,  14745600, 0, NULL),
+-      INIT_CKEN("NSSPCLK", NSSP, 3686400,  0, NULL),
+       */
+       INIT_CKEN("FICPCLK", FICP, 47923000, 0, NULL),
+ };
+@@ -216,8 +219,6 @@ static void pxa25x_cpu_pm_restore(unsigned long *sleep_save)
+ static void pxa25x_cpu_pm_enter(suspend_state_t state)
+ {
+-      CKEN = 0;
+-
+       switch (state) {
+       case PM_SUSPEND_MEM:
+               /* set resume return address */
+@@ -239,6 +240,8 @@ static void __init pxa25x_init_pm(void)
+ {
+       pxa_cpu_pm_fns = &pxa25x_cpu_pm_fns;
+ }
++#else
++static inline void pxa25x_init_pm(void) {}
+ #endif
+ /* PXA25x: supports wakeup from GPIO0..GPIO15 and RTC alarm
+@@ -300,6 +303,9 @@ static struct platform_device *pxa25x_devices[] __initdata = {
+       &pxa_device_i2s,
+       &pxa_device_ficp,
+       &pxa_device_rtc,
++      &pxa25x_device_ssp,
++      &pxa25x_device_nssp,
++      &pxa25x_device_assp,
+ };
+ static int __init pxa25x_init(void)
+@@ -315,9 +321,9 @@ static int __init pxa25x_init(void)
+               if ((ret = pxa_init_dma(16)))
+                       return ret;
+-#ifdef CONFIG_PM
++
+               pxa25x_init_pm();
+-#endif
++
+               ret = platform_add_devices(pxa25x_devices,
+                                          ARRAY_SIZE(pxa25x_devices));
+       }
+diff --git a/arch/arm/mach-pxa/pxa27x.c b/arch/arm/mach-pxa/pxa27x.c
+index 8e126e6..30ca4fd 100644
+--- a/arch/arm/mach-pxa/pxa27x.c
++++ b/arch/arm/mach-pxa/pxa27x.c
+@@ -150,11 +150,12 @@ static struct clk pxa27x_clks[] = {
+       INIT_CKEN("I2CCLK", PWRI2C, 13000000, 0, &pxa27x_device_i2c_power.dev),
+       INIT_CKEN("KBDCLK", KEYPAD, 32768, 0, NULL),
++      INIT_CKEN("SSPCLK", SSP1, 13000000, 0, &pxa27x_device_ssp1.dev),
++      INIT_CKEN("SSPCLK", SSP2, 13000000, 0, &pxa27x_device_ssp2.dev),
++      INIT_CKEN("SSPCLK", SSP3, 13000000, 0, &pxa27x_device_ssp3.dev),
++
+       /*
+       INIT_CKEN("PWMCLK",  PWM0, 13000000, 0, NULL),
+-      INIT_CKEN("SSPCLK",  SSP1, 13000000, 0, NULL),
+-      INIT_CKEN("SSPCLK",  SSP2, 13000000, 0, NULL),
+-      INIT_CKEN("SSPCLK",  SSP3, 13000000, 0, NULL),
+       INIT_CKEN("MSLCLK",  MSL,  48000000, 0, NULL),
+       INIT_CKEN("USIMCLK", USIM, 48000000, 0, NULL),
+       INIT_CKEN("MSTKCLK", MEMSTK, 19500000, 0, NULL),
+@@ -304,6 +305,8 @@ static void __init pxa27x_init_pm(void)
+ {
+       pxa_cpu_pm_fns = &pxa27x_cpu_pm_fns;
+ }
++#else
++static inline void pxa27x_init_pm(void) {}
+ #endif
+ /* PXA27x:  Various gpios can issue wakeup events.  This logic only
+@@ -423,6 +426,11 @@ struct platform_device pxa27x_device_i2c_power = {
+       .num_resources  = ARRAY_SIZE(i2c_power_resources),
+ };
++void __init pxa_set_i2c_power_info(struct i2c_pxa_platform_data *info)
++{
++      pxa27x_device_i2c_power.dev.platform_data = info;
++}
++
+ static struct platform_device *devices[] __initdata = {
+       &pxa_device_mci,
+       &pxa_device_udc,
+@@ -435,7 +443,9 @@ static struct platform_device *devices[] __initdata = {
+       &pxa_device_ficp,
+       &pxa_device_rtc,
+       &pxa27x_device_i2c_power,
+-      &pxa27x_device_ohci,
++      &pxa27x_device_ssp1,
++      &pxa27x_device_ssp2,
++      &pxa27x_device_ssp3,
+ };
+ static int __init pxa27x_init(void)
+@@ -446,9 +456,9 @@ static int __init pxa27x_init(void)
+               if ((ret = pxa_init_dma(32)))
+                       return ret;
+-#ifdef CONFIG_PM
++
+               pxa27x_init_pm();
+-#endif
++
+               ret = platform_add_devices(devices, ARRAY_SIZE(devices));
+       }
+       return ret;
+diff --git a/arch/arm/mach-pxa/pxa3xx.c b/arch/arm/mach-pxa/pxa3xx.c
+index 61d9c9d..ccab9da 100644
+--- a/arch/arm/mach-pxa/pxa3xx.c
++++ b/arch/arm/mach-pxa/pxa3xx.c
+@@ -189,8 +189,31 @@ static struct clk pxa3xx_clks[] = {
+       PXA3xx_CKEN("I2CCLK", I2C,  32842000, 0, &pxa_device_i2c.dev),
+       PXA3xx_CKEN("UDCCLK", UDC,  48000000, 5, &pxa_device_udc.dev),
++      PXA3xx_CKEN("USBCLK", USBH, 48000000, 0, &pxa27x_device_ohci.dev),
++
++      PXA3xx_CKEN("SSPCLK", SSP1, 13000000, 0, &pxa27x_device_ssp1.dev),
++      PXA3xx_CKEN("SSPCLK", SSP2, 13000000, 0, &pxa27x_device_ssp2.dev),
++      PXA3xx_CKEN("SSPCLK", SSP3, 13000000, 0, &pxa27x_device_ssp3.dev),
++      PXA3xx_CKEN("SSPCLK", SSP4, 13000000, 0, &pxa3xx_device_ssp4.dev),
++
++      PXA3xx_CKEN("MMCCLK", MMC1, 19500000, 0, &pxa_device_mci.dev),
++      PXA3xx_CKEN("MMCCLK", MMC2, 19500000, 0, &pxa3xx_device_mci2.dev),
++      PXA3xx_CKEN("MMCCLK", MMC3, 19500000, 0, &pxa3xx_device_mci3.dev),
+ };
++#ifdef CONFIG_PM
++#define SLEEP_SAVE_SIZE       4
++
++#define ISRAM_START   0x5c000000
++#define ISRAM_SIZE    SZ_256K
++
++static inline void pxa3xx_init_pm(void) {}
++static inline void pxa3xx_init_irq_pm(void) {}
++#else
++static inline void pxa3xx_init_pm(void) {}
++static inline void pxa3xx_init_irq_pm(void) {}
++#endif
++
+ void __init pxa3xx_init_irq(void)
+ {
+       /* enable CP6 access */
+@@ -202,6 +225,7 @@ void __init pxa3xx_init_irq(void)
+       pxa_init_irq_low();
+       pxa_init_irq_high();
+       pxa_init_irq_gpio(128);
++      pxa3xx_init_irq_pm();
+ }
+ /*
+@@ -219,6 +243,10 @@ static struct platform_device *devices[] __initdata = {
+       &pxa_device_i2s,
+       &pxa_device_ficp,
+       &pxa_device_rtc,
++      &pxa27x_device_ssp1,
++      &pxa27x_device_ssp2,
++      &pxa27x_device_ssp3,
++      &pxa3xx_device_ssp4,
+ };
+ static int __init pxa3xx_init(void)
+@@ -231,6 +259,8 @@ static int __init pxa3xx_init(void)
+               if ((ret = pxa_init_dma(32)))
+                       return ret;
++              pxa3xx_init_pm();
++
+               return platform_add_devices(devices, ARRAY_SIZE(devices));
+       }
+       return 0;
+diff --git a/kernel/Makefile b/kernel/Makefile
+index dfa9695..6d9a87c 100644
+--- a/kernel/Makefile
++++ b/kernel/Makefile
+@@ -57,6 +57,7 @@ obj-$(CONFIG_SYSCTL) += utsname_sysctl.o
+ obj-$(CONFIG_TASK_DELAY_ACCT) += delayacct.o
+ obj-$(CONFIG_TASKSTATS) += taskstats.o tsacct.o
+ obj-$(CONFIG_MARKERS) += marker.o
++obj-$(CONFIG_LATENCYTOP) += latencytop.o
+ ifneq ($(CONFIG_SCHED_NO_NO_OMIT_FRAME_POINTER),y)
+ # According to Alan Modra <alan@linuxcare.com.au>, the -fno-omit-frame-pointer is
+-- 
+1.5.3.8
+
diff --git a/packages/kexecboot/linux-kexecboot-2.6.24/tosa/0021-Add-an-empty-drivers-gpio-directory-for-gpiolib-infr.patch b/packages/kexecboot/linux-kexecboot-2.6.24/tosa/0021-Add-an-empty-drivers-gpio-directory-for-gpiolib-infr.patch
new file mode 100644 (file)
index 0000000..3f85121
--- /dev/null
@@ -0,0 +1,121 @@
+From b77665c545bc260d2b93add129413e4a724d7e6e Mon Sep 17 00:00:00 2001
+From: David Brownell <dbrownell@users.sourceforge.net>
+Date: Fri, 18 Jan 2008 00:35:00 +0300
+Subject: [PATCH 21/64] Add an empty drivers/gpio directory for gpiolib infrastructure and GPIO
+ expanders.  It will be populated by later patches.
+
+This won't be the only place to hold such gpio_chip code.  Many external chips
+add a few GPIOs as secondary functionality (such as MFD drivers) and platform
+code frequently needs to closely integrate GPIO and IRQ support.
+
+This is placed *early* in the build/link sequence since it's common for other
+drivers to depend on GPIOs to do their work, so they must be initialized early
+in the device_initcall() sequence.
+
+Signed-off-by: David Brownell <dbrownell@users.sourceforge.net>
+Acked-by: Jean Delvare <khali@linux-fr.org>
+Cc: Eric Miao <eric.miao@marvell.com>
+Cc: Sam Ravnborg <sam@ravnborg.org>
+Cc: Haavard Skinnemoen <hskinnemoen@atmel.com>
+Cc: Philipp Zabel <philipp.zabel@gmail.com>
+Cc: Russell King <rmk@arm.linux.org.uk>
+Cc: Ben Gardner <bgardner@wabtec.com>
+Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
+---
+ arch/arm/Kconfig      |    2 ++
+ drivers/Kconfig       |    2 ++
+ drivers/Makefile      |    1 +
+ drivers/gpio/Kconfig  |   32 ++++++++++++++++++++++++++++++++
+ drivers/gpio/Makefile |    3 +++
+ 5 files changed, 40 insertions(+), 0 deletions(-)
+ create mode 100644 drivers/gpio/Kconfig
+ create mode 100644 drivers/gpio/Makefile
+
+diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
+index 10faf9c..06ca241 100644
+--- a/arch/arm/Kconfig
++++ b/arch/arm/Kconfig
+@@ -1042,6 +1042,8 @@ source "drivers/i2c/Kconfig"
+ source "drivers/spi/Kconfig"
++source "drivers/gpio/Kconfig"
++
+ source "drivers/w1/Kconfig"
+ source "drivers/power/Kconfig"
+diff --git a/drivers/Kconfig b/drivers/Kconfig
+index f4076d9..90e295a 100644
+--- a/drivers/Kconfig
++++ b/drivers/Kconfig
+@@ -52,6 +52,8 @@ source "drivers/i2c/Kconfig"
+ source "drivers/spi/Kconfig"
++source "drivers/gpio/Kconfig"
++
+ source "drivers/w1/Kconfig"
+ source "drivers/power/Kconfig"
+diff --git a/drivers/Makefile b/drivers/Makefile
+index 8cb37e3..8e5101f 100644
+--- a/drivers/Makefile
++++ b/drivers/Makefile
+@@ -5,6 +5,7 @@
+ # Rewritten to use lists instead of if-statements.
+ #
++obj-$(CONFIG_HAVE_GPIO_LIB)   += gpio/
+ obj-$(CONFIG_PCI)             += pci/
+ obj-$(CONFIG_PARISC)          += parisc/
+ obj-$(CONFIG_RAPIDIO)         += rapidio/
+diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig
+new file mode 100644
+index 0000000..560687c
+--- /dev/null
++++ b/drivers/gpio/Kconfig
+@@ -0,0 +1,32 @@
++#
++# GPIO infrastructure and expanders
++#
++
++config HAVE_GPIO_LIB
++      bool
++      help
++        Platforms select gpiolib if they use this infrastructure
++        for all their GPIOs, usually starting with ones integrated
++        into SOC processors.
++
++menu "GPIO Support"
++      depends on HAVE_GPIO_LIB
++
++config DEBUG_GPIO
++      bool "Debug GPIO calls"
++      depends on DEBUG_KERNEL
++      help
++        Say Y here to add some extra checks and diagnostics to GPIO calls.
++        The checks help ensure that GPIOs have been properly initialized
++        before they are used and that sleeping calls aren not made from
++        nonsleeping contexts.  They can make bitbanged serial protocols
++        slower.  The diagnostics help catch the type of setup errors
++        that are most common when setting up new platforms or boards.
++
++# put expanders in the right section, in alphabetical order
++
++comment "I2C GPIO expanders:"
++
++comment "SPI GPIO expanders:"
++
++endmenu
+diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile
+new file mode 100644
+index 0000000..cdbba6b
+--- /dev/null
++++ b/drivers/gpio/Makefile
+@@ -0,0 +1,3 @@
++# gpio support: dedicated expander chips, etc
++
++ccflags-$(CONFIG_DEBUG_GPIO)  += -DDEBUG
+-- 
+1.5.3.8
+
diff --git a/packages/kexecboot/linux-kexecboot-2.6.24/tosa/0022-Provide-new-implementation-infrastructure-that-platf.patch b/packages/kexecboot/linux-kexecboot-2.6.24/tosa/0022-Provide-new-implementation-infrastructure-that-platf.patch
new file mode 100644 (file)
index 0000000..f39fedb
--- /dev/null
@@ -0,0 +1,746 @@
+From 3a0251c01446f3a6763e4406ca5495102db63aa4 Mon Sep 17 00:00:00 2001
+From: David Brownell <dbrownell@users.sourceforge.net>
+Date: Fri, 18 Jan 2008 00:35:20 +0300
+Subject: [PATCH 22/64] Provide new implementation infrastructure that platforms may choose to use
+ when implementing the GPIO programming interface.  Platforms can update their
+ GPIO support to use this.  In many cases the incremental cost to access a
+ non-inlined GPIO should be less than a dozen instructions, with the memory
+ cost being about a page (total) of extra data and code.  The upside is:
+
+  * Providing two features which were "want to have (but OK to defer)" when
+    GPIO interfaces were first discussed in November 2006:
+
+    -  A "struct gpio_chip" to plug in GPIOs that aren't directly supported
+       by SOC platforms, but come from FPGAs or other multifunction devices
+       using conventional device registers (like UCB-1x00 or SM501 GPIOs,
+       and southbridges in PCs with more open specs than usual).
+
+    -  Full support for message-based GPIO expanders, where registers are
+       accessed through sleeping I/O calls.  Previous support for these
+       "cansleep" calls was just stubs.  (One example: the widely used
+       pcf8574 I2C chips, with 8 GPIOs each.)
+
+  * Including a non-stub implementation of the gpio_{request,free}() calls,
+    making those calls much more useful.  The diagnostic labels are also
+    recorded given DEBUG_FS, so /sys/kernel/debug/gpio can show a snapshot
+    of all GPIOs known to this infrastructure.
+
+The driver programming interfaces introduced in 2.6.21 do not change at all;
+this infrastructure is entirely below those covers.
+
+Signed-off-by: David Brownell <dbrownell@users.sourceforge.net>
+Cc: Sam Ravnborg <sam@ravnborg.org>
+Cc: Jean Delvare <khali@linux-fr.org>
+Cc: Eric Miao <eric.miao@marvell.com>
+Cc: Haavard Skinnemoen <hskinnemoen@atmel.com>
+Cc: Philipp Zabel <philipp.zabel@gmail.com>
+Cc: Russell King <rmk@arm.linux.org.uk>
+Cc: Ben Gardner <bgardner@wabtec.com>
+Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
+---
+ drivers/gpio/Makefile      |    2 +
+ drivers/gpio/gpiolib.c     |  567 ++++++++++++++++++++++++++++++++++++++++++++
+ include/asm-generic/gpio.h |   98 ++++++++
+ 3 files changed, 667 insertions(+), 0 deletions(-)
+ create mode 100644 drivers/gpio/gpiolib.c
+
+diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile
+index cdbba6b..2db28ce 100644
+--- a/drivers/gpio/Makefile
++++ b/drivers/gpio/Makefile
+@@ -1,3 +1,5 @@
+ # gpio support: dedicated expander chips, etc
+ ccflags-$(CONFIG_DEBUG_GPIO)  += -DDEBUG
++
++obj-$(CONFIG_HAVE_GPIO_LIB)   += gpiolib.o
+diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c
+new file mode 100644
+index 0000000..d8db2f8
+--- /dev/null
++++ b/drivers/gpio/gpiolib.c
+@@ -0,0 +1,567 @@
++#include <linux/kernel.h>
++#include <linux/module.h>
++#include <linux/irq.h>
++#include <linux/spinlock.h>
++
++#include <asm/gpio.h>
++
++
++/* Optional implementation infrastructure for GPIO interfaces.
++ *
++ * Platforms may want to use this if they tend to use very many GPIOs
++ * that aren't part of a System-On-Chip core; or across I2C/SPI/etc.
++ *
++ * When kernel footprint or instruction count is an issue, simpler
++ * implementations may be preferred.  The GPIO programming interface
++ * allows for inlining speed-critical get/set operations for common
++ * cases, so that access to SOC-integrated GPIOs can sometimes cost
++ * only an instruction or two per bit.
++ */
++
++
++/* When debugging, extend minimal trust to callers and platform code.
++ * Also emit diagnostic messages that may help initial bringup, when
++ * board setup or driver bugs are most common.
++ *
++ * Otherwise, minimize overhead in what may be bitbanging codepaths.
++ */
++#ifdef        DEBUG
++#define       extra_checks    1
++#else
++#define       extra_checks    0
++#endif
++
++/* gpio_lock prevents conflicts during gpio_desc[] table updates.
++ * While any GPIO is requested, its gpio_chip is not removable;
++ * each GPIO's "requested" flag serves as a lock and refcount.
++ */
++static DEFINE_SPINLOCK(gpio_lock);
++
++struct gpio_desc {
++      struct gpio_chip        *chip;
++      unsigned long           flags;
++/* flag symbols are bit numbers */
++#define FLAG_REQUESTED        0
++#define FLAG_IS_OUT   1
++
++#ifdef CONFIG_DEBUG_FS
++      const char              *label;
++#endif
++};
++static struct gpio_desc gpio_desc[ARCH_NR_GPIOS];
++
++static inline void desc_set_label(struct gpio_desc *d, const char *label)
++{
++#ifdef CONFIG_DEBUG_FS
++      d->label = label;
++#endif
++}
++
++/* Warn when drivers omit gpio_request() calls -- legal but ill-advised
++ * when setting direction, and otherwise illegal.  Until board setup code
++ * and drivers use explicit requests everywhere (which won't happen when
++ * those calls have no teeth) we can't avoid autorequesting.  This nag
++ * message should motivate switching to explicit requests...
++ */
++static void gpio_ensure_requested(struct gpio_desc *desc)
++{
++      if (test_and_set_bit(FLAG_REQUESTED, &desc->flags) == 0) {
++              pr_warning("GPIO-%d autorequested\n", (int)(desc - gpio_desc));
++              desc_set_label(desc, "[auto]");
++      }
++}
++
++/* caller holds gpio_lock *OR* gpio is marked as requested */
++static inline struct gpio_chip *gpio_to_chip(unsigned gpio)
++{
++      return gpio_desc[gpio].chip;
++}
++
++/**
++ * gpiochip_add() - register a gpio_chip
++ * @chip: the chip to register, with chip->base initialized
++ * Context: potentially before irqs or kmalloc will work
++ *
++ * Returns a negative errno if the chip can't be registered, such as
++ * because the chip->base is invalid or already associated with a
++ * different chip.  Otherwise it returns zero as a success code.
++ */
++int gpiochip_add(struct gpio_chip *chip)
++{
++      unsigned long   flags;
++      int             status = 0;
++      unsigned        id;
++
++      /* NOTE chip->base negative is reserved to mean a request for
++       * dynamic allocation.  We don't currently support that.
++       */
++
++      if (chip->base < 0 || (chip->base  + chip->ngpio) >= ARCH_NR_GPIOS) {
++              status = -EINVAL;
++              goto fail;
++      }
++
++      spin_lock_irqsave(&gpio_lock, flags);
++
++      /* these GPIO numbers must not be managed by another gpio_chip */
++      for (id = chip->base; id < chip->base + chip->ngpio; id++) {
++              if (gpio_desc[id].chip != NULL) {
++                      status = -EBUSY;
++                      break;
++              }
++      }
++      if (status == 0) {
++              for (id = chip->base; id < chip->base + chip->ngpio; id++) {
++                      gpio_desc[id].chip = chip;
++                      gpio_desc[id].flags = 0;
++              }
++      }
++
++      spin_unlock_irqrestore(&gpio_lock, flags);
++fail:
++      /* failures here can mean systems won't boot... */
++      if (status)
++              pr_err("gpiochip_add: gpios %d..%d (%s) not registered\n",
++                      chip->base, chip->base + chip->ngpio,
++                      chip->label ? : "generic");
++      return status;
++}
++EXPORT_SYMBOL_GPL(gpiochip_add);
++
++/**
++ * gpiochip_remove() - unregister a gpio_chip
++ * @chip: the chip to unregister
++ *
++ * A gpio_chip with any GPIOs still requested may not be removed.
++ */
++int gpiochip_remove(struct gpio_chip *chip)
++{
++      unsigned long   flags;
++      int             status = 0;
++      unsigned        id;
++
++      spin_lock_irqsave(&gpio_lock, flags);
++
++      for (id = chip->base; id < chip->base + chip->ngpio; id++) {
++              if (test_bit(FLAG_REQUESTED, &gpio_desc[id].flags)) {
++                      status = -EBUSY;
++                      break;
++              }
++      }
++      if (status == 0) {
++              for (id = chip->base; id < chip->base + chip->ngpio; id++)
++                      gpio_desc[id].chip = NULL;
++      }
++
++      spin_unlock_irqrestore(&gpio_lock, flags);
++      return status;
++}
++EXPORT_SYMBOL_GPL(gpiochip_remove);
++
++
++/* These "optional" allocation calls help prevent drivers from stomping
++ * on each other, and help provide better diagnostics in debugfs.
++ * They're called even less than the "set direction" calls.
++ */
++int gpio_request(unsigned gpio, const char *label)
++{
++      struct gpio_desc        *desc;
++      int                     status = -EINVAL;
++      unsigned long           flags;
++
++      spin_lock_irqsave(&gpio_lock, flags);
++
++      if (gpio >= ARCH_NR_GPIOS)
++              goto done;
++      desc = &gpio_desc[gpio];
++      if (desc->chip == NULL)
++              goto done;
++
++      /* NOTE:  gpio_request() can be called in early boot,
++       * before IRQs are enabled.
++       */
++
++      if (test_and_set_bit(FLAG_REQUESTED, &desc->flags) == 0) {
++              desc_set_label(desc, label ? : "?");
++              status = 0;
++      } else
++              status = -EBUSY;
++
++done:
++      if (status)
++              pr_debug("gpio_request: gpio-%d (%s) status %d\n",
++                      gpio, label ? : "?", status);
++      spin_unlock_irqrestore(&gpio_lock, flags);
++      return status;
++}
++EXPORT_SYMBOL_GPL(gpio_request);
++
++void gpio_free(unsigned gpio)
++{
++      unsigned long           flags;
++      struct gpio_desc        *desc;
++
++      if (gpio >= ARCH_NR_GPIOS) {
++              WARN_ON(extra_checks);
++              return;
++      }
++
++      spin_lock_irqsave(&gpio_lock, flags);
++
++      desc = &gpio_desc[gpio];
++      if (desc->chip && test_and_clear_bit(FLAG_REQUESTED, &desc->flags))
++              desc_set_label(desc, NULL);
++      else
++              WARN_ON(extra_checks);
++
++      spin_unlock_irqrestore(&gpio_lock, flags);
++}
++EXPORT_SYMBOL_GPL(gpio_free);
++
++
++/**
++ * gpiochip_is_requested - return string iff signal was requested
++ * @chip: controller managing the signal
++ * @offset: of signal within controller's 0..(ngpio - 1) range
++ *
++ * Returns NULL if the GPIO is not currently requested, else a string.
++ * If debugfs support is enabled, the string returned is the label passed
++ * to gpio_request(); otherwise it is a meaningless constant.
++ *
++ * This function is for use by GPIO controller drivers.  The label can
++ * help with diagnostics, and knowing that the signal is used as a GPIO
++ * can help avoid accidentally multiplexing it to another controller.
++ */
++const char *gpiochip_is_requested(struct gpio_chip *chip, unsigned offset)
++{
++      unsigned gpio = chip->base + offset;
++
++      if (gpio >= ARCH_NR_GPIOS || gpio_desc[gpio].chip != chip)
++              return NULL;
++      if (test_bit(FLAG_REQUESTED, &gpio_desc[gpio].flags) == 0)
++              return NULL;
++#ifdef CONFIG_DEBUG_FS
++      return gpio_desc[gpio].label;
++#else
++      return "?";
++#endif
++}
++EXPORT_SYMBOL_GPL(gpiochip_is_requested);
++
++
++/* Drivers MUST set GPIO direction before making get/set calls.  In
++ * some cases this is done in early boot, before IRQs are enabled.
++ *
++ * As a rule these aren't called more than once (except for drivers
++ * using the open-drain emulation idiom) so these are natural places
++ * to accumulate extra debugging checks.  Note that we can't (yet)
++ * rely on gpio_request() having been called beforehand.
++ */
++
++int gpio_direction_input(unsigned gpio)
++{
++      unsigned long           flags;
++      struct gpio_chip        *chip;
++      struct gpio_desc        *desc = &gpio_desc[gpio];
++      int                     status = -EINVAL;
++
++      spin_lock_irqsave(&gpio_lock, flags);
++
++      if (gpio >= ARCH_NR_GPIOS)
++              goto fail;
++      chip = desc->chip;
++      if (!chip || !chip->get || !chip->direction_input)
++              goto fail;
++      gpio -= chip->base;
++      if (gpio >= chip->ngpio)
++              goto fail;
++      gpio_ensure_requested(desc);
++
++      /* now we know the gpio is valid and chip won't vanish */
++
++      spin_unlock_irqrestore(&gpio_lock, flags);
++
++      might_sleep_if(extra_checks && chip->can_sleep);
++
++      status = chip->direction_input(chip, gpio);
++      if (status == 0)
++              clear_bit(FLAG_IS_OUT, &desc->flags);
++      return status;
++fail:
++      spin_unlock_irqrestore(&gpio_lock, flags);
++      if (status)
++              pr_debug("%s: gpio-%d status %d\n",
++                      __FUNCTION__, gpio, status);
++      return status;
++}
++EXPORT_SYMBOL_GPL(gpio_direction_input);
++
++int gpio_direction_output(unsigned gpio, int value)
++{
++      unsigned long           flags;
++      struct gpio_chip        *chip;
++      struct gpio_desc        *desc = &gpio_desc[gpio];
++      int                     status = -EINVAL;
++
++      spin_lock_irqsave(&gpio_lock, flags);
++
++      if (gpio >= ARCH_NR_GPIOS)
++              goto fail;
++      chip = desc->chip;
++      if (!chip || !chip->set || !chip->direction_output)
++              goto fail;
++      gpio -= chip->base;
++      if (gpio >= chip->ngpio)
++              goto fail;
++      gpio_ensure_requested(desc);
++
++      /* now we know the gpio is valid and chip won't vanish */
++
++      spin_unlock_irqrestore(&gpio_lock, flags);
++
++      might_sleep_if(extra_checks && chip->can_sleep);
++
++      status = chip->direction_output(chip, gpio, value);
++      if (status == 0)
++              set_bit(FLAG_IS_OUT, &desc->flags);
++      return status;
++fail:
++      spin_unlock_irqrestore(&gpio_lock, flags);
++      if (status)
++              pr_debug("%s: gpio-%d status %d\n",
++                      __FUNCTION__, gpio, status);
++      return status;
++}
++EXPORT_SYMBOL_GPL(gpio_direction_output);
++
++
++/* I/O calls are only valid after configuration completed; the relevant
++ * "is this a valid GPIO" error checks should already have been done.
++ *
++ * "Get" operations are often inlinable as reading a pin value register,
++ * and masking the relevant bit in that register.
++ *
++ * When "set" operations are inlinable, they involve writing that mask to
++ * one register to set a low value, or a different register to set it high.
++ * Otherwise locking is needed, so there may be little value to inlining.
++ *
++ *------------------------------------------------------------------------
++ *
++ * IMPORTANT!!!  The hot paths -- get/set value -- assume that callers
++ * have requested the GPIO.  That can include implicit requesting by
++ * a direction setting call.  Marking a gpio as requested locks its chip
++ * in memory, guaranteeing that these table lookups need no more locking
++ * and that gpiochip_remove() will fail.
++ *
++ * REVISIT when debugging, consider adding some instrumentation to ensure
++ * that the GPIO was actually requested.
++ */
++
++/**
++ * __gpio_get_value() - return a gpio's value
++ * @gpio: gpio whose value will be returned
++ * Context: any
++ *
++ * This is used directly or indirectly to implement gpio_get_value().
++ * It returns the zero or nonzero value provided by the associated
++ * gpio_chip.get() method; or zero if no such method is provided.
++ */
++int __gpio_get_value(unsigned gpio)
++{
++      struct gpio_chip        *chip;
++
++      chip = gpio_to_chip(gpio);
++      WARN_ON(extra_checks && chip->can_sleep);
++      return chip->get ? chip->get(chip, gpio - chip->base) : 0;
++}
++EXPORT_SYMBOL_GPL(__gpio_get_value);
++
++/**
++ * __gpio_set_value() - assign a gpio's value
++ * @gpio: gpio whose value will be assigned
++ * @value: value to assign
++ * Context: any
++ *
++ * This is used directly or indirectly to implement gpio_set_value().
++ * It invokes the associated gpio_chip.set() method.
++ */
++void __gpio_set_value(unsigned gpio, int value)
++{
++      struct gpio_chip        *chip;
++
++      chip = gpio_to_chip(gpio);
++      WARN_ON(extra_checks && chip->can_sleep);
++      chip->set(chip, gpio - chip->base, value);
++}
++EXPORT_SYMBOL_GPL(__gpio_set_value);
++
++/**
++ * __gpio_cansleep() - report whether gpio value access will sleep
++ * @gpio: gpio in question
++ * Context: any
++ *
++ * This is used directly or indirectly to implement gpio_cansleep().  It
++ * returns nonzero if access reading or writing the GPIO value can sleep.
++ */
++int __gpio_cansleep(unsigned gpio)
++{
++      struct gpio_chip        *chip;
++
++      /* only call this on GPIOs that are valid! */
++      chip = gpio_to_chip(gpio);
++
++      return chip->can_sleep;
++}
++EXPORT_SYMBOL_GPL(__gpio_cansleep);
++
++
++
++/* There's no value in making it easy to inline GPIO calls that may sleep.
++ * Common examples include ones connected to I2C or SPI chips.
++ */
++
++int gpio_get_value_cansleep(unsigned gpio)
++{
++      struct gpio_chip        *chip;
++
++      might_sleep_if(extra_checks);
++      chip = gpio_to_chip(gpio);
++      return chip->get(chip, gpio - chip->base);
++}
++EXPORT_SYMBOL_GPL(gpio_get_value_cansleep);
++
++void gpio_set_value_cansleep(unsigned gpio, int value)
++{
++      struct gpio_chip        *chip;
++
++      might_sleep_if(extra_checks);
++      chip = gpio_to_chip(gpio);
++      chip->set(chip, gpio - chip->base, value);
++}
++EXPORT_SYMBOL_GPL(gpio_set_value_cansleep);
++
++
++#ifdef CONFIG_DEBUG_FS
++
++#include <linux/debugfs.h>
++#include <linux/seq_file.h>
++
++
++static void gpiolib_dbg_show(struct seq_file *s, struct gpio_chip *chip)
++{
++      unsigned                i;
++      unsigned                gpio = chip->base;
++      struct gpio_desc        *gdesc = &gpio_desc[gpio];
++      int                     is_out;
++
++      for (i = 0; i < chip->ngpio; i++, gpio++, gdesc++) {
++              if (!test_bit(FLAG_REQUESTED, &gdesc->flags))
++                      continue;
++
++              is_out = test_bit(FLAG_IS_OUT, &gdesc->flags);
++              seq_printf(s, " gpio-%-3d (%-12s) %s %s",
++                      gpio, gdesc->label,
++                      is_out ? "out" : "in ",
++                      chip->get
++                              ? (chip->get(chip, i) ? "hi" : "lo")
++                              : "?  ");
++
++              if (!is_out) {
++                      int             irq = gpio_to_irq(gpio);
++                      struct irq_desc *desc = irq_desc + irq;
++
++                      /* This races with request_irq(), set_irq_type(),
++                       * and set_irq_wake() ... but those are "rare".
++                       *
++                       * More significantly, trigger type flags aren't
++                       * currently maintained by genirq.
++                       */
++                      if (irq >= 0 && desc->action) {
++                              char *trigger;
++
++                              switch (desc->status & IRQ_TYPE_SENSE_MASK) {
++                              case IRQ_TYPE_NONE:
++                                      trigger = "(default)";
++                                      break;
++                              case IRQ_TYPE_EDGE_FALLING:
++                                      trigger = "edge-falling";
++                                      break;
++                              case IRQ_TYPE_EDGE_RISING:
++                                      trigger = "edge-rising";
++                                      break;
++                              case IRQ_TYPE_EDGE_BOTH:
++                                      trigger = "edge-both";
++                                      break;
++                              case IRQ_TYPE_LEVEL_HIGH:
++                                      trigger = "level-high";
++                                      break;
++                              case IRQ_TYPE_LEVEL_LOW:
++                                      trigger = "level-low";
++                                      break;
++                              default:
++                                      trigger = "?trigger?";
++                                      break;
++                              }
++
++                              seq_printf(s, " irq-%d %s%s",
++                                      irq, trigger,
++                                      (desc->status & IRQ_WAKEUP)
++                                              ? " wakeup" : "");
++                      }
++              }
++
++              seq_printf(s, "\n");
++      }
++}
++
++static int gpiolib_show(struct seq_file *s, void *unused)
++{
++      struct gpio_chip        *chip = NULL;
++      unsigned                gpio;
++      int                     started = 0;
++
++      /* REVISIT this isn't locked against gpio_chip removal ... */
++
++      for (gpio = 0; gpio < ARCH_NR_GPIOS; gpio++) {
++              if (chip == gpio_desc[gpio].chip)
++                      continue;
++              chip = gpio_desc[gpio].chip;
++              if (!chip)
++                      continue;
++
++              seq_printf(s, "%sGPIOs %d-%d, %s%s:\n",
++                              started ? "\n" : "",
++                              chip->base, chip->base + chip->ngpio - 1,
++                              chip->label ? : "generic",
++                              chip->can_sleep ? ", can sleep" : "");
++              started = 1;
++              if (chip->dbg_show)
++                      chip->dbg_show(s, chip);
++              else
++                      gpiolib_dbg_show(s, chip);
++      }
++      return 0;
++}
++
++static int gpiolib_open(struct inode *inode, struct file *file)
++{
++      return single_open(file, gpiolib_show, NULL);
++}
++
++static struct file_operations gpiolib_operations = {
++      .open           = gpiolib_open,
++      .read           = seq_read,
++      .llseek         = seq_lseek,
++      .release        = single_release,
++};
++
++static int __init gpiolib_debugfs_init(void)
++{
++      /* /sys/kernel/debug/gpio */
++      (void) debugfs_create_file("gpio", S_IFREG | S_IRUGO,
++                              NULL, NULL, &gpiolib_operations);
++      return 0;
++}
++subsys_initcall(gpiolib_debugfs_init);
++
++#endif        /* DEBUG_FS */
+diff --git a/include/asm-generic/gpio.h b/include/asm-generic/gpio.h
+index 2d0aab1..f29a502 100644
+--- a/include/asm-generic/gpio.h
++++ b/include/asm-generic/gpio.h
+@@ -1,6 +1,102 @@
+ #ifndef _ASM_GENERIC_GPIO_H
+ #define _ASM_GENERIC_GPIO_H
++#ifdef CONFIG_HAVE_GPIO_LIB
++
++/* Platforms may implement their GPIO interface with library code,
++ * at a small performance cost for non-inlined operations and some
++ * extra memory (for code and for per-GPIO table entries).
++ *
++ * While the GPIO programming interface defines valid GPIO numbers
++ * to be in the range 0..MAX_INT, this library restricts them to the
++ * smaller range 0..ARCH_NR_GPIOS.
++ */
++
++#ifndef ARCH_NR_GPIOS
++#define ARCH_NR_GPIOS         256
++#endif
++
++struct seq_file;
++
++/**
++ * struct gpio_chip - abstract a GPIO controller
++ * @label: for diagnostics
++ * @direction_input: configures signal "offset" as input, or returns error
++ * @get: returns value for signal "offset"; for output signals this
++ *    returns either the value actually sensed, or zero
++ * @direction_output: configures signal "offset" as output, or returns error
++ * @set: assigns output value for signal "offset"
++ * @dbg_show: optional routine to show contents in debugfs; default code
++ *    will be used when this is omitted, but custom code can show extra
++ *    state (such as pullup/pulldown configuration).
++ * @base: identifies the first GPIO number handled by this chip; or, if
++ *    negative during registration, requests dynamic ID allocation.
++ * @ngpio: the number of GPIOs handled by this controller; the last GPIO
++ *    handled is (base + ngpio - 1).
++ * @can_sleep: flag must be set iff get()/set() methods sleep, as they
++ *    must while accessing GPIO expander chips over I2C or SPI
++ *
++ * A gpio_chip can help platforms abstract various sources of GPIOs so
++ * they can all be accessed through a common programing interface.
++ * Example sources would be SOC controllers, FPGAs, multifunction
++ * chips, dedicated GPIO expanders, and so on.
++ *
++ * Each chip controls a number of signals, identified in method calls
++ * by "offset" values in the range 0..(@ngpio - 1).  When those signals
++ * are referenced through calls like gpio_get_value(gpio), the offset
++ * is calculated by subtracting @base from the gpio number.
++ */
++struct gpio_chip {
++      char                    *label;
++
++      int                     (*direction_input)(struct gpio_chip *chip,
++                                              unsigned offset);
++      int                     (*get)(struct gpio_chip *chip,
++                                              unsigned offset);
++      int                     (*direction_output)(struct gpio_chip *chip,
++                                              unsigned offset, int value);
++      void                    (*set)(struct gpio_chip *chip,
++                                              unsigned offset, int value);
++      void                    (*dbg_show)(struct seq_file *s,
++                                              struct gpio_chip *chip);
++      int                     base;
++      u16                     ngpio;
++      unsigned                can_sleep:1;
++};
++
++extern const char *gpiochip_is_requested(struct gpio_chip *chip,
++                      unsigned offset);
++
++/* add/remove chips */
++extern int gpiochip_add(struct gpio_chip *chip);
++extern int __must_check gpiochip_remove(struct gpio_chip *chip);
++
++
++/* Always use the library code for GPIO management calls,
++ * or when sleeping may be involved.
++ */
++extern int gpio_request(unsigned gpio, const char *label);
++extern void gpio_free(unsigned gpio);
++
++extern int gpio_direction_input(unsigned gpio);
++extern int gpio_direction_output(unsigned gpio, int value);
++
++extern int gpio_get_value_cansleep(unsigned gpio);
++extern void gpio_set_value_cansleep(unsigned gpio, int value);
++
++
++/* A platform's <asm/gpio.h> code may want to inline the I/O calls when
++ * the GPIO is constant and refers to some always-present controller,
++ * giving direct access to chip registers and tight bitbanging loops.
++ */
++extern int __gpio_get_value(unsigned gpio);
++extern void __gpio_set_value(unsigned gpio, int value);
++
++extern int __gpio_cansleep(unsigned gpio);
++
++
++#else
++
+ /* platforms that don't directly support access to GPIOs through I2C, SPI,
+  * or other blocking infrastructure can use these wrappers.
+  */
+@@ -22,4 +118,6 @@ static inline void gpio_set_value_cansleep(unsigned gpio, int value)
+       gpio_set_value(gpio, value);
+ }
++#endif
++
+ #endif /* _ASM_GENERIC_GPIO_H */
+-- 
+1.5.3.8
+
diff --git a/packages/kexecboot/linux-kexecboot-2.6.24/tosa/0023-This-adds-gpiolib-support-for-the-PXA-architecture.patch b/packages/kexecboot/linux-kexecboot-2.6.24/tosa/0023-This-adds-gpiolib-support-for-the-PXA-architecture.patch
new file mode 100644 (file)
index 0000000..7a37be8
--- /dev/null
@@ -0,0 +1,498 @@
+From 49da9bd487e54164a75503e0037a054cce697ed5 Mon Sep 17 00:00:00 2001
+From: Philipp Zabel <philipp.zabel@gmail.com>
+Date: Tue, 12 Feb 2008 04:38:12 +0300
+Subject: [PATCH 23/64] This adds gpiolib support for the PXA architecture:
+   - move all GPIO API functions from generic.c into gpio.c
+   - convert the gpio_get/set_value macros into inline functions
+
+This makes it easier to hook up GPIOs provided by external chips like
+ASICs and CPLDs.
+
+Signed-off-by: Philipp Zabel <philipp.zabel@gmail.com>
+Signed-off-by: David Brownell <dbrownell@users.sourceforge.net>
+Acked-by: Russell King <rmk+kernel@arm.linux.org.uk>
+Cc: Jean Delvare <khali@linux-fr.org>
+Cc: Eric Miao <eric.miao@marvell.com>
+Cc: Sam Ravnborg <sam@ravnborg.org>
+Cc: Haavard Skinnemoen <hskinnemoen@atmel.com>
+Cc: Ben Gardner <bgardner@wabtec.com>
+Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
+---
+ arch/arm/Kconfig                    |    1 +
+ arch/arm/mach-pxa/Makefile          |    3 +-
+ arch/arm/mach-pxa/generic.c         |   93 ----------------
+ arch/arm/mach-pxa/generic.h         |    1 +
+ arch/arm/mach-pxa/gpio.c            |  197 +++++++++++++++++++++++++++++++++++
+ arch/arm/mach-pxa/irq.c             |    2 +
+ include/asm-arm/arch-pxa/gpio.h     |   48 ++++-----
+ include/asm-arm/arch-pxa/pxa-regs.h |   13 +++
+ 8 files changed, 236 insertions(+), 122 deletions(-)
+ create mode 100644 arch/arm/mach-pxa/gpio.c
+
+diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
+index 06ca241..423e953 100644
+--- a/arch/arm/Kconfig
++++ b/arch/arm/Kconfig
+@@ -346,6 +346,7 @@ config ARCH_PXA
+       select GENERIC_TIME
+       select GENERIC_CLOCKEVENTS
+       select TICK_ONESHOT
++      select HAVE_GPIO_LIB
+       help
+         Support for Intel/Marvell's PXA2xx/PXA3xx processor line.
+diff --git a/arch/arm/mach-pxa/Makefile b/arch/arm/mach-pxa/Makefile
+index 4263527..5cb0216 100644
+--- a/arch/arm/mach-pxa/Makefile
++++ b/arch/arm/mach-pxa/Makefile
+@@ -3,7 +3,8 @@
+ #
+ # Common support (must be linked before board specific support)
+-obj-y                         += clock.o generic.o irq.o dma.o time.o
++obj-y                         += clock.o generic.o irq.o dma.o \
++                                 time.o gpio.o
+ obj-$(CONFIG_PXA25x)          += pxa25x.o
+ obj-$(CONFIG_PXA27x)          += pxa27x.o
+ obj-$(CONFIG_PXA3xx)          += pxa3xx.o mfp.o
+diff --git a/arch/arm/mach-pxa/generic.c b/arch/arm/mach-pxa/generic.c
+index 1c34946..6c07292 100644
+--- a/arch/arm/mach-pxa/generic.c
++++ b/arch/arm/mach-pxa/generic.c
+@@ -32,7 +32,6 @@
+ #include <asm/mach/map.h>
+ #include <asm/arch/pxa-regs.h>
+-#include <asm/arch/gpio.h>
+ #include <asm/arch/udc.h>
+ #include <asm/arch/pxafb.h>
+ #include <asm/arch/mmc.h>
+@@ -73,97 +72,6 @@ unsigned int get_memclk_frequency_10khz(void)
+ EXPORT_SYMBOL(get_memclk_frequency_10khz);
+ /*
+- * Handy function to set GPIO alternate functions
+- */
+-int pxa_last_gpio;
+-
+-int pxa_gpio_mode(int gpio_mode)
+-{
+-      unsigned long flags;
+-      int gpio = gpio_mode & GPIO_MD_MASK_NR;
+-      int fn = (gpio_mode & GPIO_MD_MASK_FN) >> 8;
+-      int gafr;
+-
+-      if (gpio > pxa_last_gpio)
+-              return -EINVAL;
+-
+-      local_irq_save(flags);
+-      if (gpio_mode & GPIO_DFLT_LOW)
+-              GPCR(gpio) = GPIO_bit(gpio);
+-      else if (gpio_mode & GPIO_DFLT_HIGH)
+-              GPSR(gpio) = GPIO_bit(gpio);
+-      if (gpio_mode & GPIO_MD_MASK_DIR)
+-              GPDR(gpio) |= GPIO_bit(gpio);
+-      else
+-              GPDR(gpio) &= ~GPIO_bit(gpio);
+-      gafr = GAFR(gpio) & ~(0x3 << (((gpio) & 0xf)*2));
+-      GAFR(gpio) = gafr |  (fn  << (((gpio) & 0xf)*2));
+-      local_irq_restore(flags);
+-
+-      return 0;
+-}
+-
+-EXPORT_SYMBOL(pxa_gpio_mode);
+-
+-int gpio_direction_input(unsigned gpio)
+-{
+-      unsigned long flags;
+-      u32 mask;
+-
+-      if (gpio > pxa_last_gpio)
+-              return -EINVAL;
+-
+-      mask = GPIO_bit(gpio);
+-      local_irq_save(flags);
+-      GPDR(gpio) &= ~mask;
+-      local_irq_restore(flags);
+-
+-      return 0;
+-}
+-EXPORT_SYMBOL(gpio_direction_input);
+-
+-int gpio_direction_output(unsigned gpio, int value)
+-{
+-      unsigned long flags;
+-      u32 mask;
+-
+-      if (gpio > pxa_last_gpio)
+-              return -EINVAL;
+-
+-      mask = GPIO_bit(gpio);
+-      local_irq_save(flags);
+-      if (value)
+-              GPSR(gpio) = mask;
+-      else
+-              GPCR(gpio) = mask;
+-      GPDR(gpio) |= mask;
+-      local_irq_restore(flags);
+-
+-      return 0;
+-}
+-EXPORT_SYMBOL(gpio_direction_output);
+-
+-/*
+- * Return GPIO level
+- */
+-int pxa_gpio_get_value(unsigned gpio)
+-{
+-      return __gpio_get_value(gpio);
+-}
+-
+-EXPORT_SYMBOL(pxa_gpio_get_value);
+-
+-/*
+- * Set output GPIO level
+- */
+-void pxa_gpio_set_value(unsigned gpio, int value)
+-{
+-      __gpio_set_value(gpio, value);
+-}
+-
+-EXPORT_SYMBOL(pxa_gpio_set_value);
+-
+-/*
+  * Routine to safely enable or disable a clock in the CKEN
+  */
+ void __pxa_set_cken(int clock, int enable)
+@@ -178,7 +86,6 @@ void __pxa_set_cken(int clock, int enable)
+       local_irq_restore(flags);
+ }
+-
+ EXPORT_SYMBOL(__pxa_set_cken);
+ /*
+diff --git a/arch/arm/mach-pxa/generic.h b/arch/arm/mach-pxa/generic.h
+index b30f240..727a9f5 100644
+--- a/arch/arm/mach-pxa/generic.h
++++ b/arch/arm/mach-pxa/generic.h
+@@ -16,6 +16,7 @@ extern void __init pxa_init_irq_low(void);
+ extern void __init pxa_init_irq_high(void);
+ extern void __init pxa_init_irq_gpio(int gpio_nr);
+ extern void __init pxa_init_irq_set_wake(int (*set_wake)(unsigned int, unsigned int));
++extern void __init pxa_init_gpio(int gpio_nr);
+ extern void __init pxa25x_init_irq(void);
+ extern void __init pxa27x_init_irq(void);
+ extern void __init pxa3xx_init_irq(void);
+diff --git a/arch/arm/mach-pxa/gpio.c b/arch/arm/mach-pxa/gpio.c
+new file mode 100644
+index 0000000..8638dd7
+--- /dev/null
++++ b/arch/arm/mach-pxa/gpio.c
+@@ -0,0 +1,197 @@
++/*
++ *  linux/arch/arm/mach-pxa/gpio.c
++ *
++ *  Generic PXA GPIO handling
++ *
++ *  Author:   Nicolas Pitre
++ *  Created:  Jun 15, 2001
++ *  Copyright:        MontaVista Software Inc.
++ *
++ *  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/init.h>
++#include <linux/module.h>
++
++#include <asm/gpio.h>
++#include <asm/hardware.h>
++#include <asm/io.h>
++#include <asm/arch/pxa-regs.h>
++
++#include "generic.h"
++
++
++struct pxa_gpio_chip {
++      struct gpio_chip chip;
++      void __iomem     *regbase;
++};
++
++int pxa_last_gpio;
++
++/*
++ * Configure pins for GPIO or other functions
++ */
++int pxa_gpio_mode(int gpio_mode)
++{
++      unsigned long flags;
++      int gpio = gpio_mode & GPIO_MD_MASK_NR;
++      int fn = (gpio_mode & GPIO_MD_MASK_FN) >> 8;
++      int gafr;
++
++      if (gpio > pxa_last_gpio)
++              return -EINVAL;
++
++      local_irq_save(flags);
++      if (gpio_mode & GPIO_DFLT_LOW)
++              GPCR(gpio) = GPIO_bit(gpio);
++      else if (gpio_mode & GPIO_DFLT_HIGH)
++              GPSR(gpio) = GPIO_bit(gpio);
++      if (gpio_mode & GPIO_MD_MASK_DIR)
++              GPDR(gpio) |= GPIO_bit(gpio);
++      else
++              GPDR(gpio) &= ~GPIO_bit(gpio);
++      gafr = GAFR(gpio) & ~(0x3 << (((gpio) & 0xf)*2));
++      GAFR(gpio) = gafr |  (fn  << (((gpio) & 0xf)*2));
++      local_irq_restore(flags);
++
++      return 0;
++}
++EXPORT_SYMBOL(pxa_gpio_mode);
++
++static int pxa_gpio_direction_input(struct gpio_chip *chip, unsigned offset)
++{
++      unsigned long        flags;
++      u32                  mask = 1 << offset;
++      u32                  value;
++      struct pxa_gpio_chip *pxa;
++      void __iomem         *gpdr;
++
++      pxa = container_of(chip, struct pxa_gpio_chip, chip);
++      gpdr = pxa->regbase + GPDR_OFFSET;
++      local_irq_save(flags);
++      value = __raw_readl(gpdr);
++      value &= ~mask;
++      __raw_writel(value, gpdr);
++      local_irq_restore(flags);
++
++      return 0;
++}
++
++static int pxa_gpio_direction_output(struct gpio_chip *chip,
++                                      unsigned offset, int value)
++{
++      unsigned long        flags;
++      u32                  mask = 1 << offset;
++      u32                  tmp;
++      struct pxa_gpio_chip *pxa;
++      void __iomem         *gpdr;
++
++      pxa = container_of(chip, struct pxa_gpio_chip, chip);
++      __raw_writel(mask,
++                      pxa->regbase + (value ? GPSR_OFFSET : GPCR_OFFSET));
++      gpdr = pxa->regbase + GPDR_OFFSET;
++      local_irq_save(flags);
++      tmp = __raw_readl(gpdr);
++      tmp |= mask;
++      __raw_writel(tmp, gpdr);
++      local_irq_restore(flags);
++
++      return 0;
++}
++
++/*
++ * Return GPIO level
++ */
++static int pxa_gpio_get(struct gpio_chip *chip, unsigned offset)
++{
++      u32                  mask = 1 << offset;
++      struct pxa_gpio_chip *pxa;
++
++      pxa = container_of(chip, struct pxa_gpio_chip, chip);
++      return __raw_readl(pxa->regbase + GPLR_OFFSET) & mask;
++}
++
++/*
++ * Set output GPIO level
++ */
++static void pxa_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
++{
++      u32                  mask = 1 << offset;
++      struct pxa_gpio_chip *pxa;
++
++      pxa = container_of(chip, struct pxa_gpio_chip, chip);
++
++      if (value)
++              __raw_writel(mask, pxa->regbase + GPSR_OFFSET);
++      else
++              __raw_writel(mask, pxa->regbase + GPCR_OFFSET);
++}
++
++static struct pxa_gpio_chip pxa_gpio_chip[] = {
++      [0] = {
++              .regbase = GPIO0_BASE,
++              .chip = {
++                      .label            = "gpio-0",
++                      .direction_input  = pxa_gpio_direction_input,
++                      .direction_output = pxa_gpio_direction_output,
++                      .get              = pxa_gpio_get,
++                      .set              = pxa_gpio_set,
++                      .base             = 0,
++                      .ngpio            = 32,
++              },
++      },
++      [1] = {
++              .regbase = GPIO1_BASE,
++              .chip = {
++                      .label            = "gpio-1",
++                      .direction_input  = pxa_gpio_direction_input,
++                      .direction_output = pxa_gpio_direction_output,
++                      .get              = pxa_gpio_get,
++                      .set              = pxa_gpio_set,
++                      .base             = 32,
++                      .ngpio            = 32,
++              },
++      },
++      [2] = {
++              .regbase = GPIO2_BASE,
++              .chip = {
++                      .label            = "gpio-2",
++                      .direction_input  = pxa_gpio_direction_input,
++                      .direction_output = pxa_gpio_direction_output,
++                      .get              = pxa_gpio_get,
++                      .set              = pxa_gpio_set,
++                      .base             = 64,
++                      .ngpio            = 32, /* 21 for PXA25x */
++              },
++      },
++#if defined(CONFIG_PXA27x) || defined(CONFIG_PXA3xx)
++      [3] = {
++              .regbase = GPIO3_BASE,
++              .chip = {
++                      .label            = "gpio-3",
++                      .direction_input  = pxa_gpio_direction_input,
++                      .direction_output = pxa_gpio_direction_output,
++                      .get              = pxa_gpio_get,
++                      .set              = pxa_gpio_set,
++                      .base             = 96,
++                      .ngpio            = 32,
++              },
++      },
++#endif
++};
++
++void __init pxa_init_gpio(int gpio_nr)
++{
++      int i;
++
++      /* add a GPIO chip for each register bank.
++       * the last PXA25x register only contains 21 GPIOs
++       */
++      for (i = 0; i < gpio_nr; i += 32) {
++              if (i+32 > gpio_nr)
++                      pxa_gpio_chip[i/32].chip.ngpio = gpio_nr - i;
++              gpiochip_add(&pxa_gpio_chip[i/32].chip);
++      }
++}
+diff --git a/arch/arm/mach-pxa/irq.c b/arch/arm/mach-pxa/irq.c
+index 07acb45..d0965ef 100644
+--- a/arch/arm/mach-pxa/irq.c
++++ b/arch/arm/mach-pxa/irq.c
+@@ -310,6 +310,8 @@ void __init pxa_init_irq_gpio(int gpio_nr)
+       /* Install handler for GPIO>=2 edge detect interrupts */
+       set_irq_chip(IRQ_GPIO_2_x, &pxa_internal_chip_low);
+       set_irq_chained_handler(IRQ_GPIO_2_x, pxa_gpio_demux_handler);
++
++      pxa_init_gpio(gpio_nr);
+ }
+ void __init pxa_init_irq_set_wake(int (*set_wake)(unsigned int, unsigned int))
+diff --git a/include/asm-arm/arch-pxa/gpio.h b/include/asm-arm/arch-pxa/gpio.h
+index 9dbc2dc..bdbf5f9 100644
+--- a/include/asm-arm/arch-pxa/gpio.h
++++ b/include/asm-arm/arch-pxa/gpio.h
+@@ -28,43 +28,35 @@
+ #include <asm/irq.h>
+ #include <asm/hardware.h>
+-static inline int gpio_request(unsigned gpio, const char *label)
+-{
+-      return 0;
+-}
++#include <asm-generic/gpio.h>
+-static inline void gpio_free(unsigned gpio)
+-{
+-      return;
+-}
+-extern int gpio_direction_input(unsigned gpio);
+-extern int gpio_direction_output(unsigned gpio, int value);
++/* NOTE: some PXAs have fewer on-chip GPIOs (like PXA255, with 85).
++ * Those cases currently cause holes in the GPIO number space.
++ */
++#define NR_BUILTIN_GPIO 128
+-static inline int __gpio_get_value(unsigned gpio)
++static inline int gpio_get_value(unsigned gpio)
+ {
+-      return GPLR(gpio) & GPIO_bit(gpio);
++      if (__builtin_constant_p(gpio) && (gpio < NR_BUILTIN_GPIO))
++              return GPLR(gpio) & GPIO_bit(gpio);
++      else
++              return __gpio_get_value(gpio);
+ }
+-#define gpio_get_value(gpio)                  \
+-      (__builtin_constant_p(gpio) ?           \
+-       __gpio_get_value(gpio) :               \
+-       pxa_gpio_get_value(gpio))
+-
+-static inline void __gpio_set_value(unsigned gpio, int value)
++static inline void gpio_set_value(unsigned gpio, int value)
+ {
+-      if (value)
+-              GPSR(gpio) = GPIO_bit(gpio);
+-      else
+-              GPCR(gpio) = GPIO_bit(gpio);
++      if (__builtin_constant_p(gpio) && (gpio < NR_BUILTIN_GPIO)) {
++              if (value)
++                      GPSR(gpio) = GPIO_bit(gpio);
++              else
++                      GPCR(gpio) = GPIO_bit(gpio);
++      } else {
++              __gpio_set_value(gpio, value);
++      }
+ }
+-#define gpio_set_value(gpio,value)            \
+-      (__builtin_constant_p(gpio) ?           \
+-       __gpio_set_value(gpio, value) :        \
+-       pxa_gpio_set_value(gpio, value))
+-
+-#include <asm-generic/gpio.h>                 /* cansleep wrappers */
++#define gpio_cansleep __gpio_cansleep
+ #define gpio_to_irq(gpio)     IRQ_GPIO(gpio)
+ #define irq_to_gpio(irq)      IRQ_TO_GPIO(irq)
+diff --git a/include/asm-arm/arch-pxa/pxa-regs.h b/include/asm-arm/arch-pxa/pxa-regs.h
+index 1bd398d..bd57417 100644
+--- a/include/asm-arm/arch-pxa/pxa-regs.h
++++ b/include/asm-arm/arch-pxa/pxa-regs.h
+@@ -1131,6 +1131,19 @@
+  * General Purpose I/O
+  */
++#define GPIO0_BASE    ((void __iomem *)io_p2v(0x40E00000))
++#define GPIO1_BASE    ((void __iomem *)io_p2v(0x40E00004))
++#define GPIO2_BASE    ((void __iomem *)io_p2v(0x40E00008))
++#define GPIO3_BASE    ((void __iomem *)io_p2v(0x40E00100))
++
++#define GPLR_OFFSET   0x00
++#define GPDR_OFFSET   0x0C
++#define GPSR_OFFSET   0x18
++#define GPCR_OFFSET   0x24
++#define GRER_OFFSET   0x30
++#define GFER_OFFSET   0x3C
++#define GEDR_OFFSET   0x48
++
+ #define GPLR0         __REG(0x40E00000)  /* GPIO Pin-Level Register GPIO<31:0> */
+ #define GPLR1         __REG(0x40E00004)  /* GPIO Pin-Level Register GPIO<63:32> */
+ #define GPLR2         __REG(0x40E00008)  /* GPIO Pin-Level Register GPIO<80:64> */
+-- 
+1.5.3.8
+
diff --git a/packages/kexecboot/linux-kexecboot-2.6.24/tosa/0024-Update-Documentation-gpio.txt-primarily-to-include.patch b/packages/kexecboot/linux-kexecboot-2.6.24/tosa/0024-Update-Documentation-gpio.txt-primarily-to-include.patch
new file mode 100644 (file)
index 0000000..e460379
--- /dev/null
@@ -0,0 +1,238 @@
+From 7ba82399f2d2df6114ad552999f2e1b9a19cb47a Mon Sep 17 00:00:00 2001
+From: David Brownell <dbrownell@users.sourceforge.net>
+Date: Sat, 19 Jan 2008 19:41:18 +0300
+Subject: [PATCH 24/64] Update Documentation/gpio.txt, primarily to include the new "gpiolib"
+ infrastructure.
+
+Signed-off-by: David Brownell <dbrownell@users.sourceforge.net>
+Cc: Jean Delvare <khali@linux-fr.org>
+Cc: Eric Miao <eric.miao@marvell.com>
+Cc: Sam Ravnborg <sam@ravnborg.org>
+Cc: Haavard Skinnemoen <hskinnemoen@atmel.com>
+Cc: Philipp Zabel <philipp.zabel@gmail.com>
+Cc: Russell King <rmk@arm.linux.org.uk>
+Cc: Ben Gardner <bgardner@wabtec.com>
+Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
+---
+ Documentation/gpio.txt |  133 +++++++++++++++++++++++++++++++++++++++++++----
+ 1 files changed, 121 insertions(+), 12 deletions(-)
+
+diff --git a/Documentation/gpio.txt b/Documentation/gpio.txt
+index 6bc2ba2..8da724e 100644
+--- a/Documentation/gpio.txt
++++ b/Documentation/gpio.txt
+@@ -32,7 +32,7 @@ The exact capabilities of GPIOs vary between systems.  Common options:
+   - Input values are likewise readable (1, 0).  Some chips support readback
+     of pins configured as "output", which is very useful in such "wire-OR"
+     cases (to support bidirectional signaling).  GPIO controllers may have
+-    input de-glitch logic, sometimes with software controls.
++    input de-glitch/debounce logic, sometimes with software controls.
+   - Inputs can often be used as IRQ signals, often edge triggered but
+     sometimes level triggered.  Such IRQs may be configurable as system
+@@ -60,10 +60,13 @@ used on a board that's wired differently.  Only least-common-denominator
+ functionality can be very portable.  Other features are platform-specific,
+ and that can be critical for glue logic.
+-Plus, this doesn't define an implementation framework, just an interface.
++Plus, this doesn't require any implementation framework, just an interface.
+ One platform might implement it as simple inline functions accessing chip
+ registers; another might implement it by delegating through abstractions
+-used for several very different kinds of GPIO controller.
++used for several very different kinds of GPIO controller.  (There is some
++optional code supporting such an implementation strategy, described later
++in this document, but drivers acting as clients to the GPIO interface must
++not care how it's implemented.)
+ That said, if the convention is supported on their platform, drivers should
+ use it when possible.  Platforms should declare GENERIC_GPIO support in
+@@ -121,6 +124,11 @@ before tasking is enabled, as part of early board setup.
+ For output GPIOs, the value provided becomes the initial output value.
+ This helps avoid signal glitching during system startup.
++For compatibility with legacy interfaces to GPIOs, setting the direction
++of a GPIO implicitly requests that GPIO (see below) if it has not been
++requested already.  That compatibility may be removed in the future;
++explicitly requesting GPIOs is strongly preferred.
++
+ Setting the direction can fail if the GPIO number is invalid, or when
+ that particular GPIO can't be used in that mode.  It's generally a bad
+ idea to rely on boot firmware to have set the direction correctly, since
+@@ -133,6 +141,7 @@ Spinlock-Safe GPIO access
+ -------------------------
+ Most GPIO controllers can be accessed with memory read/write instructions.
+ That doesn't need to sleep, and can safely be done from inside IRQ handlers.
++(That includes hardirq contexts on RT kernels.)
+ Use these calls to access such GPIOs:
+@@ -145,7 +154,7 @@ Use these calls to access such GPIOs:
+ The values are boolean, zero for low, nonzero for high.  When reading the
+ value of an output pin, the value returned should be what's seen on the
+ pin ... that won't always match the specified output value, because of
+-issues including wire-OR and output latencies.
++issues including open-drain signaling and output latencies.
+ The get/set calls have no error returns because "invalid GPIO" should have
+ been reported earlier from gpio_direction_*().  However, note that not all
+@@ -170,7 +179,8 @@ get to the head of a queue to transmit a command and get its response.
+ This requires sleeping, which can't be done from inside IRQ handlers.
+ Platforms that support this type of GPIO distinguish them from other GPIOs
+-by returning nonzero from this call:
++by returning nonzero from this call (which requires a valid GPIO number,
++either explicitly or implicitly requested):
+       int gpio_cansleep(unsigned gpio);
+@@ -209,8 +219,11 @@ before tasking is enabled, as part of early board setup.
+ These calls serve two basic purposes.  One is marking the signals which
+ are actually in use as GPIOs, for better diagnostics; systems may have
+ several hundred potential GPIOs, but often only a dozen are used on any
+-given board.  Another is to catch conflicts between drivers, reporting
+-errors when drivers wrongly think they have exclusive use of that signal.
++given board.  Another is to catch conflicts, identifying errors when
++(a) two or more drivers wrongly think they have exclusive use of that
++signal, or (b) something wrongly believes it's safe to remove drivers
++needed to manage a signal that's in active use.  That is, requesting a
++GPIO can serve as a kind of lock.
+ These two calls are optional because not not all current Linux platforms
+ offer such functionality in their GPIO support; a valid implementation
+@@ -223,6 +236,9 @@ Note that requesting a GPIO does NOT cause it to be configured in any
+ way; it just marks that GPIO as in use.  Separate code must handle any
+ pin setup (e.g. controlling which pin the GPIO uses, pullup/pulldown).
++Also note that it's your responsibility to have stopped using a GPIO
++before you free it.
++
+ GPIOs mapped to IRQs
+ --------------------
+@@ -238,7 +254,7 @@ map between them using calls like:
+ Those return either the corresponding number in the other namespace, or
+ else a negative errno code if the mapping can't be done.  (For example,
+-some GPIOs can't used as IRQs.)  It is an unchecked error to use a GPIO
++some GPIOs can't be used as IRQs.)  It is an unchecked error to use a GPIO
+ number that wasn't set up as an input using gpio_direction_input(), or
+ to use an IRQ number that didn't originally come from gpio_to_irq().
+@@ -299,17 +315,110 @@ Related to multiplexing is configuration and enabling of the pullups or
+ pulldowns integrated on some platforms.  Not all platforms support them,
+ or support them in the same way; and any given board might use external
+ pullups (or pulldowns) so that the on-chip ones should not be used.
++(When a circuit needs 5 kOhm, on-chip 100 kOhm resistors won't do.)
+ There are other system-specific mechanisms that are not specified here,
+ like the aforementioned options for input de-glitching and wire-OR output.
+ Hardware may support reading or writing GPIOs in gangs, but that's usually
+ configuration dependent:  for GPIOs sharing the same bank.  (GPIOs are
+ commonly grouped in banks of 16 or 32, with a given SOC having several such
+-banks.)  Some systems can trigger IRQs from output GPIOs.  Code relying on
+-such mechanisms will necessarily be nonportable.
++banks.)  Some systems can trigger IRQs from output GPIOs, or read values
++from pins not managed as GPIOs.  Code relying on such mechanisms will
++necessarily be nonportable.
+-Dynamic definition of GPIOs is not currently supported; for example, as
++Dynamic definition of GPIOs is not currently standard; for example, as
+ a side effect of configuring an add-on board with some GPIO expanders.
+ These calls are purely for kernel space, but a userspace API could be built
+-on top of it.
++on top of them.
++
++
++GPIO implementor's framework (OPTIONAL)
++=======================================
++As noted earlier, there is an optional implementation framework making it
++easier for platforms to support different kinds of GPIO controller using
++the same programming interface.
++
++As a debugging aid, if debugfs is available a /sys/kernel/debug/gpio file
++will be found there.  That will list all the controllers registered through
++this framework, and the state of the GPIOs currently in use.
++
++
++Controller Drivers: gpio_chip
++-----------------------------
++In this framework each GPIO controller is packaged as a "struct gpio_chip"
++with information common to each controller of that type:
++
++ - methods to establish GPIO direction
++ - methods used to access GPIO values
++ - flag saying whether calls to its methods may sleep
++ - optional debugfs dump method (showing extra state like pullup config)
++ - label for diagnostics
++
++There is also per-instance data, which may come from device.platform_data:
++the number of its first GPIO, and how many GPIOs it exposes.
++
++The code implementing a gpio_chip should support multiple instances of the
++controller, possibly using the driver model.  That code will configure each
++gpio_chip and issue gpiochip_add().  Removing a GPIO controller should be
++rare; use gpiochip_remove() when it is unavoidable.
++
++Most often a gpio_chip is part of an instance-specific structure with state
++not exposed by the GPIO interfaces, such as addressing, power management,
++and more.  Chips such as codecs will have complex non-GPIO state,
++
++Any debugfs dump method should normally ignore signals which haven't been
++requested as GPIOs.  They can use gpiochip_is_requested(), which returns
++either NULL or the label associated with that GPIO when it was requested.
++
++
++Platform Support
++----------------
++To support this framework, a platform's Kconfig will "select HAVE_GPIO_LIB"
++and arrange that its <asm/gpio.h> includes <asm-generic/gpio.h> and defines
++three functions: gpio_get_value(), gpio_set_value(), and gpio_cansleep().
++They may also want to provide a custom value for ARCH_NR_GPIOS.
++
++Trivial implementations of those functions can directly use framework
++code, which always dispatches through the gpio_chip:
++
++  #define gpio_get_value      __gpio_get_value
++  #define gpio_set_value      __gpio_set_value
++  #define gpio_cansleep               __gpio_cansleep
++
++Fancier implementations could instead define those as inline functions with
++logic optimizing access to specific SOC-based GPIOs.  For example, if the
++referenced GPIO is the constant "12", getting or setting its value could
++cost as little as two or three instructions, never sleeping.  When such an
++optimization is not possible those calls must delegate to the framework
++code, costing at least a few dozen instructions.  For bitbanged I/O, such
++instruction savings can be significant.
++
++For SOCs, platform-specific code defines and registers gpio_chip instances
++for each bank of on-chip GPIOs.  Those GPIOs should be numbered/labeled to
++match chip vendor documentation, and directly match board schematics.  They
++may well start at zero and go up to a platform-specific limit.  Such GPIOs
++are normally integrated into platform initialization to make them always be
++available, from arch_initcall() or earlier; they can often serve as IRQs.
++
++
++Board Support
++-------------
++For external GPIO controllers -- such as I2C or SPI expanders, ASICs, multi
++function devices, FPGAs or CPLDs -- most often board-specific code handles
++registering controller devices and ensures that their drivers know what GPIO
++numbers to use with gpiochip_add().  Their numbers often start right after
++platform-specific GPIOs.
++
++For example, board setup code could create structures identifying the range
++of GPIOs that chip will expose, and passes them to each GPIO expander chip
++using platform_data.  Then the chip driver's probe() routine could pass that
++data to gpiochip_add().
++
++Initialization order can be important.  For example, when a device relies on
++an I2C-based GPIO, its probe() routine should only be called after that GPIO
++becomes available.  That may mean the device should not be registered until
++calls for that GPIO can work.  One way to address such dependencies is for
++such gpio_chip controllers to provide setup() and teardown() callbacks to
++board specific code; those board specific callbacks would register devices
++once all the necessary resources are available.
+-- 
+1.5.3.8
+
diff --git a/packages/kexecboot/linux-kexecboot-2.6.24/tosa/0025-Signed-off-by-Dmitry-Baryshkov-dbaryshkov-gmail.co.patch b/packages/kexecboot/linux-kexecboot-2.6.24/tosa/0025-Signed-off-by-Dmitry-Baryshkov-dbaryshkov-gmail.co.patch
new file mode 100644 (file)
index 0000000..84d0fd3
--- /dev/null
@@ -0,0 +1,434 @@
+From 39717c1328f6aa13330eded0e0e268993cfd1eea Mon Sep 17 00:00:00 2001
+From: Dmitry Baryshkov <dbaryshkov@gmail.com>
+Date: Tue, 12 Feb 2008 10:39:53 +0300
+Subject: [PATCH 25/64] Signed-off-by: Dmitry Baryshkov <dbaryshkov@gmail.com>
+
+---
+ arch/arm/mach-pxa/Makefile  |    2 +-
+ arch/arm/mach-pxa/devices.c |  401 +++++++++++++++++++++++++++++++++++++++++++
+ 2 files changed, 402 insertions(+), 1 deletions(-)
+ create mode 100644 arch/arm/mach-pxa/devices.c
+
+diff --git a/arch/arm/mach-pxa/Makefile b/arch/arm/mach-pxa/Makefile
+index 5cb0216..f276d24 100644
+--- a/arch/arm/mach-pxa/Makefile
++++ b/arch/arm/mach-pxa/Makefile
+@@ -4,7 +4,7 @@
+ # Common support (must be linked before board specific support)
+ obj-y                         += clock.o generic.o irq.o dma.o \
+-                                 time.o gpio.o
++                                 time.o gpio.o devices.o
+ obj-$(CONFIG_PXA25x)          += pxa25x.o
+ obj-$(CONFIG_PXA27x)          += pxa27x.o
+ obj-$(CONFIG_PXA3xx)          += pxa3xx.o mfp.o
+diff --git a/arch/arm/mach-pxa/devices.c b/arch/arm/mach-pxa/devices.c
+new file mode 100644
+index 0000000..928131a
+--- /dev/null
++++ b/arch/arm/mach-pxa/devices.c
+@@ -0,0 +1,401 @@
++#include <linux/module.h>
++#include <linux/kernel.h>
++#include <linux/init.h>
++#include <linux/platform_device.h>
++#include <linux/dma-mapping.h>
++
++#include <asm/arch/gpio.h>
++#include <asm/arch/udc.h>
++#include <asm/arch/pxafb.h>
++#include <asm/arch/mmc.h>
++#include <asm/arch/irda.h>
++#include <asm/arch/i2c.h>
++#include <asm/arch/ohci.h>
++
++#include "devices.h"
++
++#ifdef CONFIG_PXA25x
++
++static u64 pxa25x_ssp_dma_mask = DMA_BIT_MASK(32);
++
++static struct resource pxa25x_resource_ssp[] = {
++      [0] = {
++              .start  = 0x41000000,
++              .end    = 0x4100001f,
++              .flags  = IORESOURCE_MEM,
++      },
++      [1] = {
++              .start  = IRQ_SSP,
++              .end    = IRQ_SSP,
++              .flags  = IORESOURCE_IRQ,
++      },
++      [2] = {
++              /* DRCMR for RX */
++              .start  = 13,
++              .end    = 13,
++              .flags  = IORESOURCE_DMA,
++      },
++      [3] = {
++              /* DRCMR for TX */
++              .start  = 14,
++              .end    = 14,
++              .flags  = IORESOURCE_DMA,
++      },
++};
++
++struct platform_device pxa25x_device_ssp = {
++      .name           = "pxa25x-ssp",
++      .id             = 0,
++      .dev            = {
++              .dma_mask = &pxa25x_ssp_dma_mask,
++              .coherent_dma_mask = DMA_BIT_MASK(32),
++      },
++      .resource       = pxa25x_resource_ssp,
++      .num_resources  = ARRAY_SIZE(pxa25x_resource_ssp),
++};
++
++static u64 pxa25x_nssp_dma_mask = DMA_BIT_MASK(32);
++
++static struct resource pxa25x_resource_nssp[] = {
++      [0] = {
++              .start  = 0x41400000,
++              .end    = 0x4140002f,
++              .flags  = IORESOURCE_MEM,
++      },
++      [1] = {
++              .start  = IRQ_NSSP,
++              .end    = IRQ_NSSP,
++              .flags  = IORESOURCE_IRQ,
++      },
++      [2] = {
++              /* DRCMR for RX */
++              .start  = 15,
++              .end    = 15,
++              .flags  = IORESOURCE_DMA,
++      },
++      [3] = {
++              /* DRCMR for TX */
++              .start  = 16,
++              .end    = 16,
++              .flags  = IORESOURCE_DMA,
++      },
++};
++
++struct platform_device pxa25x_device_nssp = {
++      .name           = "pxa25x-nssp",
++      .id             = 1,
++      .dev            = {
++              .dma_mask = &pxa25x_nssp_dma_mask,
++              .coherent_dma_mask = DMA_BIT_MASK(32),
++      },
++      .resource       = pxa25x_resource_nssp,
++      .num_resources  = ARRAY_SIZE(pxa25x_resource_nssp),
++};
++
++static u64 pxa25x_assp_dma_mask = DMA_BIT_MASK(32);
++
++static struct resource pxa25x_resource_assp[] = {
++      [0] = {
++              .start  = 0x41500000,
++              .end    = 0x4150002f,
++              .flags  = IORESOURCE_MEM,
++      },
++      [1] = {
++              .start  = IRQ_ASSP,
++              .end    = IRQ_ASSP,
++              .flags  = IORESOURCE_IRQ,
++      },
++      [2] = {
++              /* DRCMR for RX */
++              .start  = 23,
++              .end    = 23,
++              .flags  = IORESOURCE_DMA,
++      },
++      [3] = {
++              /* DRCMR for TX */
++              .start  = 24,
++              .end    = 24,
++              .flags  = IORESOURCE_DMA,
++      },
++};
++
++struct platform_device pxa25x_device_assp = {
++      /* ASSP is basically equivalent to NSSP */
++      .name           = "pxa25x-nssp",
++      .id             = 2,
++      .dev            = {
++              .dma_mask = &pxa25x_assp_dma_mask,
++              .coherent_dma_mask = DMA_BIT_MASK(32),
++      },
++      .resource       = pxa25x_resource_assp,
++      .num_resources  = ARRAY_SIZE(pxa25x_resource_assp),
++};
++#endif /* CONFIG_PXA25x */
++
++#if defined(CONFIG_PXA27x) || defined(CONFIG_PXA3xx)
++
++static u64 pxa27x_ohci_dma_mask = DMA_BIT_MASK(32);
++
++static struct resource pxa27x_resource_ohci[] = {
++      [0] = {
++              .start  = 0x4C000000,
++              .end    = 0x4C00ff6f,
++              .flags  = IORESOURCE_MEM,
++      },
++      [1] = {
++              .start  = IRQ_USBH1,
++              .end    = IRQ_USBH1,
++              .flags  = IORESOURCE_IRQ,
++      },
++};
++
++struct platform_device pxa27x_device_ohci = {
++      .name           = "pxa27x-ohci",
++      .id             = -1,
++      .dev            = {
++              .dma_mask = &pxa27x_ohci_dma_mask,
++              .coherent_dma_mask = DMA_BIT_MASK(32),
++      },
++      .num_resources  = ARRAY_SIZE(pxa27x_resource_ohci),
++      .resource       = pxa27x_resource_ohci,
++};
++
++void __init pxa_set_ohci_info(struct pxaohci_platform_data *info)
++{
++      pxa_register_device(&pxa27x_device_ohci, info);
++}
++
++static u64 pxa27x_ssp1_dma_mask = DMA_BIT_MASK(32);
++
++static struct resource pxa27x_resource_ssp1[] = {
++      [0] = {
++              .start  = 0x41000000,
++              .end    = 0x4100003f,
++              .flags  = IORESOURCE_MEM,
++      },
++      [1] = {
++              .start  = IRQ_SSP,
++              .end    = IRQ_SSP,
++              .flags  = IORESOURCE_IRQ,
++      },
++      [2] = {
++              /* DRCMR for RX */
++              .start  = 13,
++              .end    = 13,
++              .flags  = IORESOURCE_DMA,
++      },
++      [3] = {
++              /* DRCMR for TX */
++              .start  = 14,
++              .end    = 14,
++              .flags  = IORESOURCE_DMA,
++      },
++};
++
++struct platform_device pxa27x_device_ssp1 = {
++      .name           = "pxa27x-ssp",
++      .id             = 0,
++      .dev            = {
++              .dma_mask = &pxa27x_ssp1_dma_mask,
++              .coherent_dma_mask = DMA_BIT_MASK(32),
++      },
++      .resource       = pxa27x_resource_ssp1,
++      .num_resources  = ARRAY_SIZE(pxa27x_resource_ssp1),
++};
++
++static u64 pxa27x_ssp2_dma_mask = DMA_BIT_MASK(32);
++
++static struct resource pxa27x_resource_ssp2[] = {
++      [0] = {
++              .start  = 0x41700000,
++              .end    = 0x4170003f,
++              .flags  = IORESOURCE_MEM,
++      },
++      [1] = {
++              .start  = IRQ_SSP2,
++              .end    = IRQ_SSP2,
++              .flags  = IORESOURCE_IRQ,
++      },
++      [2] = {
++              /* DRCMR for RX */
++              .start  = 15,
++              .end    = 15,
++              .flags  = IORESOURCE_DMA,
++      },
++      [3] = {
++              /* DRCMR for TX */
++              .start  = 16,
++              .end    = 16,
++              .flags  = IORESOURCE_DMA,
++      },
++};
++
++struct platform_device pxa27x_device_ssp2 = {
++      .name           = "pxa27x-ssp",
++      .id             = 1,
++      .dev            = {
++              .dma_mask = &pxa27x_ssp2_dma_mask,
++              .coherent_dma_mask = DMA_BIT_MASK(32),
++      },
++      .resource       = pxa27x_resource_ssp2,
++      .num_resources  = ARRAY_SIZE(pxa27x_resource_ssp2),
++};
++
++static u64 pxa27x_ssp3_dma_mask = DMA_BIT_MASK(32);
++
++static struct resource pxa27x_resource_ssp3[] = {
++      [0] = {
++              .start  = 0x41900000,
++              .end    = 0x4190003f,
++              .flags  = IORESOURCE_MEM,
++      },
++      [1] = {
++              .start  = IRQ_SSP3,
++              .end    = IRQ_SSP3,
++              .flags  = IORESOURCE_IRQ,
++      },
++      [2] = {
++              /* DRCMR for RX */
++              .start  = 66,
++              .end    = 66,
++              .flags  = IORESOURCE_DMA,
++      },
++      [3] = {
++              /* DRCMR for TX */
++              .start  = 67,
++              .end    = 67,
++              .flags  = IORESOURCE_DMA,
++      },
++};
++
++struct platform_device pxa27x_device_ssp3 = {
++      .name           = "pxa27x-ssp",
++      .id             = 2,
++      .dev            = {
++              .dma_mask = &pxa27x_ssp3_dma_mask,
++              .coherent_dma_mask = DMA_BIT_MASK(32),
++      },
++      .resource       = pxa27x_resource_ssp3,
++      .num_resources  = ARRAY_SIZE(pxa27x_resource_ssp3),
++};
++#endif /* CONFIG_PXA27x || CONFIG_PXA3xx */
++
++#ifdef CONFIG_PXA3xx
++static u64 pxa3xx_ssp4_dma_mask = DMA_BIT_MASK(32);
++
++static struct resource pxa3xx_resource_ssp4[] = {
++      [0] = {
++              .start  = 0x41a00000,
++              .end    = 0x41a0003f,
++              .flags  = IORESOURCE_MEM,
++      },
++      [1] = {
++              .start  = IRQ_SSP4,
++              .end    = IRQ_SSP4,
++              .flags  = IORESOURCE_IRQ,
++      },
++      [2] = {
++              /* DRCMR for RX */
++              .start  = 2,
++              .end    = 2,
++              .flags  = IORESOURCE_DMA,
++      },
++      [3] = {
++              /* DRCMR for TX */
++              .start  = 3,
++              .end    = 3,
++              .flags  = IORESOURCE_DMA,
++      },
++};
++
++struct platform_device pxa3xx_device_ssp4 = {
++      /* PXA3xx SSP is basically equivalent to PXA27x */
++      .name           = "pxa27x-ssp",
++      .id             = 3,
++      .dev            = {
++              .dma_mask = &pxa3xx_ssp4_dma_mask,
++              .coherent_dma_mask = DMA_BIT_MASK(32),
++      },
++      .resource       = pxa3xx_resource_ssp4,
++      .num_resources  = ARRAY_SIZE(pxa3xx_resource_ssp4),
++};
++
++static struct resource pxa3xx_resources_mci2[] = {
++      [0] = {
++              .start  = 0x42000000,
++              .end    = 0x42000fff,
++              .flags  = IORESOURCE_MEM,
++      },
++      [1] = {
++              .start  = IRQ_MMC2,
++              .end    = IRQ_MMC2,
++              .flags  = IORESOURCE_IRQ,
++      },
++      [2] = {
++              .start  = 93,
++              .end    = 93,
++              .flags  = IORESOURCE_DMA,
++      },
++      [3] = {
++              .start  = 94,
++              .end    = 94,
++              .flags  = IORESOURCE_DMA,
++      },
++};
++
++struct platform_device pxa3xx_device_mci2 = {
++      .name           = "pxa2xx-mci",
++      .id             = 1,
++      .dev            = {
++              .dma_mask = &pxamci_dmamask,
++              .coherent_dma_mask =    0xffffffff,
++      },
++      .num_resources  = ARRAY_SIZE(pxa3xx_resources_mci2),
++      .resource       = pxa3xx_resources_mci2,
++};
++
++void __init pxa3xx_set_mci2_info(struct pxamci_platform_data *info)
++{
++      pxa_register_device(&pxa3xx_device_mci2, info);
++}
++
++static struct resource pxa3xx_resources_mci3[] = {
++      [0] = {
++              .start  = 0x42500000,
++              .end    = 0x42500fff,
++              .flags  = IORESOURCE_MEM,
++      },
++      [1] = {
++              .start  = IRQ_MMC3,
++              .end    = IRQ_MMC3,
++              .flags  = IORESOURCE_IRQ,
++      },
++      [2] = {
++              .start  = 100,
++              .end    = 100,
++              .flags  = IORESOURCE_DMA,
++      },
++      [3] = {
++              .start  = 101,
++              .end    = 101,
++              .flags  = IORESOURCE_DMA,
++      },
++};
++
++struct platform_device pxa3xx_device_mci3 = {
++      .name           = "pxa2xx-mci",
++      .id             = 2,
++      .dev            = {
++              .dma_mask = &pxamci_dmamask,
++              .coherent_dma_mask = 0xffffffff,
++      },
++      .num_resources  = ARRAY_SIZE(pxa3xx_resources_mci3),
++      .resource       = pxa3xx_resources_mci3,
++};
++
++void __init pxa3xx_set_mci3_info(struct pxamci_platform_data *info)
++{
++      pxa_register_device(&pxa3xx_device_mci3, info);
++}
++
++#endif /* CONFIG_PXA3xx */
+-- 
+1.5.3.8
+
diff --git a/packages/kexecboot/linux-kexecboot-2.6.24/tosa/0026-I-don-t-think-we-should-check-for-IRQs-when-determin.patch b/packages/kexecboot/linux-kexecboot-2.6.24/tosa/0026-I-don-t-think-we-should-check-for-IRQs-when-determin.patch
new file mode 100644 (file)
index 0000000..e1323e4
--- /dev/null
@@ -0,0 +1,134 @@
+From cbe46408b666983284e8be290950d526dbc0f0a4 Mon Sep 17 00:00:00 2001
+From: Dmitry Baryshkov <dbaryshkov@gmail.com>
+Date: Wed, 9 Jan 2008 02:08:16 +0300
+Subject: [PATCH 26/64] I don't think we should check for IRQs when determining which one
+ of power supplies to register. Better use is_{ac,usb}_online
+ callbacks, this will not produce an obstacle to implement polling --
+ when irqs aren't mandatory. I'll send my two pending patches to show
+ the idea.
+
+For this particular issue, I think something like that should work.
+If it works for you, I'll commit that version, preserving your
+authorship, of course.
+---
+ drivers/power/pda_power.c |   80 ++++++++++++++++++++++++--------------------
+ 1 files changed, 44 insertions(+), 36 deletions(-)
+
+diff --git a/drivers/power/pda_power.c b/drivers/power/pda_power.c
+index c058f28..d98622f 100644
+--- a/drivers/power/pda_power.c
++++ b/drivers/power/pda_power.c
+@@ -168,66 +168,74 @@ static int pda_power_probe(struct platform_device *pdev)
+               pda_power_supplies[1].num_supplicants = pdata->num_supplicants;
+       }
+-      ret = power_supply_register(&pdev->dev, &pda_power_supplies[0]);
+-      if (ret) {
+-              dev_err(dev, "failed to register %s power supply\n",
+-                      pda_power_supplies[0].name);
+-              goto supply0_failed;
+-      }
++      if (pdata->is_ac_online) {
++              ret = power_supply_register(&pdev->dev, &pda_power_supplies[0]);
++              if (ret) {
++                      dev_err(dev, "failed to register %s power supply\n",
++                              pda_power_supplies[0].name);
++                      goto ac_supply_failed;
++              }
+-      ret = power_supply_register(&pdev->dev, &pda_power_supplies[1]);
+-      if (ret) {
+-              dev_err(dev, "failed to register %s power supply\n",
+-                      pda_power_supplies[1].name);
+-              goto supply1_failed;
++              if (ac_irq) {
++                      ret = request_irq(ac_irq->start, power_changed_isr,
++                                        get_irq_flags(ac_irq), ac_irq->name,
++                                        &pda_power_supplies[0]);
++                      if (ret) {
++                              dev_err(dev, "request ac irq failed\n");
++                              goto ac_irq_failed;
++                      }
++              }
+       }
+-      if (ac_irq) {
+-              ret = request_irq(ac_irq->start, power_changed_isr,
+-                                get_irq_flags(ac_irq), ac_irq->name,
+-                                &pda_power_supplies[0]);
++      if (pdata->is_usb_online) {
++              ret = power_supply_register(&pdev->dev, &pda_power_supplies[1]);
+               if (ret) {
+-                      dev_err(dev, "request ac irq failed\n");
+-                      goto ac_irq_failed;
++                      dev_err(dev, "failed to register %s power supply\n",
++                              pda_power_supplies[1].name);
++                      goto usb_supply_failed;
+               }
+-      }
+-      if (usb_irq) {
+-              ret = request_irq(usb_irq->start, power_changed_isr,
+-                                get_irq_flags(usb_irq), usb_irq->name,
+-                                &pda_power_supplies[1]);
+-              if (ret) {
+-                      dev_err(dev, "request usb irq failed\n");
+-                      goto usb_irq_failed;
++              if (usb_irq) {
++                      ret = request_irq(usb_irq->start, power_changed_isr,
++                                        get_irq_flags(usb_irq),
++                                        usb_irq->name,
++                                        &pda_power_supplies[1]);
++                      if (ret) {
++                              dev_err(dev, "request usb irq failed\n");
++                              goto usb_irq_failed;
++                      }
+               }
+       }
+-      goto success;
++      return 0;
+ usb_irq_failed:
+-      if (ac_irq)
++      if (pdata->is_usb_online)
++              power_supply_unregister(&pda_power_supplies[1]);
++usb_supply_failed:
++      if (pdata->is_ac_online && ac_irq)
+               free_irq(ac_irq->start, &pda_power_supplies[0]);
+ ac_irq_failed:
+-      power_supply_unregister(&pda_power_supplies[1]);
+-supply1_failed:
+-      power_supply_unregister(&pda_power_supplies[0]);
+-supply0_failed:
++      if (pdata->is_ac_online)
++              power_supply_unregister(&pda_power_supplies[0]);
++ac_supply_failed:
+ noirqs:
+ wrongid:
+-success:
+       return ret;
+ }
+ static int pda_power_remove(struct platform_device *pdev)
+ {
+-      if (usb_irq)
++      if (pdata->is_usb_online && usb_irq)
+               free_irq(usb_irq->start, &pda_power_supplies[1]);
+-      if (ac_irq)
++      if (pdata->is_ac_online && ac_irq)
+               free_irq(ac_irq->start, &pda_power_supplies[0]);
+       del_timer_sync(&charger_timer);
+       del_timer_sync(&supply_timer);
+-      power_supply_unregister(&pda_power_supplies[1]);
+-      power_supply_unregister(&pda_power_supplies[0]);
++      if (pdata->is_usb_online)
++              power_supply_unregister(&pda_power_supplies[1]);
++      if (pdata->is_ac_online)
++              power_supply_unregister(&pda_power_supplies[0]);
+       return 0;
+ }
+-- 
+1.5.3.8
+
diff --git a/packages/kexecboot/linux-kexecboot-2.6.24/tosa/0027-Add-LiMn-one-of-the-most-common-for-small-non-recha.patch b/packages/kexecboot/linux-kexecboot-2.6.24/tosa/0027-Add-LiMn-one-of-the-most-common-for-small-non-recha.patch
new file mode 100644 (file)
index 0000000..240d2d0
--- /dev/null
@@ -0,0 +1,59 @@
+From e5e9808fd5ed9cb54dd9da9fb91b32c4f7e9da52 Mon Sep 17 00:00:00 2001
+From: Dmitry Baryshkov <dbaryshkov@gmail.com>
+Date: Wed, 9 Jan 2008 02:08:17 +0300
+Subject: [PATCH 27/64] Add LiMn (one of the most common for small non-rechargable batteries)i
+ battery technology and voltage_min/_max properties support.
+
+Signed-off-by: Dmitry Baryshkov <dbaryshkov@gmail.com>
+---
+ drivers/power/power_supply_sysfs.c |    5 ++++-
+ include/linux/power_supply.h       |    3 +++
+ 2 files changed, 7 insertions(+), 1 deletions(-)
+
+diff --git a/drivers/power/power_supply_sysfs.c b/drivers/power/power_supply_sysfs.c
+index 249f61b..45d2f95 100644
+--- a/drivers/power/power_supply_sysfs.c
++++ b/drivers/power/power_supply_sysfs.c
+@@ -46,7 +46,8 @@ static ssize_t power_supply_show_property(struct device *dev,
+               "Unspecified failure"
+       };
+       static char *technology_text[] = {
+-              "Unknown", "NiMH", "Li-ion", "Li-poly", "LiFe", "NiCd"
++              "Unknown", "NiMH", "Li-ion", "Li-poly", "LiFe", "NiCd",
++              "LiMn"
+       };
+       static char *capacity_level_text[] = {
+               "Unknown", "Critical", "Low", "Normal", "High", "Full"
+@@ -88,6 +89,8 @@ static struct device_attribute power_supply_attrs[] = {
+       POWER_SUPPLY_ATTR(present),
+       POWER_SUPPLY_ATTR(online),
+       POWER_SUPPLY_ATTR(technology),
++      POWER_SUPPLY_ATTR(voltage_max),
++      POWER_SUPPLY_ATTR(voltage_min),
+       POWER_SUPPLY_ATTR(voltage_max_design),
+       POWER_SUPPLY_ATTR(voltage_min_design),
+       POWER_SUPPLY_ATTR(voltage_now),
+diff --git a/include/linux/power_supply.h b/include/linux/power_supply.h
+index 606c095..cdbc5b8 100644
+--- a/include/linux/power_supply.h
++++ b/include/linux/power_supply.h
+@@ -54,6 +54,7 @@ enum {
+       POWER_SUPPLY_TECHNOLOGY_LIPO,
+       POWER_SUPPLY_TECHNOLOGY_LiFe,
+       POWER_SUPPLY_TECHNOLOGY_NiCd,
++      POWER_SUPPLY_TECHNOLOGY_LiMn,
+ };
+ enum {
+@@ -72,6 +73,8 @@ enum power_supply_property {
+       POWER_SUPPLY_PROP_PRESENT,
+       POWER_SUPPLY_PROP_ONLINE,
+       POWER_SUPPLY_PROP_TECHNOLOGY,
++      POWER_SUPPLY_PROP_VOLTAGE_MAX,
++      POWER_SUPPLY_PROP_VOLTAGE_MIN,
+       POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN,
+       POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN,
+       POWER_SUPPLY_PROP_VOLTAGE_NOW,
+-- 
+1.5.3.8
+
diff --git a/packages/kexecboot/linux-kexecboot-2.6.24/tosa/0028-Add-suspend-resume-wakeup-support-for-pda_power.patch b/packages/kexecboot/linux-kexecboot-2.6.24/tosa/0028-Add-suspend-resume-wakeup-support-for-pda_power.patch
new file mode 100644 (file)
index 0000000..ac5df97
--- /dev/null
@@ -0,0 +1,72 @@
+From df0801d2cd6a7081700c79f437d1185cbe1960a7 Mon Sep 17 00:00:00 2001
+From: Dmitry Baryshkov <dbaryshkov@gmail.com>
+Date: Wed, 9 Jan 2008 02:08:18 +0300
+Subject: [PATCH 28/64] Add suspend/resume/wakeup support for pda_power.
+ Now with device_init_wakeup.
+
+Signed-off-by: Dmitry Baryshkov <dbaryshkov@gmail.com>
+---
+ drivers/power/pda_power.c |   34 ++++++++++++++++++++++++++++++++++
+ 1 files changed, 34 insertions(+), 0 deletions(-)
+
+diff --git a/drivers/power/pda_power.c b/drivers/power/pda_power.c
+index d98622f..28360e8 100644
+--- a/drivers/power/pda_power.c
++++ b/drivers/power/pda_power.c
+@@ -207,6 +207,8 @@ static int pda_power_probe(struct platform_device *pdev)
+               }
+       }
++      device_init_wakeup(&pdev->dev, 1);
++
+       return 0;
+ usb_irq_failed:
+@@ -239,12 +241,44 @@ static int pda_power_remove(struct platform_device *pdev)
+       return 0;
+ }
++#ifdef CONFIG_PM
++static int pda_power_suspend(struct platform_device *pdev, pm_message_t state)
++{
++      if (device_may_wakeup(&pdev->dev)) {
++              if (ac_irq)
++                      enable_irq_wake(ac_irq->start);
++              if (usb_irq)
++                      enable_irq_wake(usb_irq->start);
++      }
++
++      return 0;
++}
++
++static int pda_power_resume(struct platform_device *pdev)
++{
++      if (device_may_wakeup(&pdev->dev)) {
++              if (usb_irq)
++                      disable_irq_wake(usb_irq->start);
++              if (ac_irq)
++                      disable_irq_wake(ac_irq->start);
++      }
++
++      return 0;
++}
++#else
++#define pda_power_suspend     NULL
++#define pda_power_resume      NULL
++#endif
++
++
+ static struct platform_driver pda_power_pdrv = {
+       .driver = {
+               .name = "pda-power",
+       },
+       .probe = pda_power_probe,
+       .remove = pda_power_remove,
++      .suspend = pda_power_suspend,
++      .resume = pda_power_resume,
+ };
+ static int __init pda_power_init(void)
+-- 
+1.5.3.8
+
diff --git a/packages/kexecboot/linux-kexecboot-2.6.24/tosa/0029-Support-using-VOLTAGE_-properties-for-apm-calculati.patch b/packages/kexecboot/linux-kexecboot-2.6.24/tosa/0029-Support-using-VOLTAGE_-properties-for-apm-calculati.patch
new file mode 100644 (file)
index 0000000..7347fd5
--- /dev/null
@@ -0,0 +1,163 @@
+From 57d1450b4e5f27fa78c75895dc30213bde7191bc Mon Sep 17 00:00:00 2001
+From: Dmitry Baryshkov <dbaryshkov@gmail.com>
+Date: Wed, 9 Jan 2008 02:08:18 +0300
+Subject: [PATCH 29/64] Support using VOLTAGE_* properties for apm calculations. It's pretty
+ dummy, but useful for batteries for which we can only get voltages.
+
+---
+ drivers/power/apm_power.c |   63 ++++++++++++++++++++++++++++++++++++--------
+ 1 files changed, 51 insertions(+), 12 deletions(-)
+
+diff --git a/drivers/power/apm_power.c b/drivers/power/apm_power.c
+index bbf3ee1..526c96e 100644
+--- a/drivers/power/apm_power.c
++++ b/drivers/power/apm_power.c
+@@ -13,6 +13,12 @@
+ #include <linux/power_supply.h>
+ #include <linux/apm-emulation.h>
++typedef enum {
++      SOURCE_ENERGY,
++      SOURCE_CHARGE,
++      SOURCE_VOLTAGE,
++} apm_source;
++
+ #define PSY_PROP(psy, prop, val) psy->get_property(psy, \
+                        POWER_SUPPLY_PROP_##prop, val)
+@@ -87,7 +93,7 @@ static void find_main_battery(void)
+       }
+ }
+-static int calculate_time(int status, int using_charge)
++static int calculate_time(int status, apm_source source)
+ {
+       union power_supply_propval full;
+       union power_supply_propval empty;
+@@ -106,20 +112,34 @@ static int calculate_time(int status, int using_charge)
+                       return -1;
+       }
+-      if (using_charge) {
++      switch (source) {
++      case SOURCE_CHARGE:
+               full_prop = POWER_SUPPLY_PROP_CHARGE_FULL;
+               full_design_prop = POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN;
+               empty_prop = POWER_SUPPLY_PROP_CHARGE_EMPTY;
+               empty_design_prop = POWER_SUPPLY_PROP_CHARGE_EMPTY;
+               cur_avg_prop = POWER_SUPPLY_PROP_CHARGE_AVG;
+               cur_now_prop = POWER_SUPPLY_PROP_CHARGE_NOW;
+-      } else {
++              break;
++      case SOURCE_ENERGY:
+               full_prop = POWER_SUPPLY_PROP_ENERGY_FULL;
+               full_design_prop = POWER_SUPPLY_PROP_ENERGY_FULL_DESIGN;
+               empty_prop = POWER_SUPPLY_PROP_ENERGY_EMPTY;
+               empty_design_prop = POWER_SUPPLY_PROP_CHARGE_EMPTY;
+               cur_avg_prop = POWER_SUPPLY_PROP_ENERGY_AVG;
+               cur_now_prop = POWER_SUPPLY_PROP_ENERGY_NOW;
++              break;
++      case SOURCE_VOLTAGE:
++              full_prop = POWER_SUPPLY_PROP_VOLTAGE_MAX;
++              full_design_prop = POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN;
++              empty_prop = POWER_SUPPLY_PROP_VOLTAGE_MIN;
++              empty_design_prop = POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN;
++              cur_avg_prop = POWER_SUPPLY_PROP_VOLTAGE_AVG;
++              cur_now_prop = POWER_SUPPLY_PROP_VOLTAGE_NOW;
++              break;
++      default:
++              printk(KERN_ERR "Unsupported source: %d\n", source);
++              return -1;
+       }
+       if (_MPSY_PROP(full_prop, &full)) {
+@@ -146,7 +166,7 @@ static int calculate_time(int status, int using_charge)
+               return -((cur.intval - empty.intval) * 60L) / I.intval;
+ }
+-static int calculate_capacity(int using_charge)
++static int calculate_capacity(apm_source source)
+ {
+       enum power_supply_property full_prop, empty_prop;
+       enum power_supply_property full_design_prop, empty_design_prop;
+@@ -154,20 +174,33 @@ static int calculate_capacity(int using_charge)
+       union power_supply_propval empty, full, cur;
+       int ret;
+-      if (using_charge) {
++      switch (source) {
++      case SOURCE_CHARGE:
+               full_prop = POWER_SUPPLY_PROP_CHARGE_FULL;
+               empty_prop = POWER_SUPPLY_PROP_CHARGE_EMPTY;
+               full_design_prop = POWER_SUPPLY_PROP_CHARGE_FULL_DESIGN;
+               empty_design_prop = POWER_SUPPLY_PROP_CHARGE_EMPTY_DESIGN;
+               now_prop = POWER_SUPPLY_PROP_CHARGE_NOW;
+               avg_prop = POWER_SUPPLY_PROP_CHARGE_AVG;
+-      } else {
++              break;
++      case SOURCE_ENERGY:
+               full_prop = POWER_SUPPLY_PROP_ENERGY_FULL;
+               empty_prop = POWER_SUPPLY_PROP_ENERGY_EMPTY;
+               full_design_prop = POWER_SUPPLY_PROP_ENERGY_FULL_DESIGN;
+               empty_design_prop = POWER_SUPPLY_PROP_ENERGY_EMPTY_DESIGN;
+               now_prop = POWER_SUPPLY_PROP_ENERGY_NOW;
+               avg_prop = POWER_SUPPLY_PROP_ENERGY_AVG;
++      case SOURCE_VOLTAGE:
++              full_prop = POWER_SUPPLY_PROP_VOLTAGE_MAX;
++              empty_prop = POWER_SUPPLY_PROP_VOLTAGE_MIN;
++              full_design_prop = POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN;
++              empty_design_prop = POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN;
++              now_prop = POWER_SUPPLY_PROP_VOLTAGE_NOW;
++              avg_prop = POWER_SUPPLY_PROP_VOLTAGE_AVG;
++              break;
++      default:
++              printk(KERN_ERR "Unsupported source: %d\n", source);
++              return -1;
+       }
+       if (_MPSY_PROP(full_prop, &full)) {
+@@ -234,10 +267,12 @@ static void apm_battery_apm_get_power_status(struct apm_power_info *info)
+               info->battery_life = capacity.intval;
+       } else {
+               /* try calculate using energy */
+-              info->battery_life = calculate_capacity(0);
++              info->battery_life = calculate_capacity(SOURCE_ENERGY);
+               /* if failed try calculate using charge instead */
+               if (info->battery_life == -1)
+-                      info->battery_life = calculate_capacity(1);
++                      info->battery_life = calculate_capacity(SOURCE_CHARGE);
++              if (info->battery_life == -1)
++                      info->battery_life = calculate_capacity(SOURCE_VOLTAGE);
+       }
+       /* charging status */
+@@ -263,18 +298,22 @@ static void apm_battery_apm_get_power_status(struct apm_power_info *info)
+                               !MPSY_PROP(TIME_TO_FULL_NOW, &time_to_full)) {
+                       info->time = time_to_full.intval / 60;
+               } else {
+-                      info->time = calculate_time(status.intval, 0);
++                      info->time = calculate_time(status.intval, SOURCE_ENERGY);
+                       if (info->time == -1)
+-                              info->time = calculate_time(status.intval, 1);
++                              info->time = calculate_time(status.intval, SOURCE_CHARGE);
++                      if (info->time == -1)
++                              info->time = calculate_time(status.intval, SOURCE_VOLTAGE);
+               }
+       } else {
+               if (!MPSY_PROP(TIME_TO_EMPTY_AVG, &time_to_empty) ||
+                             !MPSY_PROP(TIME_TO_EMPTY_NOW, &time_to_empty)) {
+                       info->time = time_to_empty.intval / 60;
+               } else {
+-                      info->time = calculate_time(status.intval, 0);
++                      info->time = calculate_time(status.intval, SOURCE_ENERGY);
++                      if (info->time == -1)
++                              info->time = calculate_time(status.intval, SOURCE_CHARGE);
+                       if (info->time == -1)
+-                              info->time = calculate_time(status.intval, 1);
++                              info->time = calculate_time(status.intval, SOURCE_VOLTAGE);
+               }
+       }
+-- 
+1.5.3.8
+
diff --git a/packages/kexecboot/linux-kexecboot-2.6.24/tosa/0030-Core-driver-for-WM97xx-touchscreens.patch b/packages/kexecboot/linux-kexecboot-2.6.24/tosa/0030-Core-driver-for-WM97xx-touchscreens.patch
new file mode 100644 (file)
index 0000000..1c86a39
--- /dev/null
@@ -0,0 +1,1083 @@
+From d3e044e0e10e6c6b75716cb927e92b4ec284132f Mon Sep 17 00:00:00 2001
+From: Mark Brown <broonie@opensource.wolfsonmicro.com>
+Date: Sat, 26 Jan 2008 21:14:20 +0300
+Subject: [PATCH 30/64] Core driver for WM97xx touchscreens
+
+This patch series adds support for the touchscreen controllers provided
+by Wolfson Microelectronics WM97xx series chips in both polled and
+streaming modes.
+
+These drivers have been maintained out of tree since 2003.  During that
+time the driver the primary maintainer was Liam Girdwood and a number of
+people have made contributions including Stanley Cai, Rodolfo Giometti,
+Russell King, Marc Kleine-Budde, Ian Molton, Vincent Sanders, Andrew
+Zabolotny, Graeme Gregory, Mike Arthur and myself.  Apologies to anyone
+I have omitted.
+
+Signed-off-by: Liam Girdwood <liam.girdwood@wolfsonmicro.com>
+Signed-off-by: Graeme Gregory <gg@opensource.wolfsonmicro.com>
+Signed-off-by: Mike Arthur <mike.arthur@wolfsonmicro.com>
+Signed-off-by: Mark Brown <broonie@opensource.wolfsonmicro.com>
+Cc: Dmitry Baryshkov <dbaryshkov@gmail.com>
+Cc: Stanley Cai <stanley.cai@intel.com>
+Cc: Rodolfo Giometti <giometti@enneenne.com>
+Cc: Russell King <rmk@arm.linux.org.uk>
+Cc: Marc Kleine-Budde <mkl@pengutronix.de>
+Cc: Ian Molton <spyro@f2s.com>
+Cc: Vincent Sanders <vince@kyllikki.org>
+Cc: Andrew Zabolotny <zap@homelink.ru>
+---
+ drivers/input/touchscreen/wm97xx-core.c |  724 +++++++++++++++++++++++++++++++
+ include/linux/wm97xx.h                  |  309 +++++++++++++
+ 2 files changed, 1033 insertions(+), 0 deletions(-)
+ create mode 100644 drivers/input/touchscreen/wm97xx-core.c
+ create mode 100644 include/linux/wm97xx.h
+
+diff --git a/drivers/input/touchscreen/wm97xx-core.c b/drivers/input/touchscreen/wm97xx-core.c
+new file mode 100644
+index 0000000..27a0a99
+--- /dev/null
++++ b/drivers/input/touchscreen/wm97xx-core.c
+@@ -0,0 +1,724 @@
++/*
++ * wm97xx-core.c  --  Touch screen driver core for Wolfson WM9705, WM9712
++ *                    and WM9713 AC97 Codecs.
++ *
++ * Copyright 2003, 2004, 2005, 2006, 2007, 2008 Wolfson Microelectronics PLC.
++ * Author: Liam Girdwood
++ *         liam.girdwood@wolfsonmicro.com or linux@wolfsonmicro.com
++ * Parts Copyright : Ian Molton <spyro@f2s.com>
++ *                   Andrew Zabolotny <zap@homelink.ru>
++ *                   Russell King <rmk@arm.linux.org.uk>
++ *
++ *  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.
++ *
++ * Notes:
++ *
++ *  Features:
++ *       - supports WM9705, WM9712, WM9713
++ *       - polling mode
++ *       - continuous mode (arch-dependent)
++ *       - adjustable rpu/dpp settings
++ *       - adjustable pressure current
++ *       - adjustable sample settle delay
++ *       - 4 and 5 wire touchscreens (5 wire is WM9712 only)
++ *       - pen down detection
++ *       - battery monitor
++ *       - sample AUX adcs
++ *       - power management
++ *       - codec GPIO
++ *       - codec event notification
++ * Todo
++ *       - Support for async sampling control for noisy LCDs.
++ *
++ */
++
++#include <linux/module.h>
++#include <linux/moduleparam.h>
++#include <linux/version.h>
++#include <linux/kernel.h>
++#include <linux/init.h>
++#include <linux/delay.h>
++#include <linux/string.h>
++#include <linux/proc_fs.h>
++#include <linux/pm.h>
++#include <linux/interrupt.h>
++#include <linux/bitops.h>
++#include <linux/workqueue.h>
++#include <linux/wm97xx.h>
++#include <linux/uaccess.h>
++#include <linux/io.h>
++
++#define TS_NAME                       "wm97xx"
++#define WM_CORE_VERSION               "0.65"
++#define DEFAULT_PRESSURE      0xb0c0
++
++
++/*
++ * Touchscreen absolute values
++ *
++ * These parameters are used to help the input layer discard out of
++ * range readings and reduce jitter etc.
++ *
++ *   o min, max:- indicate the min and max values your touch screen returns
++ *   o fuzz:- use a higher number to reduce jitter
++ *
++ * The default values correspond to Mainstone II in QVGA mode
++ *
++ * Please read
++ * Documentation/input/input-programming.txt for more details.
++ */
++
++static int abs_x[3] = {350, 3900, 5};
++module_param_array(abs_x, int, NULL, 0);
++MODULE_PARM_DESC(abs_x, "Touchscreen absolute X min, max, fuzz");
++
++static int abs_y[3] = {320, 3750, 40};
++module_param_array(abs_y, int, NULL, 0);
++MODULE_PARM_DESC(abs_y, "Touchscreen absolute Y min, max, fuzz");
++
++static int abs_p[3] = {0, 150, 4};
++module_param_array(abs_p, int, NULL, 0);
++MODULE_PARM_DESC(abs_p, "Touchscreen absolute Pressure min, max, fuzz");
++
++/*
++ * wm97xx IO access, all IO locking done by AC97 layer
++ */
++int wm97xx_reg_read(struct wm97xx *wm, u16 reg)
++{
++      if (wm->ac97)
++              return wm->ac97->bus->ops->read(wm->ac97, reg);
++      else
++              return -1;
++}
++EXPORT_SYMBOL_GPL(wm97xx_reg_read);
++
++void wm97xx_reg_write(struct wm97xx *wm, u16 reg, u16 val)
++{
++      /* cache digitiser registers */
++      if (reg >= AC97_WM9713_DIG1 && reg <= AC97_WM9713_DIG3)
++              wm->dig[(reg - AC97_WM9713_DIG1) >> 1] = val;
++
++      /* cache gpio regs */
++      if (reg >= AC97_GPIO_CFG && reg <= AC97_MISC_AFE)
++              wm->gpio[(reg - AC97_GPIO_CFG) >> 1] = val;
++
++      /* wm9713 irq reg */
++      if (reg == 0x5a)
++              wm->misc = val;
++
++      if (wm->ac97)
++              wm->ac97->bus->ops->write(wm->ac97, reg, val);
++}
++EXPORT_SYMBOL_GPL(wm97xx_reg_write);
++
++/**
++ *    wm97xx_read_aux_adc - Read the aux adc.
++ *    @wm: wm97xx device.
++ *  @adcsel: codec ADC to be read
++ *
++ *    Reads the selected AUX ADC.
++ */
++
++int wm97xx_read_aux_adc(struct wm97xx *wm, u16 adcsel)
++{
++      int power_adc = 0, auxval;
++      u16 power = 0;
++
++      /* get codec */
++      mutex_lock(&wm->codec_mutex);
++
++      /* When the touchscreen is not in use, we may have to power up
++       * the AUX ADC before we can use sample the AUX inputs->
++       */
++      if (wm->id == WM9713_ID2 &&
++          (power = wm97xx_reg_read(wm, AC97_EXTENDED_MID)) & 0x8000) {
++              power_adc = 1;
++              wm97xx_reg_write(wm, AC97_EXTENDED_MID, power & 0x7fff);
++      }
++
++      /* Prepare the codec for AUX reading */
++      wm->codec->aux_prepare(wm);
++
++      /* Turn polling mode on to read AUX ADC */
++      wm->pen_probably_down = 1;
++      wm->codec->poll_sample(wm, adcsel, &auxval);
++
++      if (power_adc)
++              wm97xx_reg_write(wm, AC97_EXTENDED_MID, power | 0x8000);
++
++      wm->codec->dig_restore(wm);
++
++      wm->pen_probably_down = 0;
++
++      mutex_unlock(&wm->codec_mutex);
++      return auxval & 0xfff;
++}
++EXPORT_SYMBOL_GPL(wm97xx_read_aux_adc);
++
++/**
++ *    wm97xx_get_gpio - Get the status of a codec GPIO.
++ *    @wm: wm97xx device.
++ *      @gpio: gpio
++ *
++ *    Get the status of a codec GPIO pin
++ */
++
++enum wm97xx_gpio_status wm97xx_get_gpio(struct wm97xx *wm, u32 gpio)
++{
++      u16 status;
++      enum wm97xx_gpio_status ret;
++
++      mutex_lock(&wm->codec_mutex);
++      status = wm97xx_reg_read(wm, AC97_GPIO_STATUS);
++
++      if (status & gpio)
++              ret = WM97XX_GPIO_HIGH;
++      else
++              ret = WM97XX_GPIO_LOW;
++
++      mutex_unlock(&wm->codec_mutex);
++      return ret;
++}
++EXPORT_SYMBOL_GPL(wm97xx_get_gpio);
++
++/**
++ *    wm97xx_set_gpio - Set the status of a codec GPIO.
++ *    @wm: wm97xx device.
++ *  @gpio: gpio
++ *
++ *
++ *    Set the status of a codec GPIO pin
++ */
++
++void wm97xx_set_gpio(struct wm97xx *wm, u32 gpio,
++                              enum wm97xx_gpio_status status)
++{
++      u16 reg;
++
++      mutex_lock(&wm->codec_mutex);
++      reg = wm97xx_reg_read(wm, AC97_GPIO_STATUS);
++
++      if (status & WM97XX_GPIO_HIGH)
++              reg |= gpio;
++      else
++              reg &= ~gpio;
++
++      if (wm->id == WM9712_ID2)
++              wm97xx_reg_write(wm, AC97_GPIO_STATUS, reg << 1);
++      else
++              wm97xx_reg_write(wm, AC97_GPIO_STATUS, reg);
++      mutex_unlock(&wm->codec_mutex);
++}
++EXPORT_SYMBOL_GPL(wm97xx_set_gpio);
++
++/*
++ * Codec GPIO pin configuration, this sets pin direction, polarity,
++ * stickyness and wake up.
++ */
++void wm97xx_config_gpio(struct wm97xx *wm, u32 gpio, enum wm97xx_gpio_dir dir,
++                 enum wm97xx_gpio_pol pol, enum wm97xx_gpio_sticky sticky,
++                 enum wm97xx_gpio_wake wake)
++{
++      u16 reg;
++
++      mutex_lock(&wm->codec_mutex);
++      reg = wm97xx_reg_read(wm, AC97_GPIO_POLARITY);
++
++      if (pol == WM97XX_GPIO_POL_HIGH)
++              reg |= gpio;
++      else
++              reg &= ~gpio;
++
++      wm97xx_reg_write(wm, AC97_GPIO_POLARITY, reg);
++      reg = wm97xx_reg_read(wm, AC97_GPIO_STICKY);
++
++      if (sticky == WM97XX_GPIO_STICKY)
++              reg |= gpio;
++      else
++              reg &= ~gpio;
++
++      wm97xx_reg_write(wm, AC97_GPIO_STICKY, reg);
++      reg = wm97xx_reg_read(wm, AC97_GPIO_WAKEUP);
++
++      if (wake == WM97XX_GPIO_WAKE)
++              reg |= gpio;
++      else
++              reg &= ~gpio;
++
++      wm97xx_reg_write(wm, AC97_GPIO_WAKEUP, reg);
++      reg = wm97xx_reg_read(wm, AC97_GPIO_CFG);
++
++      if (dir == WM97XX_GPIO_IN)
++              reg |= gpio;
++      else
++              reg &= ~gpio;
++
++      wm97xx_reg_write(wm, AC97_GPIO_CFG, reg);
++      mutex_unlock(&wm->codec_mutex);
++}
++EXPORT_SYMBOL_GPL(wm97xx_config_gpio);
++
++/*
++ * Handle a pen down interrupt.
++ */
++static void wm97xx_pen_irq_worker(struct work_struct *work)
++{
++      struct wm97xx *wm = container_of(work, struct wm97xx, pen_event_work);
++
++      /* do we need to enable the touch panel reader */
++      if (wm->id == WM9705_ID2) {
++              if (wm97xx_reg_read(wm, AC97_WM97XX_DIGITISER_RD) &
++                                      WM97XX_PEN_DOWN)
++                      wm->pen_is_down = 1;
++              else
++                      wm->pen_is_down = 0;
++      } else {
++              u16 status, pol;
++              mutex_lock(&wm->codec_mutex);
++              status = wm97xx_reg_read(wm, AC97_GPIO_STATUS);
++              pol = wm97xx_reg_read(wm, AC97_GPIO_POLARITY);
++
++              if (WM97XX_GPIO_13 & pol & status) {
++                      wm->pen_is_down = 1;
++                      wm97xx_reg_write(wm, AC97_GPIO_POLARITY, pol &
++                                              ~WM97XX_GPIO_13);
++              } else {
++                      wm->pen_is_down = 0;
++                      wm97xx_reg_write(wm, AC97_GPIO_POLARITY, pol |
++                                       WM97XX_GPIO_13);
++              }
++
++              if (wm->id == WM9712_ID2)
++                      wm97xx_reg_write(wm, AC97_GPIO_STATUS, (status &
++                                              ~WM97XX_GPIO_13) << 1);
++              else
++                      wm97xx_reg_write(wm, AC97_GPIO_STATUS, status &
++                                              ~WM97XX_GPIO_13);
++              mutex_unlock(&wm->codec_mutex);
++      }
++
++      queue_delayed_work(wm->ts_workq, &wm->ts_reader, 0);
++
++      if (!wm->pen_is_down && wm->mach_ops && wm->mach_ops->acc_enabled)
++              wm->mach_ops->acc_pen_up(wm);
++      wm->mach_ops->irq_enable(wm, 1);
++}
++
++/*
++ * Codec PENDOWN irq handler
++ *
++ * We have to disable the codec interrupt in the handler because it can
++ * take upto 1ms to clear the interrupt source. The interrupt is then enabled
++ * again in the slow handler when the source has been cleared.
++ */
++static irqreturn_t wm97xx_pen_interrupt(int irq, void *dev_id)
++{
++      struct wm97xx *wm = dev_id;
++      wm->mach_ops->irq_enable(wm, 0);
++      queue_work(wm->ts_workq, &wm->pen_event_work);
++      return IRQ_HANDLED;
++}
++
++/*
++ * initialise pen IRQ handler and workqueue
++ */
++static int wm97xx_init_pen_irq(struct wm97xx *wm)
++{
++      u16 reg;
++
++      /* If an interrupt is supplied an IRQ enable operation must also be
++       * provided. */
++      BUG_ON(!wm->mach_ops->irq_enable);
++
++      INIT_WORK(&wm->pen_event_work, wm97xx_pen_irq_worker);
++
++      if (request_irq(wm->pen_irq, wm97xx_pen_interrupt, IRQF_SHARED,
++                      "wm97xx-pen", wm)) {
++              dev_err(wm->dev,
++                      "Failed to register pen down interrupt, polling");
++              wm->pen_irq = 0;
++              return -EINVAL;
++      }
++
++      /* enable PEN down on wm9712/13 */
++      if (wm->id != WM9705_ID2) {
++              reg = wm97xx_reg_read(wm, AC97_MISC_AFE);
++              wm97xx_reg_write(wm, AC97_MISC_AFE, reg & 0xfffb);
++              reg = wm97xx_reg_read(wm, 0x5a);
++              wm97xx_reg_write(wm, 0x5a, reg & ~0x0001);
++      }
++
++      return 0;
++}
++
++static int wm97xx_read_samples(struct wm97xx *wm)
++{
++      struct wm97xx_data data;
++      int rc;
++
++      mutex_lock(&wm->codec_mutex);
++
++      if (wm->mach_ops && wm->mach_ops->acc_enabled)
++              rc = wm->mach_ops->acc_pen_down(wm);
++      else
++              rc = wm->codec->poll_touch(wm, &data);
++
++      if (rc & RC_PENUP) {
++              if (wm->pen_is_down) {
++                      wm->pen_is_down = 0;
++                      dev_dbg(wm->dev, "pen up\n");
++                      input_report_abs(wm->input_dev, ABS_PRESSURE, 0);
++                      input_sync(wm->input_dev);
++              } else if (!(rc & RC_AGAIN)) {
++                      /* We need high frequency updates only while
++                      * pen is down, the user never will be able to
++                      * touch screen faster than a few times per
++                      * second... On the other hand, when the user
++                      * is actively working with the touchscreen we
++                      * don't want to lose the quick response. So we
++                      * will slowly increase sleep time after the
++                      * pen is up and quicky restore it to ~one task
++                      * switch when pen is down again.
++                      */
++                      if (wm->ts_reader_interval < HZ / 10)
++                              wm->ts_reader_interval++;
++              }
++
++      } else if (rc & RC_VALID) {
++              dev_dbg(wm->dev,
++                      "pen down: x=%x:%d, y=%x:%d, pressure=%x:%d\n",
++                      data.x >> 12, data.x & 0xfff, data.y >> 12,
++                      data.y & 0xfff, data.p >> 12, data.p & 0xfff);
++              input_report_abs(wm->input_dev, ABS_X, data.x & 0xfff);
++              input_report_abs(wm->input_dev, ABS_Y, data.y & 0xfff);
++              input_report_abs(wm->input_dev, ABS_PRESSURE, data.p & 0xfff);
++              input_sync(wm->input_dev);
++              wm->pen_is_down = 1;
++              wm->ts_reader_interval = wm->ts_reader_min_interval;
++      } else if (rc & RC_PENDOWN) {
++              dev_dbg(wm->dev, "pen down");
++              wm->pen_is_down = 1;
++              wm->ts_reader_interval = wm->ts_reader_min_interval;
++      }
++
++      mutex_unlock(&wm->codec_mutex);
++      return rc;
++}
++
++/*
++* The touchscreen sample reader.
++*/
++static void wm97xx_ts_reader(struct work_struct *work)
++{
++      int rc;
++      struct wm97xx *wm = container_of(work, struct wm97xx, ts_reader.work);
++
++      BUG_ON(!wm->codec);
++
++      do {
++              rc = wm97xx_read_samples(wm);
++      } while (rc & RC_AGAIN);
++
++      if (wm->pen_is_down || !wm->pen_irq)
++              queue_delayed_work(wm->ts_workq, &wm->ts_reader,
++                                 wm->ts_reader_interval);
++}
++
++/**
++ *    wm97xx_ts_input_open - Open the touch screen input device.
++ *    @idev:  Input device to be opened.
++ *
++ *    Called by the input sub system to open a wm97xx touchscreen device.
++ *  Starts the touchscreen thread and touch digitiser.
++ */
++static int wm97xx_ts_input_open(struct input_dev *idev)
++{
++      struct wm97xx *wm = input_get_drvdata(idev);
++
++      wm->ts_workq = create_singlethread_workqueue("kwm97xx");
++      if (wm->ts_workq == NULL) {
++              dev_err(wm->dev,
++                      "Failed to create workqueue\n");
++              return -EINVAL;
++      }
++
++      /* start digitiser */
++      if (wm->mach_ops && wm->mach_ops->acc_enabled)
++              wm->codec->acc_enable(wm, 1);
++      wm->codec->dig_enable(wm, 1);
++
++      INIT_DELAYED_WORK(&wm->ts_reader, wm97xx_ts_reader);
++
++      wm->ts_reader_min_interval = HZ >= 100 ? HZ / 100 : 1;
++      if (wm->ts_reader_min_interval < 1)
++              wm->ts_reader_min_interval = 1;
++      wm->ts_reader_interval = wm->ts_reader_min_interval;
++
++      wm->pen_is_down = 0;
++      if (wm->pen_irq)
++              wm97xx_init_pen_irq(wm);
++      else
++              dev_err(wm->dev, "No IRQ specified\n");
++
++      /* If we either don't have an interrupt for pen down events or
++       * failed to acquire it then we need to poll.
++       */
++      if (wm->pen_irq == 0)
++              queue_delayed_work(wm->ts_workq, &wm->ts_reader,
++                                 wm->ts_reader_interval);
++
++      return 0;
++}
++
++/**
++ *    wm97xx_ts_input_close - Close the touch screen input device.
++ *    @idev:  Input device to be closed.
++ *
++ *    Called by the input sub system to close a wm97xx touchscreen device.
++ *  Kills the touchscreen thread and stops the touch digitiser.
++ */
++
++static void wm97xx_ts_input_close(struct input_dev *idev)
++{
++      struct wm97xx *wm = input_get_drvdata(idev);
++
++      if (wm->pen_irq)
++              free_irq(wm->pen_irq, wm);
++
++      wm->pen_is_down = 0;
++
++      /* ts_reader rearms itself so we need to explicitly stop it
++       * before we destroy the workqueue.
++       */
++      cancel_delayed_work_sync(&wm->ts_reader);
++      destroy_workqueue(wm->ts_workq);
++
++      /* stop digitiser */
++      wm->codec->dig_enable(wm, 0);
++      if (wm->mach_ops && wm->mach_ops->acc_enabled)
++              wm->codec->acc_enable(wm, 0);
++}
++
++static int wm97xx_probe(struct device *dev)
++{
++      struct wm97xx *wm;
++      int ret = 0, id = 0;
++
++      wm = kzalloc(sizeof(struct wm97xx), GFP_KERNEL);
++      if (!wm)
++              return -ENOMEM;
++      mutex_init(&wm->codec_mutex);
++
++      wm->dev = dev;
++      dev->driver_data = wm;
++      wm->ac97 = to_ac97_t(dev);
++
++      /* check that we have a supported codec */
++      id = wm97xx_reg_read(wm, AC97_VENDOR_ID1);
++      if (id != WM97XX_ID1) {
++              dev_err(dev, "Device with vendor %04x is not a wm97xx\n", id);
++              kfree(wm);
++              return -ENODEV;
++      }
++
++      wm->id = wm97xx_reg_read(wm, AC97_VENDOR_ID2);
++
++      dev_info(wm->dev, "detected a wm97%02x codec", wm->id & 0xff);
++
++      switch (wm->id & 0xff) {
++#ifdef CONFIG_TOUCHSCREEN_WM9705
++      case 0x05:
++              wm->codec = &wm9705_codec;
++              break;
++#endif
++#ifdef CONFIG_TOUCHSCREEN_WM9712
++      case 0x12:
++              wm->codec = &wm9712_codec;
++              break;
++#endif
++#ifdef CONFIG_TOUCHSCREEN_WM9713
++      case 0x13:
++              wm->codec = &wm9713_codec;
++              break;
++#endif
++      default:
++              dev_err(wm->dev, "Support for wm97%02x not compiled in.\n",
++                      wm->id & 0xff);
++              kfree(wm);
++              return -ENODEV;
++      }
++
++      wm->input_dev = input_allocate_device();
++      if (wm->input_dev == NULL) {
++              kfree(wm);
++              return -ENOMEM;
++      }
++
++      /* set up touch configuration */
++      wm->input_dev->name = "wm97xx touchscreen";
++      wm->input_dev->open = wm97xx_ts_input_open;
++      wm->input_dev->close = wm97xx_ts_input_close;
++      set_bit(EV_ABS, wm->input_dev->evbit);
++      set_bit(ABS_X, wm->input_dev->absbit);
++      set_bit(ABS_Y, wm->input_dev->absbit);
++      set_bit(ABS_PRESSURE, wm->input_dev->absbit);
++      input_set_abs_params(wm->input_dev, ABS_X, abs_x[0], abs_x[1],
++                           abs_x[2], 0);
++      input_set_abs_params(wm->input_dev, ABS_Y, abs_y[0], abs_y[1],
++                           abs_y[2], 0);
++      input_set_abs_params(wm->input_dev, ABS_PRESSURE, abs_p[0], abs_p[1],
++                           abs_p[2], 0);
++      input_set_drvdata(wm->input_dev, wm);
++      wm->input_dev->dev.parent = dev;
++      ret = input_register_device(wm->input_dev);
++      if (ret < 0) {
++              input_free_device(wm->input_dev);
++              kfree(wm);
++              return -ENOMEM;
++      }
++
++      /* set up physical characteristics */
++      wm->codec->phy_init(wm);
++
++      /* load gpio cache */
++      wm->gpio[0] = wm97xx_reg_read(wm, AC97_GPIO_CFG);
++      wm->gpio[1] = wm97xx_reg_read(wm, AC97_GPIO_POLARITY);
++      wm->gpio[2] = wm97xx_reg_read(wm, AC97_GPIO_STICKY);
++      wm->gpio[3] = wm97xx_reg_read(wm, AC97_GPIO_WAKEUP);
++      wm->gpio[4] = wm97xx_reg_read(wm, AC97_GPIO_STATUS);
++      wm->gpio[5] = wm97xx_reg_read(wm, AC97_MISC_AFE);
++
++      /* register our battery device */
++      wm->battery_dev = platform_device_alloc("wm97xx-battery", 0);
++      if (!wm->battery_dev)
++              goto batt_err;
++      platform_set_drvdata(wm->battery_dev, wm);
++      wm->battery_dev->dev.parent = dev;
++      ret = platform_device_register(wm->battery_dev);
++      if (ret < 0)
++              goto batt_reg_err;
++
++      /* register our extended touch device (for machine specific
++       * extensions) */
++      wm->touch_dev = platform_device_alloc("wm97xx-touch", 0);
++      if (!wm->touch_dev)
++              goto touch_err;
++      platform_set_drvdata(wm->touch_dev, wm);
++      wm->touch_dev->dev.parent = dev;
++      ret = platform_device_register(wm->touch_dev);
++      if (ret < 0)
++              goto touch_reg_err;
++
++      return ret;
++
++ touch_reg_err:
++      platform_device_put(wm->touch_dev);
++ touch_err:
++      platform_device_unregister(wm->battery_dev);
++ batt_reg_err:
++      platform_device_put(wm->battery_dev);
++ batt_err:
++      input_unregister_device(wm->input_dev);
++      kfree(wm);
++      return ret;
++}
++
++static int wm97xx_remove(struct device *dev)
++{
++      struct wm97xx *wm = dev_get_drvdata(dev);
++
++      platform_device_unregister(wm->battery_dev);
++      platform_device_unregister(wm->touch_dev);
++      input_unregister_device(wm->input_dev);
++
++      kfree(wm);
++      return 0;
++}
++
++#ifdef CONFIG_PM
++static int wm97xx_resume(struct device *dev)
++{
++      struct wm97xx *wm = dev_get_drvdata(dev);
++
++      /* restore digitiser and gpios */
++      if (wm->id == WM9713_ID2) {
++              wm97xx_reg_write(wm, AC97_WM9713_DIG1, wm->dig[0]);
++              wm97xx_reg_write(wm, 0x5a, wm->misc);
++              if (wm->input_dev->users) {
++                      u16 reg;
++                      reg = wm97xx_reg_read(wm, AC97_EXTENDED_MID) & 0x7fff;
++                      wm97xx_reg_write(wm, AC97_EXTENDED_MID, reg);
++              }
++      }
++
++      wm97xx_reg_write(wm, AC97_WM9713_DIG2, wm->dig[1]);
++      wm97xx_reg_write(wm, AC97_WM9713_DIG3, wm->dig[2]);
++
++      wm97xx_reg_write(wm, AC97_GPIO_CFG, wm->gpio[0]);
++      wm97xx_reg_write(wm, AC97_GPIO_POLARITY, wm->gpio[1]);
++      wm97xx_reg_write(wm, AC97_GPIO_STICKY, wm->gpio[2]);
++      wm97xx_reg_write(wm, AC97_GPIO_WAKEUP, wm->gpio[3]);
++      wm97xx_reg_write(wm, AC97_GPIO_STATUS, wm->gpio[4]);
++      wm97xx_reg_write(wm, AC97_MISC_AFE, wm->gpio[5]);
++
++      return 0;
++}
++
++#else
++#define wm97xx_resume         NULL
++#endif
++
++/*
++ * Machine specific operations
++ */
++int wm97xx_register_mach_ops(struct wm97xx *wm,
++                           struct wm97xx_mach_ops *mach_ops)
++{
++      mutex_lock(&wm->codec_mutex);
++      if (wm->mach_ops) {
++              mutex_unlock(&wm->codec_mutex);
++              return -EINVAL;
++      }
++      wm->mach_ops = mach_ops;
++      mutex_unlock(&wm->codec_mutex);
++      return 0;
++}
++EXPORT_SYMBOL_GPL(wm97xx_register_mach_ops);
++
++void wm97xx_unregister_mach_ops(struct wm97xx *wm)
++{
++      mutex_lock(&wm->codec_mutex);
++      wm->mach_ops = NULL;
++      mutex_unlock(&wm->codec_mutex);
++}
++EXPORT_SYMBOL_GPL(wm97xx_unregister_mach_ops);
++
++static struct device_driver wm97xx_driver = {
++      .name =         "ac97",
++      .bus =          &ac97_bus_type,
++      .owner =        THIS_MODULE,
++      .probe =        wm97xx_probe,
++      .remove =       wm97xx_remove,
++      .resume =       wm97xx_resume,
++};
++
++static int __init wm97xx_init(void)
++{
++      return driver_register(&wm97xx_driver);
++}
++
++static void __exit wm97xx_exit(void)
++{
++      driver_unregister(&wm97xx_driver);
++}
++
++module_init(wm97xx_init);
++module_exit(wm97xx_exit);
++
++/* Module information */
++MODULE_AUTHOR("Liam Girdwood <liam.girdwood@wolfsonmicro.com>");
++MODULE_DESCRIPTION("WM97xx Core - Touch Screen / AUX ADC / GPIO Driver");
++MODULE_LICENSE("GPL");
+diff --git a/include/linux/wm97xx.h b/include/linux/wm97xx.h
+new file mode 100644
+index 0000000..fc6e0b3
+--- /dev/null
++++ b/include/linux/wm97xx.h
+@@ -0,0 +1,309 @@
++
++/*
++ * Register bits and API for Wolfson WM97xx series of codecs
++ */
++
++#ifndef _LINUX_WM97XX_H
++#define _LINUX_WM97XX_H
++
++#include <sound/driver.h>
++#include <sound/core.h>
++#include <sound/pcm.h>
++#include <sound/ac97_codec.h>
++#include <sound/initval.h>
++#include <linux/types.h>
++#include <linux/list.h>
++#include <linux/input.h>      /* Input device layer */
++#include <linux/platform_device.h>
++
++/*
++ * WM97xx AC97 Touchscreen registers
++ */
++#define AC97_WM97XX_DIGITISER1                0x76
++#define AC97_WM97XX_DIGITISER2                0x78
++#define AC97_WM97XX_DIGITISER_RD      0x7a
++#define AC97_WM9713_DIG1              0x74
++#define AC97_WM9713_DIG2              AC97_WM97XX_DIGITISER1
++#define AC97_WM9713_DIG3              AC97_WM97XX_DIGITISER2
++
++/*
++ * WM97xx register bits
++ */
++#define WM97XX_POLL           0x8000  /* initiate a polling measurement */
++#define WM97XX_ADCSEL_X               0x1000  /* x coord measurement */
++#define WM97XX_ADCSEL_Y               0x2000  /* y coord measurement */
++#define WM97XX_ADCSEL_PRES    0x3000  /* pressure measurement */
++#define WM97XX_ADCSEL_MASK    0x7000
++#define WM97XX_COO            0x0800  /* enable coordinate mode */
++#define WM97XX_CTC            0x0400  /* enable continuous mode */
++#define WM97XX_CM_RATE_93     0x0000  /* 93.75Hz continuous rate */
++#define WM97XX_CM_RATE_187    0x0100  /* 187.5Hz continuous rate */
++#define WM97XX_CM_RATE_375    0x0200  /* 375Hz continuous rate */
++#define WM97XX_CM_RATE_750    0x0300  /* 750Hz continuous rate */
++#define WM97XX_CM_RATE_8K     0x00f0  /* 8kHz continuous rate */
++#define WM97XX_CM_RATE_12K    0x01f0  /* 12kHz continuous rate */
++#define WM97XX_CM_RATE_24K    0x02f0  /* 24kHz continuous rate */
++#define WM97XX_CM_RATE_48K    0x03f0  /* 48kHz continuous rate */
++#define WM97XX_CM_RATE_MASK   0x03f0
++#define WM97XX_RATE(i)                (((i & 3) << 8) | ((i & 4) ? 0xf0 : 0))
++#define WM97XX_DELAY(i)               ((i << 4) & 0x00f0)     /* sample delay times */
++#define WM97XX_DELAY_MASK     0x00f0
++#define WM97XX_SLEN           0x0008  /* slot read back enable */
++#define WM97XX_SLT(i)         ((i - 5) & 0x7) /* panel slot (5-11) */
++#define WM97XX_SLT_MASK               0x0007
++#define WM97XX_PRP_DETW               0x4000  /* detect on, digitise off, wake */
++#define WM97XX_PRP_DET                0x8000  /* detect on, digitise off, no wake */
++#define WM97XX_PRP_DET_DIG    0xc000  /* setect on, digitise on */
++#define WM97XX_RPR            0x2000  /* wake up on pen down */
++#define WM97XX_PEN_DOWN               0x8000  /* pen is down */
++#define WM97XX_ADCSRC_MASK    0x7000  /* ADC source mask */
++
++#define WM97XX_AUX_ID1                0x8001
++#define WM97XX_AUX_ID2                0x8002
++#define WM97XX_AUX_ID3                0x8003
++#define WM97XX_AUX_ID4                0x8004
++
++
++/* WM9712 Bits */
++#define WM9712_45W            0x1000  /* set for 5-wire touchscreen */
++#define WM9712_PDEN           0x0800  /* measure only when pen down */
++#define WM9712_WAIT           0x0200  /* wait until adc is read before next sample */
++#define WM9712_PIL            0x0100  /* current used for pressure measurement. set 400uA else 200uA */
++#define WM9712_MASK_HI                0x0040  /* hi on mask pin (47) stops conversions */
++#define WM9712_MASK_EDGE      0x0080  /* rising/falling edge on pin delays sample */
++#define       WM9712_MASK_SYNC        0x00c0  /* rising/falling edge on mask initiates sample */
++#define WM9712_RPU(i)         (i&0x3f)        /* internal pull up on pen detect (64k / rpu) */
++#define WM9712_PD(i)          (0x1 << i)      /* power management */
++
++/* WM9712 Registers */
++#define AC97_WM9712_POWER     0x24
++#define AC97_WM9712_REV               0x58
++
++/* WM9705 Bits */
++#define WM9705_PDEN           0x1000  /* measure only when pen is down */
++#define WM9705_PINV           0x0800  /* inverts sense of pen down output */
++#define WM9705_BSEN           0x0400  /* BUSY flag enable, pin47 is 1 when busy */
++#define WM9705_BINV           0x0200  /* invert BUSY (pin47) output */
++#define WM9705_WAIT           0x0100  /* wait until adc is read before next sample */
++#define WM9705_PIL            0x0080  /* current used for pressure measurement. set 400uA else 200uA */
++#define WM9705_PHIZ           0x0040  /* set PHONE and PCBEEP inputs to high impedance */
++#define WM9705_MASK_HI                0x0010  /* hi on mask stops conversions */
++#define WM9705_MASK_EDGE      0x0020  /* rising/falling edge on pin delays sample */
++#define       WM9705_MASK_SYNC        0x0030  /* rising/falling edge on mask initiates sample */
++#define WM9705_PDD(i)         (i & 0x000f)    /* pen detect comparator threshold */
++
++
++/* WM9713 Bits */
++#define WM9713_PDPOL          0x0400  /* Pen down polarity */
++#define WM9713_POLL           0x0200  /* initiate a polling measurement */
++#define WM9713_CTC            0x0100  /* enable continuous mode */
++#define WM9713_ADCSEL_X               0x0002  /* X measurement */
++#define WM9713_ADCSEL_Y               0x0004  /* Y measurement */
++#define WM9713_ADCSEL_PRES    0x0008  /* Pressure measurement */
++#define WM9713_COO            0x0001  /* enable coordinate mode */
++#define WM9713_PDEN           0x0800  /* measure only when pen down */
++#define WM9713_ADCSEL_MASK    0x00fe  /* ADC selection mask */
++#define WM9713_WAIT           0x0200  /* coordinate wait */
++
++/* AUX ADC ID's */
++#define TS_COMP1              0x0
++#define TS_COMP2              0x1
++#define TS_BMON                       0x2
++#define TS_WIPER              0x3
++
++/* ID numbers */
++#define WM97XX_ID1            0x574d
++#define WM9712_ID2            0x4c12
++#define WM9705_ID2            0x4c05
++#define WM9713_ID2            0x4c13
++
++/* Codec GPIO's */
++#define WM97XX_MAX_GPIO               16
++#define WM97XX_GPIO_1         (1 << 1)
++#define WM97XX_GPIO_2         (1 << 2)
++#define WM97XX_GPIO_3         (1 << 3)
++#define WM97XX_GPIO_4         (1 << 4)
++#define WM97XX_GPIO_5         (1 << 5)
++#define WM97XX_GPIO_6         (1 << 6)
++#define WM97XX_GPIO_7         (1 << 7)
++#define WM97XX_GPIO_8         (1 << 8)
++#define WM97XX_GPIO_9         (1 << 9)
++#define WM97XX_GPIO_10                (1 << 10)
++#define WM97XX_GPIO_11                (1 << 11)
++#define WM97XX_GPIO_12                (1 << 12)
++#define WM97XX_GPIO_13                (1 << 13)
++#define WM97XX_GPIO_14                (1 << 14)
++#define WM97XX_GPIO_15                (1 << 15)
++
++
++#define AC97_LINK_FRAME               21      /* time in uS for AC97 link frame */
++
++
++/*---------------- Return codes from sample reading functions ---------------*/
++
++/* More data is available; call the sample gathering function again */
++#define RC_AGAIN                      0x00000001
++/* The returned sample is valid */
++#define RC_VALID                      0x00000002
++/* The pen is up (the first RC_VALID without RC_PENUP means pen is down) */
++#define RC_PENUP                      0x00000004
++/* The pen is down (RC_VALID implies RC_PENDOWN, but sometimes it is helpful
++   to tell the handler that the pen is down but we don't know yet his coords,
++   so the handler should not sleep or wait for pendown irq) */
++#define RC_PENDOWN                    0x00000008
++
++/*
++ * The wm97xx driver provides a private API for writing platform-specific
++ * drivers.
++ */
++
++/* The structure used to return arch specific sampled data into */
++struct wm97xx_data {
++    int x;
++    int y;
++    int p;
++};
++
++/*
++ * Codec GPIO status
++ */
++enum wm97xx_gpio_status {
++    WM97XX_GPIO_HIGH,
++    WM97XX_GPIO_LOW
++};
++
++/*
++ * Codec GPIO direction
++ */
++enum wm97xx_gpio_dir {
++    WM97XX_GPIO_IN,
++    WM97XX_GPIO_OUT
++};
++
++/*
++ * Codec GPIO polarity
++ */
++enum wm97xx_gpio_pol {
++    WM97XX_GPIO_POL_HIGH,
++    WM97XX_GPIO_POL_LOW
++};
++
++/*
++ * Codec GPIO sticky
++ */
++enum wm97xx_gpio_sticky {
++    WM97XX_GPIO_STICKY,
++    WM97XX_GPIO_NOTSTICKY
++};
++
++/*
++ * Codec GPIO wake
++ */
++enum wm97xx_gpio_wake {
++    WM97XX_GPIO_WAKE,
++    WM97XX_GPIO_NOWAKE
++};
++
++/*
++ * Digitiser ioctl commands
++ */
++#define WM97XX_DIG_START      0x1
++#define WM97XX_DIG_STOP               0x2
++#define WM97XX_PHY_INIT               0x3
++#define WM97XX_AUX_PREPARE    0x4
++#define WM97XX_DIG_RESTORE    0x5
++
++struct wm97xx;
++
++extern struct wm97xx_codec_drv wm9705_codec;
++extern struct wm97xx_codec_drv wm9712_codec;
++extern struct wm97xx_codec_drv wm9713_codec;
++
++/*
++ * Codec driver interface - allows mapping to WM9705/12/13 and newer codecs
++ */
++struct wm97xx_codec_drv {
++      u16 id;
++      char *name;
++
++      /* read 1 sample */
++      int (*poll_sample) (struct wm97xx *, int adcsel, int *sample);
++
++      /* read X,Y,[P] in poll */
++      int (*poll_touch) (struct wm97xx *, struct wm97xx_data *);
++
++      int (*acc_enable) (struct wm97xx *, int enable);
++      void (*phy_init) (struct wm97xx *);
++      void (*dig_enable) (struct wm97xx *, int enable);
++      void (*dig_restore) (struct wm97xx *);
++      void (*aux_prepare) (struct wm97xx *);
++};
++
++
++/* Machine specific and accelerated touch operations */
++struct wm97xx_mach_ops {
++
++      /* accelerated touch readback - coords are transmited on AC97 link */
++      int acc_enabled;
++      void (*acc_pen_up) (struct wm97xx *);
++      int (*acc_pen_down) (struct wm97xx *);
++      int (*acc_startup) (struct wm97xx *);
++      void (*acc_shutdown) (struct wm97xx *);
++
++      /* interrupt mask control - required for accelerated operation */
++      void (*irq_enable) (struct wm97xx *, int enable);
++
++      /* pre and post sample - can be used to minimise any analog noise */
++      void (*pre_sample) (int);  /* function to run before sampling */
++      void (*post_sample) (int);  /* function to run after sampling */
++};
++
++struct wm97xx {
++      u16 dig[3], id, gpio[6], misc;  /* Cached codec registers */
++      u16 dig_save[3];                /* saved during aux reading */
++      struct wm97xx_codec_drv *codec; /* attached codec driver*/
++      struct input_dev *input_dev;    /* touchscreen input device */
++      struct snd_ac97 *ac97;          /* ALSA codec access */
++      struct device *dev;             /* ALSA device */
++      struct platform_device *battery_dev;
++      struct platform_device *touch_dev;
++      struct wm97xx_mach_ops *mach_ops;
++      struct mutex codec_mutex;
++      struct delayed_work ts_reader;  /* Used to poll touchscreen */
++      unsigned long ts_reader_interval; /* Current interval for timer */
++      unsigned long ts_reader_min_interval; /* Minimum interval */
++      unsigned int pen_irq;           /* Pen IRQ number in use */
++      struct workqueue_struct *ts_workq;
++      struct work_struct pen_event_work;
++      u16 acc_slot;                   /* AC97 slot used for acc touch data */
++      u16 acc_rate;                   /* acc touch data rate */
++      unsigned pen_is_down:1;         /* Pen is down */
++      unsigned aux_waiting:1;         /* aux measurement waiting */
++      unsigned pen_probably_down:1;   /* used in polling mode */
++};
++
++/*
++ * Codec GPIO access (not supported on WM9705)
++ * This can be used to set/get codec GPIO and Virtual GPIO status.
++ */
++enum wm97xx_gpio_status wm97xx_get_gpio(struct wm97xx *wm, u32 gpio);
++void wm97xx_set_gpio(struct wm97xx *wm, u32 gpio,
++                        enum wm97xx_gpio_status status);
++void wm97xx_config_gpio(struct wm97xx *wm, u32 gpio,
++                                   enum wm97xx_gpio_dir dir,
++                                   enum wm97xx_gpio_pol pol,
++                                   enum wm97xx_gpio_sticky sticky,
++                                   enum wm97xx_gpio_wake wake);
++
++/* codec AC97 IO access */
++int wm97xx_reg_read(struct wm97xx *wm, u16 reg);
++void wm97xx_reg_write(struct wm97xx *wm, u16 reg, u16 val);
++
++/* aux adc readback */
++int wm97xx_read_aux_adc(struct wm97xx *wm, u16 adcsel);
++
++/* machine ops */
++int wm97xx_register_mach_ops(struct wm97xx *, struct wm97xx_mach_ops *);
++void wm97xx_unregister_mach_ops(struct wm97xx *);
++
++#endif
+-- 
+1.5.3.8
+
diff --git a/packages/kexecboot/linux-kexecboot-2.6.24/tosa/0031-Add-chip-driver-for-WM9705-touchscreen.patch b/packages/kexecboot/linux-kexecboot-2.6.24/tosa/0031-Add-chip-driver-for-WM9705-touchscreen.patch
new file mode 100644 (file)
index 0000000..3890795
--- /dev/null
@@ -0,0 +1,383 @@
+From 7b366ca784d0540613a43908de803e4dedc100d3 Mon Sep 17 00:00:00 2001
+From: Mark Brown <broonie@opensource.wolfsonmicro.com>
+Date: Sat, 26 Jan 2008 21:14:20 +0300
+Subject: [PATCH 31/64] Add chip driver for WM9705 touchscreen
+
+Signed-off-by: Liam Girdwood <liam.girdwood@wolfsonmicro.com>
+Signed-off-by: Graeme Gregory <gg@opensource.wolfsonmicro.com>
+Signed-off-by: Mike Arthur <mike.arthur@wolfsonmicro.com>
+Signed-off-by: Mark Brown <broonie@opensource.wolfsonmicro.com>
+Cc: Dmitry Baryshkov <dbaryshkov@gmail.com>
+Cc: Stanley Cai <stanley.cai@intel.com>
+Cc: Rodolfo Giometti <giometti@enneenne.com>
+Cc: Russell King <rmk@arm.linux.org.uk>
+Cc: Marc Kleine-Budde <mkl@pengutronix.de>
+Cc: Ian Molton <spyro@f2s.com>
+Cc: Vince Sanders <vince@kyllikki.org>
+Cc: Andrew Zabolotny <zap@homelink.ru>
+---
+ drivers/input/touchscreen/wm9705.c |  352 ++++++++++++++++++++++++++++++++++++
+ 1 files changed, 352 insertions(+), 0 deletions(-)
+ create mode 100644 drivers/input/touchscreen/wm9705.c
+
+diff --git a/drivers/input/touchscreen/wm9705.c b/drivers/input/touchscreen/wm9705.c
+new file mode 100644
+index 0000000..f185104
+--- /dev/null
++++ b/drivers/input/touchscreen/wm9705.c
+@@ -0,0 +1,352 @@
++/*
++ * wm9705.c  --  Codec driver for Wolfson WM9705 AC97 Codec.
++ *
++ * Copyright 2003, 2004, 2005, 2006, 2007 Wolfson Microelectronics PLC.
++ * Author: Liam Girdwood
++ *         liam.girdwood@wolfsonmicro.com or linux@wolfsonmicro.com
++ * Parts Copyright : Ian Molton <spyro@f2s.com>
++ *                   Andrew Zabolotny <zap@homelink.ru>
++ *                   Russell King <rmk@arm.linux.org.uk>
++ *
++ *  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/moduleparam.h>
++#include <linux/version.h>
++#include <linux/kernel.h>
++#include <linux/input.h>
++#include <linux/delay.h>
++#include <linux/bitops.h>
++#include <linux/wm97xx.h>
++
++#define TS_NAME                       "wm97xx"
++#define WM9705_VERSION                "0.62"
++#define DEFAULT_PRESSURE      0xb0c0
++
++/*
++ * Module parameters
++ */
++
++/*
++ * Set current used for pressure measurement.
++ *
++ * Set pil = 2 to use 400uA
++ *     pil = 1 to use 200uA and
++ *     pil = 0 to disable pressure measurement.
++ *
++ * This is used to increase the range of values returned by the adc
++ * when measureing touchpanel pressure.
++ */
++static int pil;
++module_param(pil, int, 0);
++MODULE_PARM_DESC(pil, "Set current used for pressure measurement.");
++
++/*
++ * Set threshold for pressure measurement.
++ *
++ * Pen down pressure below threshold is ignored.
++ */
++static int pressure = DEFAULT_PRESSURE & 0xfff;
++module_param(pressure, int, 0);
++MODULE_PARM_DESC(pressure, "Set threshold for pressure measurement.");
++
++/*
++ * Set adc sample delay.
++ *
++ * For accurate touchpanel measurements, some settling time may be
++ * required between the switch matrix applying a voltage across the
++ * touchpanel plate and the ADC sampling the signal.
++ *
++ * This delay can be set by setting delay = n, where n is the array
++ * position of the delay in the array delay_table below.
++ * Long delays > 1ms are supported for completeness, but are not
++ * recommended.
++ */
++static int delay = 4;
++module_param(delay, int, 0);
++MODULE_PARM_DESC(delay, "Set adc sample delay.");
++
++/*
++ * Pen detect comparator threshold.
++ *
++ * 0 to Vmid in 15 steps, 0 = use zero power comparator with Vmid threshold
++ * i.e. 1 =  Vmid/15 threshold
++ *      15 =  Vmid/1 threshold
++ *
++ * Adjust this value if you are having problems with pen detect not
++ * detecting any down events.
++ */
++static int pdd = 8;
++module_param(pdd, int, 0);
++MODULE_PARM_DESC(pdd, "Set pen detect comparator threshold");
++
++/*
++ * Set adc mask function.
++ *
++ * Sources of glitch noise, such as signals driving an LCD display, may feed
++ * through to the touch screen plates and affect measurement accuracy. In
++ * order to minimise this, a signal may be applied to the MASK pin to delay or
++ * synchronise the sampling.
++ *
++ * 0 = No delay or sync
++ * 1 = High on pin stops conversions
++ * 2 = Edge triggered, edge on pin delays conversion by delay param (above)
++ * 3 = Edge triggered, edge on pin starts conversion after delay param
++ */
++static int mask;
++module_param(mask, int, 0);
++MODULE_PARM_DESC(mask, "Set adc mask function.");
++
++/*
++ * ADC sample delay times in uS
++ */
++static const int delay_table[] = {
++      21,    /* 1 AC97 Link frames */
++      42,    /* 2                  */
++      84,    /* 4                  */
++      167,   /* 8                  */
++      333,   /* 16                 */
++      667,   /* 32                 */
++      1000,  /* 48                 */
++      1333,  /* 64                 */
++      2000,  /* 96                 */
++      2667,  /* 128                */
++      3333,  /* 160                */
++      4000,  /* 192                */
++      4667,  /* 224                */
++      5333,  /* 256                */
++      6000,  /* 288                */
++      0      /* No delay, switch matrix always on */
++};
++
++/*
++ * Delay after issuing a POLL command.
++ *
++ * The delay is 3 AC97 link frames + the touchpanel settling delay
++ */
++static inline void poll_delay(int d)
++{
++      udelay(3 * AC97_LINK_FRAME + delay_table[d]);
++}
++
++/*
++ * set up the physical settings of the WM9705
++ */
++static void wm9705_phy_init(struct wm97xx *wm)
++{
++      u16 dig1 = 0, dig2 = WM97XX_RPR;
++
++      /*
++      * mute VIDEO and AUX as they share X and Y touchscreen
++      * inputs on the WM9705
++      */
++      wm97xx_reg_write(wm, AC97_AUX, 0x8000);
++      wm97xx_reg_write(wm, AC97_VIDEO, 0x8000);
++
++      /* touchpanel pressure current*/
++      if (pil == 2) {
++              dig2 |= WM9705_PIL;
++              dev_dbg(wm->dev,
++                      "setting pressure measurement current to 400uA.");
++      } else if (pil)
++              dev_dbg(wm->dev,
++                      "setting pressure measurement current to 200uA.");
++      if (!pil)
++              pressure = 0;
++
++      /* polling mode sample settling delay */
++      if (delay != 4) {
++              if (delay < 0 || delay > 15) {
++                      dev_dbg(wm->dev, "supplied delay out of range.");
++                      delay = 4;
++              }
++      }
++      dig1 &= 0xff0f;
++      dig1 |= WM97XX_DELAY(delay);
++      dev_dbg(wm->dev, "setting adc sample delay to %d u Secs.",
++              delay_table[delay]);
++
++      /* WM9705 pdd */
++      dig2 |= (pdd & 0x000f);
++      dev_dbg(wm->dev, "setting pdd to Vmid/%d", 1 - (pdd & 0x000f));
++
++      /* mask */
++      dig2 |= ((mask & 0x3) << 4);
++
++      wm97xx_reg_write(wm, AC97_WM97XX_DIGITISER1, dig1);
++      wm97xx_reg_write(wm, AC97_WM97XX_DIGITISER2, dig2);
++}
++
++static void wm9705_dig_enable(struct wm97xx *wm, int enable)
++{
++      if (enable) {
++              wm97xx_reg_write(wm, AC97_WM97XX_DIGITISER2,
++                               wm->dig[2] | WM97XX_PRP_DET_DIG);
++              wm97xx_reg_read(wm, AC97_WM97XX_DIGITISER_RD); /* dummy read */
++      } else
++              wm97xx_reg_write(wm, AC97_WM97XX_DIGITISER2,
++                               wm->dig[2] & ~WM97XX_PRP_DET_DIG);
++}
++
++static void wm9705_aux_prepare(struct wm97xx *wm)
++{
++      memcpy(wm->dig_save, wm->dig, sizeof(wm->dig));
++      wm97xx_reg_write(wm, AC97_WM97XX_DIGITISER1, 0);
++      wm97xx_reg_write(wm, AC97_WM97XX_DIGITISER2, WM97XX_PRP_DET_DIG);
++}
++
++static void wm9705_dig_restore(struct wm97xx *wm)
++{
++      wm97xx_reg_write(wm, AC97_WM97XX_DIGITISER1, wm->dig_save[1]);
++      wm97xx_reg_write(wm, AC97_WM97XX_DIGITISER2, wm->dig_save[2]);
++}
++
++static inline int is_pden(struct wm97xx *wm)
++{
++      return wm->dig[2] & WM9705_PDEN;
++}
++
++/*
++ * Read a sample from the WM9705 adc in polling mode.
++ */
++static int wm9705_poll_sample(struct wm97xx *wm, int adcsel, int *sample)
++{
++      int timeout = 5 * delay;
++
++      if (!wm->pen_probably_down) {
++              u16 data = wm97xx_reg_read(wm, AC97_WM97XX_DIGITISER_RD);
++              if (!(data & WM97XX_PEN_DOWN))
++                      return RC_PENUP;
++              wm->pen_probably_down = 1;
++      }
++
++      /* set up digitiser */
++      if (adcsel & 0x8000)
++              adcsel = ((adcsel & 0x7fff) + 3) << 12;
++
++      if (wm->mach_ops && wm->mach_ops->pre_sample)
++              wm->mach_ops->pre_sample(adcsel);
++      wm97xx_reg_write(wm, AC97_WM97XX_DIGITISER1,
++                       adcsel | WM97XX_POLL | WM97XX_DELAY(delay));
++
++      /* wait 3 AC97 time slots + delay for conversion */
++      poll_delay(delay);
++
++      /* wait for POLL to go low */
++      while ((wm97xx_reg_read(wm, AC97_WM97XX_DIGITISER1) & WM97XX_POLL)
++             && timeout) {
++              udelay(AC97_LINK_FRAME);
++              timeout--;
++      }
++
++      if (timeout <= 0) {
++              /* If PDEN is set, we can get a timeout when pen goes up */
++              if (is_pden(wm))
++                      wm->pen_probably_down = 0;
++              else
++                      dev_dbg(wm->dev, "adc sample timeout");
++              return RC_PENUP;
++      }
++
++      *sample = wm97xx_reg_read(wm, AC97_WM97XX_DIGITISER_RD);
++      if (wm->mach_ops && wm->mach_ops->post_sample)
++              wm->mach_ops->post_sample(adcsel);
++
++      /* check we have correct sample */
++      if ((*sample & WM97XX_ADCSEL_MASK) != adcsel) {
++              dev_dbg(wm->dev, "adc wrong sample, read %x got %x", adcsel,
++              *sample & WM97XX_ADCSEL_MASK);
++              return RC_PENUP;
++      }
++
++      if (!(*sample & WM97XX_PEN_DOWN)) {
++              wm->pen_probably_down = 0;
++              return RC_PENUP;
++      }
++
++      return RC_VALID;
++}
++
++/*
++ * Sample the WM9705 touchscreen in polling mode
++ */
++static int wm9705_poll_touch(struct wm97xx *wm, struct wm97xx_data *data)
++{
++      int rc;
++
++      rc = wm9705_poll_sample(wm, WM97XX_ADCSEL_X, &data->x);
++      if (rc != RC_VALID)
++              return rc;
++      rc = wm9705_poll_sample(wm, WM97XX_ADCSEL_Y, &data->y);
++      if (rc != RC_VALID)
++              return rc;
++      if (pil) {
++              rc = wm9705_poll_sample(wm, WM97XX_ADCSEL_PRES, &data->p);
++              if (rc != RC_VALID)
++                      return rc;
++      } else
++              data->p = DEFAULT_PRESSURE;
++
++      return RC_VALID;
++}
++
++/*
++ * Enable WM9705 continuous mode, i.e. touch data is streamed across
++ * an AC97 slot
++ */
++static int wm9705_acc_enable(struct wm97xx *wm, int enable)
++{
++      u16 dig1, dig2;
++      int ret = 0;
++
++      dig1 = wm->dig[1];
++      dig2 = wm->dig[2];
++
++      if (enable) {
++              /* continous mode */
++              if (wm->mach_ops->acc_startup &&
++                  (ret = wm->mach_ops->acc_startup(wm)) < 0)
++                      return ret;
++              dig1 &= ~(WM97XX_CM_RATE_MASK | WM97XX_ADCSEL_MASK |
++                        WM97XX_DELAY_MASK | WM97XX_SLT_MASK);
++              dig1 |= WM97XX_CTC | WM97XX_COO | WM97XX_SLEN |
++                      WM97XX_DELAY(delay) |
++                      WM97XX_SLT(wm->acc_slot) |
++                      WM97XX_RATE(wm->acc_rate);
++              if (pil)
++                      dig1 |= WM97XX_ADCSEL_PRES;
++              dig2 |= WM9705_PDEN;
++      } else {
++              dig1 &= ~(WM97XX_CTC | WM97XX_COO | WM97XX_SLEN);
++              dig2 &= ~WM9705_PDEN;
++              if (wm->mach_ops->acc_shutdown)
++                      wm->mach_ops->acc_shutdown(wm);
++      }
++
++      wm97xx_reg_write(wm, AC97_WM97XX_DIGITISER1, dig1);
++      wm97xx_reg_write(wm, AC97_WM97XX_DIGITISER2, dig2);
++      return ret;
++}
++
++struct wm97xx_codec_drv wm9705_codec = {
++      .id =   WM9705_ID2,
++      .name = "wm9705",
++      .poll_sample = wm9705_poll_sample,
++      .poll_touch = wm9705_poll_touch,
++      .acc_enable = wm9705_acc_enable,
++      .phy_init = wm9705_phy_init,
++      .dig_enable = wm9705_dig_enable,
++      .dig_restore = wm9705_dig_restore,
++      .aux_prepare = wm9705_aux_prepare,
++};
++EXPORT_SYMBOL_GPL(wm9705_codec);
++
++/* Module information */
++MODULE_AUTHOR("Liam Girdwood <liam.girdwood@wolfsonmicro.com>");
++MODULE_DESCRIPTION("WM9705 Touch Screen Driver");
++MODULE_LICENSE("GPL");
+-- 
+1.5.3.8
+
diff --git a/packages/kexecboot/linux-kexecboot-2.6.24/tosa/0032-Add-chip-driver-for-WM9712-touchscreen.patch b/packages/kexecboot/linux-kexecboot-2.6.24/tosa/0032-Add-chip-driver-for-WM9712-touchscreen.patch
new file mode 100644 (file)
index 0000000..6265910
--- /dev/null
@@ -0,0 +1,492 @@
+From b2640063b8321bdfb324c00d5f0c3366ac31696b Mon Sep 17 00:00:00 2001
+From: Mark Brown <broonie@opensource.wolfsonmicro.com>
+Date: Sat, 26 Jan 2008 21:14:19 +0300
+Subject: [PATCH 32/64] Add chip driver for WM9712 touchscreen
+
+Signed-off-by: Liam Girdwood <liam.girdwood@wolfsonmicro.com>
+Signed-off-by: Graeme Gregory <gg@opensource.wolfsonmicro.com>
+Signed-off-by: Mike Arthur <mike.arthur@wolfsonmicro.com>
+Signed-off-by: Mark Brown <broonie@opensource.wolfsonmicro.com>
+Cc: Dmitry Baryshkov <dbaryshkov@gmail.com>
+Cc: Stanley Cai <stanley.cai@intel.com>
+Cc: Rodolfo Giometti <giometti@enneenne.com>
+Cc: Russell King <rmk@arm.linux.org.uk>
+Cc: Marc Kleine-Budde <mkl@pengutronix.de>
+Cc: Ian Molton <spyro@f2s.com>
+Cc: Vince Sanders <vince@kyllikki.org>
+Cc: Andrew Zabolotny <zap@homelink.ru>
+---
+ drivers/input/touchscreen/wm9712.c |  461 ++++++++++++++++++++++++++++++++++++
+ 1 files changed, 461 insertions(+), 0 deletions(-)
+ create mode 100644 drivers/input/touchscreen/wm9712.c
+
+diff --git a/drivers/input/touchscreen/wm9712.c b/drivers/input/touchscreen/wm9712.c
+new file mode 100644
+index 0000000..eaab326
+--- /dev/null
++++ b/drivers/input/touchscreen/wm9712.c
+@@ -0,0 +1,461 @@
++/*
++ * wm9712.c  --  Codec driver for Wolfson WM9712 AC97 Codecs.
++ *
++ * Copyright 2003, 2004, 2005, 2006, 2007 Wolfson Microelectronics PLC.
++ * Author: Liam Girdwood
++ *         liam.girdwood@wolfsonmicro.com or linux@wolfsonmicro.com
++ * Parts Copyright : Ian Molton <spyro@f2s.com>
++ *                   Andrew Zabolotny <zap@homelink.ru>
++ *                   Russell King <rmk@arm.linux.org.uk>
++ *
++ *  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/moduleparam.h>
++#include <linux/version.h>
++#include <linux/kernel.h>
++#include <linux/input.h>
++#include <linux/delay.h>
++#include <linux/bitops.h>
++#include <linux/wm97xx.h>
++
++#define TS_NAME                       "wm97xx"
++#define WM9712_VERSION                "0.61"
++#define DEFAULT_PRESSURE      0xb0c0
++
++/*
++ * Module parameters
++ */
++
++/*
++ * Set internal pull up for pen detect.
++ *
++ * Pull up is in the range 1.02k (least sensitive) to 64k (most sensitive)
++ * i.e. pull up resistance = 64k Ohms / rpu.
++ *
++ * Adjust this value if you are having problems with pen detect not
++ * detecting any down event.
++ */
++static int rpu = 8;
++module_param(rpu, int, 0);
++MODULE_PARM_DESC(rpu, "Set internal pull up resitor for pen detect.");
++
++/*
++ * Set current used for pressure measurement.
++ *
++ * Set pil = 2 to use 400uA
++ *     pil = 1 to use 200uA and
++ *     pil = 0 to disable pressure measurement.
++ *
++ * This is used to increase the range of values returned by the adc
++ * when measureing touchpanel pressure.
++ */
++static int pil;
++module_param(pil, int, 0);
++MODULE_PARM_DESC(pil, "Set current used for pressure measurement.");
++
++/*
++ * Set threshold for pressure measurement.
++ *
++ * Pen down pressure below threshold is ignored.
++ */
++static int pressure = DEFAULT_PRESSURE & 0xfff;
++module_param(pressure, int, 0);
++MODULE_PARM_DESC(pressure, "Set threshold for pressure measurement.");
++
++/*
++ * Set adc sample delay.
++ *
++ * For accurate touchpanel measurements, some settling time may be
++ * required between the switch matrix applying a voltage across the
++ * touchpanel plate and the ADC sampling the signal.
++ *
++ * This delay can be set by setting delay = n, where n is the array
++ * position of the delay in the array delay_table below.
++ * Long delays > 1ms are supported for completeness, but are not
++ * recommended.
++ */
++static int delay = 3;
++module_param(delay, int, 0);
++MODULE_PARM_DESC(delay, "Set adc sample delay.");
++
++/*
++ * Set five_wire = 1 to use a 5 wire touchscreen.
++ *
++ * NOTE: Five wire mode does not allow for readback of pressure.
++ */
++static int five_wire;
++module_param(five_wire, int, 0);
++MODULE_PARM_DESC(five_wire, "Set to '1' to use 5-wire touchscreen.");
++
++/*
++ * Set adc mask function.
++ *
++ * Sources of glitch noise, such as signals driving an LCD display, may feed
++ * through to the touch screen plates and affect measurement accuracy. In
++ * order to minimise this, a signal may be applied to the MASK pin to delay or
++ * synchronise the sampling.
++ *
++ * 0 = No delay or sync
++ * 1 = High on pin stops conversions
++ * 2 = Edge triggered, edge on pin delays conversion by delay param (above)
++ * 3 = Edge triggered, edge on pin starts conversion after delay param
++ */
++static int mask;
++module_param(mask, int, 0);
++MODULE_PARM_DESC(mask, "Set adc mask function.");
++
++/*
++ * Coordinate Polling Enable.
++ *
++ * Set to 1 to enable coordinate polling. e.g. x,y[,p] is sampled together
++ * for every poll.
++ */
++static int coord;
++module_param(coord, int, 0);
++MODULE_PARM_DESC(coord, "Polling coordinate mode");
++
++/*
++ * ADC sample delay times in uS
++ */
++static const int delay_table[] = {
++      21,    /* 1 AC97 Link frames */
++      42,    /* 2 */
++      84,    /* 4 */
++      167,   /* 8 */
++      333,   /* 16 */
++      667,   /* 32 */
++      1000,  /* 48 */
++      1333,  /* 64 */
++      2000,  /* 96 */
++      2667,  /* 128 */
++      3333,  /* 160 */
++      4000,  /* 192 */
++      4667,  /* 224 */
++      5333,  /* 256 */
++      6000,  /* 288 */
++      0      /* No delay, switch matrix always on */
++};
++
++/*
++ * Delay after issuing a POLL command.
++ *
++ * The delay is 3 AC97 link frames + the touchpanel settling delay
++ */
++static inline void poll_delay(int d)
++{
++      udelay(3 * AC97_LINK_FRAME + delay_table[d]);
++}
++
++/*
++ * set up the physical settings of the WM9712
++ */
++static void wm9712_phy_init(struct wm97xx *wm)
++{
++      u16 dig1 = 0;
++      u16 dig2 = WM97XX_RPR | WM9712_RPU(1);
++
++      /* WM9712 rpu */
++      if (rpu) {
++              dig2 &= 0xffc0;
++              dig2 |= WM9712_RPU(rpu);
++              dev_dbg(wm->dev, "setting pen detect pull-up to %d Ohms",
++                      64000 / rpu);
++      }
++
++      /* touchpanel pressure current*/
++      if (pil == 2) {
++              dig2 |= WM9712_PIL;
++              dev_dbg(wm->dev,
++                      "setting pressure measurement current to 400uA.");
++      } else if (pil)
++              dev_dbg(wm->dev,
++                      "setting pressure measurement current to 200uA.");
++      if (!pil)
++              pressure = 0;
++
++      /* WM9712 five wire */
++      if (five_wire) {
++              dig2 |= WM9712_45W;
++              dev_dbg(wm->dev, "setting 5-wire touchscreen mode.");
++      }
++
++      /* polling mode sample settling delay */
++      if (delay < 0 || delay > 15) {
++              dev_dbg(wm->dev, "supplied delay out of range.");
++              delay = 4;
++      }
++      dig1 &= 0xff0f;
++      dig1 |= WM97XX_DELAY(delay);
++      dev_dbg(wm->dev, "setting adc sample delay to %d u Secs.",
++              delay_table[delay]);
++
++      /* mask */
++      dig2 |= ((mask & 0x3) << 6);
++      if (mask) {
++              u16 reg;
++              /* Set GPIO4 as Mask Pin*/
++              reg = wm97xx_reg_read(wm, AC97_MISC_AFE);
++              wm97xx_reg_write(wm, AC97_MISC_AFE, reg | WM97XX_GPIO_4);
++              reg = wm97xx_reg_read(wm, AC97_GPIO_CFG);
++              wm97xx_reg_write(wm, AC97_GPIO_CFG, reg | WM97XX_GPIO_4);
++      }
++
++      /* wait - coord mode */
++      if (coord)
++              dig2 |= WM9712_WAIT;
++
++      wm97xx_reg_write(wm, AC97_WM97XX_DIGITISER1, dig1);
++      wm97xx_reg_write(wm, AC97_WM97XX_DIGITISER2, dig2);
++}
++
++static void wm9712_dig_enable(struct wm97xx *wm, int enable)
++{
++      u16 dig2 = wm->dig[2];
++
++      if (enable) {
++              wm97xx_reg_write(wm, AC97_WM97XX_DIGITISER2,
++                               dig2 | WM97XX_PRP_DET_DIG);
++              wm97xx_reg_read(wm, AC97_WM97XX_DIGITISER_RD); /* dummy read */
++      } else
++              wm97xx_reg_write(wm, AC97_WM97XX_DIGITISER2,
++                               dig2 & ~WM97XX_PRP_DET_DIG);
++}
++
++static void wm9712_aux_prepare(struct wm97xx *wm)
++{
++      memcpy(wm->dig_save, wm->dig, sizeof(wm->dig));
++      wm97xx_reg_write(wm, AC97_WM97XX_DIGITISER1, 0);
++      wm97xx_reg_write(wm, AC97_WM97XX_DIGITISER2, WM97XX_PRP_DET_DIG);
++}
++
++static void wm9712_dig_restore(struct wm97xx *wm)
++{
++      wm97xx_reg_write(wm, AC97_WM97XX_DIGITISER1, wm->dig_save[1]);
++      wm97xx_reg_write(wm, AC97_WM97XX_DIGITISER2, wm->dig_save[2]);
++}
++
++static inline int is_pden(struct wm97xx *wm)
++{
++      return wm->dig[2] & WM9712_PDEN;
++}
++
++/*
++ * Read a sample from the WM9712 adc in polling mode.
++ */
++static int wm9712_poll_sample(struct wm97xx *wm, int adcsel, int *sample)
++{
++      int timeout = 5 * delay;
++
++      if (!wm->pen_probably_down) {
++              u16 data = wm97xx_reg_read(wm, AC97_WM97XX_DIGITISER_RD);
++              if (!(data & WM97XX_PEN_DOWN))
++                      return RC_PENUP;
++              wm->pen_probably_down = 1;
++      }
++
++      /* set up digitiser */
++      if (adcsel & 0x8000)
++              adcsel = ((adcsel & 0x7fff) + 3) << 12;
++
++      if (wm->mach_ops && wm->mach_ops->pre_sample)
++              wm->mach_ops->pre_sample(adcsel);
++      wm97xx_reg_write(wm, AC97_WM97XX_DIGITISER1,
++                       adcsel | WM97XX_POLL | WM97XX_DELAY(delay));
++
++      /* wait 3 AC97 time slots + delay for conversion */
++      poll_delay(delay);
++
++      /* wait for POLL to go low */
++      while ((wm97xx_reg_read(wm, AC97_WM97XX_DIGITISER1) & WM97XX_POLL)
++             && timeout) {
++              udelay(AC97_LINK_FRAME);
++              timeout--;
++      }
++
++      if (timeout <= 0) {
++              /* If PDEN is set, we can get a timeout when pen goes up */
++              if (is_pden(wm))
++                      wm->pen_probably_down = 0;
++              else
++                      dev_dbg(wm->dev, "adc sample timeout");
++              return RC_PENUP;
++      }
++
++      *sample = wm97xx_reg_read(wm, AC97_WM97XX_DIGITISER_RD);
++      if (wm->mach_ops && wm->mach_ops->post_sample)
++              wm->mach_ops->post_sample(adcsel);
++
++      /* check we have correct sample */
++      if ((*sample & WM97XX_ADCSEL_MASK) != adcsel) {
++              dev_dbg(wm->dev, "adc wrong sample, read %x got %x", adcsel,
++              *sample & WM97XX_ADCSEL_MASK);
++              return RC_PENUP;
++      }
++
++      if (!(*sample & WM97XX_PEN_DOWN)) {
++              wm->pen_probably_down = 0;
++              return RC_PENUP;
++      }
++
++      return RC_VALID;
++}
++
++/*
++ * Read a coord from the WM9712 adc in polling mode.
++ */
++static int wm9712_poll_coord(struct wm97xx *wm, struct wm97xx_data *data)
++{
++      int timeout = 5 * delay;
++
++      if (!wm->pen_probably_down) {
++              u16 data_rd = wm97xx_reg_read(wm, AC97_WM97XX_DIGITISER_RD);
++              if (!(data_rd & WM97XX_PEN_DOWN))
++                      return RC_PENUP;
++              wm->pen_probably_down = 1;
++      }
++
++      /* set up digitiser */
++      if (wm->mach_ops && wm->mach_ops->pre_sample)
++              wm->mach_ops->pre_sample(WM97XX_ADCSEL_X | WM97XX_ADCSEL_Y);
++
++      wm97xx_reg_write(wm, AC97_WM97XX_DIGITISER1,
++              WM97XX_COO | WM97XX_POLL | WM97XX_DELAY(delay));
++
++      /* wait 3 AC97 time slots + delay for conversion and read x */
++      poll_delay(delay);
++      data->x = wm97xx_reg_read(wm, AC97_WM97XX_DIGITISER_RD);
++      /* wait for POLL to go low */
++      while ((wm97xx_reg_read(wm, AC97_WM97XX_DIGITISER1) & WM97XX_POLL)
++             && timeout) {
++              udelay(AC97_LINK_FRAME);
++              timeout--;
++      }
++
++      if (timeout <= 0) {
++              /* If PDEN is set, we can get a timeout when pen goes up */
++              if (is_pden(wm))
++                      wm->pen_probably_down = 0;
++              else
++                      dev_dbg(wm->dev, "adc sample timeout");
++              return RC_PENUP;
++      }
++
++      /* read back y data */
++      data->y = wm97xx_reg_read(wm, AC97_WM97XX_DIGITISER_RD);
++      if (pil)
++              data->p = wm97xx_reg_read(wm, AC97_WM97XX_DIGITISER_RD);
++      else
++              data->p = DEFAULT_PRESSURE;
++
++      if (wm->mach_ops && wm->mach_ops->post_sample)
++              wm->mach_ops->post_sample(WM97XX_ADCSEL_X | WM97XX_ADCSEL_Y);
++
++      /* check we have correct sample */
++      if (!(data->x & WM97XX_ADCSEL_X) || !(data->y & WM97XX_ADCSEL_Y))
++              goto err;
++      if (pil && !(data->p & WM97XX_ADCSEL_PRES))
++              goto err;
++
++      if (!(data->x & WM97XX_PEN_DOWN)) {
++              wm->pen_probably_down = 0;
++              return RC_PENUP;
++      }
++      return RC_VALID;
++err:
++      return RC_PENUP;
++}
++
++/*
++ * Sample the WM9712 touchscreen in polling mode
++ */
++static int wm9712_poll_touch(struct wm97xx *wm, struct wm97xx_data *data)
++{
++      int rc;
++
++      if (coord) {
++              rc = wm9712_poll_coord(wm, data);
++              if (rc != RC_VALID)
++                      return rc;
++      } else {
++              rc = wm9712_poll_sample(wm, WM97XX_ADCSEL_X, &data->x);
++              if (rc != RC_VALID)
++                      return rc;
++
++              rc = wm9712_poll_sample(wm, WM97XX_ADCSEL_Y, &data->y);
++              if (rc != RC_VALID)
++                      return rc;
++
++              if (pil && !five_wire) {
++                      rc = wm9712_poll_sample(wm, WM97XX_ADCSEL_PRES,
++                                              &data->p);
++                      if (rc != RC_VALID)
++                              return rc;
++              } else
++                      data->p = DEFAULT_PRESSURE;
++      }
++      return RC_VALID;
++}
++
++/*
++ * Enable WM9712 continuous mode, i.e. touch data is streamed across
++ * an AC97 slot
++ */
++static int wm9712_acc_enable(struct wm97xx *wm, int enable)
++{
++      u16 dig1, dig2;
++      int ret = 0;
++
++      dig1 = wm->dig[1];
++      dig2 = wm->dig[2];
++
++      if (enable) {
++              /* continous mode */
++              if (wm->mach_ops->acc_startup) {
++                      ret = wm->mach_ops->acc_startup(wm);
++                      if (ret < 0)
++                              return ret;
++              }
++              dig1 &= ~(WM97XX_CM_RATE_MASK | WM97XX_ADCSEL_MASK |
++                      WM97XX_DELAY_MASK | WM97XX_SLT_MASK);
++              dig1 |= WM97XX_CTC | WM97XX_COO | WM97XX_SLEN |
++                      WM97XX_DELAY(delay) |
++                      WM97XX_SLT(wm->acc_slot) |
++                      WM97XX_RATE(wm->acc_rate);
++              if (pil)
++                      dig1 |= WM97XX_ADCSEL_PRES;
++              dig2 |= WM9712_PDEN;
++      } else {
++              dig1 &= ~(WM97XX_CTC | WM97XX_COO | WM97XX_SLEN);
++              dig2 &= ~WM9712_PDEN;
++              if (wm->mach_ops->acc_shutdown)
++                      wm->mach_ops->acc_shutdown(wm);
++      }
++
++      wm97xx_reg_write(wm, AC97_WM97XX_DIGITISER1, dig1);
++      wm97xx_reg_write(wm, AC97_WM97XX_DIGITISER2, dig2);
++      return 0;
++}
++
++struct wm97xx_codec_drv wm9712_codec = {
++      .id =   WM9712_ID2,
++      .name = "wm9712",
++      .poll_sample = wm9712_poll_sample,
++      .poll_touch = wm9712_poll_touch,
++      .acc_enable = wm9712_acc_enable,
++      .phy_init = wm9712_phy_init,
++      .dig_enable = wm9712_dig_enable,
++      .dig_restore = wm9712_dig_restore,
++      .aux_prepare = wm9712_aux_prepare,
++};
++EXPORT_SYMBOL_GPL(wm9712_codec);
++
++/* Module information */
++MODULE_AUTHOR("Liam Girdwood <liam.girdwood@wolfsonmicro.com>");
++MODULE_DESCRIPTION("WM9712 Touch Screen Driver");
++MODULE_LICENSE("GPL");
+-- 
+1.5.3.8
+
diff --git a/packages/kexecboot/linux-kexecboot-2.6.24/tosa/0033-Add-chip-driver-for-WM9713-touchscreen.patch b/packages/kexecboot/linux-kexecboot-2.6.24/tosa/0033-Add-chip-driver-for-WM9713-touchscreen.patch
new file mode 100644 (file)
index 0000000..a9dfa18
--- /dev/null
@@ -0,0 +1,490 @@
+From 05b2a361eedb5461e902c73ebc6e30f9916b3a8a Mon Sep 17 00:00:00 2001
+From: Mark Brown <broonie@opensource.wolfsonmicro.com>
+Date: Sat, 26 Jan 2008 21:14:19 +0300
+Subject: [PATCH 33/64] Add chip driver for WM9713 touchscreen
+
+Signed-off-by: Liam Girdwood <liam.girdwood@wolfsonmicro.com>
+Signed-off-by: Graeme Gregory <gg@opensource.wolfsonmicro.com>
+Signed-off-by: Mike Arthur <mike.arthur@wolfsonmicro.com>
+Signed-off-by: Mark Brown <broonie@opensource.wolfsonmicro.com>
+Cc: Dmitry Baryshkov <dbaryshkov@gmail.com>
+Cc: Stanley Cai <stanley.cai@intel.com>
+Cc: Rodolfo Giometti <giometti@enneenne.com>
+Cc: Russell King <rmk@arm.linux.org.uk>
+Cc: Marc Kleine-Budde <mkl@pengutronix.de>
+Cc: Ian Molton <spyro@f2s.com>
+Cc: Vince Sanders <vince@kyllikki.org>
+Cc: Andrew Zabolotny <zap@homelink.ru>
+---
+ drivers/input/touchscreen/wm9713.c |  459 ++++++++++++++++++++++++++++++++++++
+ 1 files changed, 459 insertions(+), 0 deletions(-)
+ create mode 100644 drivers/input/touchscreen/wm9713.c
+
+diff --git a/drivers/input/touchscreen/wm9713.c b/drivers/input/touchscreen/wm9713.c
+new file mode 100644
+index 0000000..5067e59
+--- /dev/null
++++ b/drivers/input/touchscreen/wm9713.c
+@@ -0,0 +1,459 @@
++/*
++ * wm9713.c  --  Codec touch driver for Wolfson WM9713 AC97 Codec.
++ *
++ * Copyright 2003, 2004, 2005, 2006, 2007, 2008 Wolfson Microelectronics PLC.
++ * Author: Liam Girdwood
++ *         liam.girdwood@wolfsonmicro.com or linux@wolfsonmicro.com
++ * Parts Copyright : Ian Molton <spyro@f2s.com>
++ *                   Andrew Zabolotny <zap@homelink.ru>
++ *                   Russell King <rmk@arm.linux.org.uk>
++ *
++ *  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/moduleparam.h>
++#include <linux/version.h>
++#include <linux/kernel.h>
++#include <linux/input.h>
++#include <linux/delay.h>
++#include <linux/bitops.h>
++#include <linux/wm97xx.h>
++
++#define TS_NAME                       "wm97xx"
++#define WM9713_VERSION                "0.53"
++#define DEFAULT_PRESSURE      0xb0c0
++
++/*
++ * Module parameters
++ */
++
++/*
++ * Set internal pull up for pen detect.
++ *
++ * Pull up is in the range 1.02k (least sensitive) to 64k (most sensitive)
++ * i.e. pull up resistance = 64k Ohms / rpu.
++ *
++ * Adjust this value if you are having problems with pen detect not
++ * detecting any down event.
++ */
++static int rpu = 8;
++module_param(rpu, int, 0);
++MODULE_PARM_DESC(rpu, "Set internal pull up resitor for pen detect.");
++
++/*
++ * Set current used for pressure measurement.
++ *
++ * Set pil = 2 to use 400uA
++ *     pil = 1 to use 200uA and
++ *     pil = 0 to disable pressure measurement.
++ *
++ * This is used to increase the range of values returned by the adc
++ * when measureing touchpanel pressure.
++ */
++static int pil;
++module_param(pil, int, 0);
++MODULE_PARM_DESC(pil, "Set current used for pressure measurement.");
++
++/*
++ * Set threshold for pressure measurement.
++ *
++ * Pen down pressure below threshold is ignored.
++ */
++static int pressure = DEFAULT_PRESSURE & 0xfff;
++module_param(pressure, int, 0);
++MODULE_PARM_DESC(pressure, "Set threshold for pressure measurement.");
++
++/*
++ * Set adc sample delay.
++ *
++ * For accurate touchpanel measurements, some settling time may be
++ * required between the switch matrix applying a voltage across the
++ * touchpanel plate and the ADC sampling the signal.
++ *
++ * This delay can be set by setting delay = n, where n is the array
++ * position of the delay in the array delay_table below.
++ * Long delays > 1ms are supported for completeness, but are not
++ * recommended.
++ */
++static int delay = 4;
++module_param(delay, int, 0);
++MODULE_PARM_DESC(delay, "Set adc sample delay.");
++
++/*
++ * Set adc mask function.
++ *
++ * Sources of glitch noise, such as signals driving an LCD display, may feed
++ * through to the touch screen plates and affect measurement accuracy. In
++ * order to minimise this, a signal may be applied to the MASK pin to delay or
++ * synchronise the sampling.
++ *
++ * 0 = No delay or sync
++ * 1 = High on pin stops conversions
++ * 2 = Edge triggered, edge on pin delays conversion by delay param (above)
++ * 3 = Edge triggered, edge on pin starts conversion after delay param
++ */
++static int mask;
++module_param(mask, int, 0);
++MODULE_PARM_DESC(mask, "Set adc mask function.");
++
++/*
++ * Coordinate Polling Enable.
++ *
++ * Set to 1 to enable coordinate polling. e.g. x,y[,p] is sampled together
++ * for every poll.
++ */
++static int coord;
++module_param(coord, int, 0);
++MODULE_PARM_DESC(coord, "Polling coordinate mode");
++
++/*
++ * ADC sample delay times in uS
++ */
++static const int delay_table[] = {
++      21,    /* 1 AC97 Link frames */
++      42,    /* 2 */
++      84,    /* 4 */
++      167,   /* 8 */
++      333,   /* 16 */
++      667,   /* 32 */
++      1000,  /* 48 */
++      1333,  /* 64 */
++      2000,  /* 96 */
++      2667,  /* 128 */
++      3333,  /* 160 */
++      4000,  /* 192 */
++      4667,  /* 224 */
++      5333,  /* 256 */
++      6000,  /* 288 */
++      0      /* No delay, switch matrix always on */
++};
++
++/*
++ * Delay after issuing a POLL command.
++ *
++ * The delay is 3 AC97 link frames + the touchpanel settling delay
++ */
++static inline void poll_delay(int d)
++{
++      udelay(3 * AC97_LINK_FRAME + delay_table[d]);
++}
++
++/*
++ * set up the physical settings of the WM9713
++ */
++static void wm9713_phy_init(struct wm97xx *wm)
++{
++      u16 dig1 = 0, dig2, dig3;
++
++      /* default values */
++      dig2 = WM97XX_DELAY(4) | WM97XX_SLT(5);
++      dig3 = WM9712_RPU(1);
++
++      /* rpu */
++      if (rpu) {
++              dig3 &= 0xffc0;
++              dig3 |= WM9712_RPU(rpu);
++              dev_info(wm->dev, "setting pen detect pull-up to %d Ohms\n",
++                       64000 / rpu);
++      }
++
++      /* touchpanel pressure */
++      if (pil == 2) {
++              dig3 |= WM9712_PIL;
++              dev_info(wm->dev,
++                       "setting pressure measurement current to 400uA.");
++      } else if (pil)
++              dev_info(wm->dev,
++                       "setting pressure measurement current to 200uA.");
++      if (!pil)
++              pressure = 0;
++
++      /* sample settling delay */
++      if (delay < 0 || delay > 15) {
++              dev_info(wm->dev, "supplied delay out of range.");
++              delay = 4;
++              dev_info(wm->dev, "setting adc sample delay to %d u Secs.",
++                       delay_table[delay]);
++      }
++      dig2 &= 0xff0f;
++      dig2 |= WM97XX_DELAY(delay);
++
++      /* mask */
++      dig3 |= ((mask & 0x3) << 4);
++      if (coord)
++              dig3 |= WM9713_WAIT;
++
++      wm->misc = wm97xx_reg_read(wm, 0x5a);
++
++      wm97xx_reg_write(wm, AC97_WM9713_DIG1, dig1);
++      wm97xx_reg_write(wm, AC97_WM9713_DIG2, dig2);
++      wm97xx_reg_write(wm, AC97_WM9713_DIG3, dig3);
++      wm97xx_reg_write(wm, AC97_GPIO_STICKY, 0x0);
++}
++
++static void wm9713_dig_enable(struct wm97xx *wm, int enable)
++{
++      u16 val;
++
++      if (enable) {
++              val = wm97xx_reg_read(wm, AC97_EXTENDED_MID);
++              wm97xx_reg_write(wm, AC97_EXTENDED_MID, val & 0x7fff);
++              wm97xx_reg_write(wm, AC97_WM9713_DIG3, wm->dig[2] |
++                               WM97XX_PRP_DET_DIG);
++              wm97xx_reg_read(wm, AC97_WM97XX_DIGITISER_RD); /* dummy read */
++      } else {
++              wm97xx_reg_write(wm, AC97_WM9713_DIG3, wm->dig[2] &
++                                      ~WM97XX_PRP_DET_DIG);
++              val = wm97xx_reg_read(wm, AC97_EXTENDED_MID);
++              wm97xx_reg_write(wm, AC97_EXTENDED_MID, val | 0x8000);
++      }
++}
++
++static void wm9713_dig_restore(struct wm97xx *wm)
++{
++      wm97xx_reg_write(wm, AC97_WM9713_DIG1, wm->dig_save[0]);
++      wm97xx_reg_write(wm, AC97_WM9713_DIG2, wm->dig_save[1]);
++      wm97xx_reg_write(wm, AC97_WM9713_DIG3, wm->dig_save[2]);
++}
++
++static void wm9713_aux_prepare(struct wm97xx *wm)
++{
++      memcpy(wm->dig_save, wm->dig, sizeof(wm->dig));
++      wm97xx_reg_write(wm, AC97_WM9713_DIG1, 0);
++      wm97xx_reg_write(wm, AC97_WM9713_DIG2, 0);
++      wm97xx_reg_write(wm, AC97_WM9713_DIG3, WM97XX_PRP_DET_DIG);
++}
++
++static inline int is_pden(struct wm97xx *wm)
++{
++      return wm->dig[2] & WM9713_PDEN;
++}
++
++/*
++ * Read a sample from the WM9713 adc in polling mode.
++ */
++static int wm9713_poll_sample(struct wm97xx *wm, int adcsel, int *sample)
++{
++      u16 dig1;
++      int timeout = 5 * delay;
++
++      if (!wm->pen_probably_down) {
++              u16 data = wm97xx_reg_read(wm, AC97_WM97XX_DIGITISER_RD);
++              if (!(data & WM97XX_PEN_DOWN))
++                      return RC_PENUP;
++              wm->pen_probably_down = 1;
++      }
++
++      /* set up digitiser */
++      if (adcsel & 0x8000)
++              adcsel = 1 << ((adcsel & 0x7fff) + 3);
++
++      dig1 = wm97xx_reg_read(wm, AC97_WM9713_DIG1);
++      dig1 &= ~WM9713_ADCSEL_MASK;
++
++      if (wm->mach_ops && wm->mach_ops->pre_sample)
++              wm->mach_ops->pre_sample(adcsel);
++      wm97xx_reg_write(wm, AC97_WM9713_DIG1, dig1 | adcsel | WM9713_POLL);
++
++      /* wait 3 AC97 time slots + delay for conversion */
++      poll_delay(delay);
++
++      /* wait for POLL to go low */
++      while ((wm97xx_reg_read(wm, AC97_WM9713_DIG1) & WM9713_POLL) &&
++              timeout) {
++              udelay(AC97_LINK_FRAME);
++              timeout--;
++      }
++
++      if (timeout <= 0) {
++              /* If PDEN is set, we can get a timeout when pen goes up */
++              if (is_pden(wm))
++                      wm->pen_probably_down = 0;
++              else
++                      dev_dbg(wm->dev, "adc sample timeout");
++              return RC_PENUP;
++      }
++
++      *sample = wm97xx_reg_read(wm, AC97_WM97XX_DIGITISER_RD);
++      if (wm->mach_ops && wm->mach_ops->post_sample)
++              wm->mach_ops->post_sample(adcsel);
++
++      /* check we have correct sample */
++      if ((*sample & WM97XX_ADCSRC_MASK) != ffs(adcsel >> 1) << 12) {
++              dev_dbg(wm->dev, "adc wrong sample, read %x got %x", adcsel,
++                      *sample & WM97XX_ADCSRC_MASK);
++              return RC_PENUP;
++      }
++
++      if (!(*sample & WM97XX_PEN_DOWN)) {
++              wm->pen_probably_down = 0;
++              return RC_PENUP;
++      }
++
++      return RC_VALID;
++}
++
++/*
++ * Read a coordinate from the WM9713 adc in polling mode.
++ */
++static int wm9713_poll_coord(struct wm97xx *wm, struct wm97xx_data *data)
++{
++      u16 dig1;
++      int timeout = 5 * delay;
++
++      if (!wm->pen_probably_down) {
++              u16 data = wm97xx_reg_read(wm, AC97_WM97XX_DIGITISER_RD);
++              if (!(data & WM97XX_PEN_DOWN))
++                      return RC_PENUP;
++              wm->pen_probably_down = 1;
++      }
++
++      /* set up digitiser */
++      dig1 = wm97xx_reg_read(wm, AC97_WM9713_DIG1);
++      dig1 &= ~WM9713_ADCSEL_MASK;
++      if (pil)
++              dig1 |= WM97XX_ADCSEL_PRES;
++
++      if (wm->mach_ops && wm->mach_ops->pre_sample)
++              wm->mach_ops->pre_sample(WM97XX_ADCSEL_X | WM97XX_ADCSEL_Y);
++      wm97xx_reg_write(wm, AC97_WM9713_DIG1,
++                       dig1 | WM9713_POLL | WM9713_COO);
++
++      /* wait 3 AC97 time slots + delay for conversion */
++      poll_delay(delay);
++      data->x = wm97xx_reg_read(wm, AC97_WM97XX_DIGITISER_RD);
++      /* wait for POLL to go low */
++      while ((wm97xx_reg_read(wm, AC97_WM9713_DIG1) & WM9713_POLL)
++             && timeout) {
++              udelay(AC97_LINK_FRAME);
++              timeout--;
++      }
++
++      if (timeout <= 0) {
++              /* If PDEN is set, we can get a timeout when pen goes up */
++              if (is_pden(wm))
++                      wm->pen_probably_down = 0;
++              else
++                      dev_dbg(wm->dev, "adc sample timeout");
++              return RC_PENUP;
++      }
++
++      /* read back data */
++      data->y = wm97xx_reg_read(wm, AC97_WM97XX_DIGITISER_RD);
++      if (pil)
++              data->p = wm97xx_reg_read(wm, AC97_WM97XX_DIGITISER_RD);
++      else
++              data->p = DEFAULT_PRESSURE;
++
++      if (wm->mach_ops && wm->mach_ops->post_sample)
++              wm->mach_ops->post_sample(WM97XX_ADCSEL_X | WM97XX_ADCSEL_Y);
++
++      /* check we have correct sample */
++      if (!(data->x & WM97XX_ADCSEL_X) || !(data->y & WM97XX_ADCSEL_Y))
++              goto err;
++      if (pil && !(data->p & WM97XX_ADCSEL_PRES))
++              goto err;
++
++      if (!(data->x & WM97XX_PEN_DOWN)) {
++              wm->pen_probably_down = 0;
++              return RC_PENUP;
++      }
++      return RC_VALID;
++err:
++      return RC_PENUP;
++}
++
++/*
++ * Sample the WM9713 touchscreen in polling mode
++ */
++static int wm9713_poll_touch(struct wm97xx *wm, struct wm97xx_data *data)
++{
++      int rc;
++
++      if (coord) {
++              rc = wm9713_poll_coord(wm, data);
++              if (rc != RC_VALID)
++                      return rc;
++      } else {
++              rc = wm9713_poll_sample(wm, WM9713_ADCSEL_X, &data->x);
++              if (rc != RC_VALID)
++                      return rc;
++              rc = wm9713_poll_sample(wm, WM9713_ADCSEL_Y, &data->y);
++              if (rc != RC_VALID)
++                      return rc;
++              if (pil) {
++                      rc = wm9713_poll_sample(wm, WM9713_ADCSEL_PRES,
++                                              &data->p);
++                      if (rc != RC_VALID)
++                              return rc;
++              } else
++                      data->p = DEFAULT_PRESSURE;
++      }
++      return RC_VALID;
++}
++
++/*
++ * Enable WM9713 continuous mode, i.e. touch data is streamed across
++ * an AC97 slot
++ */
++static int wm9713_acc_enable(struct wm97xx *wm, int enable)
++{
++      u16 dig1, dig2, dig3;
++      int ret = 0;
++
++      dig1 = wm->dig[0];
++      dig2 = wm->dig[1];
++      dig3 = wm->dig[2];
++
++      if (enable) {
++              /* continous mode */
++              if (wm->mach_ops->acc_startup &&
++                      (ret = wm->mach_ops->acc_startup(wm)) < 0)
++                      return ret;
++
++              dig1 &= ~WM9713_ADCSEL_MASK;
++              dig1 |= WM9713_CTC | WM9713_COO | WM9713_ADCSEL_X |
++                      WM9713_ADCSEL_Y;
++              if (pil)
++                      dig1 |= WM9713_ADCSEL_PRES;
++              dig2 &= ~(WM97XX_DELAY_MASK | WM97XX_SLT_MASK  |
++                      WM97XX_CM_RATE_MASK);
++              dig2 |= WM97XX_SLEN | WM97XX_DELAY(delay) |
++              WM97XX_SLT(wm->acc_slot) | WM97XX_RATE(wm->acc_rate);
++              dig3 |= WM9713_PDEN;
++      } else {
++              dig1 &= ~(WM9713_CTC | WM9713_COO);
++              dig2 &= ~WM97XX_SLEN;
++              dig3 &= ~WM9713_PDEN;
++              if (wm->mach_ops->acc_shutdown)
++                      wm->mach_ops->acc_shutdown(wm);
++      }
++
++      wm97xx_reg_write(wm, AC97_WM9713_DIG1, dig1);
++      wm97xx_reg_write(wm, AC97_WM9713_DIG2, dig2);
++      wm97xx_reg_write(wm, AC97_WM9713_DIG3, dig3);
++      return ret;
++}
++
++struct wm97xx_codec_drv wm9713_codec = {
++      .id =   WM9713_ID2,
++      .name = "wm9713",
++      .poll_sample = wm9713_poll_sample,
++      .poll_touch = wm9713_poll_touch,
++      .acc_enable = wm9713_acc_enable,
++      .phy_init = wm9713_phy_init,
++      .dig_enable = wm9713_dig_enable,
++      .dig_restore = wm9713_dig_restore,
++      .aux_prepare = wm9713_aux_prepare,
++};
++EXPORT_SYMBOL_GPL(wm9713_codec);
++
++/* Module information */
++MODULE_AUTHOR("Liam Girdwood <liam.girdwood@wolfsonmicro.com>");
++MODULE_DESCRIPTION("WM9713 Touch Screen Driver");
++MODULE_LICENSE("GPL");
+-- 
+1.5.3.8
+
diff --git a/packages/kexecboot/linux-kexecboot-2.6.24/tosa/0034-Driver-for-WM97xx-touchscreens-in-streaming-mode-on.patch b/packages/kexecboot/linux-kexecboot-2.6.24/tosa/0034-Driver-for-WM97xx-touchscreens-in-streaming-mode-on.patch
new file mode 100644 (file)
index 0000000..0391cfc
--- /dev/null
@@ -0,0 +1,329 @@
+From 821604bad5ce1ef942eeb420afd9ea2c5c92875e Mon Sep 17 00:00:00 2001
+From: Mark Brown <broonie@opensource.wolfsonmicro.com>
+Date: Sat, 26 Jan 2008 21:14:19 +0300
+Subject: [PATCH 34/64] Driver for WM97xx touchscreens in streaming mode on Mainstone
+
+Signed-off-by: Liam Girdwood <liam.girdwood@wolfsonmicro.com>
+Signed-off-by: Graeme Gregory <gg@opensource.wolfsonmicro.com>
+Signed-off-by: Mike Arthur <mike.arthur@wolfsonmicro.com>
+Signed-off-by: Mark Brown <broonie@opensource.wolfsonmicro.com>
+Cc: Dmitry Baryshkov <dbaryshkov@gmail.com>
+Cc: Stanley Cai <stanley.cai@intel.com>
+Cc: Rodolfo Giometti <giometti@enneenne.com>
+Cc: Russell King <rmk@arm.linux.org.uk>
+Cc: Marc Kleine-Budde <mkl@pengutronix.de>
+Cc: Ian Molton <spyro@f2s.com>
+Cc: Vince Sanders <vince@kyllikki.org>
+Cc: Andrew Zabolotny <zap@homelink.ru>
+---
+ drivers/input/touchscreen/mainstone-wm97xx.c |  298 ++++++++++++++++++++++++++
+ 1 files changed, 298 insertions(+), 0 deletions(-)
+ create mode 100644 drivers/input/touchscreen/mainstone-wm97xx.c
+
+diff --git a/drivers/input/touchscreen/mainstone-wm97xx.c b/drivers/input/touchscreen/mainstone-wm97xx.c
+new file mode 100644
+index 0000000..8e1c35d
+--- /dev/null
++++ b/drivers/input/touchscreen/mainstone-wm97xx.c
+@@ -0,0 +1,298 @@
++/*
++ * mainstone-wm97xx.c  --  Mainstone Continuous Touch screen driver for
++ *                         Wolfson WM97xx AC97 Codecs.
++ *
++ * Copyright 2004, 2007 Wolfson Microelectronics PLC.
++ * Author: Liam Girdwood
++ *         liam.girdwood@wolfsonmicro.com or linux@wolfsonmicro.com
++ * Parts Copyright : Ian Molton <spyro@f2s.com>
++ *                   Andrew Zabolotny <zap@homelink.ru>
++ *
++ *  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.
++ *
++ * Notes:
++ *     This is a wm97xx extended touch driver to capture touch
++ *     data in a continuous manner on the Intel XScale archictecture
++ *
++ *  Features:
++ *       - codecs supported:- WM9705, WM9712, WM9713
++ *       - processors supported:- Intel XScale PXA25x, PXA26x, PXA27x
++ *
++ */
++
++#include <linux/module.h>
++#include <linux/moduleparam.h>
++#include <linux/version.h>
++#include <linux/kernel.h>
++#include <linux/init.h>
++#include <linux/delay.h>
++#include <linux/irq.h>
++#include <linux/interrupt.h>
++#include <linux/wm97xx.h>
++#include <linux/io.h>
++#include <asm/arch/pxa-regs.h>
++
++#define VERSION               "0.13"
++
++struct continuous {
++      u16 id;    /* codec id */
++      u8 code;   /* continuous code */
++      u8 reads;  /* number of coord reads per read cycle */
++      u32 speed; /* number of coords per second */
++};
++
++#define WM_READS(sp) ((sp / HZ) + 1)
++
++static const struct continuous cinfo[] = {
++      {WM9705_ID2, 0, WM_READS(94), 94},
++      {WM9705_ID2, 1, WM_READS(188), 188},
++      {WM9705_ID2, 2, WM_READS(375), 375},
++      {WM9705_ID2, 3, WM_READS(750), 750},
++      {WM9712_ID2, 0, WM_READS(94), 94},
++      {WM9712_ID2, 1, WM_READS(188), 188},
++      {WM9712_ID2, 2, WM_READS(375), 375},
++      {WM9712_ID2, 3, WM_READS(750), 750},
++      {WM9713_ID2, 0, WM_READS(94), 94},
++      {WM9713_ID2, 1, WM_READS(120), 120},
++      {WM9713_ID2, 2, WM_READS(154), 154},
++      {WM9713_ID2, 3, WM_READS(188), 188},
++};
++
++/* continuous speed index */
++static int sp_idx;
++static u16 last, tries;
++
++/*
++ * Pen sampling frequency (Hz) in continuous mode.
++ */
++static int cont_rate = 200;
++module_param(cont_rate, int, 0);
++MODULE_PARM_DESC(cont_rate, "Sampling rate in continuous mode (Hz)");
++
++/*
++ * Pen down detection.
++ *
++ * This driver can either poll or use an interrupt to indicate a pen down
++ * event. If the irq request fails then it will fall back to polling mode.
++ */
++static int pen_int;
++module_param(pen_int, int, 0);
++MODULE_PARM_DESC(pen_int, "Pen down detection (1 = interrupt, 0 = polling)");
++
++/*
++ * Pressure readback.
++ *
++ * Set to 1 to read back pen down pressure
++ */
++static int pressure;
++module_param(pressure, int, 0);
++MODULE_PARM_DESC(pressure, "Pressure readback (1 = pressure, 0 = no pressure)");
++
++/*
++ * AC97 touch data slot.
++ *
++ * Touch screen readback data ac97 slot
++ */
++static int ac97_touch_slot = 5;
++module_param(ac97_touch_slot, int, 0);
++MODULE_PARM_DESC(ac97_touch_slot, "Touch screen data slot AC97 number");
++
++
++/* flush AC97 slot 5 FIFO on pxa machines */
++#ifdef CONFIG_PXA27x
++static void wm97xx_acc_pen_up(struct wm97xx *wm)
++{
++      set_current_state(TASK_INTERRUPTIBLE);
++      schedule_timeout(1);
++
++      while (MISR & (1 << 2))
++              MODR;
++}
++#else
++static void wm97xx_acc_pen_up(struct wm97xx *wm)
++{
++      int count = 16;
++      set_current_state(TASK_INTERRUPTIBLE);
++      schedule_timeout(1);
++
++      while (count < 16) {
++              MODR;
++              count--;
++      }
++}
++#endif
++
++static int wm97xx_acc_pen_down(struct wm97xx *wm)
++{
++      u16 x, y, p = 0x100 | WM97XX_ADCSEL_PRES;
++      int reads = 0;
++
++      /* data is never immediately available after pen down irq */
++      set_current_state(TASK_INTERRUPTIBLE);
++      schedule_timeout(1);
++
++      if (tries > 5) {
++              tries = 0;
++              return RC_PENUP;
++      }
++
++      x = MODR;
++      if (x == last) {
++              tries++;
++              return RC_AGAIN;
++      }
++      last = x;
++      do {
++              if (reads)
++                      x = MODR;
++              y = MODR;
++              if (pressure)
++                      p = MODR;
++
++              /* are samples valid */
++              if ((x & 0x7000) != WM97XX_ADCSEL_X ||
++                      (y & 0x7000) != WM97XX_ADCSEL_Y ||
++                      (p & 0x7000) != WM97XX_ADCSEL_PRES)
++                      goto up;
++
++              /* coordinate is good */
++              tries = 0;
++              input_report_abs(wm->input_dev, ABS_X, x & 0xfff);
++              input_report_abs(wm->input_dev, ABS_Y, y & 0xfff);
++              input_report_abs(wm->input_dev, ABS_PRESSURE, p & 0xfff);
++              input_sync(wm->input_dev);
++              reads++;
++      } while (reads < cinfo[sp_idx].reads);
++up:
++      return RC_PENDOWN | RC_AGAIN;
++}
++
++static int wm97xx_acc_startup(struct wm97xx *wm)
++{
++      int idx = 0;
++
++      /* check we have a codec */
++      if (wm->ac97 == NULL)
++              return -ENODEV;
++
++      /* Go you big red fire engine */
++      for (idx = 0; idx < ARRAY_SIZE(cinfo); idx++) {
++              if (wm->id != cinfo[idx].id)
++                      continue;
++              sp_idx = idx;
++              if (cont_rate <= cinfo[idx].speed)
++                      break;
++      }
++      wm->acc_rate = cinfo[sp_idx].code;
++      wm->acc_slot = ac97_touch_slot;
++      dev_info(wm->dev,
++               "mainstone accelerated touchscreen driver, %d samples/sec\n",
++               cinfo[sp_idx].speed);
++
++      /* codec specific irq config */
++      if (pen_int) {
++              switch (wm->id) {
++              case WM9705_ID2:
++                      wm->pen_irq = IRQ_GPIO(4);
++                      set_irq_type(IRQ_GPIO(4), IRQT_BOTHEDGE);
++                      break;
++              case WM9712_ID2:
++              case WM9713_ID2:
++                      /* enable pen down interrupt */
++                      /* use PEN_DOWN GPIO 13 to assert IRQ on GPIO line 2 */
++                      wm->pen_irq = MAINSTONE_AC97_IRQ;
++                      wm97xx_config_gpio(wm, WM97XX_GPIO_13, WM97XX_GPIO_IN,
++                                         WM97XX_GPIO_POL_HIGH,
++                                         WM97XX_GPIO_STICKY,
++                                         WM97XX_GPIO_WAKE);
++                      wm97xx_config_gpio(wm, WM97XX_GPIO_2, WM97XX_GPIO_OUT,
++                                         WM97XX_GPIO_POL_HIGH,
++                                         WM97XX_GPIO_NOTSTICKY,
++                                         WM97XX_GPIO_NOWAKE);
++                      break;
++              default:
++                      dev_err(wm->dev,
++                              "pen down irq not supported on this device\n");
++                      pen_int = 0;
++                      break;
++              }
++      }
++
++      return 0;
++}
++
++static void wm97xx_acc_shutdown(struct wm97xx *wm)
++{
++      /* codec specific deconfig */
++      if (pen_int) {
++              switch (wm->id & 0xffff) {
++              case WM9705_ID2:
++                      wm->pen_irq = 0;
++                      break;
++              case WM9712_ID2:
++              case WM9713_ID2:
++                      /* disable interrupt */
++                      wm->pen_irq = 0;
++                      break;
++              }
++      }
++}
++
++static void wm97xx_irq_enable(struct wm97xx *wm, int enable)
++{
++      if (enable)
++              enable_irq(wm->pen_irq);
++      else
++              disable_irq(wm->pen_irq);
++}
++
++static struct wm97xx_mach_ops mainstone_mach_ops = {
++      .acc_enabled = 1,
++      .acc_pen_up = wm97xx_acc_pen_up,
++      .acc_pen_down = wm97xx_acc_pen_down,
++      .acc_startup = wm97xx_acc_startup,
++      .acc_shutdown = wm97xx_acc_shutdown,
++      .irq_enable = wm97xx_irq_enable,
++};
++
++static int mainstone_wm97xx_probe(struct platform_device *pdev)
++{
++      struct wm97xx *wm = platform_get_drvdata(pdev);
++      return wm97xx_register_mach_ops(wm, &mainstone_mach_ops);
++}
++
++static int mainstone_wm97xx_remove(struct platform_device *pdev)
++{
++      struct wm97xx *wm = platform_get_drvdata(pdev);
++      wm97xx_unregister_mach_ops(wm);
++      return 0;
++}
++
++static struct platform_driver mainstone_wm97xx_driver = {
++      .probe = mainstone_wm97xx_probe,
++      .remove = mainstone_wm97xx_remove,
++      .driver = {
++              .name = "wm97xx-touch",
++      },
++};
++
++static int __init mainstone_wm97xx_init(void)
++{
++      return platform_driver_register(&mainstone_wm97xx_driver);
++}
++
++static void __exit mainstone_wm97xx_exit(void)
++{
++      platform_driver_unregister(&mainstone_wm97xx_driver);
++}
++
++module_init(mainstone_wm97xx_init);
++module_exit(mainstone_wm97xx_exit);
++
++/* Module information */
++MODULE_AUTHOR("Liam Girdwood <liam.girdwood@wolfsonmicro.com>");
++MODULE_DESCRIPTION("wm97xx continuous touch driver for mainstone");
++MODULE_LICENSE("GPL");
+-- 
+1.5.3.8
+
diff --git a/packages/kexecboot/linux-kexecboot-2.6.24/tosa/0035-Build-system-and-MAINTAINERS-entry-for-WM97xx-touchs.patch b/packages/kexecboot/linux-kexecboot-2.6.24/tosa/0035-Build-system-and-MAINTAINERS-entry-for-WM97xx-touchs.patch
new file mode 100644 (file)
index 0000000..aa0918f
--- /dev/null
@@ -0,0 +1,122 @@
+From eba6a504393932764a33aae64021827dd2c5c70c Mon Sep 17 00:00:00 2001
+From: Mark Brown <broonie@opensource.wolfsonmicro.com>
+Date: Sat, 26 Jan 2008 21:14:18 +0300
+Subject: [PATCH 35/64] Build system and MAINTAINERS entry for WM97xx touchscreen drivers
+
+Signed-off-by: Mark Brown <broonie@opensource.wolfsonmicro.com>
+Signed-off-by: Liam Girdwood <liam.girdwood@wolfsonmicro.com>
+---
+ MAINTAINERS                        |   10 +++++++
+ drivers/input/touchscreen/Kconfig  |   52 ++++++++++++++++++++++++++++++++++++
+ drivers/input/touchscreen/Makefile |    7 +++++
+ 3 files changed, 69 insertions(+), 0 deletions(-)
+
+diff --git a/MAINTAINERS b/MAINTAINERS
+index 2340cfb..f02851c 100644
+--- a/MAINTAINERS
++++ b/MAINTAINERS
+@@ -4204,6 +4204,16 @@ L:      linux-wireless@vger.kernel.org
+ W:    http://oops.ghostprotocols.net:81/blog
+ S:    Maintained
++WM97XX TOUCHSCREEN DRIVERS
++P:    Mark Brown
++M:    broonie@opensource.wolfsonmicro.com
++P:    Liam Girdwood
++M:    liam.girdwood@wolfsonmicro.com
++L:    linux-input@vger.kernel.org
++T:    git git://opensource.wolfsonmicro.com/linux-2.6-touch
++W:    http://opensource.wolfsonmicro.com/node/7
++S:    Supported
++
+ X.25 NETWORK LAYER
+ P:    Henner Eisen
+ M:    eis@baty.hanse.de
+diff --git a/drivers/input/touchscreen/Kconfig b/drivers/input/touchscreen/Kconfig
+index 90e8e92..0be05a2 100644
+--- a/drivers/input/touchscreen/Kconfig
++++ b/drivers/input/touchscreen/Kconfig
+@@ -158,6 +158,58 @@ config TOUCHSCREEN_TOUCHRIGHT
+         To compile this driver as a module, choose M here: the
+         module will be called touchright.
++config TOUCHSCREEN_WM97XX
++      tristate "Support for WM97xx AC97 touchscreen controllers"
++      depends on AC97_BUS
++
++config TOUCHSCREEN_WM9705
++      bool "WM9705 Touchscreen interface support"
++      depends on TOUCHSCREEN_WM97XX
++      help
++        Say Y here if you have a Wolfson Microelectronics WM9705 touchscreen
++        controller connected to your system.
++
++        If unsure, say N.
++
++        To compile this driver as a module, choose M here: the
++        module will be called wm9705.
++
++config TOUCHSCREEN_WM9712
++      bool "WM9712 Touchscreen interface support"
++      depends on TOUCHSCREEN_WM97XX
++      help
++        Say Y here if you have a Wolfson Microelectronics WM9712 touchscreen
++        controller connected to your system.
++
++        If unsure, say N.
++
++        To compile this driver as a module, choose M here: the
++        module will be called wm9712.
++
++config TOUCHSCREEN_WM9713
++      bool "WM9713 Touchscreen interface support"
++      depends on TOUCHSCREEN_WM97XX
++      help
++        Say Y here if you have a Wolfson Microelectronics WM9713 touchscreen
++        controller connected to your system.
++
++        If unsure, say N.
++
++        To compile this driver as a module, choose M here: the
++        module will be called wm9713.
++
++config TOUCHSCREEN_WM97XX_MAINSTONE
++      tristate "WM97xx Mainstone accelerated touch"
++      depends on TOUCHSCREEN_WM97XX && ARCH_PXA
++      help
++        Say Y here for support for streaming mode with WM97xx touchscreens
++        on Mainstone systems.
++
++        If unsure, say N
++
++        To compile this driver as a module, choose M here: the
++        module will be called mainstone-wm97xx
++
+ config TOUCHSCREEN_TOUCHWIN
+       tristate "Touchwin serial touchscreen"
+       select SERIO
+diff --git a/drivers/input/touchscreen/Makefile b/drivers/input/touchscreen/Makefile
+index 35d4097..d38156e 100644
+--- a/drivers/input/touchscreen/Makefile
++++ b/drivers/input/touchscreen/Makefile
+@@ -4,6 +4,8 @@
+ # Each configuration option enables a list of files.
++wm97xx-ts-y := wm97xx-core.o
++
+ obj-$(CONFIG_TOUCHSCREEN_ADS7846)     += ads7846.o
+ obj-$(CONFIG_TOUCHSCREEN_BITSY)               += h3600_ts_input.o
+ obj-$(CONFIG_TOUCHSCREEN_CORGI)               += corgi_ts.o
+@@ -19,3 +21,8 @@ obj-$(CONFIG_TOUCHSCREEN_PENMOUNT)   += penmount.o
+ obj-$(CONFIG_TOUCHSCREEN_TOUCHWIN)    += touchwin.o
+ obj-$(CONFIG_TOUCHSCREEN_UCB1400)     += ucb1400_ts.o
+ obj-$(CONFIG_TOUCHSCREEN_TSC2101)     += tsc2101_ts.o
++obj-$(CONFIG_TOUCHSCREEN_WM97XX)      += wm97xx-ts.o
++obj-$(CONFIG_TOUCHSCREEN_WM97XX_MAINSTONE)    += mainstone-wm97xx.o
++wm97xx-ts-$(CONFIG_TOUCHSCREEN_WM9705)  += wm9705.o
++wm97xx-ts-$(CONFIG_TOUCHSCREEN_WM9712)  += wm9712.o
++wm97xx-ts-$(CONFIG_TOUCHSCREEN_WM9713)  += wm9713.o
+-- 
+1.5.3.8
+
diff --git a/packages/kexecboot/linux-kexecboot-2.6.24/tosa/0036-Set-id-to-1-for-wm97xx-subdevices.patch b/packages/kexecboot/linux-kexecboot-2.6.24/tosa/0036-Set-id-to-1-for-wm97xx-subdevices.patch
new file mode 100644 (file)
index 0000000..dd10b34
--- /dev/null
@@ -0,0 +1,35 @@
+From 9ea478cbd5473f52ca036cccc00dddad717d7861 Mon Sep 17 00:00:00 2001
+From: Dmitry Baryshkov <dbaryshkov@gmail.com>
+Date: Wed, 30 Jan 2008 19:27:13 +0300
+Subject: [PATCH 36/64] Set id to -1 for wm97xx subdevices
+
+Signed-off-by: Dmitry Baryshkov <dbaryshkov@gmail.com>
+---
+ drivers/input/touchscreen/wm97xx-core.c |    4 ++--
+ 1 files changed, 2 insertions(+), 2 deletions(-)
+
+diff --git a/drivers/input/touchscreen/wm97xx-core.c b/drivers/input/touchscreen/wm97xx-core.c
+index 27a0a99..e066acc 100644
+--- a/drivers/input/touchscreen/wm97xx-core.c
++++ b/drivers/input/touchscreen/wm97xx-core.c
+@@ -592,7 +592,7 @@ static int wm97xx_probe(struct device *dev)
+       wm->gpio[5] = wm97xx_reg_read(wm, AC97_MISC_AFE);
+       /* register our battery device */
+-      wm->battery_dev = platform_device_alloc("wm97xx-battery", 0);
++      wm->battery_dev = platform_device_alloc("wm97xx-battery", -1);
+       if (!wm->battery_dev)
+               goto batt_err;
+       platform_set_drvdata(wm->battery_dev, wm);
+@@ -603,7 +603,7 @@ static int wm97xx_probe(struct device *dev)
+       /* register our extended touch device (for machine specific
+        * extensions) */
+-      wm->touch_dev = platform_device_alloc("wm97xx-touch", 0);
++      wm->touch_dev = platform_device_alloc("wm97xx-touch", -1);
+       if (!wm->touch_dev)
+               goto touch_err;
+       platform_set_drvdata(wm->touch_dev, wm);
+-- 
+1.5.3.8
+
diff --git a/packages/kexecboot/linux-kexecboot-2.6.24/tosa/0037-Don-t-lock-the-codec-list-in-snd_soc_dapm_new_widget.patch b/packages/kexecboot/linux-kexecboot-2.6.24/tosa/0037-Don-t-lock-the-codec-list-in-snd_soc_dapm_new_widget.patch
new file mode 100644 (file)
index 0000000..010194d
--- /dev/null
@@ -0,0 +1,41 @@
+From d2888c7643b07687b14a839239cbe7fc5bf565e6 Mon Sep 17 00:00:00 2001
+From: Mark Brown <broonie@opensource.wolfsonmicro.com>
+Date: Mon, 14 Jan 2008 23:24:26 +0300
+Subject: [PATCH 37/64] Don't lock the codec list in snd_soc_dapm_new_widgets()
+
+snd_soc_dapm_new_widgets() takes the codec lock when adding new widgets,
+causing lockdep warnings when applications later call down through ALSA
+to adjust controls.  Since widgets are only added during probe this lock
+should be unneeded so don't take it.
+
+Thanks to Dmitry Baryshkov <dbaryshkov@gmail.com> for reporting this issue.
+
+Signed-off-by: Mark Brown <broonie@opensource.wolfsonmicro.com>
+Cc: Dmitry Baryshkov <dbaryshkov@gmail.com>
+---
+ sound/soc/soc-dapm.c |    2 --
+ 1 files changed, 0 insertions(+), 2 deletions(-)
+
+diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c
+index 29a546f..e46cdc5 100644
+--- a/sound/soc/soc-dapm.c
++++ b/sound/soc/soc-dapm.c
+@@ -963,7 +963,6 @@ int snd_soc_dapm_new_widgets(struct snd_soc_codec *codec)
+ {
+       struct snd_soc_dapm_widget *w;
+-      mutex_lock(&codec->mutex);
+       list_for_each_entry(w, &codec->dapm_widgets, list)
+       {
+               if (w->new)
+@@ -998,7 +997,6 @@ int snd_soc_dapm_new_widgets(struct snd_soc_codec *codec)
+       }
+       dapm_power_widgets(codec, SND_SOC_DAPM_STREAM_NOP);
+-      mutex_unlock(&codec->mutex);
+       return 0;
+ }
+ EXPORT_SYMBOL_GPL(snd_soc_dapm_new_widgets);
+-- 
+1.5.3.8
+
diff --git a/packages/kexecboot/linux-kexecboot-2.6.24/tosa/0038-Don-t-lock-the-codec-list-in-snd_soc_dapm_new_widget.patch b/packages/kexecboot/linux-kexecboot-2.6.24/tosa/0038-Don-t-lock-the-codec-list-in-snd_soc_dapm_new_widget.patch
new file mode 100644 (file)
index 0000000..7a3eb61
--- /dev/null
@@ -0,0 +1,57 @@
+From 5bae1fab16c7b14a458aa90e5654fe3a1d8d960f Mon Sep 17 00:00:00 2001
+From: Mark Brown <broonie@opensource.wolfsonmicro.com>
+Date: Sun, 20 Jan 2008 00:06:06 +0300
+Subject: [PATCH 38/64] Don't lock the codec list in snd_soc_dapm_new_widgets()
+
+On Wed, Jan 16, 2008 at 02:40:55AM +0300, Dmitry wrote:
+
+> I'm sorry, but I tested this patch only now. And I just got another
+> message from lockdep:
+
+Could you give this patch a try, please?
+---
+ sound/soc/soc-core.c |    7 +++++--
+ 1 files changed, 5 insertions(+), 2 deletions(-)
+
+diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c
+index e6a67b5..7f3ed9f 100644
+--- a/sound/soc/soc-core.c
++++ b/sound/soc/soc-core.c
+@@ -1090,7 +1090,6 @@ int snd_soc_register_card(struct snd_soc_device *socdev)
+       struct snd_soc_machine *machine = socdev->machine;
+       int ret = 0, i, ac97 = 0, err = 0;
+-      mutex_lock(&codec->mutex);
+       for(i = 0; i < machine->num_links; i++) {
+               if (socdev->machine->dai_link[i].init) {
+                       err = socdev->machine->dai_link[i].init(codec);
+@@ -1116,12 +1115,14 @@ int snd_soc_register_card(struct snd_soc_device *socdev)
+               goto out;
+       }
++      mutex_lock(&codec->mutex);
+ #ifdef CONFIG_SND_SOC_AC97_BUS
+       if (ac97) {
+               ret = soc_ac97_dev_register(codec);
+               if (ret < 0) {
+                       printk(KERN_ERR "asoc: AC97 device register failed\n");
+                       snd_card_free(codec->card);
++                      mutex_unlock(&codec->mutex);
+                       goto out;
+               }
+       }
+@@ -1134,8 +1135,10 @@ int snd_soc_register_card(struct snd_soc_device *socdev)
+       err = device_create_file(socdev->dev, &dev_attr_codec_reg);
+       if (err < 0)
+               printk(KERN_WARNING "asoc: failed to add codec sysfs entries\n");
+-out:
++
+       mutex_unlock(&codec->mutex);
++
++out:
+       return ret;
+ }
+ EXPORT_SYMBOL_GPL(snd_soc_register_card);
+-- 
+1.5.3.8
+
diff --git a/packages/kexecboot/linux-kexecboot-2.6.24/tosa/0039-Add-generic-framework-for-managing-clocks.patch b/packages/kexecboot/linux-kexecboot-2.6.24/tosa/0039-Add-generic-framework-for-managing-clocks.patch
new file mode 100644 (file)
index 0000000..c09c208
--- /dev/null
@@ -0,0 +1,446 @@
+From 62c9a23cfa7181369637d0b61a8e90c83c562f03 Mon Sep 17 00:00:00 2001
+From: Dmitry Baryshkov <dbaryshkov@gmail.com>
+Date: Mon, 4 Feb 2008 03:01:06 +0300
+Subject: [PATCH 39/64] Add generic framework for managing clocks.
+
+Provide a generic framework that platform may choose
+to support clocks api. In particular this provides
+platform-independant struct clk definition, a full
+implementation of clocks api and a set of functions
+for registering and unregistering clocks in a safe way.
+
+Signed-off-by: Dmitry Baryshkov <dbaryshkov@gmail.com>
+---
+ include/linux/clklib.h |   85 ++++++++++++++
+ init/Kconfig           |    7 +
+ kernel/Makefile        |    1 +
+ kernel/clklib.c        |  295 ++++++++++++++++++++++++++++++++++++++++++++++++
+ 4 files changed, 388 insertions(+), 0 deletions(-)
+ create mode 100644 include/linux/clklib.h
+ create mode 100644 kernel/clklib.c
+
+diff --git a/include/linux/clklib.h b/include/linux/clklib.h
+new file mode 100644
+index 0000000..4bd9b4a
+--- /dev/null
++++ b/include/linux/clklib.h
+@@ -0,0 +1,85 @@
++/*
++ * Copyright (C) 2008 Dmitry Baryshkov
++ *
++ * This file is released under the GPL v2.
++ */
++
++#ifndef CLKLIB_H
++#define CLKLIB_H
++
++#include <linux/list.h>
++
++struct clk {
++      struct list_head node;
++      struct clk      *parent;
++
++      const char      *name;
++      struct module   *owner;
++
++      int             users;
++      unsigned long   rate;
++      int             delay;
++
++      int (*can_get)  (struct clk *, struct device *);
++      int (*set_parent) (struct clk *, struct clk *);
++      int (*enable)   (struct clk *);
++      void (*disable) (struct clk *);
++      unsigned long (*getrate) (struct clk*);
++      int (*setrate)  (struct clk *, unsigned long);
++      long (*roundrate) (struct clk *, unsigned long);
++
++      void            *priv;
++};
++
++int clk_register(struct clk *clk);
++void clk_unregister(struct clk *clk);
++static void __maybe_unused clks_register(struct clk *clks, size_t num)
++{
++      int i;
++      for (i = 0; i < num; i++) {
++              clk_register(&clks[i]);
++      }
++}
++
++
++int clk_alloc_function(const char *parent, struct clk *clk);
++
++struct clk_function {
++      const char *parent;
++      struct clk *clk;
++};
++
++#define CLK_FUNC(_clock, _function, _can_get, _data, _format) \
++      {                                               \
++              .parent = _clock,                       \
++              .clk = &(struct clk) {                  \
++                      .name= _function,               \
++                      .owner = THIS_MODULE,           \
++                      .can_get = _can_get,            \
++                      .priv = _data,                  \
++                      .format = _format,              \
++              },                                      \
++      }
++
++static int __maybe_unused clk_alloc_functions(
++              struct clk_function *funcs,
++              int num)
++{
++      int i;
++      int rc;
++
++      for (i = 0; i < num; i++) {
++              rc = clk_alloc_function(funcs[i].parent, funcs[i].clk);
++
++              if (rc) {
++                      printk(KERN_ERR "Error allocating %s.%s function.\n",
++                                      funcs[i].parent,
++                                      funcs[i].clk->name);
++                      return rc;
++              }
++      }
++
++      return 0;
++}
++
++#endif
+diff --git a/init/Kconfig b/init/Kconfig
+index b9d11a8..05b62ba 100644
+--- a/init/Kconfig
++++ b/init/Kconfig
+@@ -435,6 +435,13 @@ config CC_OPTIMIZE_FOR_SIZE
+ config SYSCTL
+       bool
++config HAVE_CLOCK_LIB
++      bool
++      help
++        Platforms select clocklib if they use this infrastructure
++        for managing their clocks both built into SoC and provided
++        by external devices.
++
+ menuconfig EMBEDDED
+       bool "Configure standard kernel features (for small systems)"
+       help
+diff --git a/kernel/Makefile b/kernel/Makefile
+index 6d9a87c..0b2ade7 100644
+--- a/kernel/Makefile
++++ b/kernel/Makefile
+@@ -58,6 +58,7 @@ obj-$(CONFIG_TASK_DELAY_ACCT) += delayacct.o
+ obj-$(CONFIG_TASKSTATS) += taskstats.o tsacct.o
+ obj-$(CONFIG_MARKERS) += marker.o
+ obj-$(CONFIG_LATENCYTOP) += latencytop.o
++obj-$(CONFIG_HAVE_CLOCK_LIB) += clklib.o
+ ifneq ($(CONFIG_SCHED_NO_NO_OMIT_FRAME_POINTER),y)
+ # According to Alan Modra <alan@linuxcare.com.au>, the -fno-omit-frame-pointer is
+diff --git a/kernel/clklib.c b/kernel/clklib.c
+new file mode 100644
+index 0000000..203af3d
+--- /dev/null
++++ b/kernel/clklib.c
+@@ -0,0 +1,295 @@
++#include <linux/kernel.h>
++#include <linux/module.h>
++#include <linux/clk.h>
++#include <linux/clklib.h>
++#include <linux/spinlock.h>
++#include <linux/err.h>
++#include <linux/delay.h>
++
++static LIST_HEAD(clocks);
++static DEFINE_SPINLOCK(clocks_lock);
++
++static int __clk_register(struct clk *clk)
++{
++      if (clk->parent &&
++          !try_module_get(clk->parent->owner))
++              return -EINVAL;
++
++      list_add_tail(&clk->node, &clocks);
++
++      return 0;
++}
++
++int clk_register(struct clk *clk)
++{
++      unsigned long flags;
++      int rc;
++
++      spin_lock_irqsave(&clocks_lock, flags);
++
++      rc = __clk_register(clk);
++
++      spin_unlock_irqrestore(&clocks_lock, flags);
++
++      return rc;
++}
++EXPORT_SYMBOL(clk_register);
++
++void clk_unregister(struct clk *clk)
++{
++      unsigned long flags;
++
++      spin_lock_irqsave(&clocks_lock, flags);
++      list_del(&clk->node);
++      if (clk->parent)
++              module_put(clk->parent->owner);
++      spin_unlock_irqrestore(&clocks_lock, flags);
++}
++EXPORT_SYMBOL(clk_unregister);
++
++struct clk *clk_get(struct device *dev, const char *id)
++{
++      struct clk *p, *clk = ERR_PTR(-ENOENT);
++      unsigned long flags;
++
++      spin_lock_irqsave(&clocks_lock, flags);
++
++      list_for_each_entry(p, &clocks, node) {
++              if (strcmp(id, p->name) == 0 &&
++                  (!p->can_get || p->can_get(p, dev)) &&
++                  try_module_get(p->owner)) {
++                      clk = p;
++                      break;
++              }
++      }
++
++      spin_unlock_irqrestore(&clocks_lock, flags);
++
++      return clk;
++}
++EXPORT_SYMBOL(clk_get);
++
++void clk_put(struct clk *clk)
++{
++      unsigned long flags;
++
++      if (!clk || IS_ERR(clk))
++              return;
++
++      spin_lock_irqsave(&clocks_lock, flags);
++
++      module_put(clk->owner);
++
++      spin_unlock_irqrestore(&clocks_lock, flags);
++}
++EXPORT_SYMBOL(clk_put);
++
++int clk_set_parent(struct clk *clk, struct clk *parent)
++{
++      int rc;
++      unsigned long flags;
++
++      if (!clk || IS_ERR(clk))
++              return -EINVAL;
++
++      if (!clk->set_parent)
++              return -EINVAL;
++
++      spin_lock_irqsave(&clocks_lock, flags);
++
++      rc = clk->set_parent(clk, parent);
++      if (!rc)
++              clk->parent = parent;
++
++      spin_unlock_irqrestore(&clocks_lock, flags);
++
++      return rc;
++}
++EXPORT_SYMBOL(clk_set_parent);
++
++static int __clk_enable(struct clk *clk)
++{
++      int rc = 0;
++
++      if (clk->parent) {
++              rc = __clk_enable(clk->parent);
++
++              if (rc)
++                      return rc;
++      }
++
++      if (clk->users++ == 0)
++              if (clk->enable)
++                      rc = clk->enable(clk);
++
++      if (clk->delay)
++              udelay(clk->delay);
++
++      return rc;
++}
++
++int clk_enable(struct clk *clk)
++{
++      unsigned long flags;
++      int rc;
++
++      if (!clk || IS_ERR(clk))
++              return -EINVAL;
++
++      spin_lock_irqsave(&clocks_lock, flags);
++
++      rc = __clk_enable(clk);
++
++      spin_unlock_irqrestore(&clocks_lock, flags);
++
++      return rc;
++}
++EXPORT_SYMBOL(clk_enable);
++
++static void __clk_disable(struct clk *clk)
++{
++      if (clk->users <= 0) {
++              WARN_ON(1);
++              return;
++      }
++
++      if (--clk->users == 0)
++              if (clk->disable)
++                      clk->disable(clk);
++
++      if (clk->parent)
++              __clk_disable(clk->parent);
++}
++
++void clk_disable(struct clk *clk)
++{
++      unsigned long flags;
++
++      if (!clk || IS_ERR(clk))
++              return;
++
++      spin_lock_irqsave(&clocks_lock, flags);
++
++      __clk_disable(clk);
++
++      spin_unlock_irqrestore(&clocks_lock, flags);
++}
++EXPORT_SYMBOL(clk_disable);
++
++static unsigned long __clk_get_rate(struct clk *clk)
++{
++      unsigned long rate = 0;
++
++      for (;;) {
++              if (rate || !clk)
++                      return rate;
++
++              if (clk->getrate)
++                      rate = clk->getrate(clk);
++              else if (clk->rate)
++                      rate = clk->rate;
++              else
++                      clk = clk->parent;
++      }
++}
++
++unsigned long clk_get_rate(struct clk *clk)
++{
++      unsigned long rate = 0;
++      unsigned long flags;
++
++      if (!clk || IS_ERR(clk))
++              return -EINVAL;
++
++      spin_lock_irqsave(&clocks_lock, flags);
++
++      rate = __clk_get_rate(clk);
++
++      spin_unlock_irqrestore(&clocks_lock, flags);
++
++      return rate;
++}
++EXPORT_SYMBOL(clk_get_rate);
++
++long clk_round_rate(struct clk *clk, unsigned long rate)
++{
++      long res;
++      unsigned long flags;
++
++      if (!clk || IS_ERR(clk))
++              return -EINVAL;
++
++      if (!clk->roundrate)
++              return -EINVAL;
++
++      spin_lock_irqsave(&clocks_lock, flags);
++
++      res = clk->roundrate(clk, rate);
++
++      spin_unlock_irqrestore(&clocks_lock, flags);
++
++      return res;
++}
++EXPORT_SYMBOL(clk_round_rate);
++
++int clk_set_rate(struct clk *clk, unsigned long rate)
++{
++      int rc;
++      unsigned long flags;
++
++      if (!clk || IS_ERR(clk))
++              return -EINVAL;
++
++      if (!clk->setrate)
++              return -EINVAL;
++
++      spin_lock_irqsave(&clocks_lock, flags);
++
++      rc = clk->setrate(clk, rate);
++
++      spin_unlock_irqrestore(&clocks_lock, flags);
++
++      return rc;
++}
++EXPORT_SYMBOL(clk_set_rate);
++
++int clk_alloc_function(const char *parent, struct clk *clk)
++{
++      int rc = 0;
++      unsigned long flags;
++      struct clk *pclk;
++      bool found = false;
++
++      spin_lock_irqsave(&clocks_lock, flags);
++
++      list_for_each_entry(pclk, &clocks, node) {
++              if (strcmp(parent, pclk->name) == 0 &&
++                  try_module_get(pclk->owner)) {
++                      found = true;
++                      break;
++              }
++      }
++
++      if (!found) {
++              rc = -ENODEV;
++              goto out;
++      }
++
++      clk->parent = pclk;
++
++      __clk_register(clk);
++      /*
++       * We locked parent owner during search
++       * and also in __clk_register. Free one reference
++       */
++      module_put(pclk->owner);
++
++out:
++      if (rc) {
++              kfree(clk);
++      }
++      spin_unlock_irqrestore(&clocks_lock, flags);
++
++      return rc;
++}
++EXPORT_SYMBOL(clk_alloc_function);
+-- 
+1.5.3.8
+
diff --git a/packages/kexecboot/linux-kexecboot-2.6.24/tosa/0040-Clocklib-debugfs-support.patch b/packages/kexecboot/linux-kexecboot-2.6.24/tosa/0040-Clocklib-debugfs-support.patch
new file mode 100644 (file)
index 0000000..160b274
--- /dev/null
@@ -0,0 +1,108 @@
+From cae12d96586dac77d223559d686487ea2d457a41 Mon Sep 17 00:00:00 2001
+From: Dmitry Baryshkov <dbaryshkov@gmail.com>
+Date: Mon, 4 Feb 2008 03:01:05 +0300
+Subject: [PATCH 40/64] Clocklib debugfs support
+
+Provide /sys/kernel/debug/clock to ease debugging.
+
+Signed-off-by: Dmitry Baryshkov <dbaryshkov@gmail.com>
+---
+ include/linux/clklib.h |    5 +++
+ kernel/clklib.c        |   68 ++++++++++++++++++++++++++++++++++++++++++++++++
+ 2 files changed, 73 insertions(+), 0 deletions(-)
+
+diff --git a/include/linux/clklib.h b/include/linux/clklib.h
+index 4bd9b4a..f916693 100644
+--- a/include/linux/clklib.h
++++ b/include/linux/clklib.h
+@@ -28,6 +28,11 @@ struct clk {
+       int (*setrate)  (struct clk *, unsigned long);
+       long (*roundrate) (struct clk *, unsigned long);
++      /*
++       * format any additional info
++       */
++      int (*format)   (struct clk *, struct seq_file *);
++
+       void            *priv;
+ };
+diff --git a/kernel/clklib.c b/kernel/clklib.c
+index 203af3d..b782220 100644
+--- a/kernel/clklib.c
++++ b/kernel/clklib.c
+@@ -293,3 +293,71 @@ out:
+       return rc;
+ }
+ EXPORT_SYMBOL(clk_alloc_function);
++
++#ifdef CONFIG_DEBUG_FS
++
++#include <linux/debugfs.h>
++#include <linux/seq_file.h>
++static void dump_clocks(struct seq_file *s, struct clk *parent, int nest)
++{
++      struct clk *clk;
++      int i;
++
++      list_for_each_entry(clk, &clocks, node) {
++              if (clk->parent == parent) {
++                      for (i = 0; i < nest; i++)
++                              seq_putc(s, ' ');
++                      seq_puts(s, clk->name);
++
++                      i = nest + strlen(clk->name);
++                      if (i >= 16)
++                              i = 15;
++                      for (; i < 16; i++)
++                              seq_putc(s, ' ');
++                      seq_printf(s, "%c use=%d rate=%lu KHz",
++                              clk->set_parent ? '*' : ' ',
++                              clk->users,
++                              __clk_get_rate(clk));
++                      if (clk->format)
++                              clk->format(clk, s);
++                      seq_putc(s, '\n');
++
++                      dump_clocks(s, clk, nest + 1);
++              }
++      }
++}
++
++static int clocklib_show(struct seq_file *s, void *unused)
++{
++      unsigned long flags;
++
++      spin_lock_irqsave(&clocks_lock, flags);
++
++      dump_clocks(s, NULL, 0);
++
++      spin_unlock_irqrestore(&clocks_lock, flags);
++
++      return 0;
++}
++
++static int clocklib_open(struct inode *inode, struct file *file)
++{
++      return single_open(file, clocklib_show, NULL);
++}
++
++static struct file_operations clocklib_operations = {
++      .open           = clocklib_open,
++      .read           = seq_read,
++      .llseek         = seq_lseek,
++      .release        = single_release,
++};
++
++static int __init clocklib_debugfs_init(void)
++{
++      debugfs_create_file("clock", S_IFREG | S_IRUGO,
++                              NULL, NULL, &clocklib_operations);
++      return 0;
++}
++subsys_initcall(clocklib_debugfs_init);
++
++#endif /* DEBUG_FS */
+-- 
+1.5.3.8
+
diff --git a/packages/kexecboot/linux-kexecboot-2.6.24/tosa/0041-From-80a359e60c2aec59ccf4fca0a7fd20495f82b1d2-Mon-Se.patch b/packages/kexecboot/linux-kexecboot-2.6.24/tosa/0041-From-80a359e60c2aec59ccf4fca0a7fd20495f82b1d2-Mon-Se.patch
new file mode 100644 (file)
index 0000000..9c95c67
--- /dev/null
@@ -0,0 +1,593 @@
+From 2a143b9546b01fd6c58ebaac7eb46568a17d6a41 Mon Sep 17 00:00:00 2001
+From: Dmitry Baryshkov <dbaryshkov@gmail.com>
+Date: Tue, 12 Feb 2008 04:58:59 +0300
+Subject: [PATCH 41/64] From 80a359e60c2aec59ccf4fca0a7fd20495f82b1d2 Mon Sep 17 00:00:00 2001
+ In-Reply-To: <20080207005839.GA28509@doriath.ww600.siemens.net>
+ References: <20080207005839.GA28509@doriath.ww600.siemens.net>
+ Date: Thu, 7 Feb 2008 03:35:08 +0300
+ Subject: [PATCH 3/5] Use clocklib for ARM pxa sub-arch.
+ Signed-off-by: Dmitry Baryshkov <dbaryshkov@gmail.com>
+
+---
+ arch/arm/Kconfig           |    1 +
+ arch/arm/mach-pxa/clock.c  |  108 ++++++--------------------------------------
+ arch/arm/mach-pxa/clock.h  |   58 +++++++++++++-----------
+ arch/arm/mach-pxa/pxa25x.c |   64 +++++++++++++++-----------
+ arch/arm/mach-pxa/pxa27x.c |   61 +++++++++++++-----------
+ arch/arm/mach-pxa/pxa3xx.c |   91 +++++++++++++++++++++----------------
+ 6 files changed, 169 insertions(+), 214 deletions(-)
+
+diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
+index 423e953..47f3c73 100644
+--- a/arch/arm/Kconfig
++++ b/arch/arm/Kconfig
+@@ -347,6 +347,7 @@ config ARCH_PXA
+       select GENERIC_CLOCKEVENTS
+       select TICK_ONESHOT
+       select HAVE_GPIO_LIB
++      select HAVE_CLOCK_LIB
+       help
+         Support for Intel/Marvell's PXA2xx/PXA3xx processor line.
+diff --git a/arch/arm/mach-pxa/clock.c b/arch/arm/mach-pxa/clock.c
+index 83ef5ec..3296b02 100644
+--- a/arch/arm/mach-pxa/clock.c
++++ b/arch/arm/mach-pxa/clock.c
+@@ -8,6 +8,7 @@
+ #include <linux/err.h>
+ #include <linux/string.h>
+ #include <linux/clk.h>
++#include <linux/clklib.h>
+ #include <linux/spinlock.h>
+ #include <linux/platform_device.h>
+ #include <linux/delay.h>
+@@ -19,123 +20,42 @@
+ #include "generic.h"
+ #include "clock.h"
+-static LIST_HEAD(clocks);
+-static DEFINE_MUTEX(clocks_mutex);
+-static DEFINE_SPINLOCK(clocks_lock);
+-
+-struct clk *clk_get(struct device *dev, const char *id)
+-{
+-      struct clk *p, *clk = ERR_PTR(-ENOENT);
+-
+-      mutex_lock(&clocks_mutex);
+-      list_for_each_entry(p, &clocks, node) {
+-              if (strcmp(id, p->name) == 0 &&
+-                  (p->dev == NULL || p->dev == dev)) {
+-                      clk = p;
+-                      break;
+-              }
+-      }
+-      mutex_unlock(&clocks_mutex);
+-
+-      return clk;
+-}
+-EXPORT_SYMBOL(clk_get);
+-
+-void clk_put(struct clk *clk)
++static int clk_gpio27_enable(struct clk *clk)
+ {
+-}
+-EXPORT_SYMBOL(clk_put);
+-
+-int clk_enable(struct clk *clk)
+-{
+-      unsigned long flags;
+-
+-      spin_lock_irqsave(&clocks_lock, flags);
+-      if (clk->enabled++ == 0)
+-              clk->ops->enable(clk);
+-      spin_unlock_irqrestore(&clocks_lock, flags);
+-
+-      if (clk->delay)
+-              udelay(clk->delay);
++      pxa_gpio_mode(GPIO11_3_6MHz_MD);
+       return 0;
+ }
+-EXPORT_SYMBOL(clk_enable);
+-
+-void clk_disable(struct clk *clk)
+-{
+-      unsigned long flags;
+-
+-      WARN_ON(clk->enabled == 0);
+-
+-      spin_lock_irqsave(&clocks_lock, flags);
+-      if (--clk->enabled == 0)
+-              clk->ops->disable(clk);
+-      spin_unlock_irqrestore(&clocks_lock, flags);
+-}
+-EXPORT_SYMBOL(clk_disable);
+-
+-unsigned long clk_get_rate(struct clk *clk)
+-{
+-      unsigned long rate;
+-
+-      rate = clk->rate;
+-      if (clk->ops->getrate)
+-              rate = clk->ops->getrate(clk);
+-
+-      return rate;
+-}
+-EXPORT_SYMBOL(clk_get_rate);
+-
+-
+-static void clk_gpio27_enable(struct clk *clk)
+-{
+-      pxa_gpio_mode(GPIO11_3_6MHz_MD);
+-}
+ static void clk_gpio27_disable(struct clk *clk)
+ {
++      /* FIXME: disable clock */
+ }
+-static const struct clkops clk_gpio27_ops = {
+-      .enable         = clk_gpio27_enable,
+-      .disable        = clk_gpio27_disable,
+-};
+-
+-
+-void clk_cken_enable(struct clk *clk)
++int clk_cken_enable(struct clk *clk)
+ {
+-      CKEN |= 1 << clk->cken;
++      int cken = ((struct clk_cken_priv *)clk->priv)->cken;
++      CKEN |= 1 << cken;
++
++      return 0;
+ }
+ void clk_cken_disable(struct clk *clk)
+ {
+-      CKEN &= ~(1 << clk->cken);
++      int cken = ((struct clk_cken_priv *)clk->priv)->cken;
++      CKEN &= ~(1 << cken);
+ }
+-const struct clkops clk_cken_ops = {
+-      .enable         = clk_cken_enable,
+-      .disable        = clk_cken_disable,
+-};
+-
+ static struct clk common_clks[] = {
+       {
+               .name           = "GPIO27_CLK",
+-              .ops            = &clk_gpio27_ops,
+               .rate           = 3686400,
++              .owner          = THIS_MODULE,
++              .enable         = clk_gpio27_enable,
++              .disable        = clk_gpio27_disable,
+       },
+ };
+-void clks_register(struct clk *clks, size_t num)
+-{
+-      int i;
+-
+-      mutex_lock(&clocks_mutex);
+-      for (i = 0; i < num; i++)
+-              list_add(&clks[i].node, &clocks);
+-      mutex_unlock(&clocks_mutex);
+-}
+-
+ static int __init clk_init(void)
+ {
+       clks_register(common_clks, ARRAY_SIZE(common_clks));
+diff --git a/arch/arm/mach-pxa/clock.h b/arch/arm/mach-pxa/clock.h
+index bc6b77e..5d0d067 100644
+--- a/arch/arm/mach-pxa/clock.h
++++ b/arch/arm/mach-pxa/clock.h
+@@ -1,43 +1,47 @@
+-struct clk;
++#include <linux/clklib.h>
++#include <linux/seq_file.h>
+-struct clkops {
+-      void                    (*enable)(struct clk *);
+-      void                    (*disable)(struct clk *);
+-      unsigned long           (*getrate)(struct clk *);
++struct clk_cken_priv {
++      unsigned int    cken;
+ };
+-struct clk {
+-      struct list_head        node;
+-      const char              *name;
+-      struct device           *dev;
+-      const struct clkops     *ops;
+-      unsigned long           rate;
+-      unsigned int            cken;
+-      unsigned int            delay;
+-      unsigned int            enabled;
+-};
+-
+-#define INIT_CKEN(_name, _cken, _rate, _delay, _dev)  \
++#define INIT_CKEN(_name, _cken, _rate, _delay)                \
+       {                                               \
+               .name   = _name,                        \
+-              .dev    = _dev,                         \
+-              .ops    = &clk_cken_ops,                \
++              .enable = clk_cken_enable,              \
++              .disable = clk_cken_disable,            \
+               .rate   = _rate,                        \
+-              .cken   = CKEN_##_cken,                 \
+               .delay  = _delay,                       \
++              .priv   = &(struct clk_cken_priv) {     \
++                      .cken = CKEN_##_cken,           \
++              },                                      \
+       }
+-#define INIT_CK(_name, _cken, _ops, _dev)             \
++#define INIT_CK(_name, _cken, _getrate)                       \
+       {                                               \
+               .name   = _name,                        \
+-              .dev    = _dev,                         \
+-              .ops    = _ops,                         \
+-              .cken   = CKEN_##_cken,                 \
++              .enable = clk_cken_enable,              \
++              .disable = clk_cken_disable,            \
++              .getrate = _getrate,                    \
++              .priv   = &(struct clk_cken_priv) {     \
++                      .cken = CKEN_##_cken,           \
++              },                                      \
+       }
+-extern const struct clkops clk_cken_ops;
+-
+-void clk_cken_enable(struct clk *clk);
++int clk_cken_enable(struct clk *clk);
+ void clk_cken_disable(struct clk *clk);
+ void clks_register(struct clk *clks, size_t num);
++
++static int __maybe_unused clk_dev_can_get(struct clk *clk, struct device *dev)
++{
++      return (dev == clk->priv);
++}
++
++static int __maybe_unused clk_dev_format(struct clk *clk, struct seq_file *s)
++{
++      BUG_ON(!clk->priv);
++      seq_puts(s, "for device ");
++      seq_puts(s, ((struct device *)clk->priv)->bus_id);
++      return 0;
++}
+diff --git a/arch/arm/mach-pxa/pxa25x.c b/arch/arm/mach-pxa/pxa25x.c
+index 5988d99..ed3719b 100644
+--- a/arch/arm/mach-pxa/pxa25x.c
++++ b/arch/arm/mach-pxa/pxa25x.c
+@@ -100,40 +100,50 @@ static unsigned long clk_pxa25x_lcd_getrate(struct clk *clk)
+       return pxa25x_get_memclk_frequency_10khz() * 10000;
+ }
+-static const struct clkops clk_pxa25x_lcd_ops = {
+-      .enable         = clk_cken_enable,
+-      .disable        = clk_cken_disable,
+-      .getrate        = clk_pxa25x_lcd_getrate,
+-};
+-
+ /*
+  * 3.6864MHz -> OST, GPIO, SSP, PWM, PLLs (95.842MHz, 147.456MHz)
+  * 95.842MHz -> MMC 19.169MHz, I2C 31.949MHz, FICP 47.923MHz, USB 47.923MHz
+  * 147.456MHz -> UART 14.7456MHz, AC97 12.288MHz, I2S 5.672MHz (allegedly)
+  */
+-static struct clk pxa25x_hwuart_clk =
+-      INIT_CKEN("UARTCLK", HWUART, 14745600, 1, &pxa_device_hwuart.dev)
+-;
++static struct clk pxa25x_hwuart_clk[] = {
++      INIT_CKEN("HWUARTCLK", HWUART, 14745600, 1),
++      {
++              .parent =       &pxa25x_hwuart_clk[0],
++              .name   =       "UARTCLK",
++              .can_get =      clk_dev_can_get,
++              .priv   =       &pxa_device_hwuart.dev,
++      },
++};
+ static struct clk pxa25x_clks[] = {
+-      INIT_CK("LCDCLK", LCD, &clk_pxa25x_lcd_ops, &pxa_device_fb.dev),
+-      INIT_CKEN("UARTCLK", FFUART, 14745600, 1, &pxa_device_ffuart.dev),
+-      INIT_CKEN("UARTCLK", BTUART, 14745600, 1, &pxa_device_btuart.dev),
+-      INIT_CKEN("UARTCLK", STUART, 14745600, 1, NULL),
+-      INIT_CKEN("UDCCLK", USB, 47923000, 5, &pxa_device_udc.dev),
+-      INIT_CKEN("MMCCLK", MMC, 19169000, 0, &pxa_device_mci.dev),
+-      INIT_CKEN("I2CCLK", I2C, 31949000, 0, &pxa_device_i2c.dev),
+-
+-      INIT_CKEN("SSPCLK",  SSP, 3686400, 0, &pxa25x_device_ssp.dev),
+-      INIT_CKEN("SSPCLK", NSSP, 3686400, 0, &pxa25x_device_nssp.dev),
+-      INIT_CKEN("SSPCLK", ASSP, 3686400, 0, &pxa25x_device_assp.dev),
++      INIT_CK("LCDCLK", LCD, &clk_pxa25x_lcd_getrate),
++      INIT_CKEN("FFUARTCLK", FFUART, 14745600, 1),
++      INIT_CKEN("BTUARTCLK", BTUART, 14745600, 1),
++      INIT_CKEN("STUARTCLK", STUART, 14745600, 1),
++      INIT_CKEN("UDCCLK", USB, 47923000, 5),
++      INIT_CKEN("MMCCLK", MMC, 19169000, 0),
++      INIT_CKEN("I2CCLK", I2C, 31949000, 0),
++
++      INIT_CKEN("SSP_CLK",  SSP, 3686400, 0),
++      INIT_CKEN("NSSPCLK", NSSP, 3686400, 0),
++      INIT_CKEN("ASSPCLK", ASSP, 3686400, 0),
+       /*
+-      INIT_CKEN("PWMCLK",  PWM0, 3686400,  0, NULL),
+-      INIT_CKEN("PWMCLK",  PWM0, 3686400,  0, NULL),
+-      INIT_CKEN("I2SCLK",  I2S,  14745600, 0, NULL),
++      INIT_CKEN("PWMCLK",  PWM0, 3686400,  0),
++      INIT_CKEN("PWMCLK",  PWM0, 3686400,  0),
++      INIT_CKEN("I2SCLK",  I2S,  14745600, 0),
+       */
+-      INIT_CKEN("FICPCLK", FICP, 47923000, 0, NULL),
++      INIT_CKEN("FICPCLK", FICP, 47923000, 0),
++};
++
++static struct clk_function __initdata pxa25x_clk_funcs[] = {
++      CLK_FUNC("FFUARTCLK", "UARTCLK", clk_dev_can_get, &pxa_device_ffuart.dev, clk_dev_format),
++      CLK_FUNC("BTUARTCLK", "UARTCLK", clk_dev_can_get, &pxa_device_btuart.dev, clk_dev_format),
++      CLK_FUNC("STUARTCLK", "UARTCLK", clk_dev_can_get, &pxa_device_stuart.dev, clk_dev_format),
++      CLK_FUNC("STUARTCLK", "SIRCLK", NULL, NULL, NULL),
++      CLK_FUNC("SSP_CLK", "SSPCLK", clk_dev_can_get, &pxa25x_device_ssp.dev, clk_dev_format),
++      CLK_FUNC("NSSPCLK", "SSPCLK", clk_dev_can_get, &pxa25x_device_nssp.dev, clk_dev_format),
++      CLK_FUNC("ASSPCLK", "SSPCLK", clk_dev_can_get, &pxa25x_device_assp.dev, clk_dev_format),
+ };
+ #ifdef CONFIG_PM
+@@ -313,11 +323,13 @@ static int __init pxa25x_init(void)
+       int ret = 0;
+       /* Only add HWUART for PXA255/26x; PXA210/250/27x do not have it. */
+-      if (cpu_is_pxa25x())
+-              clks_register(&pxa25x_hwuart_clk, 1);
++      if (cpu_is_pxa25x()) {
++              clks_register(pxa25x_hwuart_clk, ARRAY_SIZE(pxa25x_hwuart_clk));
++      }
+       if (cpu_is_pxa21x() || cpu_is_pxa25x()) {
+               clks_register(pxa25x_clks, ARRAY_SIZE(pxa25x_clks));
++              clk_alloc_functions(pxa25x_clk_funcs, ARRAY_SIZE(pxa25x_clk_funcs));
+               if ((ret = pxa_init_dma(16)))
+                       return ret;
+diff --git a/arch/arm/mach-pxa/pxa27x.c b/arch/arm/mach-pxa/pxa27x.c
+index 30ca4fd..c51e7b2 100644
+--- a/arch/arm/mach-pxa/pxa27x.c
++++ b/arch/arm/mach-pxa/pxa27x.c
+@@ -126,44 +126,48 @@ static unsigned long clk_pxa27x_lcd_getrate(struct clk *clk)
+       return pxa27x_get_lcdclk_frequency_10khz() * 10000;
+ }
+-static const struct clkops clk_pxa27x_lcd_ops = {
+-      .enable         = clk_cken_enable,
+-      .disable        = clk_cken_disable,
+-      .getrate        = clk_pxa27x_lcd_getrate,
+-};
+-
+ static struct clk pxa27x_clks[] = {
+-      INIT_CK("LCDCLK", LCD,    &clk_pxa27x_lcd_ops, &pxa_device_fb.dev),
+-      INIT_CK("CAMCLK", CAMERA, &clk_pxa27x_lcd_ops, NULL),
++      INIT_CK("LCDCLK", LCD,    &clk_pxa27x_lcd_getrate),
++      INIT_CK("CAMCLK", CAMERA, &clk_pxa27x_lcd_getrate),
+-      INIT_CKEN("UARTCLK", FFUART, 14857000, 1, &pxa_device_ffuart.dev),
+-      INIT_CKEN("UARTCLK", BTUART, 14857000, 1, &pxa_device_btuart.dev),
+-      INIT_CKEN("UARTCLK", STUART, 14857000, 1, NULL),
++      INIT_CKEN("FFUARTCLK", FFUART, 14857000, 1),
++      INIT_CKEN("BTUARTCLK", BTUART, 14857000, 1),
++      INIT_CKEN("STUARTCLK", STUART, 14857000, 1),
+-      INIT_CKEN("I2SCLK",  I2S,  14682000, 0, &pxa_device_i2s.dev),
+-      INIT_CKEN("I2CCLK",  I2C,  32842000, 0, &pxa_device_i2c.dev),
+-      INIT_CKEN("UDCCLK",  USB,  48000000, 5, &pxa_device_udc.dev),
+-      INIT_CKEN("MMCCLK",  MMC,  19500000, 0, &pxa_device_mci.dev),
+-      INIT_CKEN("FICPCLK", FICP, 48000000, 0, &pxa_device_ficp.dev),
++      INIT_CKEN("I2SCLK",  I2S,  14682000, 0),
++      INIT_CKEN("I2CCLK",  I2C,  32842000, 0),
++      INIT_CKEN("UDCCLK",  USB,  48000000, 5),
++      INIT_CKEN("MMCCLK",  MMC,  19500000, 0),
++      INIT_CKEN("FICPCLK", FICP, 48000000, 0),
+-      INIT_CKEN("USBCLK", USBHOST, 48000000, 0, &pxa27x_device_ohci.dev),
+-      INIT_CKEN("I2CCLK", PWRI2C, 13000000, 0, &pxa27x_device_i2c_power.dev),
+-      INIT_CKEN("KBDCLK", KEYPAD, 32768, 0, NULL),
++      INIT_CKEN("USBCLK", USBHOST, 48000000, 0),
++      INIT_CKEN("I2CCLK", PWRI2C, 13000000, 0),
++      INIT_CKEN("KBDCLK", KEYPAD, 32768, 0),
+-      INIT_CKEN("SSPCLK", SSP1, 13000000, 0, &pxa27x_device_ssp1.dev),
+-      INIT_CKEN("SSPCLK", SSP2, 13000000, 0, &pxa27x_device_ssp2.dev),
+-      INIT_CKEN("SSPCLK", SSP3, 13000000, 0, &pxa27x_device_ssp3.dev),
++      INIT_CKEN("SSP1CLK", SSP1, 13000000, 0),
++      INIT_CKEN("SSP2CLK", SSP2, 13000000, 0),
++      INIT_CKEN("SSP3CLK", SSP3, 13000000, 0),
+       /*
+-      INIT_CKEN("PWMCLK",  PWM0, 13000000, 0, NULL),
+-      INIT_CKEN("MSLCLK",  MSL,  48000000, 0, NULL),
+-      INIT_CKEN("USIMCLK", USIM, 48000000, 0, NULL),
+-      INIT_CKEN("MSTKCLK", MEMSTK, 19500000, 0, NULL),
+-      INIT_CKEN("IMCLK",   IM,   0, 0, NULL),
+-      INIT_CKEN("MEMCLK",  MEMC, 0, 0, NULL),
++      INIT_CKEN("PWMCLK",  PWM0, 13000000, 0),
++      INIT_CKEN("MSLCLK",  MSL,  48000000, 0),
++      INIT_CKEN("USIMCLK", USIM, 48000000, 0),
++      INIT_CKEN("MSTKCLK", MEMSTK, 19500000, 0),
++      INIT_CKEN("IMCLK",   IM,   0, 0),
++      INIT_CKEN("MEMCLK",  MEMC, 0, 0),
+       */
+ };
++static struct clk_function __initdata pxa27x_clk_funcs[] = {
++      CLK_FUNC("FFUARTCLK", "UARTCLK", clk_dev_can_get, &pxa_device_ffuart.dev, clk_dev_format),
++      CLK_FUNC("BTUARTCLK", "UARTCLK", clk_dev_can_get, &pxa_device_btuart.dev, clk_dev_format),
++      CLK_FUNC("STUARTCLK", "UARTCLK", clk_dev_can_get, &pxa_device_stuart.dev, clk_dev_format),
++      CLK_FUNC("STUARTCLK", "SIRCLK", NULL, NULL, NULL),
++      CLK_FUNC("SSP1CLK", "SSPCLK", clk_dev_can_get, &pxa27x_device_ssp1.dev, clk_dev_format),
++      CLK_FUNC("SSP2CLK", "SSPCLK", clk_dev_can_get, &pxa27x_device_ssp2.dev, clk_dev_format),
++      CLK_FUNC("SSP3CLK", "SSPCLK", clk_dev_can_get, &pxa27x_device_ssp3.dev, clk_dev_format),
++};
++
+ #ifdef CONFIG_PM
+ #define SAVE(x)               sleep_save[SLEEP_SAVE_##x] = x
+@@ -453,6 +457,7 @@ static int __init pxa27x_init(void)
+       int ret = 0;
+       if (cpu_is_pxa27x()) {
+               clks_register(pxa27x_clks, ARRAY_SIZE(pxa27x_clks));
++              clk_alloc_functions(pxa27x_clk_funcs, ARRAY_SIZE(pxa27x_clk_funcs));
+               if ((ret = pxa_init_dma(32)))
+                       return ret;
+diff --git a/arch/arm/mach-pxa/pxa3xx.c b/arch/arm/mach-pxa/pxa3xx.c
+index ccab9da..0f8bbf3 100644
+--- a/arch/arm/mach-pxa/pxa3xx.c
++++ b/arch/arm/mach-pxa/pxa3xx.c
+@@ -122,27 +122,31 @@ static unsigned long clk_pxa3xx_hsio_getrate(struct clk *clk)
+       return hsio_clk;
+ }
+-static void clk_pxa3xx_cken_enable(struct clk *clk)
++static int clk_pxa3xx_cken_enable(struct clk *clk)
+ {
+-      unsigned long mask = 1ul << (clk->cken & 0x1f);
++      int cken = ((struct clk_cken_priv *)clk->priv)->cken;
++      unsigned long mask = 1ul << (cken & 0x1f);
+       local_irq_disable();
+-      if (clk->cken < 32)
++      if (cken < 32)
+               CKENA |= mask;
+       else
+               CKENB |= mask;
+       local_irq_enable();
++
++      return 0;
+ }
+ static void clk_pxa3xx_cken_disable(struct clk *clk)
+ {
+-      unsigned long mask = 1ul << (clk->cken & 0x1f);
++      int cken = ((struct clk_cken_priv *)clk->priv)->cken;
++      unsigned long mask = 1ul << (cken & 0x1f);
+       local_irq_disable();
+-      if (clk->cken < 32)
++      if (cken < 32)
+               CKENA &= ~mask;
+       else
+               CKENB &= ~mask;
+@@ -150,55 +154,63 @@ static void clk_pxa3xx_cken_disable(struct clk *clk)
+       local_irq_enable();
+ }
+-static const struct clkops clk_pxa3xx_cken_ops = {
+-      .enable         = clk_pxa3xx_cken_enable,
+-      .disable        = clk_pxa3xx_cken_disable,
+-};
+-
+-static const struct clkops clk_pxa3xx_hsio_ops = {
+-      .enable         = clk_pxa3xx_cken_enable,
+-      .disable        = clk_pxa3xx_cken_disable,
+-      .getrate        = clk_pxa3xx_hsio_getrate,
+-};
+-
+-#define PXA3xx_CKEN(_name, _cken, _rate, _delay, _dev)        \
++#define PXA3xx_CKEN(_name, _cken, _rate, _delay)      \
+       {                                               \
+               .name   = _name,                        \
+-              .dev    = _dev,                         \
+-              .ops    = &clk_pxa3xx_cken_ops,         \
++              .enable = clk_pxa3xx_cken_enable,       \
++              .disable = clk_pxa3xx_cken_disable,     \
+               .rate   = _rate,                        \
+-              .cken   = CKEN_##_cken,                 \
+               .delay  = _delay,                       \
++              .priv   = &(struct clk_cken_priv) {     \
++                      .cken = CKEN_##_cken,           \
++              },                                      \
+       }
+-#define PXA3xx_CK(_name, _cken, _ops, _dev)           \
++#define PXA3xx_CK(_name, _cken, _getrate)             \
+       {                                               \
+               .name   = _name,                        \
+-              .dev    = _dev,                         \
+-              .ops    = _ops,                         \
+-              .cken   = CKEN_##_cken,                 \
++              .enable = clk_pxa3xx_cken_enable,       \
++              .disable = clk_pxa3xx_cken_disable,     \
++              .getrate = _getrate,                    \
++              .priv   = &(struct clk_cken_priv) {     \
++                      .cken = CKEN_##_cken,           \
++              },                                      \
+       }
+ static struct clk pxa3xx_clks[] = {
+-      PXA3xx_CK("LCDCLK", LCD,    &clk_pxa3xx_hsio_ops, &pxa_device_fb.dev),
+-      PXA3xx_CK("CAMCLK", CAMERA, &clk_pxa3xx_hsio_ops, NULL),
++      PXA3xx_CK("LCDCLK", LCD,    &clk_pxa3xx_hsio_getrate),
++      PXA3xx_CK("CAMCLK", CAMERA, &clk_pxa3xx_hsio_getrate),
+-      PXA3xx_CKEN("UARTCLK", FFUART, 14857000, 1, &pxa_device_ffuart.dev),
+-      PXA3xx_CKEN("UARTCLK", BTUART, 14857000, 1, &pxa_device_btuart.dev),
+-      PXA3xx_CKEN("UARTCLK", STUART, 14857000, 1, NULL),
++      PXA3xx_CKEN("FFUARTCLK", FFUART, 14857000, 1),
++      PXA3xx_CKEN("BTUARTCLK", BTUART, 14857000, 1),
++      PXA3xx_CKEN("STUARTCLK", STUART, 14857000, 1),
+-      PXA3xx_CKEN("I2CCLK", I2C,  32842000, 0, &pxa_device_i2c.dev),
+-      PXA3xx_CKEN("UDCCLK", UDC,  48000000, 5, &pxa_device_udc.dev),
+-      PXA3xx_CKEN("USBCLK", USBH, 48000000, 0, &pxa27x_device_ohci.dev),
++      PXA3xx_CKEN("I2CCLK", I2C,  32842000, 0),
++      PXA3xx_CKEN("UDCCLK", UDC,  48000000, 5),
++      PXA3xx_CKEN("USBCLK", USBH, 48000000, 0),
+-      PXA3xx_CKEN("SSPCLK", SSP1, 13000000, 0, &pxa27x_device_ssp1.dev),
+-      PXA3xx_CKEN("SSPCLK", SSP2, 13000000, 0, &pxa27x_device_ssp2.dev),
+-      PXA3xx_CKEN("SSPCLK", SSP3, 13000000, 0, &pxa27x_device_ssp3.dev),
+-      PXA3xx_CKEN("SSPCLK", SSP4, 13000000, 0, &pxa3xx_device_ssp4.dev),
++      PXA3xx_CKEN("SSP1CLK", SSP1, 13000000, 0),
++      PXA3xx_CKEN("SSP2CLK", SSP2, 13000000, 0),
++      PXA3xx_CKEN("SSP3CLK", SSP3, 13000000, 0),
++      PXA3xx_CKEN("SSP4CLK", SSP4, 13000000, 0),
++
++      PXA3xx_CKEN("MMC1CLK", MMC1, 19500000, 0),
++      PXA3xx_CKEN("MMC2CLK", MMC2, 19500000, 0),
++      PXA3xx_CKEN("MMC3CLK", MMC3, 19500000, 0),
++};
+-      PXA3xx_CKEN("MMCCLK", MMC1, 19500000, 0, &pxa_device_mci.dev),
+-      PXA3xx_CKEN("MMCCLK", MMC2, 19500000, 0, &pxa3xx_device_mci2.dev),
+-      PXA3xx_CKEN("MMCCLK", MMC3, 19500000, 0, &pxa3xx_device_mci3.dev),
++static struct clk_function __initdata pxa3xx_clk_funcs[] = {
++      CLK_FUNC("FFUARTCLK", "UARTCLK", clk_dev_can_get, &pxa_device_ffuart.dev, clk_dev_format),
++      CLK_FUNC("BTUARTCLK", "UARTCLK", clk_dev_can_get, &pxa_device_btuart.dev, clk_dev_format),
++      CLK_FUNC("STUARTCLK", "UARTCLK", clk_dev_can_get, &pxa_device_stuart.dev, clk_dev_format),
++      CLK_FUNC("STUARTCLK", "SIRCLK", NULL, NULL, NULL),
++      CLK_FUNC("SSP1CLK", "SSPCLK", clk_dev_can_get, &pxa27x_device_ssp1.dev, clk_dev_format),
++      CLK_FUNC("SSP2CLK", "SSPCLK", clk_dev_can_get, &pxa27x_device_ssp2.dev, clk_dev_format),
++      CLK_FUNC("SSP3CLK", "SSPCLK", clk_dev_can_get, &pxa27x_device_ssp3.dev, clk_dev_format),
++      CLK_FUNC("SSP4CLK", "SSPCLK", clk_dev_can_get, &pxa3xx_device_ssp4.dev, clk_dev_format),
++      CLK_FUNC("MMC1CLK", "MMCCLK", clk_dev_can_get, &pxa_device_mci.dev, clk_dev_format),
++      CLK_FUNC("MMC2CLK", "MMCCLK", clk_dev_can_get, &pxa3xx_device_mci2.dev, clk_dev_format),
++      CLK_FUNC("MMC3CLK", "MMCCLK", clk_dev_can_get, &pxa3xx_device_mci3.dev, clk_dev_format),
+ };
+ #ifdef CONFIG_PM
+@@ -255,6 +267,7 @@ static int __init pxa3xx_init(void)
+       if (cpu_is_pxa3xx()) {
+               clks_register(pxa3xx_clks, ARRAY_SIZE(pxa3xx_clks));
++              clk_alloc_functions(pxa3xx_clk_funcs, ARRAY_SIZE(pxa3xx_clk_funcs));
+               if ((ret = pxa_init_dma(32)))
+                       return ret;
+-- 
+1.5.3.8
+
diff --git a/packages/kexecboot/linux-kexecboot-2.6.24/tosa/0042-Use-correct-clock-for-IrDA-on-pxa.patch b/packages/kexecboot/linux-kexecboot-2.6.24/tosa/0042-Use-correct-clock-for-IrDA-on-pxa.patch
new file mode 100644 (file)
index 0000000..a605735
--- /dev/null
@@ -0,0 +1,26 @@
+From 70dfe7e736467af6242c61092cb64f44d2fd50e3 Mon Sep 17 00:00:00 2001
+From: Dmitry Baryshkov <dbaryshkov@gmail.com>
+Date: Mon, 4 Feb 2008 03:01:05 +0300
+Subject: [PATCH 42/64] Use correct clock for IrDA on pxa
+
+Signed-off-by: Dmitry Baryshkov <dbaryshkov@gmail.com>
+---
+ drivers/net/irda/pxaficp_ir.c |    2 +-
+ 1 files changed, 1 insertions(+), 1 deletions(-)
+
+diff --git a/drivers/net/irda/pxaficp_ir.c b/drivers/net/irda/pxaficp_ir.c
+index 8c09344..36d2ec0 100644
+--- a/drivers/net/irda/pxaficp_ir.c
++++ b/drivers/net/irda/pxaficp_ir.c
+@@ -814,7 +814,7 @@ static int pxa_irda_probe(struct platform_device *pdev)
+       si->dev = &pdev->dev;
+       si->pdata = pdev->dev.platform_data;
+-      si->sir_clk = clk_get(&pdev->dev, "UARTCLK");
++      si->sir_clk = clk_get(&pdev->dev, "SIRCLK");
+       si->fir_clk = clk_get(&pdev->dev, "FICPCLK");
+       if (IS_ERR(si->sir_clk) || IS_ERR(si->fir_clk)) {
+               err = PTR_ERR(IS_ERR(si->sir_clk) ? si->sir_clk : si->fir_clk);
+-- 
+1.5.3.8
+
diff --git a/packages/kexecboot/linux-kexecboot-2.6.24/tosa/0043-Use-clocklib-for-sa1100-sub-arch.patch b/packages/kexecboot/linux-kexecboot-2.6.24/tosa/0043-Use-clocklib-for-sa1100-sub-arch.patch
new file mode 100644 (file)
index 0000000..22b8414
--- /dev/null
@@ -0,0 +1,153 @@
+From 3932e0f5c4c05200c030b60606ed2eb83550f4bb Mon Sep 17 00:00:00 2001
+From: Dmitry Baryshkov <dbaryshkov@gmail.com>
+Date: Mon, 4 Feb 2008 03:01:04 +0300
+Subject: [PATCH 43/64] Use clocklib for sa1100 sub-arch.
+
+Signed-off-by: Dmitry Baryshkov <dbaryshkov@gmail.com>
+---
+ arch/arm/Kconfig             |    1 +
+ arch/arm/mach-sa1100/clock.c |   95 ++---------------------------------------
+ 2 files changed, 6 insertions(+), 90 deletions(-)
+
+diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
+index 47f3c73..fa47201 100644
+--- a/arch/arm/Kconfig
++++ b/arch/arm/Kconfig
+@@ -370,6 +370,7 @@ config ARCH_SA1100
+       select ARCH_MTD_XIP
+       select GENERIC_GPIO
+       select GENERIC_TIME
++      select HAVE_CLOCK_LIB
+       help
+         Support for StrongARM 11x0 based boards.
+diff --git a/arch/arm/mach-sa1100/clock.c b/arch/arm/mach-sa1100/clock.c
+index fc97fe5..6b3cc51 100644
+--- a/arch/arm/mach-sa1100/clock.c
++++ b/arch/arm/mach-sa1100/clock.c
+@@ -8,83 +8,13 @@
+ #include <linux/err.h>
+ #include <linux/string.h>
+ #include <linux/clk.h>
++#include <linux/clklib.h>
+ #include <linux/spinlock.h>
+ #include <linux/mutex.h>
+ #include <asm/hardware.h>
+-/*
+- * Very simple clock implementation - we only have one clock to
+- * deal with at the moment, so we only match using the "name".
+- */
+-struct clk {
+-      struct list_head        node;
+-      unsigned long           rate;
+-      const char              *name;
+-      unsigned int            enabled;
+-      void                    (*enable)(void);
+-      void                    (*disable)(void);
+-};
+-
+-static LIST_HEAD(clocks);
+-static DEFINE_MUTEX(clocks_mutex);
+-static DEFINE_SPINLOCK(clocks_lock);
+-
+-struct clk *clk_get(struct device *dev, const char *id)
+-{
+-      struct clk *p, *clk = ERR_PTR(-ENOENT);
+-
+-      mutex_lock(&clocks_mutex);
+-      list_for_each_entry(p, &clocks, node) {
+-              if (strcmp(id, p->name) == 0) {
+-                      clk = p;
+-                      break;
+-              }
+-      }
+-      mutex_unlock(&clocks_mutex);
+-
+-      return clk;
+-}
+-EXPORT_SYMBOL(clk_get);
+-
+-void clk_put(struct clk *clk)
+-{
+-}
+-EXPORT_SYMBOL(clk_put);
+-
+-int clk_enable(struct clk *clk)
+-{
+-      unsigned long flags;
+-
+-      spin_lock_irqsave(&clocks_lock, flags);
+-      if (clk->enabled++ == 0)
+-              clk->enable();
+-      spin_unlock_irqrestore(&clocks_lock, flags);
+-      return 0;
+-}
+-EXPORT_SYMBOL(clk_enable);
+-
+-void clk_disable(struct clk *clk)
+-{
+-      unsigned long flags;
+-
+-      WARN_ON(clk->enabled == 0);
+-
+-      spin_lock_irqsave(&clocks_lock, flags);
+-      if (--clk->enabled == 0)
+-              clk->disable();
+-      spin_unlock_irqrestore(&clocks_lock, flags);
+-}
+-EXPORT_SYMBOL(clk_disable);
+-
+-unsigned long clk_get_rate(struct clk *clk)
+-{
+-      return clk->rate;
+-}
+-EXPORT_SYMBOL(clk_get_rate);
+-
+-
+-static void clk_gpio27_enable(void)
++static int clk_gpio27_enable(struct clk *clk)
+ {
+       /*
+        * First, set up the 3.6864MHz clock on GPIO 27 for the SA-1111:
+@@ -93,9 +23,11 @@ static void clk_gpio27_enable(void)
+       GAFR |= GPIO_32_768kHz;
+       GPDR |= GPIO_32_768kHz;
+       TUCR = TUCR_3_6864MHz;
++
++      return 0;
+ }
+-static void clk_gpio27_disable(void)
++static void clk_gpio27_disable(struct clk *clk)
+ {
+       TUCR = 0;
+       GPDR &= ~GPIO_32_768kHz;
+@@ -109,23 +41,6 @@ static struct clk clk_gpio27 = {
+       .disable        = clk_gpio27_disable,
+ };
+-int clk_register(struct clk *clk)
+-{
+-      mutex_lock(&clocks_mutex);
+-      list_add(&clk->node, &clocks);
+-      mutex_unlock(&clocks_mutex);
+-      return 0;
+-}
+-EXPORT_SYMBOL(clk_register);
+-
+-void clk_unregister(struct clk *clk)
+-{
+-      mutex_lock(&clocks_mutex);
+-      list_del(&clk->node);
+-      mutex_unlock(&clocks_mutex);
+-}
+-EXPORT_SYMBOL(clk_unregister);
+-
+ static int __init clk_init(void)
+ {
+       clk_register(&clk_gpio27);
+-- 
+1.5.3.8
+
diff --git a/packages/kexecboot/linux-kexecboot-2.6.24/tosa/0044-fix-tmio_mmc-debug-compilation.patch b/packages/kexecboot/linux-kexecboot-2.6.24/tosa/0044-fix-tmio_mmc-debug-compilation.patch
new file mode 100644 (file)
index 0000000..5ca8228
--- /dev/null
@@ -0,0 +1,26 @@
+From 03fdebde257197c13c0d10882e16a2a888ab4e0a Mon Sep 17 00:00:00 2001
+From: Dmitry Baryshkov <dbaryshkov@gmail.com>
+Date: Sat, 2 Feb 2008 20:23:01 +0300
+Subject: [PATCH 44/64] fix tmio_mmc debug compilation
+
+Signed-off-by: Dmitry Baryshkov <dbaryshkov@gmail.com>
+---
+ drivers/mmc/host/tmio_mmc.c |    2 +-
+ 1 files changed, 1 insertions(+), 1 deletions(-)
+
+diff --git a/drivers/mmc/host/tmio_mmc.c b/drivers/mmc/host/tmio_mmc.c
+index 735c386..b0d38e2 100644
+--- a/drivers/mmc/host/tmio_mmc.c
++++ b/drivers/mmc/host/tmio_mmc.c
+@@ -329,7 +329,7 @@ static irqreturn_t tmio_mmc_irq(int irq, void *devid)
+       if (!ireg) {
+               disable_mmc_irqs(ctl, status & ~irq_mask);
+ #ifdef CONFIG_MMC_DEBUG
+-              WARN("tmio_mmc: Spurious MMC irq, disabling! 0x%08x 0x%08x 0x%08x\n", status, irq_mask, ireg);
++              printk(KERN_WARNING "tmio_mmc: Spurious MMC irq, disabling! 0x%08x 0x%08x 0x%08x\n", status, irq_mask, ireg);
+               debug_status(status);
+ #endif
+               goto out;
+-- 
+1.5.3.8
+
diff --git a/packages/kexecboot/linux-kexecboot-2.6.24/tosa/0045-Update-tmio_ohci.patch b/packages/kexecboot/linux-kexecboot-2.6.24/tosa/0045-Update-tmio_ohci.patch
new file mode 100644 (file)
index 0000000..10f483b
--- /dev/null
@@ -0,0 +1,416 @@
+From fe3c05491370965eb821aedc95f771b86ebab3ab Mon Sep 17 00:00:00 2001
+From: Dmitry Baryshkov <dbaryshkov@gmail.com>
+Date: Wed, 9 Jan 2008 02:01:44 +0300
+Subject: [PATCH 45/64] Update tmio_ohci:
+ Ports management.
+ Basic support for ohci suspend/resume.
+
+Signed-off-by: Dmitry Baryshkov <dbaryshkov@gmail.com>
+---
+ drivers/mfd/tc6393xb.c       |   40 ++++++++
+ drivers/usb/host/ohci-tmio.c |  206 +++++++++++++++++++++++++++++++++++++++---
+ 2 files changed, 235 insertions(+), 11 deletions(-)
+
+diff --git a/drivers/mfd/tc6393xb.c b/drivers/mfd/tc6393xb.c
+index 9439f39..5d17687 100644
+--- a/drivers/mfd/tc6393xb.c
++++ b/drivers/mfd/tc6393xb.c
+@@ -224,6 +224,44 @@ static int tc6393xb_ohci_enable(struct platform_device *ohci)
+       return 0;
+ }
++static int tc6393xb_ohci_suspend(struct platform_device *ohci)
++{
++      struct platform_device          *dev    = to_platform_device(ohci->dev.parent);
++      struct tc6393xb                 *tc6393xb = platform_get_drvdata(dev);
++      struct tc6393xb_scr __iomem     *scr    = tc6393xb->scr;
++      union tc6393xb_scr_ccr          ccr;
++      unsigned long                   flags;
++
++      spin_lock_irqsave(&tc6393xb->lock, flags);
++
++      ccr.raw = ioread16(&scr->ccr);
++      ccr.bits.usbcken = 0;
++      iowrite16(ccr.raw, &scr->ccr);
++
++      spin_unlock_irqrestore(&tc6393xb->lock, flags);
++
++      return 0;
++}
++
++static int tc6393xb_ohci_resume(struct platform_device *ohci)
++{
++      struct platform_device          *dev    = to_platform_device(ohci->dev.parent);
++      struct tc6393xb                 *tc6393xb = platform_get_drvdata(dev);
++      struct tc6393xb_scr __iomem     *scr    = tc6393xb->scr;
++      union tc6393xb_scr_ccr          ccr;
++      unsigned long                   flags;
++
++      spin_lock_irqsave(&tc6393xb->lock, flags);
++
++      ccr.raw = ioread16(&scr->ccr);
++      ccr.bits.usbcken = 1;
++      iowrite16(ccr.raw, &scr->ccr);
++
++      spin_unlock_irqrestore(&tc6393xb->lock, flags);
++
++      return 0;
++}
++
+ static int tc6393xb_fb_disable(struct platform_device *fb)
+ {
+       struct platform_device          *dev    = to_platform_device(fb->dev.parent);
+@@ -423,6 +461,8 @@ static struct mfd_cell tc6393xb_cells[] = {
+               .name = "tmio-ohci",
+               .enable = tc6393xb_ohci_enable,
+               .disable = tc6393xb_ohci_disable,
++              .suspend = tc6393xb_ohci_suspend,
++              .resume = tc6393xb_ohci_resume,
+               .num_resources = ARRAY_SIZE(tc6393xb_ohci_resources),
+               .resources = tc6393xb_ohci_resources,
+       },
+diff --git a/drivers/usb/host/ohci-tmio.c b/drivers/usb/host/ohci-tmio.c
+index be609f3..65e3cd3 100644
+--- a/drivers/usb/host/ohci-tmio.c
++++ b/drivers/usb/host/ohci-tmio.c
+@@ -75,10 +75,13 @@ struct tmio_uhccr {
+       u8 x07[3];
+ } __attribute__((packed));
++#define MAX_TMIO_OHCI_PORTS   3
++
+ #define UHCCR_PM_GKEN      0x0001
+ #define UHCCR_PM_CKRNEN    0x0002
+ #define UHCCR_PM_USBPW1    0x0004
+ #define UHCCR_PM_USBPW2    0x0008
++#define UHCCR_PM_USBPW3    0x0008
+ #define UHCCR_PM_PMEE      0x0100
+ #define UHCCR_PM_PMES      0x8000
+@@ -86,44 +89,96 @@ struct tmio_uhccr {
+ struct tmio_hcd {
+       struct tmio_uhccr __iomem *ccr;
++      spinlock_t              lock; /* protects RMW cycles and disabled_ports data */
++      bool disabled_ports[MAX_TMIO_OHCI_PORTS];
+ };
+ #define hcd_to_tmio(hcd)      ((struct tmio_hcd *)(hcd_to_ohci(hcd) + 1))
+ #define ohci_to_tmio(ohci)    ((struct tmio_hcd *)(ohci + 1))
++struct indexed_device_attribute{
++      struct device_attribute dev_attr;
++      int index;
++};
++#define to_indexed_dev_attr(_dev_attr) \
++      container_of(_dev_attr, struct indexed_device_attribute, dev_attr)
++
++#define INDEXED_ATTR(_name, _mode, _show, _store, _index)             \
++      { .dev_attr = __ATTR(_name ## _index, _mode, _show, _store),    \
++        .index = _index }
++
++#define INDEXED_DEVICE_ATTR(_name, _mode, _show, _store, _index)      \
++struct indexed_device_attribute dev_attr_##_name ## _index    \
++      = INDEXED_ATTR(_name, _mode, _show, _store, _index)
++
++static bool disabled_tmio_ports[MAX_TMIO_OHCI_PORTS];
++module_param_array(disabled_tmio_ports, bool, NULL, 0644);
++MODULE_PARM_DESC(disabled_tmio_ports,
++              "disable specified TC6393 usb ports (default: all enabled)");
++
+ /*-------------------------------------------------------------------------*/
++static void tmio_write_pm(struct platform_device *dev)
++{
++      struct usb_hcd                  *hcd    = platform_get_drvdata(dev);
++      struct tmio_hcd                 *tmio   = hcd_to_tmio(hcd);
++      struct tmio_uhccr __iomem       *ccr    = tmio->ccr;
++      u16                             pm;
++      unsigned long                   flags;
++
++      spin_lock_irqsave(&tmio->lock, flags);
++
++      pm = UHCCR_PM_GKEN | UHCCR_PM_CKRNEN |
++           UHCCR_PM_PMEE | UHCCR_PM_PMES;
++
++      if (tmio->disabled_ports[0])
++              pm |= UHCCR_PM_USBPW1;
++      if (tmio->disabled_ports[1])
++              pm |= UHCCR_PM_USBPW2;
++      if (tmio->disabled_ports[2])
++              pm |= UHCCR_PM_USBPW3;
++
++      iowrite16(pm,           &ccr->pm);
++      spin_unlock_irqrestore(&tmio->lock, flags);
++}
++
+ static void tmio_stop_hc(struct platform_device *dev)
+ {
+       struct mfd_cell                 *cell   = mfd_get_cell(dev);
+       struct usb_hcd                  *hcd    = platform_get_drvdata(dev);
++      struct ohci_hcd                 *ohci   = hcd_to_ohci(hcd);
+       struct tmio_hcd                 *tmio   = hcd_to_tmio(hcd);
+       struct tmio_uhccr __iomem       *ccr    = tmio->ccr;
+       u16                             pm;
+-      pm = UHCCR_PM_GKEN | UHCCR_PM_CKRNEN | UHCCR_PM_USBPW1 | UHCCR_PM_USBPW2;
++      pm = UHCCR_PM_GKEN | UHCCR_PM_CKRNEN;
++      switch (ohci->num_ports) {
++              default:
++                      dev_err(&dev->dev, "Unsupported amount of ports: %d\n", ohci->num_ports);
++              case 3:
++                      pm |= UHCCR_PM_USBPW3;
++              case 2:
++                      pm |= UHCCR_PM_USBPW2;
++              case 1:
++                      pm |= UHCCR_PM_USBPW1;
++      }
+       iowrite8(0,             &ccr->intc);
+       iowrite8(0,             &ccr->ilme);
+       iowrite16(0,            &ccr->basel);
+       iowrite16(0,            &ccr->baseh);
+-      iowrite16(pm,   &ccr->pm);
++      iowrite16(pm,           &ccr->pm);
+       cell->disable(dev);
+ }
+ static void tmio_start_hc(struct platform_device *dev)
+ {
+-      struct mfd_cell                 *cell   = mfd_get_cell(dev);
+       struct usb_hcd                  *hcd    = platform_get_drvdata(dev);
+       struct tmio_hcd                 *tmio   = hcd_to_tmio(hcd);
+       struct tmio_uhccr __iomem       *ccr    = tmio->ccr;
+-      u16                             pm;
+       unsigned long                   base    = hcd->rsrc_start;
+-      pm = UHCCR_PM_CKRNEN | UHCCR_PM_GKEN | UHCCR_PM_PMEE | UHCCR_PM_PMES;
+-      cell->enable(dev);
+-
+-      iowrite16(pm,   &ccr->pm);
++      tmio_write_pm(dev);
+       iowrite16(base,         &ccr->basel);
+       iowrite16(base >> 16,   &ccr->baseh);
+       iowrite8(1,             &ccr->ilme);
+@@ -133,9 +188,56 @@ static void tmio_start_hc(struct platform_device *dev)
+                       ioread8(&ccr->revid), hcd->rsrc_start, hcd->irq);
+ }
++static ssize_t tmio_disabled_port_show(struct device *dev,
++              struct device_attribute *attr,
++              char *buf)
++{
++      struct usb_hcd          *hcd    = dev_get_drvdata(dev);
++      struct tmio_hcd         *tmio   = hcd_to_tmio(hcd);
++      int                     index   = to_indexed_dev_attr(attr)->index;
++      return snprintf(buf, PAGE_SIZE, "%c",
++                      tmio->disabled_ports[index-1]? 'Y': 'N');
++}
++
++static ssize_t tmio_disabled_port_store(struct device *dev,
++              struct device_attribute *attr,
++              const char *buf, size_t count)
++{
++      struct usb_hcd          *hcd    = dev_get_drvdata(dev);
++      struct tmio_hcd         *tmio   = hcd_to_tmio(hcd);
++      int                     index   = to_indexed_dev_attr(attr)->index;
++
++      if (!count)
++              return -EINVAL;
++
++      switch (buf[0]) {
++      case 'y': case 'Y': case '1':
++              tmio->disabled_ports[index-1] = true;
++              break;
++      case 'n': case 'N': case '0':
++              tmio->disabled_ports[index-1] = false;
++              break;
++      default:
++              return -EINVAL;
++      }
++
++      tmio_write_pm(to_platform_device(dev));
++
++      return 1;
++}
++
++
++static INDEXED_DEVICE_ATTR(disabled_usb_port, S_IRUGO | S_IWUSR,
++              tmio_disabled_port_show, tmio_disabled_port_store, 1);
++static INDEXED_DEVICE_ATTR(disabled_usb_port, S_IRUGO | S_IWUSR,
++              tmio_disabled_port_show, tmio_disabled_port_store, 2);
++static INDEXED_DEVICE_ATTR(disabled_usb_port, S_IRUGO | S_IWUSR,
++              tmio_disabled_port_show, tmio_disabled_port_store, 3);
++
+ static int usb_hcd_tmio_probe(const struct hc_driver *driver,
+               struct platform_device *dev)
+ {
++      struct mfd_cell         *cell   = mfd_get_cell(dev);
+       struct resource         *config = platform_get_resource_byname(dev, IORESOURCE_MEM, TMIO_OHCI_CONFIG);
+       struct resource         *regs   = platform_get_resource_byname(dev, IORESOURCE_MEM, TMIO_OHCI_CONTROL);
+       struct resource         *sram   = platform_get_resource_byname(dev, IORESOURCE_MEM, TMIO_OHCI_SRAM);
+@@ -159,6 +261,12 @@ static int usb_hcd_tmio_probe(const struct hc_driver *driver,
+       tmio            = hcd_to_tmio(hcd);
++      spin_lock_init(&tmio->lock);
++
++      memcpy(tmio->disabled_ports,
++                      disabled_tmio_ports,
++                      sizeof(disabled_tmio_ports));
++
+       tmio->ccr = ioremap(config->start, config->end - config->start + 1);
+       if (!tmio->ccr) {
+               retval = -ENOMEM;
+@@ -183,17 +291,46 @@ static int usb_hcd_tmio_probe(const struct hc_driver *driver,
+       if (retval)
+               goto err_dmabounce_register_dev;
++      retval = cell->enable(dev);
++      if (retval)
++              goto err_enable;
++
+       tmio_start_hc(dev);
+       ohci = hcd_to_ohci(hcd);
+       ohci_hcd_init(ohci);
+       retval = usb_add_hcd(hcd, irq, IRQF_DISABLED);
++      if (retval)
++              goto err_add_hcd;
++
++      switch (ohci->num_ports) {
++              default:
++                      dev_err(&dev->dev, "Unsupported amount of ports: %d\n",
++                                      ohci->num_ports);
++              case 3:
++                      retval |= device_create_file(&dev->dev,
++                                      &dev_attr_disabled_usb_port3.dev_attr);
++              case 2:
++                      retval |= device_create_file(&dev->dev,
++                                      &dev_attr_disabled_usb_port2.dev_attr);
++              case 1:
++                      retval |= device_create_file(&dev->dev,
++                                      &dev_attr_disabled_usb_port1.dev_attr);
++      }
+       if (retval == 0)
+               return retval;
+-      tmio_stop_hc(dev);
++      device_remove_file(&dev->dev, &dev_attr_disabled_usb_port3.dev_attr);
++      device_remove_file(&dev->dev, &dev_attr_disabled_usb_port2.dev_attr);
++      device_remove_file(&dev->dev, &dev_attr_disabled_usb_port1.dev_attr);
++
++      usb_remove_hcd(hcd);
++err_add_hcd:
++      tmio_stop_hc(dev);
++      cell->disable(dev);
++err_enable:
+       dmabounce_unregister_dev(&dev->dev);
+ err_dmabounce_register_dev:
+       dma_release_declared_memory(&dev->dev);
+@@ -212,6 +349,9 @@ static void usb_hcd_tmio_remove(struct usb_hcd *hcd, struct platform_device *dev
+ {
+       struct tmio_hcd         *tmio   = hcd_to_tmio(hcd);
++      device_remove_file(&dev->dev, &dev_attr_disabled_usb_port3.dev_attr);
++      device_remove_file(&dev->dev, &dev_attr_disabled_usb_port2.dev_attr);
++      device_remove_file(&dev->dev, &dev_attr_disabled_usb_port1.dev_attr);
+       usb_remove_hcd(hcd);
+       tmio_stop_hc(dev);
+       dmabounce_unregister_dev(&dev->dev);
+@@ -297,13 +437,22 @@ static u64 dma_mask = DMA_32BIT_MASK;
+ static int ohci_hcd_tmio_drv_probe(struct platform_device *dev)
+ {
+       struct resource         *sram   = platform_get_resource_byname(dev, IORESOURCE_MEM, TMIO_OHCI_SRAM);
++      int retval;
+       dev->dev.dma_mask = &dma_mask;
+       dev->dev.coherent_dma_mask = DMA_32BIT_MASK;
++      /* FIXME: move dmabounce checkers to tc6393xb core? */
+       dmabounce_register_checker(tmio_dmabounce_check, sram);
+-      return usb_hcd_tmio_probe(&ohci_tmio_hc_driver, dev);
++      retval = usb_hcd_tmio_probe(&ohci_tmio_hc_driver, dev);
++
++      if (retval == 0)
++              return retval;
++
++      dmabounce_remove_checker(tmio_dmabounce_check, sram);
++
++      return retval;
+ }
+ static int ohci_hcd_tmio_drv_remove(struct platform_device *dev)
+@@ -323,14 +472,31 @@ static int ohci_hcd_tmio_drv_remove(struct platform_device *dev)
+ #ifdef        CONFIG_PM
+ static int ohci_hcd_tmio_drv_suspend(struct platform_device *dev, pm_message_t state)
+ {
++      struct mfd_cell         *cell   = mfd_get_cell(dev);
+       struct usb_hcd          *hcd    = platform_get_drvdata(dev);
+       struct ohci_hcd         *ohci   = hcd_to_ohci(hcd);
++      struct tmio_hcd         *tmio   = hcd_to_tmio(hcd);
++      struct tmio_uhccr __iomem *ccr  = tmio->ccr;
++      unsigned long           flags;
++      u8                      misc;
++      int                     ret;
+       if (time_before(jiffies, ohci->next_statechange))
+               msleep(5);
+       ohci->next_statechange = jiffies;
+-      tmio_stop_hc(dev);
++      spin_lock_irqsave(&tmio->lock, flags);
++
++      misc = ioread8(&ccr->misc);
++      misc |= 1 << 3; /* USSUSP */
++      iowrite8(misc, &ccr->misc);
++
++      spin_unlock_irqrestore(&tmio->lock, flags);
++
++      ret = cell->suspend(dev);
++      if (ret)
++              return ret;
++
+       hcd->state = HC_STATE_SUSPENDED;
+       dev->dev.power.power_state = PMSG_SUSPEND;
+@@ -339,15 +505,33 @@ static int ohci_hcd_tmio_drv_suspend(struct platform_device *dev, pm_message_t s
+ static int ohci_hcd_tmio_drv_resume(struct platform_device *dev)
+ {
++      struct mfd_cell         *cell   = mfd_get_cell(dev);
+       struct usb_hcd          *hcd    = platform_get_drvdata(dev);
+       struct ohci_hcd         *ohci   = hcd_to_ohci(hcd);
++      struct tmio_hcd         *tmio   = hcd_to_tmio(hcd);
++      struct tmio_uhccr __iomem *ccr  = tmio->ccr;
++      unsigned long           flags;
++      u8                      misc;
++      int                     ret;
+       if (time_before(jiffies, ohci->next_statechange))
+               msleep(5);
+       ohci->next_statechange = jiffies;
++      ret = cell->resume(dev);
++      if (ret)
++              return ret;
++
+       tmio_start_hc(dev);
++      spin_lock_irqsave(&tmio->lock, flags);
++
++      misc = ioread8(&ccr->misc);
++      misc &= ~(1 << 3); /* USSUSP */
++      iowrite8(misc, &ccr->misc);
++
++      spin_unlock_irqrestore(&tmio->lock, flags);
++
+       dev->dev.power.power_state = PMSG_ON;
+       usb_hcd_resume_root_hub(hcd);
+-- 
+1.5.3.8
+
diff --git a/packages/kexecboot/linux-kexecboot-2.6.24/tosa/0046-patch-tc6393xb-cleanup.patch b/packages/kexecboot/linux-kexecboot-2.6.24/tosa/0046-patch-tc6393xb-cleanup.patch
new file mode 100644 (file)
index 0000000..c4b57cb
--- /dev/null
@@ -0,0 +1,66 @@
+From edaab7ec86235871d8ad219a1d225ce12f67f8af Mon Sep 17 00:00:00 2001
+From: Dmitry Baryshkov <dbaryshkov@gmail.com>
+Date: Wed, 9 Jan 2008 02:13:29 +0300
+Subject: [PATCH 46/64] patch tc6393xb-cleanup
+
+---
+ drivers/mfd/tc6393xb.c |   20 ++++++++++++--------
+ 1 files changed, 12 insertions(+), 8 deletions(-)
+
+diff --git a/drivers/mfd/tc6393xb.c b/drivers/mfd/tc6393xb.c
+index 5d17687..dfae61d 100644
+--- a/drivers/mfd/tc6393xb.c
++++ b/drivers/mfd/tc6393xb.c
+@@ -590,16 +590,8 @@ static int tc6393xb_hw_init(struct platform_device *dev, int resume)
+       struct tc6393xb_platform_data   *tcpd   = dev->dev.platform_data;
+       struct tc6393xb                 *tc6393xb = platform_get_drvdata(dev);
+       struct tc6393xb_scr __iomem     *scr    = tc6393xb->scr;
+-      int                             ret;
+       int                             i;
+-      if (resume)
+-              ret = tcpd->resume(dev);
+-      else
+-              ret = tcpd->enable(dev);
+-      if (ret)
+-              return ret;
+-
+       iowrite8(resume ?
+               tc6393xb->suspend_state.fer.raw :
+               0,                              &scr->fer);
+@@ -664,6 +656,10 @@ static int __devinit tc6393xb_probe(struct platform_device *dev)
+               goto err_ioremap;
+       }
++      retval = tcpd->enable(dev);
++      if (retval)
++              goto err_enable;
++
+       retval = tc6393xb_hw_init(dev, 0);
+       if (retval)
+               goto err_hw_init;
+@@ -690,6 +686,8 @@ static int __devinit tc6393xb_probe(struct platform_device *dev)
+               tc6393xb_detach_irq(dev);
+ err_hw_init:
++      tcpd->disable(dev);
++err_enable:
+       iounmap(tc6393xb->scr);
+ err_ioremap:
+       release_resource(rscr);
+@@ -743,6 +741,12 @@ static int tc6393xb_suspend(struct platform_device *dev, pm_message_t state)
+ static int tc6393xb_resume(struct platform_device *dev)
+ {
++      struct tc6393xb_platform_data   *tcpd   = dev->dev.platform_data;
++      int ret = tcpd->resume(dev);
++
++      if (ret)
++              return ret;
++
+       return tc6393xb_hw_init(dev, 1);
+ }
+ #else
+-- 
+1.5.3.8
+
diff --git a/packages/kexecboot/linux-kexecboot-2.6.24/tosa/0047-tc6393xb-use-bitmasks-instead-of-bit-field-structs.patch b/packages/kexecboot/linux-kexecboot-2.6.24/tosa/0047-tc6393xb-use-bitmasks-instead-of-bit-field-structs.patch
new file mode 100644 (file)
index 0000000..54e8825
--- /dev/null
@@ -0,0 +1,412 @@
+From c18b8e34c39ec0d395988318e6651076a748d6bd Mon Sep 17 00:00:00 2001
+From: Dmitry Baryshkov <dbaryshkov@gmail.com>
+Date: Tue, 12 Feb 2008 04:40:54 +0300
+Subject: [PATCH 47/64] tc6393xb: use bitmasks instead of bit-field structs
+
+Signed-off-by: Dmitry Baryshkov <dbaryshkov@gmail.com>
+---
+ drivers/mfd/tc6393xb.c       |  162 ++++++++++++++++++++++++-----------------
+ include/linux/mfd/tc6393xb.h |   63 +++-------------
+ 2 files changed, 107 insertions(+), 118 deletions(-)
+
+diff --git a/drivers/mfd/tc6393xb.c b/drivers/mfd/tc6393xb.c
+index dfae61d..1a394e4 100644
+--- a/drivers/mfd/tc6393xb.c
++++ b/drivers/mfd/tc6393xb.c
+@@ -24,6 +24,31 @@
+ #include <linux/mfd/tmio.h>
+ #include <linux/mfd/tc6393xb.h>
++#define TC6393XB_FER_USBEN            BIT(0)  /* USB host enable */
++#define TC6393XB_FER_LCDCVEN          BIT(1)  /* polysilicon TFT enable */
++#define TC6393XB_FER_SLCDEN           BIT(2)  /* SLCD enable */
++
++enum pincontrol {
++      opendrain       = 0,
++      tristate        = 1,
++      pushpull        = 2,
++      /* reserved     = 3, */
++};
++
++#define TC6393XB_MCR_RDY_MASK         (3 << 0)
++#define TC6393XB_MCR_RDY_OPENDRAIN    (0 << 0)
++#define TC6393XB_MCR_RDY_TRISTATE     (1 << 0)
++#define TC6393XB_MCR_RDY_PUSHPULL     (2 << 0)
++#define TC6393XB_MCR_RDY_UNK          BIT(2)
++#define TC6393XB_MCR_RDY_EN           BIT(3)
++#define TC6393XB_MCR_INT_MASK         (3 << 4)
++#define TC6393XB_MCR_INT_OPENDRAIN    (0 << 4)
++#define TC6393XB_MCR_INT_TRISTATE     (1 << 4)
++#define TC6393XB_MCR_INT_PUSHPULL     (2 << 4)
++#define TC6393XB_MCR_INT_UNK          BIT(6)
++#define TC6393XB_MCR_INT_EN           BIT(7)
++/* bits 8 - 16 are unknown */
++
+ struct tc6393xb_scr {
+       u8 x00[8];
+       u8      revid;          /* 0x08 Revision ID                     */
+@@ -74,8 +99,8 @@ struct tc6393xb {
+       spinlock_t                      lock; /* protects RMW cycles */
+       struct {
+-              union tc6393xb_scr_fer  fer;
+-              union tc6393xb_scr_ccr  ccr;
++              u8                      fer;
++              u16                     ccr;
+               u8                      gpi_bcr[4];
+       } suspend_state;
+@@ -90,13 +115,13 @@ static int tc6393xb_mmc_enable(struct platform_device *mmc) {
+       struct platform_device          *dev    = to_platform_device(mmc->dev.parent);
+       struct tc6393xb                 *tc6393xb = platform_get_drvdata(dev);
+       struct tc6393xb_scr __iomem     *scr = tc6393xb->scr;
+-      union tc6393xb_scr_ccr          ccr;
++      u16                             ccr;
+       unsigned long                   flags;
+       spin_lock_irqsave(&tc6393xb->lock, flags);
+-      ccr.raw = ioread16(&scr->ccr);
+-      ccr.bits.ck32ken = 1;
+-      iowrite16(ccr.raw, &scr->ccr);
++      ccr = ioread16(&scr->ccr);
++      ccr |= TC6393XB_CCR_CK32K;
++      iowrite16(ccr, &scr->ccr);
+       spin_unlock_irqrestore(&tc6393xb->lock, flags);
+       return 0;
+@@ -106,13 +131,13 @@ static int tc6393xb_mmc_disable(struct platform_device *mmc) {
+       struct platform_device          *dev    = to_platform_device(mmc->dev.parent);
+       struct tc6393xb                 *tc6393xb = platform_get_drvdata(dev);
+       struct tc6393xb_scr __iomem     *scr    = tc6393xb->scr;
+-      union tc6393xb_scr_ccr          ccr;
++      u16                             ccr;
+       unsigned long                   flags;
+       spin_lock_irqsave(&tc6393xb->lock, flags);
+-      ccr.raw = ioread16(&scr->ccr);
+-      ccr.bits.ck32ken = 0;
+-      iowrite16(ccr.raw, &scr->ccr);
++      ccr = ioread16(&scr->ccr);
++      ccr &= ~TC6393XB_CCR_CK32K;
++      iowrite16(ccr, &scr->ccr);
+       spin_unlock_irqrestore(&tc6393xb->lock, flags);
+       return 0;
+@@ -148,14 +173,17 @@ int tc6393xb_lcd_set_power(struct platform_device *fb, bool on)
+       struct platform_device          *dev    = to_platform_device(fb->dev.parent);
+       struct tc6393xb                 *tc6393xb = platform_get_drvdata(dev);
+       struct tc6393xb_scr __iomem     *scr    = tc6393xb->scr;
+-      union tc6393xb_scr_fer          fer;
++      u8                              fer;
+       unsigned long                   flags;
+       spin_lock_irqsave(&tc6393xb->lock, flags);
+-      fer.raw = ioread8(&scr->fer);
+-      fer.bits.slcden = on ? 1 : 0;
+-      iowrite8(fer.raw, &scr->fer);
++      fer = ioread8(&scr->fer);
++      if (on)
++              fer |= TC6393XB_FER_SLCDEN;
++      else
++              fer &= ~TC6393XB_FER_SLCDEN;
++      iowrite8(fer, &scr->fer);
+       spin_unlock_irqrestore(&tc6393xb->lock, flags);
+@@ -181,19 +209,19 @@ static int tc6393xb_ohci_disable(struct platform_device *ohci)
+       struct platform_device          *dev    = to_platform_device(ohci->dev.parent);
+       struct tc6393xb                 *tc6393xb = platform_get_drvdata(dev);
+       struct tc6393xb_scr __iomem     *scr    = tc6393xb->scr;
+-      union tc6393xb_scr_ccr          ccr;
+-      union tc6393xb_scr_fer          fer;
++      u16                             ccr;
++      u8                              fer;
+       unsigned long                   flags;
+       spin_lock_irqsave(&tc6393xb->lock, flags);
+-      fer.raw = ioread8(&scr->fer);
+-      fer.bits.usben = 0;
+-      iowrite8(fer.raw, &scr->fer);
++      fer = ioread8(&scr->fer);
++      fer &= ~TC6393XB_FER_USBEN;
++      iowrite8(fer, &scr->fer);
+-      ccr.raw = ioread16(&scr->ccr);
+-      ccr.bits.usbcken = 0;
+-      iowrite16(ccr.raw, &scr->ccr);
++      ccr = ioread16(&scr->ccr);
++      ccr &= ~TC6393XB_CCR_USBCK;
++      iowrite16(ccr, &scr->ccr);
+       spin_unlock_irqrestore(&tc6393xb->lock, flags);
+@@ -205,19 +233,19 @@ static int tc6393xb_ohci_enable(struct platform_device *ohci)
+       struct platform_device          *dev    = to_platform_device(ohci->dev.parent);
+       struct tc6393xb                 *tc6393xb = platform_get_drvdata(dev);
+       struct tc6393xb_scr __iomem     *scr    = tc6393xb->scr;
+-      union tc6393xb_scr_ccr          ccr;
+-      union tc6393xb_scr_fer          fer;
++      u16                             ccr;
++      u8                              fer;
+       unsigned long                   flags;
+       spin_lock_irqsave(&tc6393xb->lock, flags);
+-      ccr.raw = ioread16(&scr->ccr);
+-      ccr.bits.usbcken = 1;
+-      iowrite16(ccr.raw, &scr->ccr);
++      ccr = ioread16(&scr->ccr);
++      ccr |= TC6393XB_CCR_USBCK;
++      iowrite16(ccr, &scr->ccr);
+-      fer.raw = ioread8(&scr->fer);
+-      fer.bits.usben = 1;
+-      iowrite8(fer.raw, &scr->fer);
++      fer = ioread8(&scr->fer);
++      fer |= TC6393XB_FER_USBEN;
++      iowrite8(fer, &scr->fer);
+       spin_unlock_irqrestore(&tc6393xb->lock, flags);
+@@ -229,14 +257,14 @@ static int tc6393xb_ohci_suspend(struct platform_device *ohci)
+       struct platform_device          *dev    = to_platform_device(ohci->dev.parent);
+       struct tc6393xb                 *tc6393xb = platform_get_drvdata(dev);
+       struct tc6393xb_scr __iomem     *scr    = tc6393xb->scr;
+-      union tc6393xb_scr_ccr          ccr;
++      u16                             ccr;
+       unsigned long                   flags;
+       spin_lock_irqsave(&tc6393xb->lock, flags);
+-      ccr.raw = ioread16(&scr->ccr);
+-      ccr.bits.usbcken = 0;
+-      iowrite16(ccr.raw, &scr->ccr);
++      ccr = ioread16(&scr->ccr);
++      ccr &= ~TC6393XB_CCR_USBCK;
++      iowrite16(ccr, &scr->ccr);
+       spin_unlock_irqrestore(&tc6393xb->lock, flags);
+@@ -248,14 +276,14 @@ static int tc6393xb_ohci_resume(struct platform_device *ohci)
+       struct platform_device          *dev    = to_platform_device(ohci->dev.parent);
+       struct tc6393xb                 *tc6393xb = platform_get_drvdata(dev);
+       struct tc6393xb_scr __iomem     *scr    = tc6393xb->scr;
+-      union tc6393xb_scr_ccr          ccr;
++      u16                             ccr;
+       unsigned long                   flags;
+       spin_lock_irqsave(&tc6393xb->lock, flags);
+-      ccr.raw = ioread16(&scr->ccr);
+-      ccr.bits.usbcken = 1;
+-      iowrite16(ccr.raw, &scr->ccr);
++      ccr = ioread16(&scr->ccr);
++      ccr |= TC6393XB_CCR_USBCK;
++      iowrite16(ccr, &scr->ccr);
+       spin_unlock_irqrestore(&tc6393xb->lock, flags);
+@@ -267,8 +295,8 @@ static int tc6393xb_fb_disable(struct platform_device *fb)
+       struct platform_device          *dev    = to_platform_device(fb->dev.parent);
+       struct tc6393xb                 *tc6393xb = platform_get_drvdata(dev);
+       struct tc6393xb_scr __iomem     *scr    = tc6393xb->scr;
+-      union tc6393xb_scr_ccr          ccr;
+-      union tc6393xb_scr_fer          fer;
++      u16                             ccr;
++      u8                              fer;
+       unsigned long                   flags;
+       spin_lock_irqsave(&tc6393xb->lock, flags);
+@@ -276,14 +304,13 @@ static int tc6393xb_fb_disable(struct platform_device *fb)
+       /*
+        * FIXME: is this correct or it should be moved to other _disable?
+        */
+-      fer.raw = ioread8(&scr->fer);
+-      fer.bits.slcden = 0;
+-/*    fer.bits.lcdcven = 0; */
+-      iowrite8(fer.raw, &scr->fer);
++      fer = ioread8(&scr->fer);
++      fer &= ~TC6393XB_FER_SLCDEN;
++      iowrite8(fer, &scr->fer);
+-      ccr.raw = ioread16(&scr->ccr);
+-      ccr.bits.mclksel = disable;
+-      iowrite16(ccr.raw, &scr->ccr);
++      ccr = ioread16(&scr->ccr);
++      ccr = (ccr & ~TC6393XB_CCR_MCLK_MASK) | TC6393XB_CCR_MCLK_OFF;
++      iowrite16(ccr, &scr->ccr);
+       spin_unlock_irqrestore(&tc6393xb->lock, flags);
+@@ -295,14 +322,14 @@ static int tc6393xb_fb_enable(struct platform_device *fb)
+       struct platform_device          *dev    = to_platform_device(fb->dev.parent);
+       struct tc6393xb                 *tc6393xb = platform_get_drvdata(dev);
+       struct tc6393xb_scr __iomem     *scr    = tc6393xb->scr;
+-      union tc6393xb_scr_ccr          ccr;
++      u16                             ccr;
+       unsigned long                   flags;
+       spin_lock_irqsave(&tc6393xb->lock, flags);
+-      ccr.raw = ioread16(&scr->ccr);
+-      ccr.bits.mclksel = m48MHz;
+-      iowrite16(ccr.raw, &scr->ccr);
++      ccr = ioread16(&scr->ccr);
++      ccr = (ccr & ~TC6393XB_CCR_MCLK_MASK) | TC6393XB_CCR_MCLK_48;
++      iowrite16(ccr, &scr->ccr);
+       spin_unlock_irqrestore(&tc6393xb->lock, flags);
+@@ -314,14 +341,14 @@ static int tc6393xb_fb_suspend(struct platform_device *fb)
+       struct platform_device          *dev    = to_platform_device(fb->dev.parent);
+       struct tc6393xb                 *tc6393xb = platform_get_drvdata(dev);
+       struct tc6393xb_scr __iomem     *scr    = tc6393xb->scr;
+-      union tc6393xb_scr_ccr          ccr;
++      u16                             ccr;
+       unsigned long                   flags;
+       spin_lock_irqsave(&tc6393xb->lock, flags);
+-      ccr.raw = ioread16(&scr->ccr);
+-      ccr.bits.mclksel = disable;
+-      iowrite16(ccr.raw, &scr->ccr);
++      ccr = ioread16(&scr->ccr);
++      ccr = (ccr & ~TC6393XB_CCR_MCLK_MASK) | TC6393XB_CCR_MCLK_OFF;
++      iowrite16(ccr, &scr->ccr);
+       spin_unlock_irqrestore(&tc6393xb->lock, flags);
+@@ -333,14 +360,14 @@ static int tc6393xb_fb_resume(struct platform_device *fb)
+       struct platform_device          *dev    = to_platform_device(fb->dev.parent);
+       struct tc6393xb                 *tc6393xb = platform_get_drvdata(dev);
+       struct tc6393xb_scr __iomem     *scr    = tc6393xb->scr;
+-      union tc6393xb_scr_ccr          ccr;
++      u16                             ccr;
+       unsigned long                   flags;
+       spin_lock_irqsave(&tc6393xb->lock, flags);
+-      ccr.raw = ioread16(&scr->ccr);
+-      ccr.bits.mclksel = m48MHz;
+-      iowrite16(ccr.raw, &scr->ccr);
++      ccr = ioread16(&scr->ccr);
++      ccr = (ccr & ~TC6393XB_CCR_MCLK_MASK) | TC6393XB_CCR_MCLK_48;
++      iowrite16(ccr, &scr->ccr);
+       spin_unlock_irqrestore(&tc6393xb->lock, flags);
+@@ -592,14 +619,15 @@ static int tc6393xb_hw_init(struct platform_device *dev, int resume)
+       struct tc6393xb_scr __iomem     *scr    = tc6393xb->scr;
+       int                             i;
+-      iowrite8(resume ?
+-              tc6393xb->suspend_state.fer.raw :
+-              0,                              &scr->fer);
++      iowrite8(resume ? tc6393xb->suspend_state.fer : 0,
++                                              &scr->fer);
+       iowrite16(tcpd->scr_pll2cr,             &scr->pll2cr);
+       iowrite16(resume?
+-              tc6393xb->suspend_state.ccr.raw :
+-              tcpd->scr_ccr.raw,              &scr->ccr);
+-      iowrite16(tcpd->scr_mcr.raw,            &scr->mcr);
++              tc6393xb->suspend_state.ccr :
++              tcpd->scr_ccr,          &scr->ccr);
++      iowrite16(TC6393XB_MCR_RDY_OPENDRAIN | TC6393XB_MCR_RDY_UNK | TC6393XB_MCR_RDY_EN |
++                TC6393XB_MCR_INT_OPENDRAIN | TC6393XB_MCR_INT_UNK | TC6393XB_MCR_INT_EN |
++                BIT(15),              &scr->mcr);
+       iowrite16(tcpd->scr_gper,               &scr->gper);
+       iowrite8(0,                             &scr->irr);
+       iowrite8(0xbf,                          &scr->imr);
+@@ -730,8 +758,8 @@ static int tc6393xb_suspend(struct platform_device *dev, pm_message_t state)
+       int i;
+-      tc6393xb->suspend_state.ccr.raw         = ioread16(&scr->ccr);
+-      tc6393xb->suspend_state.fer.raw         = ioread8(&scr->fer);
++      tc6393xb->suspend_state.ccr             = ioread16(&scr->ccr);
++      tc6393xb->suspend_state.fer             = ioread8(&scr->fer);
+       for (i = 0; i < 4; i++)
+               tc6393xb->suspend_state.gpi_bcr[i] =
+                       ioread8(scr->gpi_bcr + i);
+diff --git a/include/linux/mfd/tc6393xb.h b/include/linux/mfd/tc6393xb.h
+index e699294..2c69f63 100644
+--- a/include/linux/mfd/tc6393xb.h
++++ b/include/linux/mfd/tc6393xb.h
+@@ -20,60 +20,21 @@
+ #include <linux/mfd-core.h>
+ #include <linux/mfd/tmio.h>
+-union tc6393xb_scr_fer {
+-      u8              raw;
+-struct {
+-      unsigned        usben:1;        /* D0   USB enable              */
+-      unsigned        lcdcven:1;      /* D1   polysylicon TFT enable  */
+-      unsigned        slcden:1;       /* D2   SLCD enable             */
+-} __attribute__ ((packed)) bits;
+-} __attribute__ ((packed));
+-
+-union tc6393xb_scr_ccr {
+-      u16             raw;
+-struct {
+-      unsigned        ck32ken:1;      /* D0   SD host clock enable    */
+-      unsigned        usbcken:1;      /* D1   USB host clock enable   */
+-      unsigned        x00:2;
+-      unsigned        sharp:1;        /* D4   ??? set in Sharp's code */
+-      unsigned        x01:3;
+-      enum {                          disable = 0,
+-                                      m12MHz  = 1,
+-                                      m24MHz  = 2,
+-                                      m48MHz  = 3,
+-      }               mclksel:3;      /* D10-D8  LCD controller clock */
+-      unsigned        x02:1;
+-      enum {                          h24MHz  = 0,
+-                                      h48MHz  = 1,
+-      }               hclksel:2;      /* D13-D12 host bus clock       */
+-      unsigned        x03:2;
+-} __attribute__ ((packed)) bits;
+-} __attribute__ ((packed));
+-
+-enum pincontrol {
+-      opendrain       = 0,
+-      tristate        = 1,
+-      pushpull        = 2,
+-      /* reserved     = 3, */
+-};
+-
+-union tc6393xb_scr_mcr {
+-      u16             raw;
+-struct {
+-      enum pincontrol rdyst:2;        /* D1-D0   HRDY control         */
+-      unsigned        x00:1;
+-      unsigned        aren:1;         /* D3      HRDY pull up resistance cut off */
+-      enum pincontrol intst:2;        /* D5-D4   #HINT control        */
+-      unsigned        x01:1;
+-      unsigned        aien:1;         /* D7      #HINT pull up resitance cut off */
+-      unsigned        x02:8;
+-} __attribute__ ((packed)) bits;
+-} __attribute__ ((packed));
++#define TC6393XB_CCR_CK32K    BIT(0)
++#define TC6393XB_CCR_USBCK    BIT(1)
++#define TC6393XB_CCR_UNK1     BIT(4)
++#define TC6393XB_CCR_MCLK_MASK        (7 << 8)
++#define TC6393XB_CCR_MCLK_OFF (0 << 8)
++#define TC6393XB_CCR_MCLK_12  (1 << 8)
++#define TC6393XB_CCR_MCLK_24  (2 << 8)
++#define TC6393XB_CCR_MCLK_48  (3 << 8)
++#define TC6393XB_CCR_HCLK_MASK        (3 << 12)
++#define TC6393XB_CCR_HCLK_24  (0 << 12)
++#define TC6393XB_CCR_HCLK_48  (1 << 12)
+ struct tc6393xb_platform_data {
+       u16     scr_pll2cr;     /* PLL2 Control */
+-      union tc6393xb_scr_ccr  scr_ccr;        /* Clock Control */
+-      union tc6393xb_scr_mcr  scr_mcr;        /* Mode Control */
++      u16     scr_ccr;        /* Clock Control */
+       u16     scr_gper;       /* GP Enable */
+       u32     scr_gpo_doecr;  /* GPO Data OE Control */
+       u32     scr_gpo_dsr;    /* GPO Data Set */
+-- 
+1.5.3.8
+
diff --git a/packages/kexecboot/linux-kexecboot-2.6.24/tosa/0048-tc6393xb-GPIO-support.patch b/packages/kexecboot/linux-kexecboot-2.6.24/tosa/0048-tc6393xb-GPIO-support.patch
new file mode 100644 (file)
index 0000000..ef47d6c
--- /dev/null
@@ -0,0 +1,225 @@
+From 4fb4d83c7090ea21619bb652f2ea9b5c8c0c453e Mon Sep 17 00:00:00 2001
+From: Dmitry Baryshkov <dbaryshkov@gmail.com>
+Date: Wed, 9 Jan 2008 01:42:58 +0300
+Subject: [PATCH 48/64] tc6393xb GPIO support
+
+Signed-off-by: Dmitry Baryshkov <dbaryshkov@gmail.com>
+---
+ drivers/mfd/tc6393xb.c       |  124 ++++++++++++++++++++++++++++++++++++++++--
+ include/linux/mfd/tc6393xb.h |    2 +-
+ 2 files changed, 119 insertions(+), 7 deletions(-)
+
+diff --git a/drivers/mfd/tc6393xb.c b/drivers/mfd/tc6393xb.c
+index 1a394e4..9001687 100644
+--- a/drivers/mfd/tc6393xb.c
++++ b/drivers/mfd/tc6393xb.c
+@@ -49,6 +49,8 @@ enum pincontrol {
+ #define TC6393XB_MCR_INT_EN           BIT(7)
+ /* bits 8 - 16 are unknown */
++#include <asm/gpio.h>
++
+ struct tc6393xb_scr {
+       u8 x00[8];
+       u8      revid;          /* 0x08 Revision ID                     */
+@@ -96,6 +98,8 @@ struct tc6393xb_scr {
+ struct tc6393xb {
+       struct tc6393xb_scr __iomem     *scr;
++      struct gpio_chip                gpio;
++
+       spinlock_t                      lock; /* protects RMW cycles */
+       struct {
+@@ -513,6 +517,96 @@ static struct mfd_cell tc6393xb_cells[] = {
+ /*--------------------------------------------------------------------------*/
++static int tc6393xb_gpio_get(struct gpio_chip *chip,
++              unsigned offset)
++{
++      struct tc6393xb                 *tc6393xb = container_of(chip,
++                                              struct tc6393xb, gpio);
++      struct tc6393xb_scr __iomem     *scr    = tc6393xb->scr;
++      u32                              mask   = 1 << offset;
++
++      return tmio_ioread32(scr->gpo_dsr) & mask;
++}
++
++static void __tc6393xb_gpio_set(struct gpio_chip *chip,
++              unsigned offset, int value)
++{
++      struct tc6393xb                 *tc6393xb = container_of(chip,
++                                              struct tc6393xb, gpio);
++      struct tc6393xb_scr __iomem     *scr    = tc6393xb->scr;
++      u32                             dsr;
++
++      dsr = tmio_ioread32(scr->gpo_dsr);
++      if (value)
++              dsr |= (1L << offset);
++      else
++              dsr &= ~(1L << offset);
++
++      tmio_iowrite32(dsr, scr->gpo_dsr);
++}
++
++static void tc6393xb_gpio_set(struct gpio_chip *chip,
++              unsigned offset, int value)
++{
++      struct tc6393xb                 *tc6393xb = container_of(chip,
++                                              struct tc6393xb, gpio);
++      unsigned long                   flags;
++
++      spin_lock_irqsave(&tc6393xb->lock, flags);
++
++      __tc6393xb_gpio_set(chip, offset, value);
++
++      spin_unlock_irqrestore(&tc6393xb->lock, flags);
++}
++
++static int tc6393xb_gpio_direction_input(struct gpio_chip *chip,
++                      unsigned offset)
++{
++      struct tc6393xb                 *tc6393xb = container_of(chip,
++                                              struct tc6393xb, gpio);
++      struct tc6393xb_scr __iomem     *scr    = tc6393xb->scr;
++      unsigned long                   flags;
++      u32                             doecr;
++
++      spin_lock_irqsave(&tc6393xb->lock, flags);
++
++      doecr = tmio_ioread32(scr->gpo_doecr);
++
++      doecr &= ~(1 << offset);
++
++      tmio_iowrite32(doecr, scr->gpo_doecr);
++
++      spin_unlock_irqrestore(&tc6393xb->lock, flags);
++
++      return 0;
++}
++
++static int tc6393xb_gpio_direction_output(struct gpio_chip *chip,
++                      unsigned offset, int value)
++{
++      struct tc6393xb                 *tc6393xb = container_of(chip,
++                                              struct tc6393xb, gpio);
++      struct tc6393xb_scr __iomem     *scr    = tc6393xb->scr;
++      unsigned long                   flags;
++      u32                             doecr;
++
++      spin_lock_irqsave(&tc6393xb->lock, flags);
++
++      doecr = tmio_ioread32(scr->gpo_doecr);
++
++      doecr |= (1 << offset);
++
++      tmio_iowrite32(doecr, scr->gpo_doecr);
++
++      __tc6393xb_gpio_set(chip, offset, value);
++
++      spin_unlock_irqrestore(&tc6393xb->lock, flags);
++
++      return 0;
++}
++
++/*--------------------------------------------------------------------------*/
++
+ static void
+ tc6393xb_irq(unsigned int irq, struct irq_desc *desc)
+ {
+@@ -631,10 +725,8 @@ static int tc6393xb_hw_init(struct platform_device *dev, int resume)
+       iowrite16(tcpd->scr_gper,               &scr->gper);
+       iowrite8(0,                             &scr->irr);
+       iowrite8(0xbf,                          &scr->imr);
+-      iowrite16(tcpd->scr_gpo_dsr,            scr->gpo_dsr + 0);
+-      iowrite16(tcpd->scr_gpo_dsr >> 16,      scr->gpo_dsr + 1);
+-      iowrite16(tcpd->scr_gpo_doecr,          scr->gpo_doecr + 0);
+-      iowrite16(tcpd->scr_gpo_doecr >> 16,    scr->gpo_doecr + 1);
++      tmio_iowrite32(tcpd->scr_gpo_dsr,       &scr->gpo_dsr);
++      tmio_iowrite32(tcpd->scr_gpo_doecr,     &scr->gpo_doecr);
+       if (resume)
+               for (i = 0; i < 4; i++)
+@@ -650,7 +742,7 @@ static int __devinit tc6393xb_probe(struct platform_device *dev)
+       struct tc6393xb         *tc6393xb;
+       struct resource         *iomem;
+       struct resource         *rscr;
+-      int                     retval;
++      int                     retval, temp;
+       iomem = platform_get_resource(dev, IORESOURCE_MEM, 0);
+       if (!iomem)
+@@ -696,6 +788,18 @@ static int __devinit tc6393xb_probe(struct platform_device *dev)
+                       ioread8(&tc6393xb->scr->revid),
+                       (unsigned long) iomem->start, tc6393xb->irq);
++      tc6393xb->gpio.label = "tc6393xb";
++      tc6393xb->gpio.base = tcpd->gpio_base;
++      tc6393xb->gpio.ngpio = 16; /* FIXME: actually 32, but I'm not sure */
++      tc6393xb->gpio.set = tc6393xb_gpio_set;
++      tc6393xb->gpio.get = tc6393xb_gpio_get;
++      tc6393xb->gpio.direction_input = tc6393xb_gpio_direction_input;
++      tc6393xb->gpio.direction_output = tc6393xb_gpio_direction_output;
++
++      retval = gpiochip_add(&tc6393xb->gpio);
++      if (retval)
++              goto err_gpio_add;
++
+       if (tc6393xb->irq)
+               tc6393xb_attach_irq(dev);
+@@ -713,6 +817,8 @@ static int __devinit tc6393xb_probe(struct platform_device *dev)
+       if (tc6393xb->irq)
+               tc6393xb_detach_irq(dev);
++err_gpio_add:
++      temp = gpiochip_remove(&tc6393xb->gpio);
+ err_hw_init:
+       tcpd->disable(dev);
+ err_enable:
+@@ -734,6 +840,12 @@ static int __devexit tc6393xb_remove(struct platform_device *dev) {
+       if (tc6393xb->irq)
+               tc6393xb_detach_irq(dev);
++      ret = gpiochip_remove(&tc6393xb->gpio);
++      if (ret) {
++              dev_err(&dev->dev, "Can't remove gpio chip: %d\n", ret);
++              return ret;
++      }
++
+       ret = tcpd->disable(dev);
+       iounmap(tc6393xb->scr);
+@@ -804,7 +916,7 @@ static void __exit tc6393xb_exit(void)
+       platform_driver_unregister(&tc6393xb_driver);
+ }
+-module_init(tc6393xb_init);
++subsys_initcall(tc6393xb_init);
+ module_exit(tc6393xb_exit);
+ MODULE_LICENSE("GPL");
+diff --git a/include/linux/mfd/tc6393xb.h b/include/linux/mfd/tc6393xb.h
+index 2c69f63..97c4c7c 100644
+--- a/include/linux/mfd/tc6393xb.h
++++ b/include/linux/mfd/tc6393xb.h
+@@ -45,6 +45,7 @@ struct tc6393xb_platform_data {
+       int     (*resume)(struct platform_device *dev);
+       int     irq_base;       /* a base for cascaded irq */
++      int     gpio_base;
+       struct tmio_nand_data   *nand_data;
+       struct tmio_fb_data     *fb_data;
+@@ -54,7 +55,6 @@ extern int tc6393xb_lcd_set_power(struct platform_device *fb_dev, bool on);
+ extern int tc6393xb_lcd_mode(struct platform_device *fb_dev,
+                                       struct fb_videomode *mode);
+-
+ /*
+  * Relative to irq_base
+  */
+-- 
+1.5.3.8
+
diff --git a/packages/kexecboot/linux-kexecboot-2.6.24/tosa/0049-platform-support-for-TMIO-on-tosa.patch b/packages/kexecboot/linux-kexecboot-2.6.24/tosa/0049-platform-support-for-TMIO-on-tosa.patch
new file mode 100644 (file)
index 0000000..ff1186c
--- /dev/null
@@ -0,0 +1,373 @@
+From 30588bdd5c5cdd9fbe269643f582862a76f09efb Mon Sep 17 00:00:00 2001
+From: Ian Molton <spyro@f2s.com>
+Date: Tue, 12 Feb 2008 04:52:48 +0300
+Subject: [PATCH 49/64] platform support for TMIO on tosa
+
+Signed-off-by: Dmitry Baryshkov <dbaryshkov@gmail.com>
+---
+ arch/arm/mach-pxa/tosa.c        |  179 ++++++++++++++++++++++++++++++++++++++-
+ include/asm-arm/arch-pxa/irqs.h |    1 +
+ include/asm-arm/arch-pxa/tosa.h |   45 ++++++++--
+ sound/soc/pxa/tosa.c            |    3 +-
+ 4 files changed, 216 insertions(+), 12 deletions(-)
+
+diff --git a/arch/arm/mach-pxa/tosa.c b/arch/arm/mach-pxa/tosa.c
+index 5268e94..e2eec0f 100644
+--- a/arch/arm/mach-pxa/tosa.c
++++ b/arch/arm/mach-pxa/tosa.c
+@@ -18,7 +18,13 @@
+ #include <linux/major.h>
+ #include <linux/fs.h>
+ #include <linux/interrupt.h>
++#include <linux/delay.h>
++#include <linux/fb.h>
+ #include <linux/mmc/host.h>
++#include <linux/mfd/tc6393xb.h>
++#include <linux/mfd/tmio.h>
++#include <linux/mtd/nand.h>
++#include <linux/mtd/partitions.h>
+ #include <linux/pm.h>
+ #include <linux/delay.h>
+ #include <linux/gpio_keys.h>
+@@ -298,12 +304,183 @@ static struct platform_device tosaled_device = {
+     .id     = -1,
+ };
++/*
++ * Toshiba Mobile IO Controller
++ */
++static struct resource tc6393xb_resources[] = {
++      [0] = {
++              .start  = TOSA_LCDC_PHYS,
++              .end    = TOSA_LCDC_PHYS + 0x3ffffff,
++              .flags  = IORESOURCE_MEM,
++      },
++
++      [1] = {
++              .start  = TOSA_IRQ_GPIO_TC6393XB_INT,
++              .end    = TOSA_IRQ_GPIO_TC6393XB_INT,
++              .flags  = IORESOURCE_IRQ,
++      },
++};
++
++
++static int tosa_tc6393xb_enable(struct platform_device *dev)
++{
++
++      reset_scoop_gpio(&tosascoop_jc_device.dev, TOSA_SCOOP_JC_TC6393XB_L3V_ON);
++      reset_scoop_gpio(&tosascoop_jc_device.dev, TOSA_SCOOP_JC_TC6393XB_SUSPEND);
++      reset_scoop_gpio(&tosascoop_device.dev, TOSA_SCOOP_TC6393XB_REST_IN);      /* #PCLR */
++      pxa_gpio_mode(GPIO11_3_6MHz_MD);
++      pxa_gpio_mode(GPIO18_RDY_MD);
++      mdelay(1);
++      set_scoop_gpio(&tosascoop_jc_device.dev, TOSA_SCOOP_JC_TC6393XB_SUSPEND);
++      mdelay(10);
++      set_scoop_gpio(&tosascoop_device.dev, TOSA_SCOOP_TC6393XB_REST_IN);        /* #PCLR */
++      set_scoop_gpio(&tosascoop_jc_device.dev, TOSA_SCOOP_JC_TC6393XB_L3V_ON);
++
++      return 0;
++}
++
++static int tosa_tc6393xb_disable(struct platform_device *dev)
++{
++
++      reset_scoop_gpio(&tosascoop_jc_device.dev, TOSA_SCOOP_JC_TC6393XB_L3V_ON);
++      reset_scoop_gpio(&tosascoop_jc_device.dev, TOSA_SCOOP_JC_TC6393XB_SUSPEND);
++      reset_scoop_gpio(&tosascoop_device.dev, TOSA_SCOOP_TC6393XB_REST_IN);      /* #PCLR */
++      pxa_gpio_mode(GPIO11_3_6MHz_MD|GPIO_OUT);
++      GPSR0 = GPIO_bit(GPIO11_3_6MHz);
++
++      return 0;
++}
++
++static int tosa_tc6393xb_resume(struct platform_device *dev)
++{
++
++      pxa_gpio_mode(GPIO11_3_6MHz_MD);
++      pxa_gpio_mode(GPIO18_RDY_MD);
++      mdelay(1);
++      set_scoop_gpio(&tosascoop_jc_device.dev, TOSA_SCOOP_JC_TC6393XB_SUSPEND);
++      mdelay(10);
++      set_scoop_gpio(&tosascoop_jc_device.dev, TOSA_SCOOP_JC_TC6393XB_L3V_ON);
++      mdelay(10);
++
++      return 0;
++}
++
++static int tosa_tc6393xb_suspend(struct platform_device *dev)
++{
++
++      reset_scoop_gpio(&tosascoop_jc_device.dev, TOSA_SCOOP_JC_TC6393XB_L3V_ON);
++      reset_scoop_gpio(&tosascoop_jc_device.dev, TOSA_SCOOP_JC_TC6393XB_SUSPEND);
++      pxa_gpio_mode(GPIO11_3_6MHz_MD|GPIO_OUT);
++      GPSR0 = GPIO_bit(GPIO11_3_6MHz);
++
++      return 0;
++}
++
++static struct mtd_partition tosa_nand_partition[] = {
++      {
++              .name = "smf",
++              .offset = 0,
++              .size = 7 * 1024 * 1024,
++      },
++      {
++              .name = "root",
++              .offset = MTDPART_OFS_APPEND,
++              .size = 28 * 1024 * 1024,
++      },
++      {
++              .name = "home",
++              .offset = MTDPART_OFS_APPEND,
++              .size = MTDPART_SIZ_FULL,
++      },
++};
++
++static uint8_t scan_ff_pattern[] = { 0xff, 0xff };
++
++static struct nand_bbt_descr tosa_tc6393xb_nand_bbt = {
++      .options = 0,
++      .offs = 4,
++      .len = 2,
++      .pattern = scan_ff_pattern
++};
++
++static struct tmio_nand_data tosa_tc6393xb_nand_config = {
++      .num_partitions = ARRAY_SIZE(tosa_nand_partition),
++      .partition = tosa_nand_partition,
++      .badblock_pattern = &tosa_tc6393xb_nand_bbt,
++};
++
++static struct fb_videomode tosa_tc6393xb_lcd_mode[] = {
++      {
++              .xres = 480,
++              .yres = 640,
++              .pixclock = 0x002cdf00,/* PLL divisor */
++              .left_margin = 0x004c,
++              .right_margin = 0x005b,
++              .upper_margin = 0x0001,
++              .lower_margin = 0x000d,
++              .hsync_len = 0x0002,
++              .vsync_len = 0x0001,
++              .sync = FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
++              .vmode = FB_VMODE_NONINTERLACED,
++      },{
++              .xres = 240,
++              .yres = 320,
++              .pixclock = 0x00e7f203,/* PLL divisor */
++              .left_margin = 0x0024,
++              .right_margin = 0x002f,
++              .upper_margin = 0x0001,
++              .lower_margin = 0x000d,
++              .hsync_len = 0x0002,
++              .vsync_len = 0x0001,
++              .sync = FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
++              .vmode = FB_VMODE_NONINTERLACED,
++      }
++};
++
++static struct tmio_fb_data tosa_tc6393xb_fb_config = {
++      .lcd_set_power  = tc6393xb_lcd_set_power,
++      .lcd_mode       = tc6393xb_lcd_mode,
++      .num_modes      = ARRAY_SIZE(tosa_tc6393xb_lcd_mode),
++      .modes          = &tosa_tc6393xb_lcd_mode[0],
++};
++
++static struct tc6393xb_platform_data tosa_tc6393xb_setup = {
++      .scr_pll2cr     = 0x0cc1,
++      .scr_ccr = TC6393XB_CCR_UNK1 | TC6393XB_CCR_HCLK_48,
++      .scr_gper       = 0x3300,
++      .scr_gpo_dsr    = TOSA_TC6393XB_CARD_VCC_ON | TOSA_TC6393XB_CHARGE_OFF_JC,
++      .scr_gpo_doecr  = TOSA_TC6393XB_GPO_OE,
++
++      .irq_base       = IRQ_BOARD_START,
++
++      .enable         = tosa_tc6393xb_enable,
++      .disable        = tosa_tc6393xb_disable,
++      .suspend        = tosa_tc6393xb_suspend,
++      .resume         = tosa_tc6393xb_resume,
++
++      .nand_data      = &tosa_tc6393xb_nand_config,
++      .fb_data        = &tosa_tc6393xb_fb_config,
++};
++
++
++struct platform_device tc6393xb_device = {
++      .name   = "tc6393xb",
++      .id     = -1,
++      .dev    = {
++              .platform_data  = &tosa_tc6393xb_setup,
++      },
++      .num_resources  = ARRAY_SIZE(tc6393xb_resources),
++      .resource       = tc6393xb_resources,
++};
++EXPORT_SYMBOL(tc6393xb_device);
++
+ static struct platform_device *devices[] __initdata = {
+       &tosascoop_device,
+       &tosascoop_jc_device,
+       &tosakbd_device,
+       &tosa_gpio_keys_device,
+       &tosaled_device,
++      &tc6393xb_device,
+ };
+ static void tosa_poweroff(void)
+@@ -332,7 +509,7 @@ static void __init tosa_init(void)
+       arm_pm_restart = tosa_restart;
+       pxa_gpio_mode(TOSA_GPIO_ON_RESET | GPIO_IN);
+-      pxa_gpio_mode(TOSA_GPIO_TC6393_INT | GPIO_IN);
++      pxa_gpio_mode(TOSA_GPIO_TC6393XB_INT | GPIO_IN);
+       pxa_gpio_mode(TOSA_GPIO_USB_IN | GPIO_IN);
+       /* setup sleep mode values */
+diff --git a/include/asm-arm/arch-pxa/irqs.h b/include/asm-arm/arch-pxa/irqs.h
+index b76ee6d..bf622d8 100644
+--- a/include/asm-arm/arch-pxa/irqs.h
++++ b/include/asm-arm/arch-pxa/irqs.h
+@@ -180,6 +180,7 @@
+ #define NR_IRQS                       (IRQ_LOCOMO_SPI_TEND + 1)
+ #elif defined(CONFIG_ARCH_LUBBOCK) || \
+       defined(CONFIG_MACH_LOGICPD_PXA270) || \
++      defined(CONFIG_MACH_TOSA) || \
+       defined(CONFIG_MACH_MAINSTONE)
+ #define NR_IRQS                       (IRQ_BOARD_END)
+ #else
+diff --git a/include/asm-arm/arch-pxa/tosa.h b/include/asm-arm/arch-pxa/tosa.h
+index c05e4fa..1b202b2 100644
+--- a/include/asm-arm/arch-pxa/tosa.h
++++ b/include/asm-arm/arch-pxa/tosa.h
+@@ -20,11 +20,35 @@
+ /* Jacket Scoop */
+ #define TOSA_SCOOP_PHYS       (PXA_CS5_PHYS + 0x00800000)
++#define TC6393XB_GPIO(i)              (1 << (i))
++/*
++ * TC6393 GPIOs
++ */
++#define TOSA_TC6393XB_TG_ON           TC6393XB_GPIO(0)
++#define TOSA_TC6393XB_L_MUTE                  TC6393XB_GPIO(1)
++#define TOSA_TC6393XB_BL_C20MA                TC6393XB_GPIO(3)
++#define TOSA_TC6393XB_CARD_VCC_ON     TC6393XB_GPIO(4)
++#define TOSA_TC6393XB_CHARGE_OFF              TC6393XB_GPIO(6)
++#define TOSA_TC6393XB_CHARGE_OFF_JC   TC6393XB_GPIO(7)
++#define TOSA_TC6393XB_BAT0_V_ON               TC6393XB_GPIO(9)
++#define TOSA_TC6393XB_BAT1_V_ON               TC6393XB_GPIO(10)
++#define TOSA_TC6393XB_BU_CHRG_ON              TC6393XB_GPIO(11)
++#define TOSA_TC6393XB_BAT_SW_ON               TC6393XB_GPIO(12)
++#define TOSA_TC6393XB_BAT0_TH_ON              TC6393XB_GPIO(14)
++#define TOSA_TC6393XB_BAT1_TH_ON              TC6393XB_GPIO(15)
++
++#define TOSA_TC6393XB_GPO_OE (TOSA_TC6393XB_TG_ON | TOSA_TC6393XB_L_MUTE | TOSA_TC6393XB_BL_C20MA | \
++              TOSA_TC6393XB_CARD_VCC_ON | TOSA_TC6393XB_CHARGE_OFF | \
++              TOSA_TC6393XB_CHARGE_OFF_JC | TOSA_TC6393XB_BAT0_V_ON | \
++              TOSA_TC6393XB_BAT1_V_ON | TOSA_TC6393XB_BU_CHRG_ON | \
++              TOSA_TC6393XB_BAT_SW_ON | TOSA_TC6393XB_BAT0_TH_ON | \
++              TOSA_TC6393XB_BAT1_TH_ON)
++
+ /*
+  * SCOOP2 internal GPIOs
+  */
+ #define TOSA_SCOOP_PXA_VCORE1         SCOOP_GPCR_PA11
+-#define TOSA_SCOOP_TC6393_REST_IN     SCOOP_GPCR_PA12
++#define TOSA_SCOOP_TC6393XB_REST_IN   SCOOP_GPCR_PA12
+ #define TOSA_SCOOP_IR_POWERDWN                SCOOP_GPCR_PA13
+ #define TOSA_SCOOP_SD_WP              SCOOP_GPCR_PA14
+ #define TOSA_SCOOP_PWR_ON             SCOOP_GPCR_PA15
+@@ -34,11 +58,11 @@
+ #define TOSA_SCOOP_AC_IN_OL           SCOOP_GPCR_PA19
+ /* GPIO Direction   1 : output mode / 0:input mode */
+-#define TOSA_SCOOP_IO_DIR     ( TOSA_SCOOP_PXA_VCORE1 | TOSA_SCOOP_TC6393_REST_IN | \
++#define TOSA_SCOOP_IO_DIR     ( TOSA_SCOOP_PXA_VCORE1 | TOSA_SCOOP_TC6393XB_REST_IN | \
+               TOSA_SCOOP_IR_POWERDWN | TOSA_SCOOP_PWR_ON | TOSA_SCOOP_AUD_PWR_ON |\
+               TOSA_SCOOP_BT_RESET | TOSA_SCOOP_BT_PWR_EN )
+ /* GPIO out put level when init   1: Hi */
+-#define TOSA_SCOOP_IO_OUT     ( TOSA_SCOOP_TC6393_REST_IN )
++#define TOSA_SCOOP_IO_OUT     ( TOSA_SCOOP_TC6393XB_REST_IN )
+ /*
+  * SCOOP2 jacket GPIOs
+@@ -47,8 +71,8 @@
+ #define TOSA_SCOOP_JC_NOTE_LED                SCOOP_GPCR_PA12
+ #define TOSA_SCOOP_JC_CHRG_ERR_LED    SCOOP_GPCR_PA13
+ #define TOSA_SCOOP_JC_USB_PULLUP      SCOOP_GPCR_PA14
+-#define TOSA_SCOOP_JC_TC6393_SUSPEND  SCOOP_GPCR_PA15
+-#define TOSA_SCOOP_JC_TC3693_L3V_ON   SCOOP_GPCR_PA16
++#define TOSA_SCOOP_JC_TC6393XB_SUSPEND        SCOOP_GPCR_PA15
++#define TOSA_SCOOP_JC_TC6393XB_L3V_ON SCOOP_GPCR_PA16
+ #define TOSA_SCOOP_JC_WLAN_DETECT     SCOOP_GPCR_PA17
+ #define TOSA_SCOOP_JC_WLAN_LED                SCOOP_GPCR_PA18
+ #define TOSA_SCOOP_JC_CARD_LIMIT_SEL  SCOOP_GPCR_PA19
+@@ -56,7 +80,7 @@
+ /* GPIO Direction   1 : output mode / 0:input mode */
+ #define TOSA_SCOOP_JC_IO_DIR ( TOSA_SCOOP_JC_BT_LED | TOSA_SCOOP_JC_NOTE_LED | \
+               TOSA_SCOOP_JC_CHRG_ERR_LED | TOSA_SCOOP_JC_USB_PULLUP | \
+-              TOSA_SCOOP_JC_TC6393_SUSPEND | TOSA_SCOOP_JC_TC3693_L3V_ON | \
++              TOSA_SCOOP_JC_TC6393XB_SUSPEND | TOSA_SCOOP_JC_TC6393XB_L3V_ON | \
+               TOSA_SCOOP_JC_WLAN_LED | TOSA_SCOOP_JC_CARD_LIMIT_SEL )
+ /* GPIO out put level when init   1: Hi */
+ #define TOSA_SCOOP_JC_IO_OUT ( 0 )
+@@ -94,13 +118,13 @@
+ #define TOSA_GPIO_JACKET_DETECT               (7)
+ #define TOSA_GPIO_nSD_DETECT          (9)
+ #define TOSA_GPIO_nSD_INT             (10)
+-#define TOSA_GPIO_TC6393_CLK          (11)
++#define TOSA_GPIO_TC6393XB_CLK                (11)
+ #define TOSA_GPIO_BAT1_CRG            (12)
+ #define TOSA_GPIO_CF_CD                       (13)
+ #define TOSA_GPIO_BAT0_CRG            (14)
+-#define TOSA_GPIO_TC6393_INT          (15)
++#define TOSA_GPIO_TC6393XB_INT                (15)
+ #define TOSA_GPIO_BAT0_LOW            (17)
+-#define TOSA_GPIO_TC6393_RDY          (18)
++#define TOSA_GPIO_TC6393XB_RDY                (18)
+ #define TOSA_GPIO_ON_RESET            (19)
+ #define TOSA_GPIO_EAR_IN              (20)
+ #define TOSA_GPIO_CF_IRQ              (21)    /* CF slot0 Ready */
+@@ -147,7 +171,7 @@
+ #define TOSA_IRQ_GPIO_BAT1_CRG        IRQ_GPIO(TOSA_GPIO_BAT1_CRG)
+ #define TOSA_IRQ_GPIO_CF_CD           IRQ_GPIO(TOSA_GPIO_CF_CD)
+ #define TOSA_IRQ_GPIO_BAT0_CRG        IRQ_GPIO(TOSA_GPIO_BAT0_CRG)
+-#define TOSA_IRQ_GPIO_TC6393_INT      IRQ_GPIO(TOSA_GPIO_TC6393_INT)
++#define TOSA_IRQ_GPIO_TC6393XB_INT            IRQ_GPIO(TOSA_GPIO_TC6393XB_INT)
+ #define TOSA_IRQ_GPIO_BAT0_LOW        IRQ_GPIO(TOSA_GPIO_BAT0_LOW)
+ #define TOSA_IRQ_GPIO_EAR_IN          IRQ_GPIO(TOSA_GPIO_EAR_IN)
+ #define TOSA_IRQ_GPIO_CF_IRQ          IRQ_GPIO(TOSA_GPIO_CF_IRQ)
+@@ -161,6 +185,7 @@
+ #define TOSA_IRQ_GPIO_MAIN_BAT_LOW    IRQ_GPIO(TOSA_GPIO_MAIN_BAT_LOW)
++extern struct platform_device tc6393xb_device;
+ extern struct platform_device tosascoop_jc_device;
+ extern struct platform_device tosascoop_device;
+diff --git a/sound/soc/pxa/tosa.c b/sound/soc/pxa/tosa.c
+index 5504e30..21c51b5 100644
+--- a/sound/soc/pxa/tosa.c
++++ b/sound/soc/pxa/tosa.c
+@@ -32,7 +32,6 @@
+ #include <sound/soc-dapm.h>
+ #include <asm/mach-types.h>
+-#include <asm/hardware/tmio.h>
+ #include <asm/arch/pxa-regs.h>
+ #include <asm/arch/hardware.h>
+ #include <asm/arch/audio.h>
+@@ -138,10 +137,12 @@ static int tosa_set_spk(struct snd_kcontrol *kcontrol,
+ /* tosa dapm event handlers */
+ static int tosa_hp_event(struct snd_soc_dapm_widget *w, int event)
+ {
++#if 0
+       if (SND_SOC_DAPM_EVENT_ON(event))
+               set_tc6393_gpio(&tc6393_device.dev,TOSA_TC6393_L_MUTE);
+       else
+               reset_tc6393_gpio(&tc6393_device.dev,TOSA_TC6393_L_MUTE);
++#endif
+       return 0;
+ }
+-- 
+1.5.3.8
+
diff --git a/packages/kexecboot/linux-kexecboot-2.6.24/tosa/0050-tosa-update-for-tc6393xb-gpio.patch b/packages/kexecboot/linux-kexecboot-2.6.24/tosa/0050-tosa-update-for-tc6393xb-gpio.patch
new file mode 100644 (file)
index 0000000..c9b5ac2
--- /dev/null
@@ -0,0 +1,99 @@
+From f24c23ba56cdd072b332e8de3e0cff8a31e7e36a Mon Sep 17 00:00:00 2001
+From: Dmitry Baryshkov <dbaryshkov@gmail.com>
+Date: Wed, 9 Jan 2008 02:03:19 +0300
+Subject: [PATCH 50/64] tosa update for tc6393xb gpio
+
+Signed-off-by: Dmitry Baryshkov <dbaryshkov@gmail.com>
+---
+ arch/arm/mach-pxa/tosa.c        |    6 +++++-
+ include/asm-arm/arch-pxa/tosa.h |   36 ++++++++++++++++++++++++------------
+ 2 files changed, 29 insertions(+), 13 deletions(-)
+
+diff --git a/arch/arm/mach-pxa/tosa.c b/arch/arm/mach-pxa/tosa.c
+index e2eec0f..3e832dc 100644
+--- a/arch/arm/mach-pxa/tosa.c
++++ b/arch/arm/mach-pxa/tosa.c
+@@ -35,6 +35,7 @@
+ #include <asm/mach-types.h>
+ #include <asm/hardware.h>
+ #include <asm/irq.h>
++#include <asm/gpio.h>
+ #include <asm/system.h>
+ #include <asm/arch/pxa-regs.h>
+ #include <asm/arch/irda.h>
+@@ -448,10 +449,13 @@ static struct tc6393xb_platform_data tosa_tc6393xb_setup = {
+       .scr_pll2cr     = 0x0cc1,
+       .scr_ccr = TC6393XB_CCR_UNK1 | TC6393XB_CCR_HCLK_48,
+       .scr_gper       = 0x3300,
+-      .scr_gpo_dsr    = TOSA_TC6393XB_CARD_VCC_ON | TOSA_TC6393XB_CHARGE_OFF_JC,
++      .scr_gpo_dsr    =
++              TC6393XB_GPIO_BIT(TOSA_TC6393XB_CARD_VCC_ON) |
++              TC6393XB_GPIO_BIT(TOSA_TC6393XB_CHARGE_OFF_JC),
+       .scr_gpo_doecr  = TOSA_TC6393XB_GPO_OE,
+       .irq_base       = IRQ_BOARD_START,
++      .gpio_base      = TOSA_TC6393XB_GPIO_BASE,
+       .enable         = tosa_tc6393xb_enable,
+       .disable        = tosa_tc6393xb_disable,
+diff --git a/include/asm-arm/arch-pxa/tosa.h b/include/asm-arm/arch-pxa/tosa.h
+index 1b202b2..410fa9a 100644
+--- a/include/asm-arm/arch-pxa/tosa.h
++++ b/include/asm-arm/arch-pxa/tosa.h
+@@ -20,16 +20,21 @@
+ /* Jacket Scoop */
+ #define TOSA_SCOOP_PHYS       (PXA_CS5_PHYS + 0x00800000)
+-#define TC6393XB_GPIO(i)              (1 << (i))
+ /*
+  * TC6393 GPIOs
+  */
+-#define TOSA_TC6393XB_TG_ON           TC6393XB_GPIO(0)
+-#define TOSA_TC6393XB_L_MUTE                  TC6393XB_GPIO(1)
+-#define TOSA_TC6393XB_BL_C20MA                TC6393XB_GPIO(3)
+-#define TOSA_TC6393XB_CARD_VCC_ON     TC6393XB_GPIO(4)
++
++#define TOSA_TC6393XB_GPIO_BASE               NR_BUILTIN_GPIO
++
++#define TC6393XB_GPIO(i)              (TOSA_TC6393XB_GPIO_BASE + (i))
++#define TC6393XB_GPIO_BIT(gpio)                       (1 << (gpio - TOSA_TC6393XB_GPIO_BASE))
++
++#define TOSA_TC6393XB_TG_ON                   TC6393XB_GPIO(0)
++#define TOSA_TC6393XB_L_MUTE                          TC6393XB_GPIO(1)
++#define TOSA_TC6393XB_BL_C20MA                        TC6393XB_GPIO(3)
++#define TOSA_TC6393XB_CARD_VCC_ON             TC6393XB_GPIO(4)
+ #define TOSA_TC6393XB_CHARGE_OFF              TC6393XB_GPIO(6)
+-#define TOSA_TC6393XB_CHARGE_OFF_JC   TC6393XB_GPIO(7)
++#define TOSA_TC6393XB_CHARGE_OFF_JC           TC6393XB_GPIO(7)
+ #define TOSA_TC6393XB_BAT0_V_ON               TC6393XB_GPIO(9)
+ #define TOSA_TC6393XB_BAT1_V_ON               TC6393XB_GPIO(10)
+ #define TOSA_TC6393XB_BU_CHRG_ON              TC6393XB_GPIO(11)
+@@ -37,12 +42,19 @@
+ #define TOSA_TC6393XB_BAT0_TH_ON              TC6393XB_GPIO(14)
+ #define TOSA_TC6393XB_BAT1_TH_ON              TC6393XB_GPIO(15)
+-#define TOSA_TC6393XB_GPO_OE (TOSA_TC6393XB_TG_ON | TOSA_TC6393XB_L_MUTE | TOSA_TC6393XB_BL_C20MA | \
+-              TOSA_TC6393XB_CARD_VCC_ON | TOSA_TC6393XB_CHARGE_OFF | \
+-              TOSA_TC6393XB_CHARGE_OFF_JC | TOSA_TC6393XB_BAT0_V_ON | \
+-              TOSA_TC6393XB_BAT1_V_ON | TOSA_TC6393XB_BU_CHRG_ON | \
+-              TOSA_TC6393XB_BAT_SW_ON | TOSA_TC6393XB_BAT0_TH_ON | \
+-              TOSA_TC6393XB_BAT1_TH_ON)
++#define TOSA_TC6393XB_GPO_OE (                        \
++              TC6393XB_GPIO_BIT(TOSA_TC6393XB_TG_ON) |                \
++              TC6393XB_GPIO_BIT(TOSA_TC6393XB_L_MUTE) |               \
++              TC6393XB_GPIO_BIT(TOSA_TC6393XB_BL_C20MA) |     \
++              TC6393XB_GPIO_BIT(TOSA_TC6393XB_CARD_VCC_ON) |  \
++              TC6393XB_GPIO_BIT(TOSA_TC6393XB_CHARGE_OFF) |   \
++              TC6393XB_GPIO_BIT(TOSA_TC6393XB_CHARGE_OFF_JC) |        \
++              TC6393XB_GPIO_BIT(TOSA_TC6393XB_BAT0_V_ON) |    \
++              TC6393XB_GPIO_BIT(TOSA_TC6393XB_BAT1_V_ON) |    \
++              TC6393XB_GPIO_BIT(TOSA_TC6393XB_BU_CHRG_ON) |   \
++              TC6393XB_GPIO_BIT(TOSA_TC6393XB_BAT_SW_ON) |    \
++              TC6393XB_GPIO_BIT(TOSA_TC6393XB_BAT0_TH_ON) |   \
++              TC6393XB_GPIO_BIT(TOSA_TC6393XB_BAT1_TH_ON))
+ /*
+  * SCOOP2 internal GPIOs
+-- 
+1.5.3.8
+
diff --git a/packages/kexecboot/linux-kexecboot-2.6.24/tosa/0051-fix-sound-soc-pxa-tosa.c-to-new-gpio-api.patch b/packages/kexecboot/linux-kexecboot-2.6.24/tosa/0051-fix-sound-soc-pxa-tosa.c-to-new-gpio-api.patch
new file mode 100644 (file)
index 0000000..585f1af
--- /dev/null
@@ -0,0 +1,86 @@
+From 38ef1b452cc3138157b92d02b31cad439d12d0ca Mon Sep 17 00:00:00 2001
+From: Dmitry Baryshkov <dbaryshkov@gmail.com>
+Date: Wed, 9 Jan 2008 02:03:34 +0300
+Subject: [PATCH 51/64] fix sound/soc/pxa/tosa.c to new gpio api
+
+Signed-off-by: Dmitry Baryshkov <dbaryshkov@gmail.com>
+---
+ sound/soc/pxa/tosa.c |   33 ++++++++++++++++++++++++++-------
+ 1 files changed, 26 insertions(+), 7 deletions(-)
+
+diff --git a/sound/soc/pxa/tosa.c b/sound/soc/pxa/tosa.c
+index 21c51b5..b758de8 100644
+--- a/sound/soc/pxa/tosa.c
++++ b/sound/soc/pxa/tosa.c
+@@ -36,6 +36,7 @@
+ #include <asm/arch/hardware.h>
+ #include <asm/arch/audio.h>
+ #include <asm/arch/tosa.h>
++#include <asm/gpio.h>
+ #include "../codecs/wm9712.h"
+ #include "pxa2xx-pcm.h"
+@@ -137,11 +138,11 @@ static int tosa_set_spk(struct snd_kcontrol *kcontrol,
+ /* tosa dapm event handlers */
+ static int tosa_hp_event(struct snd_soc_dapm_widget *w, int event)
+ {
+-#if 0
++#ifdef CONFIG_MFD_TC6393XB
+       if (SND_SOC_DAPM_EVENT_ON(event))
+-              set_tc6393_gpio(&tc6393_device.dev,TOSA_TC6393_L_MUTE);
++              gpio_set_value(TOSA_TC6393XB_L_MUTE, 1);
+       else
+-              reset_tc6393_gpio(&tc6393_device.dev,TOSA_TC6393_L_MUTE);
++              gpio_set_value(TOSA_TC6393XB_L_MUTE, 0);
+ #endif
+       return 0;
+ }
+@@ -262,16 +263,31 @@ static int __init tosa_init(void)
+       if (!machine_is_tosa())
+               return -ENODEV;
++#ifdef CONFIG_MFD_TC6393XB
++      ret = gpio_request(TOSA_TC6393XB_L_MUTE, "Headphone Jack");
++      if (ret)
++              return ret;
++      gpio_direction_output(TOSA_TC6393XB_L_MUTE, 0);
++#endif
+       tosa_snd_device = platform_device_alloc("soc-audio", -1);
+-      if (!tosa_snd_device)
+-              return -ENOMEM;
++      if (!tosa_snd_device) {
++              ret = -ENOMEM;
++              goto err_alloc;
++      }
+       platform_set_drvdata(tosa_snd_device, &tosa_snd_devdata);
+       tosa_snd_devdata.dev = &tosa_snd_device->dev;
+       ret = platform_device_add(tosa_snd_device);
+-      if (ret)
+-              platform_device_put(tosa_snd_device);
++      if (!ret)
++              return 0;
++
++      platform_device_put(tosa_snd_device);
++
++err_alloc:
++#ifdef CONFIG_MFD_TC6393XB
++      gpio_free(TOSA_TC6393XB_L_MUTE);
++#endif
+       return ret;
+ }
+@@ -279,6 +295,9 @@ static int __init tosa_init(void)
+ static void __exit tosa_exit(void)
+ {
+       platform_device_unregister(tosa_snd_device);
++#ifdef CONFIG_MFD_TC6393XB
++      gpio_free(TOSA_TC6393XB_L_MUTE);
++#endif
+ }
+ module_init(tosa_init);
+-- 
+1.5.3.8
+
diff --git a/packages/kexecboot/linux-kexecboot-2.6.24/tosa/0052-tosa-platform-backlight-support.patch b/packages/kexecboot/linux-kexecboot-2.6.24/tosa/0052-tosa-platform-backlight-support.patch
new file mode 100644 (file)
index 0000000..ef5263c
--- /dev/null
@@ -0,0 +1,400 @@
+From c7537657bc33d4ee1616accd0259e160d57c5c1b Mon Sep 17 00:00:00 2001
+From: Ian Molton <spyro@f2s.com>
+Date: Wed, 9 Jan 2008 02:05:40 +0300
+Subject: [PATCH 52/64] tosa platform backlight support
+
+Signed-off-by: Dmitry Baryshkov <dbaryshkov@gmail.com>
+---
+ drivers/video/backlight/Kconfig   |   10 +
+ drivers/video/backlight/Makefile  |    1 +
+ drivers/video/backlight/tosa_bl.c |  345 +++++++++++++++++++++++++++++++++++++
+ 3 files changed, 356 insertions(+), 0 deletions(-)
+ create mode 100644 drivers/video/backlight/tosa_bl.c
+
+diff --git a/drivers/video/backlight/Kconfig b/drivers/video/backlight/Kconfig
+index 9609a6c..f47a601 100644
+--- a/drivers/video/backlight/Kconfig
++++ b/drivers/video/backlight/Kconfig
+@@ -59,6 +59,16 @@ config BACKLIGHT_CORGI
+         known as the Corgi backlight driver. If you have a Sharp Zaurus
+         SL-C7xx, SL-Cxx00 or SL-6000x say y. Most users can say n.
++config BACKLIGHT_TOSA
++      tristate "Sharp Tosa LCD/Backlight Driver (SL-6000)"
++      depends on BACKLIGHT_CLASS_DEVICE && MACH_TOSA
++      default y
++      select I2C
++      select I2C_PXA
++      select PXA_SSP
++      help
++        If you have a Sharp Zaurus SL-6000y enable this driver.
++
+ config BACKLIGHT_LOCOMO
+       tristate "Sharp LOCOMO LCD/Backlight Driver"
+       depends on BACKLIGHT_CLASS_DEVICE && SHARP_LOCOMO
+diff --git a/drivers/video/backlight/Makefile b/drivers/video/backlight/Makefile
+index 965a78b..e8a6a7c 100644
+--- a/drivers/video/backlight/Makefile
++++ b/drivers/video/backlight/Makefile
+@@ -5,6 +5,7 @@ obj-$(CONFIG_LCD_LTV350QV)     += ltv350qv.o
+ obj-$(CONFIG_BACKLIGHT_CLASS_DEVICE) += backlight.o
+ obj-$(CONFIG_BACKLIGHT_CORGI) += corgi_bl.o
++obj-$(CONFIG_BACKLIGHT_TOSA)  += tosa_bl.o
+ obj-$(CONFIG_BACKLIGHT_HP680) += hp680_bl.o
+ obj-$(CONFIG_BACKLIGHT_LOCOMO)        += locomolcd.o
+ obj-$(CONFIG_BACKLIGHT_PROGEAR) += progear_bl.o
+diff --git a/drivers/video/backlight/tosa_bl.c b/drivers/video/backlight/tosa_bl.c
+new file mode 100644
+index 0000000..11a89c6
+--- /dev/null
++++ b/drivers/video/backlight/tosa_bl.c
+@@ -0,0 +1,345 @@
++/*
++ *  LCD / Backlight control code for Sharp SL-6000x (tosa)
++ *
++ *  Copyright (c) 2005                Dirk Opfer
++ *  Copyright (c) 2007                Dmitry Baryshkov
++ *
++ *  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/kernel.h>
++#include <linux/module.h>
++#include <linux/i2c.h>
++#include <linux/backlight.h>
++#include <linux/platform_device.h>
++#include <linux/delay.h>
++#include <linux/fb.h>
++#include <linux/mfd/tc6393xb.h>
++
++#include <asm/hardware/scoop.h>
++#include <asm/mach/sharpsl_param.h>
++#include <asm/arch/ssp.h>
++#include <asm/arch/pxa-regs.h>
++#include <asm/arch/tosa.h>
++#include <asm/gpio.h>
++
++#define       DAC_BASE        0x4e
++#define DAC_CH1               0
++#define DAC_CH2               1
++
++#define TG_REG0_VQV   0x0001
++#define TG_REG0_COLOR 0x0002
++#define TG_REG0_UD    0x0004
++#define TG_REG0_LR    0x0008
++#define COMADJ_DEFAULT        97
++
++static unsigned short normal_i2c[] = { DAC_BASE, I2C_CLIENT_END };
++I2C_CLIENT_INSMOD;
++
++struct tosa_bl_data {
++      struct i2c_client       client;
++
++      int                     comadj;
++      spinlock_t              nssp_lock;
++      struct ssp_dev          nssp_dev;
++      struct ssp_state        nssp_state;
++
++      struct backlight_device *bl_dev;
++};
++
++static struct i2c_driver tosa_bl_driver;
++
++static void pxa_nssp_output(struct tosa_bl_data *data, unsigned char reg, unsigned char value)
++{
++      unsigned long flag;
++      u32 dummy;
++      u32 dat = ( ((reg << 5) & 0xe0) | (value & 0x1f) );
++      spin_lock_irqsave(&data->nssp_lock, flag);
++
++      ssp_config(&data->nssp_dev, (SSCR0_Motorola | (SSCR0_DSS & 0x07 )), 0, 0, SSCR0_SerClkDiv(128));
++      ssp_enable(&data->nssp_dev);
++
++      ssp_write_word(&data->nssp_dev,dat);
++
++      /* Read null data back from device to prevent SSP overflow */
++      ssp_read_word(&data->nssp_dev, &dummy);
++      ssp_disable(&data->nssp_dev);
++      spin_unlock_irqrestore(&data->nssp_lock, flag);
++
++}
++
++static void tosa_set_backlight(struct tosa_bl_data *data, int brightness)
++{
++      /* SetBacklightDuty */
++      i2c_smbus_write_byte_data(&data->client, DAC_CH2, (unsigned char)brightness);
++
++      /* SetBacklightVR */
++      if (brightness)
++              gpio_set_value(TOSA_TC6393XB_BL_C20MA, 1);
++      else
++              gpio_set_value(TOSA_TC6393XB_BL_C20MA, 0);
++
++      /* bl_enable GP04=1 otherwise GP04=0*/
++      pxa_nssp_output(data, TG_GPODR2, brightness ? 0x01 : 0x00);
++}
++
++static void tosa_lcd_tg_init(struct tosa_bl_data *data)
++{
++      dev_dbg(&data->bl_dev->dev, "tosa_lcd_init\n");
++
++      /* L3V On */
++      set_scoop_gpio( &tosascoop_jc_device.dev,TOSA_SCOOP_JC_TC6393XB_L3V_ON);
++      mdelay(60);
++
++      /* TG On */
++      gpio_set_value(TOSA_TC6393XB_TG_ON, 0);
++      mdelay(60);
++
++      pxa_nssp_output(data, TG_TPOSCTL,0x00); /* delayed 0clk TCTL signal for VGA */
++      pxa_nssp_output(data, TG_GPOSR,0x02);           /* GPOS0=powercontrol, GPOS1=GPIO, GPOS2=TCTL */
++}
++
++static void tosa_lcd_tg_on(struct tosa_bl_data *data/*, const struct fb_videomode *mode*/)
++{
++      const int value = TG_REG0_COLOR | TG_REG0_UD | TG_REG0_LR;
++
++      tosa_lcd_tg_init(data);
++
++      dev_dbg(&data->bl_dev->dev, "tosa_lcd_on\n");
++      pxa_nssp_output(data, TG_PNLCTL, value | (/*mode->yres == 320 ? 0 : */ TG_REG0_VQV));
++
++      /* TG LCD pannel power up */
++      pxa_nssp_output(data, TG_PINICTL,0x4);
++      mdelay(50);
++
++      /* TG LCD GVSS */
++      pxa_nssp_output(data, TG_PINICTL,0x0);
++      mdelay(50);
++
++      /* set common voltage */
++      i2c_smbus_write_byte_data(&data->client, DAC_CH1, data->comadj);
++}
++
++static void tosa_lcd_tg_off(struct tosa_bl_data *data)
++{
++      tosa_set_backlight(data, 0);
++      dev_dbg(&data->bl_dev->dev, "tosa_lcd_off\n");
++      /* TG LCD VHSA off */
++      pxa_nssp_output(data, TG_PINICTL,0x4);
++      mdelay(50);
++
++      /* TG LCD signal off */
++      pxa_nssp_output(data, TG_PINICTL,0x6);
++      mdelay(50);
++
++      /* TG Off */
++      gpio_set_value(TOSA_TC6393XB_TG_ON, 1);
++      mdelay(100);
++
++      /* L3V Off */
++      reset_scoop_gpio( &tosascoop_jc_device.dev,TOSA_SCOOP_JC_TC6393XB_L3V_ON);
++}
++
++
++static int tosa_bl_update_status(struct backlight_device *dev)
++{
++      struct backlight_properties *props = &dev->props;
++      struct tosa_bl_data *data = dev_get_drvdata(&dev->dev);
++      int new_power = max(props->power, props->fb_blank);
++
++      tosa_set_backlight(data, props->brightness);
++
++      if (new_power)
++              tosa_lcd_tg_off(data);
++      else
++              tosa_lcd_tg_on(data);
++
++      return 0;
++}
++
++static int tosa_bl_get_brightness(struct backlight_device *dev)
++{
++      struct backlight_properties *props = &dev->props;
++
++      return props->brightness;
++}
++
++static struct backlight_ops tosa_bl_ops = {
++      .get_brightness         = tosa_bl_get_brightness,
++      .update_status          = tosa_bl_update_status,
++};
++
++static int tosa_bl_detect_client(struct i2c_adapter *adapter, int address,
++                        int kind)
++{
++      int err = 0;
++      struct i2c_client *client;
++      struct tosa_bl_data *data;
++
++      if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA ))
++              goto out;
++
++      if (!(data = kzalloc(sizeof(struct tosa_bl_data), GFP_KERNEL))) {
++              err = -ENOMEM;
++              goto out;
++      }
++
++      client = &data->client;
++      i2c_set_clientdata(client, data);
++
++      client->addr = address;
++      client->adapter = adapter;
++      client->driver = &tosa_bl_driver;
++
++      strlcpy(client->name, "tosa_bl", I2C_NAME_SIZE);
++
++      spin_lock_init(&data->nssp_lock);
++      data->comadj = sharpsl_param.comadj == -1 ? COMADJ_DEFAULT : sharpsl_param.comadj;
++
++      err = gpio_request(TOSA_TC6393XB_BL_C20MA, "backlight");
++      if (err) {
++              dev_dbg(&data->bl_dev->dev, "Unable to request gpio!\n");
++              goto err_gpio_bl;
++      }
++
++      err = gpio_request(TOSA_TC6393XB_TG_ON, "tg");
++      if (err) {
++              dev_dbg(&data->bl_dev->dev, "Unable to request gpio!\n");
++              goto err_gpio_tg;
++      }
++
++      err = ssp_init(&data->nssp_dev,2,0);
++      if (err) {
++              dev_err(&data->bl_dev->dev, "Unable to register NSSP handler!\n");
++              goto err_ssp_init;
++      }
++
++      /* Tell the i2c layer a new client has arrived */
++      err = i2c_attach_client(client);
++      if (err)
++              goto err_i2c_attach;
++
++      gpio_direction_output(TOSA_TC6393XB_BL_C20MA, 0);
++      gpio_direction_output(TOSA_TC6393XB_TG_ON, 1);
++
++      tosa_lcd_tg_init(data);
++
++      data->bl_dev = backlight_device_register("tosa_bl",
++                      &client->dev, data, &tosa_bl_ops);
++      if (err)
++              goto err_bl_register;
++
++      data->bl_dev->props.brightness = 69;
++      data->bl_dev->props.max_brightness = 255;
++      data->bl_dev->props.power = FB_BLANK_UNBLANK;
++      backlight_update_status(data->bl_dev);
++
++
++      return 0;
++
++err_bl_register:
++      tosa_set_backlight(data, 0);
++      tosa_lcd_tg_off(data);
++
++      err = i2c_detach_client(client);
++      if (err)
++              return err;
++err_i2c_attach:
++      ssp_exit(&data->nssp_dev);
++err_ssp_init:
++      gpio_free(TOSA_TC6393XB_TG_ON);
++err_gpio_tg:
++      gpio_free(TOSA_TC6393XB_BL_C20MA);
++err_gpio_bl:
++      kfree(data);
++out:
++      return err;
++}
++
++static int tosa_bl_detach_client(struct i2c_client *client)
++{
++      int err = 0;
++      struct tosa_bl_data *data = i2c_get_clientdata(client);
++
++      backlight_device_unregister(data->bl_dev);
++
++      tosa_set_backlight(data, 0);
++      tosa_lcd_tg_off(data);
++
++      /* Try to detach the client from i2c space */
++      if ((err = i2c_detach_client(client)))
++              return err;
++
++      ssp_exit(&data->nssp_dev);
++
++      gpio_free(TOSA_TC6393XB_TG_ON);
++      gpio_free(TOSA_TC6393XB_BL_C20MA);
++
++      kfree(data);
++
++      return err;
++}
++
++#ifdef CONFIG_PM
++static int tosa_bl_suspend(struct i2c_client *client, pm_message_t mesg)
++{
++      struct tosa_bl_data *data = i2c_get_clientdata(client);
++
++      tosa_lcd_tg_off(data);
++      ssp_flush(&data->nssp_dev);
++      ssp_save_state(&data->nssp_dev,&data->nssp_state);
++
++      return 0;
++}
++
++static int tosa_bl_resume(struct i2c_client *client)
++{
++      struct tosa_bl_data *data = i2c_get_clientdata(client);
++
++      ssp_restore_state(&data->nssp_dev,&data->nssp_state);
++      ssp_enable(&data->nssp_dev);
++      tosa_bl_update_status(data->bl_dev);
++
++      return 0;
++}
++#else
++#define tosa_bl_suspend NULL
++#define tosa_bl_resume NULL
++#endif
++
++static int tosa_bl_attach_adapter(struct i2c_adapter *adapter)
++{
++      return i2c_probe(adapter, &addr_data, &tosa_bl_detect_client);
++}
++
++static struct i2c_driver tosa_bl_driver = {
++      .driver = {
++              .name   = "tosa_bl",
++      },
++
++      .attach_adapter = tosa_bl_attach_adapter,
++      .detach_client  = tosa_bl_detach_client,
++
++      .suspend        = tosa_bl_suspend,
++      .resume         = tosa_bl_resume,
++};
++
++static int __init tosa_bl_init(void)
++{
++      return i2c_add_driver(&tosa_bl_driver);
++}
++
++static void __exit tosa_bl_cleanup (void)
++{
++      i2c_del_driver(&tosa_bl_driver);
++}
++
++module_init(tosa_bl_init);
++module_exit(tosa_bl_cleanup);
++
++MODULE_DESCRIPTION("Tosa LCD device");
++MODULE_AUTHOR("Dirk Opfer, Dmitry Baryshkov");
++MODULE_LICENSE("GPL v2");
+-- 
+1.5.3.8
+
diff --git a/packages/kexecboot/linux-kexecboot-2.6.24/tosa/0053-sound-soc-codecs-wm9712.c-28.patch b/packages/kexecboot/linux-kexecboot-2.6.24/tosa/0053-sound-soc-codecs-wm9712.c-28.patch
new file mode 100644 (file)
index 0000000..0675342
--- /dev/null
@@ -0,0 +1,56 @@
+From 47616d22f8f303dfd66cf3b9125af212194a0f3c Mon Sep 17 00:00:00 2001
+From: Dmitry Baryshkov <dbaryshkov@gmail.com>
+Date: Wed, 9 Jan 2008 02:08:17 +0300
+Subject: [PATCH 53/64]  sound/soc/codecs/wm9712.c |   28 ++++++++++++++++++----------
+  1 file changed, 18 insertions(+), 10 deletions(-)
+
+Index: git/sound/soc/codecs/wm9712.c
+===================================================================
+---
+ sound/soc/codecs/wm9712.c |   28 ++++++++++++++++++----------
+ 1 files changed, 18 insertions(+), 10 deletions(-)
+
+diff --git a/sound/soc/codecs/wm9712.c b/sound/soc/codecs/wm9712.c
+index 986b5d5..dfb31e1 100644
+--- a/sound/soc/codecs/wm9712.c
++++ b/sound/soc/codecs/wm9712.c
+@@ -606,18 +606,26 @@ static int wm9712_dapm_event(struct snd_soc_codec *codec, int event)
+ static int wm9712_reset(struct snd_soc_codec *codec, int try_warm)
+ {
+-      if (try_warm && soc_ac97_ops.warm_reset) {
+-              soc_ac97_ops.warm_reset(codec->ac97);
+-              if (!(ac97_read(codec, 0) & 0x8000))
+-                      return 1;
+-      }
++      int retry = 3;
+-      soc_ac97_ops.reset(codec->ac97);
+-      if (ac97_read(codec, 0) & 0x8000)
+-              goto err;
+-      return 0;
++      while (retry--)
++      {
++              if(try_warm && soc_ac97_ops.warm_reset) {
++                      soc_ac97_ops.warm_reset(codec->ac97);
++                      if(ac97_read(codec, 0) & 0x8000)
++                              continue;
++                      else
++                              return 1;
++              }
++
++              soc_ac97_ops.reset(codec->ac97);
++              if(ac97_read(codec, 0) & 0x8000)
++                      continue;
++              else
++                      return 0;
++
++      }
+-err:
+       printk(KERN_ERR "WM9712 AC97 reset failed\n");
+       return -EIO;
+ }
+-- 
+1.5.3.8
+
diff --git a/packages/kexecboot/linux-kexecboot-2.6.24/tosa/0054-sound-soc-codecs-wm9712.c-2.patch b/packages/kexecboot/linux-kexecboot-2.6.24/tosa/0054-sound-soc-codecs-wm9712.c-2.patch
new file mode 100644 (file)
index 0000000..be7300a
--- /dev/null
@@ -0,0 +1,28 @@
+From 08fbae2307163b3f0c3b704c4b00a9447752a45e Mon Sep 17 00:00:00 2001
+From: Dmitry Baryshkov <dbaryshkov@gmail.com>
+Date: Thu, 10 Jan 2008 17:56:58 +0300
+Subject: [PATCH 54/64]  sound/soc/codecs/wm9712.c |    2 +-
+  1 file changed, 1 insertion(+), 1 deletion(-)
+
+Index: git/sound/soc/codecs/wm9712.c
+===================================================================
+---
+ sound/soc/codecs/wm9712.c |    2 +-
+ 1 files changed, 1 insertions(+), 1 deletions(-)
+
+diff --git a/sound/soc/codecs/wm9712.c b/sound/soc/codecs/wm9712.c
+index dfb31e1..a3d9f96 100644
+--- a/sound/soc/codecs/wm9712.c
++++ b/sound/soc/codecs/wm9712.c
+@@ -647,7 +647,7 @@ static int wm9712_soc_resume(struct platform_device *pdev)
+       int i, ret;
+       u16 *cache = codec->reg_cache;
+-      ret = wm9712_reset(codec, 1);
++      ret = wm9712_reset(codec, 0);
+       if (ret < 0){
+               printk(KERN_ERR "could not reset AC97 codec\n");
+               return ret;
+-- 
+1.5.3.8
+
diff --git a/packages/kexecboot/linux-kexecboot-2.6.24/tosa/0055-Add-GPIO_POWERON-to-the-list-of-devices-that-we-supp.patch b/packages/kexecboot/linux-kexecboot-2.6.24/tosa/0055-Add-GPIO_POWERON-to-the-list-of-devices-that-we-supp.patch
new file mode 100644 (file)
index 0000000..5bf691c
--- /dev/null
@@ -0,0 +1,30 @@
+From bee8b808445a53a7dbb6c15a27064f14dec410c5 Mon Sep 17 00:00:00 2001
+From: Dmitry Baryshkov <dbaryshkov@gmail.com>
+Date: Sun, 20 Jan 2008 03:01:41 +0300
+Subject: [PATCH 55/64] Add GPIO_POWERON to the list of devices that we support resume on.
+
+Signed-off-by: Dmitry Baryshkov <dbaryshkov@gmail.com>
+---
+ arch/arm/mach-pxa/tosa.c |    6 +++---
+ 1 files changed, 3 insertions(+), 3 deletions(-)
+
+diff --git a/arch/arm/mach-pxa/tosa.c b/arch/arm/mach-pxa/tosa.c
+index 3e832dc..d1cf3dc 100644
+--- a/arch/arm/mach-pxa/tosa.c
++++ b/arch/arm/mach-pxa/tosa.c
+@@ -517,9 +517,9 @@ static void __init tosa_init(void)
+       pxa_gpio_mode(TOSA_GPIO_USB_IN | GPIO_IN);
+       /* setup sleep mode values */
+-      PWER  = 0x00000002;
+-      PFER  = 0x00000000;
+-      PRER  = 0x00000002;
++      PWER  = BIT(TOSA_GPIO_POWERON) | BIT(TOSA_GPIO_RESET);
++      PFER  = 0;
++      PRER  = BIT(TOSA_GPIO_POWERON) | BIT(TOSA_GPIO_RESET);
+       PGSR0 = 0x00000000;
+       PGSR1 = 0x00FF0002;
+       PGSR2 = 0x00014000;
+-- 
+1.5.3.8
+
diff --git a/packages/kexecboot/linux-kexecboot-2.6.24/tosa/0056-Support-resetting-by-asserting-GPIO-pin.patch b/packages/kexecboot/linux-kexecboot-2.6.24/tosa/0056-Support-resetting-by-asserting-GPIO-pin.patch
new file mode 100644 (file)
index 0000000..99220f9
--- /dev/null
@@ -0,0 +1,126 @@
+From e039614a0ce6df645f8fa4cbe32e4b21fe46a288 Mon Sep 17 00:00:00 2001
+From: Dmitry Baryshkov <dbaryshkov@gmail.com>
+Date: Sun, 20 Jan 2008 02:44:03 +0300
+Subject: [PATCH 56/64] Support resetting by asserting GPIO pin
+
+This adds support for resetting via assertion of GPIO pin.
+This e.g. is used on Sharp Zaurus SL-6000.
+
+Signed-off-by: Dmitry Baryshkov <dbaryshkov@gmail.com>
+---
+ arch/arm/mach-pxa/gpio.c          |   43 +++++++++++++++++++++++++++++++++++++
+ arch/arm/mach-pxa/pm.c            |    4 +-
+ include/asm-arm/arch-pxa/system.h |   10 ++++++++
+ 3 files changed, 55 insertions(+), 2 deletions(-)
+
+diff --git a/arch/arm/mach-pxa/gpio.c b/arch/arm/mach-pxa/gpio.c
+index 8638dd7..589da3b 100644
+--- a/arch/arm/mach-pxa/gpio.c
++++ b/arch/arm/mach-pxa/gpio.c
+@@ -19,6 +19,7 @@
+ #include <asm/hardware.h>
+ #include <asm/io.h>
+ #include <asm/arch/pxa-regs.h>
++#include <asm/arch/system.h>
+ #include "generic.h"
+@@ -194,4 +195,46 @@ void __init pxa_init_gpio(int gpio_nr)
+                       pxa_gpio_chip[i/32].chip.ngpio = gpio_nr - i;
+               gpiochip_add(&pxa_gpio_chip[i/32].chip);
+       }
++
++      if (reset_gpio < gpio_nr)
++              init_reset_gpio();
++}
++
++int reset_gpio = -1;
++static int __init reset_gpio_setup(char *str)
++{
++      if (get_option(&str, &reset_gpio) != 1) {
++              printk(KERN_ERR "reset_gpio: bad value secified");
++              return 0;
++      }
++
++      return 1;
++}
++
++__setup("reset_gpio=", reset_gpio_setup);
++
++int init_reset_gpio(void)
++{
++      int rc = 0;
++      if (reset_gpio == -1)
++              goto out;
++
++      rc = gpio_request(reset_gpio, "reset generator");
++      if (rc) {
++              printk(KERN_ERR "Can't request reset_gpio\n");
++              goto out;
++      }
++
++      rc = gpio_direction_input(reset_gpio);
++      if (rc) {
++              printk(KERN_ERR "Can't configure reset_gpio for input\n");
++              gpio_free(reset_gpio);
++              goto out;
++      }
++
++out:
++      if (rc)
++              reset_gpio = -1;
++
++      return rc;
+ }
+diff --git a/arch/arm/mach-pxa/pm.c b/arch/arm/mach-pxa/pm.c
+index a941c71..64f37e5 100644
+--- a/arch/arm/mach-pxa/pm.c
++++ b/arch/arm/mach-pxa/pm.c
+@@ -40,8 +40,8 @@ int pxa_pm_enter(suspend_state_t state)
+       pxa_cpu_pm_fns->save(sleep_save);
+-      /* Clear sleep reset status */
+-      RCSR = RCSR_SMR;
++      /* Clear reset status */
++      RCSR = RCSR_HWR | RCSR_WDR | RCSR_SMR | RCSR_GPR;
+       /* before sleeping, calculate and save a checksum */
+       for (i = 0; i < pxa_cpu_pm_fns->save_size - 1; i++)
+diff --git a/include/asm-arm/arch-pxa/system.h b/include/asm-arm/arch-pxa/system.h
+index 1d56a3e..c075018 100644
+--- a/include/asm-arm/arch-pxa/system.h
++++ b/include/asm-arm/arch-pxa/system.h
+@@ -11,6 +11,7 @@
+  */
+ #include <asm/proc-fns.h>
++#include <asm/gpio.h>
+ #include "hardware.h"
+ #include "pxa-regs.h"
+@@ -19,12 +20,21 @@ static inline void arch_idle(void)
+       cpu_do_idle();
+ }
++extern int reset_gpio;
++
++int init_reset_gpio(void);
+ static inline void arch_reset(char mode)
+ {
++      RCSR = RCSR_HWR | RCSR_WDR | RCSR_SMR | RCSR_GPR;
++
+       if (mode == 's') {
+               /* Jump into ROM at address 0 */
+               cpu_reset(0);
++      } else if (mode == 'g' && reset_gpio != -1) {
++              /* Use GPIO reset */
++              gpio_direction_output(reset_gpio, 0);
++              gpio_set_value(reset_gpio, 1);
+       } else {
+               /* Initialize the watchdog and let it fire */
+               OWER = OWER_WME;
+-- 
+1.5.3.8
+
diff --git a/packages/kexecboot/linux-kexecboot-2.6.24/tosa/0057-Clean-up-tosa-resetting.patch b/packages/kexecboot/linux-kexecboot-2.6.24/tosa/0057-Clean-up-tosa-resetting.patch
new file mode 100644 (file)
index 0000000..441e1bb
--- /dev/null
@@ -0,0 +1,70 @@
+From a6f03929fa4d20cef339dbed7ef5cd1e040d0548 Mon Sep 17 00:00:00 2001
+From: Dmitry Baryshkov <dbaryshkov@gmail.com>
+Date: Sun, 20 Jan 2008 02:48:07 +0300
+Subject: [PATCH 57/64] Clean up tosa resetting
+
+Use new gpio-assertion reset.
+
+Signed-off-by: Dmitry Baryshkov <dbaryshkov@gmail.com>
+---
+ arch/arm/mach-pxa/tosa.c |   16 +++++++---------
+ 1 files changed, 7 insertions(+), 9 deletions(-)
+
+diff --git a/arch/arm/mach-pxa/tosa.c b/arch/arm/mach-pxa/tosa.c
+index d1cf3dc..2b4aef7 100644
+--- a/arch/arm/mach-pxa/tosa.c
++++ b/arch/arm/mach-pxa/tosa.c
+@@ -41,6 +41,8 @@
+ #include <asm/arch/irda.h>
+ #include <asm/arch/mmc.h>
+ #include <asm/arch/udc.h>
++#include <asm/arch/pm.h>
++#include <asm/arch/system.h>
+ #include <asm/mach/arch.h>
+ #include <asm/mach/map.h>
+@@ -489,13 +491,7 @@ static struct platform_device *devices[] __initdata = {
+ static void tosa_poweroff(void)
+ {
+-      RCSR = RCSR_HWR | RCSR_WDR | RCSR_SMR | RCSR_GPR;
+-
+-      pxa_gpio_mode(TOSA_GPIO_ON_RESET | GPIO_OUT);
+-      GPSR(TOSA_GPIO_ON_RESET) = GPIO_bit(TOSA_GPIO_ON_RESET);
+-
+-      mdelay(1000);
+-      arm_machine_restart('h');
++      arm_machine_restart('g');
+ }
+ static void tosa_restart(char mode)
+@@ -504,7 +500,7 @@ static void tosa_restart(char mode)
+       if((MSC0 & 0xffff0000) == 0x7ff00000)
+               MSC0 = (MSC0 & 0xffff) | 0x7ee00000;
+-      tosa_poweroff();
++      arm_machine_restart('g');
+ }
+ static void __init tosa_init(void)
+@@ -512,7 +508,6 @@ static void __init tosa_init(void)
+       pm_power_off = tosa_poweroff;
+       arm_pm_restart = tosa_restart;
+-      pxa_gpio_mode(TOSA_GPIO_ON_RESET | GPIO_IN);
+       pxa_gpio_mode(TOSA_GPIO_TC6393XB_INT | GPIO_IN);
+       pxa_gpio_mode(TOSA_GPIO_USB_IN | GPIO_IN);
+@@ -544,6 +539,9 @@ static void __init fixup_tosa(struct machine_desc *desc,
+       mi->bank[0].start = 0xa0000000;
+       mi->bank[0].node = 0;
+       mi->bank[0].size = (64*1024*1024);
++
++      if (reset_gpio == -1)
++              reset_gpio = TOSA_GPIO_ON_RESET;
+ }
+ MACHINE_START(TOSA, "SHARP Tosa")
+-- 
+1.5.3.8
+
diff --git a/packages/kexecboot/linux-kexecboot-2.6.24/tosa/0058-Fix-tosakbd-suspend.patch b/packages/kexecboot/linux-kexecboot-2.6.24/tosa/0058-Fix-tosakbd-suspend.patch
new file mode 100644 (file)
index 0000000..e965857
--- /dev/null
@@ -0,0 +1,27 @@
+From 8b57c409802e5feef64c4bb7659570e06558c0f2 Mon Sep 17 00:00:00 2001
+From: Dmitry Baryshkov <dbaryshkov@gmail.com>
+Date: Sun, 20 Jan 2008 02:24:43 +0300
+Subject: [PATCH 58/64] Fix tosakbd suspend
+
+Signed-off-by: Dmitry Baryshkov <dbaryshkov@gmail.com>
+---
+ drivers/input/keyboard/tosakbd.c |    3 +++
+ 1 files changed, 3 insertions(+), 0 deletions(-)
+
+diff --git a/drivers/input/keyboard/tosakbd.c b/drivers/input/keyboard/tosakbd.c
+index 3884d1e..306cbe8 100644
+--- a/drivers/input/keyboard/tosakbd.c
++++ b/drivers/input/keyboard/tosakbd.c
+@@ -210,6 +210,9 @@ static int tosakbd_suspend(struct platform_device *dev, pm_message_t state)
+       del_timer_sync(&tosakbd->timer);
++      PGSR1 = (PGSR1 & ~TOSA_GPIO_LOW_STROBE_BIT);
++      PGSR2 = (PGSR2 & ~TOSA_GPIO_HIGH_STROBE_BIT);
++
+       return 0;
+ }
+-- 
+1.5.3.8
+
diff --git a/packages/kexecboot/linux-kexecboot-2.6.24/tosa/0059-patch-tosa-wakeup-test.patch b/packages/kexecboot/linux-kexecboot-2.6.24/tosa/0059-patch-tosa-wakeup-test.patch
new file mode 100644 (file)
index 0000000..812b5ba
--- /dev/null
@@ -0,0 +1,46 @@
+From 00f6e9b946d1f653fc776d71c86a1f6a7534cd1d Mon Sep 17 00:00:00 2001
+From: Dmitry Baryshkov <dbaryshkov@gmail.com>
+Date: Fri, 25 Jan 2008 19:16:20 +0300
+Subject: [PATCH 59/64] patch tosa-wakeup-test
+
+---
+ arch/arm/mach-pxa/tosa.c |   18 +++++++++++++++++-
+ 1 files changed, 17 insertions(+), 1 deletions(-)
+
+diff --git a/arch/arm/mach-pxa/tosa.c b/arch/arm/mach-pxa/tosa.c
+index 2b4aef7..7008919 100644
+--- a/arch/arm/mach-pxa/tosa.c
++++ b/arch/arm/mach-pxa/tosa.c
+@@ -260,12 +260,28 @@ static struct platform_device tosakbd_device = {
+ };
+ static struct gpio_keys_button tosa_gpio_keys[] = {
++      /*
++       * Two following keys are directly tied to "ON" button of tosa. Why?
++       * The first one can be used as a wakeup source, the second can't:
++       * it's outside of permitted area.
++       */
++      {
++              .type   = EV_PWR,
++              .code   = KEY_RESERVED,
++              .gpio   = TOSA_GPIO_POWERON,
++              .desc   = "Poweron",
++              .wakeup = 1,
++              .active_low = 1,
++      },
+       {
+               .type   = EV_PWR,
+               .code   = KEY_SUSPEND,
+               .gpio   = TOSA_GPIO_ON_KEY,
+               .desc   = "On key",
+-              .wakeup = 1,
++              /*
++               * can't be used as wakeup
++               * .wakeup      = 1,
++               */
+               .active_low = 1,
+       },
+       {
+-- 
+1.5.3.8
+
diff --git a/packages/kexecboot/linux-kexecboot-2.6.24/tosa/0060-Add-support-for-power_supply-on-tosa.patch b/packages/kexecboot/linux-kexecboot-2.6.24/tosa/0060-Add-support-for-power_supply-on-tosa.patch
new file mode 100644 (file)
index 0000000..f7420de
--- /dev/null
@@ -0,0 +1,623 @@
+From f6ec15733eb55e851c8ad19c2143d425558f6044 Mon Sep 17 00:00:00 2001
+From: Dmitry Baryshkov <dbaryshkov@gmail.com>
+Date: Mon, 4 Feb 2008 20:11:58 +0300
+Subject: [PATCH 60/64] Add support for power_supply on tosa
+
+Signed-off-by: Dmitry Baryshkov <dbaryshkov@gmail.com>
+---
+ arch/arm/mach-pxa/Makefile     |    2 +-
+ arch/arm/mach-pxa/tosa_power.c |   82 +++++++
+ drivers/leds/leds-tosa.c       |    2 +-
+ drivers/power/Kconfig          |    7 +
+ drivers/power/Makefile         |    1 +
+ drivers/power/tosa_battery.c   |  458 ++++++++++++++++++++++++++++++++++++++++
+ 6 files changed, 550 insertions(+), 2 deletions(-)
+ create mode 100644 arch/arm/mach-pxa/tosa_power.c
+ create mode 100644 drivers/power/tosa_battery.c
+
+diff --git a/arch/arm/mach-pxa/Makefile b/arch/arm/mach-pxa/Makefile
+index f276d24..2b68254 100644
+--- a/arch/arm/mach-pxa/Makefile
++++ b/arch/arm/mach-pxa/Makefile
+@@ -21,7 +21,7 @@ obj-$(CONFIG_PXA_SHARP_C7xx) += corgi.o corgi_ssp.o corgi_lcd.o sharpsl_pm.o cor
+ obj-$(CONFIG_PXA_SHARP_Cxx00) += spitz.o corgi_ssp.o corgi_lcd.o sharpsl_pm.o spitz_pm.o
+ obj-$(CONFIG_MACH_AKITA)      += akita-ioexp.o
+ obj-$(CONFIG_MACH_POODLE)     += poodle.o corgi_ssp.o sharpsl_pm.o poodle_pm.o
+-obj-$(CONFIG_MACH_TOSA)               += tosa.o
++obj-$(CONFIG_MACH_TOSA)               += tosa.o tosa_power.o
+ obj-$(CONFIG_MACH_EM_X270)    += em-x270.o
+ ifeq ($(CONFIG_MACH_ZYLONITE),y)
+diff --git a/arch/arm/mach-pxa/tosa_power.c b/arch/arm/mach-pxa/tosa_power.c
+new file mode 100644
+index 0000000..61ca7dc
+--- /dev/null
++++ b/arch/arm/mach-pxa/tosa_power.c
+@@ -0,0 +1,82 @@
++/*
++ * Battery and Power Management code for the Sharp SL-6000x
++ *
++ * Copyright (c) 2005 Dirk Opfer
++ * Copyright (c) 2008 Dmitry Baryshkov
++ *
++ * 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/kernel.h>
++#include <linux/module.h>
++#include <linux/power_supply.h>
++#include <linux/pda_power.h>
++#include <linux/platform_device.h>
++#include <linux/interrupt.h>
++
++#include <asm/arch/tosa.h>
++#include <asm/gpio.h>
++
++static int tosa_power_ac_online(void)
++{
++      return gpio_get_value(TOSA_GPIO_AC_IN) == 0;
++}
++
++static char *tosa_ac_supplied_to[] = {
++      "main-battery",
++      "backup-battery",
++      "jacket-battery",
++};
++
++static struct pda_power_pdata tosa_power_data = {
++      .is_ac_online           = tosa_power_ac_online,
++      .supplied_to            = tosa_ac_supplied_to,
++      .num_supplicants        = ARRAY_SIZE(tosa_ac_supplied_to),
++};
++
++static struct resource tosa_power_resource[] = {
++      {
++              .name           = "ac",
++              .start          = gpio_to_irq(TOSA_GPIO_AC_IN),
++              .end            = gpio_to_irq(TOSA_GPIO_AC_IN),
++              .flags          = IORESOURCE_IRQ |
++                                IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
++      },
++};
++
++static struct platform_device tosa_power_device = {
++      .name                   = "pda-power",
++      .id                     = -1,
++      .dev.platform_data      = &tosa_power_data,
++      .resource               = tosa_power_resource,
++      .num_resources          = ARRAY_SIZE(tosa_power_resource),
++};
++
++static int __init tosa_power_init(void)
++{
++      int ret = gpio_request(TOSA_GPIO_AC_IN, "ac");
++      if (ret)
++              goto err_gpio_req;
++
++      ret = gpio_direction_input(TOSA_GPIO_AC_IN);
++      if (ret)
++              goto err_gpio_in;
++
++      return platform_device_register(&tosa_power_device);
++
++err_gpio_in:
++      gpio_free(TOSA_GPIO_AC_IN);
++err_gpio_req:
++      return ret;
++}
++
++static void __exit tosa_power_exit(void)
++{
++      platform_device_unregister(&tosa_power_device);
++      gpio_free(TOSA_GPIO_AC_IN);
++}
++
++module_init(tosa_power_init);
++module_exit(tosa_power_exit);
+diff --git a/drivers/leds/leds-tosa.c b/drivers/leds/leds-tosa.c
+index fb2416a..b4498b5 100644
+--- a/drivers/leds/leds-tosa.c
++++ b/drivers/leds/leds-tosa.c
+@@ -46,7 +46,7 @@ static void tosaled_green_set(struct led_classdev *led_cdev,
+ static struct led_classdev tosa_amber_led = {
+       .name                   = "tosa:amber",
+-      .default_trigger        = "sharpsl-charge",
++      .default_trigger        = "main-battery-charging",
+       .brightness_set         = tosaled_amber_set,
+ };
+diff --git a/drivers/power/Kconfig b/drivers/power/Kconfig
+index 58c806e..e3a9c37 100644
+--- a/drivers/power/Kconfig
++++ b/drivers/power/Kconfig
+@@ -49,4 +49,11 @@ config BATTERY_OLPC
+       help
+         Say Y to enable support for the battery on the OLPC laptop.
++config BATTERY_TOSA
++      tristate "Sharp SL-6000 (tosa) battery"
++      depends on MACH_TOSA && MFD_TC6393XB
++      help
++        Say Y to enable support for the battery on the Sharp Zaurus
++        SL-6000 (tosa) models.
++
+ endif # POWER_SUPPLY
+diff --git a/drivers/power/Makefile b/drivers/power/Makefile
+index 6413ded..1e408fa 100644
+--- a/drivers/power/Makefile
++++ b/drivers/power/Makefile
+@@ -20,3 +20,4 @@ obj-$(CONFIG_APM_POWER)              += apm_power.o
+ obj-$(CONFIG_BATTERY_DS2760)  += ds2760_battery.o
+ obj-$(CONFIG_BATTERY_PMU)     += pmu_battery.o
+ obj-$(CONFIG_BATTERY_OLPC)    += olpc_battery.o
++obj-$(CONFIG_BATTERY_TOSA)    += tosa_battery.o
+diff --git a/drivers/power/tosa_battery.c b/drivers/power/tosa_battery.c
+new file mode 100644
+index 0000000..b0fd2f2
+--- /dev/null
++++ b/drivers/power/tosa_battery.c
+@@ -0,0 +1,458 @@
++/*
++ * Battery and Power Management code for the Sharp SL-6000x
++ *
++ * Copyright (c) 2005 Dirk Opfer
++ * Copyright (c) 2008 Dmitry Baryshkov
++ *
++ * 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/kernel.h>
++#include <linux/module.h>
++#include <linux/power_supply.h>
++#include <linux/wm97xx.h>
++#include <linux/delay.h>
++#include <linux/spinlock.h>
++#include <linux/interrupt.h>
++
++#include <asm/mach-types.h>
++#include <asm/gpio.h>
++#include <asm/arch/tosa.h>
++
++#define BAT_TO_VOLTS(v)               ((v) * 1000000 / 414)
++#define BU_TO_VOLTS(v)                ((v) * 1000000 / 1266)
++/*
++ * It's pretty strange value, but that's roughly what I get from
++ * zaurus maintainer menu
++ */
++//#define BAT_TO_TEMP(t)              ((t) * 10000/2000)
++#define BAT_TO_TEMP(t)                        (t)
++
++static DEFINE_MUTEX(bat_lock); /* protects gpio pins */
++static struct work_struct bat_work;
++
++struct tosa_bat {
++      int status;
++      struct power_supply psy;
++      int full_chrg;
++
++      struct mutex work_lock; /* protects data */
++      bool (*is_present)(struct tosa_bat *bat);
++      int gpio_full;
++      int gpio_charge_off;
++      int gpio_bat;
++      int adc_bat;
++      int gpio_temp;
++      int adc_temp;
++};
++
++static struct tosa_bat tosa_bat_main;
++static struct tosa_bat tosa_bat_jacket;
++
++static enum power_supply_property tosa_bat_main_props[] = {
++      POWER_SUPPLY_PROP_STATUS,
++      POWER_SUPPLY_PROP_TECHNOLOGY,
++      POWER_SUPPLY_PROP_VOLTAGE_NOW,
++      POWER_SUPPLY_PROP_VOLTAGE_MAX,
++      POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN,
++      POWER_SUPPLY_PROP_TEMP,
++      POWER_SUPPLY_PROP_PRESENT,
++};
++
++static enum power_supply_property tosa_bat_bu_props[] = {
++      POWER_SUPPLY_PROP_STATUS,
++      POWER_SUPPLY_PROP_TECHNOLOGY,
++      POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN,
++      POWER_SUPPLY_PROP_VOLTAGE_NOW,
++      POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN,
++      POWER_SUPPLY_PROP_PRESENT,
++};
++
++static unsigned long tosa_read_bat(struct tosa_bat *bat)
++{
++      unsigned long value = 0;
++
++      if (bat->gpio_bat < 0 || bat->adc_bat < 0)
++              return 0;
++
++      mutex_lock(&bat_lock);
++      gpio_set_value(bat->gpio_bat, 1);
++      mdelay(5);
++      value = wm97xx_read_aux_adc(bat->psy.dev->parent->driver_data, bat->adc_bat);
++      gpio_set_value(bat->gpio_bat, 0);
++      mutex_unlock(&bat_lock);
++      return value;
++}
++
++static unsigned long tosa_read_temp(struct tosa_bat *bat)
++{
++      unsigned long value = 0;
++
++      if (bat->gpio_temp < 0 || bat->adc_temp < 0)
++              return 0;
++
++      mutex_lock(&bat_lock);
++      gpio_set_value(bat->gpio_temp, 1);
++      mdelay(5);
++      value = wm97xx_read_aux_adc(bat->psy.dev->parent->driver_data, bat->adc_temp);
++      gpio_set_value(bat->gpio_temp, 0);
++      mutex_unlock(&bat_lock);
++      return value;
++}
++
++static int tosa_bat_get_property(struct power_supply *psy,
++                          enum power_supply_property psp,
++                          union power_supply_propval *val)
++{
++      int ret = 0;
++      struct tosa_bat *bat = container_of(psy, struct tosa_bat, psy);
++
++      if (bat->is_present && !bat->is_present(bat)
++                      && psp != POWER_SUPPLY_PROP_PRESENT) {
++              return -ENODEV;
++      }
++
++      switch (psp) {
++      case POWER_SUPPLY_PROP_STATUS:
++              val->intval = bat->status;
++              break;
++      case POWER_SUPPLY_PROP_TECHNOLOGY:
++              val->intval = POWER_SUPPLY_TECHNOLOGY_LIPO;
++              break;
++      case POWER_SUPPLY_PROP_VOLTAGE_NOW:
++              val->intval = BAT_TO_VOLTS(tosa_read_bat(bat));
++              break;
++      case POWER_SUPPLY_PROP_VOLTAGE_MAX:
++              if (bat->full_chrg == -1)
++                      val->intval = -1;
++              else
++                      val->intval = BAT_TO_VOLTS(bat->full_chrg);
++              break;
++      case POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN:
++              val->intval = BAT_TO_VOLTS(1551);
++              break;
++      case POWER_SUPPLY_PROP_TEMP:
++              val->intval = BAT_TO_TEMP(tosa_read_temp(bat));
++              break;
++      case POWER_SUPPLY_PROP_PRESENT:
++              val->intval = bat->is_present ? bat->is_present(bat) : 1;
++              break;
++      default:
++              ret = -EINVAL;
++              break;
++      }
++      return ret;
++}
++
++static int tosa_bu_get_property(struct power_supply *psy,
++                          enum power_supply_property psp,
++                          union power_supply_propval *val)
++{
++      int ret = 0;
++      struct tosa_bat *bat = container_of(psy, struct tosa_bat, psy);
++
++      switch (psp) {
++      case POWER_SUPPLY_PROP_STATUS:
++              val->intval = POWER_SUPPLY_STATUS_UNKNOWN;
++              break;
++      case POWER_SUPPLY_PROP_TECHNOLOGY:
++              val->intval = POWER_SUPPLY_TECHNOLOGY_LiMn;
++              break;
++      case POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN:
++              val->intval = 0;
++              break;
++      case POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN:
++              val->intval = 3 * 1000000; /* 3 V */
++              break;
++      case POWER_SUPPLY_PROP_VOLTAGE_NOW:
++              /* I think so */
++              val->intval = BU_TO_VOLTS(tosa_read_bat(bat));
++              break;
++      case POWER_SUPPLY_PROP_PRESENT:
++              val->intval = 1;
++              break;
++      default:
++              ret = -EINVAL;
++              break;
++      }
++      return ret;
++}
++
++static bool tosa_jacket_bat_is_present(struct tosa_bat *bat) {
++      // FIXME
++      return 1;
++}
++
++static void tosa_bat_external_power_changed(struct power_supply *psy)
++{
++      schedule_work(&bat_work);
++}
++
++static irqreturn_t tosa_bat_full_isr(int irq, void *data)
++{
++      printk(KERN_ERR "bat_full irq: %d\n", gpio_get_value(irq_to_gpio(irq)));
++      schedule_work(&bat_work);
++      return IRQ_HANDLED;
++}
++
++static void tosa_bat_update(struct tosa_bat *bat)
++{
++      int old = bat->status;
++      struct power_supply *psy = &bat->psy;
++
++      mutex_lock(&bat->work_lock);
++
++      if (bat->is_present && !bat->is_present(bat)) {
++              printk(KERN_DEBUG "%s not present\n", psy->name);
++              bat->status = POWER_SUPPLY_STATUS_NOT_CHARGING;
++              bat->full_chrg = -1;
++      } else if (power_supply_am_i_supplied(psy)) {
++              if (gpio_get_value(bat->gpio_full)) {
++                      printk(KERN_DEBUG "%s full\n", psy->name);
++
++                      if (old == POWER_SUPPLY_STATUS_CHARGING || bat->full_chrg == -1)
++                              bat->full_chrg = tosa_read_bat(bat);
++
++                      gpio_set_value(bat->gpio_charge_off, 1);
++                      bat->status = POWER_SUPPLY_STATUS_FULL;
++              } else {
++                      printk(KERN_ERR "%s charge\n", psy->name);
++                      gpio_set_value(bat->gpio_charge_off, 0);
++                      bat->status = POWER_SUPPLY_STATUS_CHARGING;
++              }
++      } else {
++              printk(KERN_ERR "%s discharge\n", psy->name);
++              gpio_set_value(bat->gpio_charge_off, 1);
++              bat->status = POWER_SUPPLY_STATUS_DISCHARGING;
++      }
++
++      if (old != bat->status)
++              power_supply_changed(psy);
++
++      mutex_unlock(&bat->work_lock);
++}
++
++static void tosa_bat_work(struct work_struct *work)
++{
++      tosa_bat_update(&tosa_bat_main);
++      tosa_bat_update(&tosa_bat_jacket);
++}
++
++
++static struct tosa_bat tosa_bat_main = {
++      .status = POWER_SUPPLY_STATUS_UNKNOWN,
++      .full_chrg = -1,
++      .psy = {
++              .name           = "main-battery",
++              .type           = POWER_SUPPLY_TYPE_BATTERY,
++              .properties     = tosa_bat_main_props,
++              .num_properties = ARRAY_SIZE(tosa_bat_main_props),
++              .get_property   = tosa_bat_get_property,
++              .external_power_changed = tosa_bat_external_power_changed,
++              .use_for_apm    = 1,
++      },
++
++      .gpio_full = TOSA_GPIO_BAT0_CRG,
++      .gpio_charge_off = TOSA_TC6393XB_CHARGE_OFF,
++      .gpio_bat = TOSA_TC6393XB_BAT0_V_ON,
++      .adc_bat = WM97XX_AUX_ID3,
++      .gpio_temp = TOSA_TC6393XB_BAT1_TH_ON,
++      .adc_temp = WM97XX_AUX_ID2,
++};
++
++static struct tosa_bat tosa_bat_jacket = {
++      .status = POWER_SUPPLY_STATUS_UNKNOWN,
++      .full_chrg = -1,
++      .psy = {
++              .name           = "jacket-battery",
++              .type           = POWER_SUPPLY_TYPE_BATTERY,
++              .properties     = tosa_bat_main_props,
++              .num_properties = ARRAY_SIZE(tosa_bat_main_props),
++              .get_property   = tosa_bat_get_property,
++              .external_power_changed = tosa_bat_external_power_changed,
++//            .use_for_apm    = 1,
++      },
++
++      .is_present = tosa_jacket_bat_is_present,
++      .gpio_full = TOSA_GPIO_BAT1_CRG,
++      .gpio_charge_off = TOSA_TC6393XB_CHARGE_OFF_JC,
++      .gpio_bat = TOSA_TC6393XB_BAT1_V_ON,
++      .adc_bat = WM97XX_AUX_ID3,
++      .gpio_temp = TOSA_TC6393XB_BAT0_TH_ON,
++      .adc_temp = WM97XX_AUX_ID2,
++};
++
++static struct tosa_bat tosa_bat_bu = {
++      .status = POWER_SUPPLY_STATUS_UNKNOWN,
++      .full_chrg = -1,
++
++      .psy = {
++              .name           = "backup-battery",
++              .type           = POWER_SUPPLY_TYPE_BATTERY,
++              .properties     = tosa_bat_bu_props,
++              .num_properties = ARRAY_SIZE(tosa_bat_bu_props),
++              .get_property   = tosa_bu_get_property,
++              .external_power_changed = tosa_bat_external_power_changed,
++      },
++
++      .gpio_full = -1,
++      .gpio_charge_off = -1,
++      .gpio_bat = TOSA_TC6393XB_BU_CHRG_ON,
++      .adc_bat = WM97XX_AUX_ID4,
++      .gpio_temp = -1,
++      .adc_temp = -1,
++};
++
++static struct {
++      int gpio;
++      char *name;
++      bool output;
++      int value;
++} gpios[] = {
++      { TOSA_TC6393XB_CHARGE_OFF,     "main charge off",      1, 1 },
++      { TOSA_TC6393XB_CHARGE_OFF_JC,  "jacket charge off",    1, 1 },
++      { TOSA_TC6393XB_BAT_SW_ON,      "battery switch",       1, 0 },
++      { TOSA_TC6393XB_BAT0_V_ON,      "main battery",         1, 0 },
++      { TOSA_TC6393XB_BAT1_V_ON,      "jacket battery",       1, 0 },
++      { TOSA_TC6393XB_BAT1_TH_ON,     "main battery temp",    1, 0 },
++      { TOSA_TC6393XB_BAT0_TH_ON,     "jacket battery temp",  1, 0 },
++      { TOSA_TC6393XB_BU_CHRG_ON,     "backup battery",       1, 0 },
++      { TOSA_GPIO_BAT0_CRG,           "main battery full",    0, 0 },
++      { TOSA_GPIO_BAT1_CRG,           "jacket battery full",  0, 0 },
++      { TOSA_GPIO_BAT0_LOW,           "main battery low",     0, 0 },
++      { TOSA_GPIO_BAT1_LOW,           "jacket battery low",   0, 0 },
++};
++
++#ifdef CONFIG_PM
++static int tosa_bat_suspend(struct device *dev, pm_message_t state)
++{
++      /* do nothing */
++      return 0;
++}
++
++static int tosa_bat_resume(struct device *dev)
++{
++      schedule_work(&bat_work);
++      return 0;
++}
++#else
++#define tosa_bat_suspend NULL
++#define tosa_bat_resume NULL
++#endif
++
++static int __devinit tosa_bat_probe(struct device *dev)
++{
++      int ret;
++      int i;
++
++      if (!machine_is_tosa())
++              return -ENODEV;
++
++      for (i = 0; i < ARRAY_SIZE(gpios); i++) {
++              ret = gpio_request(gpios[i].gpio, gpios[i].name);
++              if (ret) {
++                      i --;
++                      goto err_gpio;
++              }
++
++              if (gpios[i].output)
++                      ret = gpio_direction_output(gpios[i].gpio,
++                                      gpios[i].value);
++              else
++                      ret = gpio_direction_input(gpios[i].gpio);
++
++              if (ret)
++                      goto err_gpio;
++      }
++
++      mutex_init(&tosa_bat_main.work_lock);
++      mutex_init(&tosa_bat_jacket.work_lock);
++
++      INIT_WORK(&bat_work, tosa_bat_work);
++
++      ret = power_supply_register(dev, &tosa_bat_main.psy);
++      if (ret)
++              goto err_psy_reg_main;
++      ret = power_supply_register(dev, &tosa_bat_jacket.psy);
++      if (ret)
++              goto err_psy_reg_jacket;
++      ret = power_supply_register(dev, &tosa_bat_bu.psy);
++      if (ret)
++              goto err_psy_reg_bu;
++
++      ret = request_irq(gpio_to_irq(TOSA_GPIO_BAT0_CRG),
++                              tosa_bat_full_isr, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
++                              "main full", &tosa_bat_main);
++      if (ret)
++              goto err_req_main;
++
++      ret = request_irq(gpio_to_irq(TOSA_GPIO_BAT1_CRG),
++                              tosa_bat_full_isr, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
++                              "jacket full", &tosa_bat_jacket);
++      if (!ret) {
++              schedule_work(&bat_work);
++              return 0;
++      }
++
++      free_irq(gpio_to_irq(TOSA_GPIO_BAT0_CRG), &tosa_bat_main);
++err_req_main:
++      power_supply_unregister(&tosa_bat_bu.psy);
++err_psy_reg_bu:
++      power_supply_unregister(&tosa_bat_jacket.psy);
++err_psy_reg_jacket:
++      power_supply_unregister(&tosa_bat_main.psy);
++err_psy_reg_main:
++
++      i --;
++err_gpio:
++      for (; i >= 0; i --)
++              gpio_free(gpios[i].gpio);
++
++      return ret;
++}
++
++static int __devexit tosa_bat_remove(struct device *dev)
++{
++      int i;
++
++      free_irq(gpio_to_irq(TOSA_GPIO_BAT1_CRG), &tosa_bat_jacket);
++      free_irq(gpio_to_irq(TOSA_GPIO_BAT0_CRG), &tosa_bat_main);
++
++      power_supply_unregister(&tosa_bat_bu.psy);
++      power_supply_unregister(&tosa_bat_jacket.psy);
++      power_supply_unregister(&tosa_bat_main.psy);
++
++      for (i = ARRAY_SIZE(gpios) - 1; i >= 0; i --)
++              gpio_free(gpios[i].gpio);
++
++      return 0;
++}
++
++static struct device_driver tosa_bat_driver = {
++      .name           = "wm97xx-battery",
++      .bus            = &wm97xx_bus_type,
++      .owner          = THIS_MODULE,
++      .probe          = tosa_bat_probe,
++      .remove         = __devexit_p(tosa_bat_remove),
++      .suspend        = tosa_bat_suspend,
++      .resume         = tosa_bat_resume,
++};
++
++static int __init tosa_bat_init(void)
++{
++      return driver_register(&tosa_bat_driver);
++}
++
++static void __exit tosa_bat_exit(void)
++{
++      driver_unregister(&tosa_bat_driver);
++}
++
++module_init(tosa_bat_init);
++module_exit(tosa_bat_exit);
++
++MODULE_LICENSE("GPL");
++MODULE_AUTHOR("Dmitry Baryshkov");
++MODULE_DESCRIPTION("Tosa battery driver");
+-- 
+1.5.3.8
+
diff --git a/packages/kexecboot/linux-kexecboot-2.6.24/tosa/0061-tosa-bat-unify.patch b/packages/kexecboot/linux-kexecboot-2.6.24/tosa/0061-tosa-bat-unify.patch
new file mode 100644 (file)
index 0000000..2bcede3
--- /dev/null
@@ -0,0 +1,342 @@
+From f05aa38af5bd5962ae04c4b128644e7f55451527 Mon Sep 17 00:00:00 2001
+From: Dmitry Baryshkov <dbaryshkov@gmail.com>
+Date: Fri, 8 Feb 2008 01:14:48 +0300
+Subject: [PATCH 61/64] tosa-bat-unify
+
+Signed-off-by: Dmitry Baryshkov <dbaryshkov@gmail.com>
+---
+ drivers/power/tosa_battery.c |  161 ++++++++++++++++++++---------------------
+ 1 files changed, 79 insertions(+), 82 deletions(-)
+
+diff --git a/drivers/power/tosa_battery.c b/drivers/power/tosa_battery.c
+index b0fd2f2..008e791 100644
+--- a/drivers/power/tosa_battery.c
++++ b/drivers/power/tosa_battery.c
+@@ -21,15 +21,6 @@
+ #include <asm/gpio.h>
+ #include <asm/arch/tosa.h>
+-#define BAT_TO_VOLTS(v)               ((v) * 1000000 / 414)
+-#define BU_TO_VOLTS(v)                ((v) * 1000000 / 1266)
+-/*
+- * It's pretty strange value, but that's roughly what I get from
+- * zaurus maintainer menu
+- */
+-//#define BAT_TO_TEMP(t)              ((t) * 10000/2000)
+-#define BAT_TO_TEMP(t)                        (t)
+-
+ static DEFINE_MUTEX(bat_lock); /* protects gpio pins */
+ static struct work_struct bat_work;
+@@ -39,37 +30,27 @@ struct tosa_bat {
+       int full_chrg;
+       struct mutex work_lock; /* protects data */
++
+       bool (*is_present)(struct tosa_bat *bat);
+       int gpio_full;
+       int gpio_charge_off;
++
++      int technology;
++
+       int gpio_bat;
+       int adc_bat;
++      int adc_bat_divider;
++      int bat_max;
++      int bat_min;
++
+       int gpio_temp;
+       int adc_temp;
++      int adc_temp_divider;
+ };
+ static struct tosa_bat tosa_bat_main;
+ static struct tosa_bat tosa_bat_jacket;
+-static enum power_supply_property tosa_bat_main_props[] = {
+-      POWER_SUPPLY_PROP_STATUS,
+-      POWER_SUPPLY_PROP_TECHNOLOGY,
+-      POWER_SUPPLY_PROP_VOLTAGE_NOW,
+-      POWER_SUPPLY_PROP_VOLTAGE_MAX,
+-      POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN,
+-      POWER_SUPPLY_PROP_TEMP,
+-      POWER_SUPPLY_PROP_PRESENT,
+-};
+-
+-static enum power_supply_property tosa_bat_bu_props[] = {
+-      POWER_SUPPLY_PROP_STATUS,
+-      POWER_SUPPLY_PROP_TECHNOLOGY,
+-      POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN,
+-      POWER_SUPPLY_PROP_VOLTAGE_NOW,
+-      POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN,
+-      POWER_SUPPLY_PROP_PRESENT,
+-};
+-
+ static unsigned long tosa_read_bat(struct tosa_bat *bat)
+ {
+       unsigned long value = 0;
+@@ -83,6 +64,9 @@ static unsigned long tosa_read_bat(struct tosa_bat *bat)
+       value = wm97xx_read_aux_adc(bat->psy.dev->parent->driver_data, bat->adc_bat);
+       gpio_set_value(bat->gpio_bat, 0);
+       mutex_unlock(&bat_lock);
++
++      value = value * 1000000 / bat->adc_bat_divider;
++
+       return value;
+ }
+@@ -99,6 +83,9 @@ static unsigned long tosa_read_temp(struct tosa_bat *bat)
+       value = wm97xx_read_aux_adc(bat->psy.dev->parent->driver_data, bat->adc_temp);
+       gpio_set_value(bat->gpio_temp, 0);
+       mutex_unlock(&bat_lock);
++
++      value = value * 10000 / bat->adc_temp_divider;
++
+       return value;
+ }
+@@ -119,22 +106,25 @@ static int tosa_bat_get_property(struct power_supply *psy,
+               val->intval = bat->status;
+               break;
+       case POWER_SUPPLY_PROP_TECHNOLOGY:
+-              val->intval = POWER_SUPPLY_TECHNOLOGY_LIPO;
++              val->intval = bat->technology;
+               break;
+       case POWER_SUPPLY_PROP_VOLTAGE_NOW:
+-              val->intval = BAT_TO_VOLTS(tosa_read_bat(bat));
++              val->intval = tosa_read_bat(bat);
+               break;
+       case POWER_SUPPLY_PROP_VOLTAGE_MAX:
+               if (bat->full_chrg == -1)
+-                      val->intval = -1;
++                      val->intval = bat->bat_max;
+               else
+-                      val->intval = BAT_TO_VOLTS(bat->full_chrg);
++                      val->intval = bat->full_chrg;
++              break;
++      case POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN:
++              val->intval = bat->bat_max;
+               break;
+       case POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN:
+-              val->intval = BAT_TO_VOLTS(1551);
++              val->intval = bat->bat_min;
+               break;
+       case POWER_SUPPLY_PROP_TEMP:
+-              val->intval = BAT_TO_TEMP(tosa_read_temp(bat));
++              val->intval = tosa_read_temp(bat);
+               break;
+       case POWER_SUPPLY_PROP_PRESENT:
+               val->intval = bat->is_present ? bat->is_present(bat) : 1;
+@@ -146,40 +136,6 @@ static int tosa_bat_get_property(struct power_supply *psy,
+       return ret;
+ }
+-static int tosa_bu_get_property(struct power_supply *psy,
+-                          enum power_supply_property psp,
+-                          union power_supply_propval *val)
+-{
+-      int ret = 0;
+-      struct tosa_bat *bat = container_of(psy, struct tosa_bat, psy);
+-
+-      switch (psp) {
+-      case POWER_SUPPLY_PROP_STATUS:
+-              val->intval = POWER_SUPPLY_STATUS_UNKNOWN;
+-              break;
+-      case POWER_SUPPLY_PROP_TECHNOLOGY:
+-              val->intval = POWER_SUPPLY_TECHNOLOGY_LiMn;
+-              break;
+-      case POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN:
+-              val->intval = 0;
+-              break;
+-      case POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN:
+-              val->intval = 3 * 1000000; /* 3 V */
+-              break;
+-      case POWER_SUPPLY_PROP_VOLTAGE_NOW:
+-              /* I think so */
+-              val->intval = BU_TO_VOLTS(tosa_read_bat(bat));
+-              break;
+-      case POWER_SUPPLY_PROP_PRESENT:
+-              val->intval = 1;
+-              break;
+-      default:
+-              ret = -EINVAL;
+-              break;
+-      }
+-      return ret;
+-}
+-
+ static bool tosa_jacket_bat_is_present(struct tosa_bat *bat) {
+       // FIXME
+       return 1;
+@@ -241,6 +197,25 @@ static void tosa_bat_work(struct work_struct *work)
+ }
++static enum power_supply_property tosa_bat_main_props[] = {
++      POWER_SUPPLY_PROP_STATUS,
++      POWER_SUPPLY_PROP_TECHNOLOGY,
++      POWER_SUPPLY_PROP_VOLTAGE_NOW,
++      POWER_SUPPLY_PROP_VOLTAGE_MAX,
++      POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN,
++      POWER_SUPPLY_PROP_TEMP,
++      POWER_SUPPLY_PROP_PRESENT,
++};
++
++static enum power_supply_property tosa_bat_bu_props[] = {
++      POWER_SUPPLY_PROP_STATUS,
++      POWER_SUPPLY_PROP_TECHNOLOGY,
++      POWER_SUPPLY_PROP_VOLTAGE_MIN_DESIGN,
++      POWER_SUPPLY_PROP_VOLTAGE_NOW,
++      POWER_SUPPLY_PROP_VOLTAGE_MAX_DESIGN,
++      POWER_SUPPLY_PROP_PRESENT,
++};
++
+ static struct tosa_bat tosa_bat_main = {
+       .status = POWER_SUPPLY_STATUS_UNKNOWN,
+       .full_chrg = -1,
+@@ -256,10 +231,18 @@ static struct tosa_bat tosa_bat_main = {
+       .gpio_full = TOSA_GPIO_BAT0_CRG,
+       .gpio_charge_off = TOSA_TC6393XB_CHARGE_OFF,
++
++      .technology = POWER_SUPPLY_TECHNOLOGY_LIPO,
++
+       .gpio_bat = TOSA_TC6393XB_BAT0_V_ON,
+       .adc_bat = WM97XX_AUX_ID3,
++      .adc_bat_divider = 414,
++      .bat_max = 4310000,
++      .bat_min = 1551 * 100000 / 414,
++
+       .gpio_temp = TOSA_TC6393XB_BAT1_TH_ON,
+       .adc_temp = WM97XX_AUX_ID2,
++      .adc_temp_divider = 10000,
+ };
+ static struct tosa_bat tosa_bat_jacket = {
+@@ -278,10 +261,18 @@ static struct tosa_bat tosa_bat_jacket = {
+       .is_present = tosa_jacket_bat_is_present,
+       .gpio_full = TOSA_GPIO_BAT1_CRG,
+       .gpio_charge_off = TOSA_TC6393XB_CHARGE_OFF_JC,
++
++      .technology = POWER_SUPPLY_TECHNOLOGY_LIPO,
++
+       .gpio_bat = TOSA_TC6393XB_BAT1_V_ON,
+       .adc_bat = WM97XX_AUX_ID3,
++      .adc_bat_divider = 414,
++      .bat_max = 4310000,
++      .bat_min = 1551 * 100000 / 414,
++
+       .gpio_temp = TOSA_TC6393XB_BAT0_TH_ON,
+       .adc_temp = WM97XX_AUX_ID2,
++      .adc_temp_divider = 10000,
+ };
+ static struct tosa_bat tosa_bat_bu = {
+@@ -293,16 +284,22 @@ static struct tosa_bat tosa_bat_bu = {
+               .type           = POWER_SUPPLY_TYPE_BATTERY,
+               .properties     = tosa_bat_bu_props,
+               .num_properties = ARRAY_SIZE(tosa_bat_bu_props),
+-              .get_property   = tosa_bu_get_property,
++              .get_property   = tosa_bat_get_property,
+               .external_power_changed = tosa_bat_external_power_changed,
+       },
+       .gpio_full = -1,
+       .gpio_charge_off = -1,
++
++      .technology = POWER_SUPPLY_TECHNOLOGY_LiMn,
++
+       .gpio_bat = TOSA_TC6393XB_BU_CHRG_ON,
+       .adc_bat = WM97XX_AUX_ID4,
++      .adc_bat_divider = 1266,
++
+       .gpio_temp = -1,
+       .adc_temp = -1,
++      .adc_temp_divider = -1,
+ };
+ static struct {
+@@ -326,13 +323,14 @@ static struct {
+ };
+ #ifdef CONFIG_PM
+-static int tosa_bat_suspend(struct device *dev, pm_message_t state)
++static int tosa_bat_suspend(struct platform_device *dev, pm_message_t state)
+ {
+       /* do nothing */
++      flush_scheduled_work();
+       return 0;
+ }
+-static int tosa_bat_resume(struct device *dev)
++static int tosa_bat_resume(struct platform_device *dev)
+ {
+       schedule_work(&bat_work);
+       return 0;
+@@ -342,7 +340,7 @@ static int tosa_bat_resume(struct device *dev)
+ #define tosa_bat_resume NULL
+ #endif
+-static int __devinit tosa_bat_probe(struct device *dev)
++static int __devinit tosa_bat_probe(struct platform_device *dev)
+ {
+       int ret;
+       int i;
+@@ -372,13 +370,13 @@ static int __devinit tosa_bat_probe(struct device *dev)
+       INIT_WORK(&bat_work, tosa_bat_work);
+-      ret = power_supply_register(dev, &tosa_bat_main.psy);
++      ret = power_supply_register(&dev->dev, &tosa_bat_main.psy);
+       if (ret)
+               goto err_psy_reg_main;
+-      ret = power_supply_register(dev, &tosa_bat_jacket.psy);
++      ret = power_supply_register(&dev->dev, &tosa_bat_jacket.psy);
+       if (ret)
+               goto err_psy_reg_jacket;
+-      ret = power_supply_register(dev, &tosa_bat_bu.psy);
++      ret = power_supply_register(&dev->dev, &tosa_bat_bu.psy);
+       if (ret)
+               goto err_psy_reg_bu;
+@@ -413,7 +411,7 @@ err_gpio:
+       return ret;
+ }
+-static int __devexit tosa_bat_remove(struct device *dev)
++static int __devexit tosa_bat_remove(struct platform_device *dev)
+ {
+       int i;
+@@ -430,10 +428,9 @@ static int __devexit tosa_bat_remove(struct device *dev)
+       return 0;
+ }
+-static struct device_driver tosa_bat_driver = {
+-      .name           = "wm97xx-battery",
+-      .bus            = &wm97xx_bus_type,
+-      .owner          = THIS_MODULE,
++static struct platform_driver tosa_bat_driver = {
++      .driver.name    = "wm97xx-battery",
++      .driver.owner   = THIS_MODULE,
+       .probe          = tosa_bat_probe,
+       .remove         = __devexit_p(tosa_bat_remove),
+       .suspend        = tosa_bat_suspend,
+@@ -442,12 +439,12 @@ static struct device_driver tosa_bat_driver = {
+ static int __init tosa_bat_init(void)
+ {
+-      return driver_register(&tosa_bat_driver);
++      return platform_driver_register(&tosa_bat_driver);
+ }
+ static void __exit tosa_bat_exit(void)
+ {
+-      driver_unregister(&tosa_bat_driver);
++      platform_driver_unregister(&tosa_bat_driver);
+ }
+ module_init(tosa_bat_init);
+-- 
+1.5.3.8
+
diff --git a/packages/kexecboot/linux-kexecboot-2.6.24/tosa/0062-tosa-bat-fix-charging.patch b/packages/kexecboot/linux-kexecboot-2.6.24/tosa/0062-tosa-bat-fix-charging.patch
new file mode 100644 (file)
index 0000000..e3a6b74
--- /dev/null
@@ -0,0 +1,78 @@
+From 0b9f80ab540b2e51f6e86f6a1adec67761f9368d Mon Sep 17 00:00:00 2001
+From: Dmitry Baryshkov <dbaryshkov@gmail.com>
+Date: Fri, 8 Feb 2008 00:50:03 +0300
+Subject: [PATCH 62/64] tosa-bat-fix-charging
+
+Signed-off-by: Dmitry Baryshkov <dbaryshkov@gmail.com>
+---
+ drivers/power/tosa_battery.c |   28 +++++++++++++++++++++-------
+ 1 files changed, 21 insertions(+), 7 deletions(-)
+
+diff --git a/drivers/power/tosa_battery.c b/drivers/power/tosa_battery.c
+index 008e791..2db9116 100644
+--- a/drivers/power/tosa_battery.c
++++ b/drivers/power/tosa_battery.c
+@@ -153,39 +153,53 @@ static irqreturn_t tosa_bat_full_isr(int irq, void *data)
+       return IRQ_HANDLED;
+ }
++static char *status_text[] = {
++      [POWER_SUPPLY_STATUS_UNKNOWN] =         "Unknown",
++      [POWER_SUPPLY_STATUS_CHARGING] =        "Charging",
++      [POWER_SUPPLY_STATUS_DISCHARGING] =     "Discharging",
++      [POWER_SUPPLY_STATUS_NOT_CHARGING] =    "Not charging",
++      [POWER_SUPPLY_STATUS_FULL] =            "Full",
++};
++
+ static void tosa_bat_update(struct tosa_bat *bat)
+ {
+-      int old = bat->status;
++      int old;
+       struct power_supply *psy = &bat->psy;
+       mutex_lock(&bat->work_lock);
++      old = bat->status;
++
+       if (bat->is_present && !bat->is_present(bat)) {
+-              printk(KERN_DEBUG "%s not present\n", psy->name);
++              printk(KERN_NOTICE "%s not present\n", psy->name);
+               bat->status = POWER_SUPPLY_STATUS_NOT_CHARGING;
+               bat->full_chrg = -1;
+       } else if (power_supply_am_i_supplied(psy)) {
++              if (bat->status == POWER_SUPPLY_STATUS_DISCHARGING) {
++                      gpio_set_value(bat->gpio_charge_off, 0);
++                      mdelay(15);
++              }
+               if (gpio_get_value(bat->gpio_full)) {
+-                      printk(KERN_DEBUG "%s full\n", psy->name);
+-
+                       if (old == POWER_SUPPLY_STATUS_CHARGING || bat->full_chrg == -1)
+                               bat->full_chrg = tosa_read_bat(bat);
+                       gpio_set_value(bat->gpio_charge_off, 1);
+                       bat->status = POWER_SUPPLY_STATUS_FULL;
+               } else {
+-                      printk(KERN_ERR "%s charge\n", psy->name);
+                       gpio_set_value(bat->gpio_charge_off, 0);
+                       bat->status = POWER_SUPPLY_STATUS_CHARGING;
+               }
+       } else {
+-              printk(KERN_ERR "%s discharge\n", psy->name);
+               gpio_set_value(bat->gpio_charge_off, 1);
+               bat->status = POWER_SUPPLY_STATUS_DISCHARGING;
+       }
+-      if (old != bat->status)
++      if (old != bat->status) {
++              printk(KERN_NOTICE "%s %s -> %s\n", psy->name,
++                              status_text[old],
++                              status_text[bat->status]);
+               power_supply_changed(psy);
++      }
+       mutex_unlock(&bat->work_lock);
+ }
+-- 
+1.5.3.8
+
diff --git a/packages/kexecboot/linux-kexecboot-2.6.24/tosa/0063-patch-tosa-bat-jacket-detect.patch b/packages/kexecboot/linux-kexecboot-2.6.24/tosa/0063-patch-tosa-bat-jacket-detect.patch
new file mode 100644 (file)
index 0000000..416cae4
--- /dev/null
@@ -0,0 +1,84 @@
+From 4ef7289137132959e3db5a1e77580ff9db185d90 Mon Sep 17 00:00:00 2001
+From: Dmitry Baryshkov <dbaryshkov@gmail.com>
+Date: Fri, 8 Feb 2008 01:13:54 +0300
+Subject: [PATCH 63/64] patch tosa-bat-jacket-detect
+
+---
+ drivers/power/tosa_battery.c |   21 +++++++++++++++------
+ 1 files changed, 15 insertions(+), 6 deletions(-)
+
+diff --git a/drivers/power/tosa_battery.c b/drivers/power/tosa_battery.c
+index 2db9116..70beed2 100644
+--- a/drivers/power/tosa_battery.c
++++ b/drivers/power/tosa_battery.c
+@@ -137,8 +137,7 @@ static int tosa_bat_get_property(struct power_supply *psy,
+ }
+ static bool tosa_jacket_bat_is_present(struct tosa_bat *bat) {
+-      // FIXME
+-      return 1;
++      return gpio_get_value(TOSA_GPIO_JACKET_DETECT) == 0;
+ }
+ static void tosa_bat_external_power_changed(struct power_supply *psy)
+@@ -146,9 +145,9 @@ static void tosa_bat_external_power_changed(struct power_supply *psy)
+       schedule_work(&bat_work);
+ }
+-static irqreturn_t tosa_bat_full_isr(int irq, void *data)
++static irqreturn_t tosa_bat_gpio_isr(int irq, void *data)
+ {
+-      printk(KERN_ERR "bat_full irq: %d\n", gpio_get_value(irq_to_gpio(irq)));
++      printk(KERN_ERR "bat_gpio irq: %d\n", gpio_get_value(irq_to_gpio(irq)));
+       schedule_work(&bat_work);
+       return IRQ_HANDLED;
+ }
+@@ -334,6 +333,7 @@ static struct {
+       { TOSA_GPIO_BAT1_CRG,           "jacket battery full",  0, 0 },
+       { TOSA_GPIO_BAT0_LOW,           "main battery low",     0, 0 },
+       { TOSA_GPIO_BAT1_LOW,           "jacket battery low",   0, 0 },
++      { TOSA_GPIO_JACKET_DETECT,      "jacket detect",        0, 0 },
+ };
+ #ifdef CONFIG_PM
+@@ -395,19 +395,27 @@ static int __devinit tosa_bat_probe(struct platform_device *dev)
+               goto err_psy_reg_bu;
+       ret = request_irq(gpio_to_irq(TOSA_GPIO_BAT0_CRG),
+-                              tosa_bat_full_isr, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
++                              tosa_bat_gpio_isr, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
+                               "main full", &tosa_bat_main);
+       if (ret)
+               goto err_req_main;
+       ret = request_irq(gpio_to_irq(TOSA_GPIO_BAT1_CRG),
+-                              tosa_bat_full_isr, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
++                              tosa_bat_gpio_isr, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
+                               "jacket full", &tosa_bat_jacket);
++      if (ret)
++              goto err_req_jacket;
++
++      ret = request_irq(gpio_to_irq(TOSA_GPIO_JACKET_DETECT),
++                              tosa_bat_gpio_isr, IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
++                              "jacket detect", &tosa_bat_jacket);
+       if (!ret) {
+               schedule_work(&bat_work);
+               return 0;
+       }
++      free_irq(gpio_to_irq(TOSA_GPIO_BAT1_CRG), &tosa_bat_jacket);
++err_req_jacket:
+       free_irq(gpio_to_irq(TOSA_GPIO_BAT0_CRG), &tosa_bat_main);
+ err_req_main:
+       power_supply_unregister(&tosa_bat_bu.psy);
+@@ -429,6 +437,7 @@ static int __devexit tosa_bat_remove(struct platform_device *dev)
+ {
+       int i;
++      free_irq(gpio_to_irq(TOSA_GPIO_JACKET_DETECT), &tosa_bat_jacket);
+       free_irq(gpio_to_irq(TOSA_GPIO_BAT1_CRG), &tosa_bat_jacket);
+       free_irq(gpio_to_irq(TOSA_GPIO_BAT0_CRG), &tosa_bat_main);
+-- 
+1.5.3.8
+
diff --git a/packages/kexecboot/linux-kexecboot-2.6.24/tosa/0064-Export-modes-via-sysfs.patch b/packages/kexecboot/linux-kexecboot-2.6.24/tosa/0064-Export-modes-via-sysfs.patch
new file mode 100644 (file)
index 0000000..eeb92cf
--- /dev/null
@@ -0,0 +1,27 @@
+From feeee5d22c00d9d1e2e06eb5610740be238749b9 Mon Sep 17 00:00:00 2001
+From: Dmitry Baryshkov <dbaryshkov@gmail.com>
+Date: Thu, 7 Feb 2008 22:27:38 +0300
+Subject: [PATCH 64/64] Export modes via sysfs
+
+Signed-off-by: Dmitry Baryshkov <dbaryshkov@gmail.com>
+---
+ drivers/video/tmiofb.c |    3 +++
+ 1 files changed, 3 insertions(+), 0 deletions(-)
+
+diff --git a/drivers/video/tmiofb.c b/drivers/video/tmiofb.c
+index 6b963a1..9389a77 100644
+--- a/drivers/video/tmiofb.c
++++ b/drivers/video/tmiofb.c
+@@ -800,6 +800,9 @@ static int tmiofb_probe(struct platform_device *dev)
+       if (retval)
+               goto err_set_par;*/
++      fb_videomode_to_modelist(data->modes, data->num_modes,
++                               &info->modelist);
++
+       retval = register_framebuffer(info);
+       if (retval < 0)
+               goto err_register_framebuffer;
+-- 
+1.5.3.8
+
diff --git a/packages/kexecboot/linux-kexecboot-2.6.24/tosa/0065-wm97xx-core-fixes.patch b/packages/kexecboot/linux-kexecboot-2.6.24/tosa/0065-wm97xx-core-fixes.patch
new file mode 100644 (file)
index 0000000..5db0cc6
--- /dev/null
@@ -0,0 +1,49 @@
+From 2544412fc47dc13f4f3935cb4c2fd500d217e905 Mon Sep 17 00:00:00 2001
+From: Dmitry Baryshkov <dbaryshkov@gmail.com>
+Date: Wed, 13 Feb 2008 02:00:15 +0300
+Subject: [PATCH] wm97xx-core fixes
+
+Signed-off-by: Dmitry Baryshkov <dbaryshkov@gmail.com>
+---
+ drivers/input/touchscreen/wm97xx-core.c |    8 ++++----
+ include/linux/wm97xx.h                  |    1 -
+ 2 files changed, 4 insertions(+), 5 deletions(-)
+
+diff --git a/drivers/input/touchscreen/wm97xx-core.c b/drivers/input/touchscreen/wm97xx-core.c
+index 840d9ff..4cbb9e5 100644
+--- a/drivers/input/touchscreen/wm97xx-core.c
++++ b/drivers/input/touchscreen/wm97xx-core.c
+@@ -596,7 +596,7 @@ static int wm97xx_probe(struct device *dev)
+       }
+       platform_set_drvdata(wm->battery_dev, wm);
+       wm->battery_dev->dev.parent = dev;
+-      ret = platform_device_register(wm->battery_dev);
++      ret = platform_device_add(wm->battery_dev);
+       if (ret < 0)
+               goto batt_reg_err;
+@@ -609,7 +609,7 @@ static int wm97xx_probe(struct device *dev)
+       }
+       platform_set_drvdata(wm->touch_dev, wm);
+       wm->touch_dev->dev.parent = dev;
+-      ret = platform_device_register(wm->touch_dev);
++      ret = platform_device_add(wm->touch_dev);
+       if (ret < 0)
+               goto touch_reg_err;
+@@ -619,10 +619,12 @@ static int wm97xx_probe(struct device *dev)
+       platform_device_put(wm->touch_dev);
+  touch_err:
+       platform_device_unregister(wm->battery_dev);
++      wm->battery_dev = NULL;
+  batt_reg_err:
+       platform_device_put(wm->battery_dev);
+  batt_err:
+       input_unregister_device(wm->input_dev);
++      wm->input_dev = NULL;
+       kfree(wm);
+       return ret;
+ }
+-- 
+1.5.4.1
+
diff --git a/packages/kexecboot/linux-kexecboot-2.6.24/tosa/0066-tmiofb_probe-should-be-__devinit.patch b/packages/kexecboot/linux-kexecboot-2.6.24/tosa/0066-tmiofb_probe-should-be-__devinit.patch
new file mode 100644 (file)
index 0000000..42320be
--- /dev/null
@@ -0,0 +1,26 @@
+From b6a63ad546cc26519a342f3fdd7b1def49ca33ee Mon Sep 17 00:00:00 2001
+From: Dmitry Baryshkov <dbaryshkov@gmail.com>
+Date: Wed, 13 Feb 2008 02:00:14 +0300
+Subject: [PATCH] tmiofb_probe should be __devinit
+
+Signed-off-by: Dmitry Baryshkov <dbaryshkov@gmail.com>
+---
+ drivers/video/tmiofb.c |    2 +-
+ 1 files changed, 1 insertions(+), 1 deletions(-)
+
+diff --git a/drivers/video/tmiofb.c b/drivers/video/tmiofb.c
+index 9389a77..958ee8a 100644
+--- a/drivers/video/tmiofb.c
++++ b/drivers/video/tmiofb.c
+@@ -704,7 +704,7 @@ static irqreturn_t tmiofb_irq(int irq, void *__info)
+       return IRQ_HANDLED;
+ }
+-static int tmiofb_probe(struct platform_device *dev)
++static int __devinit tmiofb_probe(struct platform_device *dev)
+ {
+       struct mfd_cell                 *cell   = mfd_get_cell(dev);
+       struct tmio_fb_data             *data   = cell->driver_data;
+-- 
+1.5.4.1
+
diff --git a/packages/kexecboot/linux-kexecboot-2.6.24/tosa/0067-modeswitching.patch b/packages/kexecboot/linux-kexecboot-2.6.24/tosa/0067-modeswitching.patch
new file mode 100644 (file)
index 0000000..42b69d9
--- /dev/null
@@ -0,0 +1,225 @@
+From aded2e51a7a2113dae6431c858df1d95fb312851 Mon Sep 17 00:00:00 2001
+From: Dmitry Baryshkov <dbaryshkov@gmail.com>
+Date: Wed, 13 Feb 2008 19:34:08 +0300
+Subject: [PATCH] modeswitching
+
+Signed-off-by: Dmitry Baryshkov <dbaryshkov@gmail.com>
+---
+ arch/arm/mach-pxa/tosa.c          |   33 +++++++++++++++++++++++++++++++-
+ drivers/mfd/tc6393xb.c            |    2 +-
+ drivers/video/backlight/tosa_bl.c |   38 +++++++++++++++++++++++++++++++++---
+ drivers/video/tmiofb.c            |    8 +++---
+ include/asm-arm/arch-pxa/tosa.h   |    2 +
+ include/linux/mfd/tc6393xb.h      |    2 +-
+ include/linux/mfd/tmio.h          |    2 +-
+ 7 files changed, 75 insertions(+), 12 deletions(-)
+
+diff --git a/arch/arm/mach-pxa/tosa.c b/arch/arm/mach-pxa/tosa.c
+index 94c9915..6631de2 100644
+--- a/arch/arm/mach-pxa/tosa.c
++++ b/arch/arm/mach-pxa/tosa.c
+@@ -455,9 +455,40 @@ static struct fb_videomode tosa_tc6393xb_lcd_mode[] = {
+       }
+ };
++static DEFINE_SPINLOCK(tosa_lcd_mode_lock);
++
++static const struct fb_videomode *tosa_lcd_mode = &tosa_tc6393xb_lcd_mode[0];
++
++static int tosa_lcd_set_mode(struct platform_device *fb_dev,
++                                      const struct fb_videomode *mode)
++{
++      int rc;
++      unsigned long flags;
++
++      spin_lock_irqsave(&tosa_lcd_mode_lock, flags);
++      rc = tc6393xb_lcd_mode(fb_dev, mode);
++      if (!rc)
++              tosa_lcd_mode = mode;
++      spin_unlock_irqrestore(&tosa_lcd_mode_lock, flags);
++
++      return rc;
++}
++
++const struct fb_videomode *tosa_lcd_get_mode(void)
++{
++      unsigned long flags;
++      const struct fb_videomode *mode;
++
++      spin_lock_irqsave(&tosa_lcd_mode_lock, flags);
++      mode = tosa_lcd_mode;
++      spin_unlock_irqrestore(&tosa_lcd_mode_lock, flags);
++
++      return mode;
++}
++
+ static struct tmio_fb_data tosa_tc6393xb_fb_config = {
+       .lcd_set_power  = tc6393xb_lcd_set_power,
+-      .lcd_mode       = tc6393xb_lcd_mode,
++      .lcd_mode       = tosa_lcd_set_mode,
+       .num_modes      = ARRAY_SIZE(tosa_tc6393xb_lcd_mode),
+       .modes          = &tosa_tc6393xb_lcd_mode[0],
+ };
+diff --git a/drivers/mfd/tc6393xb.c b/drivers/mfd/tc6393xb.c
+index 9001687..21190f3 100644
+--- a/drivers/mfd/tc6393xb.c
++++ b/drivers/mfd/tc6393xb.c
+@@ -196,7 +196,7 @@ int tc6393xb_lcd_set_power(struct platform_device *fb, bool on)
+ EXPORT_SYMBOL(tc6393xb_lcd_set_power);
+ int tc6393xb_lcd_mode(struct platform_device *fb_dev,
+-                                      struct fb_videomode *mode) {
++                                      const struct fb_videomode *mode) {
+       struct tc6393xb                 *tc6393xb =
+               platform_get_drvdata(to_platform_device(fb_dev->dev.parent));
+       struct tc6393xb_scr __iomem     *scr    = tc6393xb->scr;
+diff --git a/drivers/video/backlight/tosa_bl.c b/drivers/video/backlight/tosa_bl.c
+index 9ef0bfb..45fc6ae 100644
+--- a/drivers/video/backlight/tosa_bl.c
++++ b/drivers/video/backlight/tosa_bl.c
+@@ -48,6 +48,9 @@ struct tosa_bl_data {
+       struct ssp_dev          nssp_dev;
+       struct ssp_state        nssp_state;
++      /* listen for mode changes */
++      struct notifier_block   fb_notif;
++
+       struct backlight_device *bl_dev;
+ };
+@@ -103,14 +106,19 @@ static void tosa_lcd_tg_init(struct tosa_bl_data *data)
+       pxa_nssp_output(data, TG_GPOSR,0x02);           /* GPOS0=powercontrol, GPOS1=GPIO, GPOS2=TCTL */
+ }
+-static void tosa_lcd_tg_on(struct tosa_bl_data *data/*, const struct fb_videomode *mode*/)
++static void tosa_lcd_tg_on(struct tosa_bl_data *data)
+ {
+-      const int value = TG_REG0_COLOR | TG_REG0_UD | TG_REG0_LR;
++      const struct fb_videomode *mode = tosa_lcd_get_mode();
++
++      int value = TG_REG0_COLOR | TG_REG0_UD | TG_REG0_LR;
++
++      if (mode->yres == 640)
++              value |= TG_REG0_VQV;
+       tosa_lcd_tg_init(data);
+-      dev_dbg(&data->bl_dev->dev, "tosa_lcd_on\n");
+-      pxa_nssp_output(data, TG_PNLCTL, value | (/*mode->yres == 320 ? 0 : */ TG_REG0_VQV));
++      dev_dbg(&data->bl_dev->dev, "tosa_lcd_on: %04x (%d)\n", value, mode->yres);
++      pxa_nssp_output(data, TG_PNLCTL, value);
+       /* TG LCD pannel power up */
+       pxa_nssp_output(data, TG_PINICTL,0x4);
+@@ -173,6 +181,20 @@ static struct backlight_ops tosa_bl_ops = {
+       .update_status          = tosa_bl_update_status,
+ };
++static int fb_notifier_callback(struct notifier_block *self,
++                              unsigned long event, void *_data)
++{
++      struct tosa_bl_data *bl_data =
++              container_of(self, struct tosa_bl_data, fb_notif);
++
++      if (event != FB_EVENT_MODE_CHANGE && event != FB_EVENT_MODE_CHANGE_ALL)
++              return 0;
++
++      tosa_bl_update_status(bl_data->bl_dev);
++
++      return 0;
++}
++
+ static int tosa_bl_detect_client(struct i2c_adapter *adapter, int address,
+                         int kind)
+ {
+@@ -238,9 +260,15 @@ static int tosa_bl_detect_client(struct i2c_adapter *adapter, int address,
+       data->bl_dev->props.power = FB_BLANK_UNBLANK;
+       backlight_update_status(data->bl_dev);
++      data->fb_notif.notifier_call = fb_notifier_callback;
++      err = fb_register_client(&data->fb_notif);
++      if (err)
++              goto err_fb_register;
+       return 0;
++err_fb_register:
++      backlight_device_unregister(data->bl_dev);
+ err_bl_register:
+       tosa_set_backlight(data, 0);
+       tosa_lcd_tg_off(data);
+@@ -265,6 +293,8 @@ static int tosa_bl_detach_client(struct i2c_client *client)
+       int err = 0;
+       struct tosa_bl_data *data = i2c_get_clientdata(client);
++      fb_unregister_client(&data->fb_notif);
++
+       backlight_device_unregister(data->bl_dev);
+       tosa_set_backlight(data, 0);
+diff --git a/drivers/video/tmiofb.c b/drivers/video/tmiofb.c
+index 958ee8a..cc75df9 100644
+--- a/drivers/video/tmiofb.c
++++ b/drivers/video/tmiofb.c
+@@ -618,17 +618,17 @@ static int tmiofb_check_var(struct fb_var_screeninfo *var, struct fb_info *info)
+ static int tmiofb_set_par(struct fb_info *info)
+ {
+-/*    struct fb_var_screeninfo        *var    = &info->var;
++      struct fb_var_screeninfo        *var    = &info->var;
+       struct fb_videomode             *mode;
+       mode = tmiofb_find_mode(info, var);
+       if (!mode)
+               return -EINVAL;
+-      if (info->mode == mode)
+-              return 0;
++/*    if (info->mode == mode)
++              return 0;*/
+-      info->mode              = mode; */
++      info->mode              = mode;
+       info->fix.line_length   = info->mode->xres * 2;
+       tmiofb_hw_mode(to_platform_device(info->device));
+diff --git a/include/asm-arm/arch-pxa/tosa.h b/include/asm-arm/arch-pxa/tosa.h
+index 410fa9a..624c636 100644
+--- a/include/asm-arm/arch-pxa/tosa.h
++++ b/include/asm-arm/arch-pxa/tosa.h
+@@ -230,4 +230,6 @@ extern struct platform_device tosascoop_device;
+ #define TOSA_KEY_MAIL         KEY_MAIL
+ #endif
++const struct fb_videomode *tosa_lcd_get_mode(void);
++
+ #endif /* _ASM_ARCH_TOSA_H_ */
+diff --git a/include/linux/mfd/tc6393xb.h b/include/linux/mfd/tc6393xb.h
+index 97c4c7c..8ab9e91 100644
+--- a/include/linux/mfd/tc6393xb.h
++++ b/include/linux/mfd/tc6393xb.h
+@@ -53,7 +53,7 @@ struct tc6393xb_platform_data {
+ extern int tc6393xb_lcd_set_power(struct platform_device *fb_dev, bool on);
+ extern int tc6393xb_lcd_mode(struct platform_device *fb_dev,
+-                                      struct fb_videomode *mode);
++                                      const struct fb_videomode *mode);
+ /*
+  * Relative to irq_base
+diff --git a/include/linux/mfd/tmio.h b/include/linux/mfd/tmio.h
+index b6d4aac..fe7ff2d 100644
+--- a/include/linux/mfd/tmio.h
++++ b/include/linux/mfd/tmio.h
+@@ -19,7 +19,7 @@ struct tmio_fb_data {
+       int                     (*lcd_set_power)(struct platform_device *fb_dev,
+                                                               bool on);
+       int                     (*lcd_mode)(struct platform_device *fb_dev,
+-                                              struct fb_videomode *mode);
++                                      const struct fb_videomode *mode);
+       int                     num_modes;
+       struct fb_videomode     *modes;
+ };
+-- 
+1.5.4.1
+
diff --git a/packages/kexecboot/linux-kexecboot-2.6.24/tosa/0068-Preliminary-tosa-denoiser.patch b/packages/kexecboot/linux-kexecboot-2.6.24/tosa/0068-Preliminary-tosa-denoiser.patch
new file mode 100644 (file)
index 0000000..e90e375
--- /dev/null
@@ -0,0 +1,239 @@
+From f7dad1cd9c1bd3fce5d228e0b644a51baea50cd9 Mon Sep 17 00:00:00 2001
+From: Dmitry Baryshkov <dbaryshkov@gmail.com>
+Date: Fri, 15 Feb 2008 15:35:07 +0300
+Subject: [PATCH] Preliminary tosa denoiser
+
+Signed-off-by: Dmitry Baryshkov <dbaryshkov@gmail.com>
+---
+ drivers/input/touchscreen/Kconfig       |   12 ++
+ drivers/input/touchscreen/Makefile      |    1 +
+ drivers/input/touchscreen/tosa-wm97xx.c |  182 +++++++++++++++++++++++++++++++
+ 3 files changed, 195 insertions(+), 0 deletions(-)
+ create mode 100644 drivers/input/touchscreen/tosa-wm97xx.c
+
+diff --git a/drivers/input/touchscreen/Kconfig b/drivers/input/touchscreen/Kconfig
+index 0be05a2..938aed2 100644
+--- a/drivers/input/touchscreen/Kconfig
++++ b/drivers/input/touchscreen/Kconfig
+@@ -210,6 +210,18 @@ config TOUCHSCREEN_WM97XX_MAINSTONE
+         To compile this driver as a module, choose M here: the
+         module will be called mainstone-wm97xx
++config TOUCHSCREEN_WM97XX_TOSA
++      tristate "WM97xx Tosa denoiser"
++      depends on TOUCHSCREEN_WM97XX && MACH_TOSA
++      help
++        Say Y here for support for touchscreen denoising on
++        Sharl Zaurus SL-6000 (tosa) system.
++
++        If unsure, say N
++
++        To compile this driver as a module, choose M here: the
++        module will be called tosa-wm97xx
++
+ config TOUCHSCREEN_TOUCHWIN
+       tristate "Touchwin serial touchscreen"
+       select SERIO
+diff --git a/drivers/input/touchscreen/Makefile b/drivers/input/touchscreen/Makefile
+index d38156e..d86278b 100644
+--- a/drivers/input/touchscreen/Makefile
++++ b/drivers/input/touchscreen/Makefile
+@@ -23,6 +23,7 @@ obj-$(CONFIG_TOUCHSCREEN_TOUCHWIN)   += touchwin.o
+ obj-$(CONFIG_TOUCHSCREEN_UCB1400)     += ucb1400_ts.o
+ obj-$(CONFIG_TOUCHSCREEN_WM97XX)      += wm97xx-ts.o
+ obj-$(CONFIG_TOUCHSCREEN_WM97XX_MAINSTONE)    += mainstone-wm97xx.o
++obj-$(CONFIG_TOUCHSCREEN_WM97XX_TOSA) += tosa-wm97xx.o
+ wm97xx-ts-$(CONFIG_TOUCHSCREEN_WM9705)  += wm9705.o
+ wm97xx-ts-$(CONFIG_TOUCHSCREEN_WM9712)  += wm9712.o
+ wm97xx-ts-$(CONFIG_TOUCHSCREEN_WM9713)  += wm9713.o
+diff --git a/drivers/input/touchscreen/tosa-wm97xx.c b/drivers/input/touchscreen/tosa-wm97xx.c
+new file mode 100644
+index 0000000..8fd542b
+--- /dev/null
++++ b/drivers/input/touchscreen/tosa-wm97xx.c
+@@ -0,0 +1,182 @@
++/*
++ * tosa_ts.c  --  Touchscreen driver for Sharp SL-6000 (Tosa).
++ *
++ * Copyright 2008 Dmitry Baryshkov
++ * Copyright 2006 Wolfson Microelectronics PLC.
++ * Author: Mike Arthur
++ *         linux@wolfsonmicro.com
++ *
++ *  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.
++ *
++ *  Revision history
++ *     1st Sep 2006  Initial version.
++ *
++ */
++
++#include <linux/kernel.h>
++#include <linux/module.h>
++#include <linux/platform_device.h>
++#include <linux/wm97xx.h>
++#include <linux/fb.h>
++
++#include <asm/arch/tosa.h>
++#include <asm/gpio.h>
++
++static unsigned long hsync_time = 0;
++
++static void calc_hsync_time(const struct fb_videomode *mode)
++{
++      /* The 25 and 44 'magic numbers' are from Sharp's 2.4 patches */
++      if (mode->yres == 640) {
++              hsync_time = 25;
++      } else if (mode->yres == 320) {
++              hsync_time = 44;
++      } else {
++              printk(KERN_ERR "unknown video mode res specified: %dx%d!", mode->xres, mode->yres);
++              WARN_ON(1);
++      }
++
++      printk(KERN_ERR "tosa-wm97xx: using %lu hsync time\n", hsync_time);
++}
++
++static int fb_notifier_callback(struct notifier_block *self,
++                              unsigned long event, void *_data)
++{
++      if (event != FB_EVENT_MODE_CHANGE && event != FB_EVENT_MODE_CHANGE_ALL)
++              return 0;
++
++      calc_hsync_time(tosa_lcd_get_mode());
++
++      return 0;
++}
++
++static void tosa_lcd_wait_hsync(void)
++{
++      /* Waits for a rising edge on the VGA line */
++      while (gpio_get_value(TOSA_GPIO_VGA_LINE) == 0);
++      while (gpio_get_value(TOSA_GPIO_VGA_LINE) != 0);
++}
++
++/* Taken from the Sharp 2.4 kernel code */
++#define CCNT(a)     asm volatile ("mrc p14, 0, %0, C1, C1, 0" : "=r"(a))
++#define CCNT_ON()   asm("mcr p14, 0, %0, C0, C0, 0" : : "r"(1))
++#define CCNT_OFF()  asm("mcr p14, 0, %0, C0, C0, 0" : : "r"(0))
++
++/* On the Sharp SL-6000 (Tosa), due to a noisy LCD, we need to perform a wait
++ * before sampling the Y axis of the touchscreen */
++static void tosa_lcd_sync_on(int adcsel)
++{
++      unsigned long timer1 = 0, timer2 = 0, wait_time = 0;
++      if (adcsel & WM97XX_ADCSEL_Y) {
++              CCNT_ON();
++              wait_time = hsync_time;
++
++              if (wait_time) {
++
++                      /* wait for LCD rising edge */
++                      tosa_lcd_wait_hsync();
++                      /* get clock */
++                      CCNT(timer1);
++                      CCNT(timer2);
++
++                      while ((timer2 - timer1) < wait_time) {
++                              CCNT(timer2);
++                      }
++              }
++      }
++}
++
++static void tosa_lcd_sync_off(int adcsel)
++{
++      if (adcsel & WM97XX_ADCSEL_Y)
++              CCNT_OFF();
++}
++
++static struct wm97xx_mach_ops tosa_mach_ops = {
++      .pre_sample =  tosa_lcd_sync_on,
++      .post_sample = tosa_lcd_sync_off,
++};
++
++static int __devinit tosa_ts_probe(struct platform_device *dev) {
++      struct wm97xx *wm = platform_get_drvdata(dev);
++      struct notifier_block *notif;
++      int err = -ENOMEM;
++
++      notif = kzalloc(sizeof(struct notifier_block), GFP_KERNEL);
++      if (!notif)
++              goto err_alloc;
++
++      notif->notifier_call = fb_notifier_callback;
++
++      err = gpio_request(TOSA_GPIO_VGA_LINE, "hsync");
++      if (err)
++              goto err_gpio;
++
++      err = gpio_direction_input(TOSA_GPIO_VGA_LINE);
++      if (err)
++              goto err_gpio;
++
++      platform_set_drvdata(dev, notif);
++
++      err = fb_register_client(notif);
++      if (err)
++              goto err_register;
++
++      err = wm97xx_register_mach_ops(wm, &tosa_mach_ops);
++      if (err)
++              goto err_wm97xx;
++
++      calc_hsync_time(tosa_lcd_get_mode());
++
++      return 0;
++
++err_wm97xx:
++      fb_unregister_client(notif);
++err_register:
++      gpio_free(TOSA_GPIO_VGA_LINE);
++err_gpio:
++      kfree(notif);
++err_alloc:
++      return err;
++}
++
++
++static int __devexit tosa_ts_remove(struct platform_device *dev) {
++      struct wm97xx *wm = platform_get_drvdata(dev);
++
++      wm97xx_unregister_mach_ops(wm);
++
++      fb_unregister_client(platform_get_drvdata(dev));
++      gpio_free(TOSA_GPIO_VGA_LINE);
++      kfree(platform_get_drvdata(dev));
++
++      return 0;
++}
++
++static struct platform_driver tosa_ts_driver = {
++      .driver.name = "wm97xx-touch",
++      .driver.owner = THIS_MODULE,
++      .probe = tosa_ts_probe,
++      .remove = __devexit_p(tosa_ts_remove),
++};
++
++static int __init tosa_ts_init(void)
++{
++      return platform_driver_register(&tosa_ts_driver);
++}
++
++static void __exit tosa_ts_exit(void)
++{
++      platform_driver_unregister(&tosa_ts_driver);
++}
++
++module_init(tosa_ts_init);
++module_exit(tosa_ts_exit);
++
++/* Module information */
++MODULE_AUTHOR("Dmitry Baryshkov, Mike Arthur, mike@mikearthur.co.uk, www.wolfsonmicro.com");
++MODULE_DESCRIPTION("Sharp SL6000 Tosa Touch Screen Denoiser");
++MODULE_LICENSE("GPL");
+-- 
+1.5.4.1
+
index 379b8bc..9513c41 100644 (file)
@@ -1,7 +1,7 @@
 #
 # Automatically generated make config: don't edit
 # Linux kernel version: 2.6.24
-# Wed Jun  4 12:21:16 2008
+# Mon Dec  8 00:58:55 2008
 #
 CONFIG_ARM=y
 CONFIG_SYS_SUPPORTS_APM_EMULATION=y
@@ -35,9 +35,8 @@ CONFIG_LOCK_KERNEL=y
 CONFIG_INIT_ENV_ARG_LIMIT=32
 CONFIG_LOCALVERSION=""
 CONFIG_LOCALVERSION_AUTO=y
-CONFIG_SWAP=y
-CONFIG_SYSVIPC=y
-CONFIG_SYSVIPC_SYSCTL=y
+# CONFIG_SWAP is not set
+# CONFIG_SYSVIPC is not set
 # CONFIG_POSIX_MQUEUE is not set
 # CONFIG_BSD_PROCESS_ACCT is not set
 # CONFIG_TASKSTATS is not set
@@ -52,15 +51,17 @@ CONFIG_FAIR_USER_SCHED=y
 # CONFIG_FAIR_CGROUP_SCHED is not set
 # CONFIG_SYSFS_DEPRECATED is not set
 # CONFIG_RELAY is not set
-# CONFIG_BLK_DEV_INITRD is not set
+CONFIG_BLK_DEV_INITRD=y
+CONFIG_INITRAMFS_SOURCE="initramfs.cpio.gz"
+CONFIG_INITRAMFS_ROOT_UID=0
+CONFIG_INITRAMFS_ROOT_GID=0
 CONFIG_CC_OPTIMIZE_FOR_SIZE=y
 CONFIG_SYSCTL=y
 CONFIG_HAVE_CLOCK_LIB=y
 CONFIG_EMBEDDED=y
-CONFIG_UID16=y
-CONFIG_SYSCTL_SYSCALL=y
-CONFIG_KALLSYMS=y
-# CONFIG_KALLSYMS_EXTRA_PASS is not set
+# CONFIG_UID16 is not set
+# CONFIG_SYSCTL_SYSCALL is not set
+# CONFIG_KALLSYMS is not set
 CONFIG_HOTPLUG=y
 CONFIG_PRINTK=y
 CONFIG_BUG=y
@@ -72,7 +73,7 @@ CONFIG_EPOLL=y
 CONFIG_SIGNALFD=y
 CONFIG_EVENTFD=y
 CONFIG_SHMEM=y
-CONFIG_VM_EVENT_COUNTERS=y
+# CONFIG_VM_EVENT_COUNTERS is not set
 CONFIG_SLAB=y
 # CONFIG_SLUB is not set
 # CONFIG_SLOB is not set
@@ -80,12 +81,7 @@ CONFIG_SLABINFO=y
 CONFIG_RT_MUTEXES=y
 # CONFIG_TINY_SHMEM is not set
 CONFIG_BASE_SMALL=0
-CONFIG_MODULES=y
-CONFIG_MODULE_UNLOAD=y
-CONFIG_MODULE_FORCE_UNLOAD=y
-# CONFIG_MODVERSIONS is not set
-# CONFIG_MODULE_SRCVERSION_ALL is not set
-CONFIG_KMOD=y
+# CONFIG_MODULES is not set
 CONFIG_BLOCK=y
 # CONFIG_LBD is not set
 # CONFIG_BLK_DEV_IO_TRACE is not set
@@ -96,9 +92,9 @@ CONFIG_BLOCK=y
 # IO Schedulers
 #
 CONFIG_IOSCHED_NOOP=y
-CONFIG_IOSCHED_AS=m
-CONFIG_IOSCHED_DEADLINE=m
-CONFIG_IOSCHED_CFQ=m
+# CONFIG_IOSCHED_AS is not set
+# CONFIG_IOSCHED_DEADLINE is not set
+# CONFIG_IOSCHED_CFQ is not set
 # CONFIG_DEFAULT_AS is not set
 # CONFIG_DEFAULT_DEADLINE is not set
 # CONFIG_DEFAULT_CFQ is not set
@@ -141,7 +137,6 @@ CONFIG_ARCH_PXA=y
 # CONFIG_ARCH_LH7A40X is not set
 # CONFIG_ARCH_DAVINCI is not set
 # CONFIG_ARCH_OMAP is not set
-CONFIG_DMABOUNCE=y
 
 #
 # Intel PXA2xx/PXA3xx Implementations
@@ -158,6 +153,7 @@ CONFIG_PXA_SHARPSL=y
 # CONFIG_MACH_ARMCORE is not set
 CONFIG_PXA_SHARPSL_25x=y
 # CONFIG_PXA_SHARPSL_27x is not set
+# CONFIG_MACH_HTCUNIVERSAL is not set
 # CONFIG_MACH_POODLE is not set
 # CONFIG_MACH_CORGI is not set
 # CONFIG_MACH_SHEPHERD is not set
@@ -246,29 +242,15 @@ CONFIG_ALIGNMENT_TRAP=y
 #
 CONFIG_ZBOOT_ROM_TEXT=0x0
 CONFIG_ZBOOT_ROM_BSS=0x0
-CONFIG_CMDLINE="console=ttyS0,115200n8 console=tty1 noinitrd root=/dev/mtdblock2 rootfstype=jffs2   dyntick=enable debug"
+CONFIG_CMDLINE="console=ttyS0,115200n8 console=tty1 debug "
 # CONFIG_XIP_KERNEL is not set
 CONFIG_KEXEC=y
 CONFIG_ATAGS_PROC=y
-CONFIG_CPU_FREQ_PXA25x=y
 
 #
 # CPU Frequency scaling
 #
-CONFIG_CPU_FREQ=y
-CONFIG_CPU_FREQ_TABLE=y
-# CONFIG_CPU_FREQ_DEBUG is not set
-CONFIG_CPU_FREQ_STAT=m
-# CONFIG_CPU_FREQ_STAT_DETAILS is not set
-CONFIG_CPU_FREQ_DEFAULT_GOV_PERFORMANCE=y
-# CONFIG_CPU_FREQ_DEFAULT_GOV_USERSPACE is not set
-# CONFIG_CPU_FREQ_DEFAULT_GOV_ONDEMAND is not set
-# CONFIG_CPU_FREQ_DEFAULT_GOV_CONSERVATIVE is not set
-CONFIG_CPU_FREQ_GOV_PERFORMANCE=y
-CONFIG_CPU_FREQ_GOV_POWERSAVE=m
-CONFIG_CPU_FREQ_GOV_USERSPACE=m
-CONFIG_CPU_FREQ_GOV_ONDEMAND=m
-CONFIG_CPU_FREQ_GOV_CONSERVATIVE=m
+# CONFIG_CPU_FREQ is not set
 
 #
 # Floating point emulation
@@ -282,8 +264,8 @@ CONFIG_CPU_FREQ_GOV_CONSERVATIVE=m
 # Userspace binary formats
 #
 CONFIG_BINFMT_ELF=y
-CONFIG_BINFMT_AOUT=m
-CONFIG_BINFMT_MISC=m
+# CONFIG_BINFMT_AOUT is not set
+# CONFIG_BINFMT_MISC is not set
 
 #
 # Power management options
@@ -304,15 +286,9 @@ CONFIG_NET=y
 #
 # Networking options
 #
-CONFIG_PACKET=m
-CONFIG_PACKET_MMAP=y
+# CONFIG_PACKET is not set
 CONFIG_UNIX=y
-CONFIG_XFRM=y
-CONFIG_XFRM_USER=m
-# CONFIG_XFRM_SUB_POLICY is not set
-# CONFIG_XFRM_MIGRATE is not set
-CONFIG_NET_KEY=m
-# CONFIG_NET_KEY_MIGRATE is not set
+# CONFIG_NET_KEY is not set
 CONFIG_INET=y
 # CONFIG_IP_MULTICAST is not set
 # CONFIG_IP_ADVANCED_ROUTER is not set
@@ -326,35 +302,20 @@ CONFIG_SYN_COOKIES=y
 # CONFIG_INET_ESP is not set
 # CONFIG_INET_IPCOMP is not set
 # CONFIG_INET_XFRM_TUNNEL is not set
-CONFIG_INET_TUNNEL=m
-CONFIG_INET_XFRM_MODE_TRANSPORT=m
-CONFIG_INET_XFRM_MODE_TUNNEL=m
-CONFIG_INET_XFRM_MODE_BEET=m
+# CONFIG_INET_TUNNEL is not set
+# CONFIG_INET_XFRM_MODE_TRANSPORT is not set
+# CONFIG_INET_XFRM_MODE_TUNNEL is not set
+# CONFIG_INET_XFRM_MODE_BEET is not set
 # CONFIG_INET_LRO is not set
-CONFIG_INET_DIAG=m
-CONFIG_INET_TCP_DIAG=m
+# CONFIG_INET_DIAG is not set
 # CONFIG_TCP_CONG_ADVANCED is not set
 CONFIG_TCP_CONG_CUBIC=y
 CONFIG_DEFAULT_TCP_CONG="cubic"
 # CONFIG_TCP_MD5SIG is not set
 # CONFIG_IP_VS is not set
-CONFIG_IPV6=m
-# CONFIG_IPV6_PRIVACY is not set
-# CONFIG_IPV6_ROUTER_PREF is not set
-# CONFIG_IPV6_OPTIMISTIC_DAD is not set
-CONFIG_INET6_AH=m
-CONFIG_INET6_ESP=m
-CONFIG_INET6_IPCOMP=m
-# CONFIG_IPV6_MIP6 is not set
-CONFIG_INET6_XFRM_TUNNEL=m
-CONFIG_INET6_TUNNEL=m
-CONFIG_INET6_XFRM_MODE_TRANSPORT=m
-CONFIG_INET6_XFRM_MODE_TUNNEL=m
-CONFIG_INET6_XFRM_MODE_BEET=m
-# CONFIG_INET6_XFRM_MODE_ROUTEOPTIMIZATION is not set
-CONFIG_IPV6_SIT=m
-CONFIG_IPV6_TUNNEL=m
-# CONFIG_IPV6_MULTIPLE_TABLES is not set
+# CONFIG_IPV6 is not set
+# CONFIG_INET6_XFRM_TUNNEL is not set
+# CONFIG_INET6_TUNNEL is not set
 # CONFIG_NETWORK_SECMARK is not set
 CONFIG_NETFILTER=y
 # CONFIG_NETFILTER_DEBUG is not set
@@ -365,66 +326,14 @@ CONFIG_NETFILTER=y
 # CONFIG_NETFILTER_NETLINK is not set
 # CONFIG_NF_CONNTRACK_ENABLED is not set
 # CONFIG_NF_CONNTRACK is not set
-CONFIG_NETFILTER_XTABLES=m
-# CONFIG_NETFILTER_XT_TARGET_CLASSIFY is not set
-# CONFIG_NETFILTER_XT_TARGET_DSCP is not set
-# CONFIG_NETFILTER_XT_TARGET_MARK is not set
-# CONFIG_NETFILTER_XT_TARGET_NFQUEUE is not set
-# CONFIG_NETFILTER_XT_TARGET_NFLOG is not set
-# CONFIG_NETFILTER_XT_TARGET_TRACE is not set
-# CONFIG_NETFILTER_XT_TARGET_TCPMSS is not set
-# CONFIG_NETFILTER_XT_MATCH_COMMENT is not set
-# CONFIG_NETFILTER_XT_MATCH_DCCP is not set
-# CONFIG_NETFILTER_XT_MATCH_DSCP is not set
-# CONFIG_NETFILTER_XT_MATCH_ESP is not set
-# CONFIG_NETFILTER_XT_MATCH_LENGTH is not set
-# CONFIG_NETFILTER_XT_MATCH_LIMIT is not set
-# CONFIG_NETFILTER_XT_MATCH_MAC is not set
-# CONFIG_NETFILTER_XT_MATCH_MARK is not set
-# CONFIG_NETFILTER_XT_MATCH_POLICY is not set
-# CONFIG_NETFILTER_XT_MATCH_MULTIPORT is not set
-# CONFIG_NETFILTER_XT_MATCH_PKTTYPE is not set
-# CONFIG_NETFILTER_XT_MATCH_QUOTA is not set
-# CONFIG_NETFILTER_XT_MATCH_REALM is not set
-# CONFIG_NETFILTER_XT_MATCH_SCTP is not set
-# CONFIG_NETFILTER_XT_MATCH_STATISTIC is not set
-# CONFIG_NETFILTER_XT_MATCH_STRING is not set
-# CONFIG_NETFILTER_XT_MATCH_TCPMSS is not set
-# CONFIG_NETFILTER_XT_MATCH_TIME is not set
-# CONFIG_NETFILTER_XT_MATCH_U32 is not set
-# CONFIG_NETFILTER_XT_MATCH_HASHLIMIT is not set
+# CONFIG_NETFILTER_XTABLES is not set
 
 #
 # IP: Netfilter Configuration
 #
-CONFIG_IP_NF_QUEUE=m
-CONFIG_IP_NF_IPTABLES=m
-CONFIG_IP_NF_MATCH_IPRANGE=m
-CONFIG_IP_NF_MATCH_TOS=m
-CONFIG_IP_NF_MATCH_RECENT=m
-CONFIG_IP_NF_MATCH_ECN=m
-CONFIG_IP_NF_MATCH_AH=m
-CONFIG_IP_NF_MATCH_TTL=m
-CONFIG_IP_NF_MATCH_OWNER=m
-CONFIG_IP_NF_MATCH_ADDRTYPE=m
-CONFIG_IP_NF_FILTER=m
-CONFIG_IP_NF_TARGET_REJECT=m
-CONFIG_IP_NF_TARGET_LOG=m
-CONFIG_IP_NF_TARGET_ULOG=m
-CONFIG_IP_NF_MANGLE=m
-CONFIG_IP_NF_TARGET_TOS=m
-CONFIG_IP_NF_TARGET_ECN=m
-CONFIG_IP_NF_TARGET_TTL=m
-CONFIG_IP_NF_RAW=m
-CONFIG_IP_NF_ARPTABLES=m
-CONFIG_IP_NF_ARPFILTER=m
-CONFIG_IP_NF_ARP_MANGLE=m
-
-#
-# IPv6: Netfilter Configuration (EXPERIMENTAL)
-#
-# CONFIG_IP6_NF_QUEUE is not set
-# CONFIG_IP6_NF_IPTABLES is not set
+# CONFIG_IP_NF_QUEUE is not set
+# CONFIG_IP_NF_IPTABLES is not set
+# CONFIG_IP_NF_ARPTABLES is not set
 # CONFIG_IP_DCCP is not set
 # CONFIG_IP_SCTP is not set
 # CONFIG_TIPC is not set
@@ -446,83 +355,8 @@ CONFIG_IP_NF_ARP_MANGLE=m
 #
 # CONFIG_NET_PKTGEN is not set
 # CONFIG_HAMRADIO is not set
-CONFIG_IRDA=m
-
-#
-# IrDA protocols
-#
-CONFIG_IRLAN=m
-CONFIG_IRNET=m
-CONFIG_IRCOMM=m
-# CONFIG_IRDA_ULTRA is not set
-
-#
-# IrDA options
-#
-# CONFIG_IRDA_CACHE_LAST_LSAP is not set
-# CONFIG_IRDA_FAST_RR is not set
-# CONFIG_IRDA_DEBUG is not set
-
-#
-# Infrared-port device drivers
-#
-
-#
-# SIR device drivers
-#
-# CONFIG_IRTTY_SIR is not set
-
-#
-# Dongle support
-#
-# CONFIG_KINGSUN_DONGLE is not set
-# CONFIG_KSDAZZLE_DONGLE is not set
-# CONFIG_KS959_DONGLE is not set
-
-#
-# Old SIR device drivers
-#
-# CONFIG_IRPORT_SIR is not set
-
-#
-# Old Serial dongle support
-#
-
-#
-# FIR device drivers
-#
-# CONFIG_USB_IRDA is not set
-# CONFIG_SIGMATEL_FIR is not set
-CONFIG_PXA_FICP=m
-# CONFIG_MCS_FIR is not set
-CONFIG_BT=m
-CONFIG_BT_L2CAP=m
-CONFIG_BT_SCO=m
-CONFIG_BT_RFCOMM=m
-CONFIG_BT_RFCOMM_TTY=y
-CONFIG_BT_BNEP=m
-CONFIG_BT_BNEP_MC_FILTER=y
-CONFIG_BT_BNEP_PROTO_FILTER=y
-CONFIG_BT_HIDP=m
-
-#
-# Bluetooth device drivers
-#
-CONFIG_BT_HCIUSB=m
-# CONFIG_BT_HCIUSB_SCO is not set
-# CONFIG_BT_HCIBTSDIO is not set
-CONFIG_BT_HCIUART=m
-CONFIG_BT_HCIUART_H4=y
-CONFIG_BT_HCIUART_BCSP=y
-# CONFIG_BT_HCIUART_LL is not set
-CONFIG_BT_HCIBCM203X=m
-CONFIG_BT_HCIBPA10X=m
-CONFIG_BT_HCIBFUSB=m
-CONFIG_BT_HCIDTL1=m
-CONFIG_BT_HCIBT3C=m
-CONFIG_BT_HCIBLUECARD=m
-CONFIG_BT_HCIBTUART=m
-CONFIG_BT_HCIVHCI=m
+# CONFIG_IRDA is not set
+# CONFIG_BT is not set
 # CONFIG_AF_RXRPC is not set
 
 #
@@ -531,12 +365,7 @@ CONFIG_BT_HCIVHCI=m
 # CONFIG_CFG80211 is not set
 CONFIG_WIRELESS_EXT=y
 # CONFIG_MAC80211 is not set
-CONFIG_IEEE80211=m
-# CONFIG_IEEE80211_DEBUG is not set
-CONFIG_IEEE80211_CRYPT_WEP=m
-CONFIG_IEEE80211_CRYPT_CCMP=m
-CONFIG_IEEE80211_CRYPT_TKIP=m
-# CONFIG_IEEE80211_SOFTMAC is not set
+# CONFIG_IEEE80211 is not set
 # CONFIG_RFKILL is not set
 # CONFIG_NET_9P is not set
 
@@ -626,7 +455,6 @@ CONFIG_MTD_NAND_IDS=y
 CONFIG_MTD_NAND_TMIO=y
 # CONFIG_MTD_NAND_NANDSIM is not set
 # CONFIG_MTD_NAND_PLATFORM is not set
-# CONFIG_MTD_ALAUDA is not set
 # CONFIG_MTD_ONENAND is not set
 
 #
@@ -636,10 +464,9 @@ CONFIG_MTD_NAND_TMIO=y
 # CONFIG_PARPORT is not set
 CONFIG_BLK_DEV=y
 # CONFIG_BLK_DEV_COW_COMMON is not set
-CONFIG_BLK_DEV_LOOP=m
+CONFIG_BLK_DEV_LOOP=y
 # CONFIG_BLK_DEV_CRYPTOLOOP is not set
 # CONFIG_BLK_DEV_NBD is not set
-# CONFIG_BLK_DEV_UB is not set
 # CONFIG_BLK_DEV_RAM is not set
 # CONFIG_CDROM_PKTCDVD is not set
 # CONFIG_ATA_OVER_ETH is not set
@@ -655,11 +482,10 @@ CONFIG_BLK_DEV_IDE=y
 # CONFIG_BLK_DEV_IDE_SATA is not set
 CONFIG_BLK_DEV_IDEDISK=y
 # CONFIG_IDEDISK_MULTI_MODE is not set
-CONFIG_BLK_DEV_IDECS=m
-CONFIG_BLK_DEV_IDECD=m
+CONFIG_BLK_DEV_IDECS=y
+# CONFIG_BLK_DEV_IDECD is not set
 # CONFIG_BLK_DEV_IDETAPE is not set
 # CONFIG_BLK_DEV_IDEFLOPPY is not set
-# CONFIG_BLK_DEV_IDESCSI is not set
 # CONFIG_IDE_TASK_IOCTL is not set
 CONFIG_IDE_PROC_FS=y
 
@@ -677,70 +503,22 @@ CONFIG_IDE_ARCH_OBSOLETE_INIT=y
 # SCSI device support
 #
 # CONFIG_RAID_ATTRS is not set
-CONFIG_SCSI=m
-CONFIG_SCSI_DMA=y
-# CONFIG_SCSI_TGT is not set
+# CONFIG_SCSI is not set
+# CONFIG_SCSI_DMA is not set
 # CONFIG_SCSI_NETLINK is not set
-CONFIG_SCSI_PROC_FS=y
-
-#
-# SCSI support type (disk, tape, CD-ROM)
-#
-CONFIG_BLK_DEV_SD=m
-CONFIG_CHR_DEV_ST=m
-CONFIG_CHR_DEV_OSST=m
-CONFIG_BLK_DEV_SR=m
-# CONFIG_BLK_DEV_SR_VENDOR is not set
-CONFIG_CHR_DEV_SG=m
-# CONFIG_CHR_DEV_SCH is not set
-
-#
-# Some SCSI devices (e.g. CD jukebox) support multiple LUNs
-#
-CONFIG_SCSI_MULTI_LUN=y
-# CONFIG_SCSI_CONSTANTS is not set
-# CONFIG_SCSI_LOGGING is not set
-# CONFIG_SCSI_SCAN_ASYNC is not set
-CONFIG_SCSI_WAIT_SCAN=m
-
-#
-# SCSI Transports
-#
-# CONFIG_SCSI_SPI_ATTRS is not set
-# CONFIG_SCSI_FC_ATTRS is not set
-# CONFIG_SCSI_ISCSI_ATTRS is not set
-# CONFIG_SCSI_SAS_LIBSAS is not set
-# CONFIG_SCSI_SRP_ATTRS is not set
-CONFIG_SCSI_LOWLEVEL=y
-# CONFIG_ISCSI_TCP is not set
-# CONFIG_SCSI_DEBUG is not set
-# CONFIG_SCSI_LOWLEVEL_PCMCIA is not set
 # CONFIG_ATA is not set
-CONFIG_MD=y
-# CONFIG_BLK_DEV_MD is not set
-CONFIG_BLK_DEV_DM=m
-# CONFIG_DM_DEBUG is not set
-CONFIG_DM_CRYPT=m
-CONFIG_DM_SNAPSHOT=m
-CONFIG_DM_MIRROR=m
-CONFIG_DM_ZERO=m
-CONFIG_DM_MULTIPATH=m
-CONFIG_DM_MULTIPATH_EMC=m
-# CONFIG_DM_MULTIPATH_RDAC is not set
-# CONFIG_DM_MULTIPATH_HP is not set
-# CONFIG_DM_DELAY is not set
-# CONFIG_DM_UEVENT is not set
+# CONFIG_MD is not set
 CONFIG_NETDEVICES=y
 # CONFIG_NETDEVICES_MULTIQUEUE is not set
 # CONFIG_DUMMY is not set
 # CONFIG_BONDING is not set
 # CONFIG_MACVLAN is not set
 # CONFIG_EQUALIZER is not set
-CONFIG_TUN=m
+# CONFIG_TUN is not set
 # CONFIG_VETH is not set
 # CONFIG_PHYLIB is not set
 CONFIG_NET_ETHERNET=y
-CONFIG_MII=m
+# CONFIG_MII is not set
 # CONFIG_AX88796 is not set
 # CONFIG_SMC91X is not set
 # CONFIG_DM9000 is not set
@@ -758,47 +536,18 @@ CONFIG_NETDEV_10000=y
 #
 # CONFIG_WLAN_PRE80211 is not set
 # CONFIG_WLAN_80211 is not set
-
-#
-# USB Network Adapters
-#
-CONFIG_USB_CATC=m
-CONFIG_USB_KAWETH=m
-CONFIG_USB_PEGASUS=m
-CONFIG_USB_RTL8150=m
-CONFIG_USB_USBNET=m
-CONFIG_USB_NET_AX8817X=m
-CONFIG_USB_NET_CDCETHER=m
-# CONFIG_USB_NET_DM9601 is not set
-CONFIG_USB_NET_GL620A=m
-CONFIG_USB_NET_NET1080=m
-CONFIG_USB_NET_PLUSB=m
-# CONFIG_USB_NET_MCS7830 is not set
-# CONFIG_USB_NET_RNDIS_HOST is not set
-# CONFIG_USB_NET_CDC_SUBSET is not set
-# CONFIG_USB_NET_ZAURUS is not set
 CONFIG_NET_PCMCIA=y
 # CONFIG_PCMCIA_3C589 is not set
 # CONFIG_PCMCIA_3C574 is not set
 # CONFIG_PCMCIA_FMVJ18X is not set
-CONFIG_PCMCIA_PCNET=m
+# CONFIG_PCMCIA_PCNET is not set
 # CONFIG_PCMCIA_NMCLAN is not set
 # CONFIG_PCMCIA_SMC91C92 is not set
 # CONFIG_PCMCIA_XIRC2PS is not set
 # CONFIG_PCMCIA_AXNET is not set
 # CONFIG_WAN is not set
-CONFIG_PPP=m
-# CONFIG_PPP_MULTILINK is not set
-# CONFIG_PPP_FILTER is not set
-CONFIG_PPP_ASYNC=m
-# CONFIG_PPP_SYNC_TTY is not set
-CONFIG_PPP_DEFLATE=m
-CONFIG_PPP_BSDCOMP=m
-# CONFIG_PPP_MPPE is not set
-# CONFIG_PPPOE is not set
-# CONFIG_PPPOL2TP is not set
+# CONFIG_PPP is not set
 # CONFIG_SLIP is not set
-CONFIG_SLHC=m
 # CONFIG_SHAPER is not set
 # CONFIG_NETCONSOLE is not set
 # CONFIG_NETPOLL is not set
@@ -815,10 +564,7 @@ CONFIG_INPUT=y
 #
 # Userland interfaces
 #
-CONFIG_INPUT_MOUSEDEV=m
-# CONFIG_INPUT_MOUSEDEV_PSAUX is not set
-CONFIG_INPUT_MOUSEDEV_SCREEN_X=480
-CONFIG_INPUT_MOUSEDEV_SCREEN_Y=640
+# CONFIG_INPUT_MOUSEDEV is not set
 # CONFIG_INPUT_JOYDEV is not set
 CONFIG_INPUT_EVDEV=y
 # CONFIG_INPUT_EVBUG is not set
@@ -836,37 +582,21 @@ CONFIG_INPUT_KEYBOARD=y
 # CONFIG_KEYBOARD_STOWAWAY is not set
 # CONFIG_KEYBOARD_CORGI is not set
 # CONFIG_KEYBOARD_SPITZ is not set
+# CONFIG_SHARPSL_RC is not set
 CONFIG_KEYBOARD_TOSA=y
 # CONFIG_KEYBOARD_TOSA_USE_EXT_KEYCODES is not set
 # CONFIG_KEYBOARD_GPIO is not set
 # CONFIG_INPUT_MOUSE is not set
 # CONFIG_INPUT_JOYSTICK is not set
 # CONFIG_INPUT_TABLET is not set
-CONFIG_INPUT_TOUCHSCREEN=y
-# CONFIG_TOUCHSCREEN_CORGI is not set
-# CONFIG_TOUCHSCREEN_FUJITSU is not set
-# CONFIG_TOUCHSCREEN_GUNZE is not set
-# CONFIG_TOUCHSCREEN_ELO is not set
-# CONFIG_TOUCHSCREEN_MTOUCH is not set
-# CONFIG_TOUCHSCREEN_MK712 is not set
-# CONFIG_TOUCHSCREEN_PENMOUNT is not set
-# CONFIG_TOUCHSCREEN_TOUCHRIGHT is not set
-CONFIG_TOUCHSCREEN_WM97XX=y
-# CONFIG_TOUCHSCREEN_WM9705 is not set
-CONFIG_TOUCHSCREEN_WM9712=y
-# CONFIG_TOUCHSCREEN_WM9713 is not set
-# CONFIG_TOUCHSCREEN_WM97XX_MAINSTONE is not set
-CONFIG_TOUCHSCREEN_WM97XX_TOSA=y
-# CONFIG_TOUCHSCREEN_TOUCHWIN is not set
-# CONFIG_TOUCHSCREEN_UCB1400 is not set
-# CONFIG_TOUCHSCREEN_USB_COMPOSITE is not set
+# CONFIG_INPUT_TOUCHSCREEN is not set
 CONFIG_INPUT_MISC=y
 # CONFIG_INPUT_ATI_REMOTE is not set
 # CONFIG_INPUT_ATI_REMOTE2 is not set
 # CONFIG_INPUT_KEYSPAN_REMOTE is not set
 # CONFIG_INPUT_POWERMATE is not set
 # CONFIG_INPUT_YEALINK is not set
-CONFIG_INPUT_UINPUT=m
+# CONFIG_INPUT_UINPUT is not set
 
 #
 # Hardware I/O ports
@@ -880,17 +610,13 @@ CONFIG_INPUT_UINPUT=m
 CONFIG_VT=y
 CONFIG_VT_CONSOLE=y
 CONFIG_HW_CONSOLE=y
-# CONFIG_VT_HW_CONSOLE_BINDING is not set
+CONFIG_VT_HW_CONSOLE_BINDING=y
 # CONFIG_SERIAL_NONSTANDARD is not set
 
 #
 # Serial drivers
 #
-CONFIG_SERIAL_8250=m
-CONFIG_SERIAL_8250_CS=m
-CONFIG_SERIAL_8250_NR_UARTS=4
-CONFIG_SERIAL_8250_RUNTIME_UARTS=4
-# CONFIG_SERIAL_8250_EXTENDED is not set
+# CONFIG_SERIAL_8250 is not set
 
 #
 # Non-8250 serial port support
@@ -902,7 +628,7 @@ CONFIG_SERIAL_CORE_CONSOLE=y
 CONFIG_UNIX98_PTYS=y
 # CONFIG_LEGACY_PTYS is not set
 # CONFIG_IPMI_HANDLER is not set
-CONFIG_HW_RANDOM=m
+# CONFIG_HW_RANDOM is not set
 # CONFIG_NVRAM is not set
 # CONFIG_R3964 is not set
 
@@ -935,8 +661,6 @@ CONFIG_I2C_PXA=y
 # CONFIG_I2C_PARPORT_LIGHT is not set
 # CONFIG_I2C_SIMTEC is not set
 # CONFIG_I2C_TAOS_EVM is not set
-# CONFIG_I2C_STUB is not set
-# CONFIG_I2C_TINY_USB is not set
 
 #
 # Miscellaneous I2C Chip support
@@ -974,12 +698,7 @@ CONFIG_HAVE_GPIO_LIB=y
 # SPI GPIO expanders:
 #
 # CONFIG_W1 is not set
-CONFIG_POWER_SUPPLY=y
-# CONFIG_POWER_SUPPLY_DEBUG is not set
-CONFIG_PDA_POWER=y
-CONFIG_APM_POWER=y
-# CONFIG_BATTERY_DS2760 is not set
-CONFIG_BATTERY_TOSA=y
+# CONFIG_POWER_SUPPLY is not set
 # CONFIG_HWMON is not set
 # CONFIG_WATCHDOG is not set
 
@@ -997,47 +716,15 @@ CONFIG_MFD_CORE=y
 # CONFIG_MFD_TC6387XB is not set
 CONFIG_MFD_TC6393XB=y
 # CONFIG_MFD_SM501 is not set
+# CONFIG_HTC_ASIC3 is not set
+# CONFIG_HTC_ASIC3_DS1WM is not set
 
 #
 # Multimedia devices
 #
-CONFIG_VIDEO_DEV=m
-CONFIG_VIDEO_V4L1=y
-CONFIG_VIDEO_V4L1_COMPAT=y
-CONFIG_VIDEO_V4L2=y
-CONFIG_VIDEO_CAPTURE_DRIVERS=y
-# CONFIG_VIDEO_ADV_DEBUG is not set
-CONFIG_VIDEO_HELPER_CHIPS_AUTO=y
-# CONFIG_VIDEO_VIVI is not set
-# CONFIG_VIDEO_CPIA is not set
-# CONFIG_VIDEO_CPIA2 is not set
-# CONFIG_VIDEO_SAA5246A is not set
-# CONFIG_VIDEO_SAA5249 is not set
-# CONFIG_TUNER_3036 is not set
-CONFIG_V4L_USB_DRIVERS=y
-# CONFIG_VIDEO_PVRUSB2 is not set
-# CONFIG_VIDEO_EM28XX is not set
-# CONFIG_VIDEO_USBVISION is not set
-CONFIG_VIDEO_USBVIDEO=m
-CONFIG_USB_VICAM=m
-CONFIG_USB_IBMCAM=m
-CONFIG_USB_KONICAWC=m
-# CONFIG_USB_QUICKCAM_MESSENGER is not set
-# CONFIG_USB_ET61X251 is not set
-# CONFIG_VIDEO_OVCAMCHIP is not set
-# CONFIG_USB_W9968CF is not set
-CONFIG_USB_OV511=m
-CONFIG_USB_SE401=m
-CONFIG_USB_SN9C102=m
-CONFIG_USB_STV680=m
-# CONFIG_USB_ZC0301 is not set
-# CONFIG_USB_PWC is not set
-# CONFIG_USB_ZR364XX is not set
-CONFIG_RADIO_ADAPTERS=y
-CONFIG_USB_DSBR=m
+# CONFIG_VIDEO_DEV is not set
 # CONFIG_DVB_CORE is not set
-CONFIG_DAB=y
-CONFIG_USB_DABUSB=m
+# CONFIG_DAB is not set
 
 #
 # Graphics support
@@ -1070,7 +757,7 @@ CONFIG_FB_CFB_IMAGEBLIT=y
 # CONFIG_FB_MBX is not set
 # CONFIG_FB_W100 is not set
 CONFIG_FB_TMIO=y
-CONFIG_FB_TMIO_ACCELL=y
+# CONFIG_FB_TMIO_ACCELL is not set
 # CONFIG_FB_VIRTUAL is not set
 CONFIG_BACKLIGHT_LCD_SUPPORT=y
 # CONFIG_LCD_CLASS_DEVICE is not set
@@ -1115,23 +802,19 @@ CONFIG_SOUND=y
 CONFIG_SND=y
 CONFIG_SND_TIMER=y
 CONFIG_SND_PCM=y
-CONFIG_SND_HWDEP=m
-CONFIG_SND_RAWMIDI=m
 # CONFIG_SND_SEQUENCER is not set
-CONFIG_SND_OSSEMUL=y
-CONFIG_SND_MIXER_OSS=m
-CONFIG_SND_PCM_OSS=m
-CONFIG_SND_PCM_OSS_PLUGINS=y
+# CONFIG_SND_MIXER_OSS is not set
+# CONFIG_SND_PCM_OSS is not set
 # CONFIG_SND_DYNAMIC_MINORS is not set
 # CONFIG_SND_SUPPORT_OLD_API is not set
-CONFIG_SND_VERBOSE_PROCFS=y
+# CONFIG_SND_VERBOSE_PROCFS is not set
 # CONFIG_SND_VERBOSE_PRINTK is not set
 # CONFIG_SND_DEBUG is not set
 
 #
 # Generic devices
 #
-CONFIG_SND_DUMMY=m
+# CONFIG_SND_DUMMY is not set
 # CONFIG_SND_MTPAV is not set
 # CONFIG_SND_SERIAL_U16550 is not set
 # CONFIG_SND_MPU401 is not set
@@ -1141,12 +824,6 @@ CONFIG_SND_DUMMY=m
 #
 # CONFIG_SND_PXA2XX_AC97 is not set
 
-#
-# USB devices
-#
-CONFIG_SND_USB_AUDIO=m
-# CONFIG_SND_USB_CAIAQ is not set
-
 #
 # PCMCIA devices
 #
@@ -1172,206 +849,21 @@ CONFIG_SND_SOC_WM9712=y
 #
 # CONFIG_SOUND_PRIME is not set
 CONFIG_AC97_BUS=y
-CONFIG_HID_SUPPORT=y
-CONFIG_HID=m
-# CONFIG_HID_DEBUG is not set
-# CONFIG_HIDRAW is not set
-
-#
-# USB Input Devices
-#
-CONFIG_USB_HID=m
-# CONFIG_USB_HIDINPUT_POWERBOOK is not set
-# CONFIG_HID_FF is not set
-# CONFIG_USB_HIDDEV is not set
-
-#
-# USB HID Boot Protocol drivers
-#
-# CONFIG_USB_KBD is not set
-# CONFIG_USB_MOUSE is not set
+# CONFIG_HID_SUPPORT is not set
 CONFIG_USB_SUPPORT=y
 CONFIG_USB_ARCH_HAS_HCD=y
 CONFIG_USB_ARCH_HAS_OHCI=y
 # CONFIG_USB_ARCH_HAS_EHCI is not set
-CONFIG_USB=m
-# CONFIG_USB_DEBUG is not set
-
-#
-# Miscellaneous USB options
-#
-CONFIG_USB_DEVICEFS=y
-CONFIG_USB_DEVICE_CLASS=y
-# CONFIG_USB_DYNAMIC_MINORS is not set
-# CONFIG_USB_SUSPEND is not set
-# CONFIG_USB_PERSIST is not set
-# CONFIG_USB_OTG is not set
-
-#
-# USB Host Controller Drivers
-#
-# CONFIG_USB_ISP116X_HCD is not set
-CONFIG_USB_OHCI_HCD=m
-# CONFIG_USB_OHCI_BIG_ENDIAN_DESC is not set
-# CONFIG_USB_OHCI_BIG_ENDIAN_MMIO is not set
-CONFIG_USB_OHCI_LITTLE_ENDIAN=y
-CONFIG_USB_SL811_HCD=m
-CONFIG_USB_SL811_CS=m
-# CONFIG_USB_R8A66597_HCD is not set
-
-#
-# USB Device Class drivers
-#
-CONFIG_USB_ACM=m
-CONFIG_USB_PRINTER=m
+# CONFIG_USB is not set
 
 #
 # NOTE: USB_STORAGE enables SCSI, and 'SCSI disk support'
 #
 
-#
-# may also be needed; see USB_STORAGE Help for more information
-#
-CONFIG_USB_STORAGE=m
-# CONFIG_USB_STORAGE_DEBUG is not set
-# CONFIG_USB_STORAGE_DATAFAB is not set
-# CONFIG_USB_STORAGE_FREECOM is not set
-# CONFIG_USB_STORAGE_ISD200 is not set
-# CONFIG_USB_STORAGE_DPCM is not set
-# CONFIG_USB_STORAGE_USBAT is not set
-# CONFIG_USB_STORAGE_SDDR09 is not set
-# CONFIG_USB_STORAGE_SDDR55 is not set
-# CONFIG_USB_STORAGE_JUMPSHOT is not set
-# CONFIG_USB_STORAGE_ALAUDA is not set
-# CONFIG_USB_STORAGE_KARMA is not set
-# CONFIG_USB_LIBUSUAL is not set
-
-#
-# USB Imaging devices
-#
-CONFIG_USB_MDC800=m
-CONFIG_USB_MICROTEK=m
-CONFIG_USB_MON=y
-
-#
-# USB port drivers
-#
-
-#
-# USB Serial Converter support
-#
-CONFIG_USB_SERIAL=m
-CONFIG_USB_SERIAL_GENERIC=y
-# CONFIG_USB_SERIAL_AIRCABLE is not set
-# CONFIG_USB_SERIAL_AIRPRIME is not set
-# CONFIG_USB_SERIAL_ARK3116 is not set
-CONFIG_USB_SERIAL_BELKIN=m
-# CONFIG_USB_SERIAL_CH341 is not set
-# CONFIG_USB_SERIAL_WHITEHEAT is not set
-CONFIG_USB_SERIAL_DIGI_ACCELEPORT=m
-CONFIG_USB_SERIAL_CP2101=m
-CONFIG_USB_SERIAL_CYPRESS_M8=m
-CONFIG_USB_SERIAL_EMPEG=m
-CONFIG_USB_SERIAL_FTDI_SIO=m
-# CONFIG_USB_SERIAL_FUNSOFT is not set
-CONFIG_USB_SERIAL_VISOR=m
-CONFIG_USB_SERIAL_IPAQ=m
-CONFIG_USB_SERIAL_IR=m
-CONFIG_USB_SERIAL_EDGEPORT=m
-CONFIG_USB_SERIAL_EDGEPORT_TI=m
-CONFIG_USB_SERIAL_GARMIN=m
-CONFIG_USB_SERIAL_IPW=m
-CONFIG_USB_SERIAL_KEYSPAN_PDA=m
-CONFIG_USB_SERIAL_KEYSPAN=m
-# CONFIG_USB_SERIAL_KEYSPAN_MPR is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA28 is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA28X is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA28XA is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA28XB is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA19 is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA18X is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA19W is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA19QW is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA19QI is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA49W is not set
-# CONFIG_USB_SERIAL_KEYSPAN_USA49WLC is not set
-CONFIG_USB_SERIAL_KLSI=m
-CONFIG_USB_SERIAL_KOBIL_SCT=m
-CONFIG_USB_SERIAL_MCT_U232=m
-# CONFIG_USB_SERIAL_MOS7720 is not set
-# CONFIG_USB_SERIAL_MOS7840 is not set
-# CONFIG_USB_SERIAL_NAVMAN is not set
-CONFIG_USB_SERIAL_PL2303=m
-# CONFIG_USB_SERIAL_OTI6858 is not set
-# CONFIG_USB_SERIAL_HP4X is not set
-CONFIG_USB_SERIAL_SAFE=m
-# CONFIG_USB_SERIAL_SAFE_PADDED is not set
-# CONFIG_USB_SERIAL_SIERRAWIRELESS is not set
-CONFIG_USB_SERIAL_TI=m
-CONFIG_USB_SERIAL_CYBERJACK=m
-CONFIG_USB_SERIAL_XIRCOM=m
-# CONFIG_USB_SERIAL_OPTION is not set
-CONFIG_USB_SERIAL_OMNINET=m
-# CONFIG_USB_SERIAL_DEBUG is not set
-CONFIG_USB_EZUSB=y
-
-#
-# USB Miscellaneous drivers
-#
-CONFIG_USB_EMI62=m
-CONFIG_USB_EMI26=m
-# CONFIG_USB_ADUTUX is not set
-CONFIG_USB_AUERSWALD=m
-CONFIG_USB_RIO500=m
-CONFIG_USB_LEGOTOWER=m
-CONFIG_USB_LCD=m
-# CONFIG_USB_BERRY_CHARGE is not set
-CONFIG_USB_LED=m
-# CONFIG_USB_CYPRESS_CY7C63 is not set
-CONFIG_USB_CYTHERM=m
-# CONFIG_USB_PHIDGET is not set
-CONFIG_USB_IDMOUSE=m
-# CONFIG_USB_FTDI_ELAN is not set
-# CONFIG_USB_APPLEDISPLAY is not set
-# CONFIG_USB_LD is not set
-# CONFIG_USB_TRANCEVIBRATOR is not set
-# CONFIG_USB_IOWARRIOR is not set
-# CONFIG_USB_TEST is not set
-
-#
-# USB DSL modem support
-#
-
 #
 # USB Gadget Support
 #
-CONFIG_USB_GADGET=m
-# CONFIG_USB_GADGET_DEBUG_FILES is not set
-CONFIG_USB_GADGET_SELECTED=y
-# CONFIG_USB_GADGET_AMD5536UDC is not set
-# CONFIG_USB_GADGET_ATMEL_USBA is not set
-# CONFIG_USB_GADGET_FSL_USB2 is not set
-# CONFIG_USB_GADGET_NET2280 is not set
-CONFIG_USB_GADGET_PXA2XX=y
-CONFIG_USB_PXA2XX=m
-# CONFIG_USB_PXA2XX_SMALL is not set
-# CONFIG_USB_GADGET_M66592 is not set
-# CONFIG_USB_GADGET_PXA27X is not set
-# CONFIG_USB_GADGET_GOKU is not set
-# CONFIG_USB_GADGET_LH7A40X is not set
-# CONFIG_USB_GADGET_OMAP is not set
-# CONFIG_USB_GADGET_S3C2410 is not set
-# CONFIG_USB_GADGET_AT91 is not set
-# CONFIG_USB_GADGET_DUMMY_HCD is not set
-# CONFIG_USB_GADGET_DUALSPEED is not set
-CONFIG_USB_ZERO=m
-CONFIG_USB_ETH=m
-CONFIG_USB_ETH_RNDIS=y
-CONFIG_USB_GADGETFS=m
-CONFIG_USB_FILE_STORAGE=m
-# CONFIG_USB_FILE_STORAGE_TEST is not set
-CONFIG_USB_G_SERIAL=m
-# CONFIG_USB_MIDI_GADGET is not set
+# CONFIG_USB_GADGET is not set
 CONFIG_MMC=y
 # CONFIG_MMC_DEBUG is not set
 CONFIG_MMC_UNSAFE_RESUME=y
@@ -1381,7 +873,7 @@ CONFIG_MMC_UNSAFE_RESUME=y
 #
 CONFIG_MMC_BLOCK=y
 CONFIG_MMC_BLOCK_BOUNCE=y
-CONFIG_SDIO_UART=m
+# CONFIG_SDIO_UART is not set
 
 #
 # MMC/SD Host Controller Drivers
@@ -1401,7 +893,7 @@ CONFIG_LEDS_TOSA=y
 # LED Triggers
 #
 CONFIG_LEDS_TRIGGERS=y
-CONFIG_LEDS_TRIGGER_TIMER=m
+# CONFIG_LEDS_TRIGGER_TIMER is not set
 CONFIG_LEDS_TRIGGER_IDE_DISK=y
 # CONFIG_LEDS_TRIGGER_HEARTBEAT is not set
 CONFIG_RTC_LIB=y
@@ -1459,13 +951,10 @@ CONFIG_RTC_DRV_SA1100=y
 CONFIG_EXT2_FS=y
 # CONFIG_EXT2_FS_XATTR is not set
 # CONFIG_EXT2_FS_XIP is not set
-CONFIG_EXT3_FS=m
-CONFIG_EXT3_FS_XATTR=y
-# CONFIG_EXT3_FS_POSIX_ACL is not set
-# CONFIG_EXT3_FS_SECURITY is not set
+CONFIG_EXT3_FS=y
+# CONFIG_EXT3_FS_XATTR is not set
 # CONFIG_EXT4DEV_FS is not set
-CONFIG_JBD=m
-CONFIG_FS_MBCACHE=y
+CONFIG_JBD=y
 # CONFIG_REISERFS_FS is not set
 # CONFIG_JFS_FS is not set
 # CONFIG_FS_POSIX_ACL is not set
@@ -1480,24 +969,19 @@ CONFIG_INOTIFY_USER=y
 CONFIG_DNOTIFY=y
 # CONFIG_AUTOFS_FS is not set
 # CONFIG_AUTOFS4_FS is not set
-CONFIG_FUSE_FS=m
+# CONFIG_FUSE_FS is not set
 
 #
 # CD-ROM/DVD Filesystems
 #
-CONFIG_ISO9660_FS=m
-CONFIG_JOLIET=y
-# CONFIG_ZISOFS is not set
+# CONFIG_ISO9660_FS is not set
 # CONFIG_UDF_FS is not set
 
 #
 # DOS/FAT/NT Filesystems
 #
-CONFIG_FAT_FS=m
-CONFIG_MSDOS_FS=m
-CONFIG_VFAT_FS=m
-CONFIG_FAT_DEFAULT_CODEPAGE=437
-CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1"
+# CONFIG_MSDOS_FS is not set
+# CONFIG_VFAT_FS is not set
 # CONFIG_NTFS_FS is not set
 
 #
@@ -1537,42 +1021,14 @@ CONFIG_JFFS2_RUBIN=y
 CONFIG_JFFS2_CMODE_PRIORITY=y
 # CONFIG_JFFS2_CMODE_SIZE is not set
 # CONFIG_JFFS2_CMODE_FAVOURLZO is not set
-CONFIG_CRAMFS=m
-CONFIG_SQUASHFS=m
-# CONFIG_SQUASHFS_EMBEDDED is not set
-CONFIG_SQUASHFS_FRAGMENT_CACHE_SIZE=3
+# CONFIG_CRAMFS is not set
+# CONFIG_SQUASHFS is not set
 # CONFIG_VXFS_FS is not set
 # CONFIG_HPFS_FS is not set
 # CONFIG_QNX4FS_FS is not set
 # CONFIG_SYSV_FS is not set
 # CONFIG_UFS_FS is not set
-CONFIG_NETWORK_FILESYSTEMS=y
-CONFIG_NFS_FS=m
-CONFIG_NFS_V3=y
-# CONFIG_NFS_V3_ACL is not set
-CONFIG_NFS_V4=y
-# CONFIG_NFS_DIRECTIO is not set
-# CONFIG_NFSD is not set
-CONFIG_LOCKD=m
-CONFIG_LOCKD_V4=y
-CONFIG_NFS_COMMON=y
-CONFIG_SUNRPC=m
-CONFIG_SUNRPC_GSS=m
-# CONFIG_SUNRPC_BIND34 is not set
-CONFIG_RPCSEC_GSS_KRB5=m
-# CONFIG_RPCSEC_GSS_SPKM3 is not set
-CONFIG_SMB_FS=m
-CONFIG_SMB_NLS_DEFAULT=y
-CONFIG_SMB_NLS_REMOTE="cp437"
-CONFIG_CIFS=m
-# CONFIG_CIFS_STATS is not set
-# CONFIG_CIFS_WEAK_PW_HASH is not set
-# CONFIG_CIFS_XATTR is not set
-# CONFIG_CIFS_DEBUG2 is not set
-# CONFIG_CIFS_EXPERIMENTAL is not set
-# CONFIG_NCP_FS is not set
-# CONFIG_CODA_FS is not set
-# CONFIG_AFS_FS is not set
+# CONFIG_NETWORK_FILESYSTEMS is not set
 
 #
 # Partition Types
@@ -1595,46 +1051,7 @@ CONFIG_MSDOS_PARTITION=y
 # CONFIG_KARMA_PARTITION is not set
 # CONFIG_EFI_PARTITION is not set
 # CONFIG_SYSV68_PARTITION is not set
-CONFIG_NLS=m
-CONFIG_NLS_DEFAULT="cp437"
-CONFIG_NLS_CODEPAGE_437=m
-CONFIG_NLS_CODEPAGE_737=m
-CONFIG_NLS_CODEPAGE_775=m
-CONFIG_NLS_CODEPAGE_850=m
-CONFIG_NLS_CODEPAGE_852=m
-CONFIG_NLS_CODEPAGE_855=m
-CONFIG_NLS_CODEPAGE_857=m
-CONFIG_NLS_CODEPAGE_860=m
-CONFIG_NLS_CODEPAGE_861=m
-CONFIG_NLS_CODEPAGE_862=m
-CONFIG_NLS_CODEPAGE_863=m
-CONFIG_NLS_CODEPAGE_864=m
-CONFIG_NLS_CODEPAGE_865=m
-CONFIG_NLS_CODEPAGE_866=m
-CONFIG_NLS_CODEPAGE_869=m
-CONFIG_NLS_CODEPAGE_936=m
-CONFIG_NLS_CODEPAGE_950=m
-CONFIG_NLS_CODEPAGE_932=m
-CONFIG_NLS_CODEPAGE_949=m
-CONFIG_NLS_CODEPAGE_874=m
-CONFIG_NLS_ISO8859_8=m
-CONFIG_NLS_CODEPAGE_1250=m
-CONFIG_NLS_CODEPAGE_1251=m
-CONFIG_NLS_ASCII=m
-CONFIG_NLS_ISO8859_1=m
-CONFIG_NLS_ISO8859_2=m
-CONFIG_NLS_ISO8859_3=m
-CONFIG_NLS_ISO8859_4=m
-CONFIG_NLS_ISO8859_5=m
-CONFIG_NLS_ISO8859_6=m
-CONFIG_NLS_ISO8859_7=m
-CONFIG_NLS_ISO8859_9=m
-CONFIG_NLS_ISO8859_13=m
-CONFIG_NLS_ISO8859_14=m
-CONFIG_NLS_ISO8859_15=m
-CONFIG_NLS_KOI8_R=m
-CONFIG_NLS_KOI8_U=m
-CONFIG_NLS_UTF8=m
+# CONFIG_NLS is not set
 # CONFIG_DLM is not set
 # CONFIG_INSTRUMENTATION is not set
 
@@ -1661,47 +1078,42 @@ CONFIG_FRAME_POINTER=y
 # CONFIG_SECURITY is not set
 # CONFIG_SECURITY_FILE_CAPABILITIES is not set
 CONFIG_CRYPTO=y
-CONFIG_CRYPTO_ALGAPI=m
-CONFIG_CRYPTO_BLKCIPHER=m
-CONFIG_CRYPTO_HASH=m
-CONFIG_CRYPTO_MANAGER=m
-CONFIG_CRYPTO_HMAC=m
+# CONFIG_CRYPTO_MANAGER is not set
+# CONFIG_CRYPTO_HMAC is not set
 # CONFIG_CRYPTO_XCBC is not set
-CONFIG_CRYPTO_NULL=m
-CONFIG_CRYPTO_MD4=m
-CONFIG_CRYPTO_MD5=m
-CONFIG_CRYPTO_SHA1=m
-CONFIG_CRYPTO_SHA256=m
-CONFIG_CRYPTO_SHA512=m
-CONFIG_CRYPTO_WP512=m
+# CONFIG_CRYPTO_NULL is not set
+# CONFIG_CRYPTO_MD4 is not set
+# CONFIG_CRYPTO_MD5 is not set
+# CONFIG_CRYPTO_SHA1 is not set
+# CONFIG_CRYPTO_SHA256 is not set
+# CONFIG_CRYPTO_SHA512 is not set
+# CONFIG_CRYPTO_WP512 is not set
 # CONFIG_CRYPTO_TGR192 is not set
 # CONFIG_CRYPTO_GF128MUL is not set
-CONFIG_CRYPTO_ECB=m
-CONFIG_CRYPTO_CBC=m
+# CONFIG_CRYPTO_ECB is not set
+# CONFIG_CRYPTO_CBC is not set
 # CONFIG_CRYPTO_PCBC is not set
 # CONFIG_CRYPTO_LRW is not set
 # CONFIG_CRYPTO_XTS is not set
 # CONFIG_CRYPTO_CRYPTD is not set
-CONFIG_CRYPTO_DES=m
+# CONFIG_CRYPTO_DES is not set
 # CONFIG_CRYPTO_FCRYPT is not set
-CONFIG_CRYPTO_BLOWFISH=m
-CONFIG_CRYPTO_TWOFISH=m
-CONFIG_CRYPTO_TWOFISH_COMMON=m
-CONFIG_CRYPTO_SERPENT=m
-CONFIG_CRYPTO_AES=m
-CONFIG_CRYPTO_CAST5=m
-CONFIG_CRYPTO_CAST6=m
-CONFIG_CRYPTO_TEA=m
-CONFIG_CRYPTO_ARC4=m
-CONFIG_CRYPTO_KHAZAD=m
-CONFIG_CRYPTO_ANUBIS=m
+# CONFIG_CRYPTO_BLOWFISH is not set
+# CONFIG_CRYPTO_TWOFISH is not set
+# CONFIG_CRYPTO_SERPENT is not set
+# CONFIG_CRYPTO_AES is not set
+# CONFIG_CRYPTO_CAST5 is not set
+# CONFIG_CRYPTO_CAST6 is not set
+# CONFIG_CRYPTO_TEA is not set
+# CONFIG_CRYPTO_ARC4 is not set
+# CONFIG_CRYPTO_KHAZAD is not set
+# CONFIG_CRYPTO_ANUBIS is not set
 # CONFIG_CRYPTO_SEED is not set
-CONFIG_CRYPTO_DEFLATE=m
+# CONFIG_CRYPTO_DEFLATE is not set
 # CONFIG_CRYPTO_LZO is not set
-CONFIG_CRYPTO_MICHAEL_MIC=m
-CONFIG_CRYPTO_CRC32C=m
+# CONFIG_CRYPTO_MICHAEL_MIC is not set
+# CONFIG_CRYPTO_CRC32C is not set
 # CONFIG_CRYPTO_CAMELLIA is not set
-CONFIG_CRYPTO_TEST=m
 # CONFIG_CRYPTO_AUTHENC is not set
 CONFIG_CRYPTO_HW=y
 
@@ -1709,12 +1121,12 @@ CONFIG_CRYPTO_HW=y
 # Library routines
 #
 CONFIG_BITREVERSE=y
-CONFIG_CRC_CCITT=m
+# CONFIG_CRC_CCITT is not set
 # CONFIG_CRC16 is not set
 # CONFIG_CRC_ITU_T is not set
 CONFIG_CRC32=y
 # CONFIG_CRC7 is not set
-CONFIG_LIBCRC32C=m
+# CONFIG_LIBCRC32C is not set
 CONFIG_ZLIB_INFLATE=y
 CONFIG_ZLIB_DEFLATE=y
 CONFIG_LZO_COMPRESS=y
diff --git a/packages/kexecboot/linux-kexecboot-2.6.24/tosa/tmiofb-fix-unaccel.patch b/packages/kexecboot/linux-kexecboot-2.6.24/tosa/tmiofb-fix-unaccel.patch
new file mode 100644 (file)
index 0000000..d611342
--- /dev/null
@@ -0,0 +1,33 @@
+Index: linux-2.6.24/drivers/video/tmiofb.c
+===================================================================
+--- linux-2.6.24.orig/drivers/video/tmiofb.c   2008-12-07 22:30:26.600128369 +0300
++++ linux-2.6.24/drivers/video/tmiofb.c        2008-12-07 22:31:42.537112538 +0300
+@@ -689,14 +689,14 @@ static irqreturn_t tmiofb_irq(int irq, v
+       unsigned int                    bbisc   = ioread16(&lcr->bbisc);
++      iowrite16(bbisc, &lcr->bbisc);
++
++#ifdef CONFIG_FB_TMIO_ACCELL
+       if (unlikely(par->use_polling && irq != -1)) {
+               printk(KERN_INFO "tmiofb: switching to waitq\n");
+               par->use_polling = false;
+       }
+-      iowrite16(bbisc, &lcr->bbisc);
+-
+-#ifdef CONFIG_FB_TMIO_ACCELL
+       if (bbisc & 1)
+               wake_up(&par->wait_acc);
+ #endif
+@@ -972,8 +972,10 @@ static int tmiofb_suspend(struct platfor
+               info->fbops->fb_sync(info);
++#ifdef CONFIG_FB_TMIO_ACCELL
+       printk(KERN_INFO "tmiofb: switching to polling\n");
+       par->use_polling = true;
++#endif
+       tmiofb_hw_stop(dev);
+       if (cell->suspend)
diff --git a/packages/kexecboot/linux-kexecboot-2.6.24/tosa/tosa-bl-fixup.diff b/packages/kexecboot/linux-kexecboot-2.6.24/tosa/tosa-bl-fixup.diff
new file mode 100644 (file)
index 0000000..c4a23d1
--- /dev/null
@@ -0,0 +1,103 @@
+Index: linux-2.6.24/drivers/video/backlight/tosa_bl.c
+===================================================================
+--- linux-2.6.24.orig/drivers/video/backlight/tosa_bl.c        2008-11-15 22:59:51.592985003 +0300
++++ linux-2.6.24/drivers/video/backlight/tosa_bl.c     2008-11-18 04:08:13.021416618 +0300
+@@ -76,6 +76,8 @@ static void pxa_nssp_output(struct tosa_
+
+ static void tosa_set_backlight(struct tosa_bl_data *data, int brightness)
+ {
++      pr_debug("tosa_set_backlight\n");
++
+       /* SetBacklightDuty */
+       i2c_smbus_write_byte_data(&data->client, DAC_CH2, (unsigned char)brightness);
+
+@@ -91,7 +93,7 @@ static void tosa_set_backlight(struct to
+
+ static void tosa_lcd_tg_init(struct tosa_bl_data *data)
+ {
+-      dev_dbg(&data->bl_dev->dev, "tosa_lcd_init\n");
++      pr_debug("tosa_lcd_init\n");
+
+       /* L3V On */
+       set_scoop_gpio( &tosascoop_jc_device.dev,TOSA_SCOOP_JC_TC6393XB_L3V_ON);
+@@ -116,7 +118,7 @@ static void tosa_lcd_tg_on(struct tosa_b
+
+       tosa_lcd_tg_init(data);
+
+-      dev_dbg(&data->bl_dev->dev, "tosa_lcd_on: %04x (%d)\n", value, mode->yres);
++      pr_debug("tosa_lcd_on: %04x (%d)\n", value, mode->yres);
+       pxa_nssp_output(data, TG_PNLCTL, value);
+
+       /* TG LCD pannel power up */
+@@ -129,12 +131,15 @@ static void tosa_lcd_tg_on(struct tosa_b
+
+       /* set common voltage */
+       i2c_smbus_write_byte_data(&data->client, DAC_CH1, data->comadj);
++
++      tosa_set_backlight(data, data->bl_dev->props.brightness);
++
+ }
+
+ static void tosa_lcd_tg_off(struct tosa_bl_data *data)
+ {
+       tosa_set_backlight(data, 0);
+-      dev_dbg(&data->bl_dev->dev, "tosa_lcd_off\n");
++      pr_debug("tosa_lcd_off\n");
+       /* TG LCD VHSA off */
+       pxa_nssp_output(data, TG_PINICTL,0x4);
+       mdelay(50);
+@@ -158,8 +163,6 @@ static int tosa_bl_update_status(struct
+       struct tosa_bl_data *data = dev_get_drvdata(&dev->dev);
+       int new_power = max(props->power, props->fb_blank);
+
+-      tosa_set_backlight(data, props->brightness);
+-
+       if (new_power)
+               tosa_lcd_tg_off(data);
+       else
+@@ -223,22 +226,26 @@ static int tosa_bl_detect_client(struct
+
+       err = gpio_request(TOSA_TC6393XB_BL_C20MA, "backlight");
+       if (err) {
+-              dev_dbg(&data->bl_dev->dev, "Unable to request gpio!\n");
++              printk(KERN_ERR "tosa-bl; Unable to request gpio!\n");
+               goto err_gpio_bl;
+       }
+
+       err = gpio_request(TOSA_TC6393XB_TG_ON, "tg");
+       if (err) {
+-              dev_dbg(&data->bl_dev->dev, "Unable to request gpio!\n");
++              printk(KERN_ERR "tosa-bl: Unable to request gpio!\n");
+               goto err_gpio_tg;
+       }
+
+       err = ssp_init(&data->nssp_dev,2,0);
+       if (err) {
+-              dev_err(&data->bl_dev->dev, "Unable to register NSSP handler!\n");
++              printk(KERN_ERR "tosa-bl: Unable to register NSSP handler!\n");
+               goto err_ssp_init;
+       }
+
++      pxa_gpio_mode(GPIO83_NSSP_TX);
++      pxa_gpio_mode(GPIO81_NSSP_CLK_OUT);
++      pxa_gpio_mode(GPIO82_NSSP_FRM_OUT);
++
+       /* Tell the i2c layer a new client has arrived */
+       err = i2c_attach_client(client);
+       if (err)
+@@ -269,7 +276,6 @@ static int tosa_bl_detect_client(struct
+ err_fb_register:
+       backlight_device_unregister(data->bl_dev);
+ err_bl_register:
+-      tosa_set_backlight(data, 0);
+       tosa_lcd_tg_off(data);
+
+       err = i2c_detach_client(client);
+@@ -296,7 +302,6 @@ static int tosa_bl_detach_client(struct
+
+       backlight_device_unregister(data->bl_dev);
+
+-      tosa_set_backlight(data, 0);
+       tosa_lcd_tg_off(data);
+
+       /* Try to detach the client from i2c space */
index 43913e8..9a89b6a 100644 (file)
@@ -6,7 +6,7 @@ DEFAULT_PREFERENCE = "-1"
 DEFAULT_PREFERENCE_collie = "-1"
 DEFAULT_PREFERENCE_poodle = "1"
 DEFAULT_PREFERENCE_qemux86 = "-1"
-DEFAULT_PREFERENCE_tosa = "-1"
+DEFAULT_PREFERENCE_tosa = "1"
 
 # Handy URLs
 # git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux-2.6.git;protocol=git;tag=ef7d1b244fa6c94fb76d5f787b8629df64ea4046
@@ -121,8 +121,6 @@ SRC_URI_append_tosa = "\
            file://tosa/0014-tosa_udc_use_gpio_vbus.patch.patch;patch=1 \
            file://tosa/0015-sharpsl-export-params.patch;patch=1 \
            file://tosa/0016-This-patch-fixes-the-pxa25x-clocks-definitions-to-ad.patch;patch=1 \
-           file://tosa/0017-Convert-pxa2xx-UDC-to-use-debugfs.patch;patch=1 \
-           file://tosa/0018-Fix-the-pxa2xx_udc-to-balance-calls-to-clk_enable-cl.patch;patch=1 \
            file://tosa/0026-I-don-t-think-we-should-check-for-IRQs-when-determin.patch;patch=1 \
            file://tosa/0027-Add-LiMn-one-of-the-most-common-for-small-non-recha.patch;patch=1 \
            file://tosa/0028-Add-suspend-resume-wakeup-support-for-pda_power.patch;patch=1 \
@@ -173,7 +171,12 @@ SRC_URI_append_tosa = "\
            file://tosa/0043-Use-clocklib-for-sa1100-sub-arch.patch;patch=1 \
            file://tosa/0056-Support-resetting-by-asserting-GPIO-pin.patch;patch=1 \
            file://tosa/0057-Clean-up-tosa-resetting.patch;patch=1 \
+           file://tosa/0001-pxa2xx-ac97-switch-AC-unit-to-correct-state-before.patch;patch=1 \
+          file://tosa/tosa-bl-fixup.diff;patch=1 \
+           file://tosa/tmiofb-fix-unaccel.patch;patch=1 \
            "
+#           file://tosa/0017-Convert-pxa2xx-UDC-to-use-debugfs.patch;patch=1 \
+#           file://tosa/0018-Fix-the-pxa2xx_udc-to-balance-calls-to-clk_enable-cl.patch;patch=1 \
 
 SRC_URI_append_htcuniversal ="\
        file://htcuni-acx.patch;patch=1;status=external \