
#
# Patch managed by http://www.holgerschurig.de/patcher.html
#

--- linux-2.6.10-rc1/drivers/mtd/nand/Kconfig~rp-mtd-sharpsl
+++ linux-2.6.10-rc1/drivers/mtd/nand/Kconfig
@@ -192,4 +192,13 @@
 	  Even if you leave this disabled, you can enable BBT writes at module
 	  load time (assuming you build diskonchip as a module) with the module
 	  parameter "inftl_bbt_write=1".
+	  
+ config MTD_NAND_SHARPSL
+ 	bool "NAND Flash device on Sharp"
+ 	depends on MTD_NAND
+ 
+ config MTD_NAND_POST_BADBLOCK
+     bool "Enable Post Badblock"
+     depends on MTD_NAND
+  
 endmenu
--- linux-2.6.10-rc1/drivers/mtd/nand/Makefile~rp-mtd-sharpsl
+++ linux-2.6.10-rc1/drivers/mtd/nand/Makefile
@@ -18,5 +18,6 @@
 obj-$(CONFIG_MTD_NAND_DISKONCHIP)	+= diskonchip.o
 obj-$(CONFIG_MTD_NAND_H1900)		+= h1910.o
 obj-$(CONFIG_MTD_NAND_RTC_FROM4)	+= rtc_from4.o
+obj-$(CONFIG_MTD_NAND_SHARPSL)		+= sharpsl.o
 
 nand-objs = nand_base.o nand_bbt.o
--- linux-2.6.10-rc1/fs/jffs2/build.c~rp-mtd-sharpsl
+++ linux-2.6.10-rc1/fs/jffs2/build.c
@@ -297,7 +297,14 @@
 
 	c->free_size = c->flash_size;
 	c->nr_blocks = c->flash_size / c->sector_size;
+#if defined(CONFIG_MACH_HUSKY) || defined(CONFIG_ARCH_PXA_TOSA)
+	printk("Trying to alloc_coherent...#%u,#%u\n", c->flash_size,c->sector_size);
+	c->blocks = dma_alloc_coherent(NULL,
+				     sizeof(struct jffs2_eraseblock) * c->nr_blocks,
+				     &c->blocks_phys,GFP_KERNEL);
+#else
 	c->blocks = kmalloc(sizeof(struct jffs2_eraseblock) * c->nr_blocks, GFP_KERNEL);
+#endif
 	if (!c->blocks)
 		return -ENOMEM;
 	for (i=0; i<c->nr_blocks; i++) {
@@ -336,7 +343,13 @@
 		D1(printk(KERN_DEBUG "build_fs failed\n"));
 		jffs2_free_ino_caches(c);
 		jffs2_free_raw_node_refs(c);
+#if defined(CONFIG_MACH_HUSKY) || defined(CONFIG_ARCH_PXA_TOSA)
+		dma_free_coherent(NULL,
+				 sizeof(struct jffs2_eraseblock) * c->nr_blocks,
+				  c->blocks,c->blocks_phys );
+#else
 		kfree(c->blocks);
+#endif
 		return -EIO;
 	}
 
--- linux-2.6.10-rc1/fs/jffs2/fs.c~rp-mtd-sharpsl
+++ linux-2.6.10-rc1/fs/jffs2/fs.c
@@ -463,28 +463,28 @@
 	 */
 	c->sector_size = c->mtd->erasesize; 
 	blocks = c->flash_size / c->sector_size;
-	while ((blocks * sizeof (struct jffs2_eraseblock)) > (128 * 1024)) {
-		blocks >>= 1;
-		c->sector_size <<= 1;
-	}	
+//	while ((blocks * sizeof (struct jffs2_eraseblock)) > (128 * 1024)) {
+//		blocks >>= 1;
+//		c->sector_size <<= 1;
+//	}	
 	
 	/*
 	 * Size alignment check
 	 */
-	if ((c->sector_size * blocks) != c->flash_size) {
-		c->flash_size = c->sector_size * blocks;		
-		printk(KERN_INFO "jffs2: Flash size not aligned to erasesize, reducing to %dKiB\n",
-			c->flash_size / 1024);
-	}
+//	if ((c->sector_size * blocks) != c->flash_size) {
+//		c->flash_size = c->sector_size * blocks;		
+//		printk(KERN_INFO "jffs2: Flash size not aligned to erasesize, reducing to %dKiB\n",
+//			c->flash_size / 1024);
+//	}
 
-	if (c->sector_size != c->mtd->erasesize)
-		printk(KERN_INFO "jffs2: Erase block size too small (%dKiB). Using virtual blocks size (%dKiB) instead\n", 
-			c->mtd->erasesize / 1024, c->sector_size / 1024);
+//	if (c->sector_size != c->mtd->erasesize)
+//		printk(KERN_INFO "jffs2: Erase block size too small (%dKiB). Using virtual blocks size (%dKiB) instead\n", 
+//			c->mtd->erasesize / 1024, c->sector_size / 1024);
 
-	if (c->flash_size < 5*c->sector_size) {
-		printk(KERN_ERR "jffs2: Too few erase blocks (%d)\n", c->flash_size / c->sector_size);
-		return -EINVAL;
-	}
+//	if (c->flash_size < 5*c->sector_size) {
+//		printk(KERN_ERR "jffs2: Too few erase blocks (%d)\n", c->flash_size / c->sector_size);
+//		return -EINVAL;
+//	}
 
 	c->cleanmarker_size = sizeof(struct jffs2_unknown_node);
 	/* Joern -- stick alignment for weird 8-byte-page flash here */
@@ -533,7 +533,13 @@
  out_nodes:
 	jffs2_free_ino_caches(c);
 	jffs2_free_raw_node_refs(c);
+#if defined(CONFIG_MACH_HUSKY) || defined(CONFIG_ARCH_PXA_TOSA)
+	dma_free_coherent(NULL,
+			 sizeof(struct jffs2_eraseblock) * c->nr_blocks,
+			  c->blocks,c->blocks_phys );
+#else
 	kfree(c->blocks);
+#endif
  out_inohash:
 	kfree(c->inocache_list);
  out_wbuf:
--- linux-2.6.10-rc1/fs/jffs2/super.c~rp-mtd-sharpsl
+++ linux-2.6.10-rc1/fs/jffs2/super.c
@@ -266,7 +266,13 @@
 	up(&c->alloc_sem);
 	jffs2_free_ino_caches(c);
 	jffs2_free_raw_node_refs(c);
+#if defined(CONFIG_MACH_HUSKY) || defined(CONFIG_ARCH_PXA_TOSA)
+	dma_free_coherent(NULL,
+			 sizeof(struct jffs2_eraseblock) * c->nr_blocks,
+			  c->blocks,c->blocks_phys );
+#else
 	kfree(c->blocks);
+#endif	
 	jffs2_flash_cleanup(c);
 	kfree(c->inocache_list);
 	if (c->mtd->sync)
--- linux-2.6.10-rc1/fs/jffs2/wbuf.c~rp-mtd-sharpsl
+++ linux-2.6.10-rc1/fs/jffs2/wbuf.c
@@ -11,6 +11,15 @@
  *
  * $Id: wbuf.c,v 1.72 2004/09/11 19:22:43 gleixner Exp $
  *
+ * ChangeLog:
+ *     24-Nov-2002 SHARP  add erasing_dirty_size
+ *     25-Oct-2002 Lineo Japan, Inc.  deal with 1bit corruption of oob area
+ *     08-Oct-2002 Lineo Japan, Inc.  move failure counter pos in oob
+ *     04-Oct-2002 Lineo Japan, Inc.  correct jeb->bad_count value when
+ *       failure count is 0xff
+ *     25-Sep-2002 Lineo Japan, Inc.  take hamming distance for oob value
+ *       into consideration
+ *     17-Sep-2002 Lineo Japan, Inc.  add code for post-badblock  
  */
 
 #include <linux/kernel.h>
@@ -130,6 +139,46 @@
 	}
 }
 
+/*
+ * return true if hamming distance between a and b is <= 1.
+ *
+ * [NOTE]
+ *	assume that higher 3 bytes are zero
+ */
+static inline int jffs2_hamming_distance(unsigned int a, unsigned int b)
+{
+#ifdef __ARM_ARCH_5TE__
+	unsigned int n;
+	a ^= b;
+	asm (
+		"clz	%0, %1\n"
+		: "=r" (n)
+		: "r" (a)
+	);
+	return (a << (n + 1)) == 0;
+#else
+	unsigned int n;
+	a ^= b;
+	for (n = 0; n < 8; n++)
+		if (! (a & ~(1 << n)))
+			return 1;
+	return 0;
+#endif
+}
+
+static inline void jffs2_correct_cleanmarker(unsigned char* oob, unsigned char* correct_data, int len)
+{
+	int i;
+	for (i = 0; i < len; i++)
+		if (jffs2_hamming_distance(oob[i], correct_data[i]))
+			oob[i] = correct_data[i];
+}
+
+/*
+ * correct badblock marker value
+ */
+
+
 /* Recover from failure to write wbuf. Recover the nodes up to the
  * wbuf, not the one which we were starting to try to write. */
 
--- linux-2.6.10-rc1/include/linux/jffs2_fs_sb.h~rp-mtd-sharpsl
+++ linux-2.6.10-rc1/include/linux/jffs2_fs_sb.h
@@ -68,6 +68,10 @@
 						 * from the offset (blocks[ofs / sector_size]) */
 	struct jffs2_eraseblock *nextblock;	/* The block we're currently filling */
 
+#if defined(CONFIG_MACH_HUSKY) || defined(CONFIG_ARCH_PXA_TOSA)
+	dma_addr_t	blocks_phys;
+#endif
+
 	struct jffs2_eraseblock *gcblock;	/* The block we're currently garbage-collecting */
 
 	struct list_head clean_list;		/* Blocks 100% full of clean data */
--- linux-2.6.10-rc1/include/linux/mtd/nand.h~rp-mtd-sharpsl
+++ linux-2.6.10-rc1/include/linux/mtd/nand.h
@@ -49,6 +49,7 @@
  *  05-25-2004 tglx 	added bad block table support, ST-MICRO manufacturer id
  *			update of nand_chip structure description
  */
+
 #ifndef __LINUX_MTD_NAND_H
 #define __LINUX_MTD_NAND_H
 
@@ -298,7 +299,7 @@
 	int		(*block_markbad)(struct mtd_info *mtd, loff_t ofs);
 	void 		(*hwcontrol)(struct mtd_info *mtd, int cmd);
 	int  		(*dev_ready)(struct mtd_info *mtd);
-	void 		(*cmdfunc)(struct mtd_info *mtd, unsigned command, int column, int page_addr);
+	int 		(*cmdfunc)(struct mtd_info *mtd, unsigned command, int column, int page_addr);
 	int 		(*waitfunc)(struct mtd_info *mtd, struct nand_chip *this, int state);
 	int		(*calculate_ecc)(struct mtd_info *mtd, const u_char *dat, u_char *ecc_code);
 	int 		(*correct_data)(struct mtd_info *mtd, u_char *dat, u_char *read_ecc, u_char *calc_ecc);
@@ -331,7 +332,9 @@
 	struct nand_bbt_descr	*bbt_td;
 	struct nand_bbt_descr	*bbt_md;
 	struct nand_hw_control  *controller;
-	void		*priv;
+ 	int		cache_page;
+ 	u_char 		*data_cache;	
+	void		*priv; 	
 };
 
 /*
--- /dev/null
+++ linux-2.6.10-rc1/drivers/mtd/nand/sharpsl.c
@@ -0,0 +1,1092 @@
+/*
+ * drivers/mtd/nand/sharp_sl.c
+ *
+ *  Copyright (C) 2002 Lineo Japan, Inc.
+ *
+ * $Id: sharp_sl.c,v 1.13.2.27 2002/12/10 06:21:15 soka Exp $
+ *
+ * Based on:
+ *
+ *  drivers/mtd/nand/spia.c
+ *
+ *  Copyright (C) 2000 Steven J. Hill (sjhill@cotw.com)
+ *
+ *
+ *	10-29-2001 TG	change to support hardwarespecific access
+ *			to controllines	(due to change in nand.c)
+ *			page_cache added
+ *
+ * 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.
+ *
+ *  Overview:
+ *   This is a device driver for the NAND flash device found on the
+ *   SPIA board which utilizes the Toshiba TC58V64AFT part. This is
+ *   a 64Mibit (8MiB x 8 bits) NAND flash device.
+ *
+ * ChangLog:
+ *     23-Oct-2002 SHARP  add functions for CONFIG_MTD_NAND_LOGICAL_ADDRESS_ACCESS
+ *     14-Mar-2003 Sharp wait for ready
+ */
+#include <linux/genhd.h>
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <linux/delay.h>
+#include <linux/mtd/mtd.h>
+#include <linux/mtd/nand.h>
+#include <linux/mtd/nand_ecc.h>
+#include <linux/mtd/partitions.h>
+#include <linux/interrupt.h>
+#include <asm/io.h>
+#include <asm/hardware.h>
+#ifdef CONFIG_MTD_NAND_LOGICAL_ADDRESS_ACCESS
+#include "sharpsl_logical.h"
+#endif
+
+#include <asm/arch-pxa/corgi.h>
+
+//sharp_sl.phys_base=0x0C000000
+
+static int sharp_sl_io_base = 0;
+static int sharp_sl_phys_base = 0x0C000000;
+
+#define CORGI_CPLD_REG(ofst) (*(volatile unsigned char*)(sharp_sl_io_base+(ofst)))
+
+/* register offset */
+#define CORGI_ECCLPLB		0x00	/* line parity 7 - 0 bit */
+#define CORGI_ECCLPUB		0x04	/* line parity 15 - 8 bit */
+#define CORGI_ECCCP		0x08	/* column parity 5 - 0 bit */
+#define CORGI_ECCCNTR		0x0C	/* ECC byte counter */
+#define CORGI_ECCCLRR		0x10	/* cleare ECC */
+#define CORGI_FLASHIO		0x14	/* Flash I/O */
+#define CORGI_FLASHCTL		0x18	/* Flash Control */
+
+/* Flash control bit */
+#define CORGI_FLRYBY		(1 << 5)
+#define CORGI_FLCE1		(1 << 4)
+#define CORGI_FLWP		(1 << 3)
+#define CORGI_FLALE		(1 << 2)
+#define CORGI_FLCLE		(1 << 1)
+#define CORGI_FLCE0		(1 << 0)
+
+#define NAND_BADBLOCK_POS		5
+#ifdef CONFIG_MTD_NAND_POST_BADBLOCK
+#define NAND_POSTBADBLOCK_POS		4
+#endif
+
+#define NAND_JFFS2_OOB8_FSDAPOS		6
+#define NAND_JFFS2_OOB16_FSDAPOS	8
+#define NAND_JFFS2_OOB8_FSDALEN		2
+#define NAND_JFFS2_OOB16_FSDALEN	8
+
+#define NAND_BUSY_TIMEOUT	1000000
+
+#define MAX_ECC_RETRY 3
+#define MAX_WRITE_RETRIES 32
+#define MAX_COPIES 100
+
+#ifdef CONFIG_MACH_HUSKY
+#define FAILURECOUNTER_POS NAND_POSTBADBLOCK_POS
+#else
+#define FAILURECOUNTER_POS NAND_BADBLOCK_POS
+#endif
+
+/*
+ * MTD structure for Poodle
+ */
+static struct mtd_info *sharp_sl_mtd = NULL;
+
+/*
+ * original nand_* functions pointer
+ */
+static int (*orig_read_ecc)(struct mtd_info*, loff_t, size_t, size_t*, u_char*, u_char*, struct nand_oobinfo *oobsel);
+static int (*orig_write_ecc)(struct mtd_info*, loff_t, size_t, size_t*, const u_char*, u_char*, struct nand_oobinfo *oobsel);
+static int (*orig_writev_ecc)(struct mtd_info*, const struct kvec*, unsigned long, loff_t, size_t*, u_char*, struct nand_oobinfo *oobsel);
+static int (*orig_write_oob)(struct mtd_info*, loff_t, size_t, size_t*, const u_char*);
+
+
+/*
+ * Macros for low-level register control
+ */
+#define nand_select()	this->hwcontrol(mtd,NAND_CTL_SETNCE);
+
+#define nand_deselect() this->hwcontrol(mtd,NAND_CTL_CLRNCE);
+
+
+/*
+ * Define partitions for flash device
+ */
+#define DEFAULT_NUM_PARTITIONS 3
+static struct mtd_info** sharp_sl_nand_part_mtdp;
+static int nr_partitions;
+static struct mtd_partition sharp_sl_nand_default_partition_info[] = {
+    {
+	.name = "NAND flash partition 0",
+	.offset = 0,
+	.size = 7 * 1024 * 1024,
+    },
+    {
+	.name = "NAND flash partition 1",
+	.offset = 7 * 1024 * 1024,
+	.size = 30 * 1024 * 1024,
+    },
+    {
+	.name = "NAND flash partition 2",
+	.offset = 37 * 1024 * 1024,
+	.size = (64 - 37) * 1024 * 1024,
+    },
+};
+static struct mtd_partition* sharp_sl_nand_partition_info;
+
+
+/* 
+ *	hardware specific access to control-lines
+ */
+static void
+sharp_sl_nand_hwcontrol(struct mtd_info* mtd, int cmd)
+{
+    switch (cmd) {
+	case NAND_CTL_SETCLE: CORGI_CPLD_REG(CORGI_FLASHCTL) |= CORGI_FLCLE; break;
+	case NAND_CTL_CLRCLE: CORGI_CPLD_REG(CORGI_FLASHCTL) &= ~CORGI_FLCLE; break;
+
+	case NAND_CTL_SETALE: CORGI_CPLD_REG(CORGI_FLASHCTL) |= CORGI_FLALE; break;
+	case NAND_CTL_CLRALE: CORGI_CPLD_REG(CORGI_FLASHCTL) &= ~CORGI_FLALE; break;
+
+	case NAND_CTL_SETNCE: CORGI_CPLD_REG(CORGI_FLASHCTL) &= ~(CORGI_FLCE0|CORGI_FLCE1); break;
+	case NAND_CTL_CLRNCE: CORGI_CPLD_REG(CORGI_FLASHCTL) |= (CORGI_FLCE0|CORGI_FLCE1); break;
+    }
+}
+
+
+/*
+ *
+ */
+static int
+sharp_sl_nand_command_1(struct mtd_info* mtd,
+			unsigned command,
+			int column,
+			int page_addr)
+{
+    register struct nand_chip *this = mtd->priv;
+    int i;
+
+#ifdef CONFIG_MACH_HUSKY
+	if (command != NAND_CMD_RESET &&
+		command != NAND_CMD_STATUS) {
+		for (i = 0; i < NAND_BUSY_TIMEOUT; i++)
+			if (!sharp_sl_nand_flash_busy())
+				break;
+		if (i == NAND_BUSY_TIMEOUT)
+			return -EIO;
+	}
+#endif
+
+    /* Begin command latch cycle */
+    this->hwcontrol (mtd,NAND_CTL_SETCLE);
+    /*
+     * Write out the command to the device.
+     */
+    if (command != NAND_CMD_SEQIN)
+		this->write_byte(mtd, command);
+    else {
+	if (mtd->oobblock == 256 && column >= 256) {
+	    column -= 256;
+	    this->write_byte(mtd, NAND_CMD_READOOB);
+	    this->write_byte(mtd, NAND_CMD_SEQIN);
+	} else if (mtd->oobblock == 512 && column >= 256) {
+	    if (column < 512) {
+		column -= 256;
+		this->write_byte(mtd, NAND_CMD_READ1);
+		this->write_byte(mtd, NAND_CMD_SEQIN);
+	    } else {
+		column -= 512;
+		this->write_byte(mtd, NAND_CMD_READOOB);
+		this->write_byte(mtd, NAND_CMD_SEQIN);
+	    }
+	} else {
+	    this->write_byte(mtd, NAND_CMD_READ0);
+	    this->write_byte(mtd, NAND_CMD_SEQIN);
+	}
+    }
+
+    /* Set ALE and clear CLE to start address cycle */
+    this->hwcontrol (mtd,NAND_CTL_CLRCLE);
+
+    if (column != -1 || page_addr != -1) {
+	this->hwcontrol (mtd,NAND_CTL_SETALE);
+
+	/* Serially input address */
+	if (column != -1)
+	    this->write_byte(mtd, column);
+	if (page_addr != -1) {
+	    this->write_byte(mtd, (unsigned char) (page_addr & 0xff));
+	    this->write_byte(mtd, (unsigned char) ((page_addr >> 8) & 0xff));
+	    /* One more address cycle for higher density devices */
+	    if (mtd->size & 0x0c000000) 
+		this->write_byte(mtd, (unsigned char) ((page_addr >> 16) & 0x0f));
+	}
+	/* Latch in address */
+	this->hwcontrol (mtd,NAND_CTL_CLRALE);
+    }
+	
+    /* 
+     * program and erase have their own busy handlers 
+     * status and sequential in needs no delay
+     */
+    switch (command) {
+    case NAND_CMD_PAGEPROG:	/* wait in this->waitfunc() */
+    case NAND_CMD_ERASE1:
+    case NAND_CMD_ERASE2:	/* wait in this->waitfunc() */
+    case NAND_CMD_SEQIN:
+    case NAND_CMD_STATUS:
+	return 0;
+
+    case NAND_CMD_RESET:
+	break;
+    }
+	
+    /* wait until command is processed */
+    for (i = 0; i < NAND_BUSY_TIMEOUT; i++)
+	if (this->dev_ready(mtd))
+	    return 0;
+    return -EIO;
+}
+
+
+/*
+ *
+ */
+static int
+sharp_sl_nand_command(struct mtd_info* mtd,
+		      unsigned command,
+		      int column,
+		      int page_addr)
+{
+    if (command == NAND_CMD_SEQIN)
+	/* ignore Ready/Busy error */
+	sharp_sl_nand_command_1(mtd, NAND_CMD_READ0, column, page_addr);
+    return sharp_sl_nand_command_1(mtd, command, column, page_addr);
+}
+
+
+/*
+ *	Get chip for selected access
+ *	(copy from nand.c)
+ */
+static inline void
+nand_get_chip(struct nand_chip *this,
+	      struct mtd_info *mtd,
+	      int new_state)
+{
+
+    DECLARE_WAITQUEUE (wait, current);
+
+    /* 
+     * Grab the lock and see if the device is available 
+     * For erasing, we keep the spinlock until the
+     * erase command is written. 
+     */
+  retry:
+    spin_lock_bh (&this->chip_lock);
+
+    if (this->state == FL_READY) {
+	this->state = new_state;
+	if (new_state != FL_ERASING)
+	    spin_unlock_bh (&this->chip_lock);
+	return;
+    }
+
+#if 0
+    if (this->state == FL_ERASING) {
+	if (new_state != FL_ERASING) {
+	    this->state = new_state;
+	    spin_unlock_bh (&this->chip_lock);
+	    nand_select ();	/* select in any case */
+	    this->cmdfunc(mtd, NAND_CMD_RESET, -1, -1);
+	    return;
+	}
+    }
+#endif
+
+    set_current_state (TASK_UNINTERRUPTIBLE);
+    add_wait_queue (&this->wq, &wait);
+    spin_unlock_bh (&this->chip_lock);
+    schedule ();
+    remove_wait_queue (&this->wq, &wait);
+    goto retry;
+}
+
+
+static inline void
+sharp_sl_nand_read_page(struct mtd_info* mtd,
+			struct nand_chip* this,
+			u_char* data_poi,
+			u_char* oob_data,
+			u_char* ecc_calc,
+			int ecc,
+			int end)
+{
+    int j = 0;
+
+    this->enable_hwecc (mtd,NAND_ECC_READ);	
+    while (j < ecc)
+	data_poi[j++] = readb (this->IO_ADDR_R);
+    this->calculate_ecc (mtd, &data_poi[0], &ecc_calc[0]);	/* read from hardware */
+
+    this->enable_hwecc (mtd,NAND_ECC_READ);	
+    while (j < end)
+	data_poi[j++] = readb (this->IO_ADDR_R);
+    this->calculate_ecc (mtd, &data_poi[256], &ecc_calc[3]); /* read from hardware */
+
+    /* read oobdata */
+    for (j = 0; j <  mtd->oobsize; j++) 
+	oob_data[j] = readb (this->IO_ADDR_R);
+
+}
+
+
+/*
+ * this function is registered only if eccmode == NAND_ECC_HW3_256 &&
+ * oobblock == 512
+ */
+static int
+sharp_sl_nand_read_ecc(struct mtd_info* mtd,
+		       loff_t from,
+		       size_t len,
+		       size_t* retlen,
+		       u_char* buf,
+		       u_char* oob_buf,
+		       struct nand_oobinfo *oobsel)
+{
+    int col, page, end, ecc;
+    int read, ecc_failed, ret;
+    struct nand_chip *this;
+    u_char *oob_data;
+    int *oob_config;
+    u_char* data_poi = 0;
+
+    if (oobsel == NULL)	oobsel = &mtd->oobinfo;
+
+    if (oob_buf || ! oobsel->useecc)
+	return orig_read_ecc(mtd, from, len, retlen, buf, oob_buf, oobsel);
+
+    DEBUG (MTD_DEBUG_LEVEL3, "%s: from = 0x%08x, len = %i\n",
+	   __func__, (unsigned int) from, (int) len);
+
+    /* Do not allow reads past end of device */
+    if ((from + len) > mtd->size) {
+	DEBUG (MTD_DEBUG_LEVEL0, "%s: Attempt read beyond end of device\n", __func__);
+	*retlen = 0;
+	return -EINVAL;
+    }
+
+    /* Grab the lock and see if the device is available */
+    this = mtd->priv;
+    nand_get_chip (this, mtd ,FL_READING);
+
+    /* Select the NAND device */
+    nand_select ();
+
+    oob_config = oobsel->eccpos;
+    page = from >> this->page_shift;
+    col = from & (mtd->oobblock - 1);
+    end = mtd->oobblock;
+    ecc = mtd->eccsize;
+    oob_data = &this->data_buf[end];
+    read = 0;
+    ecc_failed = 0;
+    ret = 0;
+
+    /* Send the read command */
+    if (this->cmdfunc (mtd, NAND_CMD_READ0, 0x00, page)) {
+	printk(KERN_WARNING "%s: Failed in NAND_CMD_READ0 command, page 0x%08x\n",
+	       __func__, page);
+	ret = -EIO;
+	goto nand_read_ecc_exit;
+    }
+	
+    /* Loop until all data read */
+    while (read < len) {
+	int j;
+	int ecc_status;
+	int ecc_retry_counter = 0;
+	u_char ecc_calc[6];
+	u_char ecc_code[6];
+
+	/* 
+	 * If the read is not page aligned, we have to read into data buffer
+	 * due to ecc, else we read into return buffer direct
+	 */
+	if (!col && (len - read) >= end)  
+	    data_poi = &buf[read];
+	else 
+	    data_poi = this->data_buf;
+
+#ifdef CONFIG_MTD_NAND_PAGE_CACHE
+	if (page == this->cache_page) {
+	    memcpy(data_poi, this->data_cache, end);
+
+	    if (this->cmdfunc (mtd, NAND_CMD_READ0, 0x00, page + 1)) {
+		printk(KERN_WARNING "%s: Failed in NAND_CMD_READ0 command,"
+		       " page 0x%08x\n", __func__, page);
+		ret = -EIO;
+		goto nand_read_ecc_exit;
+	    }
+
+	    goto loop_next;
+	}
+#endif
+
+      ecc_retry:
+	sharp_sl_nand_read_page(mtd, this, data_poi, oob_data, ecc_calc, ecc, end);
+
+	/* Pick the ECC bytes out of the oob data */
+	for (j = 0; j < 6; j++)
+	    ecc_code[j] = oob_data[oob_config[j]];
+
+	/* If we have consequent page reads, apply delay or wait for ready/busy pin */
+	for (j = 0; j < NAND_BUSY_TIMEOUT; j++)
+	    if (this->dev_ready(mtd))
+		break;
+	if (j == NAND_BUSY_TIMEOUT) {
+	    ret = -EIO;
+	    goto nand_read_ecc_exit;
+	}
+
+	/* correct data, if neccecary */
+	ecc_status = this->correct_data (mtd, &data_poi[0], &ecc_code[0], &ecc_calc[0]);
+	if (ecc_status == -1) {
+	    if (ecc_retry_counter++ < MAX_ECC_RETRY) {
+		this->cmdfunc (mtd, NAND_CMD_RESET, -1, -1);
+		if (this->cmdfunc (mtd, NAND_CMD_READ0, 0x00, page)) {
+		    printk(KERN_WARNING
+			   "%s: Failed in NAND_CMD_READ0 command, page 0x%08x\n",
+			   __func__, page);
+		    ret = -EIO;
+		    goto nand_read_ecc_exit;
+		}
+		goto ecc_retry;
+	    }
+	    else {
+		printk (KERN_WARNING "%s: Failed ECC read, page 0x%08x\n",
+			__func__, page);
+		ecc_failed++;
+	    }
+	}
+		
+	ecc_status = this->correct_data (mtd, &data_poi[256], &ecc_code[3], &ecc_calc[3]);
+	if (ecc_status == -1) {
+	    if (ecc_retry_counter++ < MAX_ECC_RETRY) {
+		this->cmdfunc (mtd, NAND_CMD_RESET, -1, -1);
+		if (this->cmdfunc (mtd, NAND_CMD_READ0, 0x00, page)) {
+		    printk(KERN_WARNING
+			   "%s: Failed in NAND_CMD_READ0 command, page 0x%08x\n",
+			   __func__, page);
+		    ret = -EIO;
+		    goto nand_read_ecc_exit;
+		}
+		goto ecc_retry;
+	    }
+	    else {
+		printk (KERN_WARNING "%s: Failed ECC read, page 0x%08x\n",
+			__func__, page);
+		ecc_failed++;
+	    }
+	}
+
+#ifdef CONFIG_MTD_NAND_PAGE_CACHE
+      loop_next:
+#endif
+	if (col || (len - read) < end) { 
+	    for (j = col; j < end && read < len; j++)
+		buf[read++] = data_poi[j];
+	} else		
+	    read += mtd->oobblock;
+	/* For subsequent reads align to page boundary. */
+	col = 0;
+	/* Increment page address */
+	page++;
+    }
+
+  nand_read_ecc_exit:
+    ret = (ret == 0) ? (ecc_failed ? -EIO : 0) : ret;
+    if (ret == -EIO)
+	this->cmdfunc(mtd, NAND_CMD_RESET, -1, -1);
+#ifdef CONFIG_MTD_NAND_PAGE_CACHE
+    else if (page - 1 != this->cache_page && data_poi) {
+	memcpy(this->data_cache, data_poi, end);
+	this->cache_page = page - 1;
+    }
+#endif
+
+    /* De-select the NAND device */
+    nand_deselect ();
+
+    /* Wake up anyone waiting on the device */
+    spin_lock_bh (&this->chip_lock);
+    this->state = FL_READY;
+    wake_up (&this->wq);
+    spin_unlock_bh (&this->chip_lock);
+
+    /*
+     * Return success, if no ECC failures, else -EIO
+     * fs driver will take care of that, because
+     * retlen == desired len and result == -EIO
+     */
+    *retlen = read;
+    return ret;
+}
+
+
+static int
+sharp_sl_nand_read(struct mtd_info* mtd,
+		   loff_t from,
+		   size_t len,
+		   size_t* retlen,
+		   u_char* buf)
+{
+    return sharp_sl_nand_read_ecc(mtd, from, len, retlen, buf, NULL, NULL);
+    //FIXME - NAND_JFFS2_OOB
+}
+
+
+static inline int jffs2_hamming_distance(unsigned int a, unsigned int b)
+{
+#ifdef __ARM_ARCH_5TE__
+	unsigned int n;
+	a ^= b;
+	asm (
+		"clz	%0, %1\n"
+		: "=r" (n)
+		: "r" (a)
+	);
+	return (a << (n + 1)) == 0;
+#else
+	unsigned int n;
+	a ^= b;
+	for (n = 0; n < 8; n++)
+		if (! (a & ~(1 << n)))
+			return 1;
+	return 0;
+#endif
+}
+
+
+static inline void
+jffs2_correct_badblock_val(u_char* oob)
+{
+#ifdef CONFIG_MTD_NAND_POST_BADBLOCK
+    if (jffs2_hamming_distance(oob[NAND_POSTBADBLOCK_POS], 0xff))
+	oob[NAND_POSTBADBLOCK_POS] = 0xff;
+#endif
+    if (jffs2_hamming_distance(oob[NAND_BADBLOCK_POS], 0xff))
+	oob[NAND_BADBLOCK_POS] = 0xff;
+}
+
+
+static inline void
+jffs2_correct_failedblock_val(u_char* oob)
+{
+    if (jffs2_hamming_distance(oob[FAILURECOUNTER_POS], 0xff))
+	oob[FAILURECOUNTER_POS] = 0xff;
+}
+
+
+static inline void
+jffs2_correct_cleanmarker(u_char* oob,
+			  u_char* correct_data,
+			  int len)
+{
+    int i;
+    for (i = 0; i < len; i++)
+	if (jffs2_hamming_distance(oob[i], correct_data[i]))
+	    oob[i] = correct_data[i];
+}
+
+
+static int
+sharp_sl_nand_prepare_rewrite(struct mtd_info* mtd,
+			      loff_t to,
+			       struct nand_oobinfo *oobsel)
+{
+    int i;
+    loff_t block_addr = to & ~(mtd->erasesize - 1);
+    size_t len = to & (mtd->erasesize - 1);
+    int nr_oobpages = 2;	// JFFS2 only (JFFS2 uses only 2 oobpages)
+    int fsdata_pos = (mtd->oobblock == 256)
+	? NAND_JFFS2_OOB8_FSDAPOS : NAND_JFFS2_OOB16_FSDAPOS;
+    int fsdata_len = (mtd->oobblock == 256)
+	? NAND_JFFS2_OOB8_FSDALEN : NAND_JFFS2_OOB16_FSDALEN;
+    u_char* block_buf;
+    u_char* oob_buf;
+    int ret;
+    int retlen;
+    struct erase_info instr;
+
+    block_buf = kmalloc(len, GFP_KERNEL);
+    if (! block_buf) {
+	printk("Unable to allocate NAND block buffer (%u)\n", len);
+	return -EIO;
+    }
+    oob_buf = kmalloc(mtd->oobsize * nr_oobpages, GFP_KERNEL);
+    if (! oob_buf) {
+	printk("Unable to allocate NAND oob buffer\n");
+	kfree(block_buf);
+	return -EIO;
+    }
+
+    ret = mtd->read_ecc(mtd, block_addr, len, &retlen, block_buf, NULL, NULL);
+     //NAND_JFFS2_OOB
+    if (ret || retlen != len) {
+	DEBUG(MTD_DEBUG_LEVEL0, "%s: read_ecc failed (%d)\n", __func__, ret);
+	kfree(block_buf);
+	kfree(oob_buf);
+	return ret ? ret : -EIO;
+    }
+
+    ret = mtd->read_oob(mtd, block_addr, mtd->oobsize * nr_oobpages, &retlen, oob_buf);
+    if (ret || retlen != mtd->oobsize * nr_oobpages) {
+	DEBUG(MTD_DEBUG_LEVEL0, "%s: read_oob failed (%d)\n", __func__, ret);
+	kfree(block_buf);
+	kfree(oob_buf);
+	return ret ? ret : -EIO;
+    }
+#if 1			/* FIXME */
+    {
+	struct {
+	    /* All start like this */
+	    uint16_t magic;
+	    uint16_t nodetype;
+	    uint32_t totlen; /* So we can skip over nodes we don't grok */
+	} __attribute__((packed)) n = {
+	    .magic = 0x1985,
+	    .nodetype = 0x2003,
+	    .totlen = 8,
+	};
+	u_char* p;
+
+	p = (u_char*)&n;
+
+	jffs2_correct_badblock_val(oob_buf);
+	jffs2_correct_failedblock_val(&oob_buf[mtd->oobsize]);
+	jffs2_correct_cleanmarker(&oob_buf[fsdata_pos], p, fsdata_len);
+    }
+#endif
+
+    for (i = 0; i < MAX_COPIES; i++) {
+	int j;
+
+	memset(&instr, 0, sizeof instr);
+	instr.mtd = mtd;
+	instr.addr = block_addr;
+	instr.len = mtd->erasesize;
+	ret = mtd->erase(mtd, &instr);
+	if (ret) {
+	    DEBUG(MTD_DEBUG_LEVEL0, "%s: erase failed (%d)\n", __func__, ret);
+	    continue;
+	}
+
+	ret = orig_write_ecc(mtd, block_addr, len, &retlen, block_buf, NULL, NULL);
+	//		     NAND_JFFS2_OOB);
+	if (ret || retlen != len) {
+	    DEBUG(MTD_DEBUG_LEVEL0, "%s: write_ecc failed (%d)\n", __func__, ret);
+	    continue;
+	}
+
+	for (j = 0; j < nr_oobpages; j++) {
+	    loff_t addr = block_addr + mtd->oobblock * j;
+
+#ifdef CONFIG_MTD_NAND_POST_BADBLOCK
+	    ret = orig_write_oob(mtd, addr + NAND_POSTBADBLOCK_POS, 1, &retlen,
+				 oob_buf + mtd->oobsize * j + NAND_POSTBADBLOCK_POS);
+	    if (ret || retlen != 1) {
+		DEBUG(MTD_DEBUG_LEVEL0, "%s: write_oob post_badblock(%d) failed (%d)\n",
+		      __func__, j, ret);
+		break;
+	    }
+#endif
+
+	    ret = orig_write_oob(mtd, addr + NAND_BADBLOCK_POS, 1, &retlen,
+				 oob_buf + mtd->oobsize * j + NAND_BADBLOCK_POS);
+	    if (ret || retlen != 1) {
+		DEBUG(MTD_DEBUG_LEVEL0, "%s: write_oob badblock(%d) failed (%d)\n",
+		      __func__, j, ret);
+		break;
+	    }
+
+	    ret = orig_write_oob(mtd, addr + fsdata_pos, fsdata_len, &retlen,
+				 oob_buf + mtd->oobsize * j + fsdata_pos);
+	    if (ret || retlen != fsdata_len) {
+		DEBUG(MTD_DEBUG_LEVEL0, "%s: write_oob fsdata(%d) failed (%d)\n",
+		      __func__, j, ret);
+		break;
+	    }
+	}
+	if (j < nr_oobpages)
+	    continue;
+
+	break;
+    }
+
+    kfree(block_buf);
+    kfree(oob_buf);
+    DEBUG(MTD_DEBUG_LEVEL0,
+	  "%s: %d\n", __func__, (i < MAX_COPIES) ? 0 : (ret ? ret : -EIO));
+    return (i < MAX_COPIES) ? 0 : (ret ? ret : -EIO);
+}
+			      
+
+static int
+sharp_sl_nand_write_ecc(struct mtd_info* mtd,
+			loff_t to,
+			size_t len,
+			size_t* retlen,
+			const u_char* buf,
+			u_char* eccbuf,
+			struct nand_oobinfo *oobsel)
+{
+    int i;
+    int ret;
+
+    for (i = 0; i < MAX_WRITE_RETRIES; i++) {
+	ret = orig_write_ecc(mtd, to, len, retlen, buf, eccbuf, oobsel);
+	if (ret != -EIO)
+	    return ret;
+
+	ret = sharp_sl_nand_prepare_rewrite(mtd, to, oobsel);
+	if (ret)
+	    return ret;
+    }
+    return -EIO;
+}
+
+
+static int
+sharp_sl_nand_write(struct mtd_info* mtd,
+		    loff_t to,
+		    size_t len,
+		    size_t* retlen,
+		    const u_char* buf)
+{
+    return sharp_sl_nand_write_ecc(mtd, to, len, retlen, buf, NULL, NULL);
+    //NAND_JFFS2_OOB);
+}
+
+
+static int
+sharp_sl_nand_writev_ecc(struct mtd_info* mtd,
+			 const struct kvec* vecs,
+			 unsigned long count,
+			 loff_t to,
+			 size_t* retlen,
+			 u_char* eccbuf,
+			 struct nand_oobinfo *oobsel)
+{
+    int i;
+    int ret;
+
+    for (i = 0; i < MAX_WRITE_RETRIES; i++) {
+	ret = orig_writev_ecc(mtd, vecs, count, to, retlen, eccbuf, oobsel);
+	if (ret != -EIO)
+	    return ret;
+
+	ret = sharp_sl_nand_prepare_rewrite(mtd, to, oobsel);
+	if (ret)
+	    return ret;
+    }
+    return -EIO;
+}
+
+
+static int
+sharp_sl_nand_writev(struct mtd_info* mtd,
+		     const struct kvec* vecs,
+		     unsigned long count,
+		     loff_t to,
+		     size_t* retlen)
+{
+    return sharp_sl_nand_writev_ecc(mtd, vecs, count, to, retlen, NULL, NULL);
+    //NAND_JFFS2_OOB);
+}
+
+
+static int
+sharp_sl_nand_write_oob(struct mtd_info* mtd,
+			loff_t to,
+			size_t len,
+			size_t* retlen,
+			const u_char* buf)
+{
+    int i;
+    int ret;
+
+    for (i = 0; i < MAX_WRITE_RETRIES; i++) {
+	ret = orig_write_oob(mtd, to, len, retlen, buf);
+	if (ret != -EIO)
+	    return ret;
+
+	ret = sharp_sl_nand_prepare_rewrite(mtd, to & ~(mtd->erasesize - 1),	// JFFS2 only (JFFS2 calls write_oob only after erasing)
+					    NULL);
+	if (ret)
+	    return ret;
+    }
+    return -EIO;
+}
+
+
+static int
+sharp_sl_nand_flash_busy(void)
+{
+    return (CORGI_CPLD_REG(CORGI_FLASHCTL) & CORGI_FLRYBY) == 0;
+}
+
+
+/*
+ *
+ */
+static int
+sharp_sl_nand_dev_ready(struct mtd_info* mtd)
+{
+    int i;
+    for (i = 0; i < 5; i++)
+	sharp_sl_nand_flash_busy();
+
+    return ! sharp_sl_nand_flash_busy();
+}
+
+
+/*
+ *
+ */
+static int
+sharp_sl_nand_suspend(struct mtd_info* mtd)
+{
+    int i;
+    printk("%s", __func__);
+    for (i = 0; i < nr_partitions; i++) {
+	__invalidate_device(MKDEV(MTD_BLOCK_MAJOR, sharp_sl_nand_part_mtdp[i]->index), 1);
+    }
+    mtd->sync(mtd);
+
+    printk("\n");
+    return 0;
+}
+
+
+/*
+ *
+ */
+static void
+sharp_sl_nand_resume(struct mtd_info* mtd)
+{
+    printk("%s\n", __func__);
+}
+
+
+/*
+ *
+ */
+static void
+sharp_sl_nand_enable_hwecc(struct mtd_info* mtd, int mode)
+{
+    CORGI_CPLD_REG(CORGI_ECCCLRR) = 0;
+}
+
+
+/*
+ *
+ */
+static int
+sharp_sl_nand_calculate_ecc(struct mtd_info* mtd, const u_char* dat,
+			    u_char* ecc_code)
+{
+    ecc_code[0] = ~CORGI_CPLD_REG(CORGI_ECCLPUB);
+    ecc_code[1] = ~CORGI_CPLD_REG(CORGI_ECCLPLB);
+    ecc_code[2] = (~CORGI_CPLD_REG(CORGI_ECCCP) << 2) | 0x03;
+    return CORGI_CPLD_REG(CORGI_ECCCNTR) != 0;
+}
+
+
+#ifdef CONFIG_MTD_PARTITIONS
+const char *part_probes[] = { "cmdlinepart", NULL };
+#endif
+
+
+/*
+ * Main initialization routine
+ */
+int __init
+sharp_sl_nand_init (void)
+{
+    extern int parse_cmdline_partitions(struct mtd_info *, struct mtd_partition **,
+					const char *);
+    struct nand_chip *this;
+    int i;
+	int err = 0;
+
+    /* Allocate memory for MTD device structure and private data */
+    sharp_sl_mtd = kmalloc (sizeof(struct mtd_info) + sizeof (struct nand_chip),
+			    GFP_KERNEL);
+    if (!sharp_sl_mtd) {
+	printk ("Unable to allocate SharpSL NAND MTD device structure.\n");
+	err = -ENOMEM;
+	goto out;
+    }
+    
+	/* map physical adress */
+	sharp_sl_io_base = (unsigned long)ioremap(sharp_sl_phys_base, 0x1000);
+	if(!sharp_sl_io_base){
+		printk("ioremap to access Sharp SL NAND chip failed\n");
+		err = -EIO;
+		goto out_mtd;
+	}
+
+    /* Get pointer to private data */
+    this = (struct nand_chip *) (&sharp_sl_mtd[1]);
+
+    /* Initialize structures */
+    memset((char *) sharp_sl_mtd, 0, sizeof(struct mtd_info));
+    memset((char *) this, 0, sizeof(struct nand_chip));
+
+    /* Link the private data with the MTD structure */
+    sharp_sl_mtd->priv = this;
+
+    /*
+     * PXA initialize
+     */
+    CORGI_CPLD_REG(CORGI_FLASHCTL) |= CORGI_FLWP;
+
+    /* Set address of NAND IO lines */
+	this->IO_ADDR_R = sharp_sl_io_base + CORGI_FLASHIO;
+	this->IO_ADDR_W = sharp_sl_io_base + CORGI_FLASHIO;
+    /* Set address of hardware control function */
+    this->hwcontrol = sharp_sl_nand_hwcontrol;
+    this->dev_ready = sharp_sl_nand_dev_ready;
+    this->cmdfunc = sharp_sl_nand_command;
+    /* 15 us command delay time */
+    this->chip_delay = 15;
+    /* set eccmode using hardware ECC */
+    this->eccmode = NAND_ECC_HW3_256;
+    this->enable_hwecc = sharp_sl_nand_enable_hwecc;
+    this->calculate_ecc = sharp_sl_nand_calculate_ecc;
+    this->correct_data = nand_correct_data;
+
+
+    /* Scan to find existence of the device */
+    if (nand_scan (sharp_sl_mtd,1)) {
+	kfree (sharp_sl_mtd);
+	return -ENXIO;
+    }
+
+    if (this->eccmode == NAND_ECC_HW3_256 && sharp_sl_mtd->oobblock == 512) {
+	orig_read_ecc = sharp_sl_mtd->read_ecc;
+	sharp_sl_mtd->read = sharp_sl_nand_read;
+	sharp_sl_mtd->read_ecc = sharp_sl_nand_read_ecc;
+
+	orig_write_ecc = sharp_sl_mtd->write_ecc;
+	sharp_sl_mtd->write = sharp_sl_nand_write;
+	sharp_sl_mtd->write_ecc = sharp_sl_nand_write_ecc;
+
+	orig_writev_ecc = sharp_sl_mtd->writev_ecc;
+	sharp_sl_mtd->writev = sharp_sl_nand_writev;
+	sharp_sl_mtd->writev_ecc = sharp_sl_nand_writev_ecc;
+
+	orig_write_oob = sharp_sl_mtd->write_oob;
+	sharp_sl_mtd->write_oob = sharp_sl_nand_write_oob;
+    }
+    sharp_sl_mtd->suspend = sharp_sl_nand_suspend;
+    sharp_sl_mtd->resume = sharp_sl_nand_resume;
+#ifdef CONFIG_MTD_NAND_LOGICAL_ADDRESS_ACCESS
+    sharp_sl_mtd->cleanup_laddr = sharp_sl_nand_cleanup_laddr;
+    sharp_sl_mtd->read_laddr = sharp_sl_nand_read_laddr;
+    sharp_sl_mtd->write_laddr = sharp_sl_nand_write_laddr;
+#endif
+    /* Allocate memory for internal data buffer */
+    this->data_buf = kmalloc (sizeof(u_char) * (sharp_sl_mtd->oobblock + sharp_sl_mtd->oobsize), GFP_KERNEL);
+    if (!this->data_buf) {
+	printk ("Unable to allocate NAND data buffer for Poodle.\n");
+	kfree (sharp_sl_mtd);
+	return -ENOMEM;
+    }
+    /* Allocate memory for internal data buffer */
+    this->data_cache = kmalloc (sizeof(u_char) * (sharp_sl_mtd->oobblock + sharp_sl_mtd->oobsize), GFP_KERNEL);
+    if (!this->data_cache) {
+	printk ("Unable to allocate NAND data cache for Poodle.\n");
+	kfree (this->data_buf);
+	kfree (sharp_sl_mtd);
+	return -ENOMEM;
+    }
+
+    /* Register the partitions */
+    sharp_sl_mtd->name = "sharpsl-nand";
+	nr_partitions = parse_mtd_partitions(sharp_sl_mtd, part_probes,
+					    &sharp_sl_nand_partition_info, 0);
+					     
+    if (nr_partitions <= 0) {
+		nr_partitions = DEFAULT_NUM_PARTITIONS;
+		sharp_sl_nand_partition_info = sharp_sl_nand_default_partition_info;
+    }
+
+    sharp_sl_nand_part_mtdp = kmalloc(sizeof (struct mtd_info*) * nr_partitions,
+				      GFP_KERNEL);
+    if (! sharp_sl_nand_part_mtdp) {
+	printk("Unable to allocate memory for sharp_sl_nand_part_mtdp\n");
+	kfree(this->data_buf);
+	kfree(this->data_cache);
+	kfree(sharp_sl_mtd);
+	return -ENOMEM;
+    }
+
+    for (i = 0; i < nr_partitions; i++)
+	sharp_sl_nand_partition_info[i].mtdp = &sharp_sl_nand_part_mtdp[i];
+    add_mtd_partitions(sharp_sl_mtd, sharp_sl_nand_partition_info, nr_partitions);
+
+    for (i = 0; i < nr_partitions; i++)
+	add_mtd_device(sharp_sl_nand_part_mtdp[i]);
+
+#ifdef DEBUG_PROC
+    struct proc_dir_entry* res = create_proc_read_entry("mtd-debug", 0, NULL, sharp_sl_nand_read_proc, NULL);
+    res->write_proc = sharp_sl_nand_write_proc;
+#endif
+
+    /* Return happy */
+    return 0;
+out_mtd:
+	kfree (sharp_sl_mtd);
+out:
+	return err;    
+}
+module_init(sharp_sl_nand_init);
+
+/*
+ * Clean up routine
+ */
+#ifdef MODULE
+static void __exit sharp_sl_nand_cleanup (void)
+{
+	struct nand_chip *this = (struct nand_chip *) &sharp_sl_mtd[1];
+
+	/* Unregister the device */
+	del_mtd_partitions (sharp_sl_mtd);
+	int i;
+	for (i = 0; i < NUM_PARTITIONS)
+	    del_mtd_device (sharp_sl_nand_part_mtdp[i]);
+
+	/* Free internal data buffer */
+	kfree (this->data_buf);
+	kfree (this->data_cache);
+	kfree (this->page_cache);
+
+	/* Free the MTD device structure */
+	kfree (sharp_sl_nand_part_mtdp);
+	if (sharp_sl_nand_partition_info != sharp_sl_nand_default_partition_info)
+	    kfree (sharp_sl_nand_partition_info);
+	kfree (sharp_sl_mtd);
+}
+module_exit(sharp_sl_nand_cleanup);
+#endif
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Lineo Japan, Inc.");
+MODULE_DESCRIPTION("Board-specific glue layer for NAND flash on Poodle");
--- linux-2.6.10-rc1/fs/jffs2/compr.h~rp-mtd-sharpsl
+++ linux-2.6.10-rc1/fs/jffs2/compr.h
@@ -36,6 +36,7 @@
 
 #define JFFS2_RUBINMIPS_DISABLED /* RUBINs will be used only */
 #define JFFS2_DYNRUBIN_DISABLED  /*        for decompression */
+#define JFFS2_RTIME_DISABLED
 
 #define JFFS2_COMPR_MODE_NONE       0
 #define JFFS2_COMPR_MODE_PRIORITY   1
--- linux-2.6.10-rc1/drivers/mtd/nand/nand_base.c~rp-mtd-sharpsl
+++ linux-2.6.10-rc1/drivers/mtd/nand/nand_base.c
@@ -49,6 +49,23 @@
  *
  */
 
+/*
+ * ChangLog:
+ *     09-Nov-2002 Lineo Japan, Inc.  add NAND page read cache
+ *     01-Nov-2002 Lineo Japan, Inc.  retry NAND_CMD_SEQIN at calculate_ecc() error
+ *     29-Oct-2002 Lineo Japan, Inc.  modify calculate_ecc return type
+ *				      emit NAND_CMD_RESET command at I/O error
+ *     27-Sep-2002 Lineo Japan, Inc.  modify local variable declarations
+ *     26-Sep-2002 Lineo Japan, Inc.  take hamming distance into consideration
+ *     20-Sep-2002 Lineo Japan, Inc.  modify error message
+ *				      FL_ERASING waits until FL_READY
+ *     19-Sep-2002 Lineo Japan, Inc.  modify nand_command() return type
+ *				      add erase-by-force mode
+ *     18-Sep-2002 Lineo Japan, Inc.  add dev_ready() call after read
+ *     17-Sep-2002 Lineo Japan, Inc.  add code for post-badblock
+ *     09-Sep-2003 SHARP              support TC6393XB controller for Tosa
+ */
+
 #include <linux/delay.h>
 #include <linux/errno.h>
 #include <linux/sched.h>
@@ -500,7 +517,7 @@
  * Send command to NAND device. This function is used for small page
  * devices (256/512 Bytes per page)
  */
-static void nand_command (struct mtd_info *mtd, unsigned command, int column, int page_addr)
+static int nand_command (struct mtd_info *mtd, unsigned command, int column, int page_addr)
 {
 	register struct nand_chip *this = mtd->priv;
 
@@ -562,7 +579,7 @@
 	case NAND_CMD_ERASE2:
 	case NAND_CMD_SEQIN:
 	case NAND_CMD_STATUS:
-		return;
+		return 0;
 
 	case NAND_CMD_RESET:
 		if (this->dev_ready)	
@@ -572,7 +589,7 @@
 		this->write_byte(mtd, NAND_CMD_STATUS);
 		this->hwcontrol(mtd, NAND_CTL_CLRCLE);
 		while ( !(this->read_byte(mtd) & 0x40));
-		return;
+		return 0;
 
 	/* This applies to read commands */	
 	default:
@@ -582,7 +599,7 @@
 		*/
 		if (!this->dev_ready) {
 			udelay (this->chip_delay);
-			return;
+			return 0;
 		}	
 	}
 	
@@ -591,6 +608,8 @@
 	ndelay (100);
 	/* wait until command is processed */
 	while (!this->dev_ready(mtd));
+	
+	return 0;
 }
 
 /**
@@ -815,6 +834,9 @@
 	int  	*oob_config = oobsel->eccpos;
 	int	datidx = 0, eccidx = 0, eccsteps = this->eccsteps;
 	int	eccbytes = 0;
+
+	if (this->cache_page == page)
+		this->cache_page = -1;
 	
 	/* FIXME: Enable cached programming */
 	cached = 0;
@@ -1759,6 +1781,11 @@
 		/* write data */
 		this->write_buf(mtd, buf, len);
 	}
+
+	/* Invalidate cache, if we write to this page */
+	if (this->cache_page == page)
+		this->cache_page = -1;
+	
 	/* Send command to program the OOB data */
 	this->cmdfunc (mtd, NAND_CMD_PAGEPROG, -1, -1);
 
@@ -2098,6 +2125,10 @@
 		
 		status = this->waitfunc (mtd, this, FL_ERASING);
 
+		/* Invalidate cache, if last_page is inside erase-block */
+		if (this->cache_page >= page && this->cache_page < (page + pages_per_block))
+			this->cache_page = -1;
+
 		/* See if block erase succeeded */
 		if (status & 0x01) {
 			DEBUG (MTD_DEBUG_LEVEL0, "nand_erase: " "Failed erase, page 0x%08x\n", page);
@@ -2241,6 +2272,9 @@
 	if (!this->scan_bbt)
 		this->scan_bbt = nand_default_bbt;
 
+	/* make sure, that cache page is invalid */
+	this->cache_page = -1;
+
 	/* Select the device */
 	this->select_chip(mtd, 0);
 

