blob: 8f9bab8dc8da32426dee85e244dd78ff3b5262a8 [file] [log] [blame]
Vitaly Woola2c2fe42006-12-06 13:17:49 +03001/*
David Gibsonc4d5e372007-09-20 11:22:25 +10002 * Flash mappings described by the OF (or flattened) device tree
Vitaly Woola2c2fe42006-12-06 13:17:49 +03003 *
4 * Copyright (C) 2006 MontaVista Software Inc.
5 * Author: Vitaly Wool <vwool@ru.mvista.com>
6 *
David Gibson20991722007-09-07 13:23:53 +10007 * Revised to handle newer style flash binding by:
8 * Copyright (C) 2007 David Gibson, IBM Corporation.
9 *
Vitaly Woola2c2fe42006-12-06 13:17:49 +030010 * This program is free software; you can redistribute it and/or modify it
11 * under the terms of the GNU General Public License as published by the
12 * Free Software Foundation; either version 2 of the License, or (at your
13 * option) any later version.
14 */
15
16#include <linux/module.h>
17#include <linux/types.h>
Vitaly Woola2c2fe42006-12-06 13:17:49 +030018#include <linux/init.h>
Vitaly Woola2c2fe42006-12-06 13:17:49 +030019#include <linux/device.h>
20#include <linux/mtd/mtd.h>
21#include <linux/mtd/map.h>
22#include <linux/mtd/partitions.h>
Stefan Roese143070e2009-04-16 14:10:45 +020023#include <linux/mtd/concat.h>
David Gibsonc4d5e372007-09-20 11:22:25 +100024#include <linux/of.h>
25#include <linux/of_platform.h>
Tejun Heo5a0e3ad2010-03-24 17:04:11 +090026#include <linux/slab.h>
Vitaly Woola2c2fe42006-12-06 13:17:49 +030027
Stefan Roese143070e2009-04-16 14:10:45 +020028struct of_flash_list {
29 struct mtd_info *mtd;
30 struct map_info map;
31 struct resource *res;
32};
33
David Gibsonc4d5e372007-09-20 11:22:25 +100034struct of_flash {
Stefan Roese143070e2009-04-16 14:10:45 +020035 struct mtd_info *cmtd;
Vitaly Woola2c2fe42006-12-06 13:17:49 +030036#ifdef CONFIG_MTD_PARTITIONS
Vitaly Woola2c2fe42006-12-06 13:17:49 +030037 struct mtd_partition *parts;
38#endif
Stefan Roese143070e2009-04-16 14:10:45 +020039 int list_size; /* number of elements in of_flash_list */
40 struct of_flash_list list[0];
Vitaly Woola2c2fe42006-12-06 13:17:49 +030041};
42
Vitaly Woola2c2fe42006-12-06 13:17:49 +030043#ifdef CONFIG_MTD_PARTITIONS
David Gibsonc4d5e372007-09-20 11:22:25 +100044#define OF_FLASH_PARTS(info) ((info)->parts)
Vitaly Woola2c2fe42006-12-06 13:17:49 +030045
Grant Likely2dc11582010-08-06 09:25:50 -060046static int parse_obsolete_partitions(struct platform_device *dev,
David Gibsonc4d5e372007-09-20 11:22:25 +100047 struct of_flash *info,
David Gibson20991722007-09-07 13:23:53 +100048 struct device_node *dp)
Vitaly Woola2c2fe42006-12-06 13:17:49 +030049{
David Gibson20991722007-09-07 13:23:53 +100050 int i, plen, nr_parts;
51 const struct {
52 u32 offset, len;
53 } *part;
54 const char *names;
Vitaly Woola2c2fe42006-12-06 13:17:49 +030055
David Gibson20991722007-09-07 13:23:53 +100056 part = of_get_property(dp, "partitions", &plen);
57 if (!part)
David Gibsonc4d5e372007-09-20 11:22:25 +100058 return 0; /* No partitions found */
Vitaly Woola2c2fe42006-12-06 13:17:49 +030059
David Gibson20991722007-09-07 13:23:53 +100060 dev_warn(&dev->dev, "Device tree uses obsolete partition map binding\n");
Vitaly Woola2c2fe42006-12-06 13:17:49 +030061
David Gibson20991722007-09-07 13:23:53 +100062 nr_parts = plen / sizeof(part[0]);
Vitaly Woola2c2fe42006-12-06 13:17:49 +030063
David Gibsonc4d5e372007-09-20 11:22:25 +100064 info->parts = kzalloc(nr_parts * sizeof(*info->parts), GFP_KERNEL);
65 if (!info->parts)
David Gibson20991722007-09-07 13:23:53 +100066 return -ENOMEM;
Vitaly Woola2c2fe42006-12-06 13:17:49 +030067
David Gibson20991722007-09-07 13:23:53 +100068 names = of_get_property(dp, "partition-names", &plen);
Vitaly Woola2c2fe42006-12-06 13:17:49 +030069
David Gibson20991722007-09-07 13:23:53 +100070 for (i = 0; i < nr_parts; i++) {
71 info->parts[i].offset = part->offset;
72 info->parts[i].size = part->len & ~1;
73 if (part->len & 1) /* bit 0 set signifies read only partition */
74 info->parts[i].mask_flags = MTD_WRITEABLE;
Vitaly Woola2c2fe42006-12-06 13:17:49 +030075
David Gibson20991722007-09-07 13:23:53 +100076 if (names && (plen > 0)) {
77 int len = strlen(names) + 1;
Vitaly Woola2c2fe42006-12-06 13:17:49 +030078
David Gibson20991722007-09-07 13:23:53 +100079 info->parts[i].name = (char *)names;
Vitaly Woola2c2fe42006-12-06 13:17:49 +030080 plen -= len;
David Gibson20991722007-09-07 13:23:53 +100081 names += len;
82 } else {
83 info->parts[i].name = "unnamed";
84 }
Vitaly Woola2c2fe42006-12-06 13:17:49 +030085
David Gibson20991722007-09-07 13:23:53 +100086 part++;
Vitaly Woola2c2fe42006-12-06 13:17:49 +030087 }
David Gibson20991722007-09-07 13:23:53 +100088
89 return nr_parts;
Vitaly Woola2c2fe42006-12-06 13:17:49 +030090}
David Gibson20991722007-09-07 13:23:53 +100091#else /* MTD_PARTITIONS */
David Gibsonc4d5e372007-09-20 11:22:25 +100092#define OF_FLASH_PARTS(info) (0)
93#define parse_partitions(info, dev) (0)
David Gibson20991722007-09-07 13:23:53 +100094#endif /* MTD_PARTITIONS */
Vitaly Woola2c2fe42006-12-06 13:17:49 +030095
Grant Likely2dc11582010-08-06 09:25:50 -060096static int of_flash_remove(struct platform_device *dev)
Vitaly Woola2c2fe42006-12-06 13:17:49 +030097{
David Gibsonc4d5e372007-09-20 11:22:25 +100098 struct of_flash *info;
Stefan Roese143070e2009-04-16 14:10:45 +020099 int i;
Vitaly Woola2c2fe42006-12-06 13:17:49 +0300100
101 info = dev_get_drvdata(&dev->dev);
David Gibsonc4d5e372007-09-20 11:22:25 +1000102 if (!info)
Vitaly Woola2c2fe42006-12-06 13:17:49 +0300103 return 0;
104 dev_set_drvdata(&dev->dev, NULL);
105
Stefan Roese143070e2009-04-16 14:10:45 +0200106#ifdef CONFIG_MTD_CONCAT
107 if (info->cmtd != info->list[0].mtd) {
108 del_mtd_device(info->cmtd);
109 mtd_concat_destroy(info->cmtd);
110 }
111#endif
112
113 if (info->cmtd) {
David Gibsonc4d5e372007-09-20 11:22:25 +1000114 if (OF_FLASH_PARTS(info)) {
Stefan Roese143070e2009-04-16 14:10:45 +0200115 del_mtd_partitions(info->cmtd);
David Gibsonc4d5e372007-09-20 11:22:25 +1000116 kfree(OF_FLASH_PARTS(info));
Vitaly Woola2c2fe42006-12-06 13:17:49 +0300117 } else {
Stefan Roese143070e2009-04-16 14:10:45 +0200118 del_mtd_device(info->cmtd);
Vitaly Woola2c2fe42006-12-06 13:17:49 +0300119 }
Vitaly Woola2c2fe42006-12-06 13:17:49 +0300120 }
121
Stefan Roese143070e2009-04-16 14:10:45 +0200122 for (i = 0; i < info->list_size; i++) {
123 if (info->list[i].mtd)
124 map_destroy(info->list[i].mtd);
Vitaly Woola2c2fe42006-12-06 13:17:49 +0300125
Stefan Roese143070e2009-04-16 14:10:45 +0200126 if (info->list[i].map.virt)
127 iounmap(info->list[i].map.virt);
128
129 if (info->list[i].res) {
130 release_resource(info->list[i].res);
131 kfree(info->list[i].res);
132 }
Vitaly Woola2c2fe42006-12-06 13:17:49 +0300133 }
134
Stefan Roese143070e2009-04-16 14:10:45 +0200135 kfree(info);
136
Vitaly Woola2c2fe42006-12-06 13:17:49 +0300137 return 0;
138}
139
David Gibson20991722007-09-07 13:23:53 +1000140/* Helper function to handle probing of the obsolete "direct-mapped"
141 * compatible binding, which has an extra "probe-type" property
142 * describing the type of flash probe necessary. */
Grant Likely2dc11582010-08-06 09:25:50 -0600143static struct mtd_info * __devinit obsolete_probe(struct platform_device *dev,
David Gibson20991722007-09-07 13:23:53 +1000144 struct map_info *map)
145{
Grant Likely61c7a082010-04-13 16:12:29 -0700146 struct device_node *dp = dev->dev.of_node;
David Gibson20991722007-09-07 13:23:53 +1000147 const char *of_probe;
148 struct mtd_info *mtd;
149 static const char *rom_probe_types[]
150 = { "cfi_probe", "jedec_probe", "map_rom"};
151 int i;
152
153 dev_warn(&dev->dev, "Device tree uses obsolete \"direct-mapped\" "
154 "flash binding\n");
155
156 of_probe = of_get_property(dp, "probe-type", NULL);
157 if (!of_probe) {
158 for (i = 0; i < ARRAY_SIZE(rom_probe_types); i++) {
159 mtd = do_map_probe(rom_probe_types[i], map);
160 if (mtd)
161 return mtd;
162 }
163 return NULL;
164 } else if (strcmp(of_probe, "CFI") == 0) {
165 return do_map_probe("cfi_probe", map);
166 } else if (strcmp(of_probe, "JEDEC") == 0) {
167 return do_map_probe("jedec_probe", map);
168 } else {
169 if (strcmp(of_probe, "ROM") != 0)
David Gibsonc4d5e372007-09-20 11:22:25 +1000170 dev_warn(&dev->dev, "obsolete_probe: don't know probe "
171 "type '%s', mapping as rom\n", of_probe);
David Gibson20991722007-09-07 13:23:53 +1000172 return do_map_probe("mtd_rom", map);
173 }
174}
175
Jason Gunthorpe9d5da3a2010-03-09 12:27:56 -0700176#ifdef CONFIG_MTD_PARTITIONS
177/* When partitions are set we look for a linux,part-probe property which
178 specifies the list of partition probers to use. If none is given then the
179 default is use. These take precedence over other device tree
180 information. */
181static const char *part_probe_types_def[] = { "cmdlinepart", "RedBoot", NULL };
182static const char ** __devinit of_get_probes(struct device_node *dp)
183{
184 const char *cp;
185 int cplen;
186 unsigned int l;
187 unsigned int count;
188 const char **res;
189
190 cp = of_get_property(dp, "linux,part-probe", &cplen);
191 if (cp == NULL)
192 return part_probe_types_def;
193
194 count = 0;
195 for (l = 0; l != cplen; l++)
196 if (cp[l] == 0)
197 count++;
198
199 res = kzalloc((count + 1)*sizeof(*res), GFP_KERNEL);
200 count = 0;
201 while (cplen > 0) {
202 res[count] = cp;
203 l = strlen(cp) + 1;
204 cp += l;
205 cplen -= l;
206 count++;
207 }
208 return res;
209}
210
211static void __devinit of_free_probes(const char **probes)
212{
213 if (probes != part_probe_types_def)
214 kfree(probes);
215}
216#endif
217
Grant Likely2dc11582010-08-06 09:25:50 -0600218static int __devinit of_flash_probe(struct platform_device *dev,
David Gibsonc4d5e372007-09-20 11:22:25 +1000219 const struct of_device_id *match)
Vitaly Woola2c2fe42006-12-06 13:17:49 +0300220{
Scott Wood9a310d22008-01-15 17:54:43 -0600221#ifdef CONFIG_MTD_PARTITIONS
Jason Gunthorpe9d5da3a2010-03-09 12:27:56 -0700222 const char **part_probe_types;
Scott Wood9a310d22008-01-15 17:54:43 -0600223#endif
Grant Likely61c7a082010-04-13 16:12:29 -0700224 struct device_node *dp = dev->dev.of_node;
Vitaly Woola2c2fe42006-12-06 13:17:49 +0300225 struct resource res;
David Gibsonc4d5e372007-09-20 11:22:25 +1000226 struct of_flash *info;
227 const char *probe_type = match->data;
Vitaly Woola2c2fe42006-12-06 13:17:49 +0300228 const u32 *width;
229 int err;
Stefan Roese143070e2009-04-16 14:10:45 +0200230 int i;
231 int count;
232 const u32 *p;
233 int reg_tuple_size;
234 struct mtd_info **mtd_list = NULL;
Wolfram Sang2763c502009-07-17 17:54:14 +0200235 resource_size_t res_size;
Vitaly Woola2c2fe42006-12-06 13:17:49 +0300236
Stefan Roese143070e2009-04-16 14:10:45 +0200237 reg_tuple_size = (of_n_addr_cells(dp) + of_n_size_cells(dp)) * sizeof(u32);
238
239 /*
240 * Get number of "reg" tuples. Scan for MTD devices on area's
241 * described by each "reg" region. This makes it possible (including
242 * the concat support) to support the Intel P30 48F4400 chips which
243 * consists internally of 2 non-identical NOR chips on one die.
244 */
245 p = of_get_property(dp, "reg", &count);
246 if (count % reg_tuple_size != 0) {
247 dev_err(&dev->dev, "Malformed reg property on %s\n",
Grant Likely61c7a082010-04-13 16:12:29 -0700248 dev->dev.of_node->full_name);
Stefan Roese143070e2009-04-16 14:10:45 +0200249 err = -EINVAL;
vimal singhad4fbc72009-07-30 20:54:27 +0530250 goto err_flash_remove;
Vitaly Woola2c2fe42006-12-06 13:17:49 +0300251 }
Stefan Roese143070e2009-04-16 14:10:45 +0200252 count /= reg_tuple_size;
Vitaly Woola2c2fe42006-12-06 13:17:49 +0300253
David Gibsonc4d5e372007-09-20 11:22:25 +1000254 err = -ENOMEM;
Stefan Roese143070e2009-04-16 14:10:45 +0200255 info = kzalloc(sizeof(struct of_flash) +
256 sizeof(struct of_flash_list) * count, GFP_KERNEL);
257 if (!info)
vimal singhad4fbc72009-07-30 20:54:27 +0530258 goto err_flash_remove;
Vitaly Woola2c2fe42006-12-06 13:17:49 +0300259
260 dev_set_drvdata(&dev->dev, info);
261
Julia Lawalle0262552009-12-29 20:15:23 +0100262 mtd_list = kzalloc(sizeof(*mtd_list) * count, GFP_KERNEL);
vimal singhad4fbc72009-07-30 20:54:27 +0530263 if (!mtd_list)
264 goto err_flash_remove;
265
Stefan Roese143070e2009-04-16 14:10:45 +0200266 for (i = 0; i < count; i++) {
267 err = -ENXIO;
268 if (of_address_to_resource(dp, i, &res)) {
269 dev_err(&dev->dev, "Can't get IO address from device"
270 " tree\n");
271 goto err_out;
272 }
Vitaly Woola2c2fe42006-12-06 13:17:49 +0300273
Stefan Roese143070e2009-04-16 14:10:45 +0200274 dev_dbg(&dev->dev, "of_flash device: %.8llx-%.8llx\n",
275 (unsigned long long)res.start,
276 (unsigned long long)res.end);
277
278 err = -EBUSY;
Wolfram Sang2763c502009-07-17 17:54:14 +0200279 res_size = resource_size(&res);
280 info->list[i].res = request_mem_region(res.start, res_size,
Stefan Roese143070e2009-04-16 14:10:45 +0200281 dev_name(&dev->dev));
282 if (!info->list[i].res)
283 goto err_out;
284
285 err = -ENXIO;
286 width = of_get_property(dp, "bank-width", NULL);
287 if (!width) {
288 dev_err(&dev->dev, "Can't get bank width from device"
289 " tree\n");
290 goto err_out;
291 }
292
293 info->list[i].map.name = dev_name(&dev->dev);
294 info->list[i].map.phys = res.start;
Wolfram Sang2763c502009-07-17 17:54:14 +0200295 info->list[i].map.size = res_size;
Stefan Roese143070e2009-04-16 14:10:45 +0200296 info->list[i].map.bankwidth = *width;
297
298 err = -ENOMEM;
299 info->list[i].map.virt = ioremap(info->list[i].map.phys,
300 info->list[i].map.size);
301 if (!info->list[i].map.virt) {
302 dev_err(&dev->dev, "Failed to ioremap() flash"
303 " region\n");
304 goto err_out;
305 }
306
307 simple_map_init(&info->list[i].map);
308
309 if (probe_type) {
310 info->list[i].mtd = do_map_probe(probe_type,
311 &info->list[i].map);
312 } else {
313 info->list[i].mtd = obsolete_probe(dev,
314 &info->list[i].map);
315 }
316 mtd_list[i] = info->list[i].mtd;
317
318 err = -ENXIO;
319 if (!info->list[i].mtd) {
320 dev_err(&dev->dev, "do_map_probe() failed\n");
321 goto err_out;
322 } else {
323 info->list_size++;
324 }
325 info->list[i].mtd->owner = THIS_MODULE;
326 info->list[i].mtd->dev.parent = &dev->dev;
Vitaly Woola2c2fe42006-12-06 13:17:49 +0300327 }
328
Stefan Roese143070e2009-04-16 14:10:45 +0200329 err = 0;
330 if (info->list_size == 1) {
331 info->cmtd = info->list[0].mtd;
332 } else if (info->list_size > 1) {
333 /*
334 * We detected multiple devices. Concatenate them together.
335 */
336#ifdef CONFIG_MTD_CONCAT
337 info->cmtd = mtd_concat_create(mtd_list, info->list_size,
338 dev_name(&dev->dev));
339 if (info->cmtd == NULL)
340 err = -ENXIO;
341#else
342 printk(KERN_ERR "physmap_of: multiple devices "
343 "found but MTD concat support disabled.\n");
344 err = -ENXIO;
345#endif
Vitaly Woola2c2fe42006-12-06 13:17:49 +0300346 }
Stefan Roese143070e2009-04-16 14:10:45 +0200347 if (err)
Vitaly Woola2c2fe42006-12-06 13:17:49 +0300348 goto err_out;
Vitaly Woola2c2fe42006-12-06 13:17:49 +0300349
Scott Wood9a310d22008-01-15 17:54:43 -0600350#ifdef CONFIG_MTD_PARTITIONS
Jason Gunthorpe9d5da3a2010-03-09 12:27:56 -0700351 part_probe_types = of_get_probes(dp);
Stefan Roese143070e2009-04-16 14:10:45 +0200352 err = parse_mtd_partitions(info->cmtd, part_probe_types,
353 &info->parts, 0);
Jason Gunthorpe9d5da3a2010-03-09 12:27:56 -0700354 if (err < 0) {
355 of_free_probes(part_probe_types);
Scott Wood9a310d22008-01-15 17:54:43 -0600356 return err;
Jason Gunthorpe9d5da3a2010-03-09 12:27:56 -0700357 }
358 of_free_probes(part_probe_types);
Scott Wood9a310d22008-01-15 17:54:43 -0600359
360#ifdef CONFIG_MTD_OF_PARTS
361 if (err == 0) {
Sebastian Andrzej Siewior69fd3a82008-10-12 16:18:36 +0200362 err = of_mtd_parse_partitions(&dev->dev, dp, &info->parts);
Scott Wood9a310d22008-01-15 17:54:43 -0600363 if (err < 0)
364 return err;
365 }
366#endif
367
368 if (err == 0) {
369 err = parse_obsolete_partitions(dev, info, dp);
370 if (err < 0)
371 return err;
372 }
Vitaly Woola2c2fe42006-12-06 13:17:49 +0300373
David Gibsonc4d5e372007-09-20 11:22:25 +1000374 if (err > 0)
Stefan Roese143070e2009-04-16 14:10:45 +0200375 add_mtd_partitions(info->cmtd, info->parts, err);
David Gibsonc4d5e372007-09-20 11:22:25 +1000376 else
Scott Wood9a310d22008-01-15 17:54:43 -0600377#endif
Stefan Roese143070e2009-04-16 14:10:45 +0200378 add_mtd_device(info->cmtd);
379
380 kfree(mtd_list);
Vitaly Woola2c2fe42006-12-06 13:17:49 +0300381
Vitaly Woola2c2fe42006-12-06 13:17:49 +0300382 return 0;
383
384err_out:
Stefan Roese143070e2009-04-16 14:10:45 +0200385 kfree(mtd_list);
vimal singhad4fbc72009-07-30 20:54:27 +0530386err_flash_remove:
David Gibsonc4d5e372007-09-20 11:22:25 +1000387 of_flash_remove(dev);
Stefan Roese143070e2009-04-16 14:10:45 +0200388
Vitaly Woola2c2fe42006-12-06 13:17:49 +0300389 return err;
Vitaly Woola2c2fe42006-12-06 13:17:49 +0300390}
391
David Gibsonc4d5e372007-09-20 11:22:25 +1000392static struct of_device_id of_flash_match[] = {
Vitaly Woola2c2fe42006-12-06 13:17:49 +0300393 {
David Gibson20991722007-09-07 13:23:53 +1000394 .compatible = "cfi-flash",
395 .data = (void *)"cfi_probe",
396 },
397 {
398 /* FIXME: JEDEC chips can't be safely and reliably
399 * probed, although the mtd code gets it right in
400 * practice most of the time. We should use the
401 * vendor and device ids specified by the binding to
402 * bypass the heuristic probe code, but the mtd layer
403 * provides, at present, no interface for doing so
404 * :(. */
405 .compatible = "jedec-flash",
406 .data = (void *)"jedec_probe",
407 },
Vitaly Woola2c2fe42006-12-06 13:17:49 +0300408 {
Wolfram Sangfc28c39f2009-07-17 14:39:23 +0200409 .compatible = "mtd-ram",
410 .data = (void *)"map_ram",
411 },
412 {
Vitaly Woola2c2fe42006-12-06 13:17:49 +0300413 .type = "rom",
414 .compatible = "direct-mapped"
415 },
416 { },
417};
David Gibsonc4d5e372007-09-20 11:22:25 +1000418MODULE_DEVICE_TABLE(of, of_flash_match);
Vitaly Woola2c2fe42006-12-06 13:17:49 +0300419
David Gibsonc4d5e372007-09-20 11:22:25 +1000420static struct of_platform_driver of_flash_driver = {
Grant Likely40182942010-04-13 16:13:02 -0700421 .driver = {
422 .name = "of-flash",
423 .owner = THIS_MODULE,
424 .of_match_table = of_flash_match,
425 },
David Gibsonc4d5e372007-09-20 11:22:25 +1000426 .probe = of_flash_probe,
427 .remove = of_flash_remove,
Vitaly Woola2c2fe42006-12-06 13:17:49 +0300428};
429
David Gibsonc4d5e372007-09-20 11:22:25 +1000430static int __init of_flash_init(void)
Vitaly Woola2c2fe42006-12-06 13:17:49 +0300431{
David Gibsonc4d5e372007-09-20 11:22:25 +1000432 return of_register_platform_driver(&of_flash_driver);
Vitaly Woola2c2fe42006-12-06 13:17:49 +0300433}
434
David Gibsonc4d5e372007-09-20 11:22:25 +1000435static void __exit of_flash_exit(void)
Vitaly Woola2c2fe42006-12-06 13:17:49 +0300436{
David Gibsonc4d5e372007-09-20 11:22:25 +1000437 of_unregister_platform_driver(&of_flash_driver);
Vitaly Woola2c2fe42006-12-06 13:17:49 +0300438}
439
David Gibsonc4d5e372007-09-20 11:22:25 +1000440module_init(of_flash_init);
441module_exit(of_flash_exit);
Vitaly Woola2c2fe42006-12-06 13:17:49 +0300442
443MODULE_LICENSE("GPL");
444MODULE_AUTHOR("Vitaly Wool <vwool@ru.mvista.com>");
David Gibsonc4d5e372007-09-20 11:22:25 +1000445MODULE_DESCRIPTION("Device tree based MTD map driver");