• Home
  • History
  • Annotate
  • Line#
  • Navigate
  • Raw
  • Download
  • only in /asuswrt-rt-n18u-9.0.0.4.380.2695/release/src-rt-6.x.4708/linux/linux-2.6/drivers/mtd/nand/
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