1/* 2 * drivers/mtd/nand/gpio.c 3 * 4 * Updated, and converted to generic GPIO based driver by Russell King. 5 * 6 * Written by Ben Dooks <ben@simtec.co.uk> 7 * Based on 2.4 version by Mark Whittaker 8 * 9 * �� 2004 Simtec Electronics 10 * 11 * Device driver for NAND connected via GPIO 12 * 13 * This program is free software; you can redistribute it and/or modify 14 * it under the terms of the GNU General Public License version 2 as 15 * published by the Free Software Foundation. 16 * 17 */ 18 19#include <linux/kernel.h> 20#include <linux/init.h> 21#include <linux/slab.h> 22#include <linux/module.h> 23#include <linux/platform_device.h> 24#include <linux/gpio.h> 25#include <linux/io.h> 26#include <linux/mtd/mtd.h> 27#include <linux/mtd/nand.h> 28#include <linux/mtd/partitions.h> 29#include <linux/mtd/nand-gpio.h> 30 31struct gpiomtd { 32 void __iomem *io_sync; 33 struct mtd_info mtd_info; 34 struct nand_chip nand_chip; 35 struct gpio_nand_platdata plat; 36}; 37 38#define gpio_nand_getpriv(x) container_of(x, struct gpiomtd, mtd_info) 39 40 41#ifdef CONFIG_ARM 42/* gpio_nand_dosync() 43 * 44 * Make sure the GPIO state changes occur in-order with writes to NAND 45 * memory region. 46 * Needed on PXA due to bus-reordering within the SoC itself (see section on 47 * I/O ordering in PXA manual (section 2.3, p35) 48 */ 49static void gpio_nand_dosync(struct gpiomtd *gpiomtd) 50{ 51 unsigned long tmp; 52 53 if (gpiomtd->io_sync) { 54 /* 55 * Linux memory barriers don't cater for what's required here. 56 * What's required is what's here - a read from a separate 57 * region with a dependency on that read. 58 */ 59 tmp = readl(gpiomtd->io_sync); 60 asm volatile("mov %1, %0\n" : "=r" (tmp) : "r" (tmp)); 61 } 62} 63#else 64static inline void gpio_nand_dosync(struct gpiomtd *gpiomtd) {} 65#endif 66 67static void gpio_nand_cmd_ctrl(struct mtd_info *mtd, int cmd, unsigned int ctrl) 68{ 69 struct gpiomtd *gpiomtd = gpio_nand_getpriv(mtd); 70 71 gpio_nand_dosync(gpiomtd); 72 73 if (ctrl & NAND_CTRL_CHANGE) { 74 gpio_set_value(gpiomtd->plat.gpio_nce, !(ctrl & NAND_NCE)); 75 gpio_set_value(gpiomtd->plat.gpio_cle, !!(ctrl & NAND_CLE)); 76 gpio_set_value(gpiomtd->plat.gpio_ale, !!(ctrl & NAND_ALE)); 77 gpio_nand_dosync(gpiomtd); 78 } 79 if (cmd == NAND_CMD_NONE) 80 return; 81 82 writeb(cmd, gpiomtd->nand_chip.IO_ADDR_W); 83 gpio_nand_dosync(gpiomtd); 84} 85 86static void gpio_nand_writebuf(struct mtd_info *mtd, const u_char *buf, int len) 87{ 88 struct nand_chip *this = mtd->priv; 89 90 writesb(this->IO_ADDR_W, buf, len); 91} 92 93static void gpio_nand_readbuf(struct mtd_info *mtd, u_char *buf, int len) 94{ 95 struct nand_chip *this = mtd->priv; 96 97 readsb(this->IO_ADDR_R, buf, len); 98} 99 100static int gpio_nand_verifybuf(struct mtd_info *mtd, const u_char *buf, int len) 101{ 102 struct nand_chip *this = mtd->priv; 103 unsigned char read, *p = (unsigned char *) buf; 104 int i, err = 0; 105 106 for (i = 0; i < len; i++) { 107 read = readb(this->IO_ADDR_R); 108 if (read != p[i]) { 109 pr_debug("%s: err at %d (read %04x vs %04x)\n", 110 __func__, i, read, p[i]); 111 err = -EFAULT; 112 } 113 } 114 return err; 115} 116 117static void gpio_nand_writebuf16(struct mtd_info *mtd, const u_char *buf, 118 int len) 119{ 120 struct nand_chip *this = mtd->priv; 121 122 if (IS_ALIGNED((unsigned long)buf, 2)) { 123 writesw(this->IO_ADDR_W, buf, len>>1); 124 } else { 125 int i; 126 unsigned short *ptr = (unsigned short *)buf; 127 128 for (i = 0; i < len; i += 2, ptr++) 129 writew(*ptr, this->IO_ADDR_W); 130 } 131} 132 133static void gpio_nand_readbuf16(struct mtd_info *mtd, u_char *buf, int len) 134{ 135 struct nand_chip *this = mtd->priv; 136 137 if (IS_ALIGNED((unsigned long)buf, 2)) { 138 readsw(this->IO_ADDR_R, buf, len>>1); 139 } else { 140 int i; 141 unsigned short *ptr = (unsigned short *)buf; 142 143 for (i = 0; i < len; i += 2, ptr++) 144 *ptr = readw(this->IO_ADDR_R); 145 } 146} 147 148static int gpio_nand_verifybuf16(struct mtd_info *mtd, const u_char *buf, 149 int len) 150{ 151 struct nand_chip *this = mtd->priv; 152 unsigned short read, *p = (unsigned short *) buf; 153 int i, err = 0; 154 len >>= 1; 155 156 for (i = 0; i < len; i++) { 157 read = readw(this->IO_ADDR_R); 158 if (read != p[i]) { 159 pr_debug("%s: err at %d (read %04x vs %04x)\n", 160 __func__, i, read, p[i]); 161 err = -EFAULT; 162 } 163 } 164 return err; 165} 166 167 168static int gpio_nand_devready(struct mtd_info *mtd) 169{ 170 struct gpiomtd *gpiomtd = gpio_nand_getpriv(mtd); 171 return gpio_get_value(gpiomtd->plat.gpio_rdy); 172} 173 174static int __devexit gpio_nand_remove(struct platform_device *dev) 175{ 176 struct gpiomtd *gpiomtd = platform_get_drvdata(dev); 177 struct resource *res; 178 179 nand_release(&gpiomtd->mtd_info); 180 181 res = platform_get_resource(dev, IORESOURCE_MEM, 1); 182 iounmap(gpiomtd->io_sync); 183 if (res) 184 release_mem_region(res->start, resource_size(res)); 185 186 res = platform_get_resource(dev, IORESOURCE_MEM, 0); 187 iounmap(gpiomtd->nand_chip.IO_ADDR_R); 188 release_mem_region(res->start, resource_size(res)); 189 190 if (gpio_is_valid(gpiomtd->plat.gpio_nwp)) 191 gpio_set_value(gpiomtd->plat.gpio_nwp, 0); 192 gpio_set_value(gpiomtd->plat.gpio_nce, 1); 193 194 gpio_free(gpiomtd->plat.gpio_cle); 195 gpio_free(gpiomtd->plat.gpio_ale); 196 gpio_free(gpiomtd->plat.gpio_nce); 197 if (gpio_is_valid(gpiomtd->plat.gpio_nwp)) 198 gpio_free(gpiomtd->plat.gpio_nwp); 199 gpio_free(gpiomtd->plat.gpio_rdy); 200 201 kfree(gpiomtd); 202 203 return 0; 204} 205 206static void __iomem *request_and_remap(struct resource *res, size_t size, 207 const char *name, int *err) 208{ 209 void __iomem *ptr; 210 211 if (!request_mem_region(res->start, resource_size(res), name)) { 212 *err = -EBUSY; 213 return NULL; 214 } 215 216 ptr = ioremap(res->start, size); 217 if (!ptr) { 218 release_mem_region(res->start, resource_size(res)); 219 *err = -ENOMEM; 220 } 221 return ptr; 222} 223 224static int __devinit gpio_nand_probe(struct platform_device *dev) 225{ 226 struct gpiomtd *gpiomtd; 227 struct nand_chip *this; 228 struct resource *res0, *res1; 229 int ret; 230 231 if (!dev->dev.platform_data) 232 return -EINVAL; 233 234 res0 = platform_get_resource(dev, IORESOURCE_MEM, 0); 235 if (!res0) 236 return -EINVAL; 237 238 gpiomtd = kzalloc(sizeof(*gpiomtd), GFP_KERNEL); 239 if (gpiomtd == NULL) { 240 dev_err(&dev->dev, "failed to create NAND MTD\n"); 241 return -ENOMEM; 242 } 243 244 this = &gpiomtd->nand_chip; 245 this->IO_ADDR_R = request_and_remap(res0, 2, "NAND", &ret); 246 if (!this->IO_ADDR_R) { 247 dev_err(&dev->dev, "unable to map NAND\n"); 248 goto err_map; 249 } 250 251 res1 = platform_get_resource(dev, IORESOURCE_MEM, 1); 252 if (res1) { 253 gpiomtd->io_sync = request_and_remap(res1, 4, "NAND sync", &ret); 254 if (!gpiomtd->io_sync) { 255 dev_err(&dev->dev, "unable to map sync NAND\n"); 256 goto err_sync; 257 } 258 } 259 260 memcpy(&gpiomtd->plat, dev->dev.platform_data, sizeof(gpiomtd->plat)); 261 262 ret = gpio_request(gpiomtd->plat.gpio_nce, "NAND NCE"); 263 if (ret) 264 goto err_nce; 265 gpio_direction_output(gpiomtd->plat.gpio_nce, 1); 266 if (gpio_is_valid(gpiomtd->plat.gpio_nwp)) { 267 ret = gpio_request(gpiomtd->plat.gpio_nwp, "NAND NWP"); 268 if (ret) 269 goto err_nwp; 270 gpio_direction_output(gpiomtd->plat.gpio_nwp, 1); 271 } 272 ret = gpio_request(gpiomtd->plat.gpio_ale, "NAND ALE"); 273 if (ret) 274 goto err_ale; 275 gpio_direction_output(gpiomtd->plat.gpio_ale, 0); 276 ret = gpio_request(gpiomtd->plat.gpio_cle, "NAND CLE"); 277 if (ret) 278 goto err_cle; 279 gpio_direction_output(gpiomtd->plat.gpio_cle, 0); 280 ret = gpio_request(gpiomtd->plat.gpio_rdy, "NAND RDY"); 281 if (ret) 282 goto err_rdy; 283 gpio_direction_input(gpiomtd->plat.gpio_rdy); 284 285 286 this->IO_ADDR_W = this->IO_ADDR_R; 287 this->ecc.mode = NAND_ECC_SOFT; 288 this->options = gpiomtd->plat.options; 289 this->chip_delay = gpiomtd->plat.chip_delay; 290 291 /* install our routines */ 292 this->cmd_ctrl = gpio_nand_cmd_ctrl; 293 this->dev_ready = gpio_nand_devready; 294 295 if (this->options & NAND_BUSWIDTH_16) { 296 this->read_buf = gpio_nand_readbuf16; 297 this->write_buf = gpio_nand_writebuf16; 298 this->verify_buf = gpio_nand_verifybuf16; 299 } else { 300 this->read_buf = gpio_nand_readbuf; 301 this->write_buf = gpio_nand_writebuf; 302 this->verify_buf = gpio_nand_verifybuf; 303 } 304 305 /* set the mtd private data for the nand driver */ 306 gpiomtd->mtd_info.priv = this; 307 gpiomtd->mtd_info.owner = THIS_MODULE; 308 309 if (nand_scan(&gpiomtd->mtd_info, 1)) { 310 dev_err(&dev->dev, "no nand chips found?\n"); 311 ret = -ENXIO; 312 goto err_wp; 313 } 314 315 if (gpiomtd->plat.adjust_parts) 316 gpiomtd->plat.adjust_parts(&gpiomtd->plat, 317 gpiomtd->mtd_info.size); 318 319 add_mtd_partitions(&gpiomtd->mtd_info, gpiomtd->plat.parts, 320 gpiomtd->plat.num_parts); 321 platform_set_drvdata(dev, gpiomtd); 322 323 return 0; 324 325err_wp: 326 if (gpio_is_valid(gpiomtd->plat.gpio_nwp)) 327 gpio_set_value(gpiomtd->plat.gpio_nwp, 0); 328 gpio_free(gpiomtd->plat.gpio_rdy); 329err_rdy: 330 gpio_free(gpiomtd->plat.gpio_cle); 331err_cle: 332 gpio_free(gpiomtd->plat.gpio_ale); 333err_ale: 334 if (gpio_is_valid(gpiomtd->plat.gpio_nwp)) 335 gpio_free(gpiomtd->plat.gpio_nwp); 336err_nwp: 337 gpio_free(gpiomtd->plat.gpio_nce); 338err_nce: 339 iounmap(gpiomtd->io_sync); 340 if (res1) 341 release_mem_region(res1->start, resource_size(res1)); 342err_sync: 343 iounmap(gpiomtd->nand_chip.IO_ADDR_R); 344 release_mem_region(res0->start, resource_size(res0)); 345err_map: 346 kfree(gpiomtd); 347 return ret; 348} 349 350static struct platform_driver gpio_nand_driver = { 351 .probe = gpio_nand_probe, 352 .remove = gpio_nand_remove, 353 .driver = { 354 .name = "gpio-nand", 355 }, 356}; 357 358static int __init gpio_nand_init(void) 359{ 360 printk(KERN_INFO "GPIO NAND driver, �� 2004 Simtec Electronics\n"); 361 362 return platform_driver_register(&gpio_nand_driver); 363} 364 365static void __exit gpio_nand_exit(void) 366{ 367 platform_driver_unregister(&gpio_nand_driver); 368} 369 370module_init(gpio_nand_init); 371module_exit(gpio_nand_exit); 372 373MODULE_LICENSE("GPL"); 374MODULE_AUTHOR("Ben Dooks <ben@simtec.co.uk>"); 375MODULE_DESCRIPTION("GPIO NAND Driver"); 376