linux/drivers/mtd/nand/cmx270_nand.c
<<
>>
Prefs
   1/*
   2 *  linux/drivers/mtd/nand/cmx270-nand.c
   3 *
   4 *  Copyright (C) 2006 Compulab, Ltd.
   5 *  Mike Rapoport <mike@compulab.co.il>
   6 *
   7 *  Derived from drivers/mtd/nand/h1910.c
   8 *       Copyright (C) 2002 Marius Gröger (mag@sysgo.de)
   9 *       Copyright (c) 2001 Thomas Gleixner (gleixner@autronix.de)
  10 *
  11 *
  12 * This program is free software; you can redistribute it and/or modify
  13 * it under the terms of the GNU General Public License version 2 as
  14 * published by the Free Software Foundation.
  15 *
  16 *  Overview:
  17 *   This is a device driver for the NAND flash device found on the
  18 *   CM-X270 board.
  19 */
  20
  21#include <linux/mtd/nand.h>
  22#include <linux/mtd/partitions.h>
  23#include <linux/slab.h>
  24#include <linux/gpio.h>
  25#include <linux/module.h>
  26
  27#include <asm/io.h>
  28#include <asm/irq.h>
  29#include <asm/mach-types.h>
  30
  31#include <mach/pxa2xx-regs.h>
  32
  33#define GPIO_NAND_CS    (11)
  34#define GPIO_NAND_RB    (89)
  35
  36/* MTD structure for CM-X270 board */
  37static struct mtd_info *cmx270_nand_mtd;
  38
  39/* remaped IO address of the device */
  40static void __iomem *cmx270_nand_io;
  41
  42/*
  43 * Define static partitions for flash device
  44 */
  45static struct mtd_partition partition_info[] = {
  46        [0] = {
  47                .name   = "cmx270-0",
  48                .offset = 0,
  49                .size   = MTDPART_SIZ_FULL
  50        }
  51};
  52#define NUM_PARTITIONS (ARRAY_SIZE(partition_info))
  53
  54static u_char cmx270_read_byte(struct mtd_info *mtd)
  55{
  56        struct nand_chip *this = mtd_to_nand(mtd);
  57
  58        return (readl(this->IO_ADDR_R) >> 16);
  59}
  60
  61static void cmx270_write_buf(struct mtd_info *mtd, const u_char *buf, int len)
  62{
  63        int i;
  64        struct nand_chip *this = mtd_to_nand(mtd);
  65
  66        for (i=0; i<len; i++)
  67                writel((*buf++ << 16), this->IO_ADDR_W);
  68}
  69
  70static void cmx270_read_buf(struct mtd_info *mtd, u_char *buf, int len)
  71{
  72        int i;
  73        struct nand_chip *this = mtd_to_nand(mtd);
  74
  75        for (i=0; i<len; i++)
  76                *buf++ = readl(this->IO_ADDR_R) >> 16;
  77}
  78
  79static inline void nand_cs_on(void)
  80{
  81        gpio_set_value(GPIO_NAND_CS, 0);
  82}
  83
  84static void nand_cs_off(void)
  85{
  86        dsb();
  87
  88        gpio_set_value(GPIO_NAND_CS, 1);
  89}
  90
  91/*
  92 *      hardware specific access to control-lines
  93 */
  94static void cmx270_hwcontrol(struct mtd_info *mtd, int dat,
  95                             unsigned int ctrl)
  96{
  97        struct nand_chip *this = mtd_to_nand(mtd);
  98        unsigned int nandaddr = (unsigned int)this->IO_ADDR_W;
  99
 100        dsb();
 101
 102        if (ctrl & NAND_CTRL_CHANGE) {
 103                if ( ctrl & NAND_ALE )
 104                        nandaddr |=  (1 << 3);
 105                else
 106                        nandaddr &= ~(1 << 3);
 107                if ( ctrl & NAND_CLE )
 108                        nandaddr |=  (1 << 2);
 109                else
 110                        nandaddr &= ~(1 << 2);
 111                if ( ctrl & NAND_NCE )
 112                        nand_cs_on();
 113                else
 114                        nand_cs_off();
 115        }
 116
 117        dsb();
 118        this->IO_ADDR_W = (void __iomem*)nandaddr;
 119        if (dat != NAND_CMD_NONE)
 120                writel((dat << 16), this->IO_ADDR_W);
 121
 122        dsb();
 123}
 124
 125/*
 126 *      read device ready pin
 127 */
 128static int cmx270_device_ready(struct mtd_info *mtd)
 129{
 130        dsb();
 131
 132        return (gpio_get_value(GPIO_NAND_RB));
 133}
 134
 135/*
 136 * Main initialization routine
 137 */
 138static int __init cmx270_init(void)
 139{
 140        struct nand_chip *this;
 141        int ret;
 142
 143        if (!(machine_is_armcore() && cpu_is_pxa27x()))
 144                return -ENODEV;
 145
 146        ret = gpio_request(GPIO_NAND_CS, "NAND CS");
 147        if (ret) {
 148                pr_warning("CM-X270: failed to request NAND CS gpio\n");
 149                return ret;
 150        }
 151
 152        gpio_direction_output(GPIO_NAND_CS, 1);
 153
 154        ret = gpio_request(GPIO_NAND_RB, "NAND R/B");
 155        if (ret) {
 156                pr_warning("CM-X270: failed to request NAND R/B gpio\n");
 157                goto err_gpio_request;
 158        }
 159
 160        gpio_direction_input(GPIO_NAND_RB);
 161
 162        /* Allocate memory for MTD device structure and private data */
 163        this = kzalloc(sizeof(struct nand_chip), GFP_KERNEL);
 164        if (!this) {
 165                ret = -ENOMEM;
 166                goto err_kzalloc;
 167        }
 168
 169        cmx270_nand_io = ioremap(PXA_CS1_PHYS, 12);
 170        if (!cmx270_nand_io) {
 171                pr_debug("Unable to ioremap NAND device\n");
 172                ret = -EINVAL;
 173                goto err_ioremap;
 174        }
 175
 176        cmx270_nand_mtd = nand_to_mtd(this);
 177
 178        /* Link the private data with the MTD structure */
 179        cmx270_nand_mtd->owner = THIS_MODULE;
 180
 181        /* insert callbacks */
 182        this->IO_ADDR_R = cmx270_nand_io;
 183        this->IO_ADDR_W = cmx270_nand_io;
 184        this->cmd_ctrl = cmx270_hwcontrol;
 185        this->dev_ready = cmx270_device_ready;
 186
 187        /* 15 us command delay time */
 188        this->chip_delay = 20;
 189        this->ecc.mode = NAND_ECC_SOFT;
 190
 191        /* read/write functions */
 192        this->read_byte = cmx270_read_byte;
 193        this->read_buf = cmx270_read_buf;
 194        this->write_buf = cmx270_write_buf;
 195
 196        /* Scan to find existence of the device */
 197        if (nand_scan (cmx270_nand_mtd, 1)) {
 198                pr_notice("No NAND device\n");
 199                ret = -ENXIO;
 200                goto err_scan;
 201        }
 202
 203        /* Register the partitions */
 204        ret = mtd_device_parse_register(cmx270_nand_mtd, NULL, NULL,
 205                                        partition_info, NUM_PARTITIONS);
 206        if (ret)
 207                goto err_scan;
 208
 209        /* Return happy */
 210        return 0;
 211
 212err_scan:
 213        iounmap(cmx270_nand_io);
 214err_ioremap:
 215        kfree(this);
 216err_kzalloc:
 217        gpio_free(GPIO_NAND_RB);
 218err_gpio_request:
 219        gpio_free(GPIO_NAND_CS);
 220
 221        return ret;
 222
 223}
 224module_init(cmx270_init);
 225
 226/*
 227 * Clean up routine
 228 */
 229static void __exit cmx270_cleanup(void)
 230{
 231        /* Release resources, unregister device */
 232        nand_release(cmx270_nand_mtd);
 233
 234        gpio_free(GPIO_NAND_RB);
 235        gpio_free(GPIO_NAND_CS);
 236
 237        iounmap(cmx270_nand_io);
 238
 239        kfree(mtd_to_nand(cmx270_nand_mtd));
 240}
 241module_exit(cmx270_cleanup);
 242
 243MODULE_LICENSE("GPL");
 244MODULE_AUTHOR("Mike Rapoport <mike@compulab.co.il>");
 245MODULE_DESCRIPTION("NAND flash driver for Compulab CM-X270 Module");
 246