linux/arch/cris/arch-v32/drivers/mach-a3/nandflash.c
<<
>>
Prefs
   1/*
   2 *  arch/cris/arch-v32/drivers/nandflash.c
   3 *
   4 *  Copyright (c) 2007
   5 *
   6 *  Derived from drivers/mtd/nand/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 */
  14
  15#include <linux/slab.h>
  16#include <linux/init.h>
  17#include <linux/module.h>
  18#include <linux/mtd/mtd.h>
  19#include <linux/mtd/nand.h>
  20#include <linux/mtd/partitions.h>
  21#include <arch/memmap.h>
  22#include <hwregs/reg_map.h>
  23#include <hwregs/reg_rdwr.h>
  24#include <hwregs/pio_defs.h>
  25#include <pinmux.h>
  26#include <asm/io.h>
  27
  28#define MANUAL_ALE_CLE_CONTROL 1
  29
  30#define regf_ALE        a0
  31#define regf_CLE        a1
  32#define regf_NCE        ce0_n
  33
  34#define CLE_BIT 10
  35#define ALE_BIT 11
  36#define CE_BIT 12
  37
  38struct mtd_info_wrapper {
  39        struct mtd_info info;
  40        struct nand_chip chip;
  41};
  42
  43/* Bitmask for control pins */
  44#define PIN_BITMASK ((1 << CE_BIT) | (1 << CLE_BIT) | (1 << ALE_BIT))
  45
  46static struct mtd_info *crisv32_mtd;
  47/*
  48 *      hardware specific access to control-lines
  49 */
  50static void crisv32_hwcontrol(struct mtd_info *mtd, int cmd,
  51                              unsigned int ctrl)
  52{
  53        unsigned long flags;
  54        reg_pio_rw_dout dout;
  55        struct nand_chip *this = mtd->priv;
  56
  57        local_irq_save(flags);
  58
  59        /* control bits change */
  60        if (ctrl & NAND_CTRL_CHANGE) {
  61                dout = REG_RD(pio, regi_pio, rw_dout);
  62                dout.regf_NCE = (ctrl & NAND_NCE) ? 0 : 1;
  63
  64#if !MANUAL_ALE_CLE_CONTROL
  65                if (ctrl & NAND_ALE) {
  66                        /* A0 = ALE high */
  67                        this->IO_ADDR_W = (void __iomem *)REG_ADDR(pio,
  68                                regi_pio, rw_io_access1);
  69                } else if (ctrl & NAND_CLE) {
  70                        /* A1 = CLE high */
  71                        this->IO_ADDR_W = (void __iomem *)REG_ADDR(pio,
  72                                regi_pio, rw_io_access2);
  73                } else {
  74                        /* A1 = CLE and A0 = ALE low */
  75                        this->IO_ADDR_W = (void __iomem *)REG_ADDR(pio,
  76                                regi_pio, rw_io_access0);
  77                }
  78#else
  79
  80                dout.regf_CLE = (ctrl & NAND_CLE) ? 1 : 0;
  81                dout.regf_ALE = (ctrl & NAND_ALE) ? 1 : 0;
  82#endif
  83                REG_WR(pio, regi_pio, rw_dout, dout);
  84        }
  85
  86        /* command to chip */
  87        if (cmd != NAND_CMD_NONE)
  88                writeb(cmd, this->IO_ADDR_W);
  89
  90        local_irq_restore(flags);
  91}
  92
  93/*
  94*       read device ready pin
  95*/
  96static int crisv32_device_ready(struct mtd_info *mtd)
  97{
  98        reg_pio_r_din din = REG_RD(pio, regi_pio, r_din);
  99        return din.rdy;
 100}
 101
 102/*
 103 * Main initialization routine
 104 */
 105struct mtd_info *__init crisv32_nand_flash_probe(void)
 106{
 107        void __iomem *read_cs;
 108        void __iomem *write_cs;
 109
 110        struct mtd_info_wrapper *wrapper;
 111        struct nand_chip *this;
 112        int err = 0;
 113
 114        reg_pio_rw_man_ctrl man_ctrl = {
 115                .regf_NCE = regk_pio_yes,
 116#if MANUAL_ALE_CLE_CONTROL
 117                .regf_ALE = regk_pio_yes,
 118                .regf_CLE = regk_pio_yes
 119#endif
 120        };
 121        reg_pio_rw_oe oe = {
 122                .regf_NCE = regk_pio_yes,
 123#if MANUAL_ALE_CLE_CONTROL
 124                .regf_ALE = regk_pio_yes,
 125                .regf_CLE = regk_pio_yes
 126#endif
 127        };
 128        reg_pio_rw_dout dout = { .regf_NCE = 1 };
 129
 130        /* Allocate pio pins to pio */
 131        crisv32_pinmux_alloc_fixed(pinmux_pio);
 132        /* Set up CE, ALE, CLE (ce0_n, a0, a1) for manual control and output */
 133        REG_WR(pio, regi_pio, rw_man_ctrl, man_ctrl);
 134        REG_WR(pio, regi_pio, rw_dout, dout);
 135        REG_WR(pio, regi_pio, rw_oe, oe);
 136
 137        /* Allocate memory for MTD device structure and private data */
 138        wrapper = kzalloc(sizeof(struct mtd_info_wrapper), GFP_KERNEL);
 139        if (!wrapper) {
 140                printk(KERN_ERR "Unable to allocate CRISv32 NAND MTD "
 141                        "device structure.\n");
 142                err = -ENOMEM;
 143                return NULL;
 144        }
 145
 146        read_cs = write_cs = (void __iomem *)REG_ADDR(pio, regi_pio,
 147                rw_io_access0);
 148
 149        /* Get pointer to private data */
 150        this = &wrapper->chip;
 151        crisv32_mtd = &wrapper->info;
 152
 153        /* Link the private data with the MTD structure */
 154        crisv32_mtd->priv = this;
 155
 156        /* Set address of NAND IO lines */
 157        this->IO_ADDR_R = read_cs;
 158        this->IO_ADDR_W = write_cs;
 159        this->cmd_ctrl = crisv32_hwcontrol;
 160        this->dev_ready = crisv32_device_ready;
 161        /* 20 us command delay time */
 162        this->chip_delay = 20;
 163        this->ecc.mode = NAND_ECC_SOFT;
 164
 165        /* Enable the following for a flash based bad block table */
 166        /* this->options = NAND_USE_FLASH_BBT; */
 167
 168        /* Scan to find existance of the device */
 169        if (nand_scan(crisv32_mtd, 1)) {
 170                err = -ENXIO;
 171                goto out_mtd;
 172        }
 173
 174        return crisv32_mtd;
 175
 176out_mtd:
 177        kfree(wrapper);
 178        return NULL;
 179}
 180
 181