vserver 1.9.5.x5
[linux-2.6.git] / drivers / mtd / maps / sa1100-flash.c
index bb9c077..0a6f861 100644 (file)
@@ -3,9 +3,8 @@
  * 
  * (C) 2000 Nicolas Pitre <nico@cam.org>
  * 
- * $Id: sa1100-flash.c,v 1.39 2004/07/12 21:59:44 dwmw2 Exp $
+ * $Id: sa1100-flash.c,v 1.47 2004/11/01 13:44:36 rmk Exp $
  */
-
 #include <linux/config.h>
 #include <linux/module.h>
 #include <linux/types.h>
 #include <linux/init.h>
 #include <linux/errno.h>
 #include <linux/slab.h>
+#include <linux/device.h>
+#include <linux/err.h>
 
 #include <linux/mtd/mtd.h>
 #include <linux/mtd/map.h>
 #include <linux/mtd/partitions.h>
 #include <linux/mtd/concat.h>
 
-#include <asm/hardware.h>
 #include <asm/mach-types.h>
 #include <asm/io.h>
 #include <asm/sizes.h>
+#include <asm/mach/flash.h>
 
-#include <asm/arch/h3600.h>
-
-#ifndef CONFIG_ARCH_SA1100
-#error This is for SA1100 architecture only
-#endif
-
-/*
- * This isnt complete yet, so...
- */
-#define CONFIG_MTD_SA1100_STATICMAP 1
-
-#ifdef CONFIG_MTD_SA1100_STATICMAP
-/*
- * Here are partition information for all known SA1100-based devices.
- * See include/linux/mtd/partitions.h for definition of the mtd_partition
- * structure.
- *
- * Please note:
- *  1. We no longer support static flash mappings via the machine io_desc
- *     structure.
- *  2. The flash size given should be the largest flash size that can
- *     be accommodated.
- *
- * The MTD layer will detect flash chip aliasing and reduce the size of
- * the map accordingly.
- *
- * Please keep these in alphabetical order, and formatted as per existing
- * entries.  Thanks.
- */
-
-#ifdef CONFIG_SA1100_ADSBITSY
-static struct mtd_partition adsbitsy_partitions[] = {
-       {
-               .name           = "bootROM",
-               .size           = 0x80000,
-               .offset         = 0,
-               .mask_flags     = MTD_WRITEABLE,  /* force read-only */
-       }, {
-               .name           = "zImage",
-               .size           = 0x100000,
-               .offset         = MTDPART_OFS_APPEND,
-               .mask_flags     = MTD_WRITEABLE,  /* force read-only */
-       }, {
-               .name           = "ramdisk.gz",
-               .size           = 0x300000,
-               .offset         = MTDPART_OFS_APPEND,
-               .mask_flags     = MTD_WRITEABLE,  /* force read-only */
-       }, {
-               .name           = "User FS",
-               .size           = MTDPART_SIZ_FULL,
-               .offset         = MTDPART_OFS_APPEND,
-       }
-};
-#endif
-
-#ifdef CONFIG_SA1100_ASSABET
-/* Phase 4 Assabet has two 28F160B3 flash parts in bank 0: */
-static struct mtd_partition assabet4_partitions[] = {
-       {
-               .name           = "bootloader",
-               .size           = 0x00020000,
-               .offset         = 0,
-               .mask_flags     = MTD_WRITEABLE,
-       }, {
-               .name           = "bootloader params",
-               .size           = 0x00020000,
-               .offset         = MTDPART_OFS_APPEND,
-               .mask_flags     = MTD_WRITEABLE,
-       }, {
-               .name           = "jffs",
-               .size           = MTDPART_SIZ_FULL,
-               .offset         = MTDPART_OFS_APPEND,
-       }
-};
-
-/* Phase 5 Assabet has two 28F128J3A flash parts in bank 0: */
-static struct mtd_partition assabet5_partitions[] = {
-       {
-               .name           = "bootloader",
-               .size           = 0x00040000,
-               .offset         = 0,
-               .mask_flags     = MTD_WRITEABLE,
-       }, {
-               .name           = "bootloader params",
-               .size           = 0x00040000,
-               .offset         = MTDPART_OFS_APPEND,
-               .mask_flags     = MTD_WRITEABLE,
-       }, {
-               .name           = "jffs",
-               .size           = MTDPART_SIZ_FULL,
-               .offset         = MTDPART_OFS_APPEND,
-       }
-};
-
-#define assabet_partitions     assabet5_partitions
-#endif
-
-#ifdef CONFIG_SA1100_BADGE4
+#if 0
 /*
- * 1 x Intel 28F320C3 Advanced+ Boot Block Flash (32 Mi bit)
- *   Eight 4 KiW Parameter Bottom Blocks (64 KiB)
- *   Sixty-three 32 KiW Main Blocks (4032 Ki b)
- *
- * <or>
- *
- * 1 x Intel 28F640C3 Advanced+ Boot Block Flash (64 Mi bit)
- *   Eight 4 KiW Parameter Bottom Blocks (64 KiB)
- *   One-hundred-twenty-seven 32 KiW Main Blocks (8128 Ki b)
- */
-static struct mtd_partition badge4_partitions[] = {
-       {
-               .name           = "BLOB boot loader",
-               .offset         = 0,
-               .size           = 0x0000A000
-       }, {
-               .name           = "params",
-               .offset         = MTDPART_OFS_APPEND,
-               .size           = 0x00006000
-       }, {
-               .name           = "root",
-               .offset         = MTDPART_OFS_APPEND,
-               .size           = MTDPART_SIZ_FULL
-       }
-};
-#endif
-
-
-#ifdef CONFIG_SA1100_CERF
-#ifdef CONFIG_SA1100_CERF_FLASH_32MB
-#  define CERF_FLASH_SIZE      0x02000000
-#elif defined CONFIG_SA1100_CERF_FLASH_16MB
-#  define CERF_FLASH_SIZE      0x01000000
-#elif defined CONFIG_SA1100_CERF_FLASH_8MB
-#  define CERF_FLASH_SIZE      0x00800000
-#else
-#  error "Undefined flash size for CERF in sa1100-flash.c"
-#endif
-
-static struct mtd_partition cerf_partitions[] = {
-       {
-               .name           = "Bootloader",
-               .size           = 0x00020000,
-               .offset         = 0x00000000,
-       }, {
-               .name           = "Params",
-               .size           = 0x00040000,
-               .offset         = 0x00020000,
-       }, {
-               .name           = "Kernel",
-               .size           = 0x00100000,
-               .offset         = 0x00060000,
-       }, {
-               .name           = "Filesystem",
-               .size           = CERF_FLASH_SIZE-0x00160000,
-               .offset         = 0x00160000,
-       }
-};
-#endif
-
-#ifdef CONFIG_SA1100_CONSUS
-static struct mtd_partition consus_partitions[] = {
-       {
-               .name           = "Consus boot firmware",
-               .offset         = 0,
-               .size           = 0x00040000,
-               .mask_flags     = MTD_WRITABLE, /* force read-only */
-       }, {
-               .name           = "Consus kernel",
-               .offset         = 0x00040000,
-               .size           = 0x00100000,
-               .mask_flags     = 0,
-       }, {
-               .name           = "Consus disk",
-               .offset         = 0x00140000,
-               /* The rest (up to 16M) for jffs.  We could put 0 and
-                  make it find the size automatically, but right now
-                  i have 32 megs.  jffs will use all 32 megs if given
-                  the chance, and this leads to horrible problems
-                  when you try to re-flash the image because blob
-                  won't erase the whole partition. */
-               .size           = 0x01000000 - 0x00140000,
-               .mask_flags     = 0,
-       }, {
-               /* this disk is a secondary disk, which can be used as
-                  needed, for simplicity, make it the size of the other
-                  consus partition, although realistically it could be
-                  the remainder of the disk (depending on the file
-                  system used) */
-                .name          = "Consus disk2",
-                .offset        = 0x01000000,
-                .size          = 0x01000000 - 0x00140000,
-                .mask_flags    = 0,
-       }
-};
-#endif
-
-#ifdef CONFIG_SA1100_FLEXANET
-/* Flexanet has two 28F128J3A flash parts in bank 0: */
-#define FLEXANET_FLASH_SIZE            0x02000000
-static struct mtd_partition flexanet_partitions[] = {
-       {
-               .name           = "bootloader",
-               .size           = 0x00040000,
-               .offset         = 0,
-               .mask_flags     = MTD_WRITEABLE,
-       }, {
-               .name           = "bootloader params",
-               .size           = 0x00040000,
-               .offset         = MTDPART_OFS_APPEND,
-               .mask_flags     = MTD_WRITEABLE,
-       }, {
-               .name           = "kernel",
-               .size           = 0x000C0000,
-               .offset         = MTDPART_OFS_APPEND,
-               .mask_flags     = MTD_WRITEABLE,
-       }, {
-               .name           = "altkernel",
-               .size           = 0x000C0000,
-               .offset         = MTDPART_OFS_APPEND,
-               .mask_flags     = MTD_WRITEABLE,
-       }, {
-               .name           = "root",
-               .size           = 0x00400000,
-               .offset         = MTDPART_OFS_APPEND,
-               .mask_flags     = MTD_WRITEABLE,
-       }, {
-               .name           = "free1",
-               .size           = 0x00300000,
-               .offset         = MTDPART_OFS_APPEND,
-               .mask_flags     = MTD_WRITEABLE,
-       }, {
-               .name           = "free2",
-               .size           = 0x00300000,
-               .offset         = MTDPART_OFS_APPEND,
-               .mask_flags     = MTD_WRITEABLE,
-       }, {
-               .name           = "free3",
-               .size           = MTDPART_SIZ_FULL,
-               .offset         = MTDPART_OFS_APPEND,
-               .mask_flags     = MTD_WRITEABLE,
-       }
-};
-#endif
-
-#ifdef CONFIG_SA1100_FREEBIRD
-static struct mtd_partition freebird_partitions[] = {
-#ifdef CONFIG_SA1100_FREEBIRD_NEW
-       {
-               .name           = "firmware",
-               .size           = 0x00040000,
-               .offset         = 0,
-               .mask_flags     = MTD_WRITEABLE,  /* force read-only */
-       }, {
-               .name           = "kernel",
-               .size           = 0x00080000,
-               .offset         = 0x00040000,
-       }, {
-               .name           = "params",
-               .size           = 0x00040000,
-               .offset         = 0x000C0000,
-       }, {
-               .name           = "initrd",
-               .size           = 0x00100000,
-               .offset         = 0x00100000,
-       }, {
-               .name           = "root cramfs",
-               .size           = 0x00300000,
-               .offset         = 0x00200000,
-       }, {
-               .name           = "usr cramfs",
-               .size           = 0x00C00000,
-               .offset         = 0x00500000,
-       }, {
-               .name           = "local",
-               .size           = MTDPART_SIZ_FULL,
-               .offset         = 0x01100000,
-       }
-#else
-       {
-               .size           = 0x00040000,
-               .offset         = 0,
-       }, {
-               .size           = 0x000c0000,
-               .offset         = MTDPART_OFS_APPEND,
-       }, {
-               .size           = 0x00400000,
-               .offset         = MTDPART_OFS_APPEND,
-       }, {
-               .size           = MTDPART_SIZ_FULL,
-               .offset         = MTDPART_OFS_APPEND,
-       }
-#endif
-};
-#endif
-
-#ifdef CONFIG_SA1100_FRODO
-/* Frodo has 2 x 16M 28F128J3A flash chips in bank 0: */
-static struct mtd_partition frodo_partitions[] =
-{
-       {
-               .name           = "bootloader",
-               .size           = 0x00040000,
-               .offset         = 0x00000000,
-               .mask_flags     = MTD_WRITEABLE
-       }, {
-               .name           = "bootloader params",
-               .size           = 0x00040000,
-               .offset         = MTDPART_OFS_APPEND,
-               .mask_flags     = MTD_WRITEABLE
-       }, {
-               .name           = "kernel",
-               .size           = 0x00100000,
-               .offset         = MTDPART_OFS_APPEND,
-               .mask_flags     = MTD_WRITEABLE
-       }, {
-               .name           = "ramdisk",
-               .size           = 0x00400000,
-               .offset         = MTDPART_OFS_APPEND,
-               .mask_flags     = MTD_WRITEABLE
-       }, {
-               .name           = "file system",
-               .size           = MTDPART_SIZ_FULL,
-               .offset         = MTDPART_OFS_APPEND
-       }
-};
-#endif
-
-#ifdef CONFIG_SA1100_GRAPHICSCLIENT
-static struct mtd_partition graphicsclient_partitions[] = {
-       {
-               .name           = "zImage",
-               .size           = 0x100000,
-               .offset         = 0,
-               .mask_flags     = MTD_WRITEABLE,  /* force read-only */
-       }, {
-               .name           = "ramdisk.gz",
-               .size           = 0x300000,
-               .offset         = MTDPART_OFS_APPEND,
-               .mask_flags     = MTD_WRITEABLE,  /* force read-only */
-       }, {
-               .name           = "User FS",
-               .size           = MTDPART_SIZ_FULL,
-               .offset         = MTDPART_OFS_APPEND,
-       }
-};
-#endif
-
-#ifdef CONFIG_SA1100_GRAPHICSMASTER
-static struct mtd_partition graphicsmaster_partitions[] = {
-       {
-               .name           = "zImage",
-               .size           = 0x100000,
-               .offset         = 0,
-               .mask_flags     = MTD_WRITEABLE,  /* force read-only */
-       },
-       {
-               .name           = "ramdisk.gz",
-               .size           = 0x300000,
-               .offset         = MTDPART_OFS_APPEND,
-               .mask_flags     = MTD_WRITEABLE,  /* force read-only */
-       },
-       {
-               .name           = "User FS",
-               .size           = MTDPART_SIZ_FULL,
-               .offset         = MTDPART_OFS_APPEND,
-       }
-};
-#endif
-
-#ifdef CONFIG_SA1100_H3XXX
-static struct mtd_partition h3xxx_partitions[] = {
-       {
-               .name           = "H3XXX boot firmware",
-               .size           = 0x00040000,
-               .offset         = 0,
-               .mask_flags     = MTD_WRITEABLE,  /* force read-only */
-       }, {
-#ifdef CONFIG_MTD_2PARTS_IPAQ
-               .name           = "H3XXX root jffs2",
-               .size           = MTDPART_SIZ_FULL,
-               .offset         = 0x00040000,
-#else
-               .name           = "H3XXX kernel",
-               .size           = 0x00080000,
-               .offset         = 0x00040000,
-       }, {
-               .name           = "H3XXX params",
-               .size           = 0x00040000,
-               .offset         = 0x000C0000,
-       }, {
-#ifdef CONFIG_JFFS2_FS
-               .name           = "H3XXX root jffs2",
-               .size           = MTDPART_SIZ_FULL,
-               .offset         = 0x00100000,
-#else
-               .name           = "H3XXX initrd",
-               .size           = 0x00100000,
-               .offset         = 0x00100000,
-       }, {
-               .name           = "H3XXX root cramfs",
-               .size           = 0x00300000,
-               .offset         = 0x00200000,
-       }, {
-               .name           = "H3XXX usr cramfs",
-               .size           = 0x00800000,
-               .offset         = 0x00500000,
-       }, {
-               .name           = "H3XXX usr local",
-               .size           = MTDPART_SIZ_FULL,
-               .offset         = 0x00d00000,
-#endif
-#endif
-       }
-};
-
-static void h3xxx_set_vpp(struct map_info *map, int vpp)
-{
-       assign_h3600_egpio(IPAQ_EGPIO_VPP_ON, vpp);
-}
-#else
-#define h3xxx_set_vpp NULL
-#endif
-
-#ifdef CONFIG_SA1100_HACKKIT
-static struct mtd_partition hackkit_partitions[] = {
-       {
-               .name           = "BLOB",
-               .size           = 0x00040000,
-               .offset         = 0x00000000,
-               .mask_flags     = MTD_WRITEABLE,  /* force read-only */
-       }, {
-               .name           = "config",
-               .size           = 0x00040000,
-               .offset         = MTDPART_OFS_APPEND,
-       }, {
-               .name           = "kernel",
-               .size           = 0x00100000,
-               .offset         = MTDPART_OFS_APPEND,
-       }, {
-               .name           = "initrd",
-               .size           = 0x00180000,
-               .offset         = MTDPART_OFS_APPEND,
-       }, {
-               .name           = "rootfs",
-               .size           = 0x700000,
-               .offset         = MTDPART_OFS_APPEND,
-       }, {
-               .name           = "data",
-               .size           = MTDPART_SIZ_FULL,
-               .offset         = MTDPART_OFS_APPEND,
-       }
-};
-#endif
-
-#ifdef CONFIG_SA1100_HUW_WEBPANEL
-static struct mtd_partition huw_webpanel_partitions[] = {
-       {
-               .name           = "Loader",
-               .size           = 0x00040000,
-               .offset         = 0,
-       }, {
-               .name           = "Sector 1",
-               .size           = 0x00040000,
-               .offset         = MTDPART_OFS_APPEND,
-       }, {
-               .size           = MTDPART_SIZ_FULL,
-               .offset         = MTDPART_OFS_APPEND,
-       }
-};
-#endif
-
-#ifdef CONFIG_SA1100_JORNADA720
-static struct mtd_partition jornada720_partitions[] = {
-       {
-               .name           = "JORNADA720 boot firmware",
-               .size           = 0x00040000,
-               .offset         = 0,
-               .mask_flags     = MTD_WRITEABLE,  /* force read-only */
-       }, {
-               .name           = "JORNADA720 kernel",
-               .size           = 0x000c0000,
-               .offset         = 0x00040000,
-       }, {
-               .name           = "JORNADA720 params",
-               .size           = 0x00040000,
-               .offset         = 0x00100000,
-       }, {
-               .name           = "JORNADA720 initrd",
-               .size           = 0x00100000,
-               .offset         = 0x00140000,
-       }, {
-               .name           = "JORNADA720 root cramfs",
-               .size           = 0x00300000,
-               .offset         = 0x00240000,
-       }, {
-               .name           = "JORNADA720 usr cramfs",
-               .size           = 0x00800000,
-               .offset         = 0x00540000,
-       }, {
-               .name           = "JORNADA720 usr local",
-               .size           = 0,  /* will expand to the end of the flash */
-               .offset         = 0x00d00000,
-       }
-};
-
-static void jornada720_set_vpp(struct map_info *map, int vpp)
-{
-       if (vpp)
-               PPSR |= 0x80;
-       else
-               PPSR &= ~0x80;
-       PPDR |= 0x80;
-}
-#else
-#define jornada720_set_vpp NULL
-#endif
-
-#ifdef CONFIG_SA1100_PANGOLIN
-static struct mtd_partition pangolin_partitions[] = {
-       {
-               .name           = "boot firmware",
-               .size           = 0x00080000,
-               .offset         = 0x00000000,
-               .mask_flags     = MTD_WRITEABLE,  /* force read-only */
-       }, {
-               .name           = "kernel",
-               .size           = 0x00100000,
-               .offset         = 0x00080000,
-       }, {
-               .name           = "initrd",
-               .size           = 0x00280000,
-               .offset         = 0x00180000,
-       }, {
-               .name           = "initrd-test",
-               .size           = 0x03C00000,
-               .offset         = 0x00400000,
-       }
-};
-#endif
-
-#ifdef CONFIG_SA1100_PT_SYSTEM3
-/* erase size is 0x40000 == 256k partitions have to have this boundary */
-static struct mtd_partition system3_partitions[] = {
-       {
-               .name           = "BLOB",
-               .size           = 0x00040000,
-               .offset         = 0x00000000,
-               .mask_flags     = MTD_WRITEABLE,  /* force read-only */
-       }, {
-               .name           = "config",
-               .size           = 0x00040000,
-               .offset         = MTDPART_OFS_APPEND,
-       }, {
-               .name           = "kernel",
-               .size           = 0x00100000,
-               .offset         = MTDPART_OFS_APPEND,
-       }, {
-               .name           = "root",
-               .size           = MTDPART_SIZ_FULL,
-               .offset         = MTDPART_OFS_APPEND,
-       }
-};
-#endif
-
-#ifdef CONFIG_SA1100_SHANNON
-static struct mtd_partition shannon_partitions[] = {
-       {
-               .name           = "BLOB boot loader",
-               .offset         = 0,
-               .size           = 0x20000
-       },
-       {
-               .name           = "kernel",
-               .offset         = MTDPART_OFS_APPEND,
-               .size           = 0xe0000
-       },
-       { 
-               .name           = "initrd",
-               .offset         = MTDPART_OFS_APPEND,   
-               .size           = MTDPART_SIZ_FULL
-       }
-};
-
-#endif
-
-#ifdef CONFIG_SA1100_SHERMAN
-static struct mtd_partition sherman_partitions[] = {
-       {
-               .size           = 0x50000,
-               .offset         = 0,
-       }, {
-               .size           = 0x70000,
-               .offset         = MTDPART_OFS_APPEND,
-       }, {
-               .size           = 0x600000,
-               .offset         = MTDPART_OFS_APPEND,
-       }, {
-               .size           = 0xA0000,
-               .offset         = MTDPART_OFS_APPEND,
-       }
-};
-#endif
-
-#ifdef CONFIG_SA1100_SIMPAD
-static struct mtd_partition simpad_partitions[] = {
-       {
-               .name           = "SIMpad boot firmware",
-               .size           = 0x00080000,
-               .offset         = 0,
-               .mask_flags     = MTD_WRITEABLE,  /* force read-only */
-       }, {
-               .name           = "SIMpad kernel",
-               .size           = 0x00100000,
-               .offset         = MTDPART_OFS_APPEND,
-       }, {
-#ifdef CONFIG_ROOT_CRAMFS
-               .name           = "SIMpad root cramfs",
-               .size           =0x00D80000,
-               .offset         = MTDPART_OFS_APPEND
-
-       }, {
-               .name           = "SIMpad local jffs2",
-               .size           = MTDPART_SIZ_FULL,
-               .offset         = MTDPART_OFS_APPEND
-#else
-               .name           = "SIMpad root jffs2",
-               .size           = MTDPART_SIZ_FULL,
-               .offset         = MTDPART_OFS_APPEND
-#endif
-       }
-};
-#endif /* CONFIG_SA1100_SIMPAD */
-
-#ifdef CONFIG_SA1100_STORK
-static struct mtd_partition stork_partitions[] = {
+ * This is here for documentation purposes only - until these people
+ * submit their machine types.  It will be gone January 2005.
+ */
+static struct mtd_partition consus_partitions[] = {
        {
-               .name           = "STORK boot firmware",
-               .size           = 0x00040000,
+               .name           = "Consus boot firmware",
                .offset         = 0,
-               .mask_flags     = MTD_WRITEABLE,  /* force read-only */
-       }, {
-               .name           = "STORK params",
                .size           = 0x00040000,
-               .offset         = 0x00040000,
-       }, {
-               .name           = "STORK kernel",
-               .size           = 0x00100000,
-               .offset         = 0x00080000,
+               .mask_flags     = MTD_WRITABLE, /* force read-only */
        }, {
-#ifdef CONFIG_JFFS2_FS
-               .name           = "STORK root jffs2",
-               .offset         = 0x00180000,
-               .size           = MTDPART_SIZ_FULL,
-#else
-               .name           = "STORK initrd",
+               .name           = "Consus kernel",
+               .offset         = 0x00040000,
                .size           = 0x00100000,
-               .offset         = 0x00180000,
-       }, {
-               .name           = "STORK root cramfs",
-               .size           = 0x00300000,
-               .offset         = 0x00280000,
+               .mask_flags     = 0,
        }, {
-               .name           = "STORK usr cramfs",
-               .size           = 0x00800000,
-               .offset         = 0x00580000,
+               .name           = "Consus disk",
+               .offset         = 0x00140000,
+               /* The rest (up to 16M) for jffs.  We could put 0 and
+                  make it find the size automatically, but right now
+                  i have 32 megs.  jffs will use all 32 megs if given
+                  the chance, and this leads to horrible problems
+                  when you try to re-flash the image because blob
+                  won't erase the whole partition. */
+               .size           = 0x01000000 - 0x00140000,
+               .mask_flags     = 0,
        }, {
-               .name           = "STORK usr local",
-               .offset         = 0x00d80000,
-               .size           = MTDPART_SIZ_FULL,
-#endif
+               /* this disk is a secondary disk, which can be used as
+                  needed, for simplicity, make it the size of the other
+                  consus partition, although realistically it could be
+                  the remainder of the disk (depending on the file
+                  system used) */
+                .name          = "Consus disk2",
+                .offset        = 0x01000000,
+                .size          = 0x01000000 - 0x00140000,
+                .mask_flags    = 0,
        }
 };
-#endif
 
-#ifdef CONFIG_SA1100_TRIZEPS
-static struct mtd_partition trizeps_partitions[] = {
+/* Frodo has 2 x 16M 28F128J3A flash chips in bank 0: */
+static struct mtd_partition frodo_partitions[] =
+{
        {
-               .name           = "Bootloader",
-               .size           = 0x00100000,
-               .offset         = 0,
+               .name           = "bootloader",
+               .size           = 0x00040000,
+               .offset         = 0x00000000,
+               .mask_flags     = MTD_WRITEABLE
+       }, {
+               .name           = "bootloader params",
+               .size           = 0x00040000,
+               .offset         = MTDPART_OFS_APPEND,
+               .mask_flags     = MTD_WRITEABLE
        }, {
-               .name           = "Kernel",
+               .name           = "kernel",
                .size           = 0x00100000,
                .offset         = MTDPART_OFS_APPEND,
+               .mask_flags     = MTD_WRITEABLE
        }, {
-               .name           = "root",
-               .size           = MTDPART_SIZ_FULL,
+               .name           = "ramdisk",
+               .size           = 0x00400000,
                .offset         = MTDPART_OFS_APPEND,
+               .mask_flags     = MTD_WRITEABLE
+       }, {
+               .name           = "file system",
+               .size           = MTDPART_SIZ_FULL,
+               .offset         = MTDPART_OFS_APPEND
        }
 };
-#endif
 
-#ifdef CONFIG_SA1100_YOPY
-static struct mtd_partition yopy_partitions[] = {
+static struct mtd_partition jornada56x_partitions[] = {
        {
-               .name           = "boot firmware",
+               .name           = "bootldr",
                .size           = 0x00040000,
-               .offset         = 0x00000000,
-               .mask_flags     = MTD_WRITEABLE,  /* force read-only */
-       }, {
-               .name           = "kernel",
-               .size           = 0x00080000,
-               .offset         = 0x00080000,
-       }, {
-               .name           = "initrd",
-               .size           = 0x00300000,
-               .offset         = 0x00100000,
+               .offset         = 0,
+               .mask_flags     = MTD_WRITEABLE,
        }, {
-               .name           = "root",
-               .size           = 0x01000000,
-               .offset         = 0x00400000,
+               .name           = "rootfs",
+               .size           = MTDPART_SIZ_FULL,
+               .offset         = MTDPART_OFS_APPEND,
        }
 };
-#endif
 
-static int __init sa1100_static_partitions(struct mtd_partition **parts)
+static void jornada56x_set_vpp(int vpp)
 {
-       int nb_parts = 0;
-
-#ifdef CONFIG_SA1100_ADSBITSY
-       if (machine_is_adsbitsy()) {
-               *parts       = adsbitsy_partitions;
-               nb_parts     = ARRAY_SIZE(adsbitsy_partitions);
-       }
-#endif
-#ifdef CONFIG_SA1100_ASSABET
-       if (machine_is_assabet()) {
-               *parts       = assabet_partitions;
-               nb_parts     = ARRAY_SIZE(assabet_partitions);
-       }
-#endif
-#ifdef CONFIG_SA1100_BADGE4
-       if (machine_is_badge4()) {
-               *parts       = badge4_partitions;
-               nb_parts     = ARRAY_SIZE(badge4_partitions);
-       }
-#endif
-#ifdef CONFIG_SA1100_CERF
-       if (machine_is_cerf()) {
-               *parts       = cerf_partitions;
-               nb_parts     = ARRAY_SIZE(cerf_partitions);
-       }
-#endif
-#ifdef CONFIG_SA1100_CONSUS
-       if (machine_is_consus()) {
-               *parts       = consus_partitions;
-               nb_parts     = ARRAY_SIZE(consus_partitions);
-       }
-#endif
-#ifdef CONFIG_SA1100_FLEXANET
-       if (machine_is_flexanet()) {
-               *parts       = flexanet_partitions;
-               nb_parts     = ARRAY_SIZE(flexanet_partitions);
-       }
-#endif
-#ifdef CONFIG_SA1100_FREEBIRD
-       if (machine_is_freebird()) {
-               *parts       = freebird_partitions;
-               nb_parts     = ARRAY_SIZE(freebird_partitions);
-       }
-#endif
-#ifdef CONFIG_SA1100_FRODO
-       if (machine_is_frodo()) {
-               *parts       = frodo_partitions;
-               nb_parts     = ARRAY_SIZE(frodo_partitions);
-       }
-#endif 
-#ifdef CONFIG_SA1100_GRAPHICSCLIENT
-       if (machine_is_graphicsclient()) {
-               *parts       = graphicsclient_partitions;
-               nb_parts     = ARRAY_SIZE(graphicsclient_partitions);
-       }
-#endif
-#ifdef CONFIG_SA1100_GRAPHICSMASTER
-       if (machine_is_graphicsmaster()) {
-               *parts       = graphicsmaster_partitions;
-               nb_parts     = ARRAY_SIZE(graphicsmaster_partitions);
-       }
-#endif
-#ifdef CONFIG_SA1100_H3XXX
-       if (machine_is_h3xxx()) {
-               *parts       = h3xxx_partitions;
-               nb_parts     = ARRAY_SIZE(h3xxx_partitions);
-       }
-#endif
-#ifdef CONFIG_SA1100_HACKKIT
-       if (machine_is_hackkit()) {
-               *parts = hackkit_partitions;
-               nb_parts = ARRAY_SIZE(hackkit_partitions);
-       }
-#endif
-#ifdef CONFIG_SA1100_HUW_WEBPANEL
-       if (machine_is_huw_webpanel()) {
-               *parts       = huw_webpanel_partitions;
-               nb_parts     = ARRAY_SIZE(huw_webpanel_partitions);
-       }
-#endif
-#ifdef CONFIG_SA1100_JORNADA720
-       if (machine_is_jornada720()) {
-               *parts       = jornada720_partitions;
-               nb_parts     = ARRAY_SIZE(jornada720_partitions);
-       }
-#endif
-#ifdef CONFIG_SA1100_PANGOLIN
-       if (machine_is_pangolin()) {
-               *parts       = pangolin_partitions;
-               nb_parts     = ARRAY_SIZE(pangolin_partitions);
-       }
-#endif
-#ifdef CONFIG_SA1100_PT_SYSTEM3
-       if (machine_is_pt_system3()) {
-               *parts       = system3_partitions;
-               nb_parts     = ARRAY_SIZE(system3_partitions);
-       }
-#endif
-#ifdef CONFIG_SA1100_SHANNON
-       if (machine_is_shannon()) {
-               *parts       = shannon_partitions;
-               nb_parts     = ARRAY_SIZE(shannon_partitions);
-       }
-#endif
-#ifdef CONFIG_SA1100_SHERMAN
-       if (machine_is_sherman()) {
-               *parts       = sherman_partitions;
-               nb_parts     = ARRAY_SIZE(sherman_partitions);
-       }
-#endif
-#ifdef CONFIG_SA1100_SIMPAD
-       if (machine_is_simpad()) {
-               *parts       = simpad_partitions;
-               nb_parts     = ARRAY_SIZE(simpad_partitions);
-       }
-#endif
-#ifdef CONFIG_SA1100_STORK
-       if (machine_is_stork()) {
-               *parts       = stork_partitions;
-               nb_parts     = ARRAY_SIZE(stork_partitions);
-       }
-#endif
-#ifdef CONFIG_SA1100_TRIZEPS
-       if (machine_is_trizeps()) {
-               *parts       = trizeps_partitions;
-               nb_parts     = ARRAY_SIZE(trizeps_partitions);
-       }
-#endif
-#ifdef CONFIG_SA1100_YOPY
-       if (machine_is_yopy()) {
-               *parts       = yopy_partitions;
-               nb_parts     = ARRAY_SIZE(yopy_partitions);
-       }
-#endif
-
-       return nb_parts;
+       if (vpp)
+               GPSR = GPIO_GPIO26;
+       else
+               GPCR = GPIO_GPIO26;
+       GPDR |= GPIO_GPIO26;
 }
+
+/*
+ * Machine        Phys          Size    set_vpp
+ * Consus    : SA1100_CS0_PHYS SZ_32M
+ * Frodo     : SA1100_CS0_PHYS SZ_32M
+ * Jornada56x: SA1100_CS0_PHYS SZ_32M jornada56x_set_vpp
+ */
 #endif
 
-struct sa_info {
-       unsigned long base;
-       unsigned long size;
-       int width;
-       void __iomem *vbase;
-        void (*set_vpp)(struct map_info *, int);
-       struct map_info *map;
+struct sa_subdev_info {
+       char name[16];
+       struct map_info map;
        struct mtd_info *mtd;
-       struct resource *res;
+       struct flash_platform_data *data;
 };
 
-#define NR_SUBMTD 4
+struct sa_info {
+       struct mtd_partition    *parts;
+       struct mtd_info         *mtd;
+       int                     num_subdev;
+       struct sa_subdev_info   subdev[0];
+};
 
-static struct sa_info info[NR_SUBMTD];
+static void sa1100_set_vpp(struct map_info *map, int on)
+{
+       struct sa_subdev_info *subdev = container_of(map, struct sa_subdev_info, map);
+       subdev->data->set_vpp(on);
+}
 
-static int __init sa1100_setup_mtd(struct sa_info *sa, int nr, struct mtd_info **rmtd)
+static void sa1100_destroy_subdev(struct sa_subdev_info *subdev)
 {
-       struct mtd_info *subdev[nr];
-       struct map_info *maps;
-       int i, found = 0, ret = 0;
+       if (subdev->mtd)
+               map_destroy(subdev->mtd);
+       if (subdev->map.virt)
+               iounmap(subdev->map.virt);
+       release_mem_region(subdev->map.phys, subdev->map.size);
+}
 
-       /*
-        * Allocate the map_info structs in one go.
-        */
-       maps = kmalloc(sizeof(struct map_info) * nr, GFP_KERNEL);
-       if (!maps)
-               return -ENOMEM;
+static int sa1100_probe_subdev(struct sa_subdev_info *subdev, struct resource *res)
+{
+       unsigned long phys;
+       unsigned int size;
+       int ret;
 
-       memset(maps, 0, sizeof(struct map_info) * nr);
+       phys = res->start;
+       size = res->end - phys + 1;
 
        /*
-        * Claim and then map the memory regions.
+        * Retrieve the bankwidth from the MSC registers.
+        * We currently only implement CS0 and CS1 here.
         */
-       for (i = 0; i < nr; i++) {
-               if (sa[i].base == (unsigned long)-1)
-                       break;
-
-               sa[i].res = request_mem_region(sa[i].base, sa[i].size, "sa1100 flash");
-               if (!sa[i].res) {
-                       ret = -EBUSY;
-                       break;
-               }
+       switch (phys) {
+       default:
+               printk(KERN_WARNING "SA1100 flash: unknown base address "
+                      "0x%08lx, assuming CS0\n", phys);
 
-               sa[i].map = maps + i;
+       case SA1100_CS0_PHYS:
+               subdev->map.bankwidth = (MSC0 & MSC_RBW) ? 2 : 4;
+               break;
 
-               sa[i].vbase = ioremap(sa[i].base, sa[i].size);
-               if (!sa[i].vbase) {
-                       ret = -ENOMEM;
-                       break;
-               }
-
-               sa[i].map->virt = sa[i].vbase;
-               sa[i].map->phys = sa[i].base;
-               sa[i].map->set_vpp = sa[i].set_vpp;
-               sa[i].map->bankwidth = sa[i].width;
-               sa[i].map->size = sa[i].size;
+       case SA1100_CS1_PHYS:
+               subdev->map.bankwidth = ((MSC0 >> 16) & MSC_RBW) ? 2 : 4;
+               break;
+       }
 
-               simple_map_init(sa[i].map);
+       if (!request_mem_region(phys, size, subdev->name)) {
+               ret = -EBUSY;
+               goto out;
+       }
 
-               /*
-                * Now let's probe for the actual flash.  Do it here since
-                * specific machine settings might have been set above.
-                */
-               sa[i].mtd = do_map_probe("cfi_probe", sa[i].map);
-               if (sa[i].mtd == NULL) {
-                       ret = -ENXIO;
-                       break;
-               }
-               sa[i].mtd->owner = THIS_MODULE;
-               subdev[i] = sa[i].mtd;
+       if (subdev->data->set_vpp)
+               subdev->map.set_vpp = sa1100_set_vpp;
 
-               printk(KERN_INFO "SA1100 flash: CFI device at 0x%08lx, %dMiB, "
-                       "%d-bit\n", sa[i].base, sa[i].mtd->size >> 20,
-                       sa[i].width * 8);
-               found += 1;
+       subdev->map.phys = phys;
+       subdev->map.size = size;
+       subdev->map.virt = ioremap(phys, size);
+       if (!subdev->map.virt) {
+               ret = -ENOMEM;
+               goto err;
        }
 
-       /*
-        * ENXIO is special.  It means we didn't find a chip when
-        * we probed.  We need to tear down the mapping, free the
-        * resource and mark it as such.
-        */
-       if (ret == -ENXIO) {
-               iounmap(sa[i].vbase);
-               sa[i].vbase = NULL;
-               release_resource(sa[i].res);
-               sa[i].res = NULL;
-       }
+       simple_map_init(&subdev->map);
 
        /*
-        * If we found one device, don't bother with concat support.
-        * If we found multiple devices, use concat if we have it
-        * available, otherwise fail.
+        * Now let's probe for the actual flash.  Do it here since
+        * specific machine settings might have been set above.
         */
-       if (ret == 0 || ret == -ENXIO) {
-               if (found == 1) {
-                       *rmtd = subdev[0];
-                       ret = 0;
-               } else if (found > 1) {
-                       /*
-                        * We detected multiple devices.  Concatenate
-                        * them together.
-                        */
-#ifdef CONFIG_MTD_CONCAT
-                       *rmtd = mtd_concat_create(subdev, found,
-                                                 "sa1100 flash");
-                       if (*rmtd == NULL)
-                               ret = -ENXIO;
-#else
-                       printk(KERN_ERR "SA1100 flash: multiple devices "
-                              "found but MTD concat support disabled.\n");
-                       ret = -ENXIO;
-#endif
-               }
+       subdev->mtd = do_map_probe(subdev->data->map_name, &subdev->map);
+       if (subdev->mtd == NULL) {
+               ret = -ENXIO;
+               goto err;
        }
+       subdev->mtd->owner = THIS_MODULE;
 
-       /*
-        * If we failed, clean up.
-        */
-       if (ret) {
-               do {
-                       if (sa[i].mtd)
-                               map_destroy(sa[i].mtd);
-                       if (sa[i].vbase)
-                               iounmap(sa[i].vbase);
-                       if (sa[i].res)
-                               release_resource(sa[i].res);
-               } while (i--);
+       printk(KERN_INFO "SA1100 flash: CFI device at 0x%08lx, %dMiB, "
+               "%d-bit\n", phys, subdev->mtd->size >> 20,
+               subdev->map.bankwidth * 8);
 
-               kfree(maps);
-       }
+       return 0;
 
+ err:
+       sa1100_destroy_subdev(subdev);
+ out:
        return ret;
 }
 
-static void __exit sa1100_destroy_mtd(struct sa_info *sa, struct mtd_info *mtd)
+static void sa1100_destroy(struct sa_info *info)
 {
        int i;
 
-       del_mtd_partitions(mtd);
+       if (info->mtd) {
+               del_mtd_partitions(info->mtd);
 
 #ifdef CONFIG_MTD_CONCAT
-       if (mtd != sa[0].mtd)
-               mtd_concat_destroy(mtd);
+               if (info->mtd != info->subdev[0].mtd)
+                       mtd_concat_destroy(info->mtd);
 #endif
-
-       for (i = NR_SUBMTD; i >= 0; i--) {
-               if (sa[i].mtd)
-                       map_destroy(sa[i].mtd);
-               if (sa[i].vbase)
-                       iounmap(sa[i].vbase);
-               if (sa[i].res)
-                       release_resource(sa[i].res);
        }
-       kfree(sa[0].map);
-}
 
-/*
- * A Thought: can we automatically detect the flash?
- *  - Check to see if the region is busy (yes -> failure)
- *  - Is the MSC setup for flash (no -> failure)
- *  - Probe for flash
- */
+       if (info->parts)
+               kfree(info->parts);
 
-static struct map_info sa1100_probe_map __initdata = {
-       .name           = "SA1100-flash",
-};
+       for (i = info->num_subdev - 1; i >= 0; i--)
+               sa1100_destroy_subdev(&info->subdev[i]);
+       kfree(info);
+}
 
-static void __init sa1100_probe_one_cs(unsigned int msc, unsigned long phys)
+static struct sa_info *__init
+sa1100_setup_mtd(struct platform_device *pdev, struct flash_platform_data *flash)
 {
-       struct mtd_info *mtd;
-
-       printk(KERN_INFO "* Probing 0x%08lx: MSC = 0x%04x %d bit ",
-               phys, msc & 0xffff, msc & MSC_RBW ? 16 : 32);
+       struct sa_info *info;
+       int nr, size, i, ret = 0;
 
-       if (check_mem_region(phys, 0x08000000)) {
-               printk("busy\n");
-               return;
-       }
+       /*
+        * Count number of devices.
+        */
+       for (nr = 0; ; nr++)
+               if (!platform_get_resource(pdev, IORESOURCE_MEM, nr))
+                       break;
 
-       if ((msc & 3) == 1) {
-               printk("wrong type\n");
-               return;
+       if (nr == 0) {
+               ret = -ENODEV;
+               goto out;
        }
 
-       sa1100_probe_map.bankwidth = msc & MSC_RBW ? 2 : 4;
-       sa1100_probe_map.size = SZ_1M;
-       sa1100_probe_map.phys = phys;
-       sa1100_probe_map.virt = (unsigned long)ioremap(phys, SZ_1M);
-       if (sa1100_probe_map.virt == 0)
-               goto fail;
-       simple_map_init(&sa1100_probe_map);
-
-       /* Shame cfi_probe blurts out kernel messages... */
-       mtd = do_map_probe("cfi_probe", &sa1100_probe_map);
-       if (mtd)
-               map_destroy(mtd);
-       iounmap((void *)sa1100_probe_map.virt);
-
-       if (!mtd)
-               goto fail;
+       size = sizeof(struct sa_info) + sizeof(struct sa_subdev_info) * nr;
 
-       printk("pass\n");
-       return;
+       /*
+        * Allocate the map_info structs in one go.
+        */
+       info = kmalloc(size, GFP_KERNEL);
+       if (!info) {
+               ret = -ENOMEM;
+               goto out;
+       }
 
- fail:
-       printk("failed\n");
-}
+       memset(info, 0, size);
 
-static void __init sa1100_probe_flash(void)
-{
-       printk(KERN_INFO "-- SA11xx Flash probe.  Please report results.\n");
-       sa1100_probe_one_cs(MSC0, SA1100_CS0_PHYS);
-       sa1100_probe_one_cs(MSC0 >> 16, SA1100_CS1_PHYS);
-       sa1100_probe_one_cs(MSC1, SA1100_CS2_PHYS);
-       sa1100_probe_one_cs(MSC1 >> 16, SA1100_CS3_PHYS);
-       sa1100_probe_one_cs(MSC2, SA1100_CS4_PHYS);
-       sa1100_probe_one_cs(MSC2 >> 16, SA1100_CS5_PHYS);
-       printk(KERN_INFO "-- SA11xx Flash probe complete.\n");
-}
+       /*
+        * Claim and then map the memory regions.
+        */
+       for (i = 0; i < nr; i++) {
+               struct sa_subdev_info *subdev = &info->subdev[i];
+               struct resource *res;
 
-static int __init sa1100_locate_flash(void)
-{
-       int i, nr = -ENODEV;
+               res = platform_get_resource(pdev, IORESOURCE_MEM, i);
+               if (!res)
+                       break;
 
-       sa1100_probe_flash();
+               subdev->map.name = subdev->name;
+               sprintf(subdev->name, "sa1100-%d", i);
+               subdev->data = flash;
 
-       if (machine_is_adsbitsy()) {
-               info[0].base = SA1100_CS1_PHYS;
-               info[0].size = SZ_32M;
-               nr = 1;
-       }
-       if (machine_is_assabet()) {
-               info[0].base = SA1100_CS0_PHYS;
-               info[0].size = SZ_32M;
-               info[1].base = SA1100_CS1_PHYS; /* neponset */
-               info[1].size = SZ_32M;
-               nr = 2;
-       }
-       if (machine_is_badge4()) {
-               info[0].base = SA1100_CS0_PHYS;
-               info[0].size = SZ_64M;
-               nr = 1;
-       }
-       if (machine_is_cerf()) {
-               info[0].base = SA1100_CS0_PHYS;
-               info[0].size = SZ_32M;
-               nr = 1;
-       }
-       if (machine_is_consus()) {
-               info[0].base = SA1100_CS0_PHYS;
-               info[0].size = SZ_32M;
-               nr = 1;
-       }
-       if (machine_is_flexanet()) {
-               info[0].base = SA1100_CS0_PHYS;
-               info[0].size = SZ_32M;
-               nr = 1;
-       }
-       if (machine_is_freebird()) {
-               info[0].base = SA1100_CS0_PHYS;
-               info[0].size = SZ_32M;
-               nr = 1;
-       }
-       if (machine_is_frodo()) {
-               info[0].base = SA1100_CS0_PHYS;
-               info[0].size = SZ_32M;
-               nr = 1;
-       }
-       if (machine_is_graphicsclient()) {
-               info[0].base = SA1100_CS1_PHYS;
-               info[0].size = SZ_32M;
-               nr = 1;
-       }
-       if (machine_is_graphicsmaster()) {
-               info[0].base = SA1100_CS1_PHYS;
-               info[0].size = SZ_16M;
-               nr = 1;
-       }
-       if (machine_is_h3xxx()) {
-               info[0].set_vpp = h3xxx_set_vpp;
-               info[0].base = SA1100_CS0_PHYS;
-               info[0].size = SZ_32M;
-               nr = 1;
-       }
-       if (machine_is_huw_webpanel()) {
-               info[0].base = SA1100_CS0_PHYS;
-               info[0].size = SZ_16M;
-               nr = 1;
-       }
-       if (machine_is_itsy()) {
-               info[0].base = SA1100_CS0_PHYS;
-               info[0].size = SZ_32M;
-               nr = 1;
-       }
-       if (machine_is_jornada720()) {
-               info[0].set_vpp = jornada720_set_vpp;
-               info[0].base = SA1100_CS0_PHYS;
-               info[0].size = SZ_32M;
-               nr = 1;
-       }
-       if (machine_is_nanoengine()) {
-               info[0].base = SA1100_CS0_PHYS;
-               info[1].size = SZ_32M;
-               nr = 1;
-       }
-       if (machine_is_pangolin()) {
-               info[0].base = SA1100_CS0_PHYS;
-               info[0].size = SZ_64M;
-               nr = 1;
-       }
-       if (machine_is_pfs168()) {
-               info[0].base = SA1100_CS0_PHYS;
-               info[0].size = SZ_32M;
-               nr = 1;
-       }
-       if (machine_is_pleb()) {
-               info[0].base = SA1100_CS0_PHYS;
-               info[0].size = SZ_4M;
-               info[1].base = SA1100_CS1_PHYS;
-               info[1].size = SZ_4M;
-               nr = 2;
-       }
-       if (machine_is_pt_system3()) {
-               info[0].base = SA1100_CS0_PHYS;
-               info[0].size = SZ_16M;
-               nr = 1;
-       }
-       if (machine_is_shannon()) {
-               info[0].base = SA1100_CS0_PHYS;
-               info[0].size = SZ_4M;
-               nr = 1;
-       }
-       if (machine_is_sherman()) {
-               info[0].base = SA1100_CS0_PHYS;
-               info[0].size = SZ_32M;
-               nr = 1;
-       }
-       if (machine_is_simpad()) {
-               info[0].base = SA1100_CS0_PHYS;
-               info[0].size = SZ_16M;
-               info[1].base = SA1100_CS1_PHYS;
-               info[1].size = SZ_16M;
-               nr = 2;
-       }
-       if (machine_is_stork()) {
-               info[0].base = SA1100_CS0_PHYS;
-               info[0].size = SZ_32M;
-               nr = 1;
-       }
-       if (machine_is_trizeps()) {
-               info[0].base = SA1100_CS0_PHYS;
-               info[0].size = SZ_16M;
-               nr = 1;
-       }
-       if (machine_is_victor()) {
-               info[0].base = SA1100_CS0_PHYS;
-               info[0].size = SZ_2M;
-               nr = 1;
-       }
-       if (machine_is_yopy()) {
-               info[0].base = SA1100_CS0_PHYS;
-               info[0].size = SZ_64M;
-               info[1].base = SA1100_CS1_PHYS;
-               info[1].size = SZ_64M;
-               nr = 2;
+               ret = sa1100_probe_subdev(subdev, res);
+               if (ret)
+                       break;
        }
 
-       if (nr < 0)
-               return nr;
+       info->num_subdev = i;
 
        /*
-        * Retrieve the bankwidth from the MSC registers.
-        * We currently only implement CS0 and CS1 here.
+        * ENXIO is special.  It means we didn't find a chip when we probed.
         */
-       for (i = 0; i < nr; i++) {
-               switch (info[i].base) {
-               default:
-                       printk(KERN_WARNING "SA1100 flash: unknown base address "
-                               "0x%08lx, assuming CS0\n", info[i].base);
-               case SA1100_CS0_PHYS:
-                       info[i].width = (MSC0 & MSC_RBW) ? 2 : 4;
-                       break;
+       if (ret != 0 && !(ret == -ENXIO && info->num_subdev > 0))
+               goto err;
 
-               case SA1100_CS1_PHYS:
-                       info[i].width = ((MSC0 >> 16) & MSC_RBW) ? 2 : 4;
-                       break;
-               }
+       /*
+        * If we found one device, don't bother with concat support.  If
+        * we found multiple devices, use concat if we have it available,
+        * otherwise fail.  Either way, it'll be called "sa1100".
+        */
+       if (info->num_subdev == 1) {
+               strcpy(info->subdev[0].name, "sa1100");
+               info->mtd = info->subdev[0].mtd;
+               ret = 0;
+       } else if (info->num_subdev > 1) {
+#ifdef CONFIG_MTD_CONCAT
+               struct mtd_info *cdev[nr];
+               /*
+                * We detected multiple devices.  Concatenate them together.
+                */
+               for (i = 0; i < info->num_subdev; i++)
+                       cdev[i] = info->subdev[i].mtd;
+
+               info->mtd = mtd_concat_create(cdev, info->num_subdev,
+                                             "sa1100");
+               if (info->mtd == NULL)
+                       ret = -ENXIO;
+#else
+               printk(KERN_ERR "SA1100 flash: multiple devices "
+                      "found but MTD concat support disabled.\n");
+               ret = -ENXIO;
+#endif
        }
 
-       return nr;
+       if (ret == 0)
+               return info;
+
+ err:
+       sa1100_destroy(info);
+ out:
+       return ERR_PTR(ret);
 }
 
-static struct mtd_partition *parsed_parts;
-const char *part_probes[] = { "cmdlinepart", "RedBoot", NULL };
+static const char *part_probes[] = { "cmdlinepart", "RedBoot", NULL };
 
-static void __init sa1100_locate_partitions(struct mtd_info *mtd)
+static int __init sa1100_mtd_probe(struct device *dev)
 {
+       struct platform_device *pdev = to_platform_device(dev);
+       struct flash_platform_data *flash = pdev->dev.platform_data;
+       struct mtd_partition *parts;
        const char *part_type = NULL;
-       int nr_parts = 0;
+       struct sa_info *info;
+       int err, nr_parts = 0;
 
-       do {
-               /*
-                * Partition selection stuff.
-                */
+       if (!flash)
+               return -ENODEV;
+
+       info = sa1100_setup_mtd(pdev, flash);
+       if (IS_ERR(info)) {
+               err = PTR_ERR(info);
+               goto out;
+       }
+
+       /*
+        * Partition selection stuff.
+        */
 #ifdef CONFIG_MTD_PARTITIONS
-               nr_parts = parse_mtd_partitions(mtd, part_probes, &parsed_parts, 0);
-               if (nr_parts > 0) {
-                       part_type = "dynamic";
-                       break;
-               }
-#endif
-#ifdef CONFIG_MTD_SA1100_STATICMAP
-               nr_parts = sa1100_static_partitions(&parsed_parts);
-               if (nr_parts > 0) {
-                       part_type = "static";
-                       break;
-               }
+       nr_parts = parse_mtd_partitions(info->mtd, part_probes, &parts, 0);
+       if (nr_parts > 0) {
+               info->parts = parts;
+               part_type = "dynamic";
+       } else
 #endif
-       } while (0);
+       {
+               parts = flash->parts;
+               nr_parts = flash->nr_parts;
+               part_type = "static";
+       }
 
        if (nr_parts == 0) {
                printk(KERN_NOTICE "SA1100 flash: no partition info "
                        "available, registering whole flash\n");
-               add_mtd_device(mtd);
+               add_mtd_device(info->mtd);
        } else {
                printk(KERN_NOTICE "SA1100 flash: using %s partition "
                        "definition\n", part_type);
-               add_mtd_partitions(mtd, parsed_parts, nr_parts);
+               add_mtd_partitions(info->mtd, parts, nr_parts);
        }
 
-       /* Always succeeds. */
+       dev_set_drvdata(dev, info);
+       err = 0;
+
+ out:
+       return err;
 }
 
-static void __exit sa1100_destroy_partitions(void)
+static int __exit sa1100_mtd_remove(struct device *dev)
 {
-       if (parsed_parts)
-               kfree(parsed_parts);
+       struct sa_info *info = dev_get_drvdata(dev);
+       dev_set_drvdata(dev, NULL);
+       sa1100_destroy(info);
+       return 0;
 }
 
-static struct mtd_info *mymtd;
-
-static int __init sa1100_mtd_init(void)
+#ifdef CONFIG_PM
+static int sa1100_mtd_suspend(struct device *dev, u32 state, u32 level)
 {
-       int ret;
-       int nr;
-
-       nr = sa1100_locate_flash();
-       if (nr < 0)
-               return nr;
+       struct sa_info *info = dev_get_drvdata(dev);
+       int ret = 0;
 
-       ret = sa1100_setup_mtd(info, nr, &mymtd);
-       if (ret == 0)
-               sa1100_locate_partitions(mymtd);
+       if (info && level == SUSPEND_SAVE_STATE)
+               ret = info->mtd->suspend(info->mtd);
 
        return ret;
 }
 
-static void __exit sa1100_mtd_cleanup(void)
+static int sa1100_mtd_resume(struct device *dev, u32 level)
+{
+       struct sa_info *info = dev_get_drvdata(dev);
+       if (info && level == RESUME_RESTORE_STATE)
+               info->mtd->resume(info->mtd);
+       return 0;
+}
+#else
+#define sa1100_mtd_suspend NULL
+#define sa1100_mtd_resume  NULL
+#endif
+
+static struct device_driver sa1100_mtd_driver = {
+       .name           = "flash",
+       .bus            = &platform_bus_type,
+       .probe          = sa1100_mtd_probe,
+       .remove         = __exit_p(sa1100_mtd_remove),
+       .suspend        = sa1100_mtd_suspend,
+       .resume         = sa1100_mtd_resume,
+};
+
+static int __init sa1100_mtd_init(void)
+{
+       return driver_register(&sa1100_mtd_driver);
+}
+
+static void __exit sa1100_mtd_exit(void)
 {
-       sa1100_destroy_mtd(info, mymtd);
-       sa1100_destroy_partitions();
+       driver_unregister(&sa1100_mtd_driver);
 }
 
 module_init(sa1100_mtd_init);
-module_exit(sa1100_mtd_cleanup);
+module_exit(sa1100_mtd_exit);
 
 MODULE_AUTHOR("Nicolas Pitre");
 MODULE_DESCRIPTION("SA1100 CFI map driver");