linux_2.6.28: add collie patches
authorThomas Kunze <thommycheck@gmx.de>
Tue, 10 Feb 2009 19:59:05 +0000 (20:59 +0100)
committerThomas Kunze <thommycheck@gmx.de>
Tue, 10 Feb 2009 19:59:05 +0000 (20:59 +0100)
25 files changed:
packages/linux/linux-2.6.28/collie/0001-collie-start-scoop-converton-to-new-api.patch [new file with mode: 0644]
packages/linux/linux-2.6.28/collie/0002-add-locomo_spi-driver.patch [new file with mode: 0644]
packages/linux/linux-2.6.28/collie/0003-enable-cpufreq-for-collie.patch [new file with mode: 0644]
packages/linux/linux-2.6.28/collie/0004-fix-dma-for-SA1100.patch [new file with mode: 0644]
packages/linux/linux-2.6.28/collie/0005-fix-collie-keyboard-bug.patch [new file with mode: 0644]
packages/linux/linux-2.6.28/collie/0006-add-collie-flash-hack.patch [new file with mode: 0644]
packages/linux/linux-2.6.28/collie/0007-hostap-workaround-for-buggy-sa1100-pcmcia-driver.patch [new file with mode: 0644]
packages/linux/linux-2.6.28/collie/0008-fix-collie-suspend-hack.patch [new file with mode: 0644]
packages/linux/linux-2.6.28/collie/0009-add-sa1100-usb-gadget-driver-hack.patch [new file with mode: 0644]
packages/linux/linux-2.6.28/collie/0010-mmc_spi-add-suspend-and-resume-callbacks.patch [new file with mode: 0644]
packages/linux/linux-2.6.28/collie/0011-move-drivers-mfd-.h-to-include-linux-mfd.patch [new file with mode: 0644]
packages/linux/linux-2.6.28/collie/0012-move-ucb1200-ts-driver.patch [new file with mode: 0644]
packages/linux/linux-2.6.28/collie/0013-add-collie-touchscreen-driver.patch [new file with mode: 0644]
packages/linux/linux-2.6.28/collie/0014-collie-locomo-led-change-default-trigger.patch [new file with mode: 0644]
packages/linux/linux-2.6.28/collie/0015-SA1100-make-gpio_to_irq-and-reverse-a-macro.patch [new file with mode: 0644]
packages/linux/linux-2.6.28/collie/0016-add-gpiolib-support-to-ucb1x00.patch [new file with mode: 0644]
packages/linux/linux-2.6.28/collie/0017-collie-convert-to-gpiolib-for-ucb1x00.patch [new file with mode: 0644]
packages/linux/linux-2.6.28/collie/0018-collie-add-battery-driver.patch [new file with mode: 0644]
packages/linux/linux-2.6.28/collie/0019-collie-support-pda_power-driver.patch [new file with mode: 0644]
packages/linux/linux-2.6.28/collie/0020-remove-collie_pm.c.patch [new file with mode: 0644]
packages/linux/linux-2.6.28/collie/0021-mmc-trivial-annotation-of-blocks.patch [new file with mode: 0644]
packages/linux/linux-2.6.28/collie/0022-mmc_block-print-better-error-messages.patch [new file with mode: 0644]
packages/linux/linux-2.6.28/collie/0023-mmc_block-ensure-all-sectors-that-do-not-have-error.patch [new file with mode: 0644]
packages/linux/linux-2.6.28/collie/defconfig [new file with mode: 0644]
packages/linux/linux_2.6.28.bb

diff --git a/packages/linux/linux-2.6.28/collie/0001-collie-start-scoop-converton-to-new-api.patch b/packages/linux/linux-2.6.28/collie/0001-collie-start-scoop-converton-to-new-api.patch
new file mode 100644 (file)
index 0000000..51c161f
--- /dev/null
@@ -0,0 +1,106 @@
+From 4765c85914d55590c6d17b6cf9e6f7964d1af108 Mon Sep 17 00:00:00 2001
+From: Dmitry Baryshkov <dbaryshkov@gmail.com>
+Date: Tue, 28 Oct 2008 21:41:39 +0300
+Subject: [PATCH 01/23] collie: start scoop converton to new api
+
+Start converting scoop gpio access to new API instead of old
+deprecated one.
+
+Signed-off-by: Dmitry Baryshkov <dbaryshkov@gmail.com>
+---
+ arch/arm/mach-sa1100/collie.c              |   28 +++++++++++++++++++++++-----
+ arch/arm/mach-sa1100/include/mach/collie.h |    7 ++++---
+ 2 files changed, 27 insertions(+), 8 deletions(-)
+
+diff --git a/arch/arm/mach-sa1100/collie.c b/arch/arm/mach-sa1100/collie.c
+index fe28999..8cf267f 100644
+--- a/arch/arm/mach-sa1100/collie.c
++++ b/arch/arm/mach-sa1100/collie.c
+@@ -25,6 +25,7 @@
+ #include <linux/mtd/mtd.h>
+ #include <linux/mtd/partitions.h>
+ #include <linux/timer.h>
++#include <linux/gpio.h>
+ #include <mach/hardware.h>
+ #include <asm/mach-types.h>
+@@ -55,6 +56,7 @@ static struct resource collie_scoop_resources[] = {
+ static struct scoop_config collie_scoop_setup = {
+       .io_dir         = COLLIE_SCOOP_IO_DIR,
+       .io_out         = COLLIE_SCOOP_IO_OUT,
++      .gpio_base      = COLLIE_SCOOP_GPIO_BASE,
+ };
+ struct platform_device colliescoop_device = {
+@@ -196,18 +198,34 @@ static struct mtd_partition collie_partitions[] = {
+       }
+ };
++static int collie_flash_init(void)
++{
++      int rc;
++      rc = gpio_request(COLLIE_GPIO_VPEN, "flash Vpp enable");
++      if (rc)
++              return rc;
++
++      rc = gpio_direction_output(COLLIE_GPIO_VPEN, 1);
++      if (rc)
++              gpio_free(COLLIE_GPIO_VPEN);
++
++      return rc;
++}
++
+ static void collie_set_vpp(int vpp)
+ {
+-      write_scoop_reg(&colliescoop_device.dev, SCOOP_GPCR, read_scoop_reg(&colliescoop_device.dev, SCOOP_GPCR) | COLLIE_SCP_VPEN);
+-      if (vpp)
+-              write_scoop_reg(&colliescoop_device.dev, SCOOP_GPWR, read_scoop_reg(&colliescoop_device.dev, SCOOP_GPWR) | COLLIE_SCP_VPEN);
+-      else
+-              write_scoop_reg(&colliescoop_device.dev, SCOOP_GPWR, read_scoop_reg(&colliescoop_device.dev, SCOOP_GPWR) & ~COLLIE_SCP_VPEN);
++      gpio_set_value(COLLIE_GPIO_VPEN, vpp);
+ }
++static void collie_flash_exit(void)
++{
++      gpio_free(COLLIE_GPIO_VPEN);
++}
+ static struct flash_platform_data collie_flash_data = {
+       .map_name       = "cfi_probe",
++      .init           = collie_flash_init,
+       .set_vpp        = collie_set_vpp,
++      .exit           = collie_flash_exit,
+       .parts          = collie_partitions,
+       .nr_parts       = ARRAY_SIZE(collie_partitions),
+ };
+diff --git a/arch/arm/mach-sa1100/include/mach/collie.h b/arch/arm/mach-sa1100/include/mach/collie.h
+index 69e9624..9bc5349 100644
+--- a/arch/arm/mach-sa1100/include/mach/collie.h
++++ b/arch/arm/mach-sa1100/include/mach/collie.h
+@@ -14,6 +14,7 @@
+ #define __ASM_ARCH_COLLIE_H
++#define COLLIE_SCOOP_GPIO_BASE        (GPIO_MAX + 1)
+ #define COLLIE_SCP_CHARGE_ON  SCOOP_GPCR_PA11
+ #define COLLIE_SCP_DIAG_BOOT1 SCOOP_GPCR_PA12
+ #define COLLIE_SCP_DIAG_BOOT2 SCOOP_GPCR_PA13
+@@ -21,13 +22,13 @@
+ #define COLLIE_SCP_MUTE_R     SCOOP_GPCR_PA15
+ #define COLLIE_SCP_5VON               SCOOP_GPCR_PA16
+ #define COLLIE_SCP_AMP_ON     SCOOP_GPCR_PA17
+-#define COLLIE_SCP_VPEN               SCOOP_GPCR_PA18
++#define COLLIE_GPIO_VPEN      (COLLIE_SCOOP_GPIO_BASE + 7)
+ #define COLLIE_SCP_LB_VOL_CHG SCOOP_GPCR_PA19
+ #define COLLIE_SCOOP_IO_DIR   ( COLLIE_SCP_CHARGE_ON | COLLIE_SCP_MUTE_L | COLLIE_SCP_MUTE_R | \
+-                              COLLIE_SCP_5VON | COLLIE_SCP_AMP_ON | COLLIE_SCP_VPEN | \
++                              COLLIE_SCP_5VON | COLLIE_SCP_AMP_ON | \
+                               COLLIE_SCP_LB_VOL_CHG )
+-#define COLLIE_SCOOP_IO_OUT   ( COLLIE_SCP_MUTE_L | COLLIE_SCP_MUTE_R | COLLIE_SCP_VPEN | \
++#define COLLIE_SCOOP_IO_OUT   ( COLLIE_SCP_MUTE_L | COLLIE_SCP_MUTE_R | \
+                               COLLIE_SCP_CHARGE_ON )
+ /* GPIOs for which the generic definition doesn't say much */
+-- 
+1.5.6.5
+
diff --git a/packages/linux/linux-2.6.28/collie/0002-add-locomo_spi-driver.patch b/packages/linux/linux-2.6.28/collie/0002-add-locomo_spi-driver.patch
new file mode 100644 (file)
index 0000000..7530bee
--- /dev/null
@@ -0,0 +1,1228 @@
+From dae5d7c71ba47bdd0603d5cc3e8a3dfe28d209a0 Mon Sep 17 00:00:00 2001
+From: Thomas Kunze <thommycheck@gmx.de>
+Date: Mon, 20 Oct 2008 17:30:32 +0200
+Subject: [PATCH 02/23] add locomo_spi driver
+
+---
+ drivers/spi/Kconfig      |    4 +
+ drivers/spi/Makefile     |    1 +
+ drivers/spi/locomo_spi.c | 1097 ++++++++++++++++++++++++++++++++++++++++++++++
+ drivers/spi/locomo_spi.h |   75 ++++
+ 4 files changed, 1177 insertions(+), 0 deletions(-)
+ create mode 100644 drivers/spi/locomo_spi.c
+ create mode 100644 drivers/spi/locomo_spi.h
+
+diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig
+index b9d0efb..aa3c60a 100644
+--- a/drivers/spi/Kconfig
++++ b/drivers/spi/Kconfig
+@@ -123,6 +123,10 @@ config SPI_MPC52xx_PSC
+         This enables using the Freescale MPC52xx Programmable Serial
+         Controller in master SPI mode.
++config SPI_LOCOMO
++      tristate "Locomo SPI master"
++      depends on SPI_MASTER && SHARP_LOCOMO && EXPERIMENTAL
++
+ config SPI_MPC83xx
+       tristate "Freescale MPC83xx/QUICC Engine SPI controller"
+       depends on (PPC_83xx || QUICC_ENGINE) && EXPERIMENTAL
+diff --git a/drivers/spi/Makefile b/drivers/spi/Makefile
+index ccf18de..794dd45 100644
+--- a/drivers/spi/Makefile
++++ b/drivers/spi/Makefile
+@@ -29,6 +29,7 @@ obj-$(CONFIG_SPI_S3C24XX)            += spi_s3c24xx.o
+ obj-$(CONFIG_SPI_TXX9)                        += spi_txx9.o
+ obj-$(CONFIG_SPI_XILINX)              += xilinx_spi.o
+ obj-$(CONFIG_SPI_SH_SCI)              += spi_sh_sci.o
++obj-$(CONFIG_SPI_LOCOMO)                += locomo_spi.o
+ #     ... add above this line ...
+ # SPI protocol drivers (device/link on bus)
+diff --git a/drivers/spi/locomo_spi.c b/drivers/spi/locomo_spi.c
+new file mode 100644
+index 0000000..d3a4bd9
+--- /dev/null
++++ b/drivers/spi/locomo_spi.c
+@@ -0,0 +1,1097 @@
++#include <asm/io.h>
++#include <asm/irq.h>
++#include <linux/module.h>
++#include <linux/init.h>
++#include <linux/device.h>
++#include <linux/stat.h>
++#include <linux/delay.h>
++#include <linux/wait.h>
++#include <linux/interrupt.h>
++#include <asm/hardware/locomo.h>
++#include <asm/errno.h>
++#include <linux/mmc/host.h>
++#include <linux/spi/spi.h>
++#include <linux/spi/mmc_spi.h>
++#include <linux/workqueue.h>
++#include <linux/spinlock.h>
++#include <linux/list.h>
++#include "locomo_spi.h"
++static struct locomospi_dev * spidev;
++static struct work_struct transfer_wq;
++int  delay;
++
++char* transtxbuf=(char*)NULL;
++char* transrxbuf=(char*)NULL;
++int transfercount=0, transfersize=0;
++static DECLARE_WAIT_QUEUE_HEAD(transferqueue);
++/* MMC_SPI functions *********************************************************/
++
++static int locomommcspi_init(struct device *dev, irqreturn_t (*isr)(int, void*), void *mmc)
++{
++      int result;
++      result=request_irq(IRQ_LOCOMO_CARDDETECT, isr, IRQF_TRIGGER_FALLING | IRQF_TRIGGER_RISING, "locomo-spi",  mmc);
++      return result;
++}
++
++static void locomommcspi_exit(struct device *dev, void* mmc)
++{
++      free_irq(IRQ_LOCOMO_CARDDETECT, mmc);
++}
++
++static int locomommcspi_getro(struct device *dev)
++{
++      return locomo_gpio_read_level(spidev->ldev->dev.parent,LOCOMO_GPIO_WRITE_PROT) > 0 ? 1 : 0;
++}
++
++static void locomommcspi_setpower(struct device *dev, unsigned int mask)
++{
++      if(!mask && spidev->card_power)
++              locomospi_power(0);
++      else if( !spidev->card_power )
++              locomospi_power(1);
++
++}
++
++
++static struct mmc_spi_platform_data colliemmc ={
++      .init           = locomommcspi_init,
++      .exit           = locomommcspi_exit,
++      .detect_delay   = 200,
++      .get_ro         = locomommcspi_getro,
++      .ocr_mask       = MMC_VDD_32_33 | MMC_VDD_33_34,
++      .setpower       = locomommcspi_setpower,
++      .powerup_msecs  = 200,
++};
++
++/* Utility function **********************************************************/
++
++static void locomospi_power(int on)
++{
++      locomo_gpio_write(spidev->ldev->dev.parent, LOCOMO_GPIO_CARD_POWER, on);
++      spidev->card_power=on;
++      printk(KERN_DEBUG "locomospi: power %d\n",on);
++}
++
++static void locomospi_setclock(unsigned int div, unsigned int clock)
++{
++      u16 r = ioread16(spidev->base+LOCOMO_SPIMD);
++      div &= 0x7;
++      clock &= 0x3;
++      if(clock != spidev->clock_base || div != spidev->clock_div){
++              r &= ~(LOCOMO_SPI_XSEL  | LOCOMO_SPI_CLKSEL | LOCOMO_SPI_XEN);
++              iowrite16(r,spidev->base+LOCOMO_SPIMD);
++              r |=  (div | (clock <<3) | LOCOMO_SPI_XEN);
++              iowrite16(r,spidev->base+LOCOMO_SPIMD);
++              spidev->clock_div = div;
++              spidev->clock_base = clock;
++              udelay(300);
++      }
++
++}
++// returns 1 if card ist present, 0 otherwise
++static int locomospi_carddetect()
++{
++      return (locomo_gpio_read_level(spidev->ldev->dev.parent,LOCOMO_GPIO_CARD_DETECT)>0)?0:1;
++}
++
++static void locomospi_setcs(int high)
++{
++      u16 r;
++      printk(KERN_DEBUG "locomospi: cs %d\n",high);
++      r = ioread16(spidev->base + LOCOMO_SPICT);
++      if(high)
++              r |= LOCOMO_SPI_CS;
++      else
++              r &= ~LOCOMO_SPI_CS;
++      iowrite16(r, spidev->base + LOCOMO_SPICT);
++}
++
++static void locomospi_reg_open()
++{
++      u16 r;
++      spidev->clock_div = DIV_64;
++      spidev->clock_base = CLOCK_18MHZ;
++      locomospi_power(1);
++      msleep(100);
++//    iowrite16( 0xec00 | (CLOCK_18MHZ <<3)|DIV_64, spidev->base+LOCOMO_SPIMD);
++      iowrite16( LOCOMO_SPI_MSB1ST | LOCOMO_SPI_DOSTAT | LOCOMO_SPI_RCPOL | LOCOMO_SPI_TCPOL 
++                      |(CLOCK_18MHZ <<3) | DIV_64, spidev->base+LOCOMO_SPIMD);
++//    if(locomospi_carddetect()){
++              r = ioread16(spidev->base+LOCOMO_SPIMD);
++              r |= LOCOMO_SPI_XON;
++              iowrite16( r, spidev->base+LOCOMO_SPIMD);
++              r = ioread16(spidev->base+LOCOMO_SPIMD);
++              r |= LOCOMO_SPI_XEN;
++              iowrite16( r, spidev->base+LOCOMO_SPIMD);
++//    }
++      iowrite16( LOCOMO_SPI_CS, spidev->base+LOCOMO_SPICT);
++      r = ioread16(spidev->base+LOCOMO_SPICT);
++      r |= (LOCOMO_SPI_CEN | LOCOMO_SPI_RXUEN | LOCOMO_SPI_ALIGNEN);
++      iowrite16( r, spidev->base+LOCOMO_SPICT);
++      udelay(200);
++      r = ioread16(spidev->base+LOCOMO_SPICT);
++      iowrite16(r, spidev->base+LOCOMO_SPICT);
++      r = ioread16(spidev->base+LOCOMO_SPICT);
++      r &= ~LOCOMO_SPI_CS;
++      iowrite16(r, spidev->base+LOCOMO_SPICT);
++}
++
++static void locomospi_reg_release()
++{
++      u16 r;
++      r = ioread16(spidev->base+LOCOMO_SPICT);
++      r &= ~LOCOMO_SPI_CEN;
++      iowrite16(r, spidev->base+LOCOMO_SPICT);
++      r = ioread16(spidev->base+LOCOMO_SPIMD);
++      r &= ~LOCOMO_SPI_XEN;
++      iowrite16(r, spidev->base+LOCOMO_SPIMD);
++      r = ioread16(spidev->base+LOCOMO_SPIMD);
++      r &= ~LOCOMO_SPI_XON;
++      iowrite16(r, spidev->base+LOCOMO_SPIMD);
++      r = ioread16(spidev->base+LOCOMO_SPICT);
++      r |= LOCOMO_SPI_XEN;
++      iowrite16(r, spidev->base+LOCOMO_SPICT);
++      locomospi_power(0);
++}
++#if 0
++static int txrx(const char* txbuffer, char* rxbuffer, int size)
++{
++      u16 r = ioread16(spidev->base+LOCOMO_SPICT);
++      r |= LOCOMO_SPI_ALIGNEN;
++      iowrite16(r, spidev->base+LOCOMO_SPICT);
++      printk(KERN_DEBUG "locomospi: %d bytes to prozess\n",size);
++      /* initialize global vars for isr */
++      transfercount=0; transfersize=size; 
++      transtxbuf=txbuffer; transrxbuf=rxbuffer;
++
++      /* start transmit and go sleep  isr will wake us*/
++      enable_irq(IRQ_LOCOMO_SPI_TEND);
++      iowrite8(txbuffer[0], spidev->base+LOCOMO_SPITD);
++      wait_event(transferqueue, transfercount >= transfersize);
++      disable_irq(IRQ_LOCOMO_SPI_TEND);
++      transrxbuf=NULL; transtxbuf=NULL;
++      
++      r = ioread16(spidev->base+LOCOMO_SPICT);
++      r &= ~LOCOMO_SPI_ALIGNEN;
++      iowrite16(r, spidev->base+LOCOMO_SPICT);
++      int i;
++      for(i=0; i< size; i++)
++              printk(KERN_DEBUG "locomospi: sent: %x  received: %x \n",txbuffer[i], rxbuffer[i]);
++      
++      
++      return size;
++}
++
++
++static int tx(const char* txbuffer, int size)
++{
++      printk(KERN_DEBUG "locomospi: %d bytes to send\n",size);
++      /* initialize global vars for isr */
++      transfercount=0; transfersize=size; 
++      transtxbuf=txbuffer; 
++
++      /* start transmit and go sleep  isr will wake us*/
++      enable_irq(IRQ_LOCOMO_SPI_RFW);
++      iowrite8(txbuffer[0], spidev->base+LOCOMO_SPITD);
++      wait_event(transferqueue, transfercount >= transfersize);
++      disable_irq(IRQ_LOCOMO_SPI_RFW);
++      transtxbuf=NULL;
++      
++      int i;
++      for(i=0; i< size; i++)
++              printk(KERN_DEBUG "locomospi: sent: %x\n",txbuffer[i]);
++      
++      
++      return size;
++}
++
++static int rx(char* rxbuffer, int size)
++{
++      printk(KERN_DEBUG "locomospi: %d bytes to read\n",size);
++      /* initialize global vars for isr */
++      transfercount=0; transfersize=size; 
++      transrxbuf=rxbuffer;
++
++      /* start transmit and go sleep  isr will wake us*/
++      enable_irq(IRQ_LOCOMO_SPI_RFR);
++      rxbuffer[0]=ioread8(spidev->base+LOCOMO_SPIRD);
++      wait_event(transferqueue, transfercount >= transfersize);
++      disable_irq(IRQ_LOCOMO_SPI_RFR);
++      transrxbuf=NULL;
++      
++      int i;
++      for(i=0; i< size; i++)
++              printk(KERN_DEBUG "locomospi: received: %x \n", rxbuffer[i]);
++      
++      
++      return size;
++}
++
++#else
++static int txrx(const char* txbuffer, char* rxbuffer, int size)
++{
++      int i=0,j=0;
++      int wait;
++      u16 r;
++/*    char * txback = kmalloc(size * sizeof(char), GFP_KERNEL);
++      memcpy(txback, txbuffer, size); 
++*/    
++      if(spidev->clock_div == 4)
++              wait = 0x10000;
++      else
++              wait = 8;
++      
++//    printk(KERN_DEBUG "locomospi: txrx %d bytes to prozess\n",size);
++      
++//    r = ioread16(spidev->base+LOCOMO_SPICT);
++//    r |= LOCOMO_SPI_ALIGNEN;
++//    iowrite16(r, spidev->base+LOCOMO_SPICT);
++      //discard first bogus byte
++
++      ioread8(spidev->base+LOCOMO_SPIRD);
++      for(i=0; i<size; i++){
++              for(j=0; j <= wait; j++){
++                      if(ioread16(spidev->base+LOCOMO_SPIST) & LOCOMO_SPI_RFW)
++                              break;
++              }
++              iowrite8(txbuffer[i], spidev->base+LOCOMO_SPITD);
++              ndelay(delay);
++              
++              for(j=0; j <= wait; j++){
++                      if(ioread16(spidev->base+LOCOMO_SPIST) & LOCOMO_SPI_RFR)
++                              break;
++              }
++              rxbuffer[i] = ioread8(spidev->base+LOCOMO_SPIRD);
++              ndelay(delay);
++      }
++//    r = ioread16(spidev->base+LOCOMO_SPICT);
++//    r &= ~LOCOMO_SPI_ALIGNEN;
++//    iowrite16(r, spidev->base+LOCOMO_SPICT);
++      
++/*    for(j=0; j< size; j++)
++              printk(KERN_DEBUG "locomospi: sent: %x  received: %x \n",txback[j], rxbuffer[j]);
++      
++      kfree(txback);  
++*/    return i;
++}
++
++static int tx(const char* buffer, int size)
++{
++      int i=0,j=0;
++      int wait;
++      u16 r;
++      if(spidev->clock_div == 4)
++              wait = 0x10000;
++      else
++              wait = 8;
++      r = ioread16(spidev->base+LOCOMO_SPICT);
++      r &= ~LOCOMO_SPI_ALIGNEN;
++      iowrite16(r, spidev->base+LOCOMO_SPICT);
++
++//    printk(KERN_DEBUG "locomospi: tx %d bytes to transmit\n",size);
++      for(i=0; i<size; i++){
++              for(j=0; j <= wait; j++){
++                      if(ioread16(spidev->base+LOCOMO_SPIST) & LOCOMO_SPI_RFW)
++                              break;
++              }
++              iowrite8(buffer[i], spidev->base+LOCOMO_SPITD);
++              ndelay(delay);
++      }
++
++      for(j=0; j <= wait; j++){
++              if(ioread16(spidev->base+LOCOMO_SPIST) & LOCOMO_SPI_TEND)
++                      break;
++      }
++      
++      r = ioread16(spidev->base+LOCOMO_SPICT);
++      r |= LOCOMO_SPI_ALIGNEN;
++      iowrite16(r, spidev->base+LOCOMO_SPICT);
++      
++//    for(j=0; j< size; j++)
++//            printk(KERN_DEBUG "locomospi: sent: %x \n", buffer[j]);
++//    printk(KERN_DEBUG "locomospi: tx %d bytes transmitted\n",i);
++      return i;
++}
++
++static int rx(char* buffer, int size)
++{
++      int i,j;
++      int wait;
++      u16 r;  
++      printk(KERN_DEBUG "locomospi: rx %d bytes to receive\n",size);
++      if(spidev->clock_div == 4)
++              wait = 0x10000;
++      else
++              wait = 8;
++      r = ioread16(spidev->base+LOCOMO_SPICT);
++      r &= ~LOCOMO_SPI_ALIGNEN;
++      iowrite16(r, spidev->base+LOCOMO_SPICT);
++
++      for(i=0; i<size; i++){
++
++              for(j=0; j <= wait; j++){
++                      if(ioread16(spidev->base+LOCOMO_SPIST) & LOCOMO_SPI_RFR)
++                              break;
++              }
++              buffer[i]= ioread8(spidev->base+LOCOMO_SPIRD);
++              ndelay(delay);
++      }
++      
++      r = ioread16(spidev->base+LOCOMO_SPICT);
++      r |= LOCOMO_SPI_ALIGNEN;
++      iowrite16(r, spidev->base+LOCOMO_SPICT);
++      
++      for(j=0; j< size; j++)
++              printk(KERN_DEBUG "locomospi: received: %x \n", buffer[j]);
++      printk(KERN_DEBUG "locomospi: rx %d bytes received\n",i);
++      return i;
++}
++#endif
++/*
++static irqreturn_t locomospi_rwready(int irq, void *dev_id)
++{
++      struct locomospi_dev* dev=(struct locomospi_dev*) dev_id;
++//    dev_dbg(&spidev->sdev->dev, "IRQ: %d\n", irq);
++//    printk(KERN_DEBUG "locomospi: IRQ: %d\n", irq);
++      wake_up_interruptible(&dev->waitqueue);
++      return IRQ_HANDLED;
++}
++*/
++static irqreturn_t locomospi_testisr(int irq, void *dev_id)
++{
++      char *buf="";
++      switch(irq){
++              case IRQ_LOCOMO_SPI_RFR: buf="RFR";
++                                       break;
++              case IRQ_LOCOMO_SPI_RFW: buf="RFW";
++                                       break;
++              case IRQ_LOCOMO_SPI_REND:buf="REND";
++                                       break;
++              case IRQ_LOCOMO_SPI_TEND:buf="TEND";
++                                       break;
++              case IRQ_LOCOMO_CARDDETECT:
++                                       buf="CARD_DETECT";
++                                       break;
++              default:                return IRQ_NONE;
++      }
++      printk(KERN_DEBUG "locomospi: IRQ: %s\n",buf);
++//    dev_dbg(&spidev->sdev->dev, "IRQ: %s\n",buf);
++      return IRQ_HANDLED;
++}
++static irqreturn_t locomospi_txrxisr(int irq, void *dev_id)
++{
++      if(transfercount < transfersize){
++              transrxbuf[transfercount++] = ioread8(spidev->base+LOCOMO_SPIRD);
++              iowrite8(transtxbuf[transfercount], spidev->base+LOCOMO_SPITD);                 
++      }
++      else{
++              /* transfer complete. wake up txrx */
++              wake_up(&transferqueue);
++      }
++      return IRQ_HANDLED;     
++}     
++
++static irqreturn_t locomospi_txisr(int irq, void *dev_id)
++{
++      if(transfercount < transfersize){
++              iowrite8(transtxbuf[transfercount++], spidev->base+LOCOMO_SPITD);               
++      }
++      else{
++              /* transfer complete. wake up txrx */
++              wake_up(&transferqueue);
++      }
++      return IRQ_HANDLED;     
++}     
++
++static irqreturn_t locomospi_rxisr(int irq, void *dev_id)
++{
++      if(transfercount < transfersize){
++              transrxbuf[transfercount++] = ioread8(spidev->base+LOCOMO_SPIRD);
++      }
++      else{
++              /* transfer complete. wake up txrx */
++              wake_up(&transferqueue);
++      }
++      return IRQ_HANDLED;     
++}     
++
++static void locomospi_clock(unsigned int Hz)
++{
++      u16 r;
++      printk(KERN_DEBUG "locomospi: changing clock to: %d\n", Hz);
++      if(Hz == 0){
++              r = ioread16(spidev->base+LOCOMO_SPIMD);
++              r &= ~LOCOMO_SPI_XON;
++              iowrite16(r, spidev->base+LOCOMO_SPIMD);
++      }
++      else if(Hz >= 24576000){
++              r = ioread16(spidev->base+LOCOMO_SPIMD);
++              r |= LOCOMO_SPI_XON;
++              iowrite16(r, spidev->base+LOCOMO_SPIMD);
++              locomospi_setclock(DIV_1, CLOCK_25MHZ);
++              delay=41;
++      }
++      else if(Hz >= 22579200){
++              r = ioread16(spidev->base+LOCOMO_SPIMD);
++              r |= LOCOMO_SPI_XON;
++              iowrite16(r, spidev->base+LOCOMO_SPIMD);
++              locomospi_setclock(DIV_1, CLOCK_22MHZ);
++              delay=45;
++      }
++      else if(Hz >= 18432000){
++              r = ioread16(spidev->base+LOCOMO_SPIMD);
++              r |= LOCOMO_SPI_XON;
++              iowrite16(r, spidev->base+LOCOMO_SPIMD);
++              locomospi_setclock(DIV_1, CLOCK_18MHZ);
++              delay=55;
++      }
++      else if(Hz >= 12288000){
++              r = ioread16(spidev->base+LOCOMO_SPIMD);
++              r |= LOCOMO_SPI_XON;
++              iowrite16(r, spidev->base+LOCOMO_SPIMD);
++              locomospi_setclock(DIV_2, CLOCK_25MHZ);
++              delay=82;
++      }
++      else if(Hz >= 11289600){
++              r = ioread16(spidev->base+LOCOMO_SPIMD);
++              r |= LOCOMO_SPI_XON;
++              iowrite16(r, spidev->base+LOCOMO_SPIMD);
++              locomospi_setclock(DIV_2, CLOCK_22MHZ);
++              delay=89;
++      }
++      else if(Hz >= 9216000){
++              r = ioread16(spidev->base+LOCOMO_SPIMD);
++              r |= LOCOMO_SPI_XON;
++              iowrite16(r, spidev->base+LOCOMO_SPIMD);
++              locomospi_setclock(DIV_2, CLOCK_18MHZ);
++              delay=110;
++      }
++      else if(Hz >= 6144000){
++              r = ioread16(spidev->base+LOCOMO_SPIMD);
++              r |= LOCOMO_SPI_XON;
++              iowrite16(r, spidev->base+LOCOMO_SPIMD);
++              locomospi_setclock(DIV_4, CLOCK_25MHZ);
++              delay=164;
++      }
++      else if(Hz >= 5644800){
++              r = ioread16(spidev->base+LOCOMO_SPIMD);
++              r |= LOCOMO_SPI_XON;
++              iowrite16(r, spidev->base+LOCOMO_SPIMD);
++              locomospi_setclock(DIV_4, CLOCK_22MHZ);
++              delay=178;
++      }
++      else if(Hz >= 4608000){
++              r = ioread16(spidev->base+LOCOMO_SPIMD);
++              r |= LOCOMO_SPI_XON;
++              iowrite16(r, spidev->base+LOCOMO_SPIMD);
++              locomospi_setclock(DIV_4, CLOCK_18MHZ);
++              delay=218;
++      }
++      else if(Hz >= 3072000){
++              r = ioread16(spidev->base+LOCOMO_SPIMD);
++              r |= LOCOMO_SPI_XON;
++              iowrite16(r, spidev->base+LOCOMO_SPIMD);
++              locomospi_setclock(DIV_8, CLOCK_25MHZ);
++              delay=327;
++      }
++      else if(Hz >= 2822400){
++              r = ioread16(spidev->base+LOCOMO_SPIMD);
++              r |= LOCOMO_SPI_XON;
++              iowrite16(r, spidev->base+LOCOMO_SPIMD);
++              locomospi_setclock(DIV_8, CLOCK_22MHZ);
++              delay=355;
++      }
++      else if(Hz >= 2304000){
++              r = ioread16(spidev->base+LOCOMO_SPIMD);
++              r |= LOCOMO_SPI_XON;
++              iowrite16(r, spidev->base+LOCOMO_SPIMD);
++              locomospi_setclock(DIV_8, CLOCK_18MHZ);
++              delay=435;
++      }
++      else if(Hz >= 384000){
++              r = ioread16(spidev->base+LOCOMO_SPIMD);
++              r |= LOCOMO_SPI_XON;
++              iowrite16(r, spidev->base+LOCOMO_SPIMD);
++              locomospi_setclock(DIV_64, CLOCK_25MHZ);
++              delay=2605;
++      }
++      else if(Hz >= 352800){
++              r = ioread16(spidev->base+LOCOMO_SPIMD);
++              r |= LOCOMO_SPI_XON;
++              iowrite16(r, spidev->base+LOCOMO_SPIMD);
++              locomospi_setclock(DIV_64, CLOCK_22MHZ);
++              delay=2834;
++      }
++      else{ /* set to 288 KHz */
++              r = ioread16(spidev->base+LOCOMO_SPIMD);
++              r |= LOCOMO_SPI_XON;
++              iowrite16(r, spidev->base+LOCOMO_SPIMD);
++              locomospi_setclock(DIV_64, CLOCK_18MHZ);
++              delay=3473;
++      }
++      spidev->clock = Hz;
++}
++
++/* sysfs attributes used for debug *******************************************/
++
++/* SPI registers */
++ssize_t locomospi_showspimd(struct device_driver *drv, char *buf)
++{
++      return sprintf(buf, "0x%x\n", ioread16(spidev->base+LOCOMO_SPIMD));
++}
++
++ssize_t locomospi_storespimd(struct device_driver *drv, const char *buf, size_t count)
++{
++      iowrite16(simple_strtoul(buf, NULL, 16), spidev->base+LOCOMO_SPIMD);
++      return count;
++}
++static DRIVER_ATTR(spimd, S_IWUSR | S_IRUGO, locomospi_showspimd, locomospi_storespimd);
++
++ssize_t locomospi_showspict(struct device_driver *drv, char *buf)
++{
++      return sprintf(buf, "0x%x\n", ioread16(spidev->base+LOCOMO_SPICT));
++}
++
++ssize_t locomospi_storespict(struct device_driver *drv, const char *buf, size_t count)
++{
++      iowrite16(simple_strtoul(buf, NULL, 16), spidev->base+LOCOMO_SPICT);
++      return count;
++}
++static DRIVER_ATTR(spict, S_IWUSR | S_IRUGO, locomospi_showspict, locomospi_storespict);
++
++ssize_t locomospi_showspist(struct device_driver *drv, char *buf)
++{
++      return sprintf(buf, "0x%x\n", ioread16(spidev->base+LOCOMO_SPIST));
++}
++
++ssize_t locomospi_storespist(struct device_driver *drv, const char *buf, size_t count)
++{
++      iowrite16(simple_strtoul(buf, NULL, 16), spidev->base+LOCOMO_SPIST);
++      return count;
++}
++static DRIVER_ATTR(spist, S_IWUSR | S_IRUGO, locomospi_showspist, locomospi_storespist);
++
++ssize_t locomospi_showspitd(struct device_driver *drv, char *buf)
++{
++      return sprintf(buf, "0x%x\n", ioread16(spidev->base+LOCOMO_SPITD));
++}
++
++ssize_t locomospi_storespitd(struct device_driver *drv, const char *buf, size_t count)
++{
++      iowrite16(simple_strtoul(buf, NULL, 16), spidev->base+LOCOMO_SPITD);
++      return count;
++}
++static DRIVER_ATTR(spitd, S_IWUSR | S_IRUGO, locomospi_showspitd, locomospi_storespitd);
++
++ssize_t locomospi_showspird(struct device_driver *drv, char *buf)
++{
++      return sprintf(buf, "0x%x\n", ioread16(spidev->base+LOCOMO_SPIRD));
++}
++
++ssize_t locomospi_storespird(struct device_driver *drv, const char *buf, size_t count)
++{
++      iowrite16(simple_strtoul(buf, NULL, 16), spidev->base+LOCOMO_SPIRD);
++      return count;
++}
++static DRIVER_ATTR(spird, S_IWUSR | S_IRUGO, locomospi_showspird, locomospi_storespird);
++
++ssize_t locomospi_showspits(struct device_driver *drv, char *buf)
++{
++      return sprintf(buf, "0x%x\n", ioread16(spidev->base+LOCOMO_SPITS));
++}
++
++ssize_t locomospi_storespits(struct device_driver *drv, const char *buf, size_t count)
++{
++      iowrite16(simple_strtoul(buf, NULL, 16), spidev->base+LOCOMO_SPITS);
++      return count;
++}
++static DRIVER_ATTR(spits, S_IWUSR | S_IRUGO, locomospi_showspits, locomospi_storespits);
++
++ssize_t locomospi_showspirs(struct device_driver *drv, char *buf)
++{
++      return sprintf(buf, "0x%x\n", ioread16(spidev->base+LOCOMO_SPIRS));
++}
++
++ssize_t locomospi_storespirs(struct device_driver *drv, const char *buf, size_t count)
++{
++      iowrite16(simple_strtoul(buf, NULL, 16), spidev->base+LOCOMO_SPIRS);
++      return count;
++}
++static DRIVER_ATTR(spirs, S_IWUSR | S_IRUGO, locomospi_showspirs, locomospi_storespirs);
++
++/* MMC Card status */
++
++ssize_t locomospi_showpower(struct device_driver *drv, char *buf)
++{
++      return sprintf(buf, "%d\n", spidev->card_power);
++}
++
++ssize_t locomospi_storepower(struct device_driver *drv, const char *buf, size_t count)
++{
++      locomospi_power(simple_strtoul(buf, NULL, 10));
++      return count;
++}
++static DRIVER_ATTR(cardpower, S_IWUSR | S_IRUGO, locomospi_showpower, locomospi_storepower);
++
++ssize_t locomospi_detectcard(struct device_driver *drv, char *buf)
++{
++      return sprintf(buf, "%d\n",(locomo_gpio_read_level(spidev->ldev->dev.parent,LOCOMO_GPIO_CARD_DETECT)>0)?0:1);
++}
++static DRIVER_ATTR(carddetect, S_IRUGO, locomospi_detectcard, NULL);
++
++ssize_t locomospi_writeprotect(struct device_driver *drv, char *buf)
++{
++      return sprintf(buf, "%d\n",(locomo_gpio_read_level(spidev->ldev->dev.parent,LOCOMO_GPIO_WRITE_PROT)>0)?1:0);
++}
++static DRIVER_ATTR(cardwriteprotect, S_IRUGO, locomospi_writeprotect, NULL);
++
++
++ssize_t locomospi_showclock(struct device_driver *drv, char *buf)
++{
++      return sprintf(buf, "%d\n", spidev->clock);
++}
++
++ssize_t locomospi_storeclock(struct device_driver *drv, const char *buf, size_t count)
++{
++      locomospi_clock(simple_strtoul(buf, NULL, 10));
++      return count;
++}
++static DRIVER_ATTR(clock, S_IWUSR | S_IRUGO, locomospi_showclock, locomospi_storeclock);
++
++/* debug */
++ssize_t locomospi_showdelay(struct device_driver *drv, char *buf)
++{
++      return sprintf(buf, "%d\n", delay);
++}
++
++ssize_t locomospi_storedelay(struct device_driver *drv, const char *buf, size_t count)
++{
++      delay=simple_strtoul(buf,NULL,10);
++      return count;
++}
++static DRIVER_ATTR(delay, S_IWUSR | S_IRUGO, locomospi_showdelay, locomospi_storedelay);
++
++ssize_t locomospi_reset(struct device_driver *drv, const char *buf, size_t count)
++{
++      int choice = simple_strtoul(buf, NULL, 10);
++      char   buff[100];
++      u16 r; 
++      switch(choice){
++              case 0: locomospi_reg_release();
++                      schedule_timeout(2*HZ);
++                      locomospi_reg_open();
++                      break;
++              case 1: {
++                              char b1[] = "\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff";
++                              char b2[] = "\xff\x40\x00\x00\x00\x00\x95\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff";
++                              locomospi_setcs(1);
++                              txrx(b1,b1,17);
++                              locomospi_setcs(0);
++                              txrx(b2,b2,18);
++
++                      }
++                      break;
++              case 2: locomospi_setcs(1);
++                      txrx("\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff",buff,18);
++                      locomospi_setcs(0);
++                      txrx("\xff\x40\x00\x00\x00\x00\x95\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff",buff,17);
++                      break;
++              case 3: 
++                      r = ioread16(spidev->base+LOCOMO_SPIMD);
++                      r |= LOCOMO_SPI_LOOPBACK;
++                      iowrite16(r, spidev->base+LOCOMO_SPIMD);
++                      txrx("X",buff,1);
++                      txrx("abcdefghijklmnopqrstuvwxyz1234567890",buff,36);
++                      txrx("Y",buff,1);
++                      udelay(100);
++                      txrx("Z",buff,1);
++                      schedule_timeout(HZ);   
++                      txrx("abcdefghijklmnopqrstuvwxyz1234567890",buff,36);
++                      
++                      r = ioread16(spidev->base+LOCOMO_SPIMD);
++                      r &= ~LOCOMO_SPI_LOOPBACK;
++                      iowrite16(r, spidev->base+LOCOMO_SPIMD);
++                      break;
++              default: /* do nothing */;
++      }
++      return count;
++}
++static DRIVER_ATTR(reset, S_IWUSR, NULL, locomospi_reset);
++
++typedef struct locomo_reg_entry {
++        u32 addr;
++        char* name;
++} locomo_reg_entry_t;
++#define LCM     (sizeof(locomo_regs)/sizeof(locomo_reg_entry_t))
++static locomo_reg_entry_t locomo_regs[] =
++{
++/*      { addr,    name,     description } */
++        { 0x00, "VER" },
++        { 0x04, "ST" },
++        { 0x08, "C32K" },
++        { 0x0C, "ICR" },
++        { 0x10, "MCSX0" },
++        { 0x14, "MCSX1" },
++        { 0x18, "MCSX2" },
++        { 0x1C, "MCSX3" },
++        { 0x20, "ASD" },
++        { 0x28, "HSD" },
++        { 0x2C, "HSC" },
++        { 0x30, "TADC" },
++        { 0x38, "TC" },
++        { 0x3C, "CPSD" },
++        { 0x40, "KIB" },
++        { 0x44, "KSC" },
++        { 0x48, "KCMD" },
++        { 0x4C, "KIC" },
++        { 0x54, "ACC" },
++        { 0x60, "SPIMD" },
++        { 0x64, "SPICT" },
++        { 0x68, "SPIST" },
++        { 0x70, "SPIIS" },
++        { 0x74, "SPIWE" },
++        { 0x78, "SPIIE" },
++        { 0x7C, "SPIIR" },
++        { 0x80, "SPITD" },
++        { 0x84, "SPIRD" },
++        { 0x88, "SPITS" },
++        { 0x8C, "SPIRS" },
++        { 0x90, "GPD" },
++        { 0x94, "GPE" },
++        { 0x98, "GPL" },
++        { 0x9C, "GPO" },
++        { 0xa0, "GRIE" },
++        { 0xa4, "GFIE" },
++        { 0xa8, "GIS" },
++        { 0xac, "GWE" },
++        { 0xb0, "GIE" },
++        { 0xb4, "GIR" },
++        { 0xc8, "ALC" },
++        { 0xcc, "ALR" },
++        { 0xd0, "PAIF" },
++        { 0xd8, "LTC" },
++        { 0xdc, "LTINT" },
++        { 0xe0, "DAC" },
++        { 0xe8, "LPT0" },
++        { 0xec, "LPT1" },
++        { 0xfc, "TCR" },
++};
++
++static ssize_t lcm_show(struct device *dev, struct device_attribute *attr, char *buf)
++{
++      int base = spidev->base - LOCOMO_SPI; 
++      char b[4000]="";
++      char c[30];
++      int i;
++      for(i=0; i<LCM; i++){
++              sprintf(c,"%s:\t\t 0x%x\n",locomo_regs[i].name, ioread16(base + locomo_regs[i].addr));
++              strcat(b,c);
++      }
++      return sprintf(buf,"%s",b);
++}
++
++static DRIVER_ATTR(regs, 0444, lcm_show, NULL);
++
++
++/* SPI functions *************************************************************/
++
++static void locomospi_do_transfer(struct work_struct *wrk)
++{
++      struct list_head *mptr, *tptr, *mptr2;
++      struct spi_transfer *entry;
++      struct spi_message *msg;
++
++      list_for_each_safe(mptr, mptr2, &spidev->message_list){
++              msg = list_entry(mptr, struct spi_message, queue);
++
++              msg->status = 0;
++              msg->actual_length = 0;
++              list_for_each(tptr, &msg->transfers){
++                      entry = list_entry(tptr, struct spi_transfer, transfer_list);
++                      if(entry->tx_buf && entry->rx_buf){ //duplex
++                              txrx((char*) entry->tx_buf, (char*) entry->rx_buf, entry->len);                         
++                              msg->actual_length += entry->len;
++                      } else if(entry->tx_buf && !entry->rx_buf){ //write
++                              tx((char*) entry->tx_buf, entry->len);
++                              msg->actual_length += entry->len;
++                      } else if(!entry->tx_buf && entry->rx_buf){ //read
++                              rx((char*) entry->rx_buf, entry->len);
++                              msg->actual_length += entry->len;
++                      } else if(!entry->tx_buf && !entry->rx_buf){ //error
++                              dev_err(&spidev->sdev->dev, "do_transfer: no buffers allocated\n");
++                              msg->status = -EFAULT;
++                      }
++              }
++              spin_lock(&spidev->message_lock);
++              list_del(mptr);
++              spin_unlock(&spidev->message_lock);
++              msg->complete(msg->context);
++      }
++}
++
++static int locomospi_setup(struct spi_device *spi)
++{
++      if((spi->mode & SPI_CS_HIGH) != (spidev->spimode & SPI_CS_HIGH)) 
++              locomospi_setcs(spi->mode & SPI_CS_HIGH ? 1 : 0 );
++      if(spidev->clock != spi->max_speed_hz){
++              locomospi_clock(spi->max_speed_hz);
++      }
++      spidev->spimode = spi->mode;
++
++      return 0;
++}
++
++static int locomospi_transfer(struct spi_device *spi, struct spi_message *msg)
++{
++
++      spin_lock(&spidev->message_lock);
++      list_add_tail(&msg->queue, &spidev->message_list);
++      spin_unlock(&spidev->message_lock);
++      schedule_work(&transfer_wq);
++      return 0;
++}
++
++static struct locomo_driver locomo_spi_driver = {
++      .drv = {
++              .name = "locomo-spi",
++      },
++      .devid  = LOCOMO_DEVID_SPI,
++      .probe  = locomospi_probe,
++      .remove = locomospi_remove,
++#ifdef CONFIG_PM
++      .suspend = locomospi_suspend,
++      .resume = locomospi_resume,
++#endif
++};
++
++static struct spi_board_info board = {
++      .modalias       = "mmc_spi",
++      .platform_data  = (void*) &colliemmc,
++      .controller_data= NULL,
++      .irq            = 0,
++      .max_speed_hz   = 25000000,
++      .bus_num        = 0,
++      .chip_select    = 0,
++      .mode           = 0,
++};
++
++#ifdef CONFIG_PM
++static int locomospi_suspend(struct locomo_dev *dev, pm_message_t state)
++{
++      disable_irq(IRQ_LOCOMO_CARDDETECT);
++      return 0;
++}
++
++static int locomospi_resume(struct locomo_dev *dev)
++{
++      enable_irq(IRQ_LOCOMO_CARDDETECT);
++      return 0;
++}
++#endif
++
++static int locomospi_probe(struct locomo_dev *dev)
++{
++      int result=0;
++      printk(KERN_DEBUG "Collie MMC over SPI Driver\n");
++      spidev=kmalloc(sizeof(struct locomospi_dev),GFP_KERNEL);
++      if(!spidev){
++              return -ENOMEM;
++      }
++      spidev->ldev = dev;
++      spidev->card_power = 1;
++      spidev->spimode = 0;
++
++      if(!request_mem_region((unsigned long) dev->mapbase, dev->length, LOCOMO_DRIVER_NAME(dev))) {
++              dev_err(&dev->dev, " Can't aquire access to io memory\n");
++              return -EBUSY;
++      }
++      spidev->base=(unsigned long) dev->mapbase;
++      locomospi_reg_open();
++
++      locomo_gpio_set_dir(dev->dev.parent, LOCOMO_GPIO_CARD_POWER, 0);
++      locomo_gpio_set_dir(dev->dev.parent, LOCOMO_GPIO_CARD_DETECT, 1);
++      locomo_gpio_set_dir(dev->dev.parent, LOCOMO_GPIO_WRITE_PROT, 1);
++
++      result=driver_create_file(&locomo_spi_driver.drv, &driver_attr_cardpower);
++      if(result){
++              dev_err(&dev->dev, "error creating driver attribute\n");
++              goto region;
++      }
++      result=driver_create_file(&locomo_spi_driver.drv, &driver_attr_carddetect);
++      if(result){
++              dev_err(&dev->dev,"error creating driver attribute\n");
++              goto region;
++      }
++      result=driver_create_file(&locomo_spi_driver.drv, &driver_attr_cardwriteprotect);
++      if(result){
++              dev_err(&dev->dev, "error creating driver attribute\n");
++              goto region;
++      }
++      result=driver_create_file(&locomo_spi_driver.drv, &driver_attr_spimd);
++      if(result){
++              dev_err(&dev->dev, "error creating driver attribute\n");
++              goto region;
++      }
++      result=driver_create_file(&locomo_spi_driver.drv, &driver_attr_spict);
++      if(result){
++              dev_err(&dev->dev, "error creating driver attribute\n");
++              goto region;
++      }
++      result=driver_create_file(&locomo_spi_driver.drv, &driver_attr_spist);
++      if(result){
++              dev_err(&dev->dev, "error creating driver attribute\n");
++              goto region;
++      }
++      result=driver_create_file(&locomo_spi_driver.drv, &driver_attr_spitd);
++      if(result){
++              dev_err(&dev->dev, "error creating driver attribute\n");
++              goto region;
++      }
++      result=driver_create_file(&locomo_spi_driver.drv, &driver_attr_spird);
++      if(result){
++              dev_err(&dev->dev, "error creating driver attribute\n");
++              goto region;
++      }
++      result=driver_create_file(&locomo_spi_driver.drv, &driver_attr_spits);
++      if(result){
++              dev_err(&dev->dev, "error creating driver attribute\n");
++              goto region;
++      }
++      result=driver_create_file(&locomo_spi_driver.drv, &driver_attr_spirs);
++      if(result){
++              dev_err(&dev->dev, "error creating driver attribute\n");
++              goto region;
++      }
++      result=driver_create_file(&locomo_spi_driver.drv, &driver_attr_clock);
++      if(result){
++              dev_err(&dev->dev, "error creating driver attribute\n");
++              goto region;
++      }
++      result=driver_create_file(&locomo_spi_driver.drv, &driver_attr_delay);
++      if(result){
++              dev_err(&dev->dev, "error creating driver attribute\n");
++              goto region;
++      }
++      result=driver_create_file(&locomo_spi_driver.drv, &driver_attr_reset);
++      if(result){
++              dev_err(&dev->dev, "error creating driver attribute\n");
++              goto region;
++      }
++      result=driver_create_file(&locomo_spi_driver.drv, &driver_attr_regs);
++        if(result){
++                dev_err(&dev->dev, "error creating driver attribute\n");
++                goto region;
++        }
++      INIT_WORK(&transfer_wq, locomospi_do_transfer);
++      INIT_LIST_HEAD(&spidev->message_list);
++      spin_lock_init(&spidev->message_lock);
++      init_waitqueue_head(&spidev->waitqueue);
++      spidev->master=spi_alloc_master(&dev->dev,0);
++      if(!spidev->master){
++              result=-ENOMEM;
++              goto region;
++      }
++      spidev->master->bus_num = 0;
++      spidev->master->num_chipselect = 1;
++      spidev->master->setup = locomospi_setup;
++      spidev->master->transfer = locomospi_transfer;
++      spidev->sdev = spi_new_device(spidev->master, &board);
++      if(!spidev->sdev){
++              dev_err(&dev->dev, "failed to register spi device\n");
++              result = -EINVAL;
++              goto master;
++      }
++/*    result=request_irq(IRQ_LOCOMO_SPI_RFR, locomospi_testisr, IRQF_SHARED, "locomo-spi", (void*) spidev);
++      if(result) {
++              dev_err(&dev->dev, "Could not get IRQ: RFR\n");
++              goto regdev;
++      }
++      //disable_irq(IRQ_LOCOMO_SPI_RFR);
++*//*  result=request_irq(IRQ_LOCOMO_SPI_RFW, locomospi_testisr, IRQF_SHARED, "locomo-spi", (void*) spidev);
++      if(result) {
++              dev_err(&dev->dev, "Could not get IRQ: RFW\n");
++              goto irq1;
++      }
++      //disable_irq(IRQ_LOCOMO_SPI_RFW);
++*//*  result=request_irq(IRQ_LOCOMO_SPI_REND, locomospi_testisr, IRQF_SHARED, "locomo-spi", (void*) spidev);
++      if(result) {
++              dev_err(&dev->dev, "Could not get IRQ: REND\n");
++              goto irq2;
++      }
++*//*  result=request_irq(IRQ_LOCOMO_SPI_TEND, locomospi_testisr, IRQF_SHARED, "locomo-spi", (void*) spidev);
++      if(result) {
++              dev_err(&dev->dev, "Could not get IRQ: TEND\n");
++              goto irq3;
++      }
++      //disable_irq(IRQ_LOCOMO_SPI_TEND);     
++*/    spidev->workqueue = create_singlethread_workqueue("locomo-spi");
++      if(!spidev->workqueue){
++              dev_err(&dev->dev, "failed to create workqueue\n");
++              goto irq4;
++      }
++      result=spi_register_master(spidev->master);
++      if(result){
++              dev_err(&dev->dev, "failed to register spimaster\n");
++              goto wq;
++      }
++      return 0;
++wq:
++      destroy_workqueue(spidev->workqueue);
++irq4:
++//    free_irq(IRQ_LOCOMO_SPI_TEND, (void*) spidev);
++irq3:
++//    free_irq(IRQ_LOCOMO_SPI_REND, (void*) spidev);
++irq2:
++//    free_irq(IRQ_LOCOMO_SPI_RFW, (void*) spidev);
++irq1:
++//    free_irq(IRQ_LOCOMO_SPI_RFR, (void*) spidev);
++regdev:
++      spi_unregister_device(spidev->sdev);
++master:
++      spi_master_put(spidev->master);
++region:
++      release_mem_region((unsigned long) dev->mapbase, dev->length);
++      kfree(spidev);
++      return result;
++
++}
++
++static int locomospi_remove(struct locomo_dev *dev)
++{
++      spi_unregister_device(spidev->sdev);
++      spi_unregister_master(spidev->master);
++      destroy_workqueue(spidev->workqueue);
++      locomospi_reg_release();
++//    free_irq(IRQ_LOCOMO_SPI_TEND, (void*) spidev);
++//    free_irq(IRQ_LOCOMO_SPI_REND, (void*) spidev);
++//    free_irq(IRQ_LOCOMO_SPI_RFW, (void*) spidev);
++//    free_irq(IRQ_LOCOMO_SPI_RFR, (void*) spidev);
++      spi_master_put(spidev->master);
++      release_mem_region((unsigned long) dev->mapbase, dev->length);
++      kfree(spidev);
++      return 0;
++}
++
++
++
++static int __init locomospi_init(void)
++{
++      int ret = locomo_driver_register(&locomo_spi_driver);
++      if (ret)
++              return ret;
++
++
++      return 0;
++}
++
++static void __exit locomospi_exit(void)
++{
++      locomo_driver_unregister(&locomo_spi_driver);
++}
++
++module_init(locomospi_init);
++module_exit(locomospi_exit);
++
++MODULE_AUTHOR("Thomas Kunze thommy@tabao.de");
++MODULE_DESCRIPTION("Collie mmc driver");
++MODULE_LICENSE("GPL");
+diff --git a/drivers/spi/locomo_spi.h b/drivers/spi/locomo_spi.h
+new file mode 100644
+index 0000000..7e1c0ce
+--- /dev/null
++++ b/drivers/spi/locomo_spi.h
+@@ -0,0 +1,75 @@
++#include <asm/hardware/locomo.h>
++#ifndef __LOCOMO_SPI_H__
++#define __LOCOMO_SPI_H__
++
++/* locomo-spi status register LOCOMO_SPIST */
++#define LOCOMO_SPI_TEND (1 << 3)        /* Transfer end bit */
++#define LOCOMO_SPI_REND (1 << 2)        /* Receive end bit */
++#define LOCOMO_SPI_RFW  (1 << 1)        /* write buffer bit */
++#define LOCOMO_SPI_RFR  (1)             /* read buffer bit */
++
++/* locomo-spi mode register LOCOMO_SPIMD */
++#define LOCOMO_SPI_LOOPBACK (1 << 15) /* loopback tx to rx    */
++#define LOCOMO_SPI_MSB1ST   (1 << 14) /* send MSB first       */
++#define LOCOMO_SPI_DOSTAT   (1 << 13) /* transmit line is idle high */
++#define LOCOMO_SPI_TCPOL    (1 << 11)         /* transmit CPOL (maybe affects CPHA too) */
++#define LOCOMO_SPI_RCPOL    (1 << 10) /* receive CPOL (maybe affects CPHA too) */
++#define       LOCOMO_SPI_TDINV    (1 << 9)    /* invert transmit line */
++#define LOCOMO_SPI_RDINV    (1 << 8)  /* invert receive line */
++#define LOCOMO_SPI_XON            (1 << 7)    /* enable spi controller clock */
++#define LOCOMO_SPI_XEN            (1 << 6)    /* clock bit write enable xon must be off, wait 300 us before xon->1 */ 
++#define LOCOMO_SPI_XSEL           0x0018      /* clock select                 */
++#define CLOCK_18MHZ       0           /* 18,432 MHz clock     */
++#define CLOCK_22MHZ       1           /* 22,5792 MHz clock    */
++#define CLOCK_25MHZ       2           /* 24,576 MHz clock     */
++#define LOCOMO_SPI_CLKSEL   0x7       
++#define DIV_1             0           /* don't divide clock   */
++#define DIV_2             1           /* divide clock by two  */
++#define DIV_4             2           /* divide clock by four */
++#define DIV_8             3           /* divide clock by eight*/
++#define DIV_64                    4           /* divide clock by 64 */
++
++/* locomo-spi control register LOCOMO_SPICT */
++#define LOCOMO_SPI_CRC16_7_B  (1 << 15)       /* 0: crc16 1: crc7 */
++#define LOCOMO_SPI_CRCRX_TX_B (1 << 14)
++#define LOCOMO_SPI_CRCRESET_B (1 << 13)
++#define LOCOMO_SPI_CEN                (1 << 7)        /* ?? enable */
++#define LOCOMO_SPI_CS         (1 << 6)        /* chip select */
++#define LOCOMO_SPI_UNIT16     (1 << 5)        /* 0: 8 bit units, 1: 16 bit unit */
++#define LOCOMO_SPI_ALIGNEN    (1 << 2)        /* align transfer enable */
++#define LOCOMO_SPI_RXWEN      (1 << 1)        /* continous receive */
++#define LOCOMO_SPI_RXUEN      (1 << 0)        /* aligned receive */
++
++#define IRQ_LOCOMO_CARDDETECT IRQ_LOCOMO_GPIO13
++
++
++struct locomospi_dev {
++      struct locomo_dev *ldev;
++      struct spi_master *master;
++      struct spi_device *sdev;
++      int card_power;
++      int clock_base;
++      int clock_div;
++      int clock;
++      unsigned long base;
++      u8 spimode;
++      wait_queue_head_t waitqueue;
++      struct workqueue_struct *workqueue;
++      struct list_head message_list;
++      spinlock_t message_lock;
++};
++
++
++static irqreturn_t    locomospi_cardisr(int, void*);
++static int    locomospi_probe(struct locomo_dev*);
++static int    locomospi_remove(struct locomo_dev*);
++static int    locomospi_carddetect(void);
++static void   locomospi_reg_open(void);
++static void   locomospi_reg_release(void);
++static int    tx(const char*, int);
++static int    rx(char *, int);
++static void   locomospi_power(int on);
++static int locomospi_suspend(struct locomo_dev *dev, pm_message_t state);
++static int locomospi_resume(struct locomo_dev *dev);
++static void locomospi_setcs(int high);
++#endif
+-- 
+1.5.6.5
+
diff --git a/packages/linux/linux-2.6.28/collie/0003-enable-cpufreq-for-collie.patch b/packages/linux/linux-2.6.28/collie/0003-enable-cpufreq-for-collie.patch
new file mode 100644 (file)
index 0000000..4ce284d
--- /dev/null
@@ -0,0 +1,25 @@
+From 41eabd493ccc241ccd52b77c576211759976972d Mon Sep 17 00:00:00 2001
+From: Thomas Kunze <thommycheck@gmx.de>
+Date: Mon, 20 Oct 2008 17:33:29 +0200
+Subject: [PATCH 03/23] enable cpufreq for collie
+
+---
+ arch/arm/Kconfig |    2 +-
+ 1 files changed, 1 insertions(+), 1 deletions(-)
+
+diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
+index 9722f8b..609f0fb 100644
+--- a/arch/arm/Kconfig
++++ b/arch/arm/Kconfig
+@@ -1048,7 +1048,7 @@ config CPU_FREQ_SA1100
+ config CPU_FREQ_SA1110
+       bool
+-      depends on CPU_FREQ && (SA1100_ASSABET || SA1100_CERF || SA1100_PT_SYSTEM3)
++      depends on CPU_FREQ && (SA1100_ASSABET || SA1100_CERF || SA1100_PT_SYSTEM3 || SA1100_COLLIE)
+       default y
+ config CPU_FREQ_INTEGRATOR
+-- 
+1.5.6.5
+
diff --git a/packages/linux/linux-2.6.28/collie/0004-fix-dma-for-SA1100.patch b/packages/linux/linux-2.6.28/collie/0004-fix-dma-for-SA1100.patch
new file mode 100644 (file)
index 0000000..6dbb856
--- /dev/null
@@ -0,0 +1,25 @@
+From 4f4df9e1c0c82cfd9133f52089025a8ff363977c Mon Sep 17 00:00:00 2001
+From: Thomas Kunze <thommycheck@gmx.de>
+Date: Mon, 20 Oct 2008 17:39:02 +0200
+Subject: [PATCH 04/23] fix dma for SA1100
+
+---
+ arch/arm/mach-sa1100/dma.c |    2 +-
+ 1 files changed, 1 insertions(+), 1 deletions(-)
+
+diff --git a/arch/arm/mach-sa1100/dma.c b/arch/arm/mach-sa1100/dma.c
+index f990a3e..1489d64 100644
+--- a/arch/arm/mach-sa1100/dma.c
++++ b/arch/arm/mach-sa1100/dma.c
+@@ -39,7 +39,7 @@ typedef struct {
+ static sa1100_dma_t dma_chan[SA1100_DMA_CHANNELS];
+-static spinlock_t dma_list_lock;
++static  DEFINE_SPINLOCK(dma_list_lock);
+ static irqreturn_t dma_irq_handler(int irq, void *dev_id)
+-- 
+1.5.6.5
+
diff --git a/packages/linux/linux-2.6.28/collie/0005-fix-collie-keyboard-bug.patch b/packages/linux/linux-2.6.28/collie/0005-fix-collie-keyboard-bug.patch
new file mode 100644 (file)
index 0000000..1200038
--- /dev/null
@@ -0,0 +1,24 @@
+From 71f6a1b91e92c89f3fcf0330c55ad41fd3315c33 Mon Sep 17 00:00:00 2001
+From: Thomas Kunze <thommycheck@gmx.de>
+Date: Mon, 20 Oct 2008 17:40:32 +0200
+Subject: [PATCH 05/23] fix collie keyboard bug
+
+---
+ drivers/input/keyboard/locomokbd.c |    1 +
+ 1 files changed, 1 insertions(+), 0 deletions(-)
+
+diff --git a/drivers/input/keyboard/locomokbd.c b/drivers/input/keyboard/locomokbd.c
+index 9caed30..79e19bf 100644
+--- a/drivers/input/keyboard/locomokbd.c
++++ b/drivers/input/keyboard/locomokbd.c
+@@ -265,6 +265,7 @@ static int __devinit locomokbd_probe(struct locomo_dev *dev)
+       for (i = 0; i < LOCOMOKBD_NUMKEYS; i++)
+               set_bit(locomokbd->keycode[i], input_dev->keybit);
+       clear_bit(0, input_dev->keybit);
++      locomo_writel(0, locomokbd->base + LOCOMO_KSC);
+       /* attempt to get the interrupt */
+       err = request_irq(dev->irq[0], locomokbd_interrupt, 0, "locomokbd", locomokbd);
+-- 
+1.5.6.5
+
diff --git a/packages/linux/linux-2.6.28/collie/0006-add-collie-flash-hack.patch b/packages/linux/linux-2.6.28/collie/0006-add-collie-flash-hack.patch
new file mode 100644 (file)
index 0000000..0b987b6
--- /dev/null
@@ -0,0 +1,722 @@
+From 6b663bce31fb1e1a78dbca22190e98251628fd4f Mon Sep 17 00:00:00 2001
+From: Thomas Kunze <thommycheck@gmx.de>
+Date: Mon, 20 Oct 2008 17:48:10 +0200
+Subject: [PATCH 06/23] add collie flash hack
+
+---
+ arch/arm/mach-sa1100/collie.c |    2 +-
+ drivers/mtd/chips/Kconfig     |    8 +
+ drivers/mtd/chips/Makefile    |    1 +
+ drivers/mtd/chips/sharp.c     |  645 +++++++++++++++++++++++++++++++++++++++++
+ drivers/mtd/maps/Kconfig      |    2 +-
+ 5 files changed, 656 insertions(+), 2 deletions(-)
+ create mode 100644 drivers/mtd/chips/sharp.c
+
+diff --git a/arch/arm/mach-sa1100/collie.c b/arch/arm/mach-sa1100/collie.c
+index 8cf267f..ec673b8 100644
+--- a/arch/arm/mach-sa1100/collie.c
++++ b/arch/arm/mach-sa1100/collie.c
+@@ -222,7 +222,7 @@ static void collie_flash_exit(void)
+       gpio_free(COLLIE_GPIO_VPEN);
+ }
+ static struct flash_platform_data collie_flash_data = {
+-      .map_name       = "cfi_probe",
++      .map_name       = "sharp",
+       .init           = collie_flash_init,
+       .set_vpp        = collie_set_vpp,
+       .exit           = collie_flash_exit,
+diff --git a/drivers/mtd/chips/Kconfig b/drivers/mtd/chips/Kconfig
+index 9408099..2dcbd03 100644
+--- a/drivers/mtd/chips/Kconfig
++++ b/drivers/mtd/chips/Kconfig
+@@ -241,5 +241,13 @@ config MTD_XIP
+         used for XIP purposes.  If you're not sure what this is all about
+         then say N.
++config MTD_SHARP
++        tristate "pre-CFI Sharp chip support"
++        depends on MTD
++        help
++          This option enables support for flash chips using Sharp-compatible
++          commands, including some which are not CFI-compatible and hence
++          cannot be used with the CONFIG_MTD_CFI_INTELxxx options.
++
+ endmenu
+diff --git a/drivers/mtd/chips/Makefile b/drivers/mtd/chips/Makefile
+index 3658241..7283c57 100644
+--- a/drivers/mtd/chips/Makefile
++++ b/drivers/mtd/chips/Makefile
+@@ -12,4 +12,5 @@ obj-$(CONFIG_MTD_GEN_PROBE)  += gen_probe.o
+ obj-$(CONFIG_MTD_JEDECPROBE)  += jedec_probe.o
+ obj-$(CONFIG_MTD_RAM)         += map_ram.o
+ obj-$(CONFIG_MTD_ROM)         += map_rom.o
++obj-$(CONFIG_MTD_SHARP)         += sharp.o
+ obj-$(CONFIG_MTD_ABSENT)      += map_absent.o
+diff --git a/drivers/mtd/chips/sharp.c b/drivers/mtd/chips/sharp.c
+new file mode 100644
+index 0000000..046b964
+--- /dev/null
++++ b/drivers/mtd/chips/sharp.c
+@@ -0,0 +1,645 @@
++/*
++ * MTD chip driver for pre-CFI Sharp flash chips
++ *
++ * Copyright 2000,2001 David A. Schleef <ds@schleef.org>
++ *           2000,2001 Lineo, Inc.
++ *
++ * $Id: sharp.c,v 1.17 2005/11/29 14:28:28 gleixner Exp $
++ *
++ * Devices supported:
++ *   LH28F016SCT Symmetrical block flash memory, 2Mx8
++ *   LH28F008SCT Symmetrical block flash memory, 1Mx8
++ *
++ * Documentation:
++ *   http://www.sharpmeg.com/datasheets/memic/flashcmp/
++ *   http://www.sharpmeg.com/datasheets/memic/flashcmp/01symf/16m/016sctl9.pdf
++ *   016sctl9.pdf
++ *
++ * Limitations:
++ *   This driver only supports 4x1 arrangement of chips.
++ *   Not tested on anything but PowerPC.
++ */
++
++#include <linux/kernel.h>
++#include <linux/module.h>
++#include <linux/types.h>
++#include <linux/sched.h>
++#include <linux/errno.h>
++#include <linux/init.h>
++#include <linux/interrupt.h>
++#include <linux/mtd/map.h>
++#include <linux/mtd/mtd.h>
++#include <linux/mtd/cfi.h>
++#include <linux/delay.h>
++#include <linux/init.h>
++
++#define CMD_RESET             0xffffffff
++#define CMD_READ_ID           0x90909090
++#define CMD_READ_STATUS               0x70707070
++#define CMD_CLEAR_STATUS      0x50505050
++#define CMD_BLOCK_ERASE_1     0x20202020
++#define CMD_BLOCK_ERASE_2     0xd0d0d0d0
++#define CMD_BYTE_WRITE                0x40404040
++#define CMD_SUSPEND           0xb0b0b0b0
++#define CMD_RESUME            0xd0d0d0d0
++#define CMD_SET_BLOCK_LOCK_1  0x60606060
++#define CMD_SET_BLOCK_LOCK_2  0x01010101
++#define CMD_SET_MASTER_LOCK_1 0x60606060
++#define CMD_SET_MASTER_LOCK_2 0xf1f1f1f1
++#define CMD_CLEAR_BLOCK_LOCKS_1       0x60606060
++#define CMD_CLEAR_BLOCK_LOCKS_2       0xd0d0d0d0
++
++#define SR_READY              0x80808080 // 1 = ready
++#define SR_ERASE_SUSPEND      0x40404040 // 1 = block erase suspended
++#define SR_ERROR_ERASE                0x20202020 // 1 = error in block erase or clear lock bits
++#define SR_ERROR_WRITE                0x10101010 // 1 = error in byte write or set lock bit
++#define       SR_VPP                  0x08080808 // 1 = Vpp is low
++#define SR_WRITE_SUSPEND      0x04040404 // 1 = byte write suspended
++#define SR_PROTECT            0x02020202 // 1 = lock bit set
++#define SR_RESERVED           0x01010101
++
++#define SR_ERRORS (SR_ERROR_ERASE|SR_ERROR_WRITE|SR_VPP|SR_PROTECT)
++
++#define BLOCK_MASK            0xfffe0000
++
++/* Configuration options */
++
++#define AUTOUNLOCK  /* automatically unlocks blocks before erasing */
++
++static struct mtd_info *sharp_probe(struct map_info *);
++
++static int sharp_probe_map(struct map_info *map, struct mtd_info *mtd);
++
++static int sharp_read(struct mtd_info *mtd, loff_t from, size_t len,
++      size_t *retlen, u_char *buf);
++static int sharp_write(struct mtd_info *mtd, loff_t from, size_t len,
++      size_t *retlen, const u_char *buf);
++static int sharp_erase(struct mtd_info *mtd, struct erase_info *instr);
++static void sharp_sync(struct mtd_info *mtd);
++static int sharp_suspend(struct mtd_info *mtd);
++static void sharp_resume(struct mtd_info *mtd);
++static void sharp_destroy(struct mtd_info *mtd);
++
++static int sharp_write_oneword(struct map_info *map, struct flchip *chip,
++      unsigned long adr, __u32 datum);
++static int sharp_erase_oneblock(struct map_info *map, struct flchip *chip,
++      unsigned long adr);
++#ifdef AUTOUNLOCK
++static inline void sharp_unlock_oneblock(struct map_info *map, struct flchip *chip,
++      unsigned long adr);
++#endif
++
++
++struct sharp_info{
++      struct flchip *chip;
++      int bogus;
++      int chipshift;
++      int numchips;
++      struct flchip chips[1];
++};
++
++static void sharp_destroy(struct mtd_info *mtd);
++
++static struct mtd_chip_driver sharp_chipdrv = {
++      .probe          = sharp_probe,
++      .destroy        = sharp_destroy,
++      .name           = "sharp",
++      .module         = THIS_MODULE
++};
++
++static void sharp_udelay(unsigned long i) {
++      if (in_interrupt()) {
++              udelay(i);
++      } else {
++              schedule();
++      }
++}
++
++static struct mtd_info *sharp_probe(struct map_info *map)
++{
++      struct mtd_info *mtd = NULL;
++      struct sharp_info *sharp = NULL;
++      int width;
++
++      mtd = kzalloc(sizeof(*mtd), GFP_KERNEL);
++      if(!mtd)
++              return NULL;
++
++      sharp = kzalloc(sizeof(*sharp), GFP_KERNEL);
++      if(!sharp) {
++              kfree(mtd);
++              return NULL;
++      }
++
++      width = sharp_probe_map(map,mtd);
++      if(!width){
++              kfree(mtd);
++              kfree(sharp);
++              return NULL;
++      }
++
++      mtd->priv = map;
++      mtd->type = MTD_NORFLASH;
++      mtd->erase = sharp_erase;
++      mtd->read = sharp_read;
++      mtd->write = sharp_write;
++      mtd->sync = sharp_sync;
++      mtd->suspend = sharp_suspend;
++      mtd->resume = sharp_resume;
++      mtd->flags = MTD_CAP_NORFLASH;
++      mtd->writesize = 1;
++      mtd->name = map->name;
++
++      sharp->chipshift = 24;
++      sharp->numchips = 1;
++      sharp->chips[0].start = 0;
++      sharp->chips[0].state = FL_READY;
++      sharp->chips[0].mutex = &sharp->chips[0]._spinlock;
++      sharp->chips[0].word_write_time = 0;
++      init_waitqueue_head(&sharp->chips[0].wq);
++      spin_lock_init(&sharp->chips[0]._spinlock);
++
++      map->fldrv = &sharp_chipdrv;
++      map->fldrv_priv = sharp;
++
++      __module_get(THIS_MODULE);
++      return mtd;
++}
++
++static inline void sharp_send_cmd(struct map_info *map, unsigned long cmd, unsigned long adr)
++{
++      map_word map_cmd;
++      map_cmd.x[0] = cmd;
++      map_write(map, map_cmd, adr);
++}
++
++static int sharp_probe_map(struct map_info *map,struct mtd_info *mtd)
++{
++      map_word tmp, read0, read4;
++      unsigned long base = 0;
++      int width = 4;
++
++      tmp = map_read(map, base+0);
++
++      sharp_send_cmd(map, CMD_READ_ID, base+0);
++
++      read0 = map_read(map, base+0);
++      read4 = map_read(map, base+4);
++      if (read0.x[0] == 0x00b000b0) {
++              printk("Sharp chip, %lx, %lx, width = %d\n", read0.x[0], read4.x[0], width);
++              /* Prints b000b0, b000b0, width = 4 on collie */
++              switch(read4.x[0]){
++              case 0xaaaaaaaa:
++              case 0xa0a0a0a0:
++                      /* aa - LH28F016SCT-L95 2Mx8, 32 64k blocks*/
++                      /* a0 - LH28F016SCT-Z4  2Mx8, 32 64k blocks*/
++                      mtd->erasesize = 0x10000 * width;
++                      mtd->size = 0x200000 * width;
++                      return width;
++              case 0xa6a6a6a6:
++                      /* a6 - LH28F008SCT-L12 1Mx8, 16 64k blocks*/
++                      /* a6 - LH28F008SCR-L85 1Mx8, 16 64k blocks*/
++                      mtd->erasesize = 0x10000 * width;
++                      mtd->size = 0x100000 * width;
++                      return width;
++              case 0x00b000b0:
++                      /* a6 - LH28F640BFHE 8 64k * 2 chip blocks*/
++                      mtd->erasesize = 0x10000 * width / 2;
++                      mtd->size = 0x800000 * width / 2;
++                      return width;
++              default:
++                      printk("Sort-of looks like sharp flash, 0x%08lx 0x%08lx\n",
++                              read0.x[0], read4.x[0]);
++              }
++      } else if ((map_read(map, base+0).x[0] == CMD_READ_ID)){
++              /* RAM, probably */
++              printk("Looks like RAM\n");
++              map_write(map, tmp, base+0);
++      }else{
++              printk("Doesn't look like sharp flash, 0x%08lx 0x%08lx\n",
++                      read0.x[0], read4.x[0]);
++      }
++
++      return 0;
++}
++
++/* This function returns with the chip->mutex lock held. */
++static int sharp_wait(struct map_info *map, struct flchip *chip)
++{
++      map_word status;
++      unsigned long timeo = jiffies + HZ;
++      DECLARE_WAITQUEUE(wait, current);
++      int adr = 0;
++
++retry:
++      spin_lock_bh(chip->mutex);
++
++      switch (chip->state) {
++      case FL_READY:
++              sharp_send_cmd(map, CMD_READ_STATUS, adr);
++              chip->state = FL_STATUS;
++      case FL_STATUS:
++              status = map_read(map, adr);
++              if ((status.x[0] & SR_READY) == SR_READY)
++                      break;
++              spin_unlock_bh(chip->mutex);
++              if (time_after(jiffies, timeo)) {
++                      printk("Waiting for chip to be ready timed out in erase\n");
++                      return -EIO;
++              }
++              sharp_udelay(1);
++              goto retry;
++      default:
++              set_current_state(TASK_INTERRUPTIBLE);
++              add_wait_queue(&chip->wq, &wait);
++
++              spin_unlock_bh(chip->mutex);
++
++              sharp_udelay(1);
++
++              set_current_state(TASK_RUNNING);
++              remove_wait_queue(&chip->wq, &wait);
++
++              if(signal_pending(current))
++                      return -EINTR;
++
++              timeo = jiffies + HZ;
++
++              goto retry;
++      }
++
++      sharp_send_cmd(map, CMD_RESET, adr);
++
++      chip->state = FL_READY;
++
++      return 0;
++}
++
++static void sharp_release(struct flchip *chip)
++{
++      wake_up(&chip->wq);
++      spin_unlock_bh(chip->mutex);
++}
++
++static int sharp_read(struct mtd_info *mtd, loff_t from, size_t len,
++      size_t *retlen, u_char *buf)
++{
++      struct map_info *map = mtd->priv;
++      struct sharp_info *sharp = map->fldrv_priv;
++      int chipnum;
++      int ret = 0;
++      int ofs = 0;
++
++      chipnum = (from >> sharp->chipshift);
++      ofs = from & ((1 << sharp->chipshift)-1);
++
++      *retlen = 0;
++
++      while(len){
++              unsigned long thislen;
++
++              if(chipnum>=sharp->numchips)
++                      break;
++
++              thislen = len;
++              if(ofs+thislen >= (1<<sharp->chipshift))
++                      thislen = (1<<sharp->chipshift) - ofs;
++
++              ret = sharp_wait(map,&sharp->chips[chipnum]);
++              if(ret<0)
++                      break;
++
++              map_copy_from(map,buf,ofs,thislen);
++
++              sharp_release(&sharp->chips[chipnum]);
++
++              *retlen += thislen;
++              len -= thislen;
++              buf += thislen;
++
++              ofs = 0;
++              chipnum++;
++      }
++      return ret;
++}
++
++static int sharp_write(struct mtd_info *mtd, loff_t to, size_t len,
++      size_t *retlen, const u_char *buf)
++{
++      struct map_info *map = mtd->priv;
++      struct sharp_info *sharp = map->fldrv_priv;
++      int ret = 0;
++      int i,j;
++      int chipnum;
++      unsigned long ofs;
++      union { u32 l; unsigned char uc[4]; } tbuf;
++
++      *retlen = 0;
++
++      while(len){
++              tbuf.l = 0xffffffff;
++              chipnum = to >> sharp->chipshift;
++              ofs = to & ((1<<sharp->chipshift)-1);
++
++              j=0;
++              for(i=ofs&3;i<4 && len;i++){
++                      tbuf.uc[i] = *buf;
++                      buf++;
++                      to++;
++                      len--;
++                      j++;
++              }
++              sharp_write_oneword(map, &sharp->chips[chipnum], ofs&~3, tbuf.l);
++              if(ret<0)
++                      return ret;
++              (*retlen)+=j;
++      }
++
++      return 0;
++}
++
++static int sharp_write_oneword(struct map_info *map, struct flchip *chip,
++      unsigned long adr, __u32 datum)
++{
++      int ret;
++      int try;
++      int i;
++      map_word data, status;
++
++      status.x[0] = 0;
++      ret = sharp_wait(map,chip);
++      if (ret < 0)
++              return ret;
++
++      for (try=0; try<10; try++) {
++              long timeo;
++
++              sharp_send_cmd(map, CMD_BYTE_WRITE, adr);
++              /* cpu_to_le32 -> hack to fix the writel be->le conversion */
++              data.x[0] = cpu_to_le32(datum);
++              map_write(map, data, adr);
++
++              chip->state = FL_WRITING;
++              timeo = jiffies + (HZ/2);
++
++              sharp_send_cmd(map, CMD_READ_STATUS, adr);
++              for(i=0;i<100;i++){
++                      status = map_read(map, adr);
++                      if((status.x[0] & SR_READY) == SR_READY)
++                              break;
++              }
++#ifdef AUTOUNLOCK
++              if (status.x[0] & SR_PROTECT) { /* lock block */
++                      sharp_send_cmd(map, CMD_CLEAR_STATUS, adr);
++                      sharp_unlock_oneblock(map,chip,adr);
++                      sharp_send_cmd(map, CMD_CLEAR_STATUS, adr);
++                      sharp_send_cmd(map, CMD_RESET, adr);
++                      continue;
++              }
++#endif
++              if(i==100){
++                      printk("sharp: timed out writing\n");
++              }
++
++              if (!(status.x[0] & SR_ERRORS))
++                      break;
++
++              printk("sharp: error writing byte at addr=%08lx status=%08lx\n", adr, status.x[0]);
++
++              sharp_send_cmd(map, CMD_CLEAR_STATUS, adr);
++      }
++      sharp_send_cmd(map, CMD_RESET, adr);
++      chip->state = FL_READY;
++
++      sharp_release(chip);
++
++      return 0;
++}
++
++static int sharp_erase(struct mtd_info *mtd, struct erase_info *instr)
++{
++      struct map_info *map = mtd->priv;
++      struct sharp_info *sharp = map->fldrv_priv;
++      unsigned long adr,len;
++      int chipnum, ret=0;
++
++      if(instr->addr & (mtd->erasesize - 1))
++              return -EINVAL;
++      if(instr->len & (mtd->erasesize - 1))
++              return -EINVAL;
++      if(instr->len + instr->addr > mtd->size)
++              return -EINVAL;
++
++      chipnum = instr->addr >> sharp->chipshift;
++      adr = instr->addr & ((1<<sharp->chipshift)-1);
++      len = instr->len;
++
++      while(len){
++              ret = sharp_erase_oneblock(map, &sharp->chips[chipnum], adr);
++              if(ret)return ret;
++
++              if (adr >= 0xfe0000) {
++                      adr += mtd->erasesize / 8;
++                      len -= mtd->erasesize / 8;
++              } else {
++                      adr += mtd->erasesize;
++                      len -= mtd->erasesize;
++              }
++              if(adr >> sharp->chipshift){
++                      adr = 0;
++                      chipnum++;
++                      if(chipnum>=sharp->numchips)
++                              break;
++              }
++      }
++
++      instr->state = MTD_ERASE_DONE;
++      mtd_erase_callback(instr);
++
++      return 0;
++}
++
++static inline int sharp_do_wait_for_ready(struct map_info *map, struct flchip *chip,
++      unsigned long adr)
++{
++      int ret;
++      unsigned long timeo;
++      map_word status;
++      DECLARE_WAITQUEUE(wait, current);
++
++      sharp_send_cmd(map, CMD_READ_STATUS, adr);
++      status = map_read(map, adr);
++
++      timeo = jiffies + HZ * 10;
++
++      while (time_before(jiffies, timeo)) {
++              sharp_send_cmd(map, CMD_READ_STATUS, adr);
++              status = map_read(map, adr);
++              if ((status.x[0] & SR_READY) == SR_READY) {
++                      ret = 0;
++                      goto out;
++              }
++              set_current_state(TASK_INTERRUPTIBLE);
++              add_wait_queue(&chip->wq, &wait);
++
++              spin_unlock_bh(chip->mutex);
++
++              schedule_timeout(1);
++              schedule();
++
++              spin_lock_bh(chip->mutex);
++
++              remove_wait_queue(&chip->wq, &wait);
++              set_current_state(TASK_RUNNING);
++      }
++      ret = -ETIME;
++out:
++      return ret;
++}
++
++static int sharp_erase_oneblock(struct map_info *map, struct flchip *chip,
++      unsigned long adr)
++{
++      int ret;
++      map_word status;
++
++      ret = sharp_wait(map,chip);
++      if (ret < 0)
++              return ret;
++
++#ifdef AUTOUNLOCK
++      /* This seems like a good place to do an unlock */
++      sharp_unlock_oneblock(map,chip,adr);
++#endif
++
++      sharp_send_cmd(map, CMD_BLOCK_ERASE_1, adr);
++      sharp_send_cmd(map, CMD_BLOCK_ERASE_2, adr);
++
++      chip->state = FL_ERASING;
++
++      ret = sharp_do_wait_for_ready(map,chip,adr);
++      if(ret<0) {
++              spin_unlock_bh(chip->mutex);
++              return ret;
++      }
++
++      sharp_send_cmd(map, CMD_READ_STATUS, adr);
++      status = map_read(map, adr);
++
++      if (!(status.x[0] & SR_ERRORS)) {
++              sharp_send_cmd(map, CMD_RESET, adr);
++              chip->state = FL_READY;
++              spin_unlock_bh(chip->mutex);
++              return 0;
++      }
++
++      printk("sharp: error erasing block at addr=%08lx status=%08lx\n", adr, status.x[0]);
++      sharp_send_cmd(map, CMD_CLEAR_STATUS, adr);
++
++      sharp_release(chip);
++
++      return -EIO;
++}
++
++#ifdef AUTOUNLOCK
++static inline void sharp_unlock_oneblock(struct map_info *map, struct flchip *chip,
++      unsigned long adr)
++{
++      map_word status;
++
++      sharp_send_cmd(map, CMD_CLEAR_BLOCK_LOCKS_1, adr & BLOCK_MASK);
++      sharp_send_cmd(map, CMD_CLEAR_BLOCK_LOCKS_2, adr & BLOCK_MASK);
++
++      sharp_do_wait_for_ready(map,chip,adr);
++
++      status = map_read(map, adr);
++
++      if (!(status.x[0] & SR_ERRORS)) {
++              sharp_send_cmd(map, CMD_RESET, adr);
++              chip->state = FL_READY;
++              return;
++      }
++
++      printk("sharp: error unlocking block at addr=%08lx status=%08lx\n", adr, status.x[0]);
++      sharp_send_cmd(map, CMD_CLEAR_STATUS, adr);
++}
++#endif
++
++static void sharp_sync(struct mtd_info *mtd)
++{
++}
++
++static int sharp_suspend(struct mtd_info *mtd)
++{
++      struct map_info *map = mtd->priv;
++      struct sharp_info *sharp = map->fldrv_priv;
++      int i;
++      struct flchip *chip;
++      int ret = 0;
++
++      for (i = 0; !ret && i < sharp->numchips; i++) {
++              chip = &sharp->chips[i];
++              ret = sharp_wait(map,chip);
++
++              if (ret) {
++                      ret = -EAGAIN;
++              } else {
++                      chip->state = FL_PM_SUSPENDED;
++                      spin_unlock_bh(chip->mutex);
++              }
++      }
++      return ret;
++}
++
++static void sharp_resume(struct mtd_info *mtd)
++{
++      struct map_info *map = mtd->priv;
++      struct sharp_info *sharp = map->fldrv_priv;
++      int i;
++      struct flchip *chip;
++
++      for (i = 0; i < sharp->numchips; i++) {
++              chip = &sharp->chips[i];
++
++              spin_lock_bh(chip->mutex);
++
++              if (chip->state == FL_PM_SUSPENDED) {
++                      /* We need to force it back to a known state */
++                      sharp_send_cmd(map, CMD_RESET, chip->start);
++                      chip->state = FL_READY;
++                      wake_up(&chip->wq);
++              }
++
++              spin_unlock_bh(chip->mutex);
++      }
++}
++
++static void sharp_destroy(struct mtd_info *mtd)
++{
++      struct map_info *map = mtd->priv;
++      struct sharp_info *sharp = map->fldrv_priv;
++
++      kfree(sharp);
++}
++
++static int __init sharp_probe_init(void)
++{
++      printk("MTD Sharp chip driver <ds@lineo.com>\n");
++
++      register_mtd_chip_driver(&sharp_chipdrv);
++
++      return 0;
++}
++
++static void __exit sharp_probe_exit(void)
++{
++      unregister_mtd_chip_driver(&sharp_chipdrv);
++}
++
++module_init(sharp_probe_init);
++module_exit(sharp_probe_exit);
++
++
++MODULE_LICENSE("GPL");
++MODULE_AUTHOR("David Schleef <ds@schleef.org>");
++MODULE_DESCRIPTION("Old MTD chip driver for pre-CFI Sharp flash chips");
+diff --git a/drivers/mtd/maps/Kconfig b/drivers/mtd/maps/Kconfig
+index 5ea1693..d523464 100644
+--- a/drivers/mtd/maps/Kconfig
++++ b/drivers/mtd/maps/Kconfig
+@@ -360,7 +360,7 @@ config MTD_CDB89712
+ config MTD_SA1100
+       tristate "CFI Flash device mapped on StrongARM SA11x0"
+-      depends on MTD_CFI && ARCH_SA1100 && MTD_PARTITIONS
++      depends on (MTD_CFI || MTD_SHARP) && ARCH_SA1100 && MTD_PARTITIONS
+       help
+         This enables access to the flash chips on most platforms based on
+         the SA1100 and SA1110, including the Assabet and the Compaq iPAQ.
+-- 
+1.5.6.5
+
diff --git a/packages/linux/linux-2.6.28/collie/0007-hostap-workaround-for-buggy-sa1100-pcmcia-driver.patch b/packages/linux/linux-2.6.28/collie/0007-hostap-workaround-for-buggy-sa1100-pcmcia-driver.patch
new file mode 100644 (file)
index 0000000..230bd93
--- /dev/null
@@ -0,0 +1,107 @@
+From 8200a4430e1515bf4523e3651fa7c29fdebbb0fb Mon Sep 17 00:00:00 2001
+From: Thomas Kunze <thommycheck@gmx.de>
+Date: Mon, 20 Oct 2008 17:50:06 +0200
+Subject: [PATCH 07/23] hostap workaround for buggy sa1100 pcmcia driver
+
+---
+ drivers/net/wireless/hostap/hostap_cs.c  |    6 ++++--
+ drivers/net/wireless/hostap/hostap_hw.c  |   14 ++++++++++++--
+ drivers/net/wireless/hostap/hostap_pci.c |    1 +
+ drivers/net/wireless/hostap/hostap_plx.c |    2 +-
+ 4 files changed, 18 insertions(+), 5 deletions(-)
+
+diff --git a/drivers/net/wireless/hostap/hostap_cs.c b/drivers/net/wireless/hostap/hostap_cs.c
+index 6337402..928cdf0 100644
+--- a/drivers/net/wireless/hostap/hostap_cs.c
++++ b/drivers/net/wireless/hostap/hostap_cs.c
+@@ -35,7 +35,7 @@ static int ignore_cis_vcc;
+ module_param(ignore_cis_vcc, int, 0444);
+ MODULE_PARM_DESC(ignore_cis_vcc, "Ignore broken CIS VCC entry");
+-
++int activar=0;
+ /* struct local_info::hw_priv */
+ struct hostap_cs_priv {
+       dev_node_t node;
+@@ -499,11 +499,13 @@ static int hostap_cs_probe(struct pcmcia_device *p_dev)
+       PDEBUG(DEBUG_HW, "%s: setting Vcc=33 (constant)\n", dev_info);
+       p_dev->conf.IntType = INT_MEMORY_AND_IO;
+-
++      
++      activar=0;
+       ret = prism2_config(p_dev);
+       if (ret) {
+               PDEBUG(DEBUG_EXTRA, "prism2_config() failed\n");
+       }
++      activar=1;
+       return ret;
+ }
+diff --git a/drivers/net/wireless/hostap/hostap_hw.c b/drivers/net/wireless/hostap/hostap_hw.c
+index 3153fe9..188eaee 100644
+--- a/drivers/net/wireless/hostap/hostap_hw.c
++++ b/drivers/net/wireless/hostap/hostap_hw.c
+@@ -54,6 +54,7 @@
+ #include "hostap.h"
+ #include "hostap_ap.h"
++extern int activar;
+ /* #define final_version */
+@@ -1497,6 +1498,8 @@ static int prism2_hw_config(struct net_device *dev, int initial)
+       if (local->hw_downloading)
+               return 1;
++      activar=1;
++
+       if (prism2_hw_init(dev, initial)) {
+               return local->no_pri ? 0 : 1;
+       }
+@@ -2628,8 +2631,15 @@ static irqreturn_t prism2_interrupt(int irq, void *dev_id)
+       int events = 0;
+       u16 ev;
+-      iface = netdev_priv(dev);
+-      local = iface->local;
++
++      // Todos los parametros de entrada son correctos (no son nulos). De momento esta es la unica forma que conozco de detectar el problema.
++      if (!activar) {
++              printk("hostap_hw.c: INTERRUPT BEFORE DEVICE INIT!\n");
++              return IRQ_HANDLED;
++      }
++
++      iface = netdev_priv(dev);
++      local = iface->local;
+       prism2_io_debug_add(dev, PRISM2_IO_DEBUG_CMD_INTERRUPT, 0, 0);
+diff --git a/drivers/net/wireless/hostap/hostap_pci.c b/drivers/net/wireless/hostap/hostap_pci.c
+index 3a874fc..df58aa3 100644
+--- a/drivers/net/wireless/hostap/hostap_pci.c
++++ b/drivers/net/wireless/hostap/hostap_pci.c
+@@ -19,6 +19,7 @@
+ #include "hostap_wlan.h"
++int activar=1;
+ static char *dev_info = "hostap_pci";
+diff --git a/drivers/net/wireless/hostap/hostap_plx.c b/drivers/net/wireless/hostap/hostap_plx.c
+index cbf15d7..4475174 100644
+--- a/drivers/net/wireless/hostap/hostap_plx.c
++++ b/drivers/net/wireless/hostap/hostap_plx.c
+@@ -21,7 +21,7 @@
+ #include <asm/io.h>
+ #include "hostap_wlan.h"
+-
++int activar=1;
+ static char *dev_info = "hostap_plx";
+-- 
+1.5.6.5
+
diff --git a/packages/linux/linux-2.6.28/collie/0008-fix-collie-suspend-hack.patch b/packages/linux/linux-2.6.28/collie/0008-fix-collie-suspend-hack.patch
new file mode 100644 (file)
index 0000000..19557f9
--- /dev/null
@@ -0,0 +1,70 @@
+From 8ebd75d9f4d7dcc74e18b46ed82070eec52deaa8 Mon Sep 17 00:00:00 2001
+From: Thomas Kunze <thommycheck@gmx.de>
+Date: Mon, 20 Oct 2008 17:51:21 +0200
+Subject: [PATCH 08/23] fix collie suspend hack
+
+---
+ drivers/pcmcia/pxa2xx_sharpsl.c |    2 +-
+ drivers/pcmcia/sa1100_generic.c |   19 ++++++++++---------
+ 2 files changed, 11 insertions(+), 10 deletions(-)
+
+diff --git a/drivers/pcmcia/pxa2xx_sharpsl.c b/drivers/pcmcia/pxa2xx_sharpsl.c
+index 1cd02f5..3724395 100644
+--- a/drivers/pcmcia/pxa2xx_sharpsl.c
++++ b/drivers/pcmcia/pxa2xx_sharpsl.c
+@@ -222,7 +222,7 @@ static void sharpsl_pcmcia_socket_suspend(struct soc_pcmcia_socket *skt)
+       sharpsl_pcmcia_init_reset(skt);
+ }
+-static struct pcmcia_low_level sharpsl_pcmcia_ops __initdata = {
++static struct pcmcia_low_level sharpsl_pcmcia_ops = {
+       .owner                  = THIS_MODULE,
+       .hw_init                = sharpsl_pcmcia_hw_init,
+       .hw_shutdown            = sharpsl_pcmcia_hw_shutdown,
+diff --git a/drivers/pcmcia/sa1100_generic.c b/drivers/pcmcia/sa1100_generic.c
+index c5b2a44..eecbe8c 100644
+--- a/drivers/pcmcia/sa1100_generic.c
++++ b/drivers/pcmcia/sa1100_generic.c
+@@ -81,13 +81,14 @@ static int sa11x0_drv_pcmcia_probe(struct device *dev)
+       return ret;
+ }
+-static struct device_driver sa11x0_pcmcia_driver = {
+-      .probe          = sa11x0_drv_pcmcia_probe,
+-      .remove         = soc_common_drv_pcmcia_remove,
+-      .name           = "sa11x0-pcmcia",
+-      .bus            = &platform_bus_type,
+-      .suspend        = pcmcia_socket_dev_suspend,
+-      .resume         = pcmcia_socket_dev_resume,
++static struct platform_driver sa11x0_pcmcia_driver = {
++      .driver         = {
++              .name   = "sa11x0-pcmcia",
++              .probe  = sa11x0_drv_pcmcia_probe,
++              .remove = soc_common_drv_pcmcia_remove,
++              .suspend= pcmcia_socket_dev_suspend,
++              .resume = pcmcia_socket_dev_resume,
++      },
+ };
+ /* sa11x0_pcmcia_init()
+@@ -100,7 +101,7 @@ static struct device_driver sa11x0_pcmcia_driver = {
+  */
+ static int __init sa11x0_pcmcia_init(void)
+ {
+-      return driver_register(&sa11x0_pcmcia_driver);
++      return platform_driver_register(&sa11x0_pcmcia_driver);
+ }
+ /* sa11x0_pcmcia_exit()
+@@ -110,7 +111,7 @@ static int __init sa11x0_pcmcia_init(void)
+  */
+ static void __exit sa11x0_pcmcia_exit(void)
+ {
+-      driver_unregister(&sa11x0_pcmcia_driver);
++      platform_driver_unregister(&sa11x0_pcmcia_driver);
+ }
+ MODULE_AUTHOR("John Dorsey <john+@cs.cmu.edu>");
+-- 
+1.5.6.5
+
diff --git a/packages/linux/linux-2.6.28/collie/0009-add-sa1100-usb-gadget-driver-hack.patch b/packages/linux/linux-2.6.28/collie/0009-add-sa1100-usb-gadget-driver-hack.patch
new file mode 100644 (file)
index 0000000..bb8dd5c
--- /dev/null
@@ -0,0 +1,2629 @@
+From 923ac0a48c2a064e4639b0fa53dbd0a18d87043e Mon Sep 17 00:00:00 2001
+From: Thomas Kunze <thommycheck@gmx.de>
+Date: Tue, 10 Feb 2009 18:09:03 +0100
+Subject: [PATCH 09/23] add sa1100 usb gadget driver hack
+
+Conflicts:
+
+       drivers/usb/gadget/Makefile
+---
+ arch/arm/mach-sa1100/include/mach/collie.h |    5 +-
+ drivers/usb/gadget/Kconfig                 |   14 +
+ drivers/usb/gadget/Makefile                |    1 +
+ drivers/usb/gadget/sa1100_udc.c            | 2447 ++++++++++++++++++++++++++++
+ drivers/usb/gadget/sa1100_udc.h            |   94 ++
+ 5 files changed, 2558 insertions(+), 3 deletions(-)
+ create mode 100644 drivers/usb/gadget/sa1100_udc.c
+ create mode 100644 drivers/usb/gadget/sa1100_udc.h
+
+diff --git a/arch/arm/mach-sa1100/include/mach/collie.h b/arch/arm/mach-sa1100/include/mach/collie.h
+index 9bc5349..799c930 100644
+--- a/arch/arm/mach-sa1100/include/mach/collie.h
++++ b/arch/arm/mach-sa1100/include/mach/collie.h
+@@ -23,11 +23,10 @@
+ #define COLLIE_SCP_5VON               SCOOP_GPCR_PA16
+ #define COLLIE_SCP_AMP_ON     SCOOP_GPCR_PA17
+ #define COLLIE_GPIO_VPEN      (COLLIE_SCOOP_GPIO_BASE + 7)
+-#define COLLIE_SCP_LB_VOL_CHG SCOOP_GPCR_PA19
++#define COLLIE_GPIO_LB_VOL_CHG        (COLLIE_SCOOP_GPIO_BASE + 8)
+ #define COLLIE_SCOOP_IO_DIR   ( COLLIE_SCP_CHARGE_ON | COLLIE_SCP_MUTE_L | COLLIE_SCP_MUTE_R | \
+-                              COLLIE_SCP_5VON | COLLIE_SCP_AMP_ON | \
+-                              COLLIE_SCP_LB_VOL_CHG )
++                              COLLIE_SCP_5VON | COLLIE_SCP_AMP_ON )
+ #define COLLIE_SCOOP_IO_OUT   ( COLLIE_SCP_MUTE_L | COLLIE_SCP_MUTE_R | \
+                               COLLIE_SCP_CHARGE_ON )
+diff --git a/drivers/usb/gadget/Kconfig b/drivers/usb/gadget/Kconfig
+index dd4cd5a..efb65ac 100644
+--- a/drivers/usb/gadget/Kconfig
++++ b/drivers/usb/gadget/Kconfig
+@@ -419,6 +419,20 @@ config USB_GOKU
+       default USB_GADGET
+       select USB_GADGET_SELECTED
++config USB_GADGET_SA1100
++      boolean "SA1100 USB Device Port"
++      depends on ARCH_SA1100
++      select USB_GADGET_SELECTED
++      help
++
++         Say "y" to link the driver statically, or "m" to build a
++         dynamically linked module called "sa1100_udc" and force all
++         gadget drivers to also be dynamically linked.
++
++config USB_SA1100
++      tristate
++      depends on USB_GADGET_SA1100
++      default USB_GADGET
+ #
+ # LAST -- dummy/emulated controller
+diff --git a/drivers/usb/gadget/Makefile b/drivers/usb/gadget/Makefile
+index bd4041b..5cdd0ce 100644
+--- a/drivers/usb/gadget/Makefile
++++ b/drivers/usb/gadget/Makefile
+@@ -19,6 +19,7 @@ obj-$(CONFIG_USB_ATMEL_USBA) += atmel_usba_udc.o
+ obj-$(CONFIG_USB_FSL_USB2)    += fsl_usb2_udc.o
+ obj-$(CONFIG_USB_M66592)      += m66592-udc.o
+ obj-$(CONFIG_USB_FSL_QE)      += fsl_qe_udc.o
++obj-$(CONFIG_USB_SA1100)      += sa1100_udc.o
+ #
+ # USB gadget drivers
+diff --git a/drivers/usb/gadget/sa1100_udc.c b/drivers/usb/gadget/sa1100_udc.c
+new file mode 100644
+index 0000000..5e26a6d
+--- /dev/null
++++ b/drivers/usb/gadget/sa1100_udc.c
+@@ -0,0 +1,2447 @@
++/*
++ * SA1100 USB Device Controller (UDC) driver.
++ *
++ * Copyright (C) Compaq Computer Corporation, 1998, 1999
++ * Copyright (C) Extenex Corporation, 2001
++ * Copyright (C) David Brownell, 2003
++ * Copyright (C) Nick Bane, 2005, 2006, 2007
++ *   Many fragments from pxa2xx_udc.c and mach-sa1100 driver with various
++ *   GPL Copyright authors incl Russel king and Nicolas Pitre
++ *   Working port to 2.6.32-1 by N C Bane
++ *
++ * This file provides interrupt routing and overall coordination for the
++ * sa1100 USB endpoints: ep0, ep1out-bulk, ep2in-bulk, as well as device
++ * initialization and some parts of USB "Chapter 9" device behavior.
++ *
++ * It implements the "USB gadget controller" API, abstracting most hardware
++ * details so that drivers running on top of this API are mostly independent
++ * of hardware.  A key exception is that ep0 logic needs to understand which
++ * endpoints a given controller has, and their capabilities.  Also, hardware
++ * that doesn't fully support USB (like sa1100) may need workarounds in the
++ * protocols implemented by device functions.
++ *
++ * See linux/Documentation/arm/SA1100/SA1100_USB for more info, or the
++ * kerneldoc for the API exposed to gadget drivers.
++ *
++ */
++//#define DEBUG       1
++//#define     VERBOSE 1
++
++//#define SA1100_USB_DEBUG
++#ifdef SA1100_USB_DEBUG
++static int sa1100_usb_debug=0;
++#endif
++
++#define NCB_DMA_FIX
++#ifdef NCB_DMA_FIX
++// This is a clunky fix for dma alignemnt issues
++// It should probably be done better by someone more 
++// steeped in DMA lore
++#include <linux/slab.h>
++#define SEND_BUFFER_SIZE 4096 /* this is probably a bit big */
++#define RECEIVE_BUFFER_SIZE 256       /* 64 may be all that is necessary */
++static char *send_buffer=NULL;
++static char *receive_buffer=NULL;
++#endif
++
++#include <linux/module.h>
++#include <linux/kernel.h>
++#include <linux/delay.h>
++#include <linux/ioport.h>
++#include <linux/sched.h>
++#include <linux/slab.h>
++#include <linux/smp_lock.h>
++#include <linux/errno.h>
++#include <linux/init.h>
++#include <linux/timer.h>
++#include <linux/list.h>
++#include <linux/interrupt.h>
++#include <linux/version.h>
++#include <linux/device.h>
++#include <linux/platform_device.h>
++
++#include <asm/byteorder.h>
++#include <asm/io.h>
++#include <asm/irq.h>
++#include <mach/dma.h>
++#include <asm/system.h>
++#include <asm/mach-types.h>
++#include <asm/unaligned.h>
++
++#include <linux/usb.h>
++#include <linux/usb/ch9.h>
++#include <linux/usb/gadget.h>
++
++#if CONFIG_PROC_FS
++#include <linux/proc_fs.h>
++#endif
++
++#if defined(CONFIG_SA1100_BALLOON)
++#include <asm/arch/balloon2.h>
++#endif
++
++#if defined(CONFIG_SA1100_COLLIE)
++#include <linux/gpio.h>
++#include <mach/collie.h>
++#endif
++
++#define       DRIVER_VERSION          __DATE__
++
++#define       DMA_ADDR_INVALID (~(dma_addr_t)0)
++
++
++static const char driver_name [] = "sa1100_udc";
++static const char driver_desc [] = "SA-1110 USB Device Controller";
++
++static const char ep0name [] = "ep0";
++
++#ifdef        DEBUG
++static char *type_string (u8 bmAttributes)
++{
++      switch ( (bmAttributes) & USB_ENDPOINT_XFERTYPE_MASK) {
++      case USB_ENDPOINT_XFER_BULK:    return "bulk";
++      //case USB_ENDPOINT_XFER_ISOC:  return "iso";
++      case USB_ENDPOINT_XFER_INT:     return "intr";
++      };
++      return "control";
++}
++#endif
++
++#include <linux/dma-mapping.h>
++struct usb_stats_t {
++       unsigned long ep0_fifo_write_failures;
++       unsigned long ep0_bytes_written;
++       unsigned long ep0_fifo_read_failures;
++       unsigned long ep0_bytes_read;
++};
++
++struct usb_info_t {
++      dma_regs_t *dmaregs_tx, *dmaregs_rx;
++      int state;
++      unsigned char address;
++      struct usb_stats_t stats;
++};
++
++enum { kError=-1, kEvSuspend=0, kEvReset=1,
++         kEvResume=2, kEvAddress=3, kEvConfig=4, kEvDeConfig=5 };
++int usbctl_next_state_on_event( int event ) {
++    return 0;
++}
++static struct usb_info_t usbd_info;
++
++/* receiver */
++void ep1_reset(void);
++void ep1_stall(void);
++int sa1100_usb_recv (struct usb_request *req, void (*callback) (int,int));
++
++/* xmitter */
++void ep2_reset(void);
++void ep2_stall(void);
++int sa1100_usb_send (struct usb_request *req, void (*callback) (int,int));
++
++/* UDC register utility functions */
++#define UDC_write(reg, val) { \
++      int i = 10000; \
++      do { \
++              (reg) = (val); \
++              if (i-- <= 0) { \
++                      printk( "%s [%d]: write %#x to %p (%#lx) failed\n", \
++                              __FUNCTION__, __LINE__, (val), &(reg), (reg)); \
++                      break; \
++              } \
++      } while((reg) != (val)); \
++}
++
++#define UDC_set(reg, val) { \
++      int i = 10000; \
++      do { \
++              (reg) |= (val); \
++              if (i-- <= 0) { \
++                      printk( "%s [%d]: set %#x of %p (%#lx) failed\n", \
++                              __FUNCTION__, __LINE__, (val), &(reg), (reg)); \
++                      break; \
++              } \
++      } while(!((reg) & (val))); \
++}
++
++#define UDC_clear(reg, val) { \
++      int i = 10000; \
++      do { \
++              (reg) &= ~(val); \
++              if (i-- <= 0) { \
++                      printk( "%s [%d]: clear %#x of %p (%#lx) failed\n", \
++                              __FUNCTION__, __LINE__, (val), &(reg), (reg)); \
++                      break; \
++              } \
++      } while((reg) & (val)); \
++}
++
++#define UDC_flip(reg, val) { \
++      int i = 10000; \
++      (reg) = (val); \
++      do { \
++              (reg) = (val); \
++              if (i-- <= 0) { \
++                      printk( "%s [%d]: flip %#x of %p (%#lx) failed\n", \
++                              __FUNCTION__, __LINE__, (val), &(reg), (reg)); \
++                      break; \
++              } \
++      } while(((reg) & (val))); \
++}
++
++#include "sa1100_udc.h"
++
++static struct sa1100_udc      *the_controller;
++static void nuke (struct sa1100_ep *, int status);
++static void done (struct sa1100_ep *ep, struct sa1100_request *req, int status);
++static inline void ep0_idle (struct sa1100_udc *dev)
++{
++      dev->ep0state = EP0_IDLE;
++}
++
++// ep0 handlers
++
++// 1 == lots of trace noise,  0 = only "important' stuff
++#define VERBOSITY 0
++
++#if 1 && !defined( ASSERT )
++#  define ASSERT(expr) \
++          if(!(expr)) { \
++          printk( "Assertion failed! %s,%s,%s,line=%d\n",\
++          #expr,__FILE__,__FUNCTION__,__LINE__); \
++          }
++#else
++#  define ASSERT(expr)
++#endif
++
++#if VERBOSITY
++#define PRINTKD(fmt, args...) printk( fmt , ## args)
++#else
++#define PRINTKD(fmt, args...)
++#endif
++
++/* other subroutines */
++unsigned int (*wrint)(void);
++void ep0_int_hndlr( void );
++static void ep0_queue(void *buf, unsigned int req, unsigned int act);
++static void write_fifo( void );
++static int read_fifo( struct usb_ctrlrequest * p );
++
++/* some voodo helpers  01Mar01ww */
++static void set_cs_bits( __u32 set_bits );
++static void set_de( void );
++static void set_ipr( void );
++static void set_ipr_and_de( void );
++static bool clear_opr( void );
++
++/***************************************************************************
++Inline Helpers
++***************************************************************************/
++
++/* Data extraction from usb_request_t fields */
++enum { kTargetDevice=0, kTargetInterface=1, kTargetEndpoint=2 };
++static inline int request_target( __u8 b ) { return (int) ( b & 0x0F); }
++
++static inline int windex_to_ep_num( __u16 w ) { return (int) ( w & 0x000F); }
++inline int type_code_from_request( __u8 by ) { return (( by >> 4 ) & 3); }
++
++/* following is hook for self-powered flag in GET_STATUS. Some devices
++   .. might like to override and return real info */
++static inline bool self_powered_hook( void ) { return true; }
++
++#if VERBOSITY
++/* "pcs" == "print control status" */
++static inline void pcs( void )
++{
++       __u32 foo = Ser0UDCCS0;
++       printk( "%8.8X: %s %s %s %s\n",
++                       foo,
++                       foo & UDCCS0_SE ? "SE" : "",
++                       foo & UDCCS0_OPR ? "OPR" : "",
++                       foo & UDCCS0_IPR ? "IPR" : "",
++                       foo & UDCCS0_SST ? "SST" : ""
++       );
++}
++static inline void preq( struct usb_ctrlrequest * pReq )
++{
++       static char * tnames[] = { "dev", "intf", "ep", "oth" };
++       static char * rnames[] = { "std", "class", "vendor", "???" };
++       char * psz;
++       switch( pReq->bRequest ) {
++       case USB_REQ_GET_STATUS: psz = "get stat"; break;
++       case USB_REQ_CLEAR_FEATURE: psz = "clr feat"; break;
++       case USB_REQ_SET_FEATURE: psz = "set feat"; break;
++       case USB_REQ_SET_ADDRESS: psz = "set addr"; break;
++       case USB_REQ_GET_DESCRIPTOR: psz = "get desc"; break;
++       case USB_REQ_SET_DESCRIPTOR: psz = "set desc"; break;
++       case USB_REQ_GET_CONFIGURATION: psz = "get cfg"; break;
++       case USB_REQ_SET_CONFIGURATION: psz = "set cfg"; break;
++       case USB_REQ_GET_INTERFACE: psz = "get intf"; break;
++       case USB_REQ_SET_INTERFACE: psz = "set intf"; break;
++       default: psz = "unknown"; break;
++       }
++       printk( "- [%s: %s req to %s. dir=%s]\n", psz,
++                       rnames[ (pReq->bRequestType >> 5) & 3 ],
++                       tnames[ pReq->bRequestType & 3 ],
++                       ( pReq->bRequestType & 0x80 ) ? "in" : "out" );
++}
++
++static inline void usbctl_dump_request(const char *prefix, const struct usb_ctrlrequest *req)
++{
++      printk("%s: bRequestType=0x%02x bRequest=0x%02x "
++              "wValue=0x%04x wIndex=0x%04x wLength=0x%04x\n",
++              prefix, req->bRequestType, req->bRequest,
++              le16_to_cpu(req->wValue), le16_to_cpu(req->wIndex),
++              le16_to_cpu(req->wLength));
++}
++#else
++static inline void pcs( void ){}
++//static inline void preq( void ){}
++static inline void preq( void *x ){}
++static inline void usbctl_dump_request(const char *prefix, const struct usb_ctrlrequest *req) {}
++#endif
++
++/***************************************************************************
++Globals
++***************************************************************************/
++static const char pszMe[] = "usbep0: ";
++
++
++/* global write struct to keep write
++   ..state around across interrupts */
++static struct {
++              unsigned char *p;
++              int bytes_left;
++} wr;
++
++/***************************************************************************
++Public Interface
++***************************************************************************/
++
++/* reset received from HUB (or controller just went nuts and reset by itself!)
++  so udc core has been reset, track this state here  */
++void ep0_reset(void)
++{
++      /* reset state machine */
++      wr.p = NULL;
++      wr.bytes_left = 0;
++      usbd_info.address=0;
++// needed?
++      Ser0UDCAR = 0;
++}
++
++
++/* handle interrupt for endpoint zero */
++
++inline void ep0_clear_write(void) {
++      wr.p = NULL;
++      wr.bytes_left = 0;
++}
++
++/* this is a config packet parser based on that from the updated HH 2.6 udc */
++static void ep0_read_packet(void)
++{
++       unsigned char status_buf[2];  /* returned in GET_STATUS */
++       struct usb_ctrlrequest req;
++       int request_type;
++       int n;
++       __u32 address;
++       __u32 in, out;
++
++       /* reset previous count */
++       the_controller->ep0_req_len=-1;
++
++       /* read the setup request */
++       n = read_fifo( &req );
++       usbctl_dump_request("ep0_read_packet",&req);
++
++       if ( n != sizeof( req ) ) {
++                printk( "%ssetup begin: fifo READ ERROR wanted %d bytes got %d. "
++                                " Stalling out...\n",
++                                pszMe, sizeof( req ), n );
++                /* force stall, serviced out */
++                set_cs_bits( UDCCS0_FST | UDCCS0_SO  );
++                goto sh_sb_end;
++       }
++
++       /* Is it a standard request? (not vendor or class request) */
++       request_type = type_code_from_request( req.bRequestType );
++       if ( request_type != 0 ) {
++                printk( "%ssetup begin: unsupported bRequestType: %d ignored\n",
++                                pszMe, request_type );
++                set_cs_bits( UDCCS0_DE | UDCCS0_SO );
++                goto sh_sb_end;
++       }
++
++      /* save requested reply size */
++      the_controller->ep0_req_len=le16_to_cpu(req.wLength);
++      PRINTKD("%s: request length is %d\n",__FUNCTION__,the_controller->ep0_req_len);
++
++#if VERBOSITY
++       {
++       unsigned char * pdb = (unsigned char *) &req;
++       PRINTKD( "%2.2X %2.2X %2.2X %2.2X %2.2X %2.2X %2.2X %2.2X ",
++                       pdb[0], pdb[1], pdb[2], pdb[3], pdb[4], pdb[5], pdb[6], pdb[7]
++                );
++       preq( &req );
++       }
++#endif
++
++       /* Handle it */
++       switch( req.bRequest ) {
++
++                /* This first bunch have no data phase */
++
++       case USB_REQ_SET_ADDRESS:
++                address = (__u32) (req.wValue & 0x7F);
++                /* when SO and DE sent, UDC will enter status phase and ack,
++                       ..propagating new address to udc core. Next control transfer
++                       ..will be on the new address. You can't see the change in a
++                       ..read back of CAR until then. (about 250us later, on my box).
++                       ..The original Intel driver sets S0 and DE and code to check
++                       ..that address has propagated here. I tried this, but it
++                       ..would only work sometimes! The rest of the time it would
++                       ..never propagate and we'd spin forever. So now I just set
++                       ..it and pray...
++                */
++                Ser0UDCAR = address;
++                usbd_info.address = address;
++                usbctl_next_state_on_event( kEvAddress );
++                set_cs_bits( UDCCS0_SO | UDCCS0_DE );  /* no data phase */
++                printk( "%sI have been assigned address: %d\n", pszMe, address );
++                break;
++
++
++       case USB_REQ_SET_CONFIGURATION:
++                if ( req.wValue == 1 ) {
++                         /* configured */
++                         if (usbctl_next_state_on_event( kEvConfig ) != kError) {
++                              /* (re)set the out and in max packet sizes */
++                              PRINTKD( "%s: calling the_controller.driver->setup with SET_CONFIGURATION\n", __FUNCTION__ );
++                              the_controller->driver->setup(&the_controller->gadget, &req);
++                                      in  = __le16_to_cpu( the_controller->ep[1].ep.maxpacket );
++                                      out = __le16_to_cpu( the_controller->ep[2].ep.maxpacket );
++                                      Ser0UDCOMP = ( out - 1 );
++                                      Ser0UDCIMP = ( in - 1 );
++                              // we are configured
++                              usbd_info.state = USB_STATE_CONFIGURED;
++                              // enable rx and tx interrupts
++                              Ser0UDCCR &= ~(UDCCR_RIM | UDCCR_TIM);
++
++                              printk( "%sConfigured (OMP=%8.8X IMP=%8.8X)\n", pszMe, out, in );
++                              break;
++                         }
++                } else if ( req.wValue == 0 ) {
++                         /* de-configured */
++                         if (usbctl_next_state_on_event( kEvDeConfig ) != kError )
++                                      printk( "%sDe-Configured\n", pszMe );
++                      usbd_info.state = 0;
++                      Ser0UDCCR |= UDCCR_RIM | UDCCR_TIM;
++                      ep1_reset ();
++                      ep2_reset ();
++                      printk("%s: de-configured. Tx and Rx interrupts disabled. ep1 and ep2 reset\n",__FUNCTION__);
++                } else {
++                         printk( "%ssetup phase: Unknown "
++                                         "\"set configuration\" data %d\n",
++                                         pszMe, req.wValue );
++                }
++                set_cs_bits( UDCCS0_SO | UDCCS0_DE );  /* no data phase */
++                break;
++
++       case USB_REQ_CLEAR_FEATURE:
++                /* could check data length, direction...26Jan01ww */
++                if ( req.wValue == 0 ) { /* clearing ENDPOINT_HALT/STALL */
++                         int ep = windex_to_ep_num( req.wIndex );
++                         if ( ep == 1 ) {
++                                      printk( "%sclear feature \"endpoint halt\" "
++                                                      " on receiver\n", pszMe );
++                                      ep1_reset();
++                         }
++                         else if ( ep == 2 ) {
++                                      printk( "%sclear feature \"endpoint halt\" "
++                                                      "on xmitter\n", pszMe );
++                                      ep2_reset();
++                         } else {
++                                      printk( "%sclear feature \"endpoint halt\" "
++                                                      "on unsupported ep # %d\n",
++                                                      pszMe, ep );
++                         }
++                } else {
++                         printk( "%sUnsupported feature selector (%d) "
++                                         "in clear feature. Ignored.\n" ,
++                                         pszMe, req.wValue );
++                }
++                set_cs_bits( UDCCS0_SO | UDCCS0_DE );  /* no data phase */
++                break;
++
++       case USB_REQ_SET_FEATURE:
++                if ( req.wValue == 0 ) { /* setting ENDPOINT_HALT/STALL */
++                         int ep = windex_to_ep_num( req.wValue );
++                         if ( ep == 1 ) {
++                                      printk( "%set feature \"endpoint halt\" "
++                                                      "on receiver\n", pszMe );
++                                      ep1_stall();
++                         }
++                         else if ( ep == 2 ) {
++                                      printk( "%sset feature \"endpoint halt\" "
++                                                      " on xmitter\n", pszMe );
++                                      ep2_stall();
++                         } else {
++                                      printk( "%sset feature \"endpoint halt\" "
++                                                      "on unsupported ep # %d\n",
++                                                      pszMe, ep );
++                         }
++                }
++                else {
++                         printk( "%sUnsupported feature selector "
++                                         "(%d) in set feature\n",
++                                         pszMe, req.wValue );
++                }
++                set_cs_bits( UDCCS0_SO | UDCCS0_DE );  /* no data phase */
++                break;
++
++                /* The rest have a data phase that writes back to the host */
++       case USB_REQ_GET_STATUS:
++                /* return status bit flags */
++                status_buf[0] = status_buf[1] = 0;
++                n = request_target(req.bRequestType);
++                switch( n ) {
++                case kTargetDevice:
++                         if ( self_powered_hook() )
++                                      status_buf[0] |= 1;
++                         break;
++                case kTargetInterface:
++                         break;
++                case kTargetEndpoint:
++                         /* return stalled bit */
++                         n = windex_to_ep_num( req.wIndex );
++                         if ( n == 1 )
++                                      status_buf[0] |= (Ser0UDCCS1 & UDCCS1_FST) >> 4;
++                         else if ( n == 2 )
++                                      status_buf[0] |= (Ser0UDCCS2 & UDCCS2_FST) >> 5;
++                         else {
++                                      printk( "%sUnknown endpoint (%d) "
++                                                      "in GET_STATUS\n", pszMe, n );
++                         }
++                         break;
++                default:
++                         printk( "%sUnknown target (%d) in GET_STATUS\n",
++                                         pszMe, n );
++                         /* fall thru */
++                         break;
++                }
++                PRINTKD("%s: GET_STATUS writing %d\n",__FUNCTION__,req.wLength);
++                ep0_queue( status_buf, req.wLength, sizeof( status_buf ));
++                break;
++       case USB_REQ_GET_DESCRIPTOR:
++                PRINTKD( "%s: calling the_controller.driver->setup with GET_DESCRIPTOR\n", __FUNCTION__ );
++                the_controller->driver->setup(&the_controller->gadget, &req);
++                break;
++       case USB_REQ_GET_CONFIGURATION:
++                PRINTKD( "%s: calling the_controller.driver->setup with GET_CONFIGURATION\n", __FUNCTION__ );
++                the_controller->driver->setup(&the_controller->gadget, &req);
++                break;
++       case USB_REQ_GET_INTERFACE:
++                PRINTKD( "%s: calling the_controller->driver->setup with GET_INTERFACE\n", __FUNCTION__ );
++                the_controller->driver->setup(&the_controller->gadget, &req);
++                break;
++       case USB_REQ_SET_INTERFACE:
++                PRINTKD( "%s: calling the_controller->driver->setup with SET_INTERFACE\n", __FUNCTION__ );
++                the_controller->driver->setup(&the_controller->gadget, &req);
++                break;
++       default :
++                printk("%sunknown request 0x%x\n", pszMe, req.bRequest);
++                break;
++       } /* switch( bRequest ) */
++
++sh_sb_end:
++       return;
++
++}
++
++void ep0_int_hndlr(void)
++{
++      u32 cs_reg_in;
++
++      pcs();
++
++      cs_reg_in = Ser0UDCCS0;
++
++      /*
++       * If "setup end" has been set, the usb controller has terminated
++       * a setup transaction before we set DE. This happens during
++       * enumeration with some hosts. For example, the host will ask for
++       * our device descriptor and specify a return of 64 bytes. When we
++       * hand back the first 8, the host will know our max packet size
++       * and turn around and issue a new setup immediately. This causes
++       * the UDC to auto-ack the new setup and set SE. We must then
++       * "unload" (process) the new setup, which is what will happen
++       * after this preamble is finished executing.
++       */
++      if (cs_reg_in & UDCCS0_SE) {
++              PRINTKD("UDC: early termination of setup\n");
++
++              /*
++               * Clear setup end
++               */
++              set_cs_bits(UDCCS0_SSE);
++
++              /*
++               * Clear any pending write.
++               */
++              ep0_clear_write();
++      }
++
++      /*
++       * UDC sent a stall due to a protocol violation.
++       */
++      if (cs_reg_in & UDCCS0_SST) {
++              PRINTKD("UDC: write_preamble: UDC sent stall\n");
++
++              /*
++               * Clear sent stall
++               */
++              set_cs_bits(UDCCS0_SST);
++
++              /*
++               * Clear any pending write.
++               */
++              ep0_clear_write();
++      }
++
++      switch (cs_reg_in & (UDCCS0_OPR | UDCCS0_IPR)) {
++      case UDCCS0_OPR | UDCCS0_IPR:
++              PRINTKD("UDC: write_preamble: see OPR. Stopping write to "
++                      "handle new SETUP\n");
++
++              /*
++               * very rarely, you can get OPR and
++               * leftover IPR. Try to clear
++               */
++              UDC_clear(Ser0UDCCS0, UDCCS0_IPR);
++
++              /*
++               * Clear any pending write.
++               */
++              ep0_clear_write();
++
++              /*FALLTHROUGH*/
++      case UDCCS0_OPR:
++              /*
++               * A new setup request is pending.  Handle
++               * it. Note that we don't try to read a
++               * packet if SE was set and OPR is clear.
++               */
++              ep0_read_packet();
++              break;
++
++      case 0:
++              // if data pending ...
++              if (wr.p) {
++                      unsigned int cs_bits = 0;
++                      if (wr.bytes_left != 0) {
++                              /*
++                               * More data to go
++                               */
++                              write_fifo();
++                              // packet ready
++                              cs_bits |= UDCCS0_IPR;
++                      }
++
++                      if (wr.bytes_left == 0) {
++                              /*
++                               * All data sent.
++                               */
++                              cs_bits |= wrint();
++                              // a null packet may be following
++                              if (!wrint)
++                                  ep0_clear_write();
++                      }
++                      set_cs_bits(cs_bits);
++              }
++              else
++                  PRINTKD("%s: No data - probably an ACK\n",__FUNCTION__);
++              break;
++
++      case UDCCS0_IPR:
++              PRINTKD("UDC: IPR set, not writing\n");
++              break;
++      }
++
++      pcs();
++      PRINTKD( "-end-\n" );
++}
++
++static unsigned int ep0_sh_write_data(void)
++{
++      /*
++       * If bytes left is zero, we are coming in on the
++       * interrupt after the last packet went out. And
++       * we know we don't have to empty packet this
++       * transfer so just set DE and we are done
++       */
++      PRINTKD("UDC: normal packet ended\n");
++      wrint=NULL;
++      return UDCCS0_DE;
++}
++
++static unsigned int ep0_sh_write_with_empty_packet(void)
++{
++      /*
++       * If bytes left is zero, we are coming in on the
++       * interrupt after the last packet went out.
++       * We must do short packet suff, so set DE and IPR
++       */
++      PRINTKD("UDC: short packet sent\n");
++      wrint=NULL;
++      return UDCCS0_IPR | UDCCS0_DE;
++}
++
++static unsigned int ep0_sh_write_data_then_empty_packet(void)
++{
++      PRINTKD("UDC: last packet full. Send empty packet next\n");
++      wrint=ep0_sh_write_with_empty_packet;
++      return 0;
++}
++
++static void ep0_queue(void *buf, unsigned int len, unsigned int req_len)
++{
++      __u32 cs_reg_bits = UDCCS0_IPR;
++
++      PRINTKD("a=%d r=%d\n", len, req_len);
++
++      if (len == 0) {
++          // no output packet to wait for
++          PRINTKD("%s: zero byte packet being queued. Setting DE and OPR end exiting\n",__FUNCTION__);
++          set_cs_bits(UDCCS0_DE | UDCCS0_SO);
++          return;
++      }
++
++      /*
++       * thou shalt not enter data phase until
++       * Out Packet Ready is clear
++       */
++      if (!clear_opr()) {
++              printk("UDC: SO did not clear OPR\n");
++              set_cs_bits(UDCCS0_DE | UDCCS0_SO);
++              return;
++      }
++
++      // note data to xmit stored
++      wr.p=buf;
++      wr.bytes_left=min(len, req_len);
++
++      // write the first block
++      write_fifo();
++
++      // done already?
++      if (wr.bytes_left == 0) {
++              /*
++               * out in one, so data end
++               */
++              cs_reg_bits |= UDCCS0_DE;
++              ep0_clear_write();
++      // rest is a shorter than expected reply?
++      } else if (len < req_len) {
++              /*
++               * we are going to short-change host
++               * so need nul to not stall
++               */
++               if (len % 8) {
++                  PRINTKD("%s: %d more to go ending in a short packet.\n",__FUNCTION__,wr.bytes_left);
++                  wrint=ep0_sh_write_with_empty_packet;
++              }
++              // unless we are on a packet boundary. Then send full packet plus null packet.
++              else {
++                  PRINTKD("%s: %d more to go then add empty packet.\n",__FUNCTION__,wr.bytes_left);
++                  wrint=ep0_sh_write_data_then_empty_packet;
++              }
++      } else {
++              /*
++               * we have as much or more than requested
++               */
++              PRINTKD("%s: %d more to go.\n",__FUNCTION__,wr.bytes_left);
++              wrint=ep0_sh_write_data;
++      }
++
++      /*
++       * note: IPR was set uncondtionally at start of routine
++       */
++      set_cs_bits(cs_reg_bits);
++}
++
++/*
++ * write_fifo()
++ * Stick bytes in the 8 bytes endpoint zero FIFO.
++ * This version uses a variety of tricks to make sure the bytes
++ * are written correctly. 1. The count register is checked to
++ * see if the byte went in, and the write is attempted again
++ * if not. 2. An overall counter is used to break out so we
++ * don't hang in those (rare) cases where the UDC reverses
++ * direction of the FIFO underneath us without notification
++ * (in response to host aborting a setup transaction early).
++ *
++ */
++static void write_fifo( void )
++{
++      int bytes_this_time = min(wr.bytes_left, 8);
++      int bytes_written = 0;
++
++      PRINTKD( "WF=%d: ", bytes_this_time );
++
++      while( bytes_this_time-- ) {
++              unsigned int cwc;
++              int i;
++               PRINTKD( "%2.2X ", *wr.p );
++              cwc = Ser0UDCWC & 15;
++               i = 10;
++               do {
++                        Ser0UDCD0 = *wr.p;
++                        udelay( 20 );  /* voodo 28Feb01ww */
++               } while( (Ser0UDCWC &15) == cwc && --i );
++
++               if ( i == 0 ) {
++                        printk( "%swrite_fifo: write failure\n", pszMe );
++                        usbd_info.stats.ep0_fifo_write_failures++;
++               }
++
++               wr.p++;
++               bytes_written++;
++      }
++      wr.bytes_left -= bytes_written;
++
++      /* following propagation voodo so maybe caller writing IPR in
++         ..a moment might actually get it to stick 28Feb01ww */
++      udelay( 300 );
++
++      usbd_info.stats.ep0_bytes_written += bytes_written;
++      PRINTKD( "L=%d WCR=%8.8lX\n", wr.bytes_left, Ser0UDCWC );
++}
++/*
++ * read_fifo()
++ * Read 1-8 bytes out of FIFO and put in request.
++ * Called to do the initial read of setup requests
++ * from the host. Return number of bytes read.
++ *
++ * Like write fifo above, this driver uses multiple
++ * reads checked agains the count register with an
++ * overall timeout.
++ *
++ */
++static int
++read_fifo( struct usb_ctrlrequest * request )
++{
++      int bytes_read = 0;
++      int fifo_count;
++
++      unsigned char * pOut = (unsigned char*) request;
++
++      fifo_count = ( Ser0UDCWC & 0xFF );
++
++      ASSERT( fifo_count <= 8 );
++      PRINTKD( "RF=%d ", fifo_count );
++
++      while( fifo_count-- ) {
++              unsigned int cwc;
++              int i;
++
++              cwc = Ser0UDCWC & 15;
++
++               i = 10;
++               do {
++                        *pOut = (unsigned char) Ser0UDCD0;
++                        udelay( 20 );
++               } while( ( Ser0UDCWC & 15 ) == cwc && --i );
++
++               if ( i == 0 ) {
++                        printk( "%sread_fifo(): read failure\n", pszMe );
++                        usbd_info.stats.ep0_fifo_read_failures++;
++               }
++               pOut++;
++               bytes_read++;
++      }
++
++      PRINTKD( "fc=%d\n", bytes_read );
++      usbd_info.stats.ep0_bytes_read++;
++      return bytes_read;
++}
++
++/* some voodo I am adding, since the vanilla macros just aren't doing it  1Mar01ww */
++
++#define ABORT_BITS ( UDCCS0_SST | UDCCS0_SE )
++#define OK_TO_WRITE (!( Ser0UDCCS0 & ABORT_BITS ))
++#define BOTH_BITS (UDCCS0_IPR | UDCCS0_DE)
++
++static void set_cs_bits( __u32 bits )
++{
++       if ( bits & ( UDCCS0_SO | UDCCS0_SSE | UDCCS0_FST | UDCCS0_SST) )
++                Ser0UDCCS0 = bits;
++       else if ( (bits & BOTH_BITS) == BOTH_BITS )
++                set_ipr_and_de();
++       else if ( bits & UDCCS0_IPR )
++                set_ipr();
++       else if ( bits & UDCCS0_DE )
++                set_de();
++}
++
++static void set_de( void )
++{
++       int i = 1;
++       while( 1 ) {
++                if ( OK_TO_WRITE ) {
++                              Ser0UDCCS0 |= UDCCS0_DE;
++                } else {
++                         PRINTKD( "%sQuitting set DE because SST or SE set\n", pszMe );
++                         break;
++                }
++                if ( Ser0UDCCS0 & UDCCS0_DE )
++                         break;
++                udelay( i );
++                if ( ++i == 50  ) {
++                         printk( "%sDangnabbbit! Cannot set DE! (DE=%8.8X CCS0=%8.8lX)\n",
++                                         pszMe, UDCCS0_DE, Ser0UDCCS0 );
++                         break;
++                }
++       }
++}
++
++static void set_ipr( void )
++{
++       int i = 1;
++       while( 1 ) {
++                if ( OK_TO_WRITE ) {
++                              Ser0UDCCS0 |= UDCCS0_IPR;
++                } else {
++                         PRINTKD( "%sQuitting set IPR because SST or SE set\n", pszMe );
++                         break;
++                }
++                if ( Ser0UDCCS0 & UDCCS0_IPR )
++                         break;
++                udelay( i );
++                if ( ++i == 50  ) {
++                         printk( "%sDangnabbbit! Cannot set IPR! (IPR=%8.8X CCS0=%8.8lX)\n",
++                                         pszMe, UDCCS0_IPR, Ser0UDCCS0 );
++                         break;
++                }
++       }
++}
++
++static void set_ipr_and_de( void )
++{
++       int i = 1;
++       while( 1 ) {
++                if ( OK_TO_WRITE ) {
++                         Ser0UDCCS0 |= BOTH_BITS;
++                } else {
++                         PRINTKD( "%sQuitting set IPR/DE because SST or SE set\n", pszMe );
++                         break;
++                }
++                if ( (Ser0UDCCS0 & BOTH_BITS) == BOTH_BITS)
++                         break;
++                udelay( i );
++                if ( ++i == 50  ) {
++                         printk( "%sDangnabbbit! Cannot set DE/IPR! (DE=%8.8X IPR=%8.8X CCS0=%8.8lX)\n",
++                                         pszMe, UDCCS0_DE, UDCCS0_IPR, Ser0UDCCS0 );
++                         break;
++                }
++       }
++}
++
++static bool clear_opr( void )
++{
++       int i = 10000;
++       bool is_clear;
++       do {
++                Ser0UDCCS0 = UDCCS0_SO;
++                is_clear  = ! ( Ser0UDCCS0 & UDCCS0_OPR );
++                if ( i-- <= 0 ) {
++                         printk( "%sclear_opr(): failed\n", pszMe );
++                         break;
++                }
++       } while( ! is_clear );
++       return is_clear;
++}
++
++
++
++// ep1 handlers
++
++static char *ep1_buf;
++static int ep1_len;
++static void (*ep1_callback)(int flag, int size);
++static char *ep1_curdmabuf;
++static dma_addr_t ep1_curdmapos;
++static int ep1_curdmalen;
++static int ep1_remain;
++static int ep1_used;
++
++static dma_regs_t *dmaregs_rx = NULL;
++static int rx_pktsize;
++
++static int naking;
++
++static void
++ep1_start(void)
++{
++      sa1100_reset_dma(dmaregs_rx);
++      if (!ep1_curdmalen) {
++              ep1_curdmalen = rx_pktsize;
++              if (ep1_curdmalen > ep1_remain)
++                      ep1_curdmalen = ep1_remain;
++              ep1_curdmapos = dma_map_single(NULL, ep1_curdmabuf, ep1_curdmalen,
++                                             DMA_FROM_DEVICE);
++      }
++
++      UDC_write( Ser0UDCOMP, ep1_curdmalen-1 );
++
++      sa1100_start_dma(dmaregs_rx, ep1_curdmapos, ep1_curdmalen);
++
++      if ( naking ) {
++              /* turn off NAK of OUT packets, if set */
++              UDC_flip( Ser0UDCCS1, UDCCS1_RPC );
++              naking = 0;
++      }
++}
++
++static void
++ep1_done(int flag)
++{
++      int size = ep1_len - ep1_remain;
++
++      if (!ep1_len)
++              return;
++      if (ep1_curdmalen)
++              dma_unmap_single(NULL, ep1_curdmapos, ep1_curdmalen,
++                               DMA_FROM_DEVICE);
++      ep1_len = ep1_curdmalen = 0;
++      if (ep1_callback)
++              ep1_callback(flag, size);
++}
++
++void
++ep1_state_change_notify( int new_state )
++{
++
++}
++
++void
++ep1_stall( void )
++{
++      /* SET_FEATURE force stall at UDC */
++      UDC_set( Ser0UDCCS1, UDCCS1_FST );
++}
++
++int
++ep1_init(dma_regs_t *dmaregs)
++{
++      dmaregs_rx = dmaregs;
++      sa1100_reset_dma(dmaregs_rx);
++      ep1_done(-EAGAIN);
++      return 0;
++}
++
++void
++ep1_reset(void)
++{
++      if (dmaregs_rx)
++          sa1100_reset_dma(dmaregs_rx);
++      UDC_clear(Ser0UDCCS1, UDCCS1_FST);
++      ep1_done(-EINTR);
++}
++
++void ep1_int_hndlr(int udcsr)
++{
++      dma_addr_t dma_addr;
++      unsigned int len;
++      int status = Ser0UDCCS1;
++
++      if ( naking ) printk( "%sEh? in ISR but naking = %d\n", "usbrx: ", naking );
++
++      if (status & UDCCS1_RPC) {
++
++              if (!ep1_curdmalen) {
++                      printk("usb_recv: RPC for non-existent buffer\n");
++                      naking=1;
++                      return;
++              }
++
++              sa1100_stop_dma(dmaregs_rx);
++
++              if (status & UDCCS1_SST) {
++                      printk("usb_recv: stall sent OMP=%ld\n", Ser0UDCOMP);
++                      UDC_flip(Ser0UDCCS1, UDCCS1_SST);
++                      ep1_done(-EIO); // UDC aborted current transfer, so we do
++                      return;
++              }
++
++              if (status & UDCCS1_RPE) {
++                      printk("usb_recv: RPError %x\n", status);
++                      UDC_flip(Ser0UDCCS1, UDCCS1_RPC);
++                      ep1_done(-EIO);
++                      return;
++              }
++
++              dma_addr=sa1100_get_dma_pos(dmaregs_rx);
++              dma_unmap_single(NULL, ep1_curdmapos, ep1_curdmalen,
++                               DMA_FROM_DEVICE);
++              len = dma_addr - ep1_curdmapos;
++#ifdef SA1100_USB_DEBUG
++              if (sa1100_usb_debug) {
++                  int i;
++                  printk("usb rx %d :\n  ",len);
++                  if (sa1100_usb_debug>1) {
++                              for (i=0; i<len; i++) {
++                              if ((i % 32)==31)
++                                      printk("\n  ");
++                              printk("%2.2x ",((char *)ep1_curdmapos)[i]);
++                              }
++                  }
++                  printk("\n");
++              }
++#endif
++              if (len < ep1_curdmalen) {
++                      char *buf = ep1_curdmabuf + len;
++                      while (Ser0UDCCS1 & UDCCS1_RNE) {
++                              if (len >= ep1_curdmalen) {
++                                      printk("usb_recv: too much data in fifo\n");
++                                      break;
++                              }
++                              *buf++ = Ser0UDCDR;
++                              len++;
++                      }
++              } else if (Ser0UDCCS1 & UDCCS1_RNE) {
++                      printk("usb_recv: fifo screwed, shouldn't contain data\n");
++                      len = 0;
++              }
++
++#if defined(NCB_DMA_FIX)
++//            if (len && (ep1_buf != ep1_curdmabuf))
++//                memcpy(ep1_buf,ep1_curdmabuf,len);
++              if (len)
++                  memcpy(&(((unsigned char *)ep1_buf)[ep1_used]),ep1_curdmabuf,len);
++#endif
++
++              ep1_curdmalen = 0;  /* dma unmap already done */
++              ep1_remain -= len;
++              ep1_used += len;
++//            ep1_curdmabuf += len;   // use same buffer again
++              naking = 1;
++//printk("%s: received %d, %d remaining\n",__FUNCTION__,len,ep1_remain);
++              if (len && (len == rx_pktsize))
++                  ep1_start();
++              else
++              ep1_done((len) ? 0 : -EPIPE);
++      }
++      /* else, you can get here if we are holding NAK */
++}
++
++int
++sa1100_usb_recv(struct usb_request *req, void (*callback)(int flag, int size))
++{
++      unsigned long flags;
++      char *buf=req->buf;
++      int len=req->length;
++
++      if (ep1_len)
++              return -EBUSY;
++
++      local_irq_save(flags);
++      ep1_buf = buf;
++      ep1_len = len;
++      ep1_callback = callback;
++      ep1_remain = len;
++      ep1_used = 0;
++#ifdef NCB_DMA_FIX
++//    if (((size_t)buf)&3)
++      if (1)
++          ep1_curdmabuf = receive_buffer;
++      else
++#else
++      ep1_curdmabuf = buf;
++#endif
++      ep1_curdmalen = 0;
++      ep1_start();
++      local_irq_restore(flags);
++
++      return 0;
++}
++
++// ep2 handlers
++
++static char *ep2_buf;
++static int ep2_len;
++static void (*ep2_callback)(int status, int size);
++static dma_addr_t ep2_dma;
++static dma_addr_t ep2_curdmapos;
++static int ep2_curdmalen;
++static int ep2_remain;
++static dma_regs_t *dmaregs_tx = NULL;
++static int tx_pktsize;
++
++/* device state is changing, async */
++void
++ep2_state_change_notify( int new_state )
++{
++}
++
++/* set feature stall executing, async */
++void
++ep2_stall( void )
++{
++      UDC_set( Ser0UDCCS2, UDCCS2_FST );  /* force stall at UDC */
++}
++
++static void
++ep2_start(void)
++{
++      if (!ep2_len)
++              return;
++
++      ep2_curdmalen = tx_pktsize;
++      if (ep2_curdmalen > ep2_remain)
++              ep2_curdmalen = ep2_remain;
++
++      /* must do this _before_ queue buffer.. */
++      UDC_flip( Ser0UDCCS2,UDCCS2_TPC );  /* stop NAKing IN tokens */
++      UDC_write( Ser0UDCIMP, ep2_curdmalen-1 );
++
++      Ser0UDCAR = usbd_info.address; // fighting stupid silicon bug
++      sa1100_start_dma(dmaregs_tx, ep2_curdmapos, ep2_curdmalen);
++}
++
++static void
++ep2_done(int flag)
++{
++      int size = ep2_len - ep2_remain;
++      if (ep2_len) {
++              dma_unmap_single(NULL, ep2_dma, ep2_len, DMA_TO_DEVICE);
++              ep2_len = 0;
++              if (ep2_callback)
++                      ep2_callback(flag, size);
++      }
++}
++
++int ep2_init(dma_regs_t *dmaregs)
++{
++      dmaregs_tx = dmaregs;
++      sa1100_reset_dma(dmaregs_tx);
++      ep2_done(-EAGAIN);
++      return 0;
++}
++
++void ep2_reset(void)
++{
++      UDC_clear(Ser0UDCCS2, UDCCS2_FST);
++      if (dmaregs_tx)
++          sa1100_reset_dma(dmaregs_tx);
++      ep2_done(-EINTR);
++}
++
++void ep2_int_hndlr(int udcsr)
++{
++      int status = Ser0UDCCS2;
++
++      if (Ser0UDCAR != usbd_info.address) // check for stupid silicon bug.
++              Ser0UDCAR = usbd_info.address;
++
++      if (status & UDCCS2_TPC) {
++
++              UDC_flip(Ser0UDCCS2, UDCCS2_SST);
++
++              sa1100_reset_dma(dmaregs_tx);
++
++              if (status & (UDCCS2_TPE | UDCCS2_TUR)) {
++                      printk("usb_send: transmit error %x\n", status);
++                      ep2_done(-EIO);
++              } else {
++                      ep2_curdmapos += ep2_curdmalen;
++                      ep2_remain -= ep2_curdmalen;
++
++                      if (ep2_remain != 0)
++                              ep2_start();
++                      else
++                              ep2_done(0);
++              }
++      } else {
++              printk("usb_send: Not TPC: UDCCS2 = %x\n", status);
++      }
++}
++
++int
++sa1100_usb_send(struct usb_request *req, void (*callback)(int status, int size))
++{
++      char *buf=req->buf;
++      int len=req->length;
++      unsigned long flags;
++
++      if (usbd_info.state != USB_STATE_CONFIGURED) {
++              PRINTKD("%s: return -ENODEV\n",__FUNCTION__);
++              return -ENODEV;
++      }
++
++      if (ep2_len) {
++              PRINTKD("%s: return -EBUSY\n",__FUNCTION__);
++              return -EBUSY;
++      }
++
++      local_irq_save(flags);
++#ifdef NCB_DMA_FIX
++      // if misaligned, copy to aligned buffer
++//    if (((size_t)buf)&3) {
++      if (1) {
++          PRINTKD("%s: copying %d bytes to send_buffer\n",__FUNCTION__,len);
++          memcpy(send_buffer,buf,len);
++          ep2_buf = send_buffer;
++      }
++      else
++#endif
++      ep2_buf = buf;
++
++      ep2_len = len;
++      ep2_dma = dma_map_single(NULL, ep2_buf, len,DMA_TO_DEVICE);
++      PRINTKD("%s: mapped dma to buffer(%p0\n",__FUNCTION__,buf);
++
++      ep2_callback = callback;
++      ep2_remain = len;
++      ep2_curdmapos = ep2_dma;
++
++      PRINTKD("%s: calling ep2_start\n",__FUNCTION__);
++      ep2_start();
++      local_irq_restore(flags);
++
++      return 0;
++}
++/*-------------------------------------------------------------------------*/
++
++static int
++sa1100_enable(struct usb_ep *_ep, const struct usb_endpoint_descriptor *desc)
++{
++      struct sa1100_udc       *dev;
++      struct sa1100_ep        *ep;
++      u32                     max;
++      int                     type;
++
++      ep = container_of (_ep, struct sa1100_ep, ep);
++      if (!_ep || !desc || ep->desc || _ep->name == ep0name
++                      || desc->bDescriptorType != USB_DT_ENDPOINT) {
++              PRINTKD("%s: _ep = %p, desc = %p\n",__FUNCTION__,_ep,desc);
++              if (_ep && desc)
++                  PRINTKD("%s: ep->desc = %p, _ep->name = %s desc->bDescriptorType = %s\n",__FUNCTION__,ep->desc,_ep->name,
++                      (desc->bDescriptorType == USB_DT_ENDPOINT) ? "USB_DT_ENDPOINT":"bad!!");
++              return -EINVAL;
++      }
++
++      dev = ep->dev;
++      if (!dev->driver || dev->gadget.speed == USB_SPEED_UNKNOWN)
++              return -ESHUTDOWN;
++
++      type = desc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK;
++      max = le16_to_cpu (desc->wMaxPacketSize);
++      switch (max) {
++      case 64: case 32:
++      /* note:  maxpacket > 16 means DMA might overrun/underrun */
++      case 16: case 8:
++              break;
++      default:
++              if (type == USB_ENDPOINT_XFER_INT && max < 64)
++                      break;
++              return -EDOM;
++      }
++
++      switch (type) {
++      case USB_ENDPOINT_XFER_BULK:
++      case USB_ENDPOINT_XFER_INT:
++              if (ep == &dev->ep[2]) {
++                      if (desc->bEndpointAddress != (USB_DIR_IN|2)) {
++                              PRINTKD("%s: ep[2] has invalid endpoint\n",__FUNCTION__);
++                              return -EINVAL;
++                      }
++                      tx_pktsize = max;
++                      Ser0UDCOMP = max - 1;
++                      PRINTKD("%s: ep2 max packet size is %d\n",__FUNCTION__,max);
++                      break;
++              } else if (ep == &dev->ep[1]) {
++                      if (desc->bEndpointAddress != (USB_DIR_OUT|1)) {
++                              PRINTKD("%s: ep[1] has invalid endpoint\n",__FUNCTION__);
++                              return -EINVAL;
++                      }
++                      rx_pktsize = max;
++                      Ser0UDCIMP = max - 1;
++                      PRINTKD("%s: ep1 max packet size is %d\n",__FUNCTION__,max);
++                      break;
++              }
++              // FALLTHROUGH
++      default:
++              PRINTKD("%s: Invalid endpoint\n",__FUNCTION__);
++              return -EINVAL;
++      }
++
++      _ep->maxpacket = max;
++      ep->desc = desc;
++      ep->stopped = 0;
++
++      DEBUG (dev, "enabled %s %s max %04x\n", _ep->name,
++              type_string (desc->bmAttributes), max);
++
++      return 0;
++}
++
++static int sa1100_disable (struct usb_ep *_ep)
++{
++      struct sa1100_ep        *ep;
++
++      ep = container_of (_ep, struct sa1100_ep, ep);
++      if (!_ep || !ep->desc || _ep->name == ep0name)
++              return -EINVAL;
++
++      nuke (ep, -ESHUTDOWN);
++
++      DEBUG (ep->dev, "disabled %s\n", _ep->name);
++
++      ep->desc = NULL;
++      ep->stopped = 1;
++      return 0;
++}
++
++/*-------------------------------------------------------------------------*/
++
++static struct usb_request *
++sa1100_alloc_request (struct usb_ep *_ep, gfp_t gfp_flags)
++{
++      struct sa1100_request *req;
++
++      if (!_ep)
++              return 0;
++
++      req = kzalloc(sizeof *req, gfp_flags);
++      if (!req)
++              return 0;
++
++      memset (req, 0, sizeof *req);
++      req->req.dma = DMA_ADDR_INVALID;
++      INIT_LIST_HEAD (&req->queue);
++      return &req->req;
++}
++
++static void sa1100_free_request(struct usb_ep *_ep, struct usb_request *_req)
++{
++      struct sa1100_request   *req;
++
++      req = container_of (_req, struct sa1100_request, req);
++      WARN_ON (!list_empty (&req->queue));
++      kfree(req);     //NCB - see pxa2xx_udc
++}
++
++/*-------------------------------------------------------------------------*/
++
++static void done(struct sa1100_ep *ep, struct sa1100_request *req, int status)
++{
++      unsigned                stopped = ep->stopped;
++
++      list_del_init (&req->queue);
++
++      if (likely(req->req.status == -EINPROGRESS))
++              req->req.status = status;
++      else
++              status = req->req.status;
++
++      if (status && status != -ESHUTDOWN)
++              VDEBUG (ep->dev, "complete %s req %p stat %d len %u/%u\n",
++                      ep->ep.name, &req->req, status,
++                      req->req.actual, req->req.length);
++
++      /* don't modify queue heads during completion callback */
++      ep->stopped = 1;
++      req->req.complete (&ep->ep, &req->req);
++      ep->stopped = stopped;
++}
++
++/*-------------------------------------------------------------------------*/
++
++/* FIXME move away from the old non-queued api.
++ * - forces extra work on us
++ * - stores request state twice
++ * - doesn't let gadget driver handle dma mapping
++ * - status codes need mapping
++ */
++
++static int map_status(int status)
++{
++      switch (status) {
++      case 0:
++      case -EIO:      /* ep[12]_int_handler */
++              return status;
++      case -EPIPE:    /* ep1_int_handler */
++              return 0;
++      //  case -EAGAIN:       /* ep[12]_init */
++      //  case -EINTR:        /* ep[12]_reset */
++      default:
++              return -ESHUTDOWN;
++      }
++}
++
++static void tx_callback(int status, int size)
++{
++      struct sa1100_ep        *ep = &the_controller->ep[2];
++      struct sa1100_request   *req;
++
++      if (list_empty (&ep->queue)) {
++              if (status != -EAGAIN)
++                      DEBUG (ep->dev, "%s, bogus tx callback %d/%d\n",
++                              ep->ep.name, status, size);
++              return;
++      }
++      req = list_entry (ep->queue.next, struct sa1100_request, queue);
++      req->req.actual = size;
++      done (ep, req, map_status (status));
++
++      if (ep->stopped || list_empty (&ep->queue))
++              return;
++      req = list_entry (ep->queue.next, struct sa1100_request, queue);
++      sa1100_usb_send (&req->req, tx_callback);
++}
++
++static void rx_callback (int status, int size)
++{
++      struct sa1100_ep        *ep = &the_controller->ep[1];
++      struct sa1100_request   *req;
++
++      if (list_empty (&ep->queue)) {
++              if (status != -EAGAIN)
++                      DEBUG (ep->dev, "%s, bogus tx callback %d/%d\n",
++                              ep->ep.name, status, size);
++              return;
++      }
++      req = list_entry (ep->queue.next, struct sa1100_request, queue);
++      req->req.actual = size;
++      done (ep, req, map_status (status));
++
++      if (ep->stopped || list_empty (&ep->queue))
++              return;
++      req = list_entry (ep->queue.next, struct sa1100_request, queue);
++      sa1100_usb_recv (&req->req, rx_callback);
++}
++
++
++static int
++sa1100_queue (struct usb_ep *_ep, struct usb_request *_req, gfp_t gfp_flags)
++{
++      struct sa1100_request   *req;
++      struct sa1100_ep        *ep;
++      struct sa1100_udc       *dev;
++      unsigned long           flags;
++
++      req = container_of (_req, struct sa1100_request, req);
++      if (!_req || !_req->complete || !_req->buf
++                      || !list_empty (&req->queue))
++              return -EINVAL;
++
++      ep = container_of (_ep, struct sa1100_ep, ep);
++      if (unlikely(!_ep || (!ep->desc && _ep->name != ep0name)))
++              return -EINVAL;
++
++      dev = ep->dev;
++      if (unlikely(!dev->driver || dev->gadget.speed == USB_SPEED_UNKNOWN))
++              return -ESHUTDOWN;
++
++      // handle ep0
++      if (_ep->name == ep0name) {
++          ep0_queue( _req->buf, _req->length, dev->ep0_req_len >=0 ? dev->ep0_req_len: _req->length );
++          return 0;
++      }
++
++      /* sa1100 udc can't write zlps */
++      if (ep == &dev->ep[2] && _req->length == 0)
++              return -ERANGE;
++
++      /* the old sa1100 api doesn't use 'unsigned' for lengths */
++      if (_req->length > INT_MAX)
++              return -ERANGE;
++
++      VDEBUG (dev, "%s queue req %p, len %d buf %p\n",
++                      _ep->name, _req, _req->length, _req->buf);
++
++      local_irq_save (flags);
++
++      _req->status = -EINPROGRESS;
++      _req->actual = 0;
++
++      if (list_empty (&ep->queue) && !ep->stopped) {
++              /* FIXME this does DMA mapping wrong.  caller is allowed
++               * to provide buffers that don't need mapping, but this
++               * doesn't use them.
++               */
++              if (ep == &ep->dev->ep[2]) {
++                      PRINTKD("%s: sa1100_usb_send buf %p length %d\n",__FUNCTION__,_req->buf,_req->length);
++                      sa1100_usb_send (_req, tx_callback);
++              }
++              else if (ep == &ep->dev->ep[1]) {
++                      PRINTKD("%s: sa1100_usb_recv buf %p length %d\n",__FUNCTION__,_req->buf,_req->length);
++                      sa1100_usb_recv (_req, rx_callback);
++              }
++              /* ep0 rx/tx is handled separately */
++      }
++      list_add_tail (&req->queue, &ep->queue);
++
++      local_irq_restore (flags);
++
++      return 0;
++}
++
++/* dequeue ALL requests */
++static void nuke (struct sa1100_ep *ep, int status)
++{
++      struct sa1100_request   *req;
++
++      /* called with irqs blocked */
++      while (!list_empty (&ep->queue)) {
++              req = list_entry (ep->queue.next,
++                              struct sa1100_request,
++                              queue);
++              done (ep, req, status);
++      }
++      if (ep == &ep->dev->ep[1])
++              ep1_reset ();
++      else if (ep == &ep->dev->ep[2])
++              ep2_reset ();
++}
++
++/* dequeue JUST ONE request */
++static int sa1100_dequeue (struct usb_ep *_ep, struct usb_request *_req)
++{
++      struct sa1100_ep        *ep;
++      struct sa1100_request   *req;
++      unsigned long           flags;
++
++      ep = container_of (_ep, struct sa1100_ep, ep);
++      if (!_ep || (!ep->desc && _ep->name != ep0name) || !_req)
++              return -EINVAL;
++
++      local_irq_save (flags);
++
++      /* make sure it's actually queued on this endpoint */
++      list_for_each_entry (req, &ep->queue, queue) {
++              if (&req->req == _req)
++                      break;
++      }
++      if (&req->req != _req) {
++              local_irq_restore(flags);
++              return -EINVAL;
++      }
++
++      done(ep, req, -ECONNRESET);
++
++      local_irq_restore(flags);
++
++      return 0;
++}
++
++/*-------------------------------------------------------------------------*/
++
++static int
++sa1100_set_halt (struct usb_ep *_ep, int value)
++{
++      struct sa1100_ep        *ep;
++
++      ep = container_of (_ep, struct sa1100_ep, ep);
++      if (unlikely(!_ep 
++              || (!ep->desc && _ep->name != ep0name))
++              || (ep->desc->bmAttributes & 0x03) == USB_ENDPOINT_XFER_ISOC)
++              return -EINVAL;
++      if (!ep->dev->driver || ep->dev->gadget.speed == USB_SPEED_UNKNOWN)
++              return -ESHUTDOWN;
++
++      VDEBUG (ep->dev, "%s %s halt\n", _ep->name, value ? "set" : "clear");
++
++      /* set/clear, then synch memory views with the device */
++      if (value) {
++              if (ep == &ep->dev->ep[1])
++                      ep1_stall ();
++              else
++                      ep2_stall ();
++      } else {
++              if (ep == &ep->dev->ep[1])
++                      ep1_reset ();
++              else
++                      ep2_reset ();
++      }
++
++      return 0;
++}
++
++static struct usb_ep_ops sa1100_ep_ops = {
++      .enable         = sa1100_enable,
++      .disable        = sa1100_disable,
++
++      .alloc_request  = sa1100_alloc_request,
++      .free_request   = sa1100_free_request,
++
++      .queue          = sa1100_queue,
++      .dequeue        = sa1100_dequeue,
++
++      .set_halt       = sa1100_set_halt,
++      // .fifo_status = sa1100_fifo_status,
++      // .fifo_flush  = sa1100_fifo_flush,
++};
++
++/*-------------------------------------------------------------------------*/
++
++static int sa1100_get_frame (struct usb_gadget *_gadget)
++{
++      return -EOPNOTSUPP;
++}
++
++static int sa1100_wakeup (struct usb_gadget *_gadget)
++{
++      struct sa1100_udc       *dev;
++
++      if (!_gadget)
++              return 0;
++      dev = container_of (_gadget, struct sa1100_udc, gadget);
++
++      // FIXME
++
++      return 0;
++}
++
++static const struct usb_gadget_ops sa1100_ops = {
++      .get_frame      = sa1100_get_frame,
++      .wakeup         = sa1100_wakeup,
++
++      // .set_selfpowered = sa1100_set_selfpowered,
++};
++
++/*-------------------------------------------------------------------------*/
++
++static inline void enable_resume_mask_suspend (void)
++{
++       int i = 0;
++
++       while (1) {
++                Ser0UDCCR |= UDCCR_SUSIM; // mask future suspend events
++                udelay (i);
++                if ( (Ser0UDCCR & UDCCR_SUSIM) || (Ser0UDCSR & UDCSR_RSTIR))
++                         break;
++                if (++i == 50) {
++                         WARN_ (&the_controller, "%s Could not set SUSIM %8.8lX\n",
++                                      __FUNCTION__, Ser0UDCCR);
++                         break;
++                }
++       }
++
++       i = 0;
++       while (1) {
++                Ser0UDCCR &= ~UDCCR_RESIM;
++                udelay (i);
++                if ( (Ser0UDCCR & UDCCR_RESIM) == 0
++                              || (Ser0UDCSR & UDCSR_RSTIR))
++                         break;
++                if (++i == 50) {
++                         WARN_ (&the_controller, "%s Could not clear RESIM %8.8lX\n",
++                                      __FUNCTION__, Ser0UDCCR);
++                         break;
++                }
++       }
++}
++
++static inline void enable_suspend_mask_resume (void)
++{
++       int i = 0;
++       while (1) {
++                Ser0UDCCR |= UDCCR_RESIM; // mask future resume events
++                udelay (i);
++                if (Ser0UDCCR & UDCCR_RESIM || (Ser0UDCSR & UDCSR_RSTIR))
++                         break;
++                if (++i == 50) {
++                         WARN_ (&the_controller, "%s could not set RESIM %8.8lX\n",
++                                      __FUNCTION__, Ser0UDCCR);
++                         break;
++                }
++       }
++       i = 0;
++       while (1) {
++                Ser0UDCCR &= ~UDCCR_SUSIM;
++                udelay (i);
++                if ( (Ser0UDCCR & UDCCR_SUSIM) == 0
++                              || (Ser0UDCSR & UDCSR_RSTIR))
++                         break;
++                if (++i == 50) {
++                         WARN_ (&the_controller, "%s Could not clear SUSIM %8.8lX\n",
++                                      __FUNCTION__, Ser0UDCCR);
++                         break;
++                }
++       }
++}
++
++// HACK DEBUG  3Mar01ww
++// Well, maybe not, it really seems to help!  08Mar01ww
++static void core_kicker (void)
++{
++      u32 car = Ser0UDCAR;
++      u32 imp = Ser0UDCIMP;
++      u32 omp = Ser0UDCOMP;
++
++      UDC_set (Ser0UDCCR, UDCCR_UDD);
++      udelay (300);
++      UDC_clear (Ser0UDCCR, UDCCR_UDD);
++
++      Ser0UDCAR = car;
++      Ser0UDCIMP = imp;
++      Ser0UDCOMP = omp;
++}
++
++static irqreturn_t udc_int_hndlr(int irq, void *_dev)
++{
++      struct sa1100_udc       *dev = _dev;
++      u32                     status = Ser0UDCSR;
++
++      PRINTKD("%s: status = 0x%x and control = 0x%lx\n", __FUNCTION__,
++                      status, Ser0UDCCR);
++      /* ReSeT Interrupt Request - UDC has been reset */
++      if (status & UDCSR_RSTIR) {
++              PRINTKD("%s: processing UDCSR_RSTIR\n", __FUNCTION__);
++              if (usbctl_next_state_on_event(kEvReset) != kError) {
++                      /* starting 20ms or so reset sequence now... */
++                      INFO (dev, "Resetting\n");
++                      ep0_reset();  // just set state to idle
++                      ep1_reset();  // flush dma, clear false stall
++                      ep2_reset();  // flush dma, clear false stall
++              }
++              // mask reset ints, they flood during sequence, enable
++              // suspend and resume
++              UDC_set(Ser0UDCCR, UDCCR_REM);    // mask reset
++              UDC_clear(Ser0UDCCR, (UDCCR_SUSIM | UDCCR_RESIM)); // enable suspend and resume
++              UDC_flip(Ser0UDCSR, status);    // clear all pending sources
++              PRINTKD("%s: setting USB_FULL_SPEED\n",__FUNCTION__);
++              dev->gadget.speed = USB_SPEED_FULL;
++              return IRQ_HANDLED;     // NCB
++      }
++
++      /* else we have done something other than reset,
++       * so be sure reset enabled
++       */
++      UDC_clear(Ser0UDCCR, UDCCR_REM);
++
++      /* RESume Interrupt Request */
++      if (status & UDCSR_RESIR) {
++              struct usb_gadget_driver        *driver = dev->driver;
++
++              PRINTKD("%s: processing UDCSR_RESIR\n",__FUNCTION__);
++              if (driver->resume)
++                      driver->resume (&dev->gadget);
++              core_kicker ();
++              enable_suspend_mask_resume ();
++      }
++
++      /* SUSpend Interrupt Request */
++      if (status & UDCSR_SUSIR) {
++              struct usb_gadget_driver        *driver = dev->driver;
++
++              PRINTKD("%s: processing UDCSR_SUSIR\n",__FUNCTION__);
++              if (driver->suspend)
++                      driver->suspend (&dev->gadget);
++              enable_resume_mask_suspend ();
++      }
++
++      UDC_flip(Ser0UDCSR, status); // clear all pending sources
++
++      if (status & UDCSR_EIR)
++              PRINTKD("%s: processing ep0_int_hndlr\n",__FUNCTION__);
++               ep0_int_hndlr();
++
++      if (status & UDCSR_RIR) {
++              PRINTKD("%s: processing ep1_int_hndlr\n",__FUNCTION__);
++              ep1_int_hndlr(status);
++      }
++      if (status & UDCSR_TIR) {
++              PRINTKD("%s: processing ep2_int_hndlr\n",__FUNCTION__);
++              ep2_int_hndlr(status);
++      }
++
++      return IRQ_HANDLED;     // NCB
++}
++
++/* soft_connect_hook ()
++ * Some devices have platform-specific circuitry to make USB
++ * not seem to be plugged in, even when it is. This allows
++ * software to control when a device 'appears' on the USB bus
++ * (after Linux has booted and this driver has loaded, for
++ * example). If you have such a circuit, control it here.
++ */
++#ifdef CONFIG_SA1100_EXTENEX1
++static void soft_connect_hook(int enable)
++{
++      if (machine_is_extenex1 ()) {
++              if (enable) {
++                      PPDR |= PPC_USB_SOFT_CON;
++                      PPSR |= PPC_USB_SOFT_CON;
++              } else {
++                      PPSR &= ~PPC_USB_SOFT_CON;
++                      PPDR &= ~PPC_USB_SOFT_CON;
++              }
++      }
++}
++#elif defined(CONFIG_SA1100_BALLOON)
++static void soft_connect_hook(int enable)
++{
++      if (machine_is_balloon()) {
++          if (enable)
++                      balloon_cpld_control(BALLOON_UDC_DISCONNECT, 0);
++          else
++                      balloon_cpld_control(BALLOON_UDC_DISCONNECT, 1);
++      }
++}
++#elif defined(CONFIG_SA1100_COLLIE)
++static int collie_usb_init(void)
++{
++        int rc;
++        rc = gpio_request(COLLIE_GPIO_LB_VOL_CHG, "usb enable");
++        if (rc)
++                return rc;
++
++        rc = gpio_direction_output(COLLIE_GPIO_LB_VOL_CHG, 1);
++        if (rc)
++                gpio_free(COLLIE_GPIO_LB_VOL_CHG);
++
++        return rc;
++}
++
++static void collie_set_usb(int enable)
++{
++        gpio_set_value(COLLIE_GPIO_LB_VOL_CHG, enable);
++}
++
++static void collie_usb_exit(void)
++{
++        gpio_free(COLLIE_GPIO_LB_VOL_CHG);
++}
++
++static void soft_connect_hook(int enable)
++{
++      collie_set_usb(enable);
++}
++#else
++#define soft_connect_hook(x) do { } while (0);
++#endif
++
++/* "function" sysfs attribute */
++static ssize_t
++show_function(struct device *_dev, struct device_attribute *attr, char *buf)
++{
++      struct sa1100_udc       *dev = dev_get_drvdata (_dev);
++
++      if (!dev->driver
++                      || !dev->driver->function
++                      || strlen(dev->driver->function) > PAGE_SIZE)
++              return 0;
++      return scnprintf (buf, PAGE_SIZE, "%s\n", dev->driver->function);
++}
++static DEVICE_ATTR(function, S_IRUGO, show_function, NULL);
++
++/* disable the UDC at the source */
++static void udc_disable(struct sa1100_udc *dev)
++{
++      soft_connect_hook(0);
++      UDC_set(Ser0UDCCR, UDCCR_UDD);
++      dev->gadget.speed = USB_SPEED_UNKNOWN;
++      ep0_idle(dev);
++}
++
++static void udc_reinit(struct sa1100_udc *dev)
++{
++      u32     i;
++
++      /* Initialize the gadget controller data structure */
++      INIT_LIST_HEAD(&dev->gadget.ep_list);
++      INIT_LIST_HEAD(&dev->gadget.ep0->ep_list);
++      ep0_idle(dev);
++      for ( i = 0 ; i < 3 ; i++) {
++              struct sa1100_ep *ep = &dev->ep[i];
++              if (i != 0)
++                      list_add_tail(&ep->ep.ep_list, &dev->gadget.ep_list);
++              ep->desc     = NULL;
++              ep->stopped  = 0;
++              INIT_LIST_HEAD(&ep->queue);
++      }
++}
++
++/*  enable the udc at the source */
++static void udc_enable(struct sa1100_udc *dev)
++{
++      UDC_clear (Ser0UDCCR, UDCCR_UDD);
++      ep0_idle(dev);
++}
++
++static void ep0_start(struct sa1100_udc *dev)
++{
++      udc_enable(dev);
++      udelay(100);
++
++      /* clear stall - receiver seems to start stalled? 19Jan01ww */
++      /* also clear other stuff just to be thurough 22Feb01ww */
++      UDC_clear(Ser0UDCCS1, UDCCS1_FST | UDCCS1_RPE | UDCCS1_RPC );
++      UDC_clear(Ser0UDCCS2, UDCCS2_FST | UDCCS2_TPE | UDCCS2_TPC );
++
++      /* mask everything */
++      Ser0UDCCR = 0xFC;
++
++      /* flush DMA and fire through some -EAGAINs */
++      ep1_init(dev->ep[1].dmaregs);
++      ep2_init(dev->ep[2].dmaregs);
++
++      /* enable any platform specific hardware */
++      soft_connect_hook(1);
++
++      /* clear all top-level sources */
++      Ser0UDCSR = UDCSR_RSTIR | UDCSR_RESIR | UDCSR_EIR |
++                       UDCSR_RIR | UDCSR_TIR | UDCSR_SUSIR ;
++
++      /* EXERIMENT - a short line in the spec says toggling this
++       * bit diddles the internal state machine in the udc to
++       * expect a suspend
++       */
++      Ser0UDCCR  |= UDCCR_RESIM;
++      /* END EXPERIMENT 10Feb01ww */
++
++      /* enable any platform specific hardware */
++      soft_connect_hook(1);
++
++      /* Enable interrupts. If you are unplugged you will immediately
++       * get a suspend interrupt. If you are plugged and have a soft
++       * connect-circuit, you will get a reset.  If you are plugged
++       * without a soft-connect, I think you also get suspend. In short,
++       * start with suspend masked and everything else enabled
++       */
++      UDC_write(Ser0UDCCR, UDCCR_SUSIM);
++}
++
++
++/* when a driver is successfully registered, it will receive
++ * control requests including set_configuration(), which enables
++ * non-control requests.  then usb traffic follows until a
++ * disconnect is reported.  then a host may connect again, or
++ * the driver might get unbound.
++ */
++int usb_gadget_register_driver(struct usb_gadget_driver *driver)
++{
++      struct sa1100_udc       *dev = the_controller;
++      int                     retval;
++
++      if (!driver || !driver->bind || !driver->setup)
++              return -EINVAL;
++      if (!dev)
++              return -ENODEV;
++      if (dev->driver)
++              return -EBUSY;
++
++      /* hook up the driver ... */
++      dev->driver = driver;
++      dev->gadget.dev.driver = &driver->driver;
++
++      retval = device_add(&dev->gadget.dev);
++      if (retval != 0) {
++              printk(KERN_ERR "Error in device_add() : %d\n",retval);
++              goto register_error;
++      }
++
++      retval = driver->bind (&dev->gadget);
++      if (retval != 0) {
++              DEBUG(dev, "bind to driver %s --> %d\n",
++                              driver->driver.name, retval);
++              device_del(&dev->gadget.dev);
++              goto register_error;
++      }
++
++      retval = device_create_file(dev->dev, &dev_attr_function);
++
++      /* ... then enable host detection and ep0; and we're ready
++       * for set_configuration as well as eventual disconnect.
++       */
++      ep0_start(dev);
++
++      DEBUG(dev, "%s ready\n", driver->driver.name);
++
++      return 0;
++
++register_error:
++      dev->driver = NULL;
++      dev->gadget.dev.driver = NULL;
++      return retval;
++}
++EXPORT_SYMBOL (usb_gadget_register_driver);
++
++static void
++stop_activity(struct sa1100_udc *dev, struct usb_gadget_driver *driver)
++{
++      int i;
++
++      /* don't disconnect if it's not connected */
++      if (dev->gadget.speed == USB_SPEED_UNKNOWN)
++              driver = NULL;
++      dev->gadget.speed = USB_SPEED_UNKNOWN;
++
++      /* mask everything */
++      Ser0UDCCR = 0xFC;
++
++      /* stop hardware; prevent new request submissions;
++       * and kill any outstanding requests.
++       */
++      for (i = 0; i < 3; i++) {
++              struct sa1100_ep *ep = &dev->ep[i];
++              ep->stopped = 1;
++              nuke(ep, -ESHUTDOWN);
++      }
++      udc_disable (dev);
++
++      /* report disconnect; the driver is already quiesced */
++      if (driver)
++              driver->disconnect(&dev->gadget);
++
++      /* re-init driver-visible data structures */
++      udc_reinit(dev);
++}
++
++int usb_gadget_unregister_driver(struct usb_gadget_driver *driver)
++{
++      struct sa1100_udc       *dev = the_controller;
++
++      if (!dev)
++              return -ENODEV;
++      if (!driver || driver != dev->driver)
++              return -EINVAL;
++
++      local_irq_disable();
++      stop_activity (dev, driver);
++      local_irq_enable();
++      if (driver->unbind)
++              driver->unbind(&dev->gadget);
++      dev->driver = 0;
++
++      device_del(&dev->gadget.dev);
++      device_remove_file(dev->dev, &dev_attr_function);
++
++      DEBUG (dev, "unregistered driver '%s'\n", driver->driver.name);
++      return 0;
++}
++EXPORT_SYMBOL (usb_gadget_unregister_driver);
++
++
++/*-------------------------------------------------------------------------*/
++
++/*-------------------------------------------------------------------------*/
++
++//////////////////////////////////////////////////////////////////////////////
++// Proc Filesystem Support
++//////////////////////////////////////////////////////////////////////////////
++
++#if CONFIG_PROC_FS
++
++#define SAY(fmt,args...)  p += sprintf (p, fmt, ## args)
++#define SAYV(num)         p += sprintf (p, num_fmt, "Value", num)
++#define SAYC(label,yn)    p += sprintf (p, yn_fmt, label, yn)
++#define SAYS(label,v)     p += sprintf (p, cnt_fmt, label, v)
++
++static int usbctl_read_proc (char *page, char **start, off_t off,
++                          int count, int *eof, void *data)
++{
++       const char * num_fmt   = "%25.25s: %8.8lX\n";
++       const char * cnt_fmt   = "%25.25s: %lu\n";
++       const char * yn_fmt    = "%25.25s: %s\n";
++       const char * yes       = "YES";
++       const char * no        = "NO";
++       unsigned long v;
++       char * p = page;
++       int len;
++
++       SAY ("SA1100 USB Controller Core\n");
++
++       SAYS ("ep0 bytes read", usbd_info.stats.ep0_bytes_read);
++       SAYS ("ep0 bytes written", usbd_info.stats.ep0_bytes_written);
++       SAYS ("ep0 FIFO read failures", usbd_info.stats.ep0_fifo_read_failures);
++       SAYS ("ep0 FIFO write failures", usbd_info.stats.ep0_fifo_write_failures);
++
++       SAY ("\n");
++
++       v = Ser0UDCAR;
++       SAY ("%25.25s: 0x%8.8lX - %ld\n", "Address Register", v, v);
++       v = Ser0UDCIMP;
++       SAY ("%25.25s: %ld (%8.8lX)\n", "IN  max packet size", v+1, v);
++       v = Ser0UDCOMP;
++       SAY ("%25.25s: %ld (%8.8lX)\n", "OUT max packet size", v+1, v);
++
++       v = Ser0UDCCR;
++       SAY ("\nUDC Mask Register\n");
++       SAYV (v);
++       SAYC ("UDC Active", (v & UDCCR_UDA) ? yes : no);
++       SAYC ("Suspend interrupts masked", (v & UDCCR_SUSIM) ? yes : no);
++       SAYC ("Resume interrupts masked", (v & UDCCR_RESIM) ? yes : no);
++       SAYC ("Reset interrupts masked", (v & UDCCR_REM) ? yes : no);
++
++       v = Ser0UDCSR;
++       SAY ("\nUDC Interrupt Request Register\n");
++       SAYV (v);
++       SAYC ("Reset pending", (v & UDCSR_RSTIR) ? yes : no);
++       SAYC ("Suspend pending", (v & UDCSR_SUSIR) ? yes : no);
++       SAYC ("Resume pending", (v & UDCSR_RESIR) ? yes : no);
++       SAYC ("ep0 pending", (v & UDCSR_EIR)   ? yes : no);
++       SAYC ("receiver pending", (v & UDCSR_RIR)   ? yes : no);
++       SAYC ("tramsitter pending", (v & UDCSR_TIR)   ? yes : no);
++
++#ifdef CONFIG_SA1100_EXTENEX1
++       SAYC ("\nSoft connect", (PPSR & PPC_USB_SOFT_CON) ? "Visible" : "Hidden");
++#endif
++
++#if 1
++       SAY ("\nDMA Tx registers\n");
++       {
++       dma_regs_t *r=the_controller->ep[2].dmaregs;
++       SAY (" DDAR");
++       SAYV(r->DDAR);
++       SAY (" DCSR");
++       SAYV(r->RdDCSR);
++       SAY (" DBSA (address buf A) ");
++       SAYV(r->DBSA);
++       SAY (" DBTA (transfer count A) ");
++       SAYV(r->DBTA);
++       SAY (" DBSB (address buf B) ");
++       SAYV(r->DBSB);
++       SAY (" DBTB (transfer count B) ");
++       SAYV(r->DBTB);
++
++       }
++       SAY ("\nDMA Rx registers\n");
++       {
++       dma_regs_t *r=the_controller->ep[1].dmaregs;
++       SAY (" DDAR");
++       SAYV(r->DDAR);
++       SAY (" DCSR");
++       SAYV(r->RdDCSR);
++       SAY (" DBSA (address buf A) ");
++       SAYV(r->DBSA);
++       SAY (" DBTA (transfer count A) ");
++       SAYV(r->DBTA);
++       SAY (" DBSB (address buf B) ");
++       SAYV(r->DBSB);
++       SAY (" DBTB (transfer count B) ");
++       SAYV(r->DBTB);
++
++       }
++#endif
++#if 1
++       v = Ser0UDCCS0;
++       SAY ("\nUDC Endpoint Zero Status Register\n");
++       SAYV (v);
++       SAYC ("Out Packet Ready", (v & UDCCS0_OPR) ? yes : no);
++       SAYC ("In Packet Ready", (v & UDCCS0_IPR) ? yes : no);
++       SAYC ("Sent Stall", (v & UDCCS0_SST) ? yes : no);
++       SAYC ("Force Stall", (v & UDCCS0_FST) ? yes : no);
++       SAYC ("Data End", (v & UDCCS0_DE)  ? yes : no);
++       SAYC ("Data Setup End", (v & UDCCS0_SE)  ? yes : no);
++       SAYC ("Serviced (SO)", (v & UDCCS0_SO)  ? yes : no);
++
++       v = Ser0UDCCS1;
++       SAY ("\nUDC Receiver Status Register\n");
++       SAYV (v);
++       SAYC ("Receive Packet Complete", (v & UDCCS1_RPC) ? yes : no);
++       SAYC ("Sent Stall", (v & UDCCS1_SST) ? yes : no);
++       SAYC ("Force Stall", (v & UDCCS1_FST) ? yes : no);
++       SAYC ("Receive Packet Error", (v & UDCCS1_RPE) ? yes : no);
++       SAYC ("Receive FIFO not empty", (v & UDCCS1_RNE) ? yes : no);
++
++       v = Ser0UDCCS2;
++       SAY ("\nUDC Transmitter Status Register\n");
++       SAYV (v);
++       SAYC ("FIFO has < 8 of 16 chars", (v & UDCCS2_TFS) ? yes : no);
++       SAYC ("Transmit Packet Complete", (v & UDCCS2_TPC) ? yes : no);
++       SAYC ("Transmit FIFO underrun", (v & UDCCS2_TUR) ? yes : no);
++       SAYC ("Transmit Packet Error", (v & UDCCS2_TPE) ? yes : no);
++       SAYC ("Sent Stall", (v & UDCCS2_SST) ? yes : no);
++       SAYC ("Force Stall", (v & UDCCS2_FST) ? yes : no);
++#endif
++
++       len = (p - page) - off;
++       if (len < 0)
++                len = 0;
++       *eof = (len <=count) ? 1 : 0;
++       *start = page + off;
++       return len;
++}
++
++static inline void register_proc_entry (void)
++{
++      create_proc_read_entry (driver_name, 0, NULL,
++              usbctl_read_proc, NULL);
++}
++
++static inline void unregister_proc_entry (void)
++{
++      remove_proc_entry (driver_name, NULL);
++}
++
++#else
++
++#define register_proc_entry() do {} while (0)
++#define unregister_proc_entry() do {} while (0)
++
++#endif  /* CONFIG_PROC_FS */
++
++/*-------------------------------------------------------------------------*/
++
++MODULE_DESCRIPTION ("sa1100_udc");
++MODULE_AUTHOR ("Various");
++MODULE_LICENSE ("GPL");
++
++static struct sa1100_udc memory = {
++      .gadget = {
++              .ops            = &sa1100_ops,
++              .ep0            = &memory.ep[0].ep,
++              .name           = driver_name,
++              .dev = {
++                      .bus_id         = "gadget",
++              },
++      },
++
++      /* control endpoint */
++      .ep[0] = {
++              .ep = {
++                      .name           = ep0name,
++                      .ops            = &sa1100_ep_ops,
++                      .maxpacket      = EP0_FIFO_SIZE,
++              },
++              .dev            = &memory,
++      },
++
++      /* first group of endpoints */
++      .ep[1] = {
++              .ep = {
++                      .name           = "ep1out-bulk",
++                      .ops            = &sa1100_ep_ops,
++                      .maxpacket      = BULK_FIFO_SIZE,
++              },
++              .dev            = &memory,
++      },
++      .ep[2] = {
++              .ep = {
++                      .name           = "ep2in-bulk",
++                      .ops            = &sa1100_ep_ops,
++                      .maxpacket      = BULK_FIFO_SIZE,
++              },
++              .dev            = &memory,
++      }
++};
++
++static int __init sa1100_udc_probe(struct device *_dev)
++{
++      struct sa1100_udc *dev = &memory;
++      int retval = 0;
++
++      /* setup dev */
++      dev->dev = _dev;
++//    dev->mach = _dev->platform_data;
++
++      device_initialize(&dev->gadget.dev);
++      dev->gadget.dev.parent = _dev;
++      dev->gadget.dev.dma_mask = _dev->dma_mask;
++
++      the_controller = dev;
++      dev_set_drvdata(_dev, dev);
++
++      /* controller stays disabled until gadget driver is bound */
++      udc_disable(dev);
++      udc_reinit(dev);
++
++//    spin_lock_init(&the_udc.lock);
++      register_proc_entry();
++
++#if defined(CONFIG_SA1100_COLLIE)
++      collie_usb_init();
++#endif        
++
++      /* setup dma channels and IRQ */
++      retval = sa1100_request_dma(DMA_Ser0UDCRd, "USB receive",
++                                  NULL, NULL, &dev->ep[1].dmaregs);
++      if (retval) {
++              ERROR(dev, "couldn't get rx dma, err %d\n", retval);
++              goto err_rx_dma;
++      }
++      retval = sa1100_request_dma(DMA_Ser0UDCWr, "USB transmit",
++                                  NULL, NULL, &dev->ep[2].dmaregs);
++      if (retval) {
++              ERROR(dev, "couldn't get tx dma, err %d\n", retval);
++              goto err_tx_dma;
++      }
++      retval = request_irq(IRQ_Ser0UDC, udc_int_hndlr, IRQF_DISABLED,
++                      driver_name, dev);
++      if (retval) {
++              ERROR(dev, "couldn't get irq, err %d\n", retval);
++              goto err_irq;
++      }
++
++      INFO(dev, "initialized, rx %p tx %p irq %d\n",
++              dev->ep[1].dmaregs, dev->ep[2].dmaregs, IRQ_Ser0UDC);
++      return 0;
++
++err_irq:
++      sa1100_free_dma(dev->ep[2].dmaregs);
++      usbd_info.dmaregs_rx = 0;
++err_tx_dma:
++      sa1100_free_dma(dev->ep[1].dmaregs);
++      usbd_info.dmaregs_tx = 0;
++err_rx_dma:
++      return retval;
++}
++
++static int __exit sa1100_udc_remove(struct device *_dev)
++{
++      struct sa1100_udc *dev = dev_get_drvdata(_dev);
++
++      udc_disable(dev);
++      unregister_proc_entry();
++      usb_gadget_unregister_driver(dev->driver);
++      sa1100_free_dma(dev->ep[1].dmaregs);
++      sa1100_free_dma(dev->ep[2].dmaregs);
++      free_irq(IRQ_Ser0UDC, dev);
++      dev_set_drvdata(_dev,NULL);
++      the_controller = NULL;
++#if defined(CONFIG_SA1100_COLLIE)
++      collie_usb_exit();
++#endif        
++      return 0;
++}
++
++static struct device_driver udc_driver = {
++      .name           = "sa11x0-udc",
++      .bus            = &platform_bus_type,
++      .probe          = sa1100_udc_probe,
++      .remove         = __exit_p(sa1100_udc_remove),
++//    .suspend        = sa1100_udc_suspend,
++//    .resume         = sa1100_udc_resume,
++      .owner          = THIS_MODULE,
++};
++
++static int __init udc_init(void)
++{
++      printk(KERN_INFO "%s: version %s\n", driver_name, DRIVER_VERSION);
++#ifdef NCB_DMA_FIX
++      send_buffer = (char*) kzalloc(SEND_BUFFER_SIZE, GFP_KERNEL | GFP_DMA );
++      receive_buffer = (char*) kzalloc(RECEIVE_BUFFER_SIZE, GFP_KERNEL | GFP_DMA );
++#endif
++      return driver_register(&udc_driver);
++}
++module_init(udc_init);
++
++static void __exit udc_exit(void)
++{
++#ifdef NCB_DMA_FIX
++      if (send_buffer) {
++          kfree(send_buffer);
++          send_buffer = NULL;
++      }
++      if (receive_buffer) {
++          kfree(receive_buffer);
++          receive_buffer = NULL;
++      }
++#endif
++      driver_unregister(&udc_driver);
++}
++module_exit(udc_exit);
+diff --git a/drivers/usb/gadget/sa1100_udc.h b/drivers/usb/gadget/sa1100_udc.h
+new file mode 100644
+index 0000000..86fa28d
+--- /dev/null
++++ b/drivers/usb/gadget/sa1100_udc.h
+@@ -0,0 +1,94 @@
++/*
++ * internals of "new style" UDC controller
++ * <linux/usb_gadget.h> replaces ARM-specific "sa1100_usb.h".
++ */
++
++struct sa1100_ep {
++      struct usb_ep                           ep;
++      struct sa1100_udc                       *dev;
++      //unsigned long                         irqs;
++
++      const struct usb_endpoint_descriptor    *desc;
++      struct list_head                        queue;
++      dma_regs_t                              *dmaregs;
++      unsigned                                stopped : 1;
++};
++
++struct sa1100_request {
++      struct usb_request                      req;
++      struct list_head                        queue;
++// NCB        unsigned                                mapped : 1;
++};
++
++enum ep0_state {
++      EP0_IDLE,
++      EP0_IN_DATA_PHASE,
++      EP0_OUT_DATA_PHASE,
++      EP0_END_XFER,
++      EP0_STALL,
++};
++
++#define EP0_FIFO_SIZE ((unsigned)8)
++#define BULK_FIFO_SIZE        ((unsigned)64)
++//#define ISO_FIFO_SIZE       ((unsigned)256)
++//#define INT_FIFO_SIZE       ((unsigned)8)
++
++struct udc_stats {
++      struct ep0stats {
++              unsigned long           ops;
++              unsigned long           bytes;
++      } read, write;
++      unsigned long                   irqs;
++};
++
++struct sa1100_udc {
++      struct usb_gadget                       gadget;
++      struct usb_gadget_driver                *driver;
++      struct device                           *dev;
++      enum ep0_state                          ep0state;
++      struct udc_stats                        stats;
++// NCB        spinlock_t                              lock;
++// NCB        dma_regs_t                              *dmaregs_tx, *dmaregs_rx;
++      unsigned                                got_irq : 1,
++                                              vbus : 1,
++                                              pullup : 1,
++                                              has_cfr : 1,
++                                              req_pending : 1,
++                                              req_std : 1,
++                                              req_config : 1;
++      struct timer_list                       timer;
++      u64 dma_mask;
++      unsigned char                           address;
++      struct sa1100_ep                        ep[3];
++      int                                     ep0_req_len;
++};
++
++/*-------------------------------------------------------------------------*/
++
++#define xprintk(dev,level,fmt,args...) \
++      printk(level "%s: " fmt , driver_name , ## args)
++
++#ifdef DEBUG
++#undef DEBUG
++#define DEBUG(dev,fmt,args...) \
++      xprintk(dev , KERN_DEBUG , fmt , ## args)
++#else
++#define DEBUG(dev,fmt,args...) \
++      do { } while (0)
++#endif /* DEBUG */
++
++#ifdef VERBOSE
++#define VDEBUG DEBUG
++#else
++#define VDEBUG(dev,fmt,args...) \
++      do { } while (0)
++#endif        /* VERBOSE */
++
++#define ERROR(dev,fmt,args...) \
++      xprintk(dev , KERN_ERR , fmt , ## args)
++#define WARN_(dev,fmt,args...) \
++      xprintk(dev , KERN_WARNING , fmt , ## args)
++#define INFO(dev,fmt,args...) \
++      xprintk(dev , KERN_INFO , fmt , ## args)\r
++
++/*-------------------------------------------------------------------------*/
+-- 
+1.5.6.5
+
diff --git a/packages/linux/linux-2.6.28/collie/0010-mmc_spi-add-suspend-and-resume-callbacks.patch b/packages/linux/linux-2.6.28/collie/0010-mmc_spi-add-suspend-and-resume-callbacks.patch
new file mode 100644 (file)
index 0000000..fbf1b45
--- /dev/null
@@ -0,0 +1,59 @@
+From 53fc40876ed9b753f935361fb1027718a184c41e Mon Sep 17 00:00:00 2001
+From: Thomas Kunze <thommycheck@gmx.de>
+Date: Thu, 5 Feb 2009 00:49:03 +0100
+Subject: [PATCH 10/23] mmc_spi: add suspend and resume callbacks
+
+---
+ drivers/mmc/host/mmc_spi.c |   29 +++++++++++++++++++++++++++++
+ 1 files changed, 29 insertions(+), 0 deletions(-)
+
+diff --git a/drivers/mmc/host/mmc_spi.c b/drivers/mmc/host/mmc_spi.c
+index ad00e16..ac6719b 100644
+--- a/drivers/mmc/host/mmc_spi.c
++++ b/drivers/mmc/host/mmc_spi.c
+@@ -1407,6 +1407,33 @@ static int __devexit mmc_spi_remove(struct spi_device *spi)
+       return 0;
+ }
++#ifdef CONFIG_PM
++static int mmc_spi_suspend(struct spi_device *spi, pm_message_t state)
++{
++      struct mmc_host *mmc = dev_get_drvdata(&spi->dev);
++        struct mmc_spi_host *host = mmc_priv(mmc);
++      int ret = 0;
++
++        if (mmc)
++                ret = mmc_suspend_host(mmc, state);
++        return ret;
++}
++
++static int mmc_spi_resume(struct spi_device *spi)
++{
++      struct mmc_host *mmc = dev_get_drvdata(&spi->dev);        
++        int ret = 0;
++
++        if (mmc)
++                ret = mmc_resume_host(mmc);
++
++        return ret;
++}
++#else
++#define mmc_spi_suspend  NULL
++#define mmc_spi_resume   NULL
++#endif
++
+ static struct spi_driver mmc_spi_driver = {
+       .driver = {
+@@ -1416,6 +1443,8 @@ static struct spi_driver mmc_spi_driver = {
+       },
+       .probe =        mmc_spi_probe,
+       .remove =       __devexit_p(mmc_spi_remove),
++      .suspend =      mmc_spi_suspend,
++      .resume =       mmc_spi_resume,
+ };
+-- 
+1.5.6.5
+
diff --git a/packages/linux/linux-2.6.28/collie/0011-move-drivers-mfd-.h-to-include-linux-mfd.patch b/packages/linux/linux-2.6.28/collie/0011-move-drivers-mfd-.h-to-include-linux-mfd.patch
new file mode 100644 (file)
index 0000000..0bc3dbb
--- /dev/null
@@ -0,0 +1,803 @@
+From c69779dac8693a3b057b3708d19f7013c6973bf2 Mon Sep 17 00:00:00 2001
+From: Thomas Kunze <thommycheck@gmx.de>
+Date: Tue, 10 Feb 2009 14:54:57 +0100
+Subject: [PATCH 11/23] move drivers/mfd/*.h to include/linux/mfd
+
+So drivers like collie_battery driver can use
+those files easier.
+---
+ arch/arm/mach-sa1100/collie_pm.c |    2 +-
+ drivers/mfd/mcp-core.c           |    2 +-
+ drivers/mfd/mcp-sa11x0.c         |    2 +-
+ drivers/mfd/mcp.h                |   66 ----------
+ drivers/mfd/ucb1x00-assabet.c    |    2 +-
+ drivers/mfd/ucb1x00-core.c       |    2 +-
+ drivers/mfd/ucb1x00-ts.c         |    2 +-
+ drivers/mfd/ucb1x00.h            |  255 --------------------------------------
+ include/linux/mfd/mcp.h          |   68 ++++++++++
+ include/linux/mfd/ucb1x00.h      |  255 ++++++++++++++++++++++++++++++++++++++
+ 10 files changed, 329 insertions(+), 327 deletions(-)
+ delete mode 100644 drivers/mfd/mcp.h
+ delete mode 100644 drivers/mfd/ucb1x00.h
+ create mode 100644 include/linux/mfd/mcp.h
+ create mode 100644 include/linux/mfd/ucb1x00.h
+
+diff --git a/arch/arm/mach-sa1100/collie_pm.c b/arch/arm/mach-sa1100/collie_pm.c
+index b1161fc..65b8b31 100644
+--- a/arch/arm/mach-sa1100/collie_pm.c
++++ b/arch/arm/mach-sa1100/collie_pm.c
+@@ -22,6 +22,7 @@
+ #include <linux/interrupt.h>
+ #include <linux/device.h>
+ #include <linux/platform_device.h>
++#include <linux/mfd/ucb1x00.h>
+ #include <asm/irq.h>
+ #include <mach/hardware.h>
+@@ -31,7 +32,6 @@
+ #include <asm/mach/sharpsl_param.h>
+ #include <asm/hardware/sharpsl_pm.h>
+-#include "../drivers/mfd/ucb1x00.h"
+ static struct ucb1x00 *ucb;
+ static int ad_revise;
+diff --git a/drivers/mfd/mcp-core.c b/drivers/mfd/mcp-core.c
+index b4ed57e..64c806a 100644
+--- a/drivers/mfd/mcp-core.c
++++ b/drivers/mfd/mcp-core.c
+@@ -17,11 +17,11 @@
+ #include <linux/device.h>
+ #include <linux/slab.h>
+ #include <linux/string.h>
++#include <linux/mfd/mcp.h>
+ #include <asm/dma.h>
+ #include <asm/system.h>
+-#include "mcp.h"
+ #define to_mcp(d)             container_of(d, struct mcp, attached_device)
+ #define to_mcp_driver(d)      container_of(d, struct mcp_driver, drv)
+diff --git a/drivers/mfd/mcp-sa11x0.c b/drivers/mfd/mcp-sa11x0.c
+index 28380b2..88c81cf 100644
+--- a/drivers/mfd/mcp-sa11x0.c
++++ b/drivers/mfd/mcp-sa11x0.c
+@@ -19,6 +19,7 @@
+ #include <linux/spinlock.h>
+ #include <linux/slab.h>
+ #include <linux/platform_device.h>
++#include <linux/mfd/mcp.h>
+ #include <asm/dma.h>
+ #include <mach/hardware.h>
+@@ -28,7 +29,6 @@
+ #include <mach/assabet.h>
+-#include "mcp.h"
+ struct mcp_sa11x0 {
+       u32     mccr0;
+diff --git a/drivers/mfd/mcp.h b/drivers/mfd/mcp.h
+deleted file mode 100644
+index c093a93..0000000
+--- a/drivers/mfd/mcp.h
++++ /dev/null
+@@ -1,66 +0,0 @@
+-/*
+- *  linux/drivers/mfd/mcp.h
+- *
+- *  Copyright (C) 2001 Russell King, All Rights Reserved.
+- *
+- * 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.
+- */
+-#ifndef MCP_H
+-#define MCP_H
+-
+-struct mcp_ops;
+-
+-struct mcp {
+-      struct module   *owner;
+-      struct mcp_ops  *ops;
+-      spinlock_t      lock;
+-      int             use_count;
+-      unsigned int    sclk_rate;
+-      unsigned int    rw_timeout;
+-      dma_device_t    dma_audio_rd;
+-      dma_device_t    dma_audio_wr;
+-      dma_device_t    dma_telco_rd;
+-      dma_device_t    dma_telco_wr;
+-      struct device   attached_device;
+-};
+-
+-struct mcp_ops {
+-      void            (*set_telecom_divisor)(struct mcp *, unsigned int);
+-      void            (*set_audio_divisor)(struct mcp *, unsigned int);
+-      void            (*reg_write)(struct mcp *, unsigned int, unsigned int);
+-      unsigned int    (*reg_read)(struct mcp *, unsigned int);
+-      void            (*enable)(struct mcp *);
+-      void            (*disable)(struct mcp *);
+-};
+-
+-void mcp_set_telecom_divisor(struct mcp *, unsigned int);
+-void mcp_set_audio_divisor(struct mcp *, unsigned int);
+-void mcp_reg_write(struct mcp *, unsigned int, unsigned int);
+-unsigned int mcp_reg_read(struct mcp *, unsigned int);
+-void mcp_enable(struct mcp *);
+-void mcp_disable(struct mcp *);
+-#define mcp_get_sclk_rate(mcp)        ((mcp)->sclk_rate)
+-
+-struct mcp *mcp_host_alloc(struct device *, size_t);
+-int mcp_host_register(struct mcp *);
+-void mcp_host_unregister(struct mcp *);
+-
+-struct mcp_driver {
+-      struct device_driver drv;
+-      int (*probe)(struct mcp *);
+-      void (*remove)(struct mcp *);
+-      int (*suspend)(struct mcp *, pm_message_t);
+-      int (*resume)(struct mcp *);
+-};
+-
+-int mcp_driver_register(struct mcp_driver *);
+-void mcp_driver_unregister(struct mcp_driver *);
+-
+-#define mcp_get_drvdata(mcp)  dev_get_drvdata(&(mcp)->attached_device)
+-#define mcp_set_drvdata(mcp,d)        dev_set_drvdata(&(mcp)->attached_device, d)
+-
+-#define mcp_priv(mcp)         ((void *)((mcp)+1))
+-
+-#endif
+diff --git a/drivers/mfd/ucb1x00-assabet.c b/drivers/mfd/ucb1x00-assabet.c
+index 61aeaf7..0f6f46d 100644
+--- a/drivers/mfd/ucb1x00-assabet.c
++++ b/drivers/mfd/ucb1x00-assabet.c
+@@ -14,10 +14,10 @@
+ #include <linux/fs.h>
+ #include <linux/proc_fs.h>
+ #include <linux/device.h>
++#include <linux/mfd/ucb1x00.h>
+ #include <asm/dma.h>
+-#include "ucb1x00.h"
+ #define UCB1X00_ATTR(name,input)\
+ static ssize_t name##_show(struct device *dev, struct device_attribute *attr, \
+diff --git a/drivers/mfd/ucb1x00-core.c b/drivers/mfd/ucb1x00-core.c
+index a316f1b..bc2c1ba 100644
+--- a/drivers/mfd/ucb1x00-core.c
++++ b/drivers/mfd/ucb1x00-core.c
+@@ -24,11 +24,11 @@
+ #include <linux/interrupt.h>
+ #include <linux/device.h>
+ #include <linux/mutex.h>
++#include <linux/mfd/ucb1x00.h>
+ #include <asm/dma.h>
+ #include <mach/hardware.h>
+-#include "ucb1x00.h"
+ static DEFINE_MUTEX(ucb1x00_mutex);
+ static LIST_HEAD(ucb1x00_drivers);
+diff --git a/drivers/mfd/ucb1x00-ts.c b/drivers/mfd/ucb1x00-ts.c
+index 44762ca..b5feae9 100644
+--- a/drivers/mfd/ucb1x00-ts.c
++++ b/drivers/mfd/ucb1x00-ts.c
+@@ -30,12 +30,12 @@
+ #include <linux/freezer.h>
+ #include <linux/slab.h>
+ #include <linux/kthread.h>
++#include <linux/mfd/ucb1x00.h>
+ #include <asm/dma.h>
+ #include <mach/collie.h>
+ #include <asm/mach-types.h>
+-#include "ucb1x00.h"
+ struct ucb1x00_ts {
+diff --git a/drivers/mfd/ucb1x00.h b/drivers/mfd/ucb1x00.h
+deleted file mode 100644
+index a8ad8a0..0000000
+--- a/drivers/mfd/ucb1x00.h
++++ /dev/null
+@@ -1,255 +0,0 @@
+-/*
+- *  linux/drivers/mfd/ucb1x00.h
+- *
+- *  Copyright (C) 2001 Russell King, All Rights Reserved.
+- *
+- * 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.
+- */
+-#ifndef UCB1200_H
+-#define UCB1200_H
+-
+-#define UCB_IO_DATA   0x00
+-#define UCB_IO_DIR    0x01
+-
+-#define UCB_IO_0              (1 << 0)
+-#define UCB_IO_1              (1 << 1)
+-#define UCB_IO_2              (1 << 2)
+-#define UCB_IO_3              (1 << 3)
+-#define UCB_IO_4              (1 << 4)
+-#define UCB_IO_5              (1 << 5)
+-#define UCB_IO_6              (1 << 6)
+-#define UCB_IO_7              (1 << 7)
+-#define UCB_IO_8              (1 << 8)
+-#define UCB_IO_9              (1 << 9)
+-
+-#define UCB_IE_RIS    0x02
+-#define UCB_IE_FAL    0x03
+-#define UCB_IE_STATUS 0x04
+-#define UCB_IE_CLEAR  0x04
+-#define UCB_IE_ADC            (1 << 11)
+-#define UCB_IE_TSPX           (1 << 12)
+-#define UCB_IE_TSMX           (1 << 13)
+-#define UCB_IE_TCLIP          (1 << 14)
+-#define UCB_IE_ACLIP          (1 << 15)
+-
+-#define UCB_IRQ_TSPX          12
+-
+-#define UCB_TC_A      0x05
+-#define UCB_TC_A_LOOP         (1 << 7)        /* UCB1200 */
+-#define UCB_TC_A_AMPL         (1 << 7)        /* UCB1300 */
+-
+-#define UCB_TC_B      0x06
+-#define UCB_TC_B_VOICE_ENA    (1 << 3)
+-#define UCB_TC_B_CLIP         (1 << 4)
+-#define UCB_TC_B_ATT          (1 << 6)
+-#define UCB_TC_B_SIDE_ENA     (1 << 11)
+-#define UCB_TC_B_MUTE         (1 << 13)
+-#define UCB_TC_B_IN_ENA               (1 << 14)
+-#define UCB_TC_B_OUT_ENA      (1 << 15)
+-
+-#define UCB_AC_A      0x07
+-#define UCB_AC_B      0x08
+-#define UCB_AC_B_LOOP         (1 << 8)
+-#define UCB_AC_B_MUTE         (1 << 13)
+-#define UCB_AC_B_IN_ENA               (1 << 14)
+-#define UCB_AC_B_OUT_ENA      (1 << 15)
+-
+-#define UCB_TS_CR     0x09
+-#define UCB_TS_CR_TSMX_POW    (1 << 0)
+-#define UCB_TS_CR_TSPX_POW    (1 << 1)
+-#define UCB_TS_CR_TSMY_POW    (1 << 2)
+-#define UCB_TS_CR_TSPY_POW    (1 << 3)
+-#define UCB_TS_CR_TSMX_GND    (1 << 4)
+-#define UCB_TS_CR_TSPX_GND    (1 << 5)
+-#define UCB_TS_CR_TSMY_GND    (1 << 6)
+-#define UCB_TS_CR_TSPY_GND    (1 << 7)
+-#define UCB_TS_CR_MODE_INT    (0 << 8)
+-#define UCB_TS_CR_MODE_PRES   (1 << 8)
+-#define UCB_TS_CR_MODE_POS    (2 << 8)
+-#define UCB_TS_CR_BIAS_ENA    (1 << 11)
+-#define UCB_TS_CR_TSPX_LOW    (1 << 12)
+-#define UCB_TS_CR_TSMX_LOW    (1 << 13)
+-
+-#define UCB_ADC_CR    0x0a
+-#define UCB_ADC_SYNC_ENA      (1 << 0)
+-#define UCB_ADC_VREFBYP_CON   (1 << 1)
+-#define UCB_ADC_INP_TSPX      (0 << 2)
+-#define UCB_ADC_INP_TSMX      (1 << 2)
+-#define UCB_ADC_INP_TSPY      (2 << 2)
+-#define UCB_ADC_INP_TSMY      (3 << 2)
+-#define UCB_ADC_INP_AD0               (4 << 2)
+-#define UCB_ADC_INP_AD1               (5 << 2)
+-#define UCB_ADC_INP_AD2               (6 << 2)
+-#define UCB_ADC_INP_AD3               (7 << 2)
+-#define UCB_ADC_EXT_REF               (1 << 5)
+-#define UCB_ADC_START         (1 << 7)
+-#define UCB_ADC_ENA           (1 << 15)
+-
+-#define UCB_ADC_DATA  0x0b
+-#define UCB_ADC_DAT_VAL               (1 << 15)
+-#define UCB_ADC_DAT(x)                (((x) & 0x7fe0) >> 5)
+-
+-#define UCB_ID                0x0c
+-#define UCB_ID_1200           0x1004
+-#define UCB_ID_1300           0x1005
+-#define UCB_ID_TC35143          0x9712
+-
+-#define UCB_MODE      0x0d
+-#define UCB_MODE_DYN_VFLAG_ENA        (1 << 12)
+-#define UCB_MODE_AUD_OFF_CAN  (1 << 13)
+-
+-#include "mcp.h"
+-
+-struct ucb1x00_irq {
+-      void *devid;
+-      void (*fn)(int, void *);
+-};
+-
+-struct ucb1x00 {
+-      spinlock_t              lock;
+-      struct mcp              *mcp;
+-      unsigned int            irq;
+-      struct semaphore        adc_sem;
+-      spinlock_t              io_lock;
+-      u16                     id;
+-      u16                     io_dir;
+-      u16                     io_out;
+-      u16                     adc_cr;
+-      u16                     irq_fal_enbl;
+-      u16                     irq_ris_enbl;
+-      struct ucb1x00_irq      irq_handler[16];
+-      struct device           dev;
+-      struct list_head        node;
+-      struct list_head        devs;
+-};
+-
+-struct ucb1x00_driver;
+-
+-struct ucb1x00_dev {
+-      struct list_head        dev_node;
+-      struct list_head        drv_node;
+-      struct ucb1x00          *ucb;
+-      struct ucb1x00_driver   *drv;
+-      void                    *priv;
+-};
+-
+-struct ucb1x00_driver {
+-      struct list_head        node;
+-      struct list_head        devs;
+-      int     (*add)(struct ucb1x00_dev *dev);
+-      void    (*remove)(struct ucb1x00_dev *dev);
+-      int     (*suspend)(struct ucb1x00_dev *dev, pm_message_t state);
+-      int     (*resume)(struct ucb1x00_dev *dev);
+-};
+-
+-#define classdev_to_ucb1x00(cd)       container_of(cd, struct ucb1x00, dev)
+-
+-int ucb1x00_register_driver(struct ucb1x00_driver *);
+-void ucb1x00_unregister_driver(struct ucb1x00_driver *);
+-
+-/**
+- *    ucb1x00_clkrate - return the UCB1x00 SIB clock rate
+- *    @ucb: UCB1x00 structure describing chip
+- *
+- *    Return the SIB clock rate in Hz.
+- */
+-static inline unsigned int ucb1x00_clkrate(struct ucb1x00 *ucb)
+-{
+-      return mcp_get_sclk_rate(ucb->mcp);
+-}
+-
+-/**
+- *    ucb1x00_enable - enable the UCB1x00 SIB clock
+- *    @ucb: UCB1x00 structure describing chip
+- *
+- *    Enable the SIB clock.  This can be called multiple times.
+- */
+-static inline void ucb1x00_enable(struct ucb1x00 *ucb)
+-{
+-      mcp_enable(ucb->mcp);
+-}
+-
+-/**
+- *    ucb1x00_disable - disable the UCB1x00 SIB clock
+- *    @ucb: UCB1x00 structure describing chip
+- *
+- *    Disable the SIB clock.  The SIB clock will only be disabled
+- *    when the number of ucb1x00_enable calls match the number of
+- *    ucb1x00_disable calls.
+- */
+-static inline void ucb1x00_disable(struct ucb1x00 *ucb)
+-{
+-      mcp_disable(ucb->mcp);
+-}
+-
+-/**
+- *    ucb1x00_reg_write - write a UCB1x00 register
+- *    @ucb: UCB1x00 structure describing chip
+- *    @reg: UCB1x00 4-bit register index to write
+- *    @val: UCB1x00 16-bit value to write
+- *
+- *    Write the UCB1x00 register @reg with value @val.  The SIB
+- *    clock must be running for this function to return.
+- */
+-static inline void ucb1x00_reg_write(struct ucb1x00 *ucb, unsigned int reg, unsigned int val)
+-{
+-      mcp_reg_write(ucb->mcp, reg, val);
+-}
+-
+-/**
+- *    ucb1x00_reg_read - read a UCB1x00 register
+- *    @ucb: UCB1x00 structure describing chip
+- *    @reg: UCB1x00 4-bit register index to write
+- *
+- *    Read the UCB1x00 register @reg and return its value.  The SIB
+- *    clock must be running for this function to return.
+- */
+-static inline unsigned int ucb1x00_reg_read(struct ucb1x00 *ucb, unsigned int reg)
+-{
+-      return mcp_reg_read(ucb->mcp, reg);
+-}
+-/**
+- *    ucb1x00_set_audio_divisor - 
+- *    @ucb: UCB1x00 structure describing chip
+- *    @div: SIB clock divisor
+- */
+-static inline void ucb1x00_set_audio_divisor(struct ucb1x00 *ucb, unsigned int div)
+-{
+-      mcp_set_audio_divisor(ucb->mcp, div);
+-}
+-
+-/**
+- *    ucb1x00_set_telecom_divisor -
+- *    @ucb: UCB1x00 structure describing chip
+- *    @div: SIB clock divisor
+- */
+-static inline void ucb1x00_set_telecom_divisor(struct ucb1x00 *ucb, unsigned int div)
+-{
+-      mcp_set_telecom_divisor(ucb->mcp, div);
+-}
+-
+-void ucb1x00_io_set_dir(struct ucb1x00 *ucb, unsigned int, unsigned int);
+-void ucb1x00_io_write(struct ucb1x00 *ucb, unsigned int, unsigned int);
+-unsigned int ucb1x00_io_read(struct ucb1x00 *ucb);
+-
+-#define UCB_NOSYNC    (0)
+-#define UCB_SYNC      (1)
+-
+-unsigned int ucb1x00_adc_read(struct ucb1x00 *ucb, int adc_channel, int sync);
+-void ucb1x00_adc_enable(struct ucb1x00 *ucb);
+-void ucb1x00_adc_disable(struct ucb1x00 *ucb);
+-
+-/*
+- * Which edges of the IRQ do you want to control today?
+- */
+-#define UCB_RISING    (1 << 0)
+-#define UCB_FALLING   (1 << 1)
+-
+-int ucb1x00_hook_irq(struct ucb1x00 *ucb, unsigned int idx, void (*fn)(int, void *), void *devid);
+-void ucb1x00_enable_irq(struct ucb1x00 *ucb, unsigned int idx, int edges);
+-void ucb1x00_disable_irq(struct ucb1x00 *ucb, unsigned int idx, int edges);
+-int ucb1x00_free_irq(struct ucb1x00 *ucb, unsigned int idx, void *devid);
+-
+-#endif
+diff --git a/include/linux/mfd/mcp.h b/include/linux/mfd/mcp.h
+new file mode 100644
+index 0000000..be95e09
+--- /dev/null
++++ b/include/linux/mfd/mcp.h
+@@ -0,0 +1,68 @@
++/*
++ *  linux/drivers/mfd/mcp.h
++ *
++ *  Copyright (C) 2001 Russell King, All Rights Reserved.
++ *
++ * 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.
++ */
++#ifndef MCP_H
++#define MCP_H
++
++#include <mach/dma.h>
++
++struct mcp_ops;
++
++struct mcp {
++      struct module   *owner;
++      struct mcp_ops  *ops;
++      spinlock_t      lock;
++      int             use_count;
++      unsigned int    sclk_rate;
++      unsigned int    rw_timeout;
++      dma_device_t    dma_audio_rd;
++      dma_device_t    dma_audio_wr;
++      dma_device_t    dma_telco_rd;
++      dma_device_t    dma_telco_wr;
++      struct device   attached_device;
++};
++
++struct mcp_ops {
++      void            (*set_telecom_divisor)(struct mcp *, unsigned int);
++      void            (*set_audio_divisor)(struct mcp *, unsigned int);
++      void            (*reg_write)(struct mcp *, unsigned int, unsigned int);
++      unsigned int    (*reg_read)(struct mcp *, unsigned int);
++      void            (*enable)(struct mcp *);
++      void            (*disable)(struct mcp *);
++};
++
++void mcp_set_telecom_divisor(struct mcp *, unsigned int);
++void mcp_set_audio_divisor(struct mcp *, unsigned int);
++void mcp_reg_write(struct mcp *, unsigned int, unsigned int);
++unsigned int mcp_reg_read(struct mcp *, unsigned int);
++void mcp_enable(struct mcp *);
++void mcp_disable(struct mcp *);
++#define mcp_get_sclk_rate(mcp)        ((mcp)->sclk_rate)
++
++struct mcp *mcp_host_alloc(struct device *, size_t);
++int mcp_host_register(struct mcp *);
++void mcp_host_unregister(struct mcp *);
++
++struct mcp_driver {
++      struct device_driver drv;
++      int (*probe)(struct mcp *);
++      void (*remove)(struct mcp *);
++      int (*suspend)(struct mcp *, pm_message_t);
++      int (*resume)(struct mcp *);
++};
++
++int mcp_driver_register(struct mcp_driver *);
++void mcp_driver_unregister(struct mcp_driver *);
++
++#define mcp_get_drvdata(mcp)  dev_get_drvdata(&(mcp)->attached_device)
++#define mcp_set_drvdata(mcp,d)        dev_set_drvdata(&(mcp)->attached_device, d)
++
++#define mcp_priv(mcp)         ((void *)((mcp)+1))
++
++#endif
+diff --git a/include/linux/mfd/ucb1x00.h b/include/linux/mfd/ucb1x00.h
+new file mode 100644
+index 0000000..eac3463
+--- /dev/null
++++ b/include/linux/mfd/ucb1x00.h
+@@ -0,0 +1,255 @@
++/*
++ *  linux/include/mfd/ucb1x00.h
++ *
++ *  Copyright (C) 2001 Russell King, All Rights Reserved.
++ *
++ * 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.
++ */
++#ifndef UCB1200_H
++#define UCB1200_H
++
++#include <linux/mfd/mcp.h>
++#define UCB_IO_DATA   0x00
++#define UCB_IO_DIR    0x01
++
++#define UCB_IO_0              (1 << 0)
++#define UCB_IO_1              (1 << 1)
++#define UCB_IO_2              (1 << 2)
++#define UCB_IO_3              (1 << 3)
++#define UCB_IO_4              (1 << 4)
++#define UCB_IO_5              (1 << 5)
++#define UCB_IO_6              (1 << 6)
++#define UCB_IO_7              (1 << 7)
++#define UCB_IO_8              (1 << 8)
++#define UCB_IO_9              (1 << 9)
++
++#define UCB_IE_RIS    0x02
++#define UCB_IE_FAL    0x03
++#define UCB_IE_STATUS 0x04
++#define UCB_IE_CLEAR  0x04
++#define UCB_IE_ADC            (1 << 11)
++#define UCB_IE_TSPX           (1 << 12)
++#define UCB_IE_TSMX           (1 << 13)
++#define UCB_IE_TCLIP          (1 << 14)
++#define UCB_IE_ACLIP          (1 << 15)
++
++#define UCB_IRQ_TSPX          12
++
++#define UCB_TC_A      0x05
++#define UCB_TC_A_LOOP         (1 << 7)        /* UCB1200 */
++#define UCB_TC_A_AMPL         (1 << 7)        /* UCB1300 */
++
++#define UCB_TC_B      0x06
++#define UCB_TC_B_VOICE_ENA    (1 << 3)
++#define UCB_TC_B_CLIP         (1 << 4)
++#define UCB_TC_B_ATT          (1 << 6)
++#define UCB_TC_B_SIDE_ENA     (1 << 11)
++#define UCB_TC_B_MUTE         (1 << 13)
++#define UCB_TC_B_IN_ENA               (1 << 14)
++#define UCB_TC_B_OUT_ENA      (1 << 15)
++
++#define UCB_AC_A      0x07
++#define UCB_AC_B      0x08
++#define UCB_AC_B_LOOP         (1 << 8)
++#define UCB_AC_B_MUTE         (1 << 13)
++#define UCB_AC_B_IN_ENA               (1 << 14)
++#define UCB_AC_B_OUT_ENA      (1 << 15)
++
++#define UCB_TS_CR     0x09
++#define UCB_TS_CR_TSMX_POW    (1 << 0)
++#define UCB_TS_CR_TSPX_POW    (1 << 1)
++#define UCB_TS_CR_TSMY_POW    (1 << 2)
++#define UCB_TS_CR_TSPY_POW    (1 << 3)
++#define UCB_TS_CR_TSMX_GND    (1 << 4)
++#define UCB_TS_CR_TSPX_GND    (1 << 5)
++#define UCB_TS_CR_TSMY_GND    (1 << 6)
++#define UCB_TS_CR_TSPY_GND    (1 << 7)
++#define UCB_TS_CR_MODE_INT    (0 << 8)
++#define UCB_TS_CR_MODE_PRES   (1 << 8)
++#define UCB_TS_CR_MODE_POS    (2 << 8)
++#define UCB_TS_CR_BIAS_ENA    (1 << 11)
++#define UCB_TS_CR_TSPX_LOW    (1 << 12)
++#define UCB_TS_CR_TSMX_LOW    (1 << 13)
++
++#define UCB_ADC_CR    0x0a
++#define UCB_ADC_SYNC_ENA      (1 << 0)
++#define UCB_ADC_VREFBYP_CON   (1 << 1)
++#define UCB_ADC_INP_TSPX      (0 << 2)
++#define UCB_ADC_INP_TSMX      (1 << 2)
++#define UCB_ADC_INP_TSPY      (2 << 2)
++#define UCB_ADC_INP_TSMY      (3 << 2)
++#define UCB_ADC_INP_AD0               (4 << 2)
++#define UCB_ADC_INP_AD1               (5 << 2)
++#define UCB_ADC_INP_AD2               (6 << 2)
++#define UCB_ADC_INP_AD3               (7 << 2)
++#define UCB_ADC_EXT_REF               (1 << 5)
++#define UCB_ADC_START         (1 << 7)
++#define UCB_ADC_ENA           (1 << 15)
++
++#define UCB_ADC_DATA  0x0b
++#define UCB_ADC_DAT_VAL               (1 << 15)
++#define UCB_ADC_DAT(x)                (((x) & 0x7fe0) >> 5)
++
++#define UCB_ID                0x0c
++#define UCB_ID_1200           0x1004
++#define UCB_ID_1300           0x1005
++#define UCB_ID_TC35143          0x9712
++
++#define UCB_MODE      0x0d
++#define UCB_MODE_DYN_VFLAG_ENA        (1 << 12)
++#define UCB_MODE_AUD_OFF_CAN  (1 << 13)
++
++
++struct ucb1x00_irq {
++      void *devid;
++      void (*fn)(int, void *);
++};
++
++struct ucb1x00 {
++      spinlock_t              lock;
++      struct mcp              *mcp;
++      unsigned int            irq;
++      struct semaphore        adc_sem;
++      spinlock_t              io_lock;
++      u16                     id;
++      u16                     io_dir;
++      u16                     io_out;
++      u16                     adc_cr;
++      u16                     irq_fal_enbl;
++      u16                     irq_ris_enbl;
++      struct ucb1x00_irq      irq_handler[16];
++      struct device           dev;
++      struct list_head        node;
++      struct list_head        devs;
++};
++
++struct ucb1x00_driver;
++
++struct ucb1x00_dev {
++      struct list_head        dev_node;
++      struct list_head        drv_node;
++      struct ucb1x00          *ucb;
++      struct ucb1x00_driver   *drv;
++      void                    *priv;
++};
++
++struct ucb1x00_driver {
++      struct list_head        node;
++      struct list_head        devs;
++      int     (*add)(struct ucb1x00_dev *dev);
++      void    (*remove)(struct ucb1x00_dev *dev);
++      int     (*suspend)(struct ucb1x00_dev *dev, pm_message_t state);
++      int     (*resume)(struct ucb1x00_dev *dev);
++};
++
++#define classdev_to_ucb1x00(cd)       container_of(cd, struct ucb1x00, dev)
++
++int ucb1x00_register_driver(struct ucb1x00_driver *);
++void ucb1x00_unregister_driver(struct ucb1x00_driver *);
++
++/**
++ *    ucb1x00_clkrate - return the UCB1x00 SIB clock rate
++ *    @ucb: UCB1x00 structure describing chip
++ *
++ *    Return the SIB clock rate in Hz.
++ */
++static inline unsigned int ucb1x00_clkrate(struct ucb1x00 *ucb)
++{
++      return mcp_get_sclk_rate(ucb->mcp);
++}
++
++/**
++ *    ucb1x00_enable - enable the UCB1x00 SIB clock
++ *    @ucb: UCB1x00 structure describing chip
++ *
++ *    Enable the SIB clock.  This can be called multiple times.
++ */
++static inline void ucb1x00_enable(struct ucb1x00 *ucb)
++{
++      mcp_enable(ucb->mcp);
++}
++
++/**
++ *    ucb1x00_disable - disable the UCB1x00 SIB clock
++ *    @ucb: UCB1x00 structure describing chip
++ *
++ *    Disable the SIB clock.  The SIB clock will only be disabled
++ *    when the number of ucb1x00_enable calls match the number of
++ *    ucb1x00_disable calls.
++ */
++static inline void ucb1x00_disable(struct ucb1x00 *ucb)
++{
++      mcp_disable(ucb->mcp);
++}
++
++/**
++ *    ucb1x00_reg_write - write a UCB1x00 register
++ *    @ucb: UCB1x00 structure describing chip
++ *    @reg: UCB1x00 4-bit register index to write
++ *    @val: UCB1x00 16-bit value to write
++ *
++ *    Write the UCB1x00 register @reg with value @val.  The SIB
++ *    clock must be running for this function to return.
++ */
++static inline void ucb1x00_reg_write(struct ucb1x00 *ucb, unsigned int reg, unsigned int val)
++{
++      mcp_reg_write(ucb->mcp, reg, val);
++}
++
++/**
++ *    ucb1x00_reg_read - read a UCB1x00 register
++ *    @ucb: UCB1x00 structure describing chip
++ *    @reg: UCB1x00 4-bit register index to write
++ *
++ *    Read the UCB1x00 register @reg and return its value.  The SIB
++ *    clock must be running for this function to return.
++ */
++static inline unsigned int ucb1x00_reg_read(struct ucb1x00 *ucb, unsigned int reg)
++{
++      return mcp_reg_read(ucb->mcp, reg);
++}
++/**
++ *    ucb1x00_set_audio_divisor - 
++ *    @ucb: UCB1x00 structure describing chip
++ *    @div: SIB clock divisor
++ */
++static inline void ucb1x00_set_audio_divisor(struct ucb1x00 *ucb, unsigned int div)
++{
++      mcp_set_audio_divisor(ucb->mcp, div);
++}
++
++/**
++ *    ucb1x00_set_telecom_divisor -
++ *    @ucb: UCB1x00 structure describing chip
++ *    @div: SIB clock divisor
++ */
++static inline void ucb1x00_set_telecom_divisor(struct ucb1x00 *ucb, unsigned int div)
++{
++      mcp_set_telecom_divisor(ucb->mcp, div);
++}
++
++void ucb1x00_io_set_dir(struct ucb1x00 *ucb, unsigned int, unsigned int);
++void ucb1x00_io_write(struct ucb1x00 *ucb, unsigned int, unsigned int);
++unsigned int ucb1x00_io_read(struct ucb1x00 *ucb);
++
++#define UCB_NOSYNC    (0)
++#define UCB_SYNC      (1)
++
++unsigned int ucb1x00_adc_read(struct ucb1x00 *ucb, int adc_channel, int sync);
++void ucb1x00_adc_enable(struct ucb1x00 *ucb);
++void ucb1x00_adc_disable(struct ucb1x00 *ucb);
++
++/*
++ * Which edges of the IRQ do you want to control today?
++ */
++#define UCB_RISING    (1 << 0)
++#define UCB_FALLING   (1 << 1)
++
++int ucb1x00_hook_irq(struct ucb1x00 *ucb, unsigned int idx, void (*fn)(int, void *), void *devid);
++void ucb1x00_enable_irq(struct ucb1x00 *ucb, unsigned int idx, int edges);
++void ucb1x00_disable_irq(struct ucb1x00 *ucb, unsigned int idx, int edges);
++int ucb1x00_free_irq(struct ucb1x00 *ucb, unsigned int idx, void *devid);
++
++#endif
+-- 
+1.5.6.5
+
diff --git a/packages/linux/linux-2.6.28/collie/0012-move-ucb1200-ts-driver.patch b/packages/linux/linux-2.6.28/collie/0012-move-ucb1200-ts-driver.patch
new file mode 100644 (file)
index 0000000..c1aafef
--- /dev/null
@@ -0,0 +1,981 @@
+From 9e0d71c4a6247d88d3b772f6b05bcaa39711a937 Mon Sep 17 00:00:00 2001
+From: Thomas Kunze <thommycheck@gmx.de>
+Date: Tue, 10 Feb 2009 19:31:25 +0100
+Subject: [PATCH 12/23] move ucb1200-ts driver
+
+Move the touchscreen driver to drivers/input/touchscreen
+where touchscreen drivers belong.
+
+Conflicts:
+
+       drivers/input/touchscreen/Makefile
+       drivers/mfd/Kconfig
+       drivers/mfd/Makefile
+
+Conflicts:
+
+       drivers/mfd/Kconfig
+       drivers/mfd/Makefile
+---
+ drivers/input/touchscreen/Kconfig      |    7 +
+ drivers/input/touchscreen/Makefile     |    1 +
+ drivers/input/touchscreen/ucb1x00-ts.c |  438 ++++++++++++++++++++++++++++++++
+ drivers/mfd/Kconfig                    |    3 -
+ drivers/mfd/Makefile                   |    3 +-
+ drivers/mfd/ucb1x00-ts.c               |  438 --------------------------------
+ 6 files changed, 447 insertions(+), 443 deletions(-)
+ create mode 100644 drivers/input/touchscreen/ucb1x00-ts.c
+ delete mode 100644 drivers/mfd/ucb1x00-ts.c
+
+diff --git a/drivers/input/touchscreen/Kconfig b/drivers/input/touchscreen/Kconfig
+index 3d1ab8f..3ac8cd6 100644
+--- a/drivers/input/touchscreen/Kconfig
++++ b/drivers/input/touchscreen/Kconfig
+@@ -221,6 +221,13 @@ config TOUCHSCREEN_ATMEL_TSADCC
+         To compile this driver as a module, choose M here: the
+         module will be called atmel_tsadcc.
++config TOUCHSCREEN_UCB1200_TS
++      tristate "Philips UCB1200 touchscreen"
++      depends on MCP_UCB1200
++      help
++        This enabled support for the Pilips UCB1200 touchscreen interface
++        and compatible.
++
+ config TOUCHSCREEN_UCB1400
+       tristate "Philips UCB1400 touchscreen"
+       depends on AC97_BUS
+diff --git a/drivers/input/touchscreen/Makefile b/drivers/input/touchscreen/Makefile
+index 15cf290..77ba930 100644
+--- a/drivers/input/touchscreen/Makefile
++++ b/drivers/input/touchscreen/Makefile
+@@ -25,6 +25,7 @@ obj-$(CONFIG_TOUCHSCREEN_PENMOUNT)   += penmount.o
+ obj-$(CONFIG_TOUCHSCREEN_TOUCHIT213)  += touchit213.o
+ obj-$(CONFIG_TOUCHSCREEN_TOUCHRIGHT)  += touchright.o
+ obj-$(CONFIG_TOUCHSCREEN_TOUCHWIN)    += touchwin.o
++obj-$(CONFIG_TOUCHSCREEN_UCB1200_TS)  += ucb1x00-ts.o
+ obj-$(CONFIG_TOUCHSCREEN_UCB1400)     += ucb1400_ts.o
+ obj-$(CONFIG_TOUCHSCREEN_WM97XX)      += wm97xx-ts.o
+ wm97xx-ts-$(CONFIG_TOUCHSCREEN_WM9705)        += wm9705.o
+diff --git a/drivers/input/touchscreen/ucb1x00-ts.c b/drivers/input/touchscreen/ucb1x00-ts.c
+new file mode 100644
+index 0000000..b5feae9
+--- /dev/null
++++ b/drivers/input/touchscreen/ucb1x00-ts.c
+@@ -0,0 +1,438 @@
++/*
++ *  Touchscreen driver for UCB1x00-based touchscreens
++ *
++ *  Copyright (C) 2001 Russell King, All Rights Reserved.
++ *  Copyright (C) 2005 Pavel Machek
++ *
++ * 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.
++ *
++ * 21-Jan-2002 <jco@ict.es> :
++ *
++ * Added support for synchronous A/D mode. This mode is useful to
++ * avoid noise induced in the touchpanel by the LCD, provided that
++ * the UCB1x00 has a valid LCD sync signal routed to its ADCSYNC pin.
++ * It is important to note that the signal connected to the ADCSYNC
++ * pin should provide pulses even when the LCD is blanked, otherwise
++ * a pen touch needed to unblank the LCD will never be read.
++ */
++#include <linux/module.h>
++#include <linux/moduleparam.h>
++#include <linux/init.h>
++#include <linux/smp.h>
++#include <linux/sched.h>
++#include <linux/completion.h>
++#include <linux/delay.h>
++#include <linux/string.h>
++#include <linux/input.h>
++#include <linux/device.h>
++#include <linux/freezer.h>
++#include <linux/slab.h>
++#include <linux/kthread.h>
++#include <linux/mfd/ucb1x00.h>
++
++#include <asm/dma.h>
++#include <mach/collie.h>
++#include <asm/mach-types.h>
++
++
++
++struct ucb1x00_ts {
++      struct input_dev        *idev;
++      struct ucb1x00          *ucb;
++
++      wait_queue_head_t       irq_wait;
++      struct task_struct      *rtask;
++      u16                     x_res;
++      u16                     y_res;
++
++      unsigned int            restart:1;
++      unsigned int            adcsync:1;
++};
++
++static int adcsync;
++
++static inline void ucb1x00_ts_evt_add(struct ucb1x00_ts *ts, u16 pressure, u16 x, u16 y)
++{
++      struct input_dev *idev = ts->idev;
++
++      input_report_abs(idev, ABS_X, x);
++      input_report_abs(idev, ABS_Y, y);
++      input_report_abs(idev, ABS_PRESSURE, pressure);
++      input_sync(idev);
++}
++
++static inline void ucb1x00_ts_event_release(struct ucb1x00_ts *ts)
++{
++      struct input_dev *idev = ts->idev;
++
++      input_report_abs(idev, ABS_PRESSURE, 0);
++      input_sync(idev);
++}
++
++/*
++ * Switch to interrupt mode.
++ */
++static inline void ucb1x00_ts_mode_int(struct ucb1x00_ts *ts)
++{
++      ucb1x00_reg_write(ts->ucb, UCB_TS_CR,
++                      UCB_TS_CR_TSMX_POW | UCB_TS_CR_TSPX_POW |
++                      UCB_TS_CR_TSMY_GND | UCB_TS_CR_TSPY_GND |
++                      UCB_TS_CR_MODE_INT);
++}
++
++/*
++ * Switch to pressure mode, and read pressure.  We don't need to wait
++ * here, since both plates are being driven.
++ */
++static inline unsigned int ucb1x00_ts_read_pressure(struct ucb1x00_ts *ts)
++{
++      if (machine_is_collie()) {
++              ucb1x00_io_write(ts->ucb, COLLIE_TC35143_GPIO_TBL_CHK, 0);
++              ucb1x00_reg_write(ts->ucb, UCB_TS_CR,
++                                UCB_TS_CR_TSPX_POW | UCB_TS_CR_TSMX_POW |
++                                UCB_TS_CR_MODE_POS | UCB_TS_CR_BIAS_ENA);
++
++              udelay(55);
++
++              return ucb1x00_adc_read(ts->ucb, UCB_ADC_INP_AD2, ts->adcsync);
++      } else {
++              ucb1x00_reg_write(ts->ucb, UCB_TS_CR,
++                                UCB_TS_CR_TSMX_POW | UCB_TS_CR_TSPX_POW |
++                                UCB_TS_CR_TSMY_GND | UCB_TS_CR_TSPY_GND |
++                                UCB_TS_CR_MODE_PRES | UCB_TS_CR_BIAS_ENA);
++
++              return ucb1x00_adc_read(ts->ucb, UCB_ADC_INP_TSPY, ts->adcsync);
++      }
++}
++
++/*
++ * Switch to X position mode and measure Y plate.  We switch the plate
++ * configuration in pressure mode, then switch to position mode.  This
++ * gives a faster response time.  Even so, we need to wait about 55us
++ * for things to stabilise.
++ */
++static inline unsigned int ucb1x00_ts_read_xpos(struct ucb1x00_ts *ts)
++{
++      if (machine_is_collie())
++              ucb1x00_io_write(ts->ucb, 0, COLLIE_TC35143_GPIO_TBL_CHK);
++      else {
++              ucb1x00_reg_write(ts->ucb, UCB_TS_CR,
++                                UCB_TS_CR_TSMX_GND | UCB_TS_CR_TSPX_POW |
++                                UCB_TS_CR_MODE_PRES | UCB_TS_CR_BIAS_ENA);
++              ucb1x00_reg_write(ts->ucb, UCB_TS_CR,
++                                UCB_TS_CR_TSMX_GND | UCB_TS_CR_TSPX_POW |
++                                UCB_TS_CR_MODE_PRES | UCB_TS_CR_BIAS_ENA);
++      }
++      ucb1x00_reg_write(ts->ucb, UCB_TS_CR,
++                      UCB_TS_CR_TSMX_GND | UCB_TS_CR_TSPX_POW |
++                      UCB_TS_CR_MODE_POS | UCB_TS_CR_BIAS_ENA);
++
++      udelay(55);
++
++      return ucb1x00_adc_read(ts->ucb, UCB_ADC_INP_TSPY, ts->adcsync);
++}
++
++/*
++ * Switch to Y position mode and measure X plate.  We switch the plate
++ * configuration in pressure mode, then switch to position mode.  This
++ * gives a faster response time.  Even so, we need to wait about 55us
++ * for things to stabilise.
++ */
++static inline unsigned int ucb1x00_ts_read_ypos(struct ucb1x00_ts *ts)
++{
++      if (machine_is_collie())
++              ucb1x00_io_write(ts->ucb, 0, COLLIE_TC35143_GPIO_TBL_CHK);
++      else {
++              ucb1x00_reg_write(ts->ucb, UCB_TS_CR,
++                                UCB_TS_CR_TSMY_GND | UCB_TS_CR_TSPY_POW |
++                                UCB_TS_CR_MODE_PRES | UCB_TS_CR_BIAS_ENA);
++              ucb1x00_reg_write(ts->ucb, UCB_TS_CR,
++                                UCB_TS_CR_TSMY_GND | UCB_TS_CR_TSPY_POW |
++                                UCB_TS_CR_MODE_PRES | UCB_TS_CR_BIAS_ENA);
++      }
++
++      ucb1x00_reg_write(ts->ucb, UCB_TS_CR,
++                      UCB_TS_CR_TSMY_GND | UCB_TS_CR_TSPY_POW |
++                      UCB_TS_CR_MODE_POS | UCB_TS_CR_BIAS_ENA);
++
++      udelay(55);
++
++      return ucb1x00_adc_read(ts->ucb, UCB_ADC_INP_TSPX, ts->adcsync);
++}
++
++/*
++ * Switch to X plate resistance mode.  Set MX to ground, PX to
++ * supply.  Measure current.
++ */
++static inline unsigned int ucb1x00_ts_read_xres(struct ucb1x00_ts *ts)
++{
++      ucb1x00_reg_write(ts->ucb, UCB_TS_CR,
++                      UCB_TS_CR_TSMX_GND | UCB_TS_CR_TSPX_POW |
++                      UCB_TS_CR_MODE_PRES | UCB_TS_CR_BIAS_ENA);
++      return ucb1x00_adc_read(ts->ucb, 0, ts->adcsync);
++}
++
++/*
++ * Switch to Y plate resistance mode.  Set MY to ground, PY to
++ * supply.  Measure current.
++ */
++static inline unsigned int ucb1x00_ts_read_yres(struct ucb1x00_ts *ts)
++{
++      ucb1x00_reg_write(ts->ucb, UCB_TS_CR,
++                      UCB_TS_CR_TSMY_GND | UCB_TS_CR_TSPY_POW |
++                      UCB_TS_CR_MODE_PRES | UCB_TS_CR_BIAS_ENA);
++      return ucb1x00_adc_read(ts->ucb, 0, ts->adcsync);
++}
++
++static inline int ucb1x00_ts_pen_down(struct ucb1x00_ts *ts)
++{
++      unsigned int val = ucb1x00_reg_read(ts->ucb, UCB_TS_CR);
++
++      if (machine_is_collie())
++              return (!(val & (UCB_TS_CR_TSPX_LOW)));
++      else
++              return (val & (UCB_TS_CR_TSPX_LOW | UCB_TS_CR_TSMX_LOW));
++}
++
++/*
++ * This is a RT kernel thread that handles the ADC accesses
++ * (mainly so we can use semaphores in the UCB1200 core code
++ * to serialise accesses to the ADC).
++ */
++static int ucb1x00_thread(void *_ts)
++{
++      struct ucb1x00_ts *ts = _ts;
++      DECLARE_WAITQUEUE(wait, current);
++      int valid = 0;
++
++      set_freezable();
++      add_wait_queue(&ts->irq_wait, &wait);
++      while (!kthread_should_stop()) {
++              unsigned int x, y, p;
++              signed long timeout;
++
++              ts->restart = 0;
++
++              ucb1x00_adc_enable(ts->ucb);
++
++              x = ucb1x00_ts_read_xpos(ts);
++              y = ucb1x00_ts_read_ypos(ts);
++              p = ucb1x00_ts_read_pressure(ts);
++
++              /*
++               * Switch back to interrupt mode.
++               */
++              ucb1x00_ts_mode_int(ts);
++              ucb1x00_adc_disable(ts->ucb);
++
++              msleep(10);
++
++              ucb1x00_enable(ts->ucb);
++
++
++              if (ucb1x00_ts_pen_down(ts)) {
++                      set_current_state(TASK_INTERRUPTIBLE);
++
++                      ucb1x00_enable_irq(ts->ucb, UCB_IRQ_TSPX, machine_is_collie() ? UCB_RISING : UCB_FALLING);
++                      ucb1x00_disable(ts->ucb);
++
++                      /*
++                       * If we spat out a valid sample set last time,
++                       * spit out a "pen off" sample here.
++                       */
++                      if (valid) {
++                              ucb1x00_ts_event_release(ts);
++                              valid = 0;
++                      }
++
++                      timeout = MAX_SCHEDULE_TIMEOUT;
++              } else {
++                      ucb1x00_disable(ts->ucb);
++
++                      /*
++                       * Filtering is policy.  Policy belongs in user
++                       * space.  We therefore leave it to user space
++                       * to do any filtering they please.
++                       */
++                      if (!ts->restart) {
++                              ucb1x00_ts_evt_add(ts, p, x, y);
++                              valid = 1;
++                      }
++
++                      set_current_state(TASK_INTERRUPTIBLE);
++                      timeout = HZ / 100;
++              }
++
++              try_to_freeze();
++
++              schedule_timeout(timeout);
++      }
++
++      remove_wait_queue(&ts->irq_wait, &wait);
++
++      ts->rtask = NULL;
++      return 0;
++}
++
++/*
++ * We only detect touch screen _touches_ with this interrupt
++ * handler, and even then we just schedule our task.
++ */
++static void ucb1x00_ts_irq(int idx, void *id)
++{
++      struct ucb1x00_ts *ts = id;
++
++      ucb1x00_disable_irq(ts->ucb, UCB_IRQ_TSPX, UCB_FALLING);
++      wake_up(&ts->irq_wait);
++}
++
++static int ucb1x00_ts_open(struct input_dev *idev)
++{
++      struct ucb1x00_ts *ts = input_get_drvdata(idev);
++      int ret = 0;
++
++      BUG_ON(ts->rtask);
++
++      init_waitqueue_head(&ts->irq_wait);
++      ret = ucb1x00_hook_irq(ts->ucb, UCB_IRQ_TSPX, ucb1x00_ts_irq, ts);
++      if (ret < 0)
++              goto out;
++
++      /*
++       * If we do this at all, we should allow the user to
++       * measure and read the X and Y resistance at any time.
++       */
++      ucb1x00_adc_enable(ts->ucb);
++      ts->x_res = ucb1x00_ts_read_xres(ts);
++      ts->y_res = ucb1x00_ts_read_yres(ts);
++      ucb1x00_adc_disable(ts->ucb);
++
++      ts->rtask = kthread_run(ucb1x00_thread, ts, "ktsd");
++      if (!IS_ERR(ts->rtask)) {
++              ret = 0;
++      } else {
++              ucb1x00_free_irq(ts->ucb, UCB_IRQ_TSPX, ts);
++              ts->rtask = NULL;
++              ret = -EFAULT;
++      }
++
++ out:
++      return ret;
++}
++
++/*
++ * Release touchscreen resources.  Disable IRQs.
++ */
++static void ucb1x00_ts_close(struct input_dev *idev)
++{
++      struct ucb1x00_ts *ts = input_get_drvdata(idev);
++
++      if (ts->rtask)
++              kthread_stop(ts->rtask);
++
++      ucb1x00_enable(ts->ucb);
++      ucb1x00_free_irq(ts->ucb, UCB_IRQ_TSPX, ts);
++      ucb1x00_reg_write(ts->ucb, UCB_TS_CR, 0);
++      ucb1x00_disable(ts->ucb);
++}
++
++#ifdef CONFIG_PM
++static int ucb1x00_ts_resume(struct ucb1x00_dev *dev)
++{
++      struct ucb1x00_ts *ts = dev->priv;
++
++      if (ts->rtask != NULL) {
++              /*
++               * Restart the TS thread to ensure the
++               * TS interrupt mode is set up again
++               * after sleep.
++               */
++              ts->restart = 1;
++              wake_up(&ts->irq_wait);
++      }
++      return 0;
++}
++#else
++#define ucb1x00_ts_resume NULL
++#endif
++
++
++/*
++ * Initialisation.
++ */
++static int ucb1x00_ts_add(struct ucb1x00_dev *dev)
++{
++      struct ucb1x00_ts *ts;
++      struct input_dev *idev;
++      int err;
++
++      ts = kzalloc(sizeof(struct ucb1x00_ts), GFP_KERNEL);
++      idev = input_allocate_device();
++      if (!ts || !idev) {
++              err = -ENOMEM;
++              goto fail;
++      }
++
++      ts->ucb = dev->ucb;
++      ts->idev = idev;
++      ts->adcsync = adcsync ? UCB_SYNC : UCB_NOSYNC;
++
++      idev->name       = "Touchscreen panel";
++      idev->id.product = ts->ucb->id;
++      idev->open       = ucb1x00_ts_open;
++      idev->close      = ucb1x00_ts_close;
++
++      __set_bit(EV_ABS, idev->evbit);
++      __set_bit(ABS_X, idev->absbit);
++      __set_bit(ABS_Y, idev->absbit);
++      __set_bit(ABS_PRESSURE, idev->absbit);
++
++      input_set_drvdata(idev, ts);
++
++      err = input_register_device(idev);
++      if (err)
++              goto fail;
++
++      dev->priv = ts;
++
++      return 0;
++
++ fail:
++      input_free_device(idev);
++      kfree(ts);
++      return err;
++}
++
++static void ucb1x00_ts_remove(struct ucb1x00_dev *dev)
++{
++      struct ucb1x00_ts *ts = dev->priv;
++
++      input_unregister_device(ts->idev);
++      kfree(ts);
++}
++
++static struct ucb1x00_driver ucb1x00_ts_driver = {
++      .add            = ucb1x00_ts_add,
++      .remove         = ucb1x00_ts_remove,
++      .resume         = ucb1x00_ts_resume,
++};
++
++static int __init ucb1x00_ts_init(void)
++{
++      return ucb1x00_register_driver(&ucb1x00_ts_driver);
++}
++
++static void __exit ucb1x00_ts_exit(void)
++{
++      ucb1x00_unregister_driver(&ucb1x00_ts_driver);
++}
++
++module_param(adcsync, int, 0444);
++module_init(ucb1x00_ts_init);
++module_exit(ucb1x00_ts_exit);
++
++MODULE_AUTHOR("Russell King <rmk@arm.linux.org.uk>");
++MODULE_DESCRIPTION("UCB1x00 touchscreen driver");
++MODULE_LICENSE("GPL");
+diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig
+index 2572773..bbc137d 100644
+--- a/drivers/mfd/Kconfig
++++ b/drivers/mfd/Kconfig
+@@ -172,8 +172,5 @@ config MCP_UCB1200
+       tristate "Support for UCB1200 / UCB1300"
+       depends on MCP
+-config MCP_UCB1200_TS
+-      tristate "Touchscreen interface support"
+-      depends on MCP_UCB1200 && INPUT
+ endmenu
+diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile
+index 9a5ad8a..4981aff 100644
+--- a/drivers/mfd/Makefile
++++ b/drivers/mfd/Makefile
+@@ -24,11 +24,10 @@ 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
+-obj-$(CONFIG_MCP_UCB1200_TS)  += ucb1x00-ts.o
+ ifeq ($(CONFIG_SA1100_ASSABET),y)
+ obj-$(CONFIG_MCP_UCB1200)     += ucb1x00-assabet.o
+ endif
+ obj-$(CONFIG_UCB1400_CORE)    += ucb1400_core.o
+-obj-$(CONFIG_PMIC_DA903X)     += da903x.o
+\ No newline at end of file
++obj-$(CONFIG_PMIC_DA903X)     += da903x.o
+diff --git a/drivers/mfd/ucb1x00-ts.c b/drivers/mfd/ucb1x00-ts.c
+deleted file mode 100644
+index b5feae9..0000000
+--- a/drivers/mfd/ucb1x00-ts.c
++++ /dev/null
+@@ -1,438 +0,0 @@
+-/*
+- *  Touchscreen driver for UCB1x00-based touchscreens
+- *
+- *  Copyright (C) 2001 Russell King, All Rights Reserved.
+- *  Copyright (C) 2005 Pavel Machek
+- *
+- * 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.
+- *
+- * 21-Jan-2002 <jco@ict.es> :
+- *
+- * Added support for synchronous A/D mode. This mode is useful to
+- * avoid noise induced in the touchpanel by the LCD, provided that
+- * the UCB1x00 has a valid LCD sync signal routed to its ADCSYNC pin.
+- * It is important to note that the signal connected to the ADCSYNC
+- * pin should provide pulses even when the LCD is blanked, otherwise
+- * a pen touch needed to unblank the LCD will never be read.
+- */
+-#include <linux/module.h>
+-#include <linux/moduleparam.h>
+-#include <linux/init.h>
+-#include <linux/smp.h>
+-#include <linux/sched.h>
+-#include <linux/completion.h>
+-#include <linux/delay.h>
+-#include <linux/string.h>
+-#include <linux/input.h>
+-#include <linux/device.h>
+-#include <linux/freezer.h>
+-#include <linux/slab.h>
+-#include <linux/kthread.h>
+-#include <linux/mfd/ucb1x00.h>
+-
+-#include <asm/dma.h>
+-#include <mach/collie.h>
+-#include <asm/mach-types.h>
+-
+-
+-
+-struct ucb1x00_ts {
+-      struct input_dev        *idev;
+-      struct ucb1x00          *ucb;
+-
+-      wait_queue_head_t       irq_wait;
+-      struct task_struct      *rtask;
+-      u16                     x_res;
+-      u16                     y_res;
+-
+-      unsigned int            restart:1;
+-      unsigned int            adcsync:1;
+-};
+-
+-static int adcsync;
+-
+-static inline void ucb1x00_ts_evt_add(struct ucb1x00_ts *ts, u16 pressure, u16 x, u16 y)
+-{
+-      struct input_dev *idev = ts->idev;
+-
+-      input_report_abs(idev, ABS_X, x);
+-      input_report_abs(idev, ABS_Y, y);
+-      input_report_abs(idev, ABS_PRESSURE, pressure);
+-      input_sync(idev);
+-}
+-
+-static inline void ucb1x00_ts_event_release(struct ucb1x00_ts *ts)
+-{
+-      struct input_dev *idev = ts->idev;
+-
+-      input_report_abs(idev, ABS_PRESSURE, 0);
+-      input_sync(idev);
+-}
+-
+-/*
+- * Switch to interrupt mode.
+- */
+-static inline void ucb1x00_ts_mode_int(struct ucb1x00_ts *ts)
+-{
+-      ucb1x00_reg_write(ts->ucb, UCB_TS_CR,
+-                      UCB_TS_CR_TSMX_POW | UCB_TS_CR_TSPX_POW |
+-                      UCB_TS_CR_TSMY_GND | UCB_TS_CR_TSPY_GND |
+-                      UCB_TS_CR_MODE_INT);
+-}
+-
+-/*
+- * Switch to pressure mode, and read pressure.  We don't need to wait
+- * here, since both plates are being driven.
+- */
+-static inline unsigned int ucb1x00_ts_read_pressure(struct ucb1x00_ts *ts)
+-{
+-      if (machine_is_collie()) {
+-              ucb1x00_io_write(ts->ucb, COLLIE_TC35143_GPIO_TBL_CHK, 0);
+-              ucb1x00_reg_write(ts->ucb, UCB_TS_CR,
+-                                UCB_TS_CR_TSPX_POW | UCB_TS_CR_TSMX_POW |
+-                                UCB_TS_CR_MODE_POS | UCB_TS_CR_BIAS_ENA);
+-
+-              udelay(55);
+-
+-              return ucb1x00_adc_read(ts->ucb, UCB_ADC_INP_AD2, ts->adcsync);
+-      } else {
+-              ucb1x00_reg_write(ts->ucb, UCB_TS_CR,
+-                                UCB_TS_CR_TSMX_POW | UCB_TS_CR_TSPX_POW |
+-                                UCB_TS_CR_TSMY_GND | UCB_TS_CR_TSPY_GND |
+-                                UCB_TS_CR_MODE_PRES | UCB_TS_CR_BIAS_ENA);
+-
+-              return ucb1x00_adc_read(ts->ucb, UCB_ADC_INP_TSPY, ts->adcsync);
+-      }
+-}
+-
+-/*
+- * Switch to X position mode and measure Y plate.  We switch the plate
+- * configuration in pressure mode, then switch to position mode.  This
+- * gives a faster response time.  Even so, we need to wait about 55us
+- * for things to stabilise.
+- */
+-static inline unsigned int ucb1x00_ts_read_xpos(struct ucb1x00_ts *ts)
+-{
+-      if (machine_is_collie())
+-              ucb1x00_io_write(ts->ucb, 0, COLLIE_TC35143_GPIO_TBL_CHK);
+-      else {
+-              ucb1x00_reg_write(ts->ucb, UCB_TS_CR,
+-                                UCB_TS_CR_TSMX_GND | UCB_TS_CR_TSPX_POW |
+-                                UCB_TS_CR_MODE_PRES | UCB_TS_CR_BIAS_ENA);
+-              ucb1x00_reg_write(ts->ucb, UCB_TS_CR,
+-                                UCB_TS_CR_TSMX_GND | UCB_TS_CR_TSPX_POW |
+-                                UCB_TS_CR_MODE_PRES | UCB_TS_CR_BIAS_ENA);
+-      }
+-      ucb1x00_reg_write(ts->ucb, UCB_TS_CR,
+-                      UCB_TS_CR_TSMX_GND | UCB_TS_CR_TSPX_POW |
+-                      UCB_TS_CR_MODE_POS | UCB_TS_CR_BIAS_ENA);
+-
+-      udelay(55);
+-
+-      return ucb1x00_adc_read(ts->ucb, UCB_ADC_INP_TSPY, ts->adcsync);
+-}
+-
+-/*
+- * Switch to Y position mode and measure X plate.  We switch the plate
+- * configuration in pressure mode, then switch to position mode.  This
+- * gives a faster response time.  Even so, we need to wait about 55us
+- * for things to stabilise.
+- */
+-static inline unsigned int ucb1x00_ts_read_ypos(struct ucb1x00_ts *ts)
+-{
+-      if (machine_is_collie())
+-              ucb1x00_io_write(ts->ucb, 0, COLLIE_TC35143_GPIO_TBL_CHK);
+-      else {
+-              ucb1x00_reg_write(ts->ucb, UCB_TS_CR,
+-                                UCB_TS_CR_TSMY_GND | UCB_TS_CR_TSPY_POW |
+-                                UCB_TS_CR_MODE_PRES | UCB_TS_CR_BIAS_ENA);
+-              ucb1x00_reg_write(ts->ucb, UCB_TS_CR,
+-                                UCB_TS_CR_TSMY_GND | UCB_TS_CR_TSPY_POW |
+-                                UCB_TS_CR_MODE_PRES | UCB_TS_CR_BIAS_ENA);
+-      }
+-
+-      ucb1x00_reg_write(ts->ucb, UCB_TS_CR,
+-                      UCB_TS_CR_TSMY_GND | UCB_TS_CR_TSPY_POW |
+-                      UCB_TS_CR_MODE_POS | UCB_TS_CR_BIAS_ENA);
+-
+-      udelay(55);
+-
+-      return ucb1x00_adc_read(ts->ucb, UCB_ADC_INP_TSPX, ts->adcsync);
+-}
+-
+-/*
+- * Switch to X plate resistance mode.  Set MX to ground, PX to
+- * supply.  Measure current.
+- */
+-static inline unsigned int ucb1x00_ts_read_xres(struct ucb1x00_ts *ts)
+-{
+-      ucb1x00_reg_write(ts->ucb, UCB_TS_CR,
+-                      UCB_TS_CR_TSMX_GND | UCB_TS_CR_TSPX_POW |
+-                      UCB_TS_CR_MODE_PRES | UCB_TS_CR_BIAS_ENA);
+-      return ucb1x00_adc_read(ts->ucb, 0, ts->adcsync);
+-}
+-
+-/*
+- * Switch to Y plate resistance mode.  Set MY to ground, PY to
+- * supply.  Measure current.
+- */
+-static inline unsigned int ucb1x00_ts_read_yres(struct ucb1x00_ts *ts)
+-{
+-      ucb1x00_reg_write(ts->ucb, UCB_TS_CR,
+-                      UCB_TS_CR_TSMY_GND | UCB_TS_CR_TSPY_POW |
+-                      UCB_TS_CR_MODE_PRES | UCB_TS_CR_BIAS_ENA);
+-      return ucb1x00_adc_read(ts->ucb, 0, ts->adcsync);
+-}
+-
+-static inline int ucb1x00_ts_pen_down(struct ucb1x00_ts *ts)
+-{
+-      unsigned int val = ucb1x00_reg_read(ts->ucb, UCB_TS_CR);
+-
+-      if (machine_is_collie())
+-              return (!(val & (UCB_TS_CR_TSPX_LOW)));
+-      else
+-              return (val & (UCB_TS_CR_TSPX_LOW | UCB_TS_CR_TSMX_LOW));
+-}
+-
+-/*
+- * This is a RT kernel thread that handles the ADC accesses
+- * (mainly so we can use semaphores in the UCB1200 core code
+- * to serialise accesses to the ADC).
+- */
+-static int ucb1x00_thread(void *_ts)
+-{
+-      struct ucb1x00_ts *ts = _ts;
+-      DECLARE_WAITQUEUE(wait, current);
+-      int valid = 0;
+-
+-      set_freezable();
+-      add_wait_queue(&ts->irq_wait, &wait);
+-      while (!kthread_should_stop()) {
+-              unsigned int x, y, p;
+-              signed long timeout;
+-
+-              ts->restart = 0;
+-
+-              ucb1x00_adc_enable(ts->ucb);
+-
+-              x = ucb1x00_ts_read_xpos(ts);
+-              y = ucb1x00_ts_read_ypos(ts);
+-              p = ucb1x00_ts_read_pressure(ts);
+-
+-              /*
+-               * Switch back to interrupt mode.
+-               */
+-              ucb1x00_ts_mode_int(ts);
+-              ucb1x00_adc_disable(ts->ucb);
+-
+-              msleep(10);
+-
+-              ucb1x00_enable(ts->ucb);
+-
+-
+-              if (ucb1x00_ts_pen_down(ts)) {
+-                      set_current_state(TASK_INTERRUPTIBLE);
+-
+-                      ucb1x00_enable_irq(ts->ucb, UCB_IRQ_TSPX, machine_is_collie() ? UCB_RISING : UCB_FALLING);
+-                      ucb1x00_disable(ts->ucb);
+-
+-                      /*
+-                       * If we spat out a valid sample set last time,
+-                       * spit out a "pen off" sample here.
+-                       */
+-                      if (valid) {
+-                              ucb1x00_ts_event_release(ts);
+-                              valid = 0;
+-                      }
+-
+-                      timeout = MAX_SCHEDULE_TIMEOUT;
+-              } else {
+-                      ucb1x00_disable(ts->ucb);
+-
+-                      /*
+-                       * Filtering is policy.  Policy belongs in user
+-                       * space.  We therefore leave it to user space
+-                       * to do any filtering they please.
+-                       */
+-                      if (!ts->restart) {
+-                              ucb1x00_ts_evt_add(ts, p, x, y);
+-                              valid = 1;
+-                      }
+-
+-                      set_current_state(TASK_INTERRUPTIBLE);
+-                      timeout = HZ / 100;
+-              }
+-
+-              try_to_freeze();
+-
+-              schedule_timeout(timeout);
+-      }
+-
+-      remove_wait_queue(&ts->irq_wait, &wait);
+-
+-      ts->rtask = NULL;
+-      return 0;
+-}
+-
+-/*
+- * We only detect touch screen _touches_ with this interrupt
+- * handler, and even then we just schedule our task.
+- */
+-static void ucb1x00_ts_irq(int idx, void *id)
+-{
+-      struct ucb1x00_ts *ts = id;
+-
+-      ucb1x00_disable_irq(ts->ucb, UCB_IRQ_TSPX, UCB_FALLING);
+-      wake_up(&ts->irq_wait);
+-}
+-
+-static int ucb1x00_ts_open(struct input_dev *idev)
+-{
+-      struct ucb1x00_ts *ts = input_get_drvdata(idev);
+-      int ret = 0;
+-
+-      BUG_ON(ts->rtask);
+-
+-      init_waitqueue_head(&ts->irq_wait);
+-      ret = ucb1x00_hook_irq(ts->ucb, UCB_IRQ_TSPX, ucb1x00_ts_irq, ts);
+-      if (ret < 0)
+-              goto out;
+-
+-      /*
+-       * If we do this at all, we should allow the user to
+-       * measure and read the X and Y resistance at any time.
+-       */
+-      ucb1x00_adc_enable(ts->ucb);
+-      ts->x_res = ucb1x00_ts_read_xres(ts);
+-      ts->y_res = ucb1x00_ts_read_yres(ts);
+-      ucb1x00_adc_disable(ts->ucb);
+-
+-      ts->rtask = kthread_run(ucb1x00_thread, ts, "ktsd");
+-      if (!IS_ERR(ts->rtask)) {
+-              ret = 0;
+-      } else {
+-              ucb1x00_free_irq(ts->ucb, UCB_IRQ_TSPX, ts);
+-              ts->rtask = NULL;
+-              ret = -EFAULT;
+-      }
+-
+- out:
+-      return ret;
+-}
+-
+-/*
+- * Release touchscreen resources.  Disable IRQs.
+- */
+-static void ucb1x00_ts_close(struct input_dev *idev)
+-{
+-      struct ucb1x00_ts *ts = input_get_drvdata(idev);
+-
+-      if (ts->rtask)
+-              kthread_stop(ts->rtask);
+-
+-      ucb1x00_enable(ts->ucb);
+-      ucb1x00_free_irq(ts->ucb, UCB_IRQ_TSPX, ts);
+-      ucb1x00_reg_write(ts->ucb, UCB_TS_CR, 0);
+-      ucb1x00_disable(ts->ucb);
+-}
+-
+-#ifdef CONFIG_PM
+-static int ucb1x00_ts_resume(struct ucb1x00_dev *dev)
+-{
+-      struct ucb1x00_ts *ts = dev->priv;
+-
+-      if (ts->rtask != NULL) {
+-              /*
+-               * Restart the TS thread to ensure the
+-               * TS interrupt mode is set up again
+-               * after sleep.
+-               */
+-              ts->restart = 1;
+-              wake_up(&ts->irq_wait);
+-      }
+-      return 0;
+-}
+-#else
+-#define ucb1x00_ts_resume NULL
+-#endif
+-
+-
+-/*
+- * Initialisation.
+- */
+-static int ucb1x00_ts_add(struct ucb1x00_dev *dev)
+-{
+-      struct ucb1x00_ts *ts;
+-      struct input_dev *idev;
+-      int err;
+-
+-      ts = kzalloc(sizeof(struct ucb1x00_ts), GFP_KERNEL);
+-      idev = input_allocate_device();
+-      if (!ts || !idev) {
+-              err = -ENOMEM;
+-              goto fail;
+-      }
+-
+-      ts->ucb = dev->ucb;
+-      ts->idev = idev;
+-      ts->adcsync = adcsync ? UCB_SYNC : UCB_NOSYNC;
+-
+-      idev->name       = "Touchscreen panel";
+-      idev->id.product = ts->ucb->id;
+-      idev->open       = ucb1x00_ts_open;
+-      idev->close      = ucb1x00_ts_close;
+-
+-      __set_bit(EV_ABS, idev->evbit);
+-      __set_bit(ABS_X, idev->absbit);
+-      __set_bit(ABS_Y, idev->absbit);
+-      __set_bit(ABS_PRESSURE, idev->absbit);
+-
+-      input_set_drvdata(idev, ts);
+-
+-      err = input_register_device(idev);
+-      if (err)
+-              goto fail;
+-
+-      dev->priv = ts;
+-
+-      return 0;
+-
+- fail:
+-      input_free_device(idev);
+-      kfree(ts);
+-      return err;
+-}
+-
+-static void ucb1x00_ts_remove(struct ucb1x00_dev *dev)
+-{
+-      struct ucb1x00_ts *ts = dev->priv;
+-
+-      input_unregister_device(ts->idev);
+-      kfree(ts);
+-}
+-
+-static struct ucb1x00_driver ucb1x00_ts_driver = {
+-      .add            = ucb1x00_ts_add,
+-      .remove         = ucb1x00_ts_remove,
+-      .resume         = ucb1x00_ts_resume,
+-};
+-
+-static int __init ucb1x00_ts_init(void)
+-{
+-      return ucb1x00_register_driver(&ucb1x00_ts_driver);
+-}
+-
+-static void __exit ucb1x00_ts_exit(void)
+-{
+-      ucb1x00_unregister_driver(&ucb1x00_ts_driver);
+-}
+-
+-module_param(adcsync, int, 0444);
+-module_init(ucb1x00_ts_init);
+-module_exit(ucb1x00_ts_exit);
+-
+-MODULE_AUTHOR("Russell King <rmk@arm.linux.org.uk>");
+-MODULE_DESCRIPTION("UCB1x00 touchscreen driver");
+-MODULE_LICENSE("GPL");
+-- 
+1.5.6.5
+
diff --git a/packages/linux/linux-2.6.28/collie/0013-add-collie-touchscreen-driver.patch b/packages/linux/linux-2.6.28/collie/0013-add-collie-touchscreen-driver.patch
new file mode 100644 (file)
index 0000000..92159d5
--- /dev/null
@@ -0,0 +1,528 @@
+From 40787f3e48d1cc1e63dc5dd6aeda720f688fc05e Mon Sep 17 00:00:00 2001
+From: Thomas Kunze <thommycheck@gmx.de>
+Date: Mon, 20 Oct 2008 17:44:23 +0200
+Subject: [PATCH 13/23] add collie touchscreen driver
+
+---
+ drivers/input/touchscreen/Kconfig     |    6 +
+ drivers/input/touchscreen/Makefile    |    1 +
+ drivers/input/touchscreen/collie-ts.c |  449 +++++++++++++++++++++++++++++++++
+ drivers/mfd/Makefile                  |    1 -
+ include/linux/mfd/ucb1x00.h           |    3 +
+ 5 files changed, 459 insertions(+), 1 deletions(-)
+ create mode 100644 drivers/input/touchscreen/collie-ts.c
+
+diff --git a/drivers/input/touchscreen/Kconfig b/drivers/input/touchscreen/Kconfig
+index 3ac8cd6..a9f89ed 100644
+--- a/drivers/input/touchscreen/Kconfig
++++ b/drivers/input/touchscreen/Kconfig
+@@ -228,6 +228,12 @@ config TOUCHSCREEN_UCB1200_TS
+         This enabled support for the Pilips UCB1200 touchscreen interface
+         and compatible.
++config TOUCHSCREEN_COLLIE_TS
++      tristate "Touchscreen collie support"
++      depends on MCP_UCB1200 && INPUT && !MCP_UCB1200_TS
++      help
++        Driver for touchscreen on collie - sharp sl-5500.
++
+ config TOUCHSCREEN_UCB1400
+       tristate "Philips UCB1400 touchscreen"
+       depends on AC97_BUS
+diff --git a/drivers/input/touchscreen/Makefile b/drivers/input/touchscreen/Makefile
+index 77ba930..77715cd 100644
+--- a/drivers/input/touchscreen/Makefile
++++ b/drivers/input/touchscreen/Makefile
+@@ -26,6 +26,7 @@ obj-$(CONFIG_TOUCHSCREEN_TOUCHIT213) += touchit213.o
+ obj-$(CONFIG_TOUCHSCREEN_TOUCHRIGHT)  += touchright.o
+ obj-$(CONFIG_TOUCHSCREEN_TOUCHWIN)    += touchwin.o
+ obj-$(CONFIG_TOUCHSCREEN_UCB1200_TS)  += ucb1x00-ts.o
++obj-$(CONFIG_TOUCHSCREEN_COLLIE_TS)     += collie-ts.o
+ obj-$(CONFIG_TOUCHSCREEN_UCB1400)     += ucb1400_ts.o
+ obj-$(CONFIG_TOUCHSCREEN_WM97XX)      += wm97xx-ts.o
+ wm97xx-ts-$(CONFIG_TOUCHSCREEN_WM9705)        += wm9705.o
+diff --git a/drivers/input/touchscreen/collie-ts.c b/drivers/input/touchscreen/collie-ts.c
+new file mode 100644
+index 0000000..c7c0272
+--- /dev/null
++++ b/drivers/input/touchscreen/collie-ts.c
+@@ -0,0 +1,449 @@
++/*
++ *  Touchscreen driver for UCB1x00-based touchscreens
++ *
++ *  Copyright (C) 2001 Russell King, All Rights Reserved.
++ *  Copyright (C) 2005 Pavel Machek
++ *
++ * 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.
++ *
++ * 21-Jan-2002 <jco@ict.es> :
++ *
++ * Added support for synchronous A/D mode. This mode is useful to
++ * avoid noise induced in the touchpanel by the LCD, provided that
++ * the UCB1x00 has a valid LCD sync signal routed to its ADCSYNC pin.
++ * It is important to note that the signal connected to the ADCSYNC
++ * pin should provide pulses even when the LCD is blanked, otherwise
++ * a pen touch needed to unblank the LCD will never be read.
++ */
++#include <linux/module.h>
++#include <linux/moduleparam.h>
++#include <linux/init.h>
++#include <linux/smp.h>
++#include <linux/smp_lock.h>
++#include <linux/sched.h>
++#include <linux/completion.h>
++#include <linux/delay.h>
++#include <linux/string.h>
++#include <linux/input.h>
++#include <linux/device.h>
++#include <linux/freezer.h>
++#include <linux/slab.h>
++#include <linux/kthread.h>
++#include <linux/semaphore.h>
++
++#include <mach/dma.h>
++#include <mach/collie.h>
++#include <asm/mach-types.h>
++
++#include <linux/mfd/ucb1x00.h>
++
++struct ucb1x00_ts {
++      struct input_dev        *idev;
++      struct ucb1x00          *ucb;
++
++      wait_queue_head_t       irq_wait;
++      struct task_struct      *rtask;
++      u16                     x_res;
++      u16                     y_res;
++
++      unsigned int            adcsync:1;
++};
++
++static int adcsync;
++
++/**********************************
++
++     ................
++     .              . = 340
++     .              .
++     .             ^.
++     .             ^.
++     .             ^.
++     .             ^.
++     .              .
++     .             X. = 10
++     .  <<<<<<<<  Y .
++     ................
++     .   Sharp    =200
++     .              .
++     .  -   O    -  .
++     .              .
++     ................
++
++**********************************/
++
++
++static inline void ucb1x00_ts_evt_add(struct ucb1x00_ts *ts, u16 pressure, u16 x, u16 y)
++{
++      struct input_dev *idev = ts->idev;
++
++      input_report_abs(idev, ABS_X, x);
++      input_report_abs(idev, ABS_Y, y);
++      input_report_abs(idev, ABS_PRESSURE, pressure);
++        input_report_key(idev, BTN_TOUCH, 1);
++      input_sync(idev);
++}
++
++static inline void ucb1x00_ts_event_release(struct ucb1x00_ts *ts)
++{
++      struct input_dev *idev = ts->idev;
++
++      input_report_abs(idev, ABS_PRESSURE, 0);
++        input_report_key(idev, BTN_TOUCH, 0);
++      input_sync(idev);
++}
++
++/*
++ * Switch to interrupt mode. This set touchscreen to interrupt 
++ * mode, so that chip is able to send interrupt.
++ */
++static inline void ucb1x00_ts_mode_int(struct ucb1x00_ts *ts)
++{
++      ucb1x00_reg_write(ts->ucb, UCB_TS_CR,
++                      UCB_TS_CR_TSMX_POW | UCB_TS_CR_TSPX_POW |
++                      UCB_TS_CR_TSMY_GND | UCB_TS_CR_TSPY_GND |
++                      UCB_TS_CR_MODE_INT);
++}
++
++/*
++ * Switch to pressure mode, and read pressure.  We don't need to wait
++ * here, since both plates are being driven.
++ *
++ * set_read_pressure() in sharp code
++ */
++static inline void ucb1x00_ts_read_pressure(struct ucb1x00_ts *ts)
++{
++      ucb1x00_io_write(ts->ucb, COLLIE_TC35143_GPIO_TBL_CHK, 0);
++      ucb1x00_reg_write(ts->ucb, UCB_TS_CR,
++                        UCB_TS_CR_TSPX_POW | UCB_TS_CR_TSMX_POW |
++                        UCB_TS_CR_MODE_POS | UCB_TS_CR_BIAS_ENA);
++
++      ucb1x00_reg_write(ts->ucb, UCB_ADC_CR, ts->ucb->adc_cr | 
++                        UCB_ADC_INP_AD2 | 
++                        UCB_ADC_SYNC_ENA);
++      udelay(100);
++      ucb1x00_reg_write(ts->ucb, UCB_ADC_CR, ts->ucb->adc_cr | 
++                        UCB_ADC_INP_AD2 | 
++                        UCB_ADC_SYNC_ENA | UCB_ADC_START);
++}
++
++/*
++ * Switch to X position mode and measure Y plate.  We switch the plate
++ * configuration in pressure mode, then switch to position mode.  This
++ * gives a faster response time.  Even so, we need to wait about 55us
++ * for things to stabilise.
++ */
++static inline void ucb1x00_ts_read_xpos(struct ucb1x00_ts *ts)
++{
++      ucb1x00_io_write(ts->ucb, 0, COLLIE_TC35143_GPIO_TBL_CHK);
++      ucb1x00_reg_write(ts->ucb, UCB_TS_CR,
++                      UCB_TS_CR_TSMX_GND | UCB_TS_CR_TSPX_POW |
++                      UCB_TS_CR_MODE_POS | UCB_TS_CR_BIAS_ENA);
++
++
++      ucb1x00_reg_write(ts->ucb, UCB_ADC_CR, ts->ucb->adc_cr | 
++                        UCB_ADC_INP_TSPY | UCB_ADC_SYNC_ENA);
++      udelay(100);
++      ucb1x00_reg_write(ts->ucb, UCB_ADC_CR, ts->ucb->adc_cr | 
++                        UCB_ADC_INP_TSPY | UCB_ADC_SYNC_ENA | 
++                        UCB_ADC_START);
++}
++
++/*
++ * Switch to Y position mode and measure X plate.  We switch the plate
++ * configuration in pressure mode, then switch to position mode.  This
++ * gives a faster response time.  Even so, we need to wait about 55us
++ * for things to stabilise.
++ */
++static inline void ucb1x00_ts_read_ypos(struct ucb1x00_ts *ts)
++{
++      ucb1x00_io_write(ts->ucb, 0, COLLIE_TC35143_GPIO_TBL_CHK);
++
++      ucb1x00_reg_write(ts->ucb, UCB_TS_CR,
++                      UCB_TS_CR_TSMY_GND | UCB_TS_CR_TSPY_POW |
++                      UCB_TS_CR_MODE_POS | UCB_TS_CR_BIAS_ENA);
++
++
++      ucb1x00_reg_write(ts->ucb, UCB_ADC_CR, ts->ucb->adc_cr | 
++                        UCB_ADC_INP_TSPX | UCB_ADC_SYNC_ENA);
++      udelay(100);
++      ucb1x00_reg_write(ts->ucb, UCB_ADC_CR, ts->ucb->adc_cr |
++                        UCB_ADC_INP_TSPX | UCB_ADC_SYNC_ENA | 
++                        UCB_ADC_START);
++}
++
++/*
++ * Switch to X plate resistance mode.  Set MX to ground, PX to
++ * supply.  Measure current.
++ */
++static inline unsigned int ucb1x00_ts_read_xres(struct ucb1x00_ts *ts)
++{
++      ucb1x00_reg_write(ts->ucb, UCB_TS_CR,
++                      UCB_TS_CR_TSMX_GND | UCB_TS_CR_TSPX_POW |
++                      UCB_TS_CR_MODE_PRES | UCB_TS_CR_BIAS_ENA);
++      return ucb1x00_adc_read(ts->ucb, 0, ts->adcsync);
++}
++
++/*
++ * Switch to Y plate resistance mode.  Set MY to ground, PY to
++ * supply.  Measure current.
++ */
++static inline unsigned int ucb1x00_ts_read_yres(struct ucb1x00_ts *ts)
++{
++      ucb1x00_reg_write(ts->ucb, UCB_TS_CR,
++                      UCB_TS_CR_TSMY_GND | UCB_TS_CR_TSPY_POW |
++                      UCB_TS_CR_MODE_PRES | UCB_TS_CR_BIAS_ENA);
++      return ucb1x00_adc_read(ts->ucb, 0, ts->adcsync);
++}
++
++/*
++ * This is a RT kernel thread that handles the ADC accesses
++ * (mainly so we can use semaphores in the UCB1200 core code
++ * to serialise accesses to the ADC).
++ */
++static int ucb1x00_thread(void *_ts)
++{
++      struct ucb1x00_ts *ts = _ts;
++      struct task_struct *tsk = current;
++      DECLARE_WAITQUEUE(wait, tsk);
++      int state;
++
++      /*
++       * We could run as a real-time thread.  However, thus far
++       * this doesn't seem to be necessary.
++       */
++
++      add_wait_queue(&ts->irq_wait, &wait);   
++
++      while (!kthread_should_stop()) {
++              unsigned int data[3];
++                      
++              for (state=0; state<3; state++) {
++                      
++                      ucb1x00_adc_enable(ts->ucb);
++                      ucb1x00_enable_irq(ts->ucb, UCB_IRQ_ADC, UCB_FALLING);
++                      switch (state) {
++                      /* Order matters here; last measurement seems to be more noisy then the
++                         rest, and we care about pressure least */
++                              case 2: ucb1x00_ts_read_pressure(ts);
++                                      break;
++                              case 0: ucb1x00_ts_read_ypos(ts);
++                                      break;
++                              case 1: ucb1x00_ts_read_xpos(ts);
++                                      break;
++                      }
++                      /* wait for adc */
++                      try_to_freeze();
++                      schedule_timeout(1000 * HZ);
++                      ucb1x00_disable_irq(ts->ucb, UCB_IRQ_ADC, UCB_FALLING);
++                      data[state] = UCB_ADC_DAT(ucb1x00_reg_read(ts->ucb, UCB_ADC_DATA));
++                      ucb1x00_adc_disable(ts->ucb);
++              }       
++              
++              /* If not pressed any more, try to sleep! */
++              if (data[2] < 300) {
++                      set_task_state(tsk, TASK_INTERRUPTIBLE);
++                      ucb1x00_enable_irq(ts->ucb, UCB_IRQ_TSPX, UCB_RISING);
++                      ucb1x00_ts_mode_int(ts);
++                      ucb1x00_disable(ts->ucb);
++                      ucb1x00_ts_event_release(ts);
++                      try_to_freeze();
++                      schedule_timeout(1000 * HZ);
++                      ucb1x00_disable_irq(ts->ucb, UCB_IRQ_TSPX, UCB_RISING);
++                      ucb1x00_enable(ts->ucb);
++              } else {        
++                      ucb1x00_ts_evt_add(ts, data[2], data[1], data[0]);
++              }
++              ucb1x00_disable(ts->ucb);
++              msleep(20);
++              ucb1x00_enable(ts->ucb);
++      }
++
++      remove_wait_queue(&ts->irq_wait, &wait);
++
++      ts->rtask = NULL;
++      return 0;
++}
++
++/*
++ * We only detect touch screen _touches_ with this interrupt
++ * handler, and even then we just schedule our task.
++ */
++static void ucb1x00_ts_irq(int idx, void *id)
++{
++      struct ucb1x00_ts *ts = id;
++      wake_up(&ts->irq_wait);
++}
++
++static void ucb1x00_adc_irq(int idx, void *id)
++{
++      struct ucb1x00_ts *ts = id;
++      wake_up(&ts->irq_wait);
++}
++
++static int ucb1x00_ts_open(struct input_dev *idev)
++{
++      struct ucb1x00_ts *ts = input_get_drvdata(idev);
++      int ret = 0;
++
++      BUG_ON(ts->rtask);
++
++      init_waitqueue_head(&ts->irq_wait);
++      
++      ret = ucb1x00_hook_irq(ts->ucb, UCB_IRQ_TSPX, ucb1x00_ts_irq, ts);
++      if (ret < 0)
++              return ret;
++      
++      ret = ucb1x00_hook_irq(ts->ucb, UCB_IRQ_ADC, ucb1x00_adc_irq, ts);
++      if (ret < 0) {
++              ucb1x00_free_irq(ts->ucb, UCB_IRQ_TSPX, ts);
++              return ret;
++      }
++
++      ucb1x00_enable_irq(ts->ucb, UCB_IRQ_TSPX, UCB_RISING);
++      
++      /*
++       * If we do this at all, we should allow the user to
++       * measure and read the X and Y resistance at any time.
++       */
++      ucb1x00_adc_enable(ts->ucb);
++      ts->x_res = ucb1x00_ts_read_xres(ts);
++      ts->y_res = ucb1x00_ts_read_yres(ts);
++      ucb1x00_adc_disable(ts->ucb);
++
++      if (machine_is_collie()) {
++              ucb1x00_io_set_dir(ts->ucb, 0, COLLIE_TC35143_GPIO_TBL_CHK);
++      }
++
++      ts->rtask = kthread_run(ucb1x00_thread, ts, "ktsd");
++      if (!IS_ERR(ts->rtask)) {
++              ret = 0;
++      } else {
++              ucb1x00_free_irq(ts->ucb, UCB_IRQ_TSPX, ts);
++              ts->rtask = NULL;
++              ret = -EFAULT;
++      }
++      
++      return ret;
++}
++
++/*
++ * Release touchscreen resources.  Disable IRQs.
++ */
++static void ucb1x00_ts_close(struct input_dev *idev)
++{
++      struct ucb1x00_ts *ts = input_get_drvdata(idev);
++
++      if (ts->rtask)
++              kthread_stop(ts->rtask);
++
++      ucb1x00_enable(ts->ucb);
++      ucb1x00_free_irq(ts->ucb, UCB_IRQ_TSPX, ts);
++      ucb1x00_free_irq(ts->ucb, UCB_IRQ_ADC, ts);
++      ucb1x00_reg_write(ts->ucb, UCB_TS_CR, 0);
++      ucb1x00_disable(ts->ucb);
++}
++
++#ifdef CONFIG_PM
++static int ucb1x00_ts_resume(struct ucb1x00_dev *dev)
++{
++      struct ucb1x00_ts *ts = dev->priv;
++
++      if (ts->rtask != NULL) {
++              /*
++               * Restart the TS thread to ensure the
++               * TS interrupt mode is set up again
++               * after sleep.
++               */
++              wake_up(&ts->irq_wait);
++      }
++      return 0;
++}
++#else
++#define ucb1x00_ts_resume NULL
++#endif
++
++
++/*
++ * Initialisation.
++ */
++static int ucb1x00_ts_add(struct ucb1x00_dev *dev)
++{
++      struct ucb1x00_ts *ts;
++      struct input_dev *idev;
++      int err;
++
++      ts = kzalloc(sizeof(struct ucb1x00_ts), GFP_KERNEL);
++      idev = input_allocate_device();
++      if (!ts || !idev) {
++              err = -ENOMEM;
++              goto fail;
++      }
++
++      ts->ucb = dev->ucb;
++      ts->idev = idev;
++      ts->adcsync = adcsync ? UCB_SYNC : UCB_NOSYNC;
++
++      input_set_drvdata(idev, ts);
++      idev->name       = "Touchscreen panel";
++      idev->id.product = ts->ucb->id;
++      idev->open       = ucb1x00_ts_open;
++      idev->close      = ucb1x00_ts_close;
++
++      __set_bit(EV_ABS, idev->evbit);
++      __set_bit(ABS_X, idev->absbit);
++      __set_bit(ABS_Y, idev->absbit);
++      __set_bit(ABS_PRESSURE, idev->absbit);
++
++        input_set_abs_params(ts->idev, ABS_X, 0, 450, 0, 0);
++        input_set_abs_params(ts->idev, ABS_Y, 200, 800, 0, 0);
++        input_set_abs_params(ts->idev, ABS_PRESSURE, 400, 800, 0, 0);
++
++
++      err = input_register_device(idev);
++      if (err)
++              goto fail;
++
++      dev->priv = ts;
++
++      return 0;
++
++ fail:
++      input_free_device(idev);
++      kfree(ts);
++      return err;
++}
++
++static void ucb1x00_ts_remove(struct ucb1x00_dev *dev)
++{
++      struct ucb1x00_ts *ts = dev->priv;
++
++      input_unregister_device(ts->idev);
++      kfree(ts);
++}
++
++static struct ucb1x00_driver ucb1x00_ts_driver = {
++      .add            = ucb1x00_ts_add,
++      .remove         = ucb1x00_ts_remove,
++      .resume         = ucb1x00_ts_resume,
++};
++
++static int __init ucb1x00_ts_init(void)
++{
++      return ucb1x00_register_driver(&ucb1x00_ts_driver);
++}
++
++static void __exit ucb1x00_ts_exit(void)
++{
++      ucb1x00_unregister_driver(&ucb1x00_ts_driver);
++}
++
++module_param(adcsync, int, 0444);
++module_init(ucb1x00_ts_init);
++module_exit(ucb1x00_ts_exit);
++
++MODULE_AUTHOR("Russell King <rmk@arm.linux.org.uk>");
++MODULE_DESCRIPTION("UCB1x00 touchscreen driver");
++MODULE_LICENSE("GPL");
+diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile
+index 4981aff..7bbba6e 100644
+--- a/drivers/mfd/Makefile
++++ b/drivers/mfd/Makefile
+@@ -24,7 +24,6 @@ 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
+-
+ ifeq ($(CONFIG_SA1100_ASSABET),y)
+ obj-$(CONFIG_MCP_UCB1200)     += ucb1x00-assabet.o
+ endif
+diff --git a/include/linux/mfd/ucb1x00.h b/include/linux/mfd/ucb1x00.h
+index eac3463..70eb763 100644
+--- a/include/linux/mfd/ucb1x00.h
++++ b/include/linux/mfd/ucb1x00.h
+@@ -35,7 +35,10 @@
+ #define UCB_IE_TCLIP          (1 << 14)
+ #define UCB_IE_ACLIP          (1 << 15)
++/* UCB1200 irqs */
++#define UCB_IRQ_ADC           11
+ #define UCB_IRQ_TSPX          12
++#define UCB_IRQ_TSMX          13
+ #define UCB_TC_A      0x05
+ #define UCB_TC_A_LOOP         (1 << 7)        /* UCB1200 */
+-- 
+1.5.6.5
+
diff --git a/packages/linux/linux-2.6.28/collie/0014-collie-locomo-led-change-default-trigger.patch b/packages/linux/linux-2.6.28/collie/0014-collie-locomo-led-change-default-trigger.patch
new file mode 100644 (file)
index 0000000..4d2828e
--- /dev/null
@@ -0,0 +1,27 @@
+From 047e4432e024fbec1e308e3c496822f52ce63ecb Mon Sep 17 00:00:00 2001
+From: Thomas Kunze <thommycheck@gmx.de>
+Date: Tue, 10 Feb 2009 13:21:42 +0100
+Subject: [PATCH 14/23] collie: locomo-led change default trigger
+
+Collie uses now the powersupply framework. Change the
+default led-trigger of locomo-led to reflect that.
+---
+ drivers/leds/leds-locomo.c |    2 +-
+ 1 files changed, 1 insertions(+), 1 deletions(-)
+
+diff --git a/drivers/leds/leds-locomo.c b/drivers/leds/leds-locomo.c
+index 5d91362..1f7c10f 100644
+--- a/drivers/leds/leds-locomo.c
++++ b/drivers/leds/leds-locomo.c
+@@ -44,7 +44,7 @@ static void locomoled_brightness_set1(struct led_classdev *led_cdev,
+ static struct led_classdev locomo_led0 = {
+       .name                   = "locomo:amber:charge",
+-      .default_trigger        = "sharpsl-charge",
++      .default_trigger        = "main-battery-charging",
+       .brightness_set         = locomoled_brightness_set0,
+ };
+-- 
+1.5.6.5
+
diff --git a/packages/linux/linux-2.6.28/collie/0015-SA1100-make-gpio_to_irq-and-reverse-a-macro.patch b/packages/linux/linux-2.6.28/collie/0015-SA1100-make-gpio_to_irq-and-reverse-a-macro.patch
new file mode 100644 (file)
index 0000000..99d0314
--- /dev/null
@@ -0,0 +1,43 @@
+From 87e4ecb2702d0d1a800da0ba81cd867b0f150410 Mon Sep 17 00:00:00 2001
+From: Thomas Kunze <thommycheck@gmx.de>
+Date: Mon, 9 Feb 2009 23:14:44 +0100
+Subject: [PATCH 15/23] SA1100: make gpio_to_irq and reverse a macro
+
+The function can't be used for static initialisations so
+convert them to macros.
+---
+ arch/arm/mach-sa1100/include/mach/gpio.h |   19 ++++---------------
+ 1 files changed, 4 insertions(+), 15 deletions(-)
+
+diff --git a/arch/arm/mach-sa1100/include/mach/gpio.h b/arch/arm/mach-sa1100/include/mach/gpio.h
+index 582a0c9..7befc10 100644
+--- a/arch/arm/mach-sa1100/include/mach/gpio.h
++++ b/arch/arm/mach-sa1100/include/mach/gpio.h
+@@ -49,20 +49,9 @@ static inline void gpio_set_value(unsigned gpio, int value)
+ #define gpio_cansleep __gpio_cansleep
+-static inline unsigned gpio_to_irq(unsigned gpio)
+-{
+-      if (gpio < 11)
+-              return IRQ_GPIO0 + gpio;
+-      else
+-              return IRQ_GPIO11 - 11 + gpio;
+-}
+-
+-static inline unsigned irq_to_gpio(unsigned irq)
+-{
+-      if (irq < IRQ_GPIO11_27)
+-              return irq - IRQ_GPIO0;
+-      else
+-              return irq - IRQ_GPIO11 + 11;
+-}
++#define gpio_to_irq(gpio)     ((gpio < 11) ? (IRQ_GPIO0 + gpio) : \
++                                      (IRQ_GPIO11 - 11 + gpio))
++#define irq_to_gpio(irq)      ((irq < IRQ_GPIO11_27) ? (irq - IRQ_GPIO0) : \
++                                      (irq - IRQ_GPIO11 + 11))
+ #endif
+-- 
+1.5.6.5
+
diff --git a/packages/linux/linux-2.6.28/collie/0016-add-gpiolib-support-to-ucb1x00.patch b/packages/linux/linux-2.6.28/collie/0016-add-gpiolib-support-to-ucb1x00.patch
new file mode 100644 (file)
index 0000000..aab08a6
--- /dev/null
@@ -0,0 +1,242 @@
+From 1de1b5c2860d889a9422f187ad90d8e38b2431fd Mon Sep 17 00:00:00 2001
+From: Thomas Kunze <thommycheck@gmx.de>
+Date: Tue, 10 Feb 2009 14:50:56 +0100
+Subject: [PATCH 16/23] add gpiolib support to ucb1x00
+
+The old access methods to the gpios will be removed when
+all users has been converted. (mainly ucb1x00-ts)
+---
+ arch/arm/mach-sa1100/include/mach/mcp.h |    1 +
+ drivers/mfd/mcp-sa11x0.c                |    1 +
+ drivers/mfd/ucb1x00-core.c              |   87 ++++++++++++++++++++++++++++++-
+ include/linux/mfd/mcp.h                 |    1 +
+ include/linux/mfd/ucb1x00.h             |    3 +
+ 5 files changed, 91 insertions(+), 2 deletions(-)
+
+diff --git a/arch/arm/mach-sa1100/include/mach/mcp.h b/arch/arm/mach-sa1100/include/mach/mcp.h
+index fb8b09a..ed1a331 100644
+--- a/arch/arm/mach-sa1100/include/mach/mcp.h
++++ b/arch/arm/mach-sa1100/include/mach/mcp.h
+@@ -16,6 +16,7 @@ struct mcp_plat_data {
+       u32 mccr0;
+       u32 mccr1;
+       unsigned int sclk_rate;
++      int gpio_base;
+ };
+ #endif
+diff --git a/drivers/mfd/mcp-sa11x0.c b/drivers/mfd/mcp-sa11x0.c
+index 88c81cf..dfa59eb 100644
+--- a/drivers/mfd/mcp-sa11x0.c
++++ b/drivers/mfd/mcp-sa11x0.c
+@@ -163,6 +163,7 @@ static int mcp_sa11x0_probe(struct platform_device *pdev)
+       mcp->dma_audio_wr       = DMA_Ser4MCP0Wr;
+       mcp->dma_telco_rd       = DMA_Ser4MCP1Rd;
+       mcp->dma_telco_wr       = DMA_Ser4MCP1Wr;
++      mcp->gpio_base          = data->gpio_base;
+       platform_set_drvdata(pdev, mcp);
+diff --git a/drivers/mfd/ucb1x00-core.c b/drivers/mfd/ucb1x00-core.c
+index bc2c1ba..b9c3f3d 100644
+--- a/drivers/mfd/ucb1x00-core.c
++++ b/drivers/mfd/ucb1x00-core.c
+@@ -25,11 +25,11 @@
+ #include <linux/device.h>
+ #include <linux/mutex.h>
+ #include <linux/mfd/ucb1x00.h>
++#include <linux/gpio.h>
+ #include <asm/dma.h>
+ #include <mach/hardware.h>
+-
+ static DEFINE_MUTEX(ucb1x00_mutex);
+ static LIST_HEAD(ucb1x00_drivers);
+ static LIST_HEAD(ucb1x00_devices);
+@@ -107,6 +107,60 @@ unsigned int ucb1x00_io_read(struct ucb1x00 *ucb)
+       return ucb1x00_reg_read(ucb, UCB_IO_DATA);
+ }
++static void ucb1x00_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
++{
++      struct ucb1x00 *ucb = container_of(chip, struct ucb1x00, gpio);
++      unsigned long flags;
++
++      spin_lock_irqsave(&ucb->io_lock, flags);
++      if (value)
++              ucb->io_out |= 1 << offset;
++      else
++              ucb->io_out &= ~(1 << offset);
++
++      ucb1x00_reg_write(ucb, UCB_IO_DATA, ucb->io_out);
++      spin_unlock_irqrestore(&ucb->io_lock, flags);
++}
++
++static int ucb1x00_gpio_get(struct gpio_chip *chip, unsigned offset)
++{
++      struct ucb1x00 *ucb = container_of(chip, struct ucb1x00, gpio);
++      return ucb1x00_reg_read(ucb, UCB_IO_DATA) & (1 << offset);
++}
++
++static int ucb1x00_gpio_direction_input(struct gpio_chip *chip, unsigned offset)
++{
++      struct ucb1x00 *ucb = container_of(chip, struct ucb1x00, gpio);
++      unsigned long flags;
++
++      spin_lock_irqsave(&ucb->io_lock, flags);
++      ucb->io_dir &= ~(1 << offset);
++      ucb1x00_reg_write(ucb, UCB_IO_DIR, ucb->io_dir);
++      spin_unlock_irqrestore(&ucb->io_lock, flags);
++
++      return 0;
++}
++
++static int ucb1x00_gpio_direction_output(struct gpio_chip *chip, unsigned offset
++              , int value)
++{
++      struct ucb1x00 *ucb = container_of(chip, struct ucb1x00, gpio);
++      unsigned long flags;
++
++      spin_lock_irqsave(&ucb->io_lock, flags);
++      ucb->io_dir |= (1 << offset);
++      ucb1x00_reg_write(ucb, UCB_IO_DIR, ucb->io_dir);
++
++      if (value)
++              ucb->io_out |= 1 << offset;
++      else
++              ucb->io_out &= ~(1 << offset);
++      ucb1x00_reg_write(ucb, UCB_IO_DATA, ucb->io_out);
++      spin_unlock_irqrestore(&ucb->io_lock, flags);
++
++      return 0;
++}
++
+ /*
+  * UCB1300 data sheet says we must:
+  *  1. enable ADC     => 5us (including reference startup time)
+@@ -475,6 +529,7 @@ static int ucb1x00_probe(struct mcp *mcp)
+       struct ucb1x00_driver *drv;
+       unsigned int id;
+       int ret = -ENODEV;
++      int temp;
+       mcp_enable(mcp);
+       id = mcp_reg_read(mcp, UCB_ID);
+@@ -507,12 +562,27 @@ static int ucb1x00_probe(struct mcp *mcp)
+               goto err_free;
+       }
++      ucb->gpio.base = -1;
++      if (mcp->gpio_base != 0) {
++              ucb->gpio.label = dev_name(&ucb->dev);
++              ucb->gpio.base = mcp->gpio_base;
++              ucb->gpio.ngpio = 10;
++              ucb->gpio.set = ucb1x00_gpio_set;
++              ucb->gpio.get = ucb1x00_gpio_get;
++              ucb->gpio.direction_input = ucb1x00_gpio_direction_input;
++              ucb->gpio.direction_output = ucb1x00_gpio_direction_output;
++              ret = gpiochip_add(&ucb->gpio);
++              if (ret)
++                      goto err_free;
++      } else
++              dev_info(&ucb->dev, "gpio_base not set so no gpiolib support");
++
+       ret = request_irq(ucb->irq, ucb1x00_irq, IRQF_TRIGGER_RISING,
+                         "UCB1x00", ucb);
+       if (ret) {
+               printk(KERN_ERR "ucb1x00: unable to grab irq%d: %d\n",
+                       ucb->irq, ret);
+-              goto err_free;
++              goto err_gpio;
+       }
+       mcp_set_drvdata(mcp, ucb);
+@@ -521,6 +591,7 @@ static int ucb1x00_probe(struct mcp *mcp)
+       if (ret)
+               goto err_irq;
++
+       INIT_LIST_HEAD(&ucb->devs);
+       mutex_lock(&ucb1x00_mutex);
+       list_add(&ucb->node, &ucb1x00_devices);
+@@ -528,10 +599,14 @@ static int ucb1x00_probe(struct mcp *mcp)
+               ucb1x00_add_dev(ucb, drv);
+       }
+       mutex_unlock(&ucb1x00_mutex);
++
+       goto out;
+  err_irq:
+       free_irq(ucb->irq, ucb);
++ err_gpio:
++      if (ucb->gpio.base != -1)
++              temp = gpiochip_remove(&ucb->gpio);
+  err_free:
+       kfree(ucb);
+  err_disable:
+@@ -544,6 +619,7 @@ static void ucb1x00_remove(struct mcp *mcp)
+ {
+       struct ucb1x00 *ucb = mcp_get_drvdata(mcp);
+       struct list_head *l, *n;
++      int ret;
+       mutex_lock(&ucb1x00_mutex);
+       list_del(&ucb->node);
+@@ -553,6 +629,12 @@ static void ucb1x00_remove(struct mcp *mcp)
+       }
+       mutex_unlock(&ucb1x00_mutex);
++      if (ucb->gpio.base != -1) {
++              ret = gpiochip_remove(&ucb->gpio);
++              if (ret)
++                      dev_err(&ucb->dev, "Can't remove gpio chip: %d\n", ret);
++      }
++
+       free_irq(ucb->irq, ucb);
+       device_unregister(&ucb->dev);
+ }
+@@ -603,6 +685,7 @@ static int ucb1x00_resume(struct mcp *mcp)
+       struct ucb1x00 *ucb = mcp_get_drvdata(mcp);
+       struct ucb1x00_dev *dev;
++      ucb1x00_reg_write(ucb, UCB_IO_DIR, ucb->io_dir);
+       mutex_lock(&ucb1x00_mutex);
+       list_for_each_entry(dev, &ucb->devs, dev_node) {
+               if (dev->drv->resume)
+diff --git a/include/linux/mfd/mcp.h b/include/linux/mfd/mcp.h
+index be95e09..ee49670 100644
+--- a/include/linux/mfd/mcp.h
++++ b/include/linux/mfd/mcp.h
+@@ -26,6 +26,7 @@ struct mcp {
+       dma_device_t    dma_telco_rd;
+       dma_device_t    dma_telco_wr;
+       struct device   attached_device;
++      int             gpio_base;
+ };
+ struct mcp_ops {
+diff --git a/include/linux/mfd/ucb1x00.h b/include/linux/mfd/ucb1x00.h
+index 70eb763..b13171e 100644
+--- a/include/linux/mfd/ucb1x00.h
++++ b/include/linux/mfd/ucb1x00.h
+@@ -11,6 +11,8 @@
+ #define UCB1200_H
+ #include <linux/mfd/mcp.h>
++#include <linux/gpio.h>
++
+ #define UCB_IO_DATA   0x00
+ #define UCB_IO_DIR    0x01
+@@ -126,6 +128,7 @@ struct ucb1x00 {
+       struct device           dev;
+       struct list_head        node;
+       struct list_head        devs;
++      struct gpio_chip        gpio;
+ };
+ struct ucb1x00_driver;
+-- 
+1.5.6.5
+
diff --git a/packages/linux/linux-2.6.28/collie/0017-collie-convert-to-gpiolib-for-ucb1x00.patch b/packages/linux/linux-2.6.28/collie/0017-collie-convert-to-gpiolib-for-ucb1x00.patch
new file mode 100644 (file)
index 0000000..c08c21a
--- /dev/null
@@ -0,0 +1,137 @@
+From c1bf0dcce68a5e01213e18c9ca1fd49efad4ddff Mon Sep 17 00:00:00 2001
+From: Thomas Kunze <thommycheck@gmx.de>
+Date: Tue, 10 Feb 2009 18:15:34 +0100
+Subject: [PATCH 17/23] collie: convert to gpiolib for ucb1x00
+
+Only the parts used for collie_battery are converted.
+The rest will be cleaned up later.
+
+Conflicts:
+
+       arch/arm/mach-sa1100/collie.c
+       arch/arm/mach-sa1100/include/mach/collie.h
+---
+ arch/arm/mach-sa1100/collie.c              |    3 +-
+ arch/arm/mach-sa1100/include/mach/collie.h |   68 ++++++++++++++-------------
+ 2 files changed, 37 insertions(+), 34 deletions(-)
+
+diff --git a/arch/arm/mach-sa1100/collie.c b/arch/arm/mach-sa1100/collie.c
+index ec673b8..4b52f30 100644
+--- a/arch/arm/mach-sa1100/collie.c
++++ b/arch/arm/mach-sa1100/collie.c
+@@ -87,6 +87,7 @@ static struct scoop_pcmcia_config collie_pcmcia_config = {
+ static struct mcp_plat_data collie_mcp_data = {
+       .mccr0          = MCCR0_ADM | MCCR0_ExtClk,
+       .sclk_rate      = 9216000,
++      .gpio_base      = COLLIE_TC35143_GPIO_BASE,
+ };
+ #ifdef CONFIG_SHARP_LOCOMO
+@@ -256,7 +257,7 @@ static void __init collie_init(void)
+               PPC_LDD6 | PPC_LDD7 | PPC_L_PCLK | PPC_L_LCLK | PPC_L_FCLK | PPC_L_BIAS |
+               PPC_TXD1 | PPC_TXD2 | PPC_TXD3 | PPC_TXD4 | PPC_SCLK | PPC_SFRM;
+-      PWER = COLLIE_GPIO_AC_IN | COLLIE_GPIO_CO | COLLIE_GPIO_ON_KEY |
++      PWER = COLLIE_GPIO_AC_IN_ | COLLIE_GPIO_CO_ | COLLIE_GPIO_ON_KEY |
+               COLLIE_GPIO_WAKEUP | COLLIE_GPIO_nREMOCON_INT | PWER_RTC;
+       PGSR = COLLIE_GPIO_nREMOCON_ON;
+diff --git a/arch/arm/mach-sa1100/include/mach/collie.h b/arch/arm/mach-sa1100/include/mach/collie.h
+index 799c930..bba8978 100644
+--- a/arch/arm/mach-sa1100/include/mach/collie.h
++++ b/arch/arm/mach-sa1100/include/mach/collie.h
+@@ -15,7 +15,7 @@
+ #define COLLIE_SCOOP_GPIO_BASE        (GPIO_MAX + 1)
+-#define COLLIE_SCP_CHARGE_ON  SCOOP_GPCR_PA11
++#define COLLIE_GPIO_CHARGE_ON (COLLIE_SCOOP_GPIO_BASE)
+ #define COLLIE_SCP_DIAG_BOOT1 SCOOP_GPCR_PA12
+ #define COLLIE_SCP_DIAG_BOOT2 SCOOP_GPCR_PA13
+ #define COLLIE_SCP_MUTE_L     SCOOP_GPCR_PA14
+@@ -25,28 +25,29 @@
+ #define COLLIE_GPIO_VPEN      (COLLIE_SCOOP_GPIO_BASE + 7)
+ #define COLLIE_GPIO_LB_VOL_CHG        (COLLIE_SCOOP_GPIO_BASE + 8)
+-#define COLLIE_SCOOP_IO_DIR   ( COLLIE_SCP_CHARGE_ON | COLLIE_SCP_MUTE_L | COLLIE_SCP_MUTE_R | \
++#define COLLIE_SCOOP_IO_DIR   (COLLIE_SCP_MUTE_L | COLLIE_SCP_MUTE_R | \
+                               COLLIE_SCP_5VON | COLLIE_SCP_AMP_ON )
+-#define COLLIE_SCOOP_IO_OUT   ( COLLIE_SCP_MUTE_L | COLLIE_SCP_MUTE_R | \
+-                              COLLIE_SCP_CHARGE_ON )
++#define COLLIE_SCOOP_IO_OUT   (COLLIE_SCP_MUTE_L | COLLIE_SCP_MUTE_R)
+ /* GPIOs for which the generic definition doesn't say much */
+-#define COLLIE_GPIO_ON_KEY            GPIO_GPIO (0)
+-#define COLLIE_GPIO_AC_IN             GPIO_GPIO (1)
+-#define COLLIE_GPIO_SDIO_INT          GPIO_GPIO (11)
+-#define COLLIE_GPIO_CF_IRQ            GPIO_GPIO (14)
+-#define COLLIE_GPIO_nREMOCON_INT      GPIO_GPIO (15)
+-#define COLLIE_GPIO_UCB1x00_RESET     GPIO_GPIO (16)
+-#define COLLIE_GPIO_nMIC_ON           GPIO_GPIO (17)
+-#define COLLIE_GPIO_nREMOCON_ON               GPIO_GPIO (18)
+-#define COLLIE_GPIO_CO                        GPIO_GPIO (20)
+-#define COLLIE_GPIO_MCP_CLK           GPIO_GPIO (21)
+-#define COLLIE_GPIO_CF_CD             GPIO_GPIO (22)
+-#define COLLIE_GPIO_UCB1x00_IRQ               GPIO_GPIO (23)
+-#define COLLIE_GPIO_WAKEUP            GPIO_GPIO (24)
+-#define COLLIE_GPIO_GA_INT            GPIO_GPIO (25)
+-#define COLLIE_GPIO_MAIN_BAT_LOW      GPIO_GPIO (26)
++#define COLLIE_GPIO_ON_KEY            GPIO_GPIO(0)
++#define COLLIE_GPIO_AC_IN             (1)
++#define COLLIE_GPIO_AC_IN_            GPIO_GPIO(1)
++#define COLLIE_GPIO_SDIO_INT          GPIO_GPIO(11)
++#define COLLIE_GPIO_CF_IRQ            GPIO_GPIO(14)
++#define COLLIE_GPIO_nREMOCON_INT      GPIO_GPIO(15)
++#define COLLIE_GPIO_UCB1x00_RESET     GPIO_GPIO(16)
++#define COLLIE_GPIO_nMIC_ON           GPIO_GPIO(17)
++#define COLLIE_GPIO_nREMOCON_ON               GPIO_GPIO(18)
++#define COLLIE_GPIO_CO                        (20)
++#define COLLIE_GPIO_CO_                       GPIO_GPIO(20)
++#define COLLIE_GPIO_MCP_CLK           GPIO_GPIO(21)
++#define COLLIE_GPIO_CF_CD             GPIO_GPIO(22)
++#define COLLIE_GPIO_UCB1x00_IRQ               GPIO_GPIO(23)
++#define COLLIE_GPIO_WAKEUP            GPIO_GPIO(24)
++#define COLLIE_GPIO_GA_INT            GPIO_GPIO(25)
++#define COLLIE_GPIO_MAIN_BAT_LOW      (26)
+ /* Interrupts */
+@@ -70,19 +71,20 @@
+ #define COLLIE_LCM_IRQ_GPIO_nSD_WP    IRQ_LOCOMO_GPIO14
+ /* GPIO's on the TC35143AF (Toshiba Analog Frontend) */
+-#define COLLIE_TC35143_GPIO_VERSION0    UCB_IO_0      /* GPIO0=Version                 */
+-#define COLLIE_TC35143_GPIO_TBL_CHK     UCB_IO_1      /* GPIO1=TBL_CHK                 */
+-#define COLLIE_TC35143_GPIO_VPEN_ON     UCB_IO_2      /* GPIO2=VPNE_ON                 */
+-#define COLLIE_TC35143_GPIO_IR_ON       UCB_IO_3      /* GPIO3=IR_ON                   */
+-#define COLLIE_TC35143_GPIO_AMP_ON      UCB_IO_4      /* GPIO4=AMP_ON                  */
+-#define COLLIE_TC35143_GPIO_VERSION1    UCB_IO_5      /* GPIO5=Version                 */
+-#define COLLIE_TC35143_GPIO_FS8KLPF     UCB_IO_5      /* GPIO5=fs 8k LPF               */
+-#define COLLIE_TC35143_GPIO_BUZZER_BIAS UCB_IO_6      /* GPIO6=BUZZER BIAS             */
+-#define COLLIE_TC35143_GPIO_MBAT_ON     UCB_IO_7      /* GPIO7=MBAT_ON                 */
+-#define COLLIE_TC35143_GPIO_BBAT_ON     UCB_IO_8      /* GPIO8=BBAT_ON                 */
+-#define COLLIE_TC35143_GPIO_TMP_ON      UCB_IO_9      /* GPIO9=TMP_ON                  */
+-#define COLLIE_TC35143_GPIO_IN                ( UCB_IO_0 | UCB_IO_2 | UCB_IO_5 )
+-#define COLLIE_TC35143_GPIO_OUT               ( UCB_IO_1 | UCB_IO_3 | UCB_IO_4 | UCB_IO_6 | \
+-                                      UCB_IO_7 | UCB_IO_8 | UCB_IO_9 )
++#define COLLIE_TC35143_GPIO_BASE      (GPIO_MAX + 13)
++#define COLLIE_TC35143_GPIO_VERSION0    UCB_IO_0
++#define COLLIE_TC35143_GPIO_TBL_CHK     UCB_IO_1
++#define COLLIE_TC35143_GPIO_VPEN_ON     UCB_IO_2
++#define COLLIE_TC35143_GPIO_IR_ON       UCB_IO_3
++#define COLLIE_TC35143_GPIO_AMP_ON      UCB_IO_4
++#define COLLIE_TC35143_GPIO_VERSION1    UCB_IO_5
++#define COLLIE_TC35143_GPIO_FS8KLPF     UCB_IO_5
++#define COLLIE_TC35143_GPIO_BUZZER_BIAS UCB_IO_6
++#define COLLIE_GPIO_MBAT_ON           (COLLIE_TC35143_GPIO_BASE + 7)
++#define COLLIE_GPIO_BBAT_ON           (COLLIE_TC35143_GPIO_BASE + 8)
++#define COLLIE_GPIO_TMP_ON            (COLLIE_TC35143_GPIO_BASE + 9)
++#define COLLIE_TC35143_GPIO_IN                (UCB_IO_0 | UCB_IO_2 | UCB_IO_5)
++#define COLLIE_TC35143_GPIO_OUT               (UCB_IO_1 | UCB_IO_3 | UCB_IO_4 \
++                                              | UCB_IO_6)
+ #endif
+-- 
+1.5.6.5
+
diff --git a/packages/linux/linux-2.6.28/collie/0018-collie-add-battery-driver.patch b/packages/linux/linux-2.6.28/collie/0018-collie-add-battery-driver.patch
new file mode 100644 (file)
index 0000000..b28db63
--- /dev/null
@@ -0,0 +1,473 @@
+From a2cf77eaf64b201a00b9682c25596ef0bcda8dc4 Mon Sep 17 00:00:00 2001
+From: Thomas Kunze <thommycheck@gmx.de>
+Date: Tue, 10 Feb 2009 18:16:03 +0100
+Subject: [PATCH 18/23] collie: add battery driver
+
+This driver is based on tosa_battery.c.
+
+Conflicts:
+
+       drivers/power/Makefile
+---
+ drivers/power/Kconfig          |    7 +
+ drivers/power/Makefile         |    1 +
+ drivers/power/collie_battery.c |  418 ++++++++++++++++++++++++++++++++++++++++
+ 3 files changed, 426 insertions(+), 0 deletions(-)
+ create mode 100644 drivers/power/collie_battery.c
+
+diff --git a/drivers/power/Kconfig b/drivers/power/Kconfig
+index 8e0c2b4..a945046 100644
+--- a/drivers/power/Kconfig
++++ b/drivers/power/Kconfig
+@@ -56,6 +56,13 @@ config BATTERY_TOSA
+         Say Y to enable support for the battery on the Sharp Zaurus
+         SL-6000 (tosa) models.
++config BATTERY_COLLIE
++      tristate "Sharp SL-5500 (collie) battery"
++      depends on SA1100_COLLIE && MCP_UCB1200
++      help
++        Say Y to enable support for the battery on the Sharp Zaurus
++        SL-5500 (collie) models.
++
+ config BATTERY_WM97XX
+       bool "WM97xx generic battery driver"
+       depends on TOUCHSCREEN_WM97XX=y
+diff --git a/drivers/power/Makefile b/drivers/power/Makefile
+index e8f1ece..51a7263 100644
+--- a/drivers/power/Makefile
++++ b/drivers/power/Makefile
+@@ -21,5 +21,6 @@ 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
++obj-$(CONFIG_BATTERY_COLLIE)  += collie_battery.o
+ obj-$(CONFIG_BATTERY_WM97XX)  += wm97xx_battery.o
+ obj-$(CONFIG_BATTERY_BQ27x00) += bq27x00_battery.o
+diff --git a/drivers/power/collie_battery.c b/drivers/power/collie_battery.c
+new file mode 100644
+index 0000000..039f41a
+--- /dev/null
++++ b/drivers/power/collie_battery.c
+@@ -0,0 +1,418 @@
++/*
++ * Battery and Power Management code for the Sharp SL-5x00
++ *
++ * Copyright (C) 2009 Thomas Kunze
++ *
++ * based on tosa_battery.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/power_supply.h>
++#include <linux/delay.h>
++#include <linux/spinlock.h>
++#include <linux/interrupt.h>
++#include <linux/gpio.h>
++#include <linux/mfd/ucb1x00.h>
++
++#include <asm/mach/sharpsl_param.h>
++#include <asm/mach-types.h>
++#include <mach/collie.h>
++
++static DEFINE_MUTEX(bat_lock); /* protects gpio pins */
++static struct work_struct bat_work;
++static struct ucb1x00 *ucb;
++
++struct collie_bat {
++      int status;
++      struct power_supply psy;
++      int full_chrg;
++
++      struct mutex work_lock; /* protects data */
++
++      bool (*is_present)(struct collie_bat *bat);
++      int gpio_full;
++      int gpio_charge_on;
++
++      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 collie_bat collie_bat_main;
++
++static unsigned long collie_read_bat(struct collie_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);
++      msleep(5);
++      ucb1x00_adc_enable(ucb);
++      value = ucb1x00_adc_read(ucb, bat->adc_bat, UCB_SYNC);
++      ucb1x00_adc_disable(ucb);
++      gpio_set_value(bat->gpio_bat, 0);
++      mutex_unlock(&bat_lock);
++      value = value * 1000000 / bat->adc_bat_divider;
++
++      return value;
++}
++
++static unsigned long collie_read_temp(struct collie_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);
++      msleep(5);
++      ucb1x00_adc_enable(ucb);
++      value = ucb1x00_adc_read(ucb, bat->adc_temp, UCB_SYNC);
++      ucb1x00_adc_disable(ucb);
++      gpio_set_value(bat->gpio_temp, 0);
++      mutex_unlock(&bat_lock);
++
++      value = value * 10000 / bat->adc_temp_divider;
++
++      return value;
++}
++
++static int collie_bat_get_property(struct power_supply *psy,
++                          enum power_supply_property psp,
++                          union power_supply_propval *val)
++{
++      int ret = 0;
++      struct collie_bat *bat = container_of(psy, struct collie_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 = bat->technology;
++              break;
++      case POWER_SUPPLY_PROP_VOLTAGE_NOW:
++              val->intval = collie_read_bat(bat);
++              break;
++      case POWER_SUPPLY_PROP_VOLTAGE_MAX:
++              if (bat->full_chrg == -1)
++                      val->intval = bat->bat_max;
++              else
++                      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->bat_min;
++              break;
++      case POWER_SUPPLY_PROP_TEMP:
++              val->intval = collie_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 void collie_bat_external_power_changed(struct power_supply *psy)
++{
++      schedule_work(&bat_work);
++}
++
++static irqreturn_t collie_bat_gpio_isr(int irq, void *data)
++{
++      pr_info("collie_bat_gpio irq: %d\n", gpio_get_value(irq_to_gpio(irq)));
++      schedule_work(&bat_work);
++      return IRQ_HANDLED;
++}
++
++static void collie_bat_update(struct collie_bat *bat)
++{
++      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_NOTICE "%s not present\n", psy->name);
++              bat->status = POWER_SUPPLY_STATUS_UNKNOWN;
++              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_on, 1);
++                      mdelay(15);
++              }
++
++              if (gpio_get_value(bat->gpio_full)) {
++                      if (old == POWER_SUPPLY_STATUS_CHARGING ||
++                                      bat->full_chrg == -1)
++                              bat->full_chrg = collie_read_bat(bat);
++
++                      gpio_set_value(bat->gpio_charge_on, 0);
++                      bat->status = POWER_SUPPLY_STATUS_FULL;
++              } else {
++                      gpio_set_value(bat->gpio_charge_on, 1);
++                      bat->status = POWER_SUPPLY_STATUS_CHARGING;
++              }
++      } else {
++              gpio_set_value(bat->gpio_charge_on, 0);
++              bat->status = POWER_SUPPLY_STATUS_DISCHARGING;
++      }
++
++      if (old != bat->status)
++              power_supply_changed(psy);
++
++      mutex_unlock(&bat->work_lock);
++}
++
++static void collie_bat_work(struct work_struct *work)
++{
++      collie_bat_update(&collie_bat_main);
++}
++
++
++static enum power_supply_property collie_bat_main_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_VOLTAGE_MAX,
++      POWER_SUPPLY_PROP_PRESENT,
++      POWER_SUPPLY_PROP_TEMP,
++};
++
++static enum power_supply_property collie_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_VOLTAGE_MAX,
++      POWER_SUPPLY_PROP_PRESENT,
++};
++
++static struct collie_bat collie_bat_main = {
++      .status = POWER_SUPPLY_STATUS_DISCHARGING,
++      .full_chrg = -1,
++      .psy = {
++              .name           = "main-battery",
++              .type           = POWER_SUPPLY_TYPE_BATTERY,
++              .properties     = collie_bat_main_props,
++              .num_properties = ARRAY_SIZE(collie_bat_main_props),
++              .get_property   = collie_bat_get_property,
++              .external_power_changed = collie_bat_external_power_changed,
++              .use_for_apm    = 1,
++      },
++
++      .gpio_full = COLLIE_GPIO_CO,
++      .gpio_charge_on = COLLIE_GPIO_CHARGE_ON,
++
++      .technology = POWER_SUPPLY_TECHNOLOGY_LIPO,
++
++      .gpio_bat = COLLIE_GPIO_MBAT_ON,
++      .adc_bat = UCB_ADC_INP_AD1,
++      .adc_bat_divider = 155,
++      .bat_max = 4310000,
++      .bat_min = 1551 * 1000000 / 414,
++
++      .gpio_temp = COLLIE_GPIO_TMP_ON,
++      .adc_temp = UCB_ADC_INP_AD0,
++      .adc_temp_divider = 10000,
++};
++
++static struct collie_bat collie_bat_bu = {
++      .status = POWER_SUPPLY_STATUS_UNKNOWN,
++      .full_chrg = -1,
++
++      .psy = {
++              .name           = "backup-battery",
++              .type           = POWER_SUPPLY_TYPE_BATTERY,
++              .properties     = collie_bat_bu_props,
++              .num_properties = ARRAY_SIZE(collie_bat_bu_props),
++              .get_property   = collie_bat_get_property,
++              .external_power_changed = collie_bat_external_power_changed,
++      },
++
++      .gpio_full = -1,
++      .gpio_charge_on = -1,
++
++      .technology = POWER_SUPPLY_TECHNOLOGY_LiMn,
++
++      .gpio_bat = COLLIE_GPIO_BBAT_ON,
++      .adc_bat = UCB_ADC_INP_AD1,
++      .adc_bat_divider = 155,
++      .bat_max = 3000000,
++      .bat_min = 1900000,
++
++      .gpio_temp = -1,
++      .adc_temp = -1,
++      .adc_temp_divider = -1,
++};
++
++static struct {
++      int gpio;
++      char *name;
++      bool output;
++      int value;
++} gpios[] = {
++      { COLLIE_GPIO_CO,               "main battery full",    0, 0 },
++      { COLLIE_GPIO_MAIN_BAT_LOW,     "main battery low",     0, 0 },
++      { COLLIE_GPIO_CHARGE_ON,        "main charge on",       1, 0 },
++      { COLLIE_GPIO_MBAT_ON,          "main battery",         1, 0 },
++      { COLLIE_GPIO_TMP_ON,           "main battery temp",    1, 0 },
++      { COLLIE_GPIO_BBAT_ON,          "backup battery",       1, 0 },
++};
++
++#ifdef CONFIG_PM
++static int collie_bat_suspend(struct ucb1x00_dev *dev, pm_message_t state)
++{
++      /* flush all pending status updates */
++      flush_scheduled_work();
++      return 0;
++}
++
++static int collie_bat_resume(struct ucb1x00_dev *dev)
++{
++      /* things may have changed while we were away */
++      schedule_work(&bat_work);
++      return 0;
++}
++#else
++#define collie_bat_suspend NULL
++#define collie_bat_resume NULL
++#endif
++
++static int __devinit collie_bat_probe(struct ucb1x00_dev *dev)
++{
++      int ret;
++      int i;
++
++      if (!machine_is_collie())
++              return -ENODEV;
++
++      ucb = dev->ucb;
++
++      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(&collie_bat_main.work_lock);
++
++      INIT_WORK(&bat_work, collie_bat_work);
++
++      ret = power_supply_register(&dev->ucb->dev, &collie_bat_main.psy);
++      if (ret)
++              goto err_psy_reg_main;
++      ret = power_supply_register(&dev->ucb->dev, &collie_bat_bu.psy);
++      if (ret)
++              goto err_psy_reg_bu;
++
++      ret = request_irq(gpio_to_irq(COLLIE_GPIO_CO),
++                              collie_bat_gpio_isr,
++                              IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
++                              "main full", &collie_bat_main);
++      if (!ret) {
++              schedule_work(&bat_work);
++              return 0;
++      }
++      power_supply_unregister(&collie_bat_bu.psy);
++err_psy_reg_bu:
++      power_supply_unregister(&collie_bat_main.psy);
++err_psy_reg_main:
++
++      /* see comment in collie_bat_remove */
++      flush_scheduled_work();
++
++      i--;
++err_gpio:
++      for (; i >= 0; i--)
++              gpio_free(gpios[i].gpio);
++
++      return ret;
++}
++
++static void __devexit collie_bat_remove(struct ucb1x00_dev *dev)
++{
++      int i;
++
++      free_irq(gpio_to_irq(COLLIE_GPIO_CO), &collie_bat_main);
++
++      power_supply_unregister(&collie_bat_bu.psy);
++      power_supply_unregister(&collie_bat_main.psy);
++
++      /*
++       * now flush all pending work.
++       * we won't get any more schedules, since all
++       * sources (isr and external_power_changed)
++       * are unregistered now.
++       */
++      flush_scheduled_work();
++
++      for (i = ARRAY_SIZE(gpios) - 1; i >= 0; i--)
++              gpio_free(gpios[i].gpio);
++}
++
++static struct ucb1x00_driver collie_bat_driver = {
++      .add            = collie_bat_probe,
++      .remove         = __devexit_p(collie_bat_remove),
++      .suspend        = collie_bat_suspend,
++      .resume         = collie_bat_resume,
++};
++
++static int __init collie_bat_init(void)
++{
++      return ucb1x00_register_driver(&collie_bat_driver);
++}
++
++static void __exit collie_bat_exit(void)
++{
++      ucb1x00_unregister_driver(&collie_bat_driver);
++}
++
++module_init(collie_bat_init);
++module_exit(collie_bat_exit);
++
++MODULE_LICENSE("GPL");
++MODULE_AUTHOR("Thomas Kunze");
++MODULE_DESCRIPTION("Collie battery driver");
+-- 
+1.5.6.5
+
diff --git a/packages/linux/linux-2.6.28/collie/0019-collie-support-pda_power-driver.patch b/packages/linux/linux-2.6.28/collie/0019-collie-support-pda_power-driver.patch
new file mode 100644 (file)
index 0000000..7d74cb7
--- /dev/null
@@ -0,0 +1,103 @@
+From c1a769bcd789ef7284ee4ece4324274278ee6401 Mon Sep 17 00:00:00 2001
+From: Thomas Kunze <thommycheck@gmx.de>
+Date: Tue, 10 Feb 2009 13:48:32 +0100
+Subject: [PATCH 19/23] collie: support pda_power driver
+
+This add the pda-power platform device to collie.
+---
+ arch/arm/mach-sa1100/collie.c |   65 +++++++++++++++++++++++++++++++++++++++++
+ 1 files changed, 65 insertions(+), 0 deletions(-)
+
+diff --git a/arch/arm/mach-sa1100/collie.c b/arch/arm/mach-sa1100/collie.c
+index 4b52f30..7da2f28 100644
+--- a/arch/arm/mach-sa1100/collie.c
++++ b/arch/arm/mach-sa1100/collie.c
+@@ -26,6 +26,7 @@
+ #include <linux/mtd/partitions.h>
+ #include <linux/timer.h>
+ #include <linux/gpio.h>
++#include <linux/pda_power.h>
+ #include <mach/hardware.h>
+ #include <asm/mach-types.h>
+@@ -90,6 +91,69 @@ static struct mcp_plat_data collie_mcp_data = {
+       .gpio_base      = COLLIE_TC35143_GPIO_BASE,
+ };
++/*
++ * Collie AC IN
++ */
++static int collie_power_init(struct device *dev)
++{
++      int ret = gpio_request(COLLIE_GPIO_AC_IN, "ac in");
++      if (ret)
++              goto err_gpio_req;
++
++      ret = gpio_direction_input(COLLIE_GPIO_AC_IN);
++      if (ret)
++              goto err_gpio_in;
++
++      return 0;
++
++err_gpio_in:
++      gpio_free(COLLIE_GPIO_AC_IN);
++err_gpio_req:
++      return ret;
++}
++
++static void collie_power_exit(struct device *dev)
++{
++      gpio_free(COLLIE_GPIO_AC_IN);
++}
++
++static int collie_power_ac_online(void)
++{
++      return gpio_get_value(COLLIE_GPIO_AC_IN) == 2;
++}
++
++static char *collie_ac_supplied_to[] = {
++      "main-battery",
++      "backup-battery",
++};
++
++static struct pda_power_pdata collie_power_data = {
++      .init                   = collie_power_init,
++      .is_ac_online           = collie_power_ac_online,
++      .exit                   = collie_power_exit,
++      .supplied_to            = collie_ac_supplied_to,
++      .num_supplicants        = ARRAY_SIZE(collie_ac_supplied_to),
++};
++
++static struct resource collie_power_resource[] = {
++      {
++              .name           = "ac",
++              .start          = gpio_to_irq(COLLIE_GPIO_AC_IN),
++              .end            = gpio_to_irq(COLLIE_GPIO_AC_IN),
++              .flags          = IORESOURCE_IRQ |
++                                IORESOURCE_IRQ_HIGHEDGE |
++                                IORESOURCE_IRQ_LOWEDGE,
++      },
++};
++
++static struct platform_device collie_power_device = {
++      .name                   = "pda-power",
++      .id                     = -1,
++      .dev.platform_data      = &collie_power_data,
++      .resource               = collie_power_resource,
++      .num_resources          = ARRAY_SIZE(collie_power_resource),
++};
++
+ #ifdef CONFIG_SHARP_LOCOMO
+ /*
+  * low-level UART features.
+@@ -180,6 +244,7 @@ struct platform_device collie_locomo_device = {
+ static struct platform_device *devices[] __initdata = {
+       &collie_locomo_device,
+       &colliescoop_device,
++      &collie_power_device,
+ };
+ static struct mtd_partition collie_partitions[] = {
+-- 
+1.5.6.5
+
diff --git a/packages/linux/linux-2.6.28/collie/0020-remove-collie_pm.c.patch b/packages/linux/linux-2.6.28/collie/0020-remove-collie_pm.c.patch
new file mode 100644 (file)
index 0000000..490e333
--- /dev/null
@@ -0,0 +1,323 @@
+From 702663223fdc1e3f73e9adbcb1415713b2c92652 Mon Sep 17 00:00:00 2001
+From: Thomas Kunze <thommycheck@gmx.de>
+Date: Tue, 10 Feb 2009 18:16:57 +0100
+Subject: [PATCH 20/23] remove collie_pm.c
+
+This file was unused. The new battery driver makes it
+obsolete. So remove it
+
+Conflicts:
+
+       arch/arm/mach-sa1100/collie_pm.c
+---
+ arch/arm/mach-sa1100/collie_pm.c |  298 --------------------------------------
+ 1 files changed, 0 insertions(+), 298 deletions(-)
+ delete mode 100644 arch/arm/mach-sa1100/collie_pm.c
+
+diff --git a/arch/arm/mach-sa1100/collie_pm.c b/arch/arm/mach-sa1100/collie_pm.c
+deleted file mode 100644
+index 65b8b31..0000000
+--- a/arch/arm/mach-sa1100/collie_pm.c
++++ /dev/null
+@@ -1,298 +0,0 @@
+-/*
+- * Based on spitz_pm.c and sharp code.
+- *
+- * Copyright (C) 2001  SHARP
+- * Copyright 2005 Pavel Machek <pavel@suse.cz>
+- *
+- * Distribute under GPLv2.
+- *
+- * Li-ion batteries are angry beasts, and they like to explode. This driver is not finished,
+- * and sometimes charges them when it should not. If it makes angry lithium to come your way...
+- * ...well, you have been warned.
+- *
+- * Actually, this should be quite safe, it seems sharp leaves charger enabled by default,
+- * and my collie did not explode (yet).
+- */
+-
+-#include <linux/module.h>
+-#include <linux/stat.h>
+-#include <linux/init.h>
+-#include <linux/kernel.h>
+-#include <linux/delay.h>
+-#include <linux/interrupt.h>
+-#include <linux/device.h>
+-#include <linux/platform_device.h>
+-#include <linux/mfd/ucb1x00.h>
+-
+-#include <asm/irq.h>
+-#include <mach/hardware.h>
+-#include <asm/hardware/scoop.h>
+-#include <asm/dma.h>
+-#include <mach/collie.h>
+-#include <asm/mach/sharpsl_param.h>
+-#include <asm/hardware/sharpsl_pm.h>
+-
+-
+-static struct ucb1x00 *ucb;
+-static int ad_revise;
+-
+-#define ADCtoPower(x)        ((330 * x * 2) / 1024)
+-
+-static void collie_charger_init(void)
+-{
+-      int err;
+-
+-      if (sharpsl_param.adadj != -1)
+-              ad_revise = sharpsl_param.adadj;
+-
+-      /* Register interrupt handler. */
+-      if ((err = request_irq(COLLIE_IRQ_GPIO_AC_IN, sharpsl_ac_isr, IRQF_DISABLED,
+-                             "ACIN", sharpsl_ac_isr))) {
+-              printk("Could not get irq %d.\n", COLLIE_IRQ_GPIO_AC_IN);
+-              return;
+-      }
+-      if ((err = request_irq(COLLIE_IRQ_GPIO_CO, sharpsl_chrg_full_isr, IRQF_DISABLED,
+-                             "CO", sharpsl_chrg_full_isr))) {
+-              free_irq(COLLIE_IRQ_GPIO_AC_IN, sharpsl_ac_isr);
+-              printk("Could not get irq %d.\n", COLLIE_IRQ_GPIO_CO);
+-              return;
+-      }
+-
+-      ucb1x00_io_set_dir(ucb, 0, COLLIE_TC35143_GPIO_MBAT_ON | COLLIE_TC35143_GPIO_TMP_ON |
+-                                 COLLIE_TC35143_GPIO_BBAT_ON);
+-      return;
+-}
+-
+-static void collie_measure_temp(int on)
+-{
+-      if (on)
+-              ucb1x00_io_write(ucb, COLLIE_TC35143_GPIO_TMP_ON, 0);
+-      else
+-              ucb1x00_io_write(ucb, 0, COLLIE_TC35143_GPIO_TMP_ON);
+-}
+-
+-static void collie_charge(int on)
+-{
+-      extern struct platform_device colliescoop_device;
+-
+-      /* Zaurus seems to contain LTC1731; it should know when to
+-       * stop charging itself, so setting charge on should be
+-       * relatively harmless (as long as it is not done too often).
+-       */
+-      if (on) {
+-              set_scoop_gpio(&colliescoop_device.dev, COLLIE_SCP_CHARGE_ON);
+-      } else {
+-              reset_scoop_gpio(&colliescoop_device.dev, COLLIE_SCP_CHARGE_ON);
+-      }
+-}
+-
+-static void collie_discharge(int on)
+-{
+-}
+-
+-static void collie_discharge1(int on)
+-{
+-}
+-
+-static void collie_presuspend(void)
+-{
+-}
+-
+-static void collie_postsuspend(void)
+-{
+-}
+-
+-static int collie_should_wakeup(unsigned int resume_on_alarm)
+-{
+-      return 0;
+-}
+-
+-static unsigned long collie_charger_wakeup(void)
+-{
+-      return 0;
+-}
+-
+-int collie_read_backup_battery(void)
+-{
+-      int voltage;
+-
+-      ucb1x00_adc_enable(ucb);
+-
+-      ucb1x00_io_write(ucb, COLLIE_TC35143_GPIO_BBAT_ON, 0);
+-      voltage = ucb1x00_adc_read(ucb, UCB_ADC_INP_AD1, UCB_SYNC);
+-
+-      ucb1x00_io_write(ucb, 0, COLLIE_TC35143_GPIO_BBAT_ON);
+-      ucb1x00_adc_disable(ucb);
+-
+-      printk("Backup battery = %d(%d)\n", ADCtoPower(voltage), voltage);
+-
+-      return ADCtoPower(voltage);
+-}
+-
+-int collie_read_main_battery(void)
+-{
+-      int voltage, voltage_rev, voltage_volts;
+-
+-      ucb1x00_adc_enable(ucb);
+-      ucb1x00_io_write(ucb, 0, COLLIE_TC35143_GPIO_BBAT_ON);
+-      ucb1x00_io_write(ucb, COLLIE_TC35143_GPIO_MBAT_ON, 0);
+-
+-      mdelay(1);
+-      voltage = ucb1x00_adc_read(ucb, UCB_ADC_INP_AD1, UCB_SYNC);
+-
+-      ucb1x00_io_write(ucb, 0, COLLIE_TC35143_GPIO_MBAT_ON);
+-      ucb1x00_adc_disable(ucb);
+-
+-      voltage_rev = voltage + ((ad_revise * voltage) / 652);
+-      voltage_volts = ADCtoPower(voltage_rev);
+-
+-      printk("Main battery = %d(%d)\n", voltage_volts, voltage);
+-
+-      if (voltage != -1)
+-              return voltage_volts;
+-      else
+-              return voltage;
+-}
+-
+-int collie_read_temp(void)
+-{
+-      int voltage;
+-
+-      /* According to Sharp, temp must be > 973, main battery must be < 465,
+-         FIXME: sharpsl_pm.c has both conditions negated? FIXME: values
+-         are way out of range? */
+-
+-      ucb1x00_adc_enable(ucb);
+-      ucb1x00_io_write(ucb, COLLIE_TC35143_GPIO_TMP_ON, 0);
+-      /* >1010 = battery removed, 460 = 22C ?, higher = lower temp ? */
+-      voltage = ucb1x00_adc_read(ucb, UCB_ADC_INP_AD0, UCB_SYNC);
+-      ucb1x00_io_write(ucb, 0, COLLIE_TC35143_GPIO_TMP_ON);
+-      ucb1x00_adc_disable(ucb);
+-
+-      printk("Battery temp = %d\n", voltage);
+-      return voltage;
+-}
+-
+-static unsigned long read_devdata(int which)
+-{
+-      switch (which) {
+-      case SHARPSL_BATT_VOLT:
+-              return collie_read_main_battery();
+-      case SHARPSL_BATT_TEMP:
+-              return collie_read_temp();
+-      case SHARPSL_ACIN_VOLT:
+-              return 500;
+-      case SHARPSL_STATUS_ACIN: {
+-              int ret = GPLR & COLLIE_GPIO_AC_IN;
+-              printk("AC status = %d\n", ret);
+-              return ret;
+-      }
+-      case SHARPSL_STATUS_FATAL: {
+-              int ret = GPLR & COLLIE_GPIO_MAIN_BAT_LOW;
+-              printk("Fatal bat = %d\n", ret);
+-              return ret;
+-      }
+-      default:
+-              return ~0;
+-      }
+-}
+-
+-struct battery_thresh collie_battery_levels_acin[] = {
+-      { 420, 100},
+-      { 417,  95},
+-      { 415,  90},
+-      { 413,  80},
+-      { 411,  75},
+-      { 408,  70},
+-      { 406,  60},
+-      { 403,  50},
+-      { 398,  40},
+-      { 391,  25},
+-      {  10,   5},
+-      {   0,   0},
+-};
+-
+-struct battery_thresh collie_battery_levels[] = {
+-      { 394, 100},
+-      { 390,  95},
+-      { 380,  90},
+-      { 370,  80},
+-      { 368,  75},    /* From sharp code: battery high with frontlight */
+-      { 366,  70},    /* 60..90 -- fake values invented by me for testing */
+-      { 364,  60},
+-      { 362,  50},
+-      { 360,  40},
+-      { 358,  25},    /* From sharp code: battery low with frontlight */
+-      { 356,   5},    /* From sharp code: battery verylow with frontlight */
+-      {   0,   0},
+-};
+-
+-struct sharpsl_charger_machinfo collie_pm_machinfo = {
+-      .init             = collie_charger_init,
+-      .read_devdata     = read_devdata,
+-      .discharge        = collie_discharge,
+-      .discharge1       = collie_discharge1,
+-      .charge           = collie_charge,
+-      .measure_temp     = collie_measure_temp,
+-      .presuspend       = collie_presuspend,
+-      .postsuspend      = collie_postsuspend,
+-      .charger_wakeup   = collie_charger_wakeup,
+-      .should_wakeup    = collie_should_wakeup,
+-      .bat_levels       = 12,
+-      .bat_levels_noac  = collie_battery_levels,
+-      .bat_levels_acin  = collie_battery_levels_acin,
+-      .status_high_acin = 368,
+-      .status_low_acin  = 358,
+-      .status_high_noac = 368,
+-      .status_low_noac  = 358,
+-      .charge_on_volt   = 350,        /* spitz uses 2.90V, but lets play it safe. */
+-      .charge_on_temp   = 550,
+-      .charge_acin_high = 550,        /* collie does not seem to have sensor for this, anyway */
+-      .charge_acin_low  = 450,        /* ignored, too */
+-      .fatal_acin_volt  = 356,
+-      .fatal_noacin_volt = 356,
+-
+-      .batfull_irq = 1,               /* We do not want periodical charge restarts */
+-};
+-
+-static int __init collie_pm_ucb_add(struct ucb1x00_dev *pdev)
+-{
+-      sharpsl_pm.machinfo = &collie_pm_machinfo;
+-      ucb = pdev->ucb;
+-      return 0;
+-}
+-
+-static struct ucb1x00_driver collie_pm_ucb_driver = {
+-      .add            = collie_pm_ucb_add,
+-};
+-
+-static struct platform_device *collie_pm_device;
+-
+-static int __init collie_pm_init(void)
+-{
+-        int ret;
+-
+-        collie_pm_device = platform_device_alloc("sharpsl-pm", -1);
+-        if (!collie_pm_device)
+-                return -ENOMEM;
+-
+-        collie_pm_device->dev.platform_data = &collie_pm_machinfo;
+-        ret = platform_device_add(collie_pm_device);
+-
+-        if (ret)
+-                platform_device_put(collie_pm_device);
+-
+-      if (!ret)
+-              ret = ucb1x00_register_driver(&collie_pm_ucb_driver);
+-
+-      return ret;
+-}
+-
+-static void __exit collie_pm_exit(void)
+-{
+-      ucb1x00_unregister_driver(&collie_pm_ucb_driver);
+-        platform_device_unregister(collie_pm_device);
+-}
+-
+-module_init(collie_pm_init);
+-module_exit(collie_pm_exit);
+-- 
+1.5.6.5
+
diff --git a/packages/linux/linux-2.6.28/collie/0021-mmc-trivial-annotation-of-blocks.patch b/packages/linux/linux-2.6.28/collie/0021-mmc-trivial-annotation-of-blocks.patch
new file mode 100644 (file)
index 0000000..c40be53
--- /dev/null
@@ -0,0 +1,40 @@
+From 0057c3469772d6cddcaa486abe46a2957bc62a2c Mon Sep 17 00:00:00 2001
+From: Harvey Harrison <harvey.harrison@gmail.com>
+Date: Wed, 22 Oct 2008 17:09:00 -0700
+Subject: [PATCH 21/23] mmc: trivial annotation of 'blocks'
+
+sg_init_one is reading a be32, annotate as such.
+
+Signed-off-by: Harvey Harrison <harvey.harrison@gmail.com>
+Signed-off-by: Pierre Ossman <drzeus@drzeus.cx>
+---
+ drivers/mmc/card/block.c |    6 ++----
+ 1 files changed, 2 insertions(+), 4 deletions(-)
+
+diff --git a/drivers/mmc/card/block.c b/drivers/mmc/card/block.c
+index 3d067c3..903c8aa 100644
+--- a/drivers/mmc/card/block.c
++++ b/drivers/mmc/card/block.c
+@@ -145,7 +145,7 @@ struct mmc_blk_request {
+ static u32 mmc_sd_num_wr_blocks(struct mmc_card *card)
+ {
+       int err;
+-      u32 blocks;
++      __be32 blocks;
+       struct mmc_request mrq;
+       struct mmc_command cmd;
+@@ -204,9 +204,7 @@ static u32 mmc_sd_num_wr_blocks(struct mmc_card *card)
+       if (cmd.error || data.error)
+               return (u32)-1;
+-      blocks = ntohl(blocks);
+-
+-      return blocks;
++      return ntohl(blocks);
+ }
+ static int mmc_blk_issue_rq(struct mmc_queue *mq, struct request *req)
+-- 
+1.5.6.5
+
diff --git a/packages/linux/linux-2.6.28/collie/0022-mmc_block-print-better-error-messages.patch b/packages/linux/linux-2.6.28/collie/0022-mmc_block-print-better-error-messages.patch
new file mode 100644 (file)
index 0000000..b6cef07
--- /dev/null
@@ -0,0 +1,93 @@
+From d71af40a7a15a2ee7040fa0d5c8ac1bc19873c7d Mon Sep 17 00:00:00 2001
+From: Adrian Hunter <ext-adrian.hunter@nokia.com>
+Date: Thu, 16 Oct 2008 12:55:25 +0300
+Subject: [PATCH 22/23] mmc_block: print better error messages
+
+Add command response and card status to error
+messages.
+
+Signed-off-by: Adrian Hunter <ext-adrian.hunter@nokia.com>
+Signed-off-by: Pierre Ossman <drzeus@drzeus.cx>
+---
+ drivers/mmc/card/block.c |   44 +++++++++++++++++++++++++++++++++++++-------
+ 1 files changed, 37 insertions(+), 7 deletions(-)
+
+diff --git a/drivers/mmc/card/block.c b/drivers/mmc/card/block.c
+index 903c8aa..cc9b3ab 100644
+--- a/drivers/mmc/card/block.c
++++ b/drivers/mmc/card/block.c
+@@ -207,6 +207,23 @@ static u32 mmc_sd_num_wr_blocks(struct mmc_card *card)
+       return ntohl(blocks);
+ }
++static u32 get_card_status(struct mmc_card *card, struct request *req)
++{
++      struct mmc_command cmd;
++      int err;
++
++      memset(&cmd, 0, sizeof(struct mmc_command));
++      cmd.opcode = MMC_SEND_STATUS;
++      if (!mmc_host_is_spi(card->host))
++              cmd.arg = card->rca << 16;
++      cmd.flags = MMC_RSP_SPI_R2 | MMC_RSP_R1 | MMC_CMD_AC;
++      err = mmc_wait_for_cmd(card->host, &cmd, 0);
++      if (err)
++              printk(KERN_ERR "%s: error %d sending status comand",
++                     req->rq_disk->disk_name, err);
++      return cmd.resp[0];
++}
++
+ static int mmc_blk_issue_rq(struct mmc_queue *mq, struct request *req)
+ {
+       struct mmc_blk_data *md = mq->data;
+@@ -218,7 +235,7 @@ static int mmc_blk_issue_rq(struct mmc_queue *mq, struct request *req)
+       do {
+               struct mmc_command cmd;
+-              u32 readcmd, writecmd;
++              u32 readcmd, writecmd, status = 0;
+               memset(&brq, 0, sizeof(struct mmc_blk_request));
+               brq.mrq.cmd = &brq.cmd;
+@@ -273,19 +290,32 @@ static int mmc_blk_issue_rq(struct mmc_queue *mq, struct request *req)
+                * until later as we need to wait for the card to leave
+                * programming mode even when things go wrong.
+                */
++              if (brq.cmd.error || brq.data.error || brq.stop.error)
++                      status = get_card_status(card, req);
++
+               if (brq.cmd.error) {
+-                      printk(KERN_ERR "%s: error %d sending read/write command\n",
+-                             req->rq_disk->disk_name, brq.cmd.error);
++                      printk(KERN_ERR "%s: error %d sending read/write "
++                             "command, response %#x, card status %#x\n",
++                             req->rq_disk->disk_name, brq.cmd.error,
++                             brq.cmd.resp[0], status);
+               }
+               if (brq.data.error) {
+-                      printk(KERN_ERR "%s: error %d transferring data\n",
+-                             req->rq_disk->disk_name, brq.data.error);
++                      if (brq.data.error == -ETIMEDOUT && brq.mrq.stop)
++                              /* 'Stop' response contains card status */
++                              status = brq.mrq.stop->resp[0];
++                      printk(KERN_ERR "%s: error %d transferring data,"
++                             " sector %u, nr %u, card status %#x\n",
++                             req->rq_disk->disk_name, brq.data.error,
++                             (unsigned)req->sector,
++                             (unsigned)req->nr_sectors, status);
+               }
+               if (brq.stop.error) {
+-                      printk(KERN_ERR "%s: error %d sending stop command\n",
+-                             req->rq_disk->disk_name, brq.stop.error);
++                      printk(KERN_ERR "%s: error %d sending stop command, "
++                             "response %#x, card status %#x\n",
++                             req->rq_disk->disk_name, brq.stop.error,
++                             brq.stop.resp[0], status);
+               }
+               if (!mmc_host_is_spi(card->host) && rq_data_dir(req) != READ) {
+-- 
+1.5.6.5
+
diff --git a/packages/linux/linux-2.6.28/collie/0023-mmc_block-ensure-all-sectors-that-do-not-have-error.patch b/packages/linux/linux-2.6.28/collie/0023-mmc_block-ensure-all-sectors-that-do-not-have-error.patch
new file mode 100644 (file)
index 0000000..3ff32b0
--- /dev/null
@@ -0,0 +1,148 @@
+From fba35a4bb8f9cabcd374e19a2a34ee5496d971d2 Mon Sep 17 00:00:00 2001
+From: Adrian Hunter <ext-adrian.hunter@nokia.com>
+Date: Wed, 31 Dec 2008 18:21:17 +0100
+Subject: [PATCH 23/23] mmc_block: ensure all sectors that do not have errors are read
+
+If a card encounters an ECC error while reading a sector it will
+timeout.  Instead of reporting the entire I/O request as having
+an error, redo the I/O one sector at a time so that all readable
+sectors are provided to the upper layers.
+
+Signed-off-by: Adrian Hunter <ext-adrian.hunter@nokia.com>
+Signed-off-by: Pierre Ossman <drzeus@drzeus.cx>
+---
+ drivers/mmc/card/block.c |   76 +++++++++++++++++++++++++++++++++++----------
+ 1 files changed, 59 insertions(+), 17 deletions(-)
+
+diff --git a/drivers/mmc/card/block.c b/drivers/mmc/card/block.c
+index cc9b3ab..45b1f43 100644
+--- a/drivers/mmc/card/block.c
++++ b/drivers/mmc/card/block.c
+@@ -229,7 +229,7 @@ static int mmc_blk_issue_rq(struct mmc_queue *mq, struct request *req)
+       struct mmc_blk_data *md = mq->data;
+       struct mmc_card *card = md->queue.card;
+       struct mmc_blk_request brq;
+-      int ret = 1;
++      int ret = 1, disable_multi = 0;
+       mmc_claim_host(card->host);
+@@ -251,6 +251,14 @@ static int mmc_blk_issue_rq(struct mmc_queue *mq, struct request *req)
+               brq.stop.flags = MMC_RSP_SPI_R1B | MMC_RSP_R1B | MMC_CMD_AC;
+               brq.data.blocks = req->nr_sectors;
++              /*
++               * After a read error, we redo the request one sector at a time
++               * in order to accurately determine which sectors can be read
++               * successfully.
++               */
++              if (disable_multi && brq.data.blocks > 1)
++                      brq.data.blocks = 1;
++
+               if (brq.data.blocks > 1) {
+                       /* SPI multiblock writes terminate using a special
+                        * token, not a STOP_TRANSMISSION request.
+@@ -279,6 +287,25 @@ static int mmc_blk_issue_rq(struct mmc_queue *mq, struct request *req)
+               brq.data.sg = mq->sg;
+               brq.data.sg_len = mmc_queue_map_sg(mq);
++              /*
++               * Adjust the sg list so it is the same size as the
++               * request.
++               */
++              if (brq.data.blocks != req->nr_sectors) {
++                      int i, data_size = brq.data.blocks << 9;
++                      struct scatterlist *sg;
++
++                      for_each_sg(brq.data.sg, sg, brq.data.sg_len, i) {
++                              data_size -= sg->length;
++                              if (data_size <= 0) {
++                                      sg->length += data_size;
++                                      i++;
++                                      break;
++                              }
++                      }
++                      brq.data.sg_len = i;
++              }
++
+               mmc_queue_bounce_pre(mq);
+               mmc_wait_for_req(card->host, &brq.mrq);
+@@ -290,8 +317,16 @@ static int mmc_blk_issue_rq(struct mmc_queue *mq, struct request *req)
+                * until later as we need to wait for the card to leave
+                * programming mode even when things go wrong.
+                */
+-              if (brq.cmd.error || brq.data.error || brq.stop.error)
++              if (brq.cmd.error || brq.data.error || brq.stop.error) {
++                      if (brq.data.blocks > 1 && rq_data_dir(req) == READ) {
++                              /* Redo read one sector at a time */
++                              printk(KERN_WARNING "%s: retrying using single "
++                                     "block read\n", req->rq_disk->disk_name);
++                              disable_multi = 1;
++                              continue;
++                      }
+                       status = get_card_status(card, req);
++              }
+               if (brq.cmd.error) {
+                       printk(KERN_ERR "%s: error %d sending read/write "
+@@ -348,8 +383,20 @@ static int mmc_blk_issue_rq(struct mmc_queue *mq, struct request *req)
+ #endif
+               }
+-              if (brq.cmd.error || brq.data.error || brq.stop.error)
++              if (brq.cmd.error || brq.stop.error || brq.data.error) {
++                      if (rq_data_dir(req) == READ) {
++                              /*
++                               * After an error, we redo I/O one sector at a
++                               * time, so we only reach here after trying to
++                               * read a single sector.
++                               */
++                              spin_lock_irq(&md->lock);
++                              ret = __blk_end_request(req, -EIO, brq.data.blksz);
++                              spin_unlock_irq(&md->lock);
++                              continue;
++                      }
+                       goto cmd_err;
++              }
+               /*
+                * A block was successfully transferred.
+@@ -371,25 +418,20 @@ static int mmc_blk_issue_rq(struct mmc_queue *mq, struct request *req)
+        * If the card is not SD, we can still ok written sectors
+        * as reported by the controller (which might be less than
+        * the real number of written sectors, but never more).
+-       *
+-       * For reads we just fail the entire chunk as that should
+-       * be safe in all cases.
+        */
+-      if (rq_data_dir(req) != READ) {
+-              if (mmc_card_sd(card)) {
+-                      u32 blocks;
++      if (mmc_card_sd(card)) {
++              u32 blocks;
+-                      blocks = mmc_sd_num_wr_blocks(card);
+-                      if (blocks != (u32)-1) {
+-                              spin_lock_irq(&md->lock);
+-                              ret = __blk_end_request(req, 0, blocks << 9);
+-                              spin_unlock_irq(&md->lock);
+-                      }
+-              } else {
++              blocks = mmc_sd_num_wr_blocks(card);
++              if (blocks != (u32)-1) {
+                       spin_lock_irq(&md->lock);
+-                      ret = __blk_end_request(req, 0, brq.data.bytes_xfered);
++                      ret = __blk_end_request(req, 0, blocks << 9);
+                       spin_unlock_irq(&md->lock);
+               }
++      } else {
++              spin_lock_irq(&md->lock);
++              ret = __blk_end_request(req, 0, brq.data.bytes_xfered);
++              spin_unlock_irq(&md->lock);
+       }
+       mmc_release_host(card->host);
+-- 
+1.5.6.5
+
diff --git a/packages/linux/linux-2.6.28/collie/defconfig b/packages/linux/linux-2.6.28/collie/defconfig
new file mode 100644 (file)
index 0000000..3baea84
--- /dev/null
@@ -0,0 +1,1677 @@
+#
+# Automatically generated make config: don't edit
+# Linux kernel version: 2.6.28
+# Tue Feb 10 20:46:22 2009
+#
+CONFIG_ARM=y
+CONFIG_SYS_SUPPORTS_APM_EMULATION=y
+CONFIG_GENERIC_GPIO=y
+CONFIG_GENERIC_TIME=y
+CONFIG_GENERIC_CLOCKEVENTS=y
+CONFIG_MMU=y
+# CONFIG_NO_IOPORT is not set
+CONFIG_GENERIC_HARDIRQS=y
+CONFIG_STACKTRACE_SUPPORT=y
+CONFIG_HAVE_LATENCYTOP_SUPPORT=y
+CONFIG_LOCKDEP_SUPPORT=y
+CONFIG_TRACE_IRQFLAGS_SUPPORT=y
+CONFIG_HARDIRQS_SW_RESEND=y
+CONFIG_GENERIC_IRQ_PROBE=y
+CONFIG_RWSEM_GENERIC_SPINLOCK=y
+# CONFIG_ARCH_HAS_ILOG2_U32 is not set
+# CONFIG_ARCH_HAS_ILOG2_U64 is not set
+CONFIG_GENERIC_HWEIGHT=y
+CONFIG_GENERIC_CALIBRATE_DELAY=y
+CONFIG_ARCH_MTD_XIP=y
+CONFIG_GENERIC_HARDIRQS_NO__DO_IRQ=y
+CONFIG_VECTORS_BASE=0xffff0000
+CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
+
+#
+# General setup
+#
+CONFIG_EXPERIMENTAL=y
+CONFIG_BROKEN_ON_SMP=y
+CONFIG_LOCK_KERNEL=y
+CONFIG_INIT_ENV_ARG_LIMIT=32
+CONFIG_LOCALVERSION=""
+# CONFIG_LOCALVERSION_AUTO is not set
+CONFIG_SWAP=y
+CONFIG_SYSVIPC=y
+CONFIG_SYSVIPC_SYSCTL=y
+# CONFIG_POSIX_MQUEUE is not set
+CONFIG_BSD_PROCESS_ACCT=y
+CONFIG_BSD_PROCESS_ACCT_V3=y
+# CONFIG_TASKSTATS is not set
+# CONFIG_AUDIT is not set
+# CONFIG_IKCONFIG is not set
+CONFIG_LOG_BUF_SHIFT=14
+# CONFIG_CGROUPS is not set
+# CONFIG_GROUP_SCHED is not set
+# CONFIG_USER_SCHED is not set
+# CONFIG_CGROUP_SCHED is not set
+CONFIG_SYSFS_DEPRECATED=y
+CONFIG_SYSFS_DEPRECATED_V2=y
+# CONFIG_RELAY is not set
+# CONFIG_NAMESPACES is not set
+# CONFIG_BLK_DEV_INITRD is not set
+CONFIG_CC_OPTIMIZE_FOR_SIZE=y
+CONFIG_SYSCTL=y
+CONFIG_EMBEDDED=y
+CONFIG_UID16=y
+CONFIG_SYSCTL_SYSCALL=y
+CONFIG_KALLSYMS=y
+# CONFIG_KALLSYMS_ALL is not set
+# CONFIG_KALLSYMS_EXTRA_PASS is not set
+CONFIG_HOTPLUG=y
+CONFIG_PRINTK=y
+CONFIG_BUG=y
+CONFIG_ELF_CORE=y
+CONFIG_COMPAT_BRK=y
+CONFIG_BASE_FULL=y
+CONFIG_FUTEX=y
+CONFIG_ANON_INODES=y
+CONFIG_EPOLL=y
+CONFIG_SIGNALFD=y
+CONFIG_TIMERFD=y
+CONFIG_EVENTFD=y
+CONFIG_SHMEM=y
+CONFIG_AIO=y
+CONFIG_VM_EVENT_COUNTERS=y
+CONFIG_SLAB=y
+# CONFIG_SLUB is not set
+# CONFIG_SLOB is not set
+CONFIG_PROFILING=y
+# CONFIG_MARKERS is not set
+CONFIG_OPROFILE=m
+CONFIG_HAVE_OPROFILE=y
+# CONFIG_KPROBES is not set
+CONFIG_HAVE_KPROBES=y
+CONFIG_HAVE_KRETPROBES=y
+CONFIG_HAVE_CLK=y
+CONFIG_HAVE_GENERIC_DMA_COHERENT=y
+CONFIG_SLABINFO=y
+CONFIG_RT_MUTEXES=y
+# CONFIG_TINY_SHMEM is not set
+CONFIG_BASE_SMALL=0
+CONFIG_MODULES=y
+# CONFIG_MODULE_FORCE_LOAD is not set
+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_BLOCK=y
+# CONFIG_LBD is not set
+# CONFIG_BLK_DEV_IO_TRACE is not set
+# CONFIG_LSF is not set
+# CONFIG_BLK_DEV_BSG is not set
+# CONFIG_BLK_DEV_INTEGRITY is not set
+
+#
+# IO Schedulers
+#
+CONFIG_IOSCHED_NOOP=y
+CONFIG_IOSCHED_AS=y
+CONFIG_IOSCHED_DEADLINE=m
+CONFIG_IOSCHED_CFQ=m
+CONFIG_DEFAULT_AS=y
+# CONFIG_DEFAULT_DEADLINE is not set
+# CONFIG_DEFAULT_CFQ is not set
+# CONFIG_DEFAULT_NOOP is not set
+CONFIG_DEFAULT_IOSCHED="anticipatory"
+CONFIG_CLASSIC_RCU=y
+CONFIG_FREEZER=y
+
+#
+# System Type
+#
+# CONFIG_ARCH_AAEC2000 is not set
+# CONFIG_ARCH_INTEGRATOR is not set
+# CONFIG_ARCH_REALVIEW is not set
+# CONFIG_ARCH_VERSATILE is not set
+# CONFIG_ARCH_AT91 is not set
+# CONFIG_ARCH_CLPS7500 is not set
+# CONFIG_ARCH_CLPS711X is not set
+# CONFIG_ARCH_EBSA110 is not set
+# CONFIG_ARCH_EP93XX is not set
+# CONFIG_ARCH_FOOTBRIDGE is not set
+# CONFIG_ARCH_NETX is not set
+# CONFIG_ARCH_H720X is not set
+# CONFIG_ARCH_IMX is not set
+# CONFIG_ARCH_IOP13XX is not set
+# CONFIG_ARCH_IOP32X is not set
+# CONFIG_ARCH_IOP33X is not set
+# CONFIG_ARCH_IXP23XX is not set
+# CONFIG_ARCH_IXP2000 is not set
+# CONFIG_ARCH_IXP4XX is not set
+# CONFIG_ARCH_L7200 is not set
+# CONFIG_ARCH_KIRKWOOD is not set
+# CONFIG_ARCH_KS8695 is not set
+# CONFIG_ARCH_NS9XXX is not set
+# CONFIG_ARCH_LOKI is not set
+# CONFIG_ARCH_MV78XX0 is not set
+# CONFIG_ARCH_MXC is not set
+# CONFIG_ARCH_ORION5X is not set
+# CONFIG_ARCH_PNX4008 is not set
+# CONFIG_ARCH_PXA is not set
+# CONFIG_ARCH_RPC is not set
+CONFIG_ARCH_SA1100=y
+# CONFIG_ARCH_S3C2410 is not set
+# CONFIG_ARCH_SHARK is not set
+# CONFIG_ARCH_LH7A40X is not set
+# CONFIG_ARCH_DAVINCI is not set
+# CONFIG_ARCH_OMAP is not set
+# CONFIG_ARCH_MSM is not set
+
+#
+# SA11x0 Implementations
+#
+# CONFIG_SA1100_ASSABET is not set
+# CONFIG_SA1100_CERF is not set
+CONFIG_SA1100_COLLIE=y
+# CONFIG_SA1100_H3100 is not set
+# CONFIG_SA1100_H3600 is not set
+# CONFIG_SA1100_H3800 is not set
+# CONFIG_SA1100_BADGE4 is not set
+# CONFIG_SA1100_JORNADA720 is not set
+# CONFIG_SA1100_HACKKIT is not set
+# CONFIG_SA1100_LART is not set
+# CONFIG_SA1100_PLEB is not set
+# CONFIG_SA1100_SHANNON is not set
+# CONFIG_SA1100_SIMPAD is not set
+# CONFIG_SA1100_SSP is not set
+
+#
+# Boot options
+#
+
+#
+# Power management
+#
+
+#
+# Processor Type
+#
+CONFIG_CPU_32=y
+CONFIG_CPU_SA1100=y
+CONFIG_CPU_32v4=y
+CONFIG_CPU_ABRT_EV4=y
+CONFIG_CPU_PABRT_NOIFAR=y
+CONFIG_CPU_CACHE_V4WB=y
+CONFIG_CPU_CACHE_VIVT=y
+CONFIG_CPU_TLB_V4WB=y
+CONFIG_CPU_CP15=y
+CONFIG_CPU_CP15_MMU=y
+
+#
+# Processor Features
+#
+# CONFIG_CPU_ICACHE_DISABLE is not set
+# CONFIG_CPU_DCACHE_DISABLE is not set
+# CONFIG_OUTER_CACHE is not set
+CONFIG_SHARP_LOCOMO=y
+CONFIG_SHARP_PARAM=y
+CONFIG_SHARP_SCOOP=y
+
+#
+# Bus support
+#
+CONFIG_ISA=y
+# CONFIG_PCI_SYSCALL is not set
+# CONFIG_ARCH_SUPPORTS_MSI is not set
+CONFIG_PCCARD=y
+# CONFIG_PCMCIA_DEBUG is not set
+CONFIG_PCMCIA=y
+CONFIG_PCMCIA_LOAD_CIS=y
+CONFIG_PCMCIA_IOCTL=y
+
+#
+# PC-card bridges
+#
+# CONFIG_I82365 is not set
+# CONFIG_TCIC is not set
+CONFIG_PCMCIA_SA1100=y
+
+#
+# Kernel Features
+#
+CONFIG_TICK_ONESHOT=y
+CONFIG_NO_HZ=y
+CONFIG_HIGH_RES_TIMERS=y
+CONFIG_GENERIC_CLOCKEVENTS_BUILD=y
+CONFIG_VMSPLIT_3G=y
+# CONFIG_VMSPLIT_2G is not set
+# CONFIG_VMSPLIT_1G is not set
+CONFIG_PAGE_OFFSET=0xC0000000
+CONFIG_PREEMPT=y
+CONFIG_HZ=100
+# CONFIG_AEABI is not set
+CONFIG_ARCH_SPARSEMEM_ENABLE=y
+CONFIG_ARCH_SPARSEMEM_DEFAULT=y
+# CONFIG_ARCH_SELECT_MEMORY_MODEL is not set
+CONFIG_SELECT_MEMORY_MODEL=y
+# CONFIG_FLATMEM_MANUAL is not set
+# CONFIG_DISCONTIGMEM_MANUAL is not set
+CONFIG_SPARSEMEM_MANUAL=y
+CONFIG_SPARSEMEM=y
+CONFIG_HAVE_MEMORY_PRESENT=y
+CONFIG_SPARSEMEM_EXTREME=y
+CONFIG_PAGEFLAGS_EXTENDED=y
+CONFIG_SPLIT_PTLOCK_CPUS=4096
+# CONFIG_RESOURCES_64BIT is not set
+# CONFIG_PHYS_ADDR_T_64BIT is not set
+CONFIG_ZONE_DMA_FLAG=0
+CONFIG_VIRT_TO_BUS=y
+CONFIG_UNEVICTABLE_LRU=y
+# CONFIG_LEDS is not set
+CONFIG_ALIGNMENT_TRAP=y
+
+#
+# Boot options
+#
+CONFIG_ZBOOT_ROM_TEXT=0x0
+CONFIG_ZBOOT_ROM_BSS=0x0
+CONFIG_CMDLINE="console=ttySA0,115200n8 console=tty1 root=/dev/mmcblk0p1 rootfstype=ext2 rootdelay=3 mem=64M fbcon=rotate:1 debug"
+# CONFIG_XIP_KERNEL is not set
+CONFIG_KEXEC=y
+CONFIG_ATAGS_PROC=y
+
+#
+# CPU Power Management
+#
+# CONFIG_CPU_FREQ is not set
+# CONFIG_CPU_IDLE is not set
+
+#
+# Floating point emulation
+#
+
+#
+# At least one emulation must be selected
+#
+CONFIG_FPE_NWFPE=y
+# CONFIG_FPE_NWFPE_XP is not set
+# CONFIG_FPE_FASTFPE is not set
+
+#
+# Userspace binary formats
+#
+CONFIG_BINFMT_ELF=y
+# CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set
+CONFIG_HAVE_AOUT=y
+CONFIG_BINFMT_AOUT=m
+CONFIG_BINFMT_MISC=m
+# CONFIG_ARTHUR is not set
+
+#
+# Power management options
+#
+CONFIG_PM=y
+# CONFIG_PM_DEBUG is not set
+CONFIG_PM_SLEEP=y
+CONFIG_SUSPEND=y
+CONFIG_SUSPEND_FREEZER=y
+CONFIG_APM_EMULATION=y
+CONFIG_ARCH_SUSPEND_POSSIBLE=y
+CONFIG_NET=y
+
+#
+# Networking options
+#
+CONFIG_PACKET=y
+CONFIG_PACKET_MMAP=y
+CONFIG_UNIX=y
+CONFIG_XFRM=y
+CONFIG_XFRM_USER=m
+# CONFIG_XFRM_SUB_POLICY is not set
+# CONFIG_XFRM_MIGRATE is not set
+# CONFIG_XFRM_STATISTICS is not set
+CONFIG_XFRM_IPCOMP=m
+# CONFIG_NET_KEY is not set
+CONFIG_INET=y
+# CONFIG_IP_MULTICAST is not set
+# CONFIG_IP_ADVANCED_ROUTER is not set
+# CONFIG_ASK_IP_FIB_HASH is not set
+# CONFIG_IP_FIB_TRIE is not set
+CONFIG_IP_FIB_HASH=y
+# CONFIG_IP_PNP is not set
+# CONFIG_NET_IPIP is not set
+# CONFIG_NET_IPGRE is not set
+# CONFIG_ARPD is not set
+CONFIG_SYN_COOKIES=y
+# CONFIG_INET_AH is not set
+# 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_LRO is not set
+CONFIG_INET_DIAG=m
+CONFIG_INET_TCP_DIAG=m
+# CONFIG_TCP_CONG_ADVANCED is not set
+CONFIG_TCP_CONG_CUBIC=y
+# CONFIG_DEFAULT_BIC is not set
+# CONFIG_DEFAULT_CUBIC is not set
+# CONFIG_DEFAULT_HTCP is not set
+# CONFIG_DEFAULT_VEGAS is not set
+# CONFIG_DEFAULT_WESTWOOD is not set
+# CONFIG_DEFAULT_RENO is not set
+CONFIG_DEFAULT_TCP_CONG="cubic"
+# CONFIG_TCP_MD5SIG 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_NDISC_NODETYPE=y
+CONFIG_IPV6_TUNNEL=m
+# CONFIG_IPV6_MULTIPLE_TABLES is not set
+# CONFIG_IPV6_MROUTE is not set
+# CONFIG_NETWORK_SECMARK is not set
+CONFIG_NETFILTER=y
+# CONFIG_NETFILTER_DEBUG is not set
+CONFIG_NETFILTER_ADVANCED=y
+
+#
+# Core Netfilter Configuration
+#
+# CONFIG_NETFILTER_NETLINK_QUEUE is not set
+# CONFIG_NETFILTER_NETLINK_LOG 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_NFLOG is not set
+# CONFIG_NETFILTER_XT_TARGET_NFQUEUE is not set
+# CONFIG_NETFILTER_XT_TARGET_RATEEST is not set
+# CONFIG_NETFILTER_XT_TARGET_TRACE is not set
+# CONFIG_NETFILTER_XT_TARGET_TCPMSS is not set
+# CONFIG_NETFILTER_XT_TARGET_TCPOPTSTRIP 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_HASHLIMIT is not set
+# CONFIG_NETFILTER_XT_MATCH_IPRANGE 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_MULTIPORT is not set
+# CONFIG_NETFILTER_XT_MATCH_OWNER is not set
+# CONFIG_NETFILTER_XT_MATCH_POLICY is not set
+# CONFIG_NETFILTER_XT_MATCH_PKTTYPE is not set
+# CONFIG_NETFILTER_XT_MATCH_QUOTA is not set
+# CONFIG_NETFILTER_XT_MATCH_RATEEST is not set
+# CONFIG_NETFILTER_XT_MATCH_REALM is not set
+# CONFIG_NETFILTER_XT_MATCH_RECENT 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_IP_VS is not set
+
+#
+# IP: Netfilter Configuration
+#
+# CONFIG_NF_DEFRAG_IPV4 is not set
+CONFIG_IP_NF_QUEUE=m
+CONFIG_IP_NF_IPTABLES=m
+CONFIG_IP_NF_MATCH_ADDRTYPE=m
+CONFIG_IP_NF_MATCH_AH=m
+CONFIG_IP_NF_MATCH_ECN=m
+CONFIG_IP_NF_MATCH_TTL=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_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
+#
+# CONFIG_IP6_NF_QUEUE is not set
+# CONFIG_IP6_NF_IPTABLES is not set
+# CONFIG_IP_DCCP is not set
+# CONFIG_IP_SCTP is not set
+# CONFIG_SCTP_HMAC_NONE is not set
+# CONFIG_SCTP_HMAC_SHA1 is not set
+# CONFIG_SCTP_HMAC_MD5 is not set
+# CONFIG_TIPC is not set
+# CONFIG_ATM is not set
+# CONFIG_BRIDGE is not set
+# CONFIG_NET_DSA is not set
+# CONFIG_VLAN_8021Q is not set
+# CONFIG_DECNET is not set
+# CONFIG_LLC2 is not set
+# CONFIG_IPX is not set
+# CONFIG_ATALK is not set
+# CONFIG_X25 is not set
+# CONFIG_LAPB is not set
+# CONFIG_ECONET is not set
+# CONFIG_WAN_ROUTER is not set
+# CONFIG_NET_SCHED is not set
+
+#
+# Network testing
+#
+# CONFIG_NET_PKTGEN is not set
+# CONFIG_HAMRADIO is not set
+# CONFIG_CAN 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
+#
+
+#
+# FIR device drivers
+#
+# CONFIG_SA1100_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_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_HCIDTL1 is not set
+# CONFIG_BT_HCIBT3C is not set
+# CONFIG_BT_HCIBLUECARD is not set
+# CONFIG_BT_HCIBTUART is not set
+CONFIG_BT_HCIVHCI=m
+# CONFIG_AF_RXRPC is not set
+# CONFIG_PHONET is not set
+CONFIG_WIRELESS=y
+CONFIG_CFG80211=y
+CONFIG_NL80211=y
+CONFIG_WIRELESS_OLD_REGULATORY=y
+CONFIG_WIRELESS_EXT=y
+CONFIG_WIRELESS_EXT_SYSFS=y
+CONFIG_MAC80211=y
+
+#
+# Rate control algorithm selection
+#
+# CONFIG_MAC80211_RC_PID is not set
+CONFIG_MAC80211_RC_MINSTREL=y
+# CONFIG_MAC80211_RC_DEFAULT_PID is not set
+CONFIG_MAC80211_RC_DEFAULT_MINSTREL=y
+CONFIG_MAC80211_RC_DEFAULT="minstrel"
+# CONFIG_MAC80211_MESH is not set
+# CONFIG_MAC80211_LEDS is not set
+# CONFIG_MAC80211_DEBUGFS is not set
+# CONFIG_MAC80211_DEBUG_MENU is not set
+CONFIG_IEEE80211=y
+# CONFIG_IEEE80211_DEBUG is not set
+CONFIG_IEEE80211_CRYPT_WEP=y
+CONFIG_IEEE80211_CRYPT_CCMP=y
+CONFIG_IEEE80211_CRYPT_TKIP=y
+# CONFIG_RFKILL is not set
+# CONFIG_NET_9P is not set
+
+#
+# Device Drivers
+#
+
+#
+# Generic Driver Options
+#
+CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
+CONFIG_STANDALONE=y
+CONFIG_PREVENT_FIRMWARE_BUILD=y
+CONFIG_FW_LOADER=y
+CONFIG_FIRMWARE_IN_KERNEL=y
+CONFIG_EXTRA_FIRMWARE=""
+# CONFIG_DEBUG_DRIVER is not set
+# CONFIG_DEBUG_DEVRES is not set
+# CONFIG_SYS_HYPERVISOR is not set
+# CONFIG_CONNECTOR is not set
+CONFIG_MTD=y
+CONFIG_MTD_DEBUG=y
+CONFIG_MTD_DEBUG_VERBOSE=0
+# CONFIG_MTD_CONCAT is not set
+CONFIG_MTD_PARTITIONS=y
+# CONFIG_MTD_REDBOOT_PARTS is not set
+# CONFIG_MTD_CMDLINE_PARTS is not set
+# CONFIG_MTD_AFS_PARTS is not set
+# CONFIG_MTD_AR7_PARTS is not set
+
+#
+# User Modules And Translation Layers
+#
+CONFIG_MTD_CHAR=y
+CONFIG_MTD_BLKDEVS=y
+CONFIG_MTD_BLOCK=y
+# CONFIG_FTL is not set
+# CONFIG_NFTL is not set
+# CONFIG_INFTL is not set
+# CONFIG_RFD_FTL is not set
+# CONFIG_SSFDC is not set
+# CONFIG_MTD_OOPS is not set
+
+#
+# RAM/ROM/Flash chip drivers
+#
+# CONFIG_MTD_CFI is not set
+# CONFIG_MTD_JEDECPROBE is not set
+CONFIG_MTD_MAP_BANK_WIDTH_1=y
+CONFIG_MTD_MAP_BANK_WIDTH_2=y
+CONFIG_MTD_MAP_BANK_WIDTH_4=y
+# CONFIG_MTD_MAP_BANK_WIDTH_8 is not set
+# CONFIG_MTD_MAP_BANK_WIDTH_16 is not set
+# CONFIG_MTD_MAP_BANK_WIDTH_32 is not set
+CONFIG_MTD_CFI_I1=y
+CONFIG_MTD_CFI_I2=y
+# CONFIG_MTD_CFI_I4 is not set
+# CONFIG_MTD_CFI_I8 is not set
+# CONFIG_MTD_RAM is not set
+# CONFIG_MTD_ROM is not set
+# CONFIG_MTD_ABSENT is not set
+CONFIG_MTD_SHARP=y
+
+#
+# Mapping drivers for chip access
+#
+CONFIG_MTD_COMPLEX_MAPPINGS=y
+CONFIG_MTD_SA1100=y
+# CONFIG_MTD_PLATRAM is not set
+
+#
+# Self-contained MTD device drivers
+#
+# CONFIG_MTD_DATAFLASH is not set
+# CONFIG_MTD_M25P80 is not set
+# CONFIG_MTD_SLRAM is not set
+# CONFIG_MTD_PHRAM is not set
+# CONFIG_MTD_MTDRAM is not set
+# CONFIG_MTD_BLOCK2MTD is not set
+
+#
+# Disk-On-Chip Device Drivers
+#
+# CONFIG_MTD_DOC2000 is not set
+# CONFIG_MTD_DOC2001 is not set
+# CONFIG_MTD_DOC2001PLUS is not set
+# CONFIG_MTD_NAND is not set
+# CONFIG_MTD_ONENAND is not set
+
+#
+# UBI - Unsorted block images
+#
+CONFIG_MTD_UBI=m
+CONFIG_MTD_UBI_WL_THRESHOLD=4096
+CONFIG_MTD_UBI_BEB_RESERVE=1
+# CONFIG_MTD_UBI_GLUEBI is not set
+
+#
+# UBI debugging options
+#
+# CONFIG_MTD_UBI_DEBUG is not set
+# CONFIG_PARPORT is not set
+# CONFIG_PNP is not set
+CONFIG_BLK_DEV=y
+# CONFIG_BLK_DEV_COW_COMMON is not set
+CONFIG_BLK_DEV_LOOP=y
+CONFIG_BLK_DEV_CRYPTOLOOP=m
+CONFIG_BLK_DEV_NBD=m
+CONFIG_BLK_DEV_RAM=m
+CONFIG_BLK_DEV_RAM_COUNT=16
+CONFIG_BLK_DEV_RAM_SIZE=4096
+# CONFIG_BLK_DEV_XIP is not set
+CONFIG_CDROM_PKTCDVD=m
+CONFIG_CDROM_PKTCDVD_BUFFERS=8
+# CONFIG_CDROM_PKTCDVD_WCACHE is not set
+CONFIG_ATA_OVER_ETH=m
+# CONFIG_MISC_DEVICES is not set
+CONFIG_HAVE_IDE=y
+CONFIG_IDE=y
+
+#
+# Please see Documentation/ide/ide.txt for help/info on IDE drives
+#
+# CONFIG_BLK_DEV_IDE_SATA is not set
+CONFIG_IDE_GD=y
+CONFIG_IDE_GD_ATA=y
+# CONFIG_IDE_GD_ATAPI is not set
+# CONFIG_BLK_DEV_IDECS is not set
+# CONFIG_BLK_DEV_IDECD is not set
+# CONFIG_BLK_DEV_IDETAPE is not set
+# CONFIG_BLK_DEV_IDESCSI is not set
+# CONFIG_IDE_TASK_IOCTL is not set
+CONFIG_IDE_PROC_FS=y
+
+#
+# IDE chipset support/bugfixes
+#
+# CONFIG_BLK_DEV_PLATFORM is not set
+# CONFIG_BLK_DEV_IDEDMA is not set
+
+#
+# SCSI device support
+#
+# CONFIG_RAID_ATTRS is not set
+CONFIG_SCSI=m
+CONFIG_SCSI_DMA=y
+# CONFIG_SCSI_TGT 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_AHA152X is not set
+# CONFIG_SCSI_AIC7XXX_OLD is not set
+# CONFIG_SCSI_ADVANSYS is not set
+# CONFIG_SCSI_IN2000 is not set
+# CONFIG_SCSI_DTC3280 is not set
+# CONFIG_SCSI_FUTURE_DOMAIN is not set
+# CONFIG_SCSI_GENERIC_NCR5380 is not set
+# CONFIG_SCSI_GENERIC_NCR5380_MMIO is not set
+# CONFIG_SCSI_NCR53C406A is not set
+# CONFIG_SCSI_PAS16 is not set
+# CONFIG_SCSI_QLOGIC_FAS is not set
+# CONFIG_SCSI_SYM53C416 is not set
+# CONFIG_SCSI_T128 is not set
+# CONFIG_SCSI_DEBUG is not set
+# CONFIG_SCSI_LOWLEVEL_PCMCIA is not set
+# CONFIG_SCSI_DH 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_DELAY is not set
+# CONFIG_DM_UEVENT is not set
+CONFIG_NETDEVICES=y
+# CONFIG_DUMMY is not set
+# CONFIG_BONDING is not set
+# CONFIG_MACVLAN is not set
+# CONFIG_EQUALIZER is not set
+CONFIG_TUN=m
+# CONFIG_VETH is not set
+# CONFIG_ARCNET is not set
+# CONFIG_NET_ETHERNET is not set
+CONFIG_MII=m
+# CONFIG_NETDEV_1000 is not set
+# CONFIG_NETDEV_10000 is not set
+# CONFIG_TR is not set
+
+#
+# Wireless LAN
+#
+# CONFIG_WLAN_PRE80211 is not set
+CONFIG_WLAN_80211=y
+CONFIG_PCMCIA_RAYCS=m
+CONFIG_LIBERTAS=m
+CONFIG_LIBERTAS_CS=m
+CONFIG_LIBERTAS_SDIO=m
+# CONFIG_LIBERTAS_DEBUG is not set
+CONFIG_LIBERTAS_THINFIRM=m
+CONFIG_HERMES=m
+CONFIG_PCMCIA_HERMES=m
+CONFIG_PCMCIA_SPECTRUM=m
+CONFIG_ATMEL=m
+CONFIG_PCMCIA_ATMEL=m
+CONFIG_AIRO_CS=m
+CONFIG_PCMCIA_WL3501=m
+CONFIG_MAC80211_HWSIM=m
+CONFIG_P54_COMMON=m
+# CONFIG_IWLWIFI_LEDS is not set
+CONFIG_HOSTAP=m
+CONFIG_HOSTAP_FIRMWARE=y
+# CONFIG_HOSTAP_FIRMWARE_NVRAM is not set
+CONFIG_HOSTAP_CS=m
+CONFIG_B43=m
+# CONFIG_B43_PCMCIA is not set
+# CONFIG_B43_DEBUG is not set
+CONFIG_B43LEGACY=m
+# CONFIG_B43LEGACY_DEBUG is not set
+CONFIG_B43LEGACY_DMA=y
+CONFIG_B43LEGACY_PIO=y
+CONFIG_B43LEGACY_DMA_AND_PIO_MODE=y
+# CONFIG_B43LEGACY_DMA_MODE is not set
+# CONFIG_B43LEGACY_PIO_MODE is not set
+CONFIG_RT2X00=m
+CONFIG_NET_PCMCIA=y
+CONFIG_PCMCIA_3C589=m
+CONFIG_PCMCIA_3C574=m
+CONFIG_PCMCIA_FMVJ18X=m
+CONFIG_PCMCIA_PCNET=m
+CONFIG_PCMCIA_NMCLAN=m
+CONFIG_PCMCIA_SMC91C92=m
+CONFIG_PCMCIA_XIRC2PS=m
+CONFIG_PCMCIA_AXNET=m
+# 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_SLIP is not set
+CONFIG_SLHC=m
+# CONFIG_NETCONSOLE is not set
+# CONFIG_NETPOLL is not set
+# CONFIG_NET_POLL_CONTROLLER is not set
+# CONFIG_ISDN is not set
+
+#
+# Input device support
+#
+CONFIG_INPUT=y
+# CONFIG_INPUT_FF_MEMLESS is not set
+# CONFIG_INPUT_POLLDEV is not set
+
+#
+# Userland interfaces
+#
+CONFIG_INPUT_MOUSEDEV=m
+# CONFIG_INPUT_MOUSEDEV_PSAUX is not set
+CONFIG_INPUT_MOUSEDEV_SCREEN_X=640
+CONFIG_INPUT_MOUSEDEV_SCREEN_Y=480
+# CONFIG_INPUT_JOYDEV is not set
+CONFIG_INPUT_EVDEV=y
+# CONFIG_INPUT_EVBUG is not set
+CONFIG_INPUT_APMPOWER=y
+
+#
+# Input Device Drivers
+#
+CONFIG_INPUT_KEYBOARD=y
+# CONFIG_KEYBOARD_ATKBD is not set
+# CONFIG_KEYBOARD_SUNKBD is not set
+# CONFIG_KEYBOARD_LKKBD is not set
+CONFIG_KEYBOARD_LOCOMO=y
+# CONFIG_KEYBOARD_XTKBD is not set
+# CONFIG_KEYBOARD_NEWTON is not set
+# CONFIG_KEYBOARD_STOWAWAY 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_ADS7846 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_INEXIO is not set
+# CONFIG_TOUCHSCREEN_MK712 is not set
+# CONFIG_TOUCHSCREEN_HTCPEN is not set
+# CONFIG_TOUCHSCREEN_PENMOUNT is not set
+# CONFIG_TOUCHSCREEN_TOUCHRIGHT is not set
+# CONFIG_TOUCHSCREEN_TOUCHWIN is not set
+# CONFIG_TOUCHSCREEN_UCB1200_TS is not set
+CONFIG_TOUCHSCREEN_COLLIE_TS=y
+# CONFIG_TOUCHSCREEN_USB_COMPOSITE is not set
+# CONFIG_TOUCHSCREEN_TOUCHIT213 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_CM109 is not set
+CONFIG_INPUT_UINPUT=m
+
+#
+# Hardware I/O ports
+#
+# CONFIG_SERIO is not set
+# CONFIG_GAMEPORT is not set
+
+#
+# Character devices
+#
+CONFIG_VT=y
+CONFIG_CONSOLE_TRANSLATIONS=y
+CONFIG_VT_CONSOLE=y
+CONFIG_HW_CONSOLE=y
+# CONFIG_VT_HW_CONSOLE_BINDING is not set
+CONFIG_DEVKMEM=y
+# CONFIG_SERIAL_NONSTANDARD is not set
+
+#
+# Serial drivers
+#
+CONFIG_SERIAL_8250=m
+# CONFIG_SERIAL_8250_CS is not set
+CONFIG_SERIAL_8250_NR_UARTS=4
+CONFIG_SERIAL_8250_RUNTIME_UARTS=4
+# CONFIG_SERIAL_8250_EXTENDED is not set
+
+#
+# Non-8250 serial port support
+#
+CONFIG_SERIAL_SA1100=y
+CONFIG_SERIAL_SA1100_CONSOLE=y
+CONFIG_SERIAL_CORE=y
+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_NVRAM is not set
+# CONFIG_DTLK is not set
+# CONFIG_R3964 is not set
+
+#
+# PCMCIA character devices
+#
+# CONFIG_SYNCLINK_CS is not set
+# CONFIG_CARDMAN_4000 is not set
+# CONFIG_CARDMAN_4040 is not set
+# CONFIG_IPWIRELESS is not set
+# CONFIG_RAW_DRIVER is not set
+# CONFIG_TCG_TPM is not set
+CONFIG_DEVPORT=y
+# CONFIG_I2C is not set
+CONFIG_SPI=y
+# CONFIG_SPI_DEBUG is not set
+CONFIG_SPI_MASTER=y
+
+#
+# SPI Master Controller Drivers
+#
+# CONFIG_SPI_BITBANG is not set
+CONFIG_SPI_LOCOMO=y
+
+#
+# SPI Protocol Masters
+#
+# CONFIG_SPI_AT25 is not set
+# CONFIG_SPI_SPIDEV is not set
+# CONFIG_SPI_TLE62X0 is not set
+CONFIG_ARCH_REQUIRE_GPIOLIB=y
+CONFIG_GPIOLIB=y
+# CONFIG_DEBUG_GPIO is not set
+# CONFIG_GPIO_SYSFS is not set
+
+#
+# Memory mapped GPIO expanders:
+#
+
+#
+# I2C GPIO expanders:
+#
+
+#
+# PCI GPIO expanders:
+#
+
+#
+# SPI GPIO expanders:
+#
+# CONFIG_GPIO_MAX7301 is not set
+# CONFIG_GPIO_MCP23S08 is not set
+# 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_COLLIE=y
+# CONFIG_HWMON is not set
+# CONFIG_THERMAL is not set
+# CONFIG_THERMAL_HWMON is not set
+CONFIG_WATCHDOG=y
+# CONFIG_WATCHDOG_NOWAYOUT is not set
+
+#
+# Watchdog Device Drivers
+#
+# CONFIG_SOFT_WATCHDOG is not set
+CONFIG_SA1100_WATCHDOG=m
+
+#
+# ISA-based Watchdog Cards
+#
+# CONFIG_PCWATCHDOG is not set
+# CONFIG_MIXCOMWD is not set
+# CONFIG_WDT is not set
+CONFIG_SSB_POSSIBLE=y
+
+#
+# Sonics Silicon Backplane
+#
+CONFIG_SSB=m
+CONFIG_SSB_PCMCIAHOST_POSSIBLE=y
+# CONFIG_SSB_PCMCIAHOST is not set
+# CONFIG_SSB_SILENT is not set
+# CONFIG_SSB_DEBUG is not set
+
+#
+# Multifunction device drivers
+#
+# CONFIG_MFD_CORE is not set
+# CONFIG_MFD_SM501 is not set
+# CONFIG_MFD_ASIC3 is not set
+# CONFIG_HTC_EGPIO is not set
+# CONFIG_HTC_PASIC3 is not set
+# CONFIG_MFD_TMIO is not set
+# CONFIG_MFD_T7L66XB is not set
+# CONFIG_MFD_TC6387XB is not set
+# CONFIG_MFD_TC6393XB is not set
+
+#
+# Multimedia Capabilities Port drivers
+#
+CONFIG_MCP=y
+CONFIG_MCP_SA11X0=y
+CONFIG_MCP_UCB1200=y
+
+#
+# Multimedia devices
+#
+
+#
+# Multimedia core support
+#
+# CONFIG_VIDEO_DEV is not set
+# CONFIG_DVB_CORE is not set
+# CONFIG_VIDEO_MEDIA is not set
+
+#
+# Multimedia drivers
+#
+# CONFIG_DAB is not set
+
+#
+# Graphics support
+#
+# CONFIG_VGASTATE is not set
+# CONFIG_VIDEO_OUTPUT_CONTROL is not set
+CONFIG_FB=y
+# CONFIG_FIRMWARE_EDID is not set
+# CONFIG_FB_DDC is not set
+# CONFIG_FB_BOOT_VESA_SUPPORT is not set
+CONFIG_FB_CFB_FILLRECT=y
+CONFIG_FB_CFB_COPYAREA=y
+CONFIG_FB_CFB_IMAGEBLIT=y
+# CONFIG_FB_CFB_REV_PIXELS_IN_BYTE is not set
+# CONFIG_FB_SYS_FILLRECT is not set
+# CONFIG_FB_SYS_COPYAREA is not set
+# CONFIG_FB_SYS_IMAGEBLIT is not set
+# CONFIG_FB_FOREIGN_ENDIAN is not set
+# CONFIG_FB_SYS_FOPS is not set
+# CONFIG_FB_SVGALIB is not set
+# CONFIG_FB_MACMODES is not set
+# CONFIG_FB_BACKLIGHT is not set
+# CONFIG_FB_MODE_HELPERS is not set
+# CONFIG_FB_TILEBLITTING is not set
+
+#
+# Frame buffer hardware drivers
+#
+CONFIG_FB_SA1100=y
+# CONFIG_FB_S1D13XXX is not set
+# CONFIG_FB_VIRTUAL is not set
+# CONFIG_FB_METRONOME is not set
+# CONFIG_FB_MB862XX is not set
+CONFIG_BACKLIGHT_LCD_SUPPORT=y
+# CONFIG_LCD_CLASS_DEVICE is not set
+CONFIG_BACKLIGHT_CLASS_DEVICE=y
+# CONFIG_BACKLIGHT_CORGI is not set
+CONFIG_BACKLIGHT_LOCOMO=y
+
+#
+# Display device support
+#
+# CONFIG_DISPLAY_SUPPORT is not set
+
+#
+# Console display driver support
+#
+# CONFIG_VGA_CONSOLE is not set
+# CONFIG_MDA_CONSOLE is not set
+CONFIG_DUMMY_CONSOLE=y
+CONFIG_FRAMEBUFFER_CONSOLE=y
+# CONFIG_FRAMEBUFFER_CONSOLE_DETECT_PRIMARY is not set
+CONFIG_FRAMEBUFFER_CONSOLE_ROTATION=y
+CONFIG_FONTS=y
+CONFIG_FONT_8x8=y
+# CONFIG_FONT_8x16 is not set
+# CONFIG_FONT_6x11 is not set
+# CONFIG_FONT_7x14 is not set
+# CONFIG_FONT_PEARL_8x8 is not set
+# CONFIG_FONT_ACORN_8x8 is not set
+# CONFIG_FONT_MINI_4x6 is not set
+# CONFIG_FONT_SUN8x16 is not set
+# CONFIG_FONT_SUN12x22 is not set
+# CONFIG_FONT_10x18 is not set
+CONFIG_LOGO=y
+# CONFIG_LOGO_LINUX_MONO is not set
+# CONFIG_LOGO_LINUX_VGA16 is not set
+CONFIG_LOGO_LINUX_CLUT224=y
+# CONFIG_SOUND is not set
+# CONFIG_HID_SUPPORT is not set
+CONFIG_HID=m
+CONFIG_USB_SUPPORT=y
+CONFIG_USB_ARCH_HAS_HCD=y
+# CONFIG_USB_ARCH_HAS_OHCI is not set
+# CONFIG_USB_ARCH_HAS_EHCI is not set
+# CONFIG_USB is not set
+# CONFIG_USB_OTG_WHITELIST is not set
+# CONFIG_USB_OTG_BLACKLIST_HUB is not set
+# CONFIG_USB_MUSB_HDRC is not set
+# CONFIG_USB_GADGET_MUSB_HDRC is not set
+
+#
+# NOTE: USB_STORAGE depends on SCSI but BLK_DEV_SD may also be needed;
+#
+CONFIG_USB_GADGET=y
+# CONFIG_USB_GADGET_DEBUG is not set
+# CONFIG_USB_GADGET_DEBUG_FILES is not set
+# CONFIG_USB_GADGET_DEBUG_FS is not set
+CONFIG_USB_GADGET_VBUS_DRAW=500
+CONFIG_USB_GADGET_SELECTED=y
+# CONFIG_USB_GADGET_AT91 is not set
+# CONFIG_USB_GADGET_ATMEL_USBA is not set
+# CONFIG_USB_GADGET_FSL_USB2 is not set
+# CONFIG_USB_GADGET_LH7A40X is not set
+# CONFIG_USB_GADGET_OMAP is not set
+# CONFIG_USB_GADGET_PXA25X is not set
+# CONFIG_USB_GADGET_PXA27X is not set
+# CONFIG_USB_GADGET_S3C2410 is not set
+# CONFIG_USB_GADGET_M66592 is not set
+# CONFIG_USB_GADGET_AMD5536UDC is not set
+# CONFIG_USB_GADGET_FSL_QE is not set
+# CONFIG_USB_GADGET_NET2280 is not set
+# CONFIG_USB_GADGET_GOKU is not set
+CONFIG_USB_GADGET_SA1100=y
+CONFIG_USB_SA1100=y
+# 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 is not set
+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_G_PRINTER=m
+CONFIG_USB_CDC_COMPOSITE=m
+CONFIG_MMC=y
+# CONFIG_MMC_DEBUG is not set
+CONFIG_MMC_UNSAFE_RESUME=y
+
+#
+# MMC/SD/SDIO Card Drivers
+#
+CONFIG_MMC_BLOCK=y
+# CONFIG_MMC_BLOCK_BOUNCE is not set
+CONFIG_SDIO_UART=m
+CONFIG_MMC_TEST=m
+
+#
+# MMC/SD/SDIO Host Controller Drivers
+#
+CONFIG_MMC_SDHCI=y
+CONFIG_MMC_SPI=y
+# CONFIG_MEMSTICK is not set
+# CONFIG_ACCESSIBILITY is not set
+CONFIG_NEW_LEDS=y
+CONFIG_LEDS_CLASS=y
+
+#
+# LED drivers
+#
+CONFIG_LEDS_LOCOMO=y
+# CONFIG_LEDS_GPIO is not set
+
+#
+# LED Triggers
+#
+CONFIG_LEDS_TRIGGERS=y
+CONFIG_LEDS_TRIGGER_TIMER=m
+CONFIG_LEDS_TRIGGER_IDE_DISK=y
+CONFIG_LEDS_TRIGGER_HEARTBEAT=m
+CONFIG_LEDS_TRIGGER_BACKLIGHT=m
+CONFIG_LEDS_TRIGGER_DEFAULT_ON=m
+CONFIG_RTC_LIB=y
+CONFIG_RTC_CLASS=y
+CONFIG_RTC_HCTOSYS=y
+CONFIG_RTC_HCTOSYS_DEVICE="rtc0"
+# CONFIG_RTC_DEBUG is not set
+
+#
+# RTC interfaces
+#
+CONFIG_RTC_INTF_SYSFS=y
+CONFIG_RTC_INTF_PROC=y
+CONFIG_RTC_INTF_DEV=y
+# CONFIG_RTC_INTF_DEV_UIE_EMUL is not set
+# CONFIG_RTC_DRV_TEST is not set
+
+#
+# SPI RTC drivers
+#
+# CONFIG_RTC_DRV_M41T94 is not set
+# CONFIG_RTC_DRV_DS1305 is not set
+# CONFIG_RTC_DRV_DS1390 is not set
+# CONFIG_RTC_DRV_MAX6902 is not set
+# CONFIG_RTC_DRV_R9701 is not set
+# CONFIG_RTC_DRV_RS5C348 is not set
+# CONFIG_RTC_DRV_DS3234 is not set
+
+#
+# Platform RTC drivers
+#
+# CONFIG_RTC_DRV_CMOS is not set
+# CONFIG_RTC_DRV_DS1286 is not set
+# CONFIG_RTC_DRV_DS1511 is not set
+# CONFIG_RTC_DRV_DS1553 is not set
+# CONFIG_RTC_DRV_DS1742 is not set
+# CONFIG_RTC_DRV_STK17TA8 is not set
+# CONFIG_RTC_DRV_M48T86 is not set
+# CONFIG_RTC_DRV_M48T35 is not set
+# CONFIG_RTC_DRV_M48T59 is not set
+# CONFIG_RTC_DRV_BQ4802 is not set
+# CONFIG_RTC_DRV_V3020 is not set
+
+#
+# on-CPU RTC drivers
+#
+CONFIG_RTC_DRV_SA1100=y
+# CONFIG_DMADEVICES is not set
+# CONFIG_REGULATOR is not set
+CONFIG_UIO=m
+CONFIG_UIO_PDRV=m
+CONFIG_UIO_PDRV_GENIRQ=m
+CONFIG_UIO_SMX=m
+CONFIG_UIO_SERCOS3=m
+
+#
+# File systems
+#
+CONFIG_EXT2_FS=y
+# CONFIG_EXT2_FS_XATTR is not set
+# CONFIG_EXT2_FS_XIP is not set
+CONFIG_EXT3_FS=y
+# CONFIG_EXT3_FS_XATTR is not set
+CONFIG_EXT4_FS=m
+# CONFIG_EXT4DEV_COMPAT is not set
+CONFIG_EXT4_FS_XATTR=y
+# CONFIG_EXT4_FS_POSIX_ACL is not set
+# CONFIG_EXT4_FS_SECURITY is not set
+CONFIG_JBD=y
+# CONFIG_JBD_DEBUG is not set
+CONFIG_JBD2=m
+# CONFIG_JBD2_DEBUG is not set
+CONFIG_FS_MBCACHE=m
+CONFIG_REISERFS_FS=m
+# CONFIG_REISERFS_CHECK is not set
+# CONFIG_REISERFS_PROC_INFO is not set
+# CONFIG_REISERFS_FS_XATTR is not set
+CONFIG_JFS_FS=m
+# CONFIG_JFS_POSIX_ACL is not set
+# CONFIG_JFS_SECURITY is not set
+# CONFIG_JFS_DEBUG is not set
+# CONFIG_JFS_STATISTICS is not set
+CONFIG_FS_POSIX_ACL=y
+CONFIG_FILE_LOCKING=y
+CONFIG_XFS_FS=m
+# CONFIG_XFS_QUOTA is not set
+# CONFIG_XFS_POSIX_ACL is not set
+# CONFIG_XFS_RT is not set
+# CONFIG_XFS_DEBUG is not set
+CONFIG_OCFS2_FS=m
+CONFIG_OCFS2_FS_O2CB=m
+CONFIG_OCFS2_FS_STATS=y
+CONFIG_OCFS2_DEBUG_MASKLOG=y
+# CONFIG_OCFS2_DEBUG_FS is not set
+# CONFIG_OCFS2_COMPAT_JBD is not set
+CONFIG_DNOTIFY=y
+CONFIG_INOTIFY=y
+CONFIG_INOTIFY_USER=y
+# CONFIG_QUOTA is not set
+# CONFIG_AUTOFS_FS is not set
+# CONFIG_AUTOFS4_FS is not set
+CONFIG_FUSE_FS=m
+
+#
+# CD-ROM/DVD Filesystems
+#
+CONFIG_ISO9660_FS=m
+# CONFIG_JOLIET is not set
+# CONFIG_ZISOFS is not set
+CONFIG_UDF_FS=m
+CONFIG_UDF_NLS=y
+
+#
+# DOS/FAT/NT Filesystems
+#
+CONFIG_FAT_FS=y
+CONFIG_MSDOS_FS=m
+CONFIG_VFAT_FS=y
+CONFIG_FAT_DEFAULT_CODEPAGE=437
+CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1"
+CONFIG_NTFS_FS=m
+# CONFIG_NTFS_DEBUG is not set
+# CONFIG_NTFS_RW is not set
+
+#
+# Pseudo filesystems
+#
+CONFIG_PROC_FS=y
+CONFIG_PROC_SYSCTL=y
+CONFIG_PROC_PAGE_MONITOR=y
+CONFIG_SYSFS=y
+CONFIG_TMPFS=y
+# CONFIG_TMPFS_POSIX_ACL is not set
+# CONFIG_HUGETLB_PAGE is not set
+CONFIG_CONFIGFS_FS=m
+
+#
+# Miscellaneous filesystems
+#
+# CONFIG_ADFS_FS is not set
+# CONFIG_AFFS_FS is not set
+# CONFIG_HFS_FS is not set
+# CONFIG_HFSPLUS_FS is not set
+# CONFIG_BEFS_FS is not set
+# CONFIG_BFS_FS is not set
+# CONFIG_EFS_FS is not set
+CONFIG_JFFS2_FS=y
+CONFIG_JFFS2_FS_DEBUG=0
+CONFIG_JFFS2_FS_WRITEBUFFER=y
+# CONFIG_JFFS2_FS_WBUF_VERIFY is not set
+# CONFIG_JFFS2_SUMMARY is not set
+# CONFIG_JFFS2_FS_XATTR is not set
+CONFIG_JFFS2_COMPRESSION_OPTIONS=y
+CONFIG_JFFS2_ZLIB=y
+CONFIG_JFFS2_LZO=y
+CONFIG_JFFS2_RTIME=y
+CONFIG_JFFS2_RUBIN=y
+# CONFIG_JFFS2_CMODE_NONE is not set
+CONFIG_JFFS2_CMODE_PRIORITY=y
+# CONFIG_JFFS2_CMODE_SIZE is not set
+# CONFIG_JFFS2_CMODE_FAVOURLZO is not set
+# CONFIG_UBIFS_FS is not set
+CONFIG_CRAMFS=m
+# CONFIG_VXFS_FS is not set
+# CONFIG_MINIX_FS is not set
+# CONFIG_OMFS_FS is not set
+# CONFIG_HPFS_FS is not set
+# CONFIG_QNX4FS_FS is not set
+# CONFIG_ROMFS_FS is not set
+# CONFIG_SYSV_FS is not set
+# CONFIG_UFS_FS is not set
+CONFIG_NETWORK_FILESYSTEMS=y
+CONFIG_NFS_FS=y
+CONFIG_NFS_V3=y
+# CONFIG_NFS_V3_ACL is not set
+CONFIG_NFS_V4=y
+CONFIG_NFSD=m
+CONFIG_NFSD_V3=y
+# CONFIG_NFSD_V3_ACL is not set
+CONFIG_NFSD_V4=y
+CONFIG_LOCKD=y
+CONFIG_LOCKD_V4=y
+CONFIG_EXPORTFS=m
+CONFIG_NFS_COMMON=y
+CONFIG_SUNRPC=y
+CONFIG_SUNRPC_GSS=y
+# CONFIG_SUNRPC_REGISTER_V4 is not set
+CONFIG_RPCSEC_GSS_KRB5=y
+# 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
+
+#
+# Partition Types
+#
+CONFIG_PARTITION_ADVANCED=y
+# CONFIG_ACORN_PARTITION is not set
+# CONFIG_OSF_PARTITION is not set
+# CONFIG_AMIGA_PARTITION is not set
+# CONFIG_ATARI_PARTITION is not set
+# CONFIG_MAC_PARTITION is not set
+CONFIG_MSDOS_PARTITION=y
+# CONFIG_BSD_DISKLABEL is not set
+# CONFIG_MINIX_SUBPARTITION is not set
+# CONFIG_SOLARIS_X86_PARTITION is not set
+# CONFIG_UNIXWARE_DISKLABEL is not set
+# CONFIG_LDM_PARTITION is not set
+# CONFIG_SGI_PARTITION is not set
+# CONFIG_ULTRIX_PARTITION is not set
+# CONFIG_SUN_PARTITION is not set
+# CONFIG_KARMA_PARTITION is not set
+# CONFIG_EFI_PARTITION is not set
+# CONFIG_SYSV68_PARTITION is not set
+CONFIG_NLS=y
+CONFIG_NLS_DEFAULT="cp437"
+CONFIG_NLS_CODEPAGE_437=y
+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=y
+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=y
+# CONFIG_DLM is not set
+
+#
+# Kernel hacking
+#
+# CONFIG_PRINTK_TIME is not set
+CONFIG_ENABLE_WARN_DEPRECATED=y
+CONFIG_ENABLE_MUST_CHECK=y
+CONFIG_FRAME_WARN=1024
+CONFIG_MAGIC_SYSRQ=y
+# CONFIG_UNUSED_SYMBOLS is not set
+CONFIG_DEBUG_FS=y
+# CONFIG_HEADERS_CHECK is not set
+CONFIG_DEBUG_KERNEL=y
+# CONFIG_DEBUG_SHIRQ is not set
+# CONFIG_DETECT_SOFTLOCKUP is not set
+# CONFIG_SCHED_DEBUG is not set
+# CONFIG_SCHEDSTATS is not set
+CONFIG_TIMER_STATS=y
+# CONFIG_DEBUG_OBJECTS is not set
+# CONFIG_DEBUG_SLAB is not set
+# CONFIG_DEBUG_PREEMPT is not set
+# CONFIG_DEBUG_RT_MUTEXES is not set
+# CONFIG_RT_MUTEX_TESTER is not set
+# CONFIG_DEBUG_SPINLOCK is not set
+# CONFIG_DEBUG_MUTEXES is not set
+# CONFIG_DEBUG_LOCK_ALLOC is not set
+# CONFIG_PROVE_LOCKING is not set
+# CONFIG_LOCK_STAT is not set
+# CONFIG_DEBUG_SPINLOCK_SLEEP is not set
+# CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set
+# CONFIG_DEBUG_KOBJECT is not set
+CONFIG_DEBUG_BUGVERBOSE=y
+# CONFIG_DEBUG_INFO is not set
+# CONFIG_DEBUG_VM is not set
+# CONFIG_DEBUG_WRITECOUNT is not set
+# CONFIG_DEBUG_MEMORY_INIT is not set
+# CONFIG_DEBUG_LIST is not set
+# CONFIG_DEBUG_SG is not set
+CONFIG_FRAME_POINTER=y
+# CONFIG_BOOT_PRINTK_DELAY is not set
+# CONFIG_RCU_TORTURE_TEST is not set
+# CONFIG_RCU_CPU_STALL_DETECTOR is not set
+# CONFIG_BACKTRACE_SELF_TEST is not set
+# CONFIG_DEBUG_BLOCK_EXT_DEVT is not set
+# CONFIG_FAULT_INJECTION is not set
+# CONFIG_LATENCYTOP is not set
+CONFIG_SYSCTL_SYSCALL_CHECK=y
+CONFIG_HAVE_FUNCTION_TRACER=y
+
+#
+# Tracers
+#
+# CONFIG_FUNCTION_TRACER is not set
+# CONFIG_IRQSOFF_TRACER is not set
+# CONFIG_PREEMPT_TRACER is not set
+# CONFIG_SCHED_TRACER is not set
+# CONFIG_CONTEXT_SWITCH_TRACER is not set
+# CONFIG_BOOT_TRACER is not set
+# CONFIG_STACK_TRACER is not set
+# CONFIG_DYNAMIC_PRINTK_DEBUG is not set
+# CONFIG_SAMPLES is not set
+CONFIG_HAVE_ARCH_KGDB=y
+# CONFIG_KGDB is not set
+# CONFIG_DEBUG_USER is not set
+CONFIG_DEBUG_ERRORS=y
+# CONFIG_DEBUG_STACK_USAGE is not set
+# CONFIG_DEBUG_LL is not set
+
+#
+# Security options
+#
+# CONFIG_KEYS is not set
+# CONFIG_SECURITY is not set
+# CONFIG_SECURITYFS is not set
+# CONFIG_SECURITY_FILE_CAPABILITIES is not set
+CONFIG_CRYPTO=y
+
+#
+# Crypto core or helper
+#
+# CONFIG_CRYPTO_FIPS is not set
+CONFIG_CRYPTO_ALGAPI=y
+CONFIG_CRYPTO_ALGAPI2=y
+CONFIG_CRYPTO_AEAD=m
+CONFIG_CRYPTO_AEAD2=y
+CONFIG_CRYPTO_BLKCIPHER=y
+CONFIG_CRYPTO_BLKCIPHER2=y
+CONFIG_CRYPTO_HASH=m
+CONFIG_CRYPTO_HASH2=y
+CONFIG_CRYPTO_RNG2=y
+CONFIG_CRYPTO_MANAGER=y
+CONFIG_CRYPTO_MANAGER2=y
+# CONFIG_CRYPTO_GF128MUL is not set
+CONFIG_CRYPTO_NULL=m
+# CONFIG_CRYPTO_CRYPTD is not set
+CONFIG_CRYPTO_AUTHENC=m
+CONFIG_CRYPTO_TEST=m
+
+#
+# Authenticated Encryption with Associated Data
+#
+# CONFIG_CRYPTO_CCM is not set
+# CONFIG_CRYPTO_GCM is not set
+# CONFIG_CRYPTO_SEQIV is not set
+
+#
+# Block modes
+#
+CONFIG_CRYPTO_CBC=y
+# CONFIG_CRYPTO_CTR is not set
+# CONFIG_CRYPTO_CTS is not set
+CONFIG_CRYPTO_ECB=y
+# CONFIG_CRYPTO_LRW is not set
+CONFIG_CRYPTO_PCBC=m
+# CONFIG_CRYPTO_XTS is not set
+
+#
+# Hash modes
+#
+CONFIG_CRYPTO_HMAC=m
+# CONFIG_CRYPTO_XCBC is not set
+
+#
+# Digest
+#
+CONFIG_CRYPTO_CRC32C=m
+CONFIG_CRYPTO_MD4=m
+CONFIG_CRYPTO_MD5=y
+CONFIG_CRYPTO_MICHAEL_MIC=y
+# CONFIG_CRYPTO_RMD128 is not set
+# CONFIG_CRYPTO_RMD160 is not set
+# CONFIG_CRYPTO_RMD256 is not set
+# CONFIG_CRYPTO_RMD320 is not set
+CONFIG_CRYPTO_SHA1=m
+CONFIG_CRYPTO_SHA256=m
+CONFIG_CRYPTO_SHA512=m
+# CONFIG_CRYPTO_TGR192 is not set
+CONFIG_CRYPTO_WP512=m
+
+#
+# Ciphers
+#
+CONFIG_CRYPTO_AES=y
+CONFIG_CRYPTO_ANUBIS=m
+CONFIG_CRYPTO_ARC4=y
+CONFIG_CRYPTO_BLOWFISH=m
+CONFIG_CRYPTO_CAMELLIA=m
+CONFIG_CRYPTO_CAST5=m
+CONFIG_CRYPTO_CAST6=m
+CONFIG_CRYPTO_DES=y
+# CONFIG_CRYPTO_FCRYPT is not set
+CONFIG_CRYPTO_KHAZAD=m
+# CONFIG_CRYPTO_SALSA20 is not set
+# CONFIG_CRYPTO_SEED is not set
+CONFIG_CRYPTO_SERPENT=m
+CONFIG_CRYPTO_TEA=m
+CONFIG_CRYPTO_TWOFISH=m
+CONFIG_CRYPTO_TWOFISH_COMMON=m
+
+#
+# Compression
+#
+CONFIG_CRYPTO_DEFLATE=m
+CONFIG_CRYPTO_LZO=m
+
+#
+# Random Number Generation
+#
+# CONFIG_CRYPTO_ANSI_CPRNG is not set
+# CONFIG_CRYPTO_HW is not set
+
+#
+# Library routines
+#
+CONFIG_BITREVERSE=y
+CONFIG_CRC_CCITT=y
+CONFIG_CRC16=m
+# CONFIG_CRC_T10DIF is not set
+CONFIG_CRC_ITU_T=y
+CONFIG_CRC32=y
+CONFIG_CRC7=y
+CONFIG_LIBCRC32C=m
+CONFIG_ZLIB_INFLATE=y
+CONFIG_ZLIB_DEFLATE=y
+CONFIG_LZO_COMPRESS=y
+CONFIG_LZO_DECOMPRESS=y
+CONFIG_PLIST=y
+CONFIG_HAS_IOMEM=y
+CONFIG_HAS_IOPORT=y
+CONFIG_HAS_DMA=y
index 393209c..331f6bb 100644 (file)
@@ -1,12 +1,13 @@
 require linux.inc
 
-PR = "r2"
+PR = "r3"
 
 # Mark archs/machines that this kernel supports
 DEFAULT_PREFERENCE = "-1"
 
 DEFAULT_PREFERENCE_at91sam9263ek = "28"
 DEFAULT_PREFERENCE_stb225 = "28"
+DEFAULT_PREFERENCE_collie = "1"
 
 SRC_URI = "${KERNELORG_MIRROR}/pub/linux/kernel/v2.6/linux-2.6.28.tar.bz2 \
            file://defconfig"
@@ -20,3 +21,29 @@ SRC_URI_append_stb225 = " \
            file://ebase-fix.patch;patch=1 \
            file://enable-uart.patch;patch=1 \
            file://ip3902.patch;patch=1"
+
+SRC_URI_append_collie = " \
+       file://0001-collie-start-scoop-converton-to-new-api.patch;patch=1 \
+       file://0002-add-locomo_spi-driver.patch;patch=1 \
+       file://0003-enable-cpufreq-for-collie.patch;patch=1 \
+       file://0004-fix-dma-for-SA1100.patch;patch=1 \
+       file://0005-fix-collie-keyboard-bug.patch;patch=1 \
+       file://0006-add-collie-flash-hack.patch;patch=1 \
+       file://0007-hostap-workaround-for-buggy-sa1100-pcmcia-driver.patch;patch=1 \
+       file://0008-fix-collie-suspend-hack.patch;patch=1 \
+       file://0009-add-sa1100-usb-gadget-driver-hack.patch;patch=1 \
+       file://0010-mmc_spi-add-suspend-and-resume-callbacks.patch;patch=1 \
+       file://0011-move-drivers-mfd-.h-to-include-linux-mfd.patch;patch=1 \
+       file://0012-move-ucb1200-ts-driver.patch;patch=1 \
+       file://0013-add-collie-touchscreen-driver.patch;patch=1 \
+       file://0014-collie-locomo-led-change-default-trigger.patch;patch=1 \
+       file://0015-SA1100-make-gpio_to_irq-and-reverse-a-macro.patch;patch=1 \
+       file://0016-add-gpiolib-support-to-ucb1x00.patch;patch=1 \
+       file://0017-collie-convert-to-gpiolib-for-ucb1x00.patch;patch=1 \
+       file://0018-collie-add-battery-driver.patch;patch=1 \
+       file://0019-collie-support-pda_power-driver.patch;patch=1 \
+       file://0020-remove-collie_pm.c.patch;patch=1 \
+       file://0021-mmc-trivial-annotation-of-blocks.patch;patch=1 \
+       file://0022-mmc_block-print-better-error-messages.patch;patch=1 \
+       file://0023-mmc_block-ensure-all-sectors-that-do-not-have-error.patch;patch=1 " 
+