1/* 2 * drivers/mtd/nand/socrates_nand.c 3 * 4 * Copyright �� 2008 Ilya Yanok, Emcraft Systems 5 * 6 * 7 * This program is free software; you can redistribute it and/or modify 8 * it under the terms of the GNU General Public License version 2 as 9 * published by the Free Software Foundation. 10 * 11 */ 12 13#include <linux/slab.h> 14#include <linux/module.h> 15#include <linux/mtd/mtd.h> 16#include <linux/mtd/nand.h> 17#include <linux/mtd/partitions.h> 18#include <linux/of_platform.h> 19#include <linux/io.h> 20 21#define FPGA_NAND_CMD_MASK (0x7 << 28) 22#define FPGA_NAND_CMD_COMMAND (0x0 << 28) 23#define FPGA_NAND_CMD_ADDR (0x1 << 28) 24#define FPGA_NAND_CMD_READ (0x2 << 28) 25#define FPGA_NAND_CMD_WRITE (0x3 << 28) 26#define FPGA_NAND_BUSY (0x1 << 15) 27#define FPGA_NAND_ENABLE (0x1 << 31) 28#define FPGA_NAND_DATA_SHIFT 16 29 30struct socrates_nand_host { 31 struct nand_chip nand_chip; 32 struct mtd_info mtd; 33 void __iomem *io_base; 34 struct device *dev; 35}; 36 37/** 38 * socrates_nand_write_buf - write buffer to chip 39 * @mtd: MTD device structure 40 * @buf: data buffer 41 * @len: number of bytes to write 42 */ 43static void socrates_nand_write_buf(struct mtd_info *mtd, 44 const uint8_t *buf, int len) 45{ 46 int i; 47 struct nand_chip *this = mtd->priv; 48 struct socrates_nand_host *host = this->priv; 49 50 for (i = 0; i < len; i++) { 51 out_be32(host->io_base, FPGA_NAND_ENABLE | 52 FPGA_NAND_CMD_WRITE | 53 (buf[i] << FPGA_NAND_DATA_SHIFT)); 54 } 55} 56 57/** 58 * socrates_nand_read_buf - read chip data into buffer 59 * @mtd: MTD device structure 60 * @buf: buffer to store date 61 * @len: number of bytes to read 62 */ 63static void socrates_nand_read_buf(struct mtd_info *mtd, uint8_t *buf, int len) 64{ 65 int i; 66 struct nand_chip *this = mtd->priv; 67 struct socrates_nand_host *host = this->priv; 68 uint32_t val; 69 70 val = FPGA_NAND_ENABLE | FPGA_NAND_CMD_READ; 71 72 out_be32(host->io_base, val); 73 for (i = 0; i < len; i++) { 74 buf[i] = (in_be32(host->io_base) >> 75 FPGA_NAND_DATA_SHIFT) & 0xff; 76 } 77} 78 79/** 80 * socrates_nand_read_byte - read one byte from the chip 81 * @mtd: MTD device structure 82 */ 83static uint8_t socrates_nand_read_byte(struct mtd_info *mtd) 84{ 85 uint8_t byte; 86 socrates_nand_read_buf(mtd, &byte, sizeof(byte)); 87 return byte; 88} 89 90/** 91 * socrates_nand_read_word - read one word from the chip 92 * @mtd: MTD device structure 93 */ 94static uint16_t socrates_nand_read_word(struct mtd_info *mtd) 95{ 96 uint16_t word; 97 socrates_nand_read_buf(mtd, (uint8_t *)&word, sizeof(word)); 98 return word; 99} 100 101/** 102 * socrates_nand_verify_buf - Verify chip data against buffer 103 * @mtd: MTD device structure 104 * @buf: buffer containing the data to compare 105 * @len: number of bytes to compare 106 */ 107static int socrates_nand_verify_buf(struct mtd_info *mtd, const u8 *buf, 108 int len) 109{ 110 int i; 111 112 for (i = 0; i < len; i++) { 113 if (buf[i] != socrates_nand_read_byte(mtd)) 114 return -EFAULT; 115 } 116 return 0; 117} 118 119/* 120 * Hardware specific access to control-lines 121 */ 122static void socrates_nand_cmd_ctrl(struct mtd_info *mtd, int cmd, 123 unsigned int ctrl) 124{ 125 struct nand_chip *nand_chip = mtd->priv; 126 struct socrates_nand_host *host = nand_chip->priv; 127 uint32_t val; 128 129 if (cmd == NAND_CMD_NONE) 130 return; 131 132 if (ctrl & NAND_CLE) 133 val = FPGA_NAND_CMD_COMMAND; 134 else 135 val = FPGA_NAND_CMD_ADDR; 136 137 if (ctrl & NAND_NCE) 138 val |= FPGA_NAND_ENABLE; 139 140 val |= (cmd & 0xff) << FPGA_NAND_DATA_SHIFT; 141 142 out_be32(host->io_base, val); 143} 144 145/* 146 * Read the Device Ready pin. 147 */ 148static int socrates_nand_device_ready(struct mtd_info *mtd) 149{ 150 struct nand_chip *nand_chip = mtd->priv; 151 struct socrates_nand_host *host = nand_chip->priv; 152 153 if (in_be32(host->io_base) & FPGA_NAND_BUSY) 154 return 0; /* busy */ 155 return 1; 156} 157 158#ifdef CONFIG_MTD_PARTITIONS 159static const char *part_probes[] = { "cmdlinepart", NULL }; 160#endif 161 162/* 163 * Probe for the NAND device. 164 */ 165static int __devinit socrates_nand_probe(struct platform_device *ofdev, 166 const struct of_device_id *ofid) 167{ 168 struct socrates_nand_host *host; 169 struct mtd_info *mtd; 170 struct nand_chip *nand_chip; 171 int res; 172 173#ifdef CONFIG_MTD_PARTITIONS 174 struct mtd_partition *partitions = NULL; 175 int num_partitions = 0; 176#endif 177 178 /* Allocate memory for the device structure (and zero it) */ 179 host = kzalloc(sizeof(struct socrates_nand_host), GFP_KERNEL); 180 if (!host) { 181 printk(KERN_ERR 182 "socrates_nand: failed to allocate device structure.\n"); 183 return -ENOMEM; 184 } 185 186 host->io_base = of_iomap(ofdev->dev.of_node, 0); 187 if (host->io_base == NULL) { 188 printk(KERN_ERR "socrates_nand: ioremap failed\n"); 189 kfree(host); 190 return -EIO; 191 } 192 193 mtd = &host->mtd; 194 nand_chip = &host->nand_chip; 195 host->dev = &ofdev->dev; 196 197 nand_chip->priv = host; /* link the private data structures */ 198 mtd->priv = nand_chip; 199 mtd->name = "socrates_nand"; 200 mtd->owner = THIS_MODULE; 201 mtd->dev.parent = &ofdev->dev; 202 203 /*should never be accessed directly */ 204 nand_chip->IO_ADDR_R = (void *)0xdeadbeef; 205 nand_chip->IO_ADDR_W = (void *)0xdeadbeef; 206 207 nand_chip->cmd_ctrl = socrates_nand_cmd_ctrl; 208 nand_chip->read_byte = socrates_nand_read_byte; 209 nand_chip->read_word = socrates_nand_read_word; 210 nand_chip->write_buf = socrates_nand_write_buf; 211 nand_chip->read_buf = socrates_nand_read_buf; 212 nand_chip->verify_buf = socrates_nand_verify_buf; 213 nand_chip->dev_ready = socrates_nand_device_ready; 214 215 nand_chip->ecc.mode = NAND_ECC_SOFT; /* enable ECC */ 216 217 /* TODO: I have no idea what real delay is. */ 218 nand_chip->chip_delay = 20; /* 20us command delay time */ 219 220 dev_set_drvdata(&ofdev->dev, host); 221 222 /* first scan to find the device and get the page size */ 223 if (nand_scan_ident(mtd, 1, NULL)) { 224 res = -ENXIO; 225 goto out; 226 } 227 228 /* second phase scan */ 229 if (nand_scan_tail(mtd)) { 230 res = -ENXIO; 231 goto out; 232 } 233 234#ifdef CONFIG_MTD_PARTITIONS 235#ifdef CONFIG_MTD_CMDLINE_PARTS 236 num_partitions = parse_mtd_partitions(mtd, part_probes, 237 &partitions, 0); 238 if (num_partitions < 0) { 239 res = num_partitions; 240 goto release; 241 } 242#endif 243 244#ifdef CONFIG_MTD_OF_PARTS 245 if (num_partitions == 0) { 246 num_partitions = of_mtd_parse_partitions(&ofdev->dev, 247 ofdev->dev.of_node, 248 &partitions); 249 if (num_partitions < 0) { 250 res = num_partitions; 251 goto release; 252 } 253 } 254#endif 255 if (partitions && (num_partitions > 0)) 256 res = add_mtd_partitions(mtd, partitions, num_partitions); 257 else 258#endif 259 res = add_mtd_device(mtd); 260 261 if (!res) 262 return res; 263 264#ifdef CONFIG_MTD_PARTITIONS 265release: 266#endif 267 nand_release(mtd); 268 269out: 270 dev_set_drvdata(&ofdev->dev, NULL); 271 iounmap(host->io_base); 272 kfree(host); 273 return res; 274} 275 276/* 277 * Remove a NAND device. 278 */ 279static int __devexit socrates_nand_remove(struct platform_device *ofdev) 280{ 281 struct socrates_nand_host *host = dev_get_drvdata(&ofdev->dev); 282 struct mtd_info *mtd = &host->mtd; 283 284 nand_release(mtd); 285 286 dev_set_drvdata(&ofdev->dev, NULL); 287 iounmap(host->io_base); 288 kfree(host); 289 290 return 0; 291} 292 293static const struct of_device_id socrates_nand_match[] = 294{ 295 { 296 .compatible = "abb,socrates-nand", 297 }, 298 {}, 299}; 300 301MODULE_DEVICE_TABLE(of, socrates_nand_match); 302 303static struct of_platform_driver socrates_nand_driver = { 304 .driver = { 305 .name = "socrates_nand", 306 .owner = THIS_MODULE, 307 .of_match_table = socrates_nand_match, 308 }, 309 .probe = socrates_nand_probe, 310 .remove = __devexit_p(socrates_nand_remove), 311}; 312 313static int __init socrates_nand_init(void) 314{ 315 return of_register_platform_driver(&socrates_nand_driver); 316} 317 318static void __exit socrates_nand_exit(void) 319{ 320 of_unregister_platform_driver(&socrates_nand_driver); 321} 322 323module_init(socrates_nand_init); 324module_exit(socrates_nand_exit); 325 326MODULE_LICENSE("GPL"); 327MODULE_AUTHOR("Ilya Yanok"); 328MODULE_DESCRIPTION("NAND driver for Socrates board"); 329