ams-delta.c 5.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239
  1. /*
  2. * drivers/mtd/nand/ams-delta.c
  3. *
  4. * Copyright (C) 2006 Jonathan McDowell <noodles@earth.li>
  5. *
  6. * Derived from drivers/mtd/toto.c
  7. *
  8. * This program is free software; you can redistribute it and/or modify
  9. * it under the terms of the GNU General Public License version 2 as
  10. * published by the Free Software Foundation.
  11. *
  12. * Overview:
  13. * This is a device driver for the NAND flash device found on the
  14. * Amstrad E3 (Delta).
  15. */
  16. #include <linux/slab.h>
  17. #include <linux/init.h>
  18. #include <linux/module.h>
  19. #include <linux/delay.h>
  20. #include <linux/mtd/mtd.h>
  21. #include <linux/mtd/nand.h>
  22. #include <linux/mtd/partitions.h>
  23. #include <asm/io.h>
  24. #include <mach/hardware.h>
  25. #include <asm/sizes.h>
  26. #include <mach/gpio.h>
  27. #include <mach/board-ams-delta.h>
  28. /*
  29. * MTD structure for E3 (Delta)
  30. */
  31. static struct mtd_info *ams_delta_mtd = NULL;
  32. #define NAND_MASK (AMS_DELTA_LATCH2_NAND_NRE | AMS_DELTA_LATCH2_NAND_NWE | AMS_DELTA_LATCH2_NAND_CLE | AMS_DELTA_LATCH2_NAND_ALE | AMS_DELTA_LATCH2_NAND_NCE | AMS_DELTA_LATCH2_NAND_NWP)
  33. /*
  34. * Define partitions for flash devices
  35. */
  36. static struct mtd_partition partition_info[] = {
  37. { .name = "Kernel",
  38. .offset = 0,
  39. .size = 3 * SZ_1M + SZ_512K },
  40. { .name = "u-boot",
  41. .offset = 3 * SZ_1M + SZ_512K,
  42. .size = SZ_256K },
  43. { .name = "u-boot params",
  44. .offset = 3 * SZ_1M + SZ_512K + SZ_256K,
  45. .size = SZ_256K },
  46. { .name = "Amstrad LDR",
  47. .offset = 4 * SZ_1M,
  48. .size = SZ_256K },
  49. { .name = "File system",
  50. .offset = 4 * SZ_1M + 1 * SZ_256K,
  51. .size = 27 * SZ_1M },
  52. { .name = "PBL reserved",
  53. .offset = 32 * SZ_1M - 3 * SZ_256K,
  54. .size = 3 * SZ_256K },
  55. };
  56. static void ams_delta_write_byte(struct mtd_info *mtd, u_char byte)
  57. {
  58. struct nand_chip *this = mtd->priv;
  59. omap_writew(0, (OMAP_MPUIO_BASE + OMAP_MPUIO_IO_CNTL));
  60. omap_writew(byte, this->IO_ADDR_W);
  61. ams_delta_latch2_write(AMS_DELTA_LATCH2_NAND_NWE, 0);
  62. ndelay(40);
  63. ams_delta_latch2_write(AMS_DELTA_LATCH2_NAND_NWE,
  64. AMS_DELTA_LATCH2_NAND_NWE);
  65. }
  66. static u_char ams_delta_read_byte(struct mtd_info *mtd)
  67. {
  68. u_char res;
  69. struct nand_chip *this = mtd->priv;
  70. ams_delta_latch2_write(AMS_DELTA_LATCH2_NAND_NRE, 0);
  71. ndelay(40);
  72. omap_writew(~0, (OMAP_MPUIO_BASE + OMAP_MPUIO_IO_CNTL));
  73. res = omap_readw(this->IO_ADDR_R);
  74. ams_delta_latch2_write(AMS_DELTA_LATCH2_NAND_NRE,
  75. AMS_DELTA_LATCH2_NAND_NRE);
  76. return res;
  77. }
  78. static void ams_delta_write_buf(struct mtd_info *mtd, const u_char *buf,
  79. int len)
  80. {
  81. int i;
  82. for (i=0; i<len; i++)
  83. ams_delta_write_byte(mtd, buf[i]);
  84. }
  85. static void ams_delta_read_buf(struct mtd_info *mtd, u_char *buf, int len)
  86. {
  87. int i;
  88. for (i=0; i<len; i++)
  89. buf[i] = ams_delta_read_byte(mtd);
  90. }
  91. static int ams_delta_verify_buf(struct mtd_info *mtd, const u_char *buf,
  92. int len)
  93. {
  94. int i;
  95. for (i=0; i<len; i++)
  96. if (buf[i] != ams_delta_read_byte(mtd))
  97. return -EFAULT;
  98. return 0;
  99. }
  100. /*
  101. * Command control function
  102. *
  103. * ctrl:
  104. * NAND_NCE: bit 0 -> bit 2
  105. * NAND_CLE: bit 1 -> bit 7
  106. * NAND_ALE: bit 2 -> bit 6
  107. */
  108. static void ams_delta_hwcontrol(struct mtd_info *mtd, int cmd,
  109. unsigned int ctrl)
  110. {
  111. if (ctrl & NAND_CTRL_CHANGE) {
  112. unsigned long bits;
  113. bits = (~ctrl & NAND_NCE) ? AMS_DELTA_LATCH2_NAND_NCE : 0;
  114. bits |= (ctrl & NAND_CLE) ? AMS_DELTA_LATCH2_NAND_CLE : 0;
  115. bits |= (ctrl & NAND_ALE) ? AMS_DELTA_LATCH2_NAND_ALE : 0;
  116. ams_delta_latch2_write(AMS_DELTA_LATCH2_NAND_CLE |
  117. AMS_DELTA_LATCH2_NAND_ALE |
  118. AMS_DELTA_LATCH2_NAND_NCE, bits);
  119. }
  120. if (cmd != NAND_CMD_NONE)
  121. ams_delta_write_byte(mtd, cmd);
  122. }
  123. static int ams_delta_nand_ready(struct mtd_info *mtd)
  124. {
  125. return omap_get_gpio_datain(AMS_DELTA_GPIO_PIN_NAND_RB);
  126. }
  127. /*
  128. * Main initialization routine
  129. */
  130. static int __init ams_delta_init(void)
  131. {
  132. struct nand_chip *this;
  133. int err = 0;
  134. /* Allocate memory for MTD device structure and private data */
  135. ams_delta_mtd = kmalloc(sizeof(struct mtd_info) +
  136. sizeof(struct nand_chip), GFP_KERNEL);
  137. if (!ams_delta_mtd) {
  138. printk (KERN_WARNING "Unable to allocate E3 NAND MTD device structure.\n");
  139. err = -ENOMEM;
  140. goto out;
  141. }
  142. ams_delta_mtd->owner = THIS_MODULE;
  143. /* Get pointer to private data */
  144. this = (struct nand_chip *) (&ams_delta_mtd[1]);
  145. /* Initialize structures */
  146. memset(ams_delta_mtd, 0, sizeof(struct mtd_info));
  147. memset(this, 0, sizeof(struct nand_chip));
  148. /* Link the private data with the MTD structure */
  149. ams_delta_mtd->priv = this;
  150. /* Set address of NAND IO lines */
  151. this->IO_ADDR_R = (OMAP_MPUIO_BASE + OMAP_MPUIO_INPUT_LATCH);
  152. this->IO_ADDR_W = (OMAP_MPUIO_BASE + OMAP_MPUIO_OUTPUT);
  153. this->read_byte = ams_delta_read_byte;
  154. this->write_buf = ams_delta_write_buf;
  155. this->read_buf = ams_delta_read_buf;
  156. this->verify_buf = ams_delta_verify_buf;
  157. this->cmd_ctrl = ams_delta_hwcontrol;
  158. if (!omap_request_gpio(AMS_DELTA_GPIO_PIN_NAND_RB)) {
  159. this->dev_ready = ams_delta_nand_ready;
  160. } else {
  161. this->dev_ready = NULL;
  162. printk(KERN_NOTICE "Couldn't request gpio for Delta NAND ready.\n");
  163. }
  164. /* 25 us command delay time */
  165. this->chip_delay = 30;
  166. this->ecc.mode = NAND_ECC_SOFT;
  167. /* Set chip enabled, but */
  168. ams_delta_latch2_write(NAND_MASK, AMS_DELTA_LATCH2_NAND_NRE |
  169. AMS_DELTA_LATCH2_NAND_NWE |
  170. AMS_DELTA_LATCH2_NAND_NCE |
  171. AMS_DELTA_LATCH2_NAND_NWP);
  172. /* Scan to find existance of the device */
  173. if (nand_scan(ams_delta_mtd, 1)) {
  174. err = -ENXIO;
  175. goto out_mtd;
  176. }
  177. /* Register the partitions */
  178. add_mtd_partitions(ams_delta_mtd, partition_info,
  179. ARRAY_SIZE(partition_info));
  180. goto out;
  181. out_mtd:
  182. kfree(ams_delta_mtd);
  183. out:
  184. return err;
  185. }
  186. module_init(ams_delta_init);
  187. /*
  188. * Clean up routine
  189. */
  190. static void __exit ams_delta_cleanup(void)
  191. {
  192. /* Release resources, unregister device */
  193. nand_release(ams_delta_mtd);
  194. /* Free the MTD device structure */
  195. kfree(ams_delta_mtd);
  196. }
  197. module_exit(ams_delta_cleanup);
  198. MODULE_LICENSE("GPL");
  199. MODULE_AUTHOR("Jonathan McDowell <noodles@earth.li>");
  200. MODULE_DESCRIPTION("Glue layer for NAND flash on Amstrad E3 (Delta)");