Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

at v3.6-rc6 280 lines 6.5 kB view raw
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/* 159 * Probe for the NAND device. 160 */ 161static int __devinit socrates_nand_probe(struct platform_device *ofdev) 162{ 163 struct socrates_nand_host *host; 164 struct mtd_info *mtd; 165 struct nand_chip *nand_chip; 166 int res; 167 struct mtd_part_parser_data ppdata; 168 169 /* Allocate memory for the device structure (and zero it) */ 170 host = kzalloc(sizeof(struct socrates_nand_host), GFP_KERNEL); 171 if (!host) { 172 printk(KERN_ERR 173 "socrates_nand: failed to allocate device structure.\n"); 174 return -ENOMEM; 175 } 176 177 host->io_base = of_iomap(ofdev->dev.of_node, 0); 178 if (host->io_base == NULL) { 179 printk(KERN_ERR "socrates_nand: ioremap failed\n"); 180 kfree(host); 181 return -EIO; 182 } 183 184 mtd = &host->mtd; 185 nand_chip = &host->nand_chip; 186 host->dev = &ofdev->dev; 187 188 nand_chip->priv = host; /* link the private data structures */ 189 mtd->priv = nand_chip; 190 mtd->name = "socrates_nand"; 191 mtd->owner = THIS_MODULE; 192 mtd->dev.parent = &ofdev->dev; 193 ppdata.of_node = ofdev->dev.of_node; 194 195 /*should never be accessed directly */ 196 nand_chip->IO_ADDR_R = (void *)0xdeadbeef; 197 nand_chip->IO_ADDR_W = (void *)0xdeadbeef; 198 199 nand_chip->cmd_ctrl = socrates_nand_cmd_ctrl; 200 nand_chip->read_byte = socrates_nand_read_byte; 201 nand_chip->read_word = socrates_nand_read_word; 202 nand_chip->write_buf = socrates_nand_write_buf; 203 nand_chip->read_buf = socrates_nand_read_buf; 204 nand_chip->verify_buf = socrates_nand_verify_buf; 205 nand_chip->dev_ready = socrates_nand_device_ready; 206 207 nand_chip->ecc.mode = NAND_ECC_SOFT; /* enable ECC */ 208 209 /* TODO: I have no idea what real delay is. */ 210 nand_chip->chip_delay = 20; /* 20us command delay time */ 211 212 dev_set_drvdata(&ofdev->dev, host); 213 214 /* first scan to find the device and get the page size */ 215 if (nand_scan_ident(mtd, 1, NULL)) { 216 res = -ENXIO; 217 goto out; 218 } 219 220 /* second phase scan */ 221 if (nand_scan_tail(mtd)) { 222 res = -ENXIO; 223 goto out; 224 } 225 226 res = mtd_device_parse_register(mtd, NULL, &ppdata, NULL, 0); 227 if (!res) 228 return res; 229 230 nand_release(mtd); 231 232out: 233 dev_set_drvdata(&ofdev->dev, NULL); 234 iounmap(host->io_base); 235 kfree(host); 236 return res; 237} 238 239/* 240 * Remove a NAND device. 241 */ 242static int __devexit socrates_nand_remove(struct platform_device *ofdev) 243{ 244 struct socrates_nand_host *host = dev_get_drvdata(&ofdev->dev); 245 struct mtd_info *mtd = &host->mtd; 246 247 nand_release(mtd); 248 249 dev_set_drvdata(&ofdev->dev, NULL); 250 iounmap(host->io_base); 251 kfree(host); 252 253 return 0; 254} 255 256static const struct of_device_id socrates_nand_match[] = 257{ 258 { 259 .compatible = "abb,socrates-nand", 260 }, 261 {}, 262}; 263 264MODULE_DEVICE_TABLE(of, socrates_nand_match); 265 266static struct platform_driver socrates_nand_driver = { 267 .driver = { 268 .name = "socrates_nand", 269 .owner = THIS_MODULE, 270 .of_match_table = socrates_nand_match, 271 }, 272 .probe = socrates_nand_probe, 273 .remove = __devexit_p(socrates_nand_remove), 274}; 275 276module_platform_driver(socrates_nand_driver); 277 278MODULE_LICENSE("GPL"); 279MODULE_AUTHOR("Ilya Yanok"); 280MODULE_DESCRIPTION("NAND driver for Socrates board");