blob: 6a75743f8ea5f81799a150eb9b34dbefe926ed37 [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>
Graeme Smecher7a50d062010-08-17 10:13:44 -070025#include <linux/of_address.h>
David Gibsonc4d5e372007-09-20 11:22:25 +100026#include <linux/of_platform.h>
Tejun Heo5a0e3ad2010-03-24 17:04:11 +090027#include <linux/slab.h>
Vitaly Woola2c2fe42006-12-06 13:17:49 +030028
Stefan Roese143070e2009-04-16 14:10:45 +020029struct of_flash_list {
30 struct mtd_info *mtd;
31 struct map_info map;
32 struct resource *res;
33};
34
David Gibsonc4d5e372007-09-20 11:22:25 +100035struct of_flash {
Stefan Roese143070e2009-04-16 14:10:45 +020036 struct mtd_info *cmtd;
Vitaly Woola2c2fe42006-12-06 13:17:49 +030037 struct mtd_partition *parts;
Stefan Roese143070e2009-04-16 14:10:45 +020038 int list_size; /* number of elements in of_flash_list */
39 struct of_flash_list list[0];
Vitaly Woola2c2fe42006-12-06 13:17:49 +030040};
41
David Gibsonc4d5e372007-09-20 11:22:25 +100042#define OF_FLASH_PARTS(info) ((info)->parts)
Grant Likely2dc11582010-08-06 09:25:50 -060043static int parse_obsolete_partitions(struct platform_device *dev,
David Gibsonc4d5e372007-09-20 11:22:25 +100044 struct of_flash *info,
David Gibson20991722007-09-07 13:23:53 +100045 struct device_node *dp)
Vitaly Woola2c2fe42006-12-06 13:17:49 +030046{
David Gibson20991722007-09-07 13:23:53 +100047 int i, plen, nr_parts;
48 const struct {
Ian Munsie766f2712010-10-01 17:06:08 +100049 __be32 offset, len;
David Gibson20991722007-09-07 13:23:53 +100050 } *part;
51 const char *names;
Vitaly Woola2c2fe42006-12-06 13:17:49 +030052
David Gibson20991722007-09-07 13:23:53 +100053 part = of_get_property(dp, "partitions", &plen);
54 if (!part)
David Gibsonc4d5e372007-09-20 11:22:25 +100055 return 0; /* No partitions found */
Vitaly Woola2c2fe42006-12-06 13:17:49 +030056
David Gibson20991722007-09-07 13:23:53 +100057 dev_warn(&dev->dev, "Device tree uses obsolete partition map binding\n");
Vitaly Woola2c2fe42006-12-06 13:17:49 +030058
David Gibson20991722007-09-07 13:23:53 +100059 nr_parts = plen / sizeof(part[0]);
Vitaly Woola2c2fe42006-12-06 13:17:49 +030060
David Gibsonc4d5e372007-09-20 11:22:25 +100061 info->parts = kzalloc(nr_parts * sizeof(*info->parts), GFP_KERNEL);
62 if (!info->parts)
David Gibson20991722007-09-07 13:23:53 +100063 return -ENOMEM;
Vitaly Woola2c2fe42006-12-06 13:17:49 +030064
David Gibson20991722007-09-07 13:23:53 +100065 names = of_get_property(dp, "partition-names", &plen);
Vitaly Woola2c2fe42006-12-06 13:17:49 +030066
David Gibson20991722007-09-07 13:23:53 +100067 for (i = 0; i < nr_parts; i++) {
Ian Munsie766f2712010-10-01 17:06:08 +100068 info->parts[i].offset = be32_to_cpu(part->offset);
69 info->parts[i].size = be32_to_cpu(part->len) & ~1;
70 if (be32_to_cpu(part->len) & 1) /* bit 0 set signifies read only partition */
David Gibson20991722007-09-07 13:23:53 +100071 info->parts[i].mask_flags = MTD_WRITEABLE;
Vitaly Woola2c2fe42006-12-06 13:17:49 +030072
David Gibson20991722007-09-07 13:23:53 +100073 if (names && (plen > 0)) {
74 int len = strlen(names) + 1;
Vitaly Woola2c2fe42006-12-06 13:17:49 +030075
David Gibson20991722007-09-07 13:23:53 +100076 info->parts[i].name = (char *)names;
Vitaly Woola2c2fe42006-12-06 13:17:49 +030077 plen -= len;
David Gibson20991722007-09-07 13:23:53 +100078 names += len;
79 } else {
80 info->parts[i].name = "unnamed";
81 }
Vitaly Woola2c2fe42006-12-06 13:17:49 +030082
David Gibson20991722007-09-07 13:23:53 +100083 part++;
Vitaly Woola2c2fe42006-12-06 13:17:49 +030084 }
David Gibson20991722007-09-07 13:23:53 +100085
86 return nr_parts;
Vitaly Woola2c2fe42006-12-06 13:17:49 +030087}
Vitaly Woola2c2fe42006-12-06 13:17:49 +030088
Grant Likely2dc11582010-08-06 09:25:50 -060089static int of_flash_remove(struct platform_device *dev)
Vitaly Woola2c2fe42006-12-06 13:17:49 +030090{
David Gibsonc4d5e372007-09-20 11:22:25 +100091 struct of_flash *info;
Stefan Roese143070e2009-04-16 14:10:45 +020092 int i;
Vitaly Woola2c2fe42006-12-06 13:17:49 +030093
94 info = dev_get_drvdata(&dev->dev);
David Gibsonc4d5e372007-09-20 11:22:25 +100095 if (!info)
Vitaly Woola2c2fe42006-12-06 13:17:49 +030096 return 0;
97 dev_set_drvdata(&dev->dev, NULL);
98
Stefan Roese143070e2009-04-16 14:10:45 +020099 if (info->cmtd != info->list[0].mtd) {
Jamie Iles984e6d82011-05-23 10:22:45 +0100100 mtd_device_unregister(info->cmtd);
Stefan Roese143070e2009-04-16 14:10:45 +0200101 mtd_concat_destroy(info->cmtd);
102 }
Stefan Roese143070e2009-04-16 14:10:45 +0200103
104 if (info->cmtd) {
Jamie Iles984e6d82011-05-23 10:22:45 +0100105 if (OF_FLASH_PARTS(info))
David Gibsonc4d5e372007-09-20 11:22:25 +1000106 kfree(OF_FLASH_PARTS(info));
Jamie Iles984e6d82011-05-23 10:22:45 +0100107 mtd_device_unregister(info->cmtd);
Vitaly Woola2c2fe42006-12-06 13:17:49 +0300108 }
109
Stefan Roese143070e2009-04-16 14:10:45 +0200110 for (i = 0; i < info->list_size; i++) {
111 if (info->list[i].mtd)
112 map_destroy(info->list[i].mtd);
Vitaly Woola2c2fe42006-12-06 13:17:49 +0300113
Stefan Roese143070e2009-04-16 14:10:45 +0200114 if (info->list[i].map.virt)
115 iounmap(info->list[i].map.virt);
116
117 if (info->list[i].res) {
118 release_resource(info->list[i].res);
119 kfree(info->list[i].res);
120 }
Vitaly Woola2c2fe42006-12-06 13:17:49 +0300121 }
122
Stefan Roese143070e2009-04-16 14:10:45 +0200123 kfree(info);
124
Vitaly Woola2c2fe42006-12-06 13:17:49 +0300125 return 0;
126}
127
David Gibson20991722007-09-07 13:23:53 +1000128/* Helper function to handle probing of the obsolete "direct-mapped"
129 * compatible binding, which has an extra "probe-type" property
130 * describing the type of flash probe necessary. */
Grant Likely2dc11582010-08-06 09:25:50 -0600131static struct mtd_info * __devinit obsolete_probe(struct platform_device *dev,
David Gibson20991722007-09-07 13:23:53 +1000132 struct map_info *map)
133{
Grant Likely61c7a082010-04-13 16:12:29 -0700134 struct device_node *dp = dev->dev.of_node;
David Gibson20991722007-09-07 13:23:53 +1000135 const char *of_probe;
136 struct mtd_info *mtd;
137 static const char *rom_probe_types[]
138 = { "cfi_probe", "jedec_probe", "map_rom"};
139 int i;
140
141 dev_warn(&dev->dev, "Device tree uses obsolete \"direct-mapped\" "
142 "flash binding\n");
143
144 of_probe = of_get_property(dp, "probe-type", NULL);
145 if (!of_probe) {
146 for (i = 0; i < ARRAY_SIZE(rom_probe_types); i++) {
147 mtd = do_map_probe(rom_probe_types[i], map);
148 if (mtd)
149 return mtd;
150 }
151 return NULL;
152 } else if (strcmp(of_probe, "CFI") == 0) {
153 return do_map_probe("cfi_probe", map);
154 } else if (strcmp(of_probe, "JEDEC") == 0) {
155 return do_map_probe("jedec_probe", map);
156 } else {
157 if (strcmp(of_probe, "ROM") != 0)
David Gibsonc4d5e372007-09-20 11:22:25 +1000158 dev_warn(&dev->dev, "obsolete_probe: don't know probe "
159 "type '%s', mapping as rom\n", of_probe);
David Gibson20991722007-09-07 13:23:53 +1000160 return do_map_probe("mtd_rom", map);
161 }
162}
163
Jason Gunthorpe9d5da3a2010-03-09 12:27:56 -0700164/* When partitions are set we look for a linux,part-probe property which
165 specifies the list of partition probers to use. If none is given then the
166 default is use. These take precedence over other device tree
167 information. */
Dmitry Eremin-Solenikov5f4ba9f2011-05-30 01:02:21 +0400168static const char *part_probe_types_def[] = { "cmdlinepart", "RedBoot",
169 "ofpart", NULL };
Jason Gunthorpe9d5da3a2010-03-09 12:27:56 -0700170static const char ** __devinit of_get_probes(struct device_node *dp)
171{
172 const char *cp;
173 int cplen;
174 unsigned int l;
175 unsigned int count;
176 const char **res;
177
178 cp = of_get_property(dp, "linux,part-probe", &cplen);
179 if (cp == NULL)
180 return part_probe_types_def;
181
182 count = 0;
183 for (l = 0; l != cplen; l++)
184 if (cp[l] == 0)
185 count++;
186
187 res = kzalloc((count + 1)*sizeof(*res), GFP_KERNEL);
188 count = 0;
189 while (cplen > 0) {
190 res[count] = cp;
191 l = strlen(cp) + 1;
192 cp += l;
193 cplen -= l;
194 count++;
195 }
196 return res;
197}
198
199static void __devinit of_free_probes(const char **probes)
200{
201 if (probes != part_probe_types_def)
202 kfree(probes);
203}
Jason Gunthorpe9d5da3a2010-03-09 12:27:56 -0700204
Grant Likelyb1608d62011-05-18 11:19:24 -0600205static struct of_device_id of_flash_match[];
Grant Likely1c48a5c2011-02-17 02:43:24 -0700206static int __devinit of_flash_probe(struct platform_device *dev)
Vitaly Woola2c2fe42006-12-06 13:17:49 +0300207{
Jason Gunthorpe9d5da3a2010-03-09 12:27:56 -0700208 const char **part_probe_types;
Grant Likelyb1608d62011-05-18 11:19:24 -0600209 const struct of_device_id *match;
Grant Likely61c7a082010-04-13 16:12:29 -0700210 struct device_node *dp = dev->dev.of_node;
Vitaly Woola2c2fe42006-12-06 13:17:49 +0300211 struct resource res;
David Gibsonc4d5e372007-09-20 11:22:25 +1000212 struct of_flash *info;
Grant Likely1c48a5c2011-02-17 02:43:24 -0700213 const char *probe_type;
Ian Munsie766f2712010-10-01 17:06:08 +1000214 const __be32 *width;
Vitaly Woola2c2fe42006-12-06 13:17:49 +0300215 int err;
Stefan Roese143070e2009-04-16 14:10:45 +0200216 int i;
217 int count;
Ian Munsie766f2712010-10-01 17:06:08 +1000218 const __be32 *p;
Stefan Roese143070e2009-04-16 14:10:45 +0200219 int reg_tuple_size;
220 struct mtd_info **mtd_list = NULL;
Wolfram Sang2763c502009-07-17 17:54:14 +0200221 resource_size_t res_size;
Dmitry Eremin-Solenikov5f4ba9f2011-05-30 01:02:21 +0400222 struct mtd_part_parser_data ppdata;
Vitaly Woola2c2fe42006-12-06 13:17:49 +0300223
Grant Likelyb1608d62011-05-18 11:19:24 -0600224 match = of_match_device(of_flash_match, &dev->dev);
225 if (!match)
Grant Likely1c48a5c2011-02-17 02:43:24 -0700226 return -EINVAL;
Grant Likelyb1608d62011-05-18 11:19:24 -0600227 probe_type = match->data;
Grant Likely1c48a5c2011-02-17 02:43:24 -0700228
Stefan Roese143070e2009-04-16 14:10:45 +0200229 reg_tuple_size = (of_n_addr_cells(dp) + of_n_size_cells(dp)) * sizeof(u32);
230
231 /*
232 * Get number of "reg" tuples. Scan for MTD devices on area's
233 * described by each "reg" region. This makes it possible (including
234 * the concat support) to support the Intel P30 48F4400 chips which
235 * consists internally of 2 non-identical NOR chips on one die.
236 */
237 p = of_get_property(dp, "reg", &count);
238 if (count % reg_tuple_size != 0) {
239 dev_err(&dev->dev, "Malformed reg property on %s\n",
Grant Likely61c7a082010-04-13 16:12:29 -0700240 dev->dev.of_node->full_name);
Stefan Roese143070e2009-04-16 14:10:45 +0200241 err = -EINVAL;
vimal singhad4fbc72009-07-30 20:54:27 +0530242 goto err_flash_remove;
Vitaly Woola2c2fe42006-12-06 13:17:49 +0300243 }
Stefan Roese143070e2009-04-16 14:10:45 +0200244 count /= reg_tuple_size;
Vitaly Woola2c2fe42006-12-06 13:17:49 +0300245
David Gibsonc4d5e372007-09-20 11:22:25 +1000246 err = -ENOMEM;
Stefan Roese143070e2009-04-16 14:10:45 +0200247 info = kzalloc(sizeof(struct of_flash) +
248 sizeof(struct of_flash_list) * count, GFP_KERNEL);
249 if (!info)
vimal singhad4fbc72009-07-30 20:54:27 +0530250 goto err_flash_remove;
Vitaly Woola2c2fe42006-12-06 13:17:49 +0300251
252 dev_set_drvdata(&dev->dev, info);
253
Julia Lawalle0262552009-12-29 20:15:23 +0100254 mtd_list = kzalloc(sizeof(*mtd_list) * count, GFP_KERNEL);
vimal singhad4fbc72009-07-30 20:54:27 +0530255 if (!mtd_list)
256 goto err_flash_remove;
257
Stefan Roese143070e2009-04-16 14:10:45 +0200258 for (i = 0; i < count; i++) {
259 err = -ENXIO;
260 if (of_address_to_resource(dp, i, &res)) {
Stefan Roese940fe282010-10-08 14:41:27 +0200261 /*
262 * Continue with next register tuple if this
263 * one is not mappable
264 */
265 continue;
Stefan Roese143070e2009-04-16 14:10:45 +0200266 }
Vitaly Woola2c2fe42006-12-06 13:17:49 +0300267
Joe Perchesf9a52792010-11-12 13:37:57 -0800268 dev_dbg(&dev->dev, "of_flash device: %pR\n", &res);
Stefan Roese143070e2009-04-16 14:10:45 +0200269
270 err = -EBUSY;
Wolfram Sang2763c502009-07-17 17:54:14 +0200271 res_size = resource_size(&res);
272 info->list[i].res = request_mem_region(res.start, res_size,
Stefan Roese143070e2009-04-16 14:10:45 +0200273 dev_name(&dev->dev));
274 if (!info->list[i].res)
275 goto err_out;
276
277 err = -ENXIO;
278 width = of_get_property(dp, "bank-width", NULL);
279 if (!width) {
280 dev_err(&dev->dev, "Can't get bank width from device"
281 " tree\n");
282 goto err_out;
283 }
284
285 info->list[i].map.name = dev_name(&dev->dev);
286 info->list[i].map.phys = res.start;
Wolfram Sang2763c502009-07-17 17:54:14 +0200287 info->list[i].map.size = res_size;
Ian Munsie766f2712010-10-01 17:06:08 +1000288 info->list[i].map.bankwidth = be32_to_cpup(width);
Stefan Roese143070e2009-04-16 14:10:45 +0200289
290 err = -ENOMEM;
291 info->list[i].map.virt = ioremap(info->list[i].map.phys,
292 info->list[i].map.size);
293 if (!info->list[i].map.virt) {
294 dev_err(&dev->dev, "Failed to ioremap() flash"
295 " region\n");
296 goto err_out;
297 }
298
299 simple_map_init(&info->list[i].map);
300
301 if (probe_type) {
302 info->list[i].mtd = do_map_probe(probe_type,
303 &info->list[i].map);
304 } else {
305 info->list[i].mtd = obsolete_probe(dev,
306 &info->list[i].map);
307 }
308 mtd_list[i] = info->list[i].mtd;
309
310 err = -ENXIO;
311 if (!info->list[i].mtd) {
312 dev_err(&dev->dev, "do_map_probe() failed\n");
313 goto err_out;
314 } else {
315 info->list_size++;
316 }
317 info->list[i].mtd->owner = THIS_MODULE;
318 info->list[i].mtd->dev.parent = &dev->dev;
Vitaly Woola2c2fe42006-12-06 13:17:49 +0300319 }
320
Stefan Roese143070e2009-04-16 14:10:45 +0200321 err = 0;
322 if (info->list_size == 1) {
323 info->cmtd = info->list[0].mtd;
324 } else if (info->list_size > 1) {
325 /*
326 * We detected multiple devices. Concatenate them together.
327 */
Stefan Roese143070e2009-04-16 14:10:45 +0200328 info->cmtd = mtd_concat_create(mtd_list, info->list_size,
329 dev_name(&dev->dev));
330 if (info->cmtd == NULL)
331 err = -ENXIO;
Vitaly Woola2c2fe42006-12-06 13:17:49 +0300332 }
Stefan Roese143070e2009-04-16 14:10:45 +0200333 if (err)
Vitaly Woola2c2fe42006-12-06 13:17:49 +0300334 goto err_out;
Vitaly Woola2c2fe42006-12-06 13:17:49 +0300335
Dmitry Eremin-Solenikov5f4ba9f2011-05-30 01:02:21 +0400336 ppdata.of_node = dp;
Jason Gunthorpe9d5da3a2010-03-09 12:27:56 -0700337 part_probe_types = of_get_probes(dp);
Stefan Roese143070e2009-04-16 14:10:45 +0200338 err = parse_mtd_partitions(info->cmtd, part_probe_types,
Dmitry Eremin-Solenikov5f4ba9f2011-05-30 01:02:21 +0400339 &info->parts, &ppdata);
Jason Gunthorpe9d5da3a2010-03-09 12:27:56 -0700340 if (err < 0) {
341 of_free_probes(part_probe_types);
Julia Lawall00b275d2010-06-01 16:34:20 +0200342 goto err_out;
Jason Gunthorpe9d5da3a2010-03-09 12:27:56 -0700343 }
344 of_free_probes(part_probe_types);
Scott Wood9a310d22008-01-15 17:54:43 -0600345
Scott Wood9a310d22008-01-15 17:54:43 -0600346 if (err == 0) {
Scott Wood9a310d22008-01-15 17:54:43 -0600347 err = parse_obsolete_partitions(dev, info, dp);
348 if (err < 0)
Julia Lawall00b275d2010-06-01 16:34:20 +0200349 goto err_out;
Scott Wood9a310d22008-01-15 17:54:43 -0600350 }
Vitaly Woola2c2fe42006-12-06 13:17:49 +0300351
Jamie Iles984e6d82011-05-23 10:22:45 +0100352 mtd_device_register(info->cmtd, info->parts, err);
Stefan Roese143070e2009-04-16 14:10:45 +0200353
354 kfree(mtd_list);
Vitaly Woola2c2fe42006-12-06 13:17:49 +0300355
Vitaly Woola2c2fe42006-12-06 13:17:49 +0300356 return 0;
357
358err_out:
Stefan Roese143070e2009-04-16 14:10:45 +0200359 kfree(mtd_list);
vimal singhad4fbc72009-07-30 20:54:27 +0530360err_flash_remove:
David Gibsonc4d5e372007-09-20 11:22:25 +1000361 of_flash_remove(dev);
Stefan Roese143070e2009-04-16 14:10:45 +0200362
Vitaly Woola2c2fe42006-12-06 13:17:49 +0300363 return err;
Vitaly Woola2c2fe42006-12-06 13:17:49 +0300364}
365
David Gibsonc4d5e372007-09-20 11:22:25 +1000366static struct of_device_id of_flash_match[] = {
Vitaly Woola2c2fe42006-12-06 13:17:49 +0300367 {
David Gibson20991722007-09-07 13:23:53 +1000368 .compatible = "cfi-flash",
369 .data = (void *)"cfi_probe",
370 },
371 {
372 /* FIXME: JEDEC chips can't be safely and reliably
373 * probed, although the mtd code gets it right in
374 * practice most of the time. We should use the
375 * vendor and device ids specified by the binding to
376 * bypass the heuristic probe code, but the mtd layer
377 * provides, at present, no interface for doing so
378 * :(. */
379 .compatible = "jedec-flash",
380 .data = (void *)"jedec_probe",
381 },
Vitaly Woola2c2fe42006-12-06 13:17:49 +0300382 {
Wolfram Sangfc28c39f2009-07-17 14:39:23 +0200383 .compatible = "mtd-ram",
384 .data = (void *)"map_ram",
385 },
386 {
Vitaly Woola2c2fe42006-12-06 13:17:49 +0300387 .type = "rom",
388 .compatible = "direct-mapped"
389 },
390 { },
391};
David Gibsonc4d5e372007-09-20 11:22:25 +1000392MODULE_DEVICE_TABLE(of, of_flash_match);
Vitaly Woola2c2fe42006-12-06 13:17:49 +0300393
Grant Likely1c48a5c2011-02-17 02:43:24 -0700394static struct platform_driver of_flash_driver = {
Grant Likely40182942010-04-13 16:13:02 -0700395 .driver = {
396 .name = "of-flash",
397 .owner = THIS_MODULE,
398 .of_match_table = of_flash_match,
399 },
David Gibsonc4d5e372007-09-20 11:22:25 +1000400 .probe = of_flash_probe,
401 .remove = of_flash_remove,
Vitaly Woola2c2fe42006-12-06 13:17:49 +0300402};
403
David Gibsonc4d5e372007-09-20 11:22:25 +1000404static int __init of_flash_init(void)
Vitaly Woola2c2fe42006-12-06 13:17:49 +0300405{
Grant Likely1c48a5c2011-02-17 02:43:24 -0700406 return platform_driver_register(&of_flash_driver);
Vitaly Woola2c2fe42006-12-06 13:17:49 +0300407}
408
David Gibsonc4d5e372007-09-20 11:22:25 +1000409static void __exit of_flash_exit(void)
Vitaly Woola2c2fe42006-12-06 13:17:49 +0300410{
Grant Likely1c48a5c2011-02-17 02:43:24 -0700411 platform_driver_unregister(&of_flash_driver);
Vitaly Woola2c2fe42006-12-06 13:17:49 +0300412}
413
David Gibsonc4d5e372007-09-20 11:22:25 +1000414module_init(of_flash_init);
415module_exit(of_flash_exit);
Vitaly Woola2c2fe42006-12-06 13:17:49 +0300416
417MODULE_LICENSE("GPL");
418MODULE_AUTHOR("Vitaly Wool <vwool@ru.mvista.com>");
David Gibsonc4d5e372007-09-20 11:22:25 +1000419MODULE_DESCRIPTION("Device tree based MTD map driver");