linux/drivers/mtd/nand/ams-delta.c
<<
>>
Prefs
   1/*
   2 *  drivers/mtd/nand/ams-delta.c
   3 *
   4 *  Copyright (C) 2006 Jonathan McDowell <noodles@earth.li>
   5 *
   6 *  Derived from drivers/mtd/toto.c
   7 *
   8 * This program is free software; you can redistribute it and/or modify
   9 * it under the terms of the GNU General Public License version 2 as
  10 * published by the Free Software Foundation.
  11 *
  12 *  Overview:
  13 *   This is a device driver for the NAND flash device found on the
  14 *   Amstrad E3 (Delta).
  15 */
  16
  17#include <linux/slab.h>
  18#include <linux/init.h>
  19#include <linux/module.h>
  20#include <linux/delay.h>
  21#include <linux/mtd/mtd.h>
  22#include <linux/mtd/nand.h>
  23#include <linux/mtd/partitions.h>
  24#include <asm/io.h>
  25#include <mach/hardware.h>
  26#include <asm/sizes.h>
  27#include <mach/gpio.h>
  28#include <mach/board-ams-delta.h>
  29
  30/*
  31 * MTD structure for E3 (Delta)
  32 */
  33static struct mtd_info *ams_delta_mtd = NULL;
  34
  35#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)
  36
  37/*
  38 * Define partitions for flash devices
  39 */
  40
  41static struct mtd_partition partition_info[] = {
  42        { .name         = "Kernel",
  43          .offset       = 0,
  44          .size         = 3 * SZ_1M + SZ_512K },
  45        { .name         = "u-boot",
  46          .offset       = 3 * SZ_1M + SZ_512K,
  47          .size         = SZ_256K },
  48        { .name         = "u-boot params",
  49          .offset       = 3 * SZ_1M + SZ_512K + SZ_256K,
  50          .size         = SZ_256K },
  51        { .name         = "Amstrad LDR",
  52          .offset       = 4 * SZ_1M,
  53          .size         = SZ_256K },
  54        { .name         = "File system",
  55          .offset       = 4 * SZ_1M + 1 * SZ_256K,
  56          .size         = 27 * SZ_1M },
  57        { .name         = "PBL reserved",
  58          .offset       = 32 * SZ_1M - 3 * SZ_256K,
  59          .size         =  3 * SZ_256K },
  60};
  61
  62static void ams_delta_write_byte(struct mtd_info *mtd, u_char byte)
  63{
  64        struct nand_chip *this = mtd->priv;
  65
  66        omap_writew(0, (OMAP1_MPUIO_BASE + OMAP_MPUIO_IO_CNTL));
  67        omap_writew(byte, this->IO_ADDR_W);
  68        ams_delta_latch2_write(AMS_DELTA_LATCH2_NAND_NWE, 0);
  69        ndelay(40);
  70        ams_delta_latch2_write(AMS_DELTA_LATCH2_NAND_NWE,
  71                               AMS_DELTA_LATCH2_NAND_NWE);
  72}
  73
  74static u_char ams_delta_read_byte(struct mtd_info *mtd)
  75{
  76        u_char res;
  77        struct nand_chip *this = mtd->priv;
  78
  79        ams_delta_latch2_write(AMS_DELTA_LATCH2_NAND_NRE, 0);
  80        ndelay(40);
  81        omap_writew(~0, (OMAP1_MPUIO_BASE + OMAP_MPUIO_IO_CNTL));
  82        res = omap_readw(this->IO_ADDR_R);
  83        ams_delta_latch2_write(AMS_DELTA_LATCH2_NAND_NRE,
  84                               AMS_DELTA_LATCH2_NAND_NRE);
  85
  86        return res;
  87}
  88
  89static void ams_delta_write_buf(struct mtd_info *mtd, const u_char *buf,
  90                                int len)
  91{
  92        int i;
  93
  94        for (i=0; i<len; i++)
  95                ams_delta_write_byte(mtd, buf[i]);
  96}
  97
  98static void ams_delta_read_buf(struct mtd_info *mtd, u_char *buf, int len)
  99{
 100        int i;
 101
 102        for (i=0; i<len; i++)
 103                buf[i] = ams_delta_read_byte(mtd);
 104}
 105
 106static int ams_delta_verify_buf(struct mtd_info *mtd, const u_char *buf,
 107                                int len)
 108{
 109        int i;
 110
 111        for (i=0; i<len; i++)
 112                if (buf[i] != ams_delta_read_byte(mtd))
 113                        return -EFAULT;
 114
 115        return 0;
 116}
 117
 118/*
 119 * Command control function
 120 *
 121 * ctrl:
 122 * NAND_NCE: bit 0 -> bit 2
 123 * NAND_CLE: bit 1 -> bit 7
 124 * NAND_ALE: bit 2 -> bit 6
 125 */
 126static void ams_delta_hwcontrol(struct mtd_info *mtd, int cmd,
 127                                unsigned int ctrl)
 128{
 129
 130        if (ctrl & NAND_CTRL_CHANGE) {
 131                unsigned long bits;
 132
 133                bits = (~ctrl & NAND_NCE) ? AMS_DELTA_LATCH2_NAND_NCE : 0;
 134                bits |= (ctrl & NAND_CLE) ? AMS_DELTA_LATCH2_NAND_CLE : 0;
 135                bits |= (ctrl & NAND_ALE) ? AMS_DELTA_LATCH2_NAND_ALE : 0;
 136
 137                ams_delta_latch2_write(AMS_DELTA_LATCH2_NAND_CLE |
 138                                AMS_DELTA_LATCH2_NAND_ALE |
 139                                AMS_DELTA_LATCH2_NAND_NCE, bits);
 140        }
 141
 142        if (cmd != NAND_CMD_NONE)
 143                ams_delta_write_byte(mtd, cmd);
 144}
 145
 146static int ams_delta_nand_ready(struct mtd_info *mtd)
 147{
 148        return gpio_get_value(AMS_DELTA_GPIO_PIN_NAND_RB);
 149}
 150
 151/*
 152 * Main initialization routine
 153 */
 154static int __init ams_delta_init(void)
 155{
 156        struct nand_chip *this;
 157        int err = 0;
 158
 159        /* Allocate memory for MTD device structure and private data */
 160        ams_delta_mtd = kmalloc(sizeof(struct mtd_info) +
 161                                sizeof(struct nand_chip), GFP_KERNEL);
 162        if (!ams_delta_mtd) {
 163                printk (KERN_WARNING "Unable to allocate E3 NAND MTD device structure.\n");
 164                err = -ENOMEM;
 165                goto out;
 166        }
 167
 168        ams_delta_mtd->owner = THIS_MODULE;
 169
 170        /* Get pointer to private data */
 171        this = (struct nand_chip *) (&ams_delta_mtd[1]);
 172
 173        /* Initialize structures */
 174        memset(ams_delta_mtd, 0, sizeof(struct mtd_info));
 175        memset(this, 0, sizeof(struct nand_chip));
 176
 177        /* Link the private data with the MTD structure */
 178        ams_delta_mtd->priv = this;
 179
 180        /* Set address of NAND IO lines */
 181        this->IO_ADDR_R = (OMAP1_MPUIO_BASE + OMAP_MPUIO_INPUT_LATCH);
 182        this->IO_ADDR_W = (OMAP1_MPUIO_BASE + OMAP_MPUIO_OUTPUT);
 183        this->read_byte = ams_delta_read_byte;
 184        this->write_buf = ams_delta_write_buf;
 185        this->read_buf = ams_delta_read_buf;
 186        this->verify_buf = ams_delta_verify_buf;
 187        this->cmd_ctrl = ams_delta_hwcontrol;
 188        if (gpio_request(AMS_DELTA_GPIO_PIN_NAND_RB, "nand_rdy") == 0) {
 189                this->dev_ready = ams_delta_nand_ready;
 190        } else {
 191                this->dev_ready = NULL;
 192                printk(KERN_NOTICE "Couldn't request gpio for Delta NAND ready.\n");
 193        }
 194        /* 25 us command delay time */
 195        this->chip_delay = 30;
 196        this->ecc.mode = NAND_ECC_SOFT;
 197
 198        /* Set chip enabled, but  */
 199        ams_delta_latch2_write(NAND_MASK, AMS_DELTA_LATCH2_NAND_NRE |
 200                                          AMS_DELTA_LATCH2_NAND_NWE |
 201                                          AMS_DELTA_LATCH2_NAND_NCE |
 202                                          AMS_DELTA_LATCH2_NAND_NWP);
 203
 204        /* Scan to find existance of the device */
 205        if (nand_scan(ams_delta_mtd, 1)) {
 206                err = -ENXIO;
 207                goto out_mtd;
 208        }
 209
 210        /* Register the partitions */
 211        add_mtd_partitions(ams_delta_mtd, partition_info,
 212                           ARRAY_SIZE(partition_info));
 213
 214        goto out;
 215
 216 out_mtd:
 217        kfree(ams_delta_mtd);
 218 out:
 219        return err;
 220}
 221
 222module_init(ams_delta_init);
 223
 224/*
 225 * Clean up routine
 226 */
 227static void __exit ams_delta_cleanup(void)
 228{
 229        /* Release resources, unregister device */
 230        nand_release(ams_delta_mtd);
 231
 232        /* Free the MTD device structure */
 233        kfree(ams_delta_mtd);
 234}
 235module_exit(ams_delta_cleanup);
 236
 237MODULE_LICENSE("GPL");
 238MODULE_AUTHOR("Jonathan McDowell <noodles@earth.li>");
 239MODULE_DESCRIPTION("Glue layer for NAND flash on Amstrad E3 (Delta)");
 240