aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/mtd/nand/Kconfig9
-rw-r--r--drivers/mtd/nand/Makefile1
-rw-r--r--drivers/mtd/nand/plat_nand.c150
3 files changed, 160 insertions, 0 deletions
diff --git a/drivers/mtd/nand/Kconfig b/drivers/mtd/nand/Kconfig
index 03ed2545f094..f1d60b6f048e 100644
--- a/drivers/mtd/nand/Kconfig
+++ b/drivers/mtd/nand/Kconfig
@@ -272,4 +272,13 @@ config MTD_NAND_NANDSIM
272 The simulator may simulate various NAND flash chips for the 272 The simulator may simulate various NAND flash chips for the
273 MTD nand layer. 273 MTD nand layer.
274 274
275config MTD_NAND_PLATFORM
276 tristate "Support for generic platform NAND driver"
277 depends on MTD_NAND
278 help
279 This implements a generic NAND driver for on-SOC platform
280 devices. You will need to provide platform-specific functions
281 via platform_data.
282
283
275endif # MTD_NAND 284endif # MTD_NAND
diff --git a/drivers/mtd/nand/Makefile b/drivers/mtd/nand/Makefile
index de1424b06b99..edba1db14bfa 100644
--- a/drivers/mtd/nand/Makefile
+++ b/drivers/mtd/nand/Makefile
@@ -26,5 +26,6 @@ obj-$(CONFIG_MTD_NAND_NDFC) += ndfc.o
26obj-$(CONFIG_MTD_NAND_AT91) += at91_nand.o 26obj-$(CONFIG_MTD_NAND_AT91) += at91_nand.o
27obj-$(CONFIG_MTD_NAND_CM_X270) += cmx270_nand.o 27obj-$(CONFIG_MTD_NAND_CM_X270) += cmx270_nand.o
28obj-$(CONFIG_MTD_NAND_BASLER_EXCITE) += excite_nandflash.o 28obj-$(CONFIG_MTD_NAND_BASLER_EXCITE) += excite_nandflash.o
29obj-$(CONFIG_MTD_NAND_PLATFORM) += plat_nand.o
29 30
30nand-objs := nand_base.o nand_bbt.o 31nand-objs := nand_base.o nand_bbt.o
diff --git a/drivers/mtd/nand/plat_nand.c b/drivers/mtd/nand/plat_nand.c
new file mode 100644
index 000000000000..cd725fc5e813
--- /dev/null
+++ b/drivers/mtd/nand/plat_nand.c
@@ -0,0 +1,150 @@
1/*
2 * Generic NAND driver
3 *
4 * Author: Vitaly Wool <vitalywool@gmail.com>
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License version 2 as
8 * published by the Free Software Foundation.
9 *
10 */
11
12#include <linux/io.h>
13#include <linux/module.h>
14#include <linux/platform_device.h>
15#include <linux/slab.h>
16#include <linux/mtd/mtd.h>
17#include <linux/mtd/nand.h>
18#include <linux/mtd/partitions.h>
19
20struct plat_nand_data {
21 struct nand_chip chip;
22 struct mtd_info mtd;
23 void __iomem *io_base;
24#ifdef CONFIG_MTD_PARTITIONS
25 int nr_parts;
26 struct mtd_partition *parts;
27#endif
28};
29
30/*
31 * Probe for the NAND device.
32 */
33static int __init plat_nand_probe(struct platform_device *pdev)
34{
35 struct platform_nand_data *pdata = pdev->dev.platform_data;
36 struct plat_nand_data *data;
37 int res = 0;
38
39 /* Allocate memory for the device structure (and zero it) */
40 data = kzalloc(sizeof(struct plat_nand_data), GFP_KERNEL);
41 if (!data) {
42 dev_err(&pdev->dev, "failed to allocate device structure.\n");
43 return -ENOMEM;
44 }
45
46 data->io_base = ioremap(pdev->resource[0].start,
47 pdev->resource[0].end - pdev->resource[0].start + 1);
48 if (data->io_base == NULL) {
49 dev_err(&pdev->dev, "ioremap failed\n");
50 kfree(data);
51 return -EIO;
52 }
53
54 data->chip.priv = &data;
55 data->mtd.priv = &data->chip;
56 data->mtd.owner = THIS_MODULE;
57
58 data->chip.IO_ADDR_R = data->io_base;
59 data->chip.IO_ADDR_W = data->io_base;
60 data->chip.cmd_ctrl = pdata->ctrl.cmd_ctrl;
61 data->chip.dev_ready = pdata->ctrl.dev_ready;
62 data->chip.select_chip = pdata->ctrl.select_chip;
63 data->chip.chip_delay = pdata->chip.chip_delay;
64 data->chip.options |= pdata->chip.options;
65
66 data->chip.ecc.hwctl = pdata->ctrl.hwcontrol;
67 data->chip.ecc.layout = pdata->chip.ecclayout;
68 data->chip.ecc.mode = NAND_ECC_SOFT;
69
70 platform_set_drvdata(pdev, data);
71
72 /* Scan to find existance of the device */
73 if (nand_scan(&data->mtd, 1)) {
74 res = -ENXIO;
75 goto out;
76 }
77
78#ifdef CONFIG_MTD_PARTITIONS
79 if (pdata->chip.part_probe_types) {
80 res = parse_mtd_partitions(&data->mtd,
81 pdata->chip.part_probe_types,
82 &data->parts, 0);
83 if (res > 0) {
84 add_mtd_partitions(&data->mtd, data->parts, res);
85 return 0;
86 }
87 }
88 if (pdata->chip.partitions) {
89 data->parts = pdata->chip.partitions;
90 res = add_mtd_partitions(&data->mtd, data->parts,
91 pdata->chip.nr_partitions);
92 } else
93#endif
94 res = add_mtd_device(&data->mtd);
95
96 if (!res)
97 return res;
98
99 nand_release(&data->mtd);
100out:
101 platform_set_drvdata(pdev, NULL);
102 iounmap(data->io_base);
103 kfree(data);
104 return res;
105}
106
107/*
108 * Remove a NAND device.
109 */
110static int __devexit plat_nand_remove(struct platform_device *pdev)
111{
112 struct plat_nand_data *data = platform_get_drvdata(pdev);
113 struct platform_nand_data *pdata = pdev->dev.platform_data;
114
115 nand_release(&data->mtd);
116#ifdef CONFIG_MTD_PARTITIONS
117 if (data->parts && data->parts != pdata->chip.partitions)
118 kfree(data->parts);
119#endif
120 iounmap(data->io_base);
121 kfree(data);
122
123 return 0;
124}
125
126static struct platform_driver plat_nand_driver = {
127 .probe = plat_nand_probe,
128 .remove = plat_nand_remove,
129 .driver = {
130 .name = "gen_nand",
131 .owner = THIS_MODULE,
132 },
133};
134
135static int __init plat_nand_init(void)
136{
137 return platform_driver_register(&plat_nand_driver);
138}
139
140static void __exit plat_nand_exit(void)
141{
142 platform_driver_unregister(&plat_nand_driver);
143}
144
145module_init(plat_nand_init);
146module_exit(plat_nand_exit);
147
148MODULE_LICENSE("GPL");
149MODULE_AUTHOR("Vitaly Wool");
150MODULE_DESCRIPTION("Simple generic NAND driver");