1/* 2 * drivers/mtd/nand/at91_nand.c 3 * 4 * Copyright (C) 2003 Rick Bronson 5 * 6 * Derived from drivers/mtd/nand/autcpu12.c 7 * Copyright (c) 2001 Thomas Gleixner (gleixner@autronix.de) 8 * 9 * Derived from drivers/mtd/spia.c 10 * Copyright (C) 2000 Steven J. Hill (sjhill@cotw.com) 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 */ 17 18#include <linux/slab.h> 19#include <linux/module.h> 20#include <linux/platform_device.h> 21#include <linux/mtd/mtd.h> 22#include <linux/mtd/nand.h> 23#include <linux/mtd/partitions.h> 24 25#include <asm/io.h> 26#include <asm/sizes.h> 27 28#include <asm/hardware.h> 29#include <asm/arch/board.h> 30#include <asm/arch/gpio.h> 31 32struct at91_nand_host { 33 struct nand_chip nand_chip; 34 struct mtd_info mtd; 35 void __iomem *io_base; 36 struct at91_nand_data *board; 37}; 38 39/* 40 * Hardware specific access to control-lines 41 */ 42static void at91_nand_cmd_ctrl(struct mtd_info *mtd, int cmd, unsigned int ctrl) 43{ 44 struct nand_chip *nand_chip = mtd->priv; 45 struct at91_nand_host *host = nand_chip->priv; 46 47 if (cmd == NAND_CMD_NONE) 48 return; 49 50 if (ctrl & NAND_CLE) 51 writeb(cmd, host->io_base + (1 << host->board->cle)); 52 else 53 writeb(cmd, host->io_base + (1 << host->board->ale)); 54} 55 56/* 57 * Read the Device Ready pin. 58 */ 59static int at91_nand_device_ready(struct mtd_info *mtd) 60{ 61 struct nand_chip *nand_chip = mtd->priv; 62 struct at91_nand_host *host = nand_chip->priv; 63 64 return at91_get_gpio_value(host->board->rdy_pin); 65} 66 67/* 68 * Enable NAND. 69 */ 70static void at91_nand_enable(struct at91_nand_host *host) 71{ 72 if (host->board->enable_pin) 73 at91_set_gpio_value(host->board->enable_pin, 0); 74} 75 76/* 77 * Disable NAND. 78 */ 79static void at91_nand_disable(struct at91_nand_host *host) 80{ 81 if (host->board->enable_pin) 82 at91_set_gpio_value(host->board->enable_pin, 1); 83} 84 85#ifdef CONFIG_MTD_PARTITIONS 86const char *part_probes[] = { "cmdlinepart", NULL }; 87#endif 88 89/* 90 * Probe for the NAND device. 91 */ 92static int __init at91_nand_probe(struct platform_device *pdev) 93{ 94 struct at91_nand_host *host; 95 struct mtd_info *mtd; 96 struct nand_chip *nand_chip; 97 int res; 98 99#ifdef CONFIG_MTD_PARTITIONS 100 struct mtd_partition *partitions = NULL; 101 int num_partitions = 0; 102#endif 103 104 /* Allocate memory for the device structure (and zero it) */ 105 host = kzalloc(sizeof(struct at91_nand_host), GFP_KERNEL); 106 if (!host) { 107 printk(KERN_ERR "at91_nand: failed to allocate device structure.\n"); 108 return -ENOMEM; 109 } 110 111 host->io_base = ioremap(pdev->resource[0].start, 112 pdev->resource[0].end - pdev->resource[0].start + 1); 113 if (host->io_base == NULL) { 114 printk(KERN_ERR "at91_nand: ioremap failed\n"); 115 kfree(host); 116 return -EIO; 117 } 118 119 mtd = &host->mtd; 120 nand_chip = &host->nand_chip; 121 host->board = pdev->dev.platform_data; 122 123 nand_chip->priv = host; /* link the private data structures */ 124 mtd->priv = nand_chip; 125 mtd->owner = THIS_MODULE; 126 127 /* Set address of NAND IO lines */ 128 nand_chip->IO_ADDR_R = host->io_base; 129 nand_chip->IO_ADDR_W = host->io_base; 130 nand_chip->cmd_ctrl = at91_nand_cmd_ctrl; 131 nand_chip->dev_ready = at91_nand_device_ready; 132 nand_chip->ecc.mode = NAND_ECC_SOFT; /* enable ECC */ 133 nand_chip->chip_delay = 20; /* 20us command delay time */ 134 135 if (host->board->bus_width_16) /* 16-bit bus width */ 136 nand_chip->options |= NAND_BUSWIDTH_16; 137 138 platform_set_drvdata(pdev, host); 139 at91_nand_enable(host); 140 141 if (host->board->det_pin) { 142 if (at91_get_gpio_value(host->board->det_pin)) { 143 printk ("No SmartMedia card inserted.\n"); 144 res = ENXIO; 145 goto out; 146 } 147 } 148 149 /* Scan to find existance of the device */ 150 if (nand_scan(mtd, 1)) { 151 res = -ENXIO; 152 goto out; 153 } 154 155#ifdef CONFIG_MTD_PARTITIONS 156 if (host->board->partition_info) 157 partitions = host->board->partition_info(mtd->size, &num_partitions); 158#ifdef CONFIG_MTD_CMDLINE_PARTS 159 else { 160 mtd->name = "at91_nand"; 161 num_partitions = parse_mtd_partitions(mtd, part_probes, &partitions, 0); 162 } 163#endif 164 165 if ((!partitions) || (num_partitions == 0)) { 166 printk(KERN_ERR "at91_nand: No parititions defined, or unsupported device.\n"); 167 res = ENXIO; 168 goto release; 169 } 170 171 res = add_mtd_partitions(mtd, partitions, num_partitions); 172#else 173 res = add_mtd_device(mtd); 174#endif 175 176 if (!res) 177 return res; 178 179release: 180 nand_release(mtd); 181out: 182 at91_nand_disable(host); 183 platform_set_drvdata(pdev, NULL); 184 iounmap(host->io_base); 185 kfree(host); 186 return res; 187} 188 189/* 190 * Remove a NAND device. 191 */ 192static int __devexit at91_nand_remove(struct platform_device *pdev) 193{ 194 struct at91_nand_host *host = platform_get_drvdata(pdev); 195 struct mtd_info *mtd = &host->mtd; 196 197 nand_release(mtd); 198 199 at91_nand_disable(host); 200 201 iounmap(host->io_base); 202 kfree(host); 203 204 return 0; 205} 206 207static struct platform_driver at91_nand_driver = { 208 .probe = at91_nand_probe, 209 .remove = at91_nand_remove, 210 .driver = { 211 .name = "at91_nand", 212 .owner = THIS_MODULE, 213 }, 214}; 215 216static int __init at91_nand_init(void) 217{ 218 return platform_driver_register(&at91_nand_driver); 219} 220 221 222static void __exit at91_nand_exit(void) 223{ 224 platform_driver_unregister(&at91_nand_driver); 225} 226 227 228module_init(at91_nand_init); 229module_exit(at91_nand_exit); 230 231MODULE_LICENSE("GPL"); 232MODULE_AUTHOR("Rick Bronson"); 233MODULE_DESCRIPTION("NAND/SmartMedia driver for AT91RM9200"); 234