aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/mtd/nand/ams-delta.c
diff options
context:
space:
mode:
authorJonathan McDowell <noodles@earth.li>2006-05-21 13:11:55 -0400
committerDavid Woodhouse <dwmw2@infradead.org>2006-05-21 13:11:55 -0400
commit3d12c0c75db0cd85beb11c4e2d86a49cabe3cfff (patch)
tree5ca5abdf22e5b9887ea3665fd14c9a91c7c77d0b /drivers/mtd/nand/ams-delta.c
parent6c8b44abc86a3e23dd1a22c0ee187f06bd7c7f5d (diff)
[MTD] Add Amstrad Delta NAND support
The patch below adds support for the NAND device on the Amstrad Delta. This is a 32MiB 8bit Toshiba device, with the data bus connected to the OMAP MPUIO pins and ALE, CLE, NCE, NRE, NWE and NWP all connected to the Delta's latch2 16bit latch. Signed-Off-By: Jonathan McDowell <noodles@earth.li> Signed-off-by: David Woodhouse <dwmw2@infradead.org>
Diffstat (limited to 'drivers/mtd/nand/ams-delta.c')
-rw-r--r--drivers/mtd/nand/ams-delta.c238
1 files changed, 238 insertions, 0 deletions
diff --git a/drivers/mtd/nand/ams-delta.c b/drivers/mtd/nand/ams-delta.c
new file mode 100644
index 000000000000..5a349eb316f5
--- /dev/null
+++ b/drivers/mtd/nand/ams-delta.c
@@ -0,0 +1,238 @@
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
17#include <linux/slab.h>
18#include <linux/init.h>
19#include <linux/module.h>
20#include <linux/delay.h>
21#include <linux/mtd/mtd.h>
22#include <linux/mtd/nand.h>
23#include <linux/mtd/partitions.h>
24#include <asm/io.h>
25#include <asm/arch/hardware.h>
26#include <asm/sizes.h>
27#include <asm/arch/gpio.h>
28#include <asm/arch/board-ams-delta.h>
29
30/*
31 * MTD structure for E3 (Delta)
32 */
33static struct mtd_info *ams_delta_mtd = NULL;
34
35#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)
36
37#define T_NAND_CTL_CLRALE(iob) ams_delta_latch2_write(AMS_DELTA_LATCH2_NAND_ALE, 0)
38#define T_NAND_CTL_SETALE(iob) ams_delta_latch2_write(AMS_DELTA_LATCH2_NAND_ALE, AMS_DELTA_LATCH2_NAND_ALE)
39#define T_NAND_CTL_CLRCLE(iob) ams_delta_latch2_write(AMS_DELTA_LATCH2_NAND_CLE, 0)
40#define T_NAND_CTL_SETCLE(iob) ams_delta_latch2_write(AMS_DELTA_LATCH2_NAND_CLE, AMS_DELTA_LATCH2_NAND_CLE)
41#define T_NAND_CTL_SETNCE(iob) ams_delta_latch2_write(AMS_DELTA_LATCH2_NAND_NCE, 0)
42#define T_NAND_CTL_CLRNCE(iob) ams_delta_latch2_write(AMS_DELTA_LATCH2_NAND_NCE, AMS_DELTA_LATCH2_NAND_NCE)
43
44/*
45 * Define partitions for flash devices
46 */
47
48static struct mtd_partition partition_info[] = {
49 { .name = "Kernel",
50 .offset = 0,
51 .size = 3 * SZ_1M + SZ_512K },
52 { .name = "u-boot",
53 .offset = 3 * SZ_1M + SZ_512K,
54 .size = SZ_256K },
55 { .name = "u-boot params",
56 .offset = 3 * SZ_1M + SZ_512K + SZ_256K,
57 .size = SZ_256K },
58 { .name = "Amstrad LDR",
59 .offset = 4 * SZ_1M,
60 .size = SZ_256K },
61 { .name = "File system",
62 .offset = 4 * SZ_1M + 1 * SZ_256K,
63 .size = 27 * SZ_1M },
64 { .name = "PBL reserved",
65 .offset = 32 * SZ_1M - 3 * SZ_256K,
66 .size = 3 * SZ_256K },
67};
68
69/*
70 * hardware specific access to control-lines
71*/
72
73static void ams_delta_hwcontrol(struct mtd_info *mtd, int cmd)
74{
75 switch (cmd) {
76
77 case NAND_CTL_SETCLE: T_NAND_CTL_SETCLE(cmd); break;
78 case NAND_CTL_CLRCLE: T_NAND_CTL_CLRCLE(cmd); break;
79
80 case NAND_CTL_SETALE: T_NAND_CTL_SETALE(cmd); break;
81 case NAND_CTL_CLRALE: T_NAND_CTL_CLRALE(cmd); break;
82
83 case NAND_CTL_SETNCE: T_NAND_CTL_SETNCE(cmd); break;
84 case NAND_CTL_CLRNCE: T_NAND_CTL_CLRNCE(cmd); break;
85 }
86}
87
88static void ams_delta_write_byte(struct mtd_info *mtd, u_char byte)
89{
90 struct nand_chip *this = mtd->priv;
91
92 omap_writew(0, (OMAP_MPUIO_BASE + OMAP_MPUIO_IO_CNTL));
93 omap_writew(byte, this->IO_ADDR_W);
94 ams_delta_latch2_write(AMS_DELTA_LATCH2_NAND_NWE, 0);
95 ndelay(40);
96 ams_delta_latch2_write(AMS_DELTA_LATCH2_NAND_NWE,
97 AMS_DELTA_LATCH2_NAND_NWE);
98}
99
100static u_char ams_delta_read_byte(struct mtd_info *mtd)
101{
102 u_char res;
103 struct nand_chip *this = mtd->priv;
104
105 ams_delta_latch2_write(AMS_DELTA_LATCH2_NAND_NRE, 0);
106 ndelay(40);
107 omap_writew(~0, (OMAP_MPUIO_BASE + OMAP_MPUIO_IO_CNTL));
108 res = omap_readw(this->IO_ADDR_R);
109 ams_delta_latch2_write(AMS_DELTA_LATCH2_NAND_NRE,
110 AMS_DELTA_LATCH2_NAND_NRE);
111
112 return res;
113}
114
115static void ams_delta_write_buf(struct mtd_info *mtd, const u_char *buf,
116 int len)
117{
118 int i;
119
120 for (i=0; i<len; i++)
121 ams_delta_write_byte(mtd, buf[i]);
122}
123
124static void ams_delta_read_buf(struct mtd_info *mtd, u_char *buf, int len)
125{
126 int i;
127
128 for (i=0; i<len; i++)
129 buf[i] = ams_delta_read_byte(mtd);
130}
131
132static int ams_delta_verify_buf(struct mtd_info *mtd, const u_char *buf,
133 int len)
134{
135 int i;
136
137 for (i=0; i<len; i++)
138 if (buf[i] != ams_delta_read_byte(mtd))
139 return -EFAULT;
140
141 return 0;
142}
143
144static int ams_delta_nand_ready(struct mtd_info *mtd)
145{
146 return omap_get_gpio_datain(AMS_DELTA_GPIO_PIN_NAND_RB);
147}
148
149/*
150 * Main initialization routine
151 */
152static int __init ams_delta_init(void)
153{
154 struct nand_chip *this;
155 int err = 0;
156
157 /* Allocate memory for MTD device structure and private data */
158 ams_delta_mtd = kmalloc(sizeof(struct mtd_info) +
159 sizeof(struct nand_chip), GFP_KERNEL);
160 if (!ams_delta_mtd) {
161 printk (KERN_WARNING "Unable to allocate E3 NAND MTD device structure.\n");
162 err = -ENOMEM;
163 goto out;
164 }
165
166 ams_delta_mtd->owner = THIS_MODULE;
167
168 /* Get pointer to private data */
169 this = (struct nand_chip *) (&ams_delta_mtd[1]);
170
171 /* Initialize structures */
172 memset(ams_delta_mtd, 0, sizeof(struct mtd_info));
173 memset(this, 0, sizeof(struct nand_chip));
174
175 /* Link the private data with the MTD structure */
176 ams_delta_mtd->priv = this;
177
178 /* Set address of NAND IO lines */
179 this->IO_ADDR_R = (OMAP_MPUIO_BASE + OMAP_MPUIO_INPUT_LATCH);
180 this->IO_ADDR_W = (OMAP_MPUIO_BASE + OMAP_MPUIO_OUTPUT);
181 this->read_byte = ams_delta_read_byte;
182 this->write_byte = ams_delta_write_byte;
183 this->write_buf = ams_delta_write_buf;
184 this->read_buf = ams_delta_read_buf;
185 this->verify_buf = ams_delta_verify_buf;
186 this->hwcontrol = ams_delta_hwcontrol;
187 if (!omap_request_gpio(AMS_DELTA_GPIO_PIN_NAND_RB)) {
188 this->dev_ready = ams_delta_nand_ready;
189 } else {
190 this->dev_ready = NULL;
191 printk(KERN_NOTICE "Couldn't request gpio for Delta NAND ready.\n");
192 }
193 /* 25 us command delay time */
194 this->chip_delay = 30;
195 this->eccmode = NAND_ECC_SOFT;
196
197 /* Set chip enabled, but */
198 ams_delta_latch2_write(NAND_MASK, AMS_DELTA_LATCH2_NAND_NRE |
199 AMS_DELTA_LATCH2_NAND_NWE |
200 AMS_DELTA_LATCH2_NAND_NCE |
201 AMS_DELTA_LATCH2_NAND_NWP);
202
203 /* Scan to find existance of the device */
204 if (nand_scan(ams_delta_mtd, 1)) {
205 err = -ENXIO;
206 goto out_mtd;
207 }
208
209 /* Register the partitions */
210 add_mtd_partitions(ams_delta_mtd, partition_info,
211 ARRAY_SIZE(partition_info));
212
213 goto out;
214
215 out_mtd:
216 kfree(ams_delta_mtd);
217 out:
218 return err;
219}
220
221module_init(ams_delta_init);
222
223/*
224 * Clean up routine
225 */
226static void __exit ams_delta_cleanup(void)
227{
228 /* Release resources, unregister device */
229 nand_release(ams_delta_mtd);
230
231 /* Free the MTD device structure */
232 kfree(ams_delta_mtd);
233}
234module_exit(ams_delta_cleanup);
235
236MODULE_LICENSE("GPL");
237MODULE_AUTHOR("Jonathan McDowell <noodles@earth.li>");
238MODULE_DESCRIPTION("Glue layer for NAND flash on Amstrad E3 (Delta)");