diff options
Diffstat (limited to 'drivers/mtd/nand/w90p910_nand.c')
-rw-r--r-- | drivers/mtd/nand/w90p910_nand.c | 382 |
1 files changed, 0 insertions, 382 deletions
diff --git a/drivers/mtd/nand/w90p910_nand.c b/drivers/mtd/nand/w90p910_nand.c deleted file mode 100644 index 7680e731348a..000000000000 --- a/drivers/mtd/nand/w90p910_nand.c +++ /dev/null @@ -1,382 +0,0 @@ -/* - * Copyright (c) 2009 Nuvoton technology corporation. - * - * Wan ZongShun <mcuos.com@gmail.com> - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation;version 2 of the License. - * - */ - -#include <linux/slab.h> -#include <linux/init.h> -#include <linux/module.h> -#include <linux/interrupt.h> -#include <linux/io.h> -#include <linux/platform_device.h> -#include <linux/delay.h> -#include <linux/clk.h> -#include <linux/err.h> - -#include <linux/mtd/mtd.h> -#include <linux/mtd/nand.h> -#include <linux/mtd/partitions.h> - -#define REG_FMICSR 0x00 -#define REG_SMCSR 0xa0 -#define REG_SMISR 0xac -#define REG_SMCMD 0xb0 -#define REG_SMADDR 0xb4 -#define REG_SMDATA 0xb8 - -#define RESET_FMI 0x01 -#define NAND_EN 0x08 -#define READYBUSY (0x01 << 18) - -#define SWRST 0x01 -#define PSIZE (0x01 << 3) -#define DMARWEN (0x03 << 1) -#define BUSWID (0x01 << 4) -#define ECC4EN (0x01 << 5) -#define WP (0x01 << 24) -#define NANDCS (0x01 << 25) -#define ENDADDR (0x01 << 31) - -#define read_data_reg(dev) \ - __raw_readl((dev)->reg + REG_SMDATA) - -#define write_data_reg(dev, val) \ - __raw_writel((val), (dev)->reg + REG_SMDATA) - -#define write_cmd_reg(dev, val) \ - __raw_writel((val), (dev)->reg + REG_SMCMD) - -#define write_addr_reg(dev, val) \ - __raw_writel((val), (dev)->reg + REG_SMADDR) - -struct w90p910_nand { - struct mtd_info mtd; - struct nand_chip chip; - void __iomem *reg; - struct clk *clk; - spinlock_t lock; -}; - -static const struct mtd_partition partitions[] = { - { - .name = "NAND FS 0", - .offset = 0, - .size = 8 * 1024 * 1024 - }, - { - .name = "NAND FS 1", - .offset = MTDPART_OFS_APPEND, - .size = MTDPART_SIZ_FULL - } -}; - -static unsigned char w90p910_nand_read_byte(struct mtd_info *mtd) -{ - unsigned char ret; - struct w90p910_nand *nand; - - nand = container_of(mtd, struct w90p910_nand, mtd); - - ret = (unsigned char)read_data_reg(nand); - - return ret; -} - -static void w90p910_nand_read_buf(struct mtd_info *mtd, - unsigned char *buf, int len) -{ - int i; - struct w90p910_nand *nand; - - nand = container_of(mtd, struct w90p910_nand, mtd); - - for (i = 0; i < len; i++) - buf[i] = (unsigned char)read_data_reg(nand); -} - -static void w90p910_nand_write_buf(struct mtd_info *mtd, - const unsigned char *buf, int len) -{ - int i; - struct w90p910_nand *nand; - - nand = container_of(mtd, struct w90p910_nand, mtd); - - for (i = 0; i < len; i++) - write_data_reg(nand, buf[i]); -} - -static int w90p910_verify_buf(struct mtd_info *mtd, - const unsigned char *buf, int len) -{ - int i; - struct w90p910_nand *nand; - - nand = container_of(mtd, struct w90p910_nand, mtd); - - for (i = 0; i < len; i++) { - if (buf[i] != (unsigned char)read_data_reg(nand)) - return -EFAULT; - } - - return 0; -} - -static int w90p910_check_rb(struct w90p910_nand *nand) -{ - unsigned int val; - spin_lock(&nand->lock); - val = __raw_readl(REG_SMISR); - val &= READYBUSY; - spin_unlock(&nand->lock); - - return val; -} - -static int w90p910_nand_devready(struct mtd_info *mtd) -{ - struct w90p910_nand *nand; - int ready; - - nand = container_of(mtd, struct w90p910_nand, mtd); - - ready = (w90p910_check_rb(nand)) ? 1 : 0; - return ready; -} - -static void w90p910_nand_command_lp(struct mtd_info *mtd, - unsigned int command, int column, int page_addr) -{ - register struct nand_chip *chip = mtd->priv; - struct w90p910_nand *nand; - - nand = container_of(mtd, struct w90p910_nand, mtd); - - if (command == NAND_CMD_READOOB) { - column += mtd->writesize; - command = NAND_CMD_READ0; - } - - write_cmd_reg(nand, command & 0xff); - - if (column != -1 || page_addr != -1) { - - if (column != -1) { - if (chip->options & NAND_BUSWIDTH_16) - column >>= 1; - write_addr_reg(nand, column); - write_addr_reg(nand, column >> 8 | ENDADDR); - } - if (page_addr != -1) { - write_addr_reg(nand, page_addr); - - if (chip->chipsize > (128 << 20)) { - write_addr_reg(nand, page_addr >> 8); - write_addr_reg(nand, page_addr >> 16 | ENDADDR); - } else { - write_addr_reg(nand, page_addr >> 8 | ENDADDR); - } - } - } - - switch (command) { - case NAND_CMD_CACHEDPROG: - case NAND_CMD_PAGEPROG: - case NAND_CMD_ERASE1: - case NAND_CMD_ERASE2: - case NAND_CMD_SEQIN: - case NAND_CMD_RNDIN: - case NAND_CMD_STATUS: - case NAND_CMD_DEPLETE1: - return; - - case NAND_CMD_STATUS_ERROR: - case NAND_CMD_STATUS_ERROR0: - case NAND_CMD_STATUS_ERROR1: - case NAND_CMD_STATUS_ERROR2: - case NAND_CMD_STATUS_ERROR3: - udelay(chip->chip_delay); - return; - - case NAND_CMD_RESET: - if (chip->dev_ready) - break; - udelay(chip->chip_delay); - - write_cmd_reg(nand, NAND_CMD_STATUS); - write_cmd_reg(nand, command); - - while (!w90p910_check_rb(nand)) - ; - - return; - - case NAND_CMD_RNDOUT: - write_cmd_reg(nand, NAND_CMD_RNDOUTSTART); - return; - - case NAND_CMD_READ0: - - write_cmd_reg(nand, NAND_CMD_READSTART); - default: - - if (!chip->dev_ready) { - udelay(chip->chip_delay); - return; - } - } - - /* Apply this short delay always to ensure that we do wait tWB in - * any case on any machine. */ - ndelay(100); - - while (!chip->dev_ready(mtd)) - ; -} - - -static void w90p910_nand_enable(struct w90p910_nand *nand) -{ - unsigned int val; - spin_lock(&nand->lock); - __raw_writel(RESET_FMI, (nand->reg + REG_FMICSR)); - - val = __raw_readl(nand->reg + REG_FMICSR); - - if (!(val & NAND_EN)) - __raw_writel(val | NAND_EN, REG_FMICSR); - - val = __raw_readl(nand->reg + REG_SMCSR); - - val &= ~(SWRST|PSIZE|DMARWEN|BUSWID|ECC4EN|NANDCS); - val |= WP; - - __raw_writel(val, nand->reg + REG_SMCSR); - - spin_unlock(&nand->lock); -} - -static int __devinit w90p910_nand_probe(struct platform_device *pdev) -{ - struct w90p910_nand *w90p910_nand; - struct nand_chip *chip; - int retval; - struct resource *res; - - retval = 0; - - w90p910_nand = kzalloc(sizeof(struct w90p910_nand), GFP_KERNEL); - if (!w90p910_nand) - return -ENOMEM; - chip = &(w90p910_nand->chip); - - w90p910_nand->mtd.priv = chip; - w90p910_nand->mtd.owner = THIS_MODULE; - spin_lock_init(&w90p910_nand->lock); - - w90p910_nand->clk = clk_get(&pdev->dev, NULL); - if (IS_ERR(w90p910_nand->clk)) { - retval = -ENOENT; - goto fail1; - } - clk_enable(w90p910_nand->clk); - - chip->cmdfunc = w90p910_nand_command_lp; - chip->dev_ready = w90p910_nand_devready; - chip->read_byte = w90p910_nand_read_byte; - chip->write_buf = w90p910_nand_write_buf; - chip->read_buf = w90p910_nand_read_buf; - chip->verify_buf = w90p910_verify_buf; - chip->chip_delay = 50; - chip->options = 0; - chip->ecc.mode = NAND_ECC_SOFT; - - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - if (!res) { - retval = -ENXIO; - goto fail1; - } - - if (!request_mem_region(res->start, resource_size(res), pdev->name)) { - retval = -EBUSY; - goto fail1; - } - - w90p910_nand->reg = ioremap(res->start, resource_size(res)); - if (!w90p910_nand->reg) { - retval = -ENOMEM; - goto fail2; - } - - w90p910_nand_enable(w90p910_nand); - - if (nand_scan(&(w90p910_nand->mtd), 1)) { - retval = -ENXIO; - goto fail3; - } - - add_mtd_partitions(&(w90p910_nand->mtd), partitions, - ARRAY_SIZE(partitions)); - - platform_set_drvdata(pdev, w90p910_nand); - - return retval; - -fail3: iounmap(w90p910_nand->reg); -fail2: release_mem_region(res->start, resource_size(res)); -fail1: kfree(w90p910_nand); - return retval; -} - -static int __devexit w90p910_nand_remove(struct platform_device *pdev) -{ - struct w90p910_nand *w90p910_nand = platform_get_drvdata(pdev); - struct resource *res; - - iounmap(w90p910_nand->reg); - - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); - release_mem_region(res->start, resource_size(res)); - - clk_disable(w90p910_nand->clk); - clk_put(w90p910_nand->clk); - - kfree(w90p910_nand); - - platform_set_drvdata(pdev, NULL); - - return 0; -} - -static struct platform_driver w90p910_nand_driver = { - .probe = w90p910_nand_probe, - .remove = __devexit_p(w90p910_nand_remove), - .driver = { - .name = "w90p910-fmi", - .owner = THIS_MODULE, - }, -}; - -static int __init w90p910_nand_init(void) -{ - return platform_driver_register(&w90p910_nand_driver); -} - -static void __exit w90p910_nand_exit(void) -{ - platform_driver_unregister(&w90p910_nand_driver); -} - -module_init(w90p910_nand_init); -module_exit(w90p910_nand_exit); - -MODULE_AUTHOR("Wan ZongShun <mcuos.com@gmail.com>"); -MODULE_DESCRIPTION("w90p910 nand driver!"); -MODULE_LICENSE("GPL"); -MODULE_ALIAS("platform:w90p910-fmi"); |