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