mpc83xx: add support for 3.7
[openwrt/svn-archive/archive.git] / target / linux / mpc83xx / patches-3.7 / 203-mtd-add-rbppc_nand-driver.patch
1 --- a/drivers/mtd/nand/Kconfig
2 +++ b/drivers/mtd/nand/Kconfig
3 @@ -454,6 +454,13 @@ config MTD_NAND_PLATFORM
4 devices. You will need to provide platform-specific functions
5 via platform_data.
6
7 +config MTD_NAND_RB_PPC
8 + tristate "MikroTik RB333/600 NAND support"
9 + depends on RB_PPC
10 + help
11 + This option enables support for the NAND device on MikroTik
12 + RouterBOARD 333/600 series boards.
13 +
14 config MTD_ALAUDA
15 tristate "MTD driver for Olympus MAUSB-10 and Fujifilm DPC-R1"
16 depends on USB
17 --- a/drivers/mtd/nand/Makefile
18 +++ b/drivers/mtd/nand/Makefile
19 @@ -34,6 +34,7 @@ obj-$(CONFIG_MTD_NAND_CM_X270) += cmx27
20 obj-$(CONFIG_MTD_NAND_PXA3xx) += pxa3xx_nand.o
21 obj-$(CONFIG_MTD_NAND_TMIO) += tmio_nand.o
22 obj-$(CONFIG_MTD_NAND_PLATFORM) += plat_nand.o
23 +obj-$(CONFIG_MTD_NAND_RB_PPC) += rbppc_nand.o
24 obj-$(CONFIG_MTD_ALAUDA) += alauda.o
25 obj-$(CONFIG_MTD_NAND_PASEMI) += pasemi_nand.o
26 obj-$(CONFIG_MTD_NAND_ORION) += orion_nand.o
27 --- /dev/null
28 +++ b/drivers/mtd/nand/rbppc_nand.c
29 @@ -0,0 +1,250 @@
30 +/*
31 + * Copyright (C) 2008-2009 Noah Fontes <nfontes@transtruct.org>
32 + * Copyright (C) 2009 Michael Guntsche <mike@it-loops.com>
33 + * Copyright (C) Mikrotik 2007
34 + *
35 + * This program is free software; you can redistribute it and/or modify it
36 + * under the terms of the GNU General Public License as published by the
37 + * Free Software Foundation; either version 2 of the License, or (at your
38 + * option) any later version.
39 + */
40 +
41 +#include <linux/init.h>
42 +#include <linux/module.h>
43 +#include <linux/mtd/nand.h>
44 +#include <linux/mtd/mtd.h>
45 +#include <linux/mtd/partitions.h>
46 +#include <linux/of_platform.h>
47 +#include <linux/of_device.h>
48 +#include <linux/slab.h>
49 +#include <linux/delay.h>
50 +#include <asm/io.h>
51 +
52 +#define DRV_NAME "rbppc_nand"
53 +#define DRV_VERSION "0.0.2"
54 +
55 +static struct mtd_info rmtd;
56 +static struct nand_chip rnand;
57 +
58 +struct rbppc_nand_info {
59 + void *gpi;
60 + void *gpo;
61 + void *localbus;
62 +
63 + unsigned gpio_rdy;
64 + unsigned gpio_nce;
65 + unsigned gpio_cle;
66 + unsigned gpio_ale;
67 + unsigned gpio_ctrls;
68 +};
69 +
70 +/* We must use the OOB layout from yaffs 1 if we want this to be recognized
71 + * properly. Borrowed from the OpenWRT patches for the RB532.
72 + *
73 + * See <https://dev.openwrt.org/browser/trunk/target/linux/rb532/
74 + * patches-2.6.28/025-rb532_nand_fixup.patch> for more details.
75 + */
76 +static struct nand_ecclayout rbppc_nand_oob_16 = {
77 + .eccbytes = 6,
78 + .eccpos = { 8, 9, 10, 13, 14, 15 },
79 + .oobavail = 9,
80 + .oobfree = { { 0, 4 }, { 6, 2 }, { 11, 2 }, { 4, 1 } }
81 +};
82 +
83 +static struct mtd_partition rbppc_nand_partition_info[] = {
84 + {
85 + name: "kernel",
86 + offset: 0,
87 + size: 4 * 1024 * 1024,
88 + },
89 + {
90 + name: "rootfs",
91 + offset: MTDPART_OFS_NXTBLK,
92 + size: MTDPART_SIZ_FULL,
93 + },
94 +};
95 +
96 +static int rbppc_nand_dev_ready(struct mtd_info *mtd) {
97 + struct nand_chip *chip = mtd->priv;
98 + struct rbppc_nand_info *priv = chip->priv;
99 +
100 + return in_be32(priv->gpi) & priv->gpio_rdy;
101 +}
102 +
103 +static void rbppc_nand_cmd_ctrl(struct mtd_info *mtd, int cmd, unsigned int ctrl) {
104 + struct nand_chip *chip = mtd->priv;
105 + struct rbppc_nand_info *priv = chip->priv;
106 +
107 + if (ctrl & NAND_CTRL_CHANGE) {
108 + unsigned val = in_be32(priv->gpo);
109 + if (!(val & priv->gpio_nce)) {
110 + /* make sure Local Bus has done NAND operations */
111 + readb(priv->localbus);
112 + }
113 +
114 + if (ctrl & NAND_CLE) {
115 + val |= priv->gpio_cle;
116 + } else {
117 + val &= ~priv->gpio_cle;
118 + }
119 + if (ctrl & NAND_ALE) {
120 + val |= priv->gpio_ale;
121 + } else {
122 + val &= ~priv->gpio_ale;
123 + }
124 + if (!(ctrl & NAND_NCE)) {
125 + val |= priv->gpio_nce;
126 + } else {
127 + val &= ~priv->gpio_nce;
128 + }
129 + out_be32(priv->gpo, val);
130 +
131 + /* make sure GPIO output has changed */
132 + val ^= in_be32(priv->gpo);
133 + if (val & priv->gpio_ctrls) {
134 + printk(KERN_ERR "rbppc_nand_hwcontrol: NAND GPO change failed 0x%08x\n", val);
135 + }
136 + }
137 +
138 + if (cmd != NAND_CMD_NONE) writeb(cmd, chip->IO_ADDR_W);
139 +}
140 +
141 +static void rbppc_nand_read_buf(struct mtd_info *mtd, uint8_t *buf, int len)
142 +{
143 + struct nand_chip *chip = mtd->priv;
144 + memcpy(buf, chip->IO_ADDR_R, len);
145 +}
146 +
147 +static unsigned init_ok = 0;
148 +
149 +static int __devinit rbppc_nand_probe(struct platform_device *pdev)
150 +{
151 + struct device_node *gpio;
152 + struct device_node *nnand;
153 + struct resource res;
154 + struct rbppc_nand_info *info;
155 + void *baddr;
156 + const unsigned *rdy, *nce, *cle, *ale;
157 +
158 + printk(KERN_INFO "rbppc_nand_probe: MikroTik RouterBOARD 333/600 series NAND driver, version " DRV_VERSION "\n");
159 +
160 + info = kmalloc(sizeof(*info), GFP_KERNEL);
161 +
162 + rdy = of_get_property(pdev->dev.of_node, "rdy", NULL);
163 + nce = of_get_property(pdev->dev.of_node, "nce", NULL);
164 + cle = of_get_property(pdev->dev.of_node, "cle", NULL);
165 + ale = of_get_property(pdev->dev.of_node, "ale", NULL);
166 +
167 + if (!rdy || !nce || !cle || !ale) {
168 + printk(KERN_ERR "rbppc_nand_probe: GPIO properties are missing\n");
169 + goto err;
170 + }
171 + if (rdy[0] != nce[0] || rdy[0] != cle[0] || rdy[0] != ale[0]) {
172 + printk(KERN_ERR "rbppc_nand_probe: Different GPIOs are not supported\n");
173 + goto err;
174 + }
175 +
176 + gpio = of_find_node_by_phandle(rdy[0]);
177 + if (!gpio) {
178 + printk(KERN_ERR "rbppc_nand_probe: No GPIO<%x> node found\n", *rdy);
179 + goto err;
180 + }
181 + if (of_address_to_resource(gpio, 0, &res)) {
182 + printk(KERN_ERR "rbppc_nand_probe: No reg property in GPIO found\n");
183 + goto err;
184 + }
185 + info->gpo = ioremap_nocache(res.start, res.end - res.start + 1);
186 +
187 + if (!of_address_to_resource(gpio, 1, &res)) {
188 + info->gpi = ioremap_nocache(res.start, res.end - res.start + 1);
189 + } else {
190 + info->gpi = info->gpo;
191 + }
192 + of_node_put(gpio);
193 +
194 + info->gpio_rdy = 1 << (31 - rdy[1]);
195 + info->gpio_nce = 1 << (31 - nce[1]);
196 + info->gpio_cle = 1 << (31 - cle[1]);
197 + info->gpio_ale = 1 << (31 - ale[1]);
198 + info->gpio_ctrls = info->gpio_nce | info->gpio_cle | info->gpio_ale;
199 +
200 + nnand = of_find_node_by_name(NULL, "nnand");
201 + if (!nnand) {
202 + printk("rbppc_nand_probe: No nNAND found\n");
203 + goto err;
204 + }
205 + if (of_address_to_resource(nnand, 0, &res)) {
206 + printk("rbppc_nand_probe: No reg property in nNAND found\n");
207 + goto err;
208 + }
209 + of_node_put(nnand);
210 + info->localbus = ioremap_nocache(res.start, res.end - res.start + 1);
211 +
212 + if (of_address_to_resource(pdev->dev.of_node, 0, &res)) {
213 + printk("rbppc_nand_probe: No reg property found\n");
214 + goto err;
215 + }
216 + baddr = ioremap_nocache(res.start, res.end - res.start + 1);
217 +
218 + memset(&rnand, 0, sizeof(rnand));
219 + rnand.cmd_ctrl = rbppc_nand_cmd_ctrl;
220 + rnand.dev_ready = rbppc_nand_dev_ready;
221 + rnand.read_buf = rbppc_nand_read_buf;
222 + rnand.IO_ADDR_W = baddr;
223 + rnand.IO_ADDR_R = baddr;
224 + rnand.priv = info;
225 +
226 + memset(&rmtd, 0, sizeof(rmtd));
227 + rnand.ecc.mode = NAND_ECC_SOFT;
228 + rnand.ecc.layout = &rbppc_nand_oob_16;
229 + rnand.chip_delay = 25;
230 + rmtd.priv = &rnand;
231 + rmtd.owner = THIS_MODULE;
232 +
233 + if (nand_scan(&rmtd, 1) && nand_scan(&rmtd, 1) && nand_scan(&rmtd, 1) && nand_scan(&rmtd, 1)) {
234 + printk(KERN_ERR "rbppc_nand_probe: RouterBOARD NAND device not found\n");
235 + return -ENXIO;
236 + }
237 +
238 + mtd_device_parse_register(&rmtd, NULL, 0, rbppc_nand_partition_info, 2);
239 + init_ok = 1;
240 + return 0;
241 +
242 +err:
243 + kfree(info);
244 + return -1;
245 +}
246 +
247 +static struct of_device_id rbppc_nand_ids[] = {
248 + { .name = "nand", },
249 + { },
250 +};
251 +
252 +static struct platform_driver rbppc_nand_driver = {
253 + .probe = rbppc_nand_probe,
254 + .driver = {
255 + .name = "rbppc-nand",
256 + .owner = THIS_MODULE,
257 + .of_match_table = rbppc_nand_ids,
258 + },
259 +};
260 +
261 +static int __init rbppc_nand_init(void)
262 +{
263 + return platform_driver_register(&rbppc_nand_driver);
264 +}
265 +
266 +static void __exit rbppc_nand_exit(void)
267 +{
268 + platform_driver_unregister(&rbppc_nand_driver);
269 +}
270 +
271 +MODULE_AUTHOR("Mikrotikls SIA");
272 +MODULE_AUTHOR("Noah Fontes");
273 +MODULE_AUTHOR("Michael Guntsche");
274 +MODULE_DESCRIPTION("MikroTik RouterBOARD 333/600 series NAND driver");
275 +MODULE_LICENSE("GPL");
276 +MODULE_VERSION(DRV_VERSION);
277 +
278 +module_init(rbppc_nand_init);
279 +module_exit(rbppc_nand_exit);