diff options
-rw-r--r-- | drivers/mtd/chips/gen_probe.c | 6 | ||||
-rw-r--r-- | drivers/mtd/devices/docprobe.c | 47 | ||||
-rw-r--r-- | drivers/mtd/nand/Kconfig | 6 | ||||
-rw-r--r-- | drivers/mtd/nand/Makefile | 1 | ||||
-rw-r--r-- | drivers/mtd/nand/ams-delta.c | 238 |
5 files changed, 253 insertions, 45 deletions
diff --git a/drivers/mtd/chips/gen_probe.c b/drivers/mtd/chips/gen_probe.c index 00ca6f59120..cdb0f590b40 100644 --- a/drivers/mtd/chips/gen_probe.c +++ b/drivers/mtd/chips/gen_probe.c @@ -207,14 +207,14 @@ static inline struct mtd_info *cfi_cmdset_unknown(struct map_info *map, struct cfi_private *cfi = map->fldrv_priv; __u16 type = primary?cfi->cfiq->P_ID:cfi->cfiq->A_ID; #ifdef CONFIG_MODULES - char probename[32]; + char probename[16+sizeof(MODULE_SYMBOL_PREFIX)]; cfi_cmdset_fn_t *probe_function; - sprintf(probename, "cfi_cmdset_%4.4X", type); + sprintf(probename, MODULE_SYMBOL_PREFIX "cfi_cmdset_%4.4X", type); probe_function = __symbol_get(probename); if (!probe_function) { - request_module(probename); + request_module(probename + sizeof(MODULE_SYMBOL_PREFIX) - 1); probe_function = __symbol_get(probename); } diff --git a/drivers/mtd/devices/docprobe.c b/drivers/mtd/devices/docprobe.c index dce4c904b63..593bb033a3f 100644 --- a/drivers/mtd/devices/docprobe.c +++ b/drivers/mtd/devices/docprobe.c @@ -231,26 +231,9 @@ static inline int __init doccheck(void __iomem *potential, unsigned long physadr static int docfound; -#ifdef CONFIG_MTD_DOC2000 extern void DoC2k_init(struct mtd_info *); -#define doc2k_initfunc (&DoC2k_init) -#else -#define doc2k_initfunc NULL -#endif - -#ifdef CONFIG_MTD_DOC2001 extern void DoCMil_init(struct mtd_info *); -#define docmil_initfunc (&DoCMil_init) -#else -#define docmil_initfunc NULL -#endif - -#ifdef CONFIG_MTD_DOC2001PLUS extern void DoCMilPlus_init(struct mtd_info *); -#define docmplus_initfunc (&DoCMilPlus_init) -#else -#define docmplus_initfunc NULL -#endif static void __init DoC_Probe(unsigned long physadr) { @@ -260,8 +243,6 @@ static void __init DoC_Probe(unsigned long physadr) int ChipID; char namebuf[15]; char *name = namebuf; - char *im_funcname = NULL; - char *im_modname = NULL; void (*initroutine)(struct mtd_info *) = NULL; docptr = ioremap(physadr, DOC_IOREMAP_LEN); @@ -299,48 +280,30 @@ static void __init DoC_Probe(unsigned long physadr) switch(ChipID) { case DOC_ChipID_Doc2kTSOP: name="2000 TSOP"; - im_funcname = "DoC2k_init"; - im_modname = "doc2000"; - initroutine = doc2k_initfunc; + initroutine = symbol_request(DoC2k_init); break; case DOC_ChipID_Doc2k: name="2000"; - im_funcname = "DoC2k_init"; - im_modname = "doc2000"; - initroutine = doc2k_initfunc; + initroutine = symbol_request(DoC2k_init); break; case DOC_ChipID_DocMil: name="Millennium"; #ifdef DOC_SINGLE_DRIVER - im_funcname = "DoC2k_init"; - im_modname = "doc2000"; - initroutine = doc2k_initfunc; + initroutine = symbol_request(DoC2k_init); #else - im_funcname = "DoCMil_init"; - im_modname = "doc2001"; - initroutine = docmil_initfunc; + initroutine = symbol_request(DoCMil_init); #endif /* DOC_SINGLE_DRIVER */ break; case DOC_ChipID_DocMilPlus16: case DOC_ChipID_DocMilPlus32: name="MillenniumPlus"; - im_funcname = "DoCMilPlus_init"; - im_modname = "doc2001plus"; - initroutine = docmplus_initfunc; + initroutine = symbol_request(DoCMilPlus_init); break; } -#ifdef CONFIG_MODULES - if (im_funcname && !initroutine) - initroutine = __symbol_get(im_funcname); - if (im_funcname && !initroutine) { - request_module(im_modname); - initroutine = __symbol_get(im_funcname); - } -#endif if (initroutine) { (*initroutine)(mtd); symbol_put_addr(initroutine); diff --git a/drivers/mtd/nand/Kconfig b/drivers/mtd/nand/Kconfig index b1f807980b7..2d0ebad55a4 100644 --- a/drivers/mtd/nand/Kconfig +++ b/drivers/mtd/nand/Kconfig @@ -49,6 +49,12 @@ config MTD_NAND_SPIA help If you had to ask, you don't have one. Say 'N'. +config MTD_NAND_AMS_DELTA + tristate "NAND Flash device on Amstrad E3" + depends on MACH_AMS_DELTA && MTD_NAND + help + Support for NAND flash on Amstrad E3 (Delta). + config MTD_NAND_TOTO tristate "NAND Flash device on TOTO board" depends on ARCH_OMAP && MTD_NAND diff --git a/drivers/mtd/nand/Makefile b/drivers/mtd/nand/Makefile index 0741d739cb8..33475087dbf 100644 --- a/drivers/mtd/nand/Makefile +++ b/drivers/mtd/nand/Makefile @@ -7,6 +7,7 @@ obj-$(CONFIG_MTD_NAND) += nand.o nand_ecc.o obj-$(CONFIG_MTD_NAND_IDS) += nand_ids.o obj-$(CONFIG_MTD_NAND_SPIA) += spia.o +obj-$(CONFIG_MTD_NAND_AMS_DELTA) += ams-delta.o obj-$(CONFIG_MTD_NAND_TOTO) += toto.o obj-$(CONFIG_MTD_NAND_AUTCPU12) += autcpu12.o obj-$(CONFIG_MTD_NAND_EDB7312) += edb7312.o diff --git a/drivers/mtd/nand/ams-delta.c b/drivers/mtd/nand/ams-delta.c new file mode 100644 index 00000000000..5a349eb316f --- /dev/null +++ b/drivers/mtd/nand/ams-delta.c @@ -0,0 +1,238 @@ +/* + * drivers/mtd/nand/ams-delta.c + * + * Copyright (C) 2006 Jonathan McDowell <noodles@earth.li> + * + * Derived from drivers/mtd/toto.c + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License version 2 as + * published by the Free Software Foundation. + * + * Overview: + * This is a device driver for the NAND flash device found on the + * Amstrad E3 (Delta). + */ + +#include <linux/slab.h> +#include <linux/init.h> +#include <linux/module.h> +#include <linux/delay.h> +#include <linux/mtd/mtd.h> +#include <linux/mtd/nand.h> +#include <linux/mtd/partitions.h> +#include <asm/io.h> +#include <asm/arch/hardware.h> +#include <asm/sizes.h> +#include <asm/arch/gpio.h> +#include <asm/arch/board-ams-delta.h> + +/* + * MTD structure for E3 (Delta) + */ +static struct mtd_info *ams_delta_mtd = NULL; + +#define NAND_MASK (AMS_DELTA_LATCH2_NAND_NRE | AMS_DELTA_LATCH2_NAND_NWE | AMS_DELTA_LATCH2_NAND_CLE | AMS_DELTA_LATCH2_NAND_ALE | AMS_DELTA_LATCH2_NAND_NCE | AMS_DELTA_LATCH2_NAND_NWP) + +#define T_NAND_CTL_CLRALE(iob) ams_delta_latch2_write(AMS_DELTA_LATCH2_NAND_ALE, 0) +#define T_NAND_CTL_SETALE(iob) ams_delta_latch2_write(AMS_DELTA_LATCH2_NAND_ALE, AMS_DELTA_LATCH2_NAND_ALE) +#define T_NAND_CTL_CLRCLE(iob) ams_delta_latch2_write(AMS_DELTA_LATCH2_NAND_CLE, 0) +#define T_NAND_CTL_SETCLE(iob) ams_delta_latch2_write(AMS_DELTA_LATCH2_NAND_CLE, AMS_DELTA_LATCH2_NAND_CLE) +#define T_NAND_CTL_SETNCE(iob) ams_delta_latch2_write(AMS_DELTA_LATCH2_NAND_NCE, 0) +#define T_NAND_CTL_CLRNCE(iob) ams_delta_latch2_write(AMS_DELTA_LATCH2_NAND_NCE, AMS_DELTA_LATCH2_NAND_NCE) + +/* + * Define partitions for flash devices + */ + +static struct mtd_partition partition_info[] = { + { .name = "Kernel", + .offset = 0, + .size = 3 * SZ_1M + SZ_512K }, + { .name = "u-boot", + .offset = 3 * SZ_1M + SZ_512K, + .size = SZ_256K }, + { .name = "u-boot params", + .offset = 3 * SZ_1M + SZ_512K + SZ_256K, + .size = SZ_256K }, + { .name = "Amstrad LDR", + .offset = 4 * SZ_1M, + .size = SZ_256K }, + { .name = "File system", + .offset = 4 * SZ_1M + 1 * SZ_256K, + .size = 27 * SZ_1M }, + { .name = "PBL reserved", + .offset = 32 * SZ_1M - 3 * SZ_256K, + .size = 3 * SZ_256K }, +}; + +/* + * hardware specific access to control-lines +*/ + +static void ams_delta_hwcontrol(struct mtd_info *mtd, int cmd) +{ + switch (cmd) { + + case NAND_CTL_SETCLE: T_NAND_CTL_SETCLE(cmd); break; + case NAND_CTL_CLRCLE: T_NAND_CTL_CLRCLE(cmd); break; + + case NAND_CTL_SETALE: T_NAND_CTL_SETALE(cmd); break; + case NAND_CTL_CLRALE: T_NAND_CTL_CLRALE(cmd); break; + + case NAND_CTL_SETNCE: T_NAND_CTL_SETNCE(cmd); break; + case NAND_CTL_CLRNCE: T_NAND_CTL_CLRNCE(cmd); break; + } +} + +static void ams_delta_write_byte(struct mtd_info *mtd, u_char byte) +{ + struct nand_chip *this = mtd->priv; + + omap_writew(0, (OMAP_MPUIO_BASE + OMAP_MPUIO_IO_CNTL)); + omap_writew(byte, this->IO_ADDR_W); + ams_delta_latch2_write(AMS_DELTA_LATCH2_NAND_NWE, 0); + ndelay(40); + ams_delta_latch2_write(AMS_DELTA_LATCH2_NAND_NWE, + AMS_DELTA_LATCH2_NAND_NWE); +} + +static u_char ams_delta_read_byte(struct mtd_info *mtd) +{ + u_char res; + struct nand_chip *this = mtd->priv; + + ams_delta_latch2_write(AMS_DELTA_LATCH2_NAND_NRE, 0); + ndelay(40); + omap_writew(~0, (OMAP_MPUIO_BASE + OMAP_MPUIO_IO_CNTL)); + res = omap_readw(this->IO_ADDR_R); + ams_delta_latch2_write(AMS_DELTA_LATCH2_NAND_NRE, + AMS_DELTA_LATCH2_NAND_NRE); + + return res; +} + +static void ams_delta_write_buf(struct mtd_info *mtd, const u_char *buf, + int len) +{ + int i; + + for (i=0; i<len; i++) + ams_delta_write_byte(mtd, buf[i]); +} + +static void ams_delta_read_buf(struct mtd_info *mtd, u_char *buf, int len) +{ + int i; + + for (i=0; i<len; i++) + buf[i] = ams_delta_read_byte(mtd); +} + +static int ams_delta_verify_buf(struct mtd_info *mtd, const u_char *buf, + int len) +{ + int i; + + for (i=0; i<len; i++) + if (buf[i] != ams_delta_read_byte(mtd)) + return -EFAULT; + + return 0; +} + +static int ams_delta_nand_ready(struct mtd_info *mtd) +{ + return omap_get_gpio_datain(AMS_DELTA_GPIO_PIN_NAND_RB); +} + +/* + * Main initialization routine + */ +static int __init ams_delta_init(void) +{ + struct nand_chip *this; + int err = 0; + + /* Allocate memory for MTD device structure and private data */ + ams_delta_mtd = kmalloc(sizeof(struct mtd_info) + + sizeof(struct nand_chip), GFP_KERNEL); + if (!ams_delta_mtd) { + printk (KERN_WARNING "Unable to allocate E3 NAND MTD device structure.\n"); + err = -ENOMEM; + goto out; + } + + ams_delta_mtd->owner = THIS_MODULE; + + /* Get pointer to private data */ + this = (struct nand_chip *) (&ams_delta_mtd[1]); + + /* Initialize structures */ + memset(ams_delta_mtd, 0, sizeof(struct mtd_info)); + memset(this, 0, sizeof(struct nand_chip)); + + /* Link the private data with the MTD structure */ + ams_delta_mtd->priv = this; + + /* Set address of NAND IO lines */ + this->IO_ADDR_R = (OMAP_MPUIO_BASE + OMAP_MPUIO_INPUT_LATCH); + this->IO_ADDR_W = (OMAP_MPUIO_BASE + OMAP_MPUIO_OUTPUT); + this->read_byte = ams_delta_read_byte; + this->write_byte = ams_delta_write_byte; + this->write_buf = ams_delta_write_buf; + this->read_buf = ams_delta_read_buf; + this->verify_buf = ams_delta_verify_buf; + this->hwcontrol = ams_delta_hwcontrol; + if (!omap_request_gpio(AMS_DELTA_GPIO_PIN_NAND_RB)) { + this->dev_ready = ams_delta_nand_ready; + } else { + this->dev_ready = NULL; + printk(KERN_NOTICE "Couldn't request gpio for Delta NAND ready.\n"); + } + /* 25 us command delay time */ + this->chip_delay = 30; + this->eccmode = NAND_ECC_SOFT; + + /* Set chip enabled, but */ + ams_delta_latch2_write(NAND_MASK, AMS_DELTA_LATCH2_NAND_NRE | + AMS_DELTA_LATCH2_NAND_NWE | + AMS_DELTA_LATCH2_NAND_NCE | + AMS_DELTA_LATCH2_NAND_NWP); + + /* Scan to find existance of the device */ + if (nand_scan(ams_delta_mtd, 1)) { + err = -ENXIO; + goto out_mtd; + } + + /* Register the partitions */ + add_mtd_partitions(ams_delta_mtd, partition_info, + ARRAY_SIZE(partition_info)); + + goto out; + + out_mtd: + kfree(ams_delta_mtd); + out: + return err; +} + +module_init(ams_delta_init); + +/* + * Clean up routine + */ +static void __exit ams_delta_cleanup(void) +{ + /* Release resources, unregister device */ + nand_release(ams_delta_mtd); + + /* Free the MTD device structure */ + kfree(ams_delta_mtd); +} +module_exit(ams_delta_cleanup); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Jonathan McDowell <noodles@earth.li>"); +MODULE_DESCRIPTION("Glue layer for NAND flash on Amstrad E3 (Delta)"); |