linux/drivers/mtd/nand/autcpu12.c
<<
>>
Prefs
   1/*
   2 *  drivers/mtd/autcpu12.c
   3 *
   4 *  Copyright (c) 2002 Thomas Gleixner <tgxl@linutronix.de>
   5 *
   6 *  Derived from drivers/mtd/spia.c
   7 *       Copyright (C) 2000 Steven J. Hill (sjhill@realitydiluted.com)
   8 *
   9 * This program is free software; you can redistribute it and/or modify
  10 * it under the terms of the GNU General Public License version 2 as
  11 * published by the Free Software Foundation.
  12 *
  13 *  Overview:
  14 *   This is a device driver for the NAND flash device found on the
  15 *   autronix autcpu12 board, which is a SmartMediaCard. It supports
  16 *   16MiB, 32MiB and 64MiB cards.
  17 *
  18 *
  19 *      02-12-2002 TG   Cleanup of module params
  20 *
  21 *      02-20-2002 TG   adjusted for different rd/wr address support
  22 *                      added support for read device ready/busy line
  23 *                      added page_cache
  24 *
  25 *      10-06-2002 TG   128K card support added
  26 */
  27
  28#include <linux/slab.h>
  29#include <linux/init.h>
  30#include <linux/module.h>
  31#include <linux/mtd/mtd.h>
  32#include <linux/mtd/nand.h>
  33#include <linux/mtd/partitions.h>
  34#include <asm/io.h>
  35#include <mach/hardware.h>
  36#include <asm/sizes.h>
  37#include <mach/autcpu12.h>
  38
  39/*
  40 * MTD structure for AUTCPU12 board
  41 */
  42static struct mtd_info *autcpu12_mtd = NULL;
  43static void __iomem *autcpu12_fio_base;
  44
  45/*
  46 * Define partitions for flash devices
  47 */
  48static struct mtd_partition partition_info16k[] = {
  49        { .name         = "AUTCPU12 flash partition 1",
  50          .offset       = 0,
  51          .size         = 8 * SZ_1M },
  52        { .name         = "AUTCPU12 flash partition 2",
  53          .offset       = 8 * SZ_1M,
  54          .size         = 8 * SZ_1M },
  55};
  56
  57static struct mtd_partition partition_info32k[] = {
  58        { .name         = "AUTCPU12 flash partition 1",
  59          .offset       = 0,
  60          .size         = 8 * SZ_1M },
  61        { .name         = "AUTCPU12 flash partition 2",
  62          .offset       = 8 * SZ_1M,
  63          .size         = 24 * SZ_1M },
  64};
  65
  66static struct mtd_partition partition_info64k[] = {
  67        { .name         = "AUTCPU12 flash partition 1",
  68          .offset       = 0,
  69          .size         = 16 * SZ_1M },
  70        { .name         = "AUTCPU12 flash partition 2",
  71          .offset       = 16 * SZ_1M,
  72          .size         = 48 * SZ_1M },
  73};
  74
  75static struct mtd_partition partition_info128k[] = {
  76        { .name         = "AUTCPU12 flash partition 1",
  77          .offset       = 0,
  78          .size         = 16 * SZ_1M },
  79        { .name         = "AUTCPU12 flash partition 2",
  80          .offset       = 16 * SZ_1M,
  81          .size         = 112 * SZ_1M },
  82};
  83
  84#define NUM_PARTITIONS16K 2
  85#define NUM_PARTITIONS32K 2
  86#define NUM_PARTITIONS64K 2
  87#define NUM_PARTITIONS128K 2
  88/*
  89 *      hardware specific access to control-lines
  90 *
  91 *      ALE bit 4 autcpu12_pedr
  92 *      CLE bit 5 autcpu12_pedr
  93 *      NCE bit 0 fio_ctrl
  94 *
  95 */
  96static void autcpu12_hwcontrol(struct mtd_info *mtd, int cmd,
  97                               unsigned int ctrl)
  98{
  99        struct nand_chip *chip = mtd->priv;
 100
 101        if (ctrl & NAND_CTRL_CHANGE) {
 102                void __iomem *addr;
 103                unsigned char bits;
 104
 105                addr = CS89712_VIRT_BASE + AUTCPU12_SMC_PORT_OFFSET;
 106                bits = (ctrl & NAND_CLE) << 4;
 107                bits |= (ctrl & NAND_ALE) << 2;
 108                writeb((readb(addr) & ~0x30) | bits, addr);
 109
 110                addr = autcpu12_fio_base + AUTCPU12_SMC_SELECT_OFFSET;
 111                writeb((readb(addr) & ~0x1) | (ctrl & NAND_NCE), addr);
 112        }
 113
 114        if (cmd != NAND_CMD_NONE)
 115                writeb(cmd, chip->IO_ADDR_W);
 116}
 117
 118/*
 119 *      read device ready pin
 120 */
 121int autcpu12_device_ready(struct mtd_info *mtd)
 122{
 123        void __iomem *addr = CS89712_VIRT_BASE + AUTCPU12_SMC_PORT_OFFSET;
 124
 125        return readb(addr) & AUTCPU12_SMC_RDY;
 126}
 127
 128/*
 129 * Main initialization routine
 130 */
 131static int __init autcpu12_init(void)
 132{
 133        struct nand_chip *this;
 134        int err = 0;
 135
 136        /* Allocate memory for MTD device structure and private data */
 137        autcpu12_mtd = kmalloc(sizeof(struct mtd_info) + sizeof(struct nand_chip),
 138                               GFP_KERNEL);
 139        if (!autcpu12_mtd) {
 140                printk("Unable to allocate AUTCPU12 NAND MTD device structure.\n");
 141                err = -ENOMEM;
 142                goto out;
 143        }
 144
 145        /* map physical address */
 146        autcpu12_fio_base = ioremap(AUTCPU12_PHYS_SMC, SZ_1K);
 147        if (!autcpu12_fio_base) {
 148                printk("Ioremap autcpu12 SmartMedia Card failed\n");
 149                err = -EIO;
 150                goto out_mtd;
 151        }
 152
 153        /* Get pointer to private data */
 154        this = (struct nand_chip *)(&autcpu12_mtd[1]);
 155
 156        /* Initialize structures */
 157        memset(autcpu12_mtd, 0, sizeof(struct mtd_info));
 158        memset(this, 0, sizeof(struct nand_chip));
 159
 160        /* Link the private data with the MTD structure */
 161        autcpu12_mtd->priv = this;
 162        autcpu12_mtd->owner = THIS_MODULE;
 163
 164        /* Set address of NAND IO lines */
 165        this->IO_ADDR_R = autcpu12_fio_base;
 166        this->IO_ADDR_W = autcpu12_fio_base;
 167        this->cmd_ctrl = autcpu12_hwcontrol;
 168        this->dev_ready = autcpu12_device_ready;
 169        /* 20 us command delay time */
 170        this->chip_delay = 20;
 171        this->ecc.mode = NAND_ECC_SOFT;
 172
 173        /* Enable the following for a flash based bad block table */
 174        /*
 175           this->options = NAND_USE_FLASH_BBT;
 176         */
 177        this->options = NAND_USE_FLASH_BBT;
 178
 179        /* Scan to find existance of the device */
 180        if (nand_scan(autcpu12_mtd, 1)) {
 181                err = -ENXIO;
 182                goto out_ior;
 183        }
 184
 185        /* Register the partitions */
 186        switch (autcpu12_mtd->size) {
 187                case SZ_16M:
 188                        add_mtd_partitions(autcpu12_mtd, partition_info16k,
 189                                           NUM_PARTITIONS16K);
 190                        break;
 191                case SZ_32M:
 192                        add_mtd_partitions(autcpu12_mtd, partition_info32k,
 193                                           NUM_PARTITIONS32K);
 194                        break;
 195                case SZ_64M:
 196                        add_mtd_partitions(autcpu12_mtd, partition_info64k,
 197                                           NUM_PARTITIONS64K);
 198                        break;
 199                case SZ_128M:
 200                        add_mtd_partitions(autcpu12_mtd, partition_info128k,
 201                                           NUM_PARTITIONS128K);
 202                        break;
 203                default:
 204                        printk("Unsupported SmartMedia device\n");
 205                        err = -ENXIO;
 206                        goto out_ior;
 207        }
 208        goto out;
 209
 210 out_ior:
 211        iounmap(autcpu12_fio_base);
 212 out_mtd:
 213        kfree(autcpu12_mtd);
 214 out:
 215        return err;
 216}
 217
 218module_init(autcpu12_init);
 219
 220/*
 221 * Clean up routine
 222 */
 223static void __exit autcpu12_cleanup(void)
 224{
 225        /* Release resources, unregister device */
 226        nand_release(autcpu12_mtd);
 227
 228        /* unmap physical address */
 229        iounmap(autcpu12_fio_base);
 230
 231        /* Free the MTD device structure */
 232        kfree(autcpu12_mtd);
 233}
 234
 235module_exit(autcpu12_cleanup);
 236
 237MODULE_LICENSE("GPL");
 238MODULE_AUTHOR("Thomas Gleixner <tglx@linutronix.de>");
 239MODULE_DESCRIPTION("Glue layer for SmartMediaCard on autronix autcpu12");
 240