blob: c1d33464aee8926e66afcccc23dbbbacdb718ba8 [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#ifdef CONFIG_MTD_PARTITIONS
Vitaly Woola2c2fe42006-12-06 13:17:49 +030038 struct mtd_partition *parts;
39#endif
Stefan Roese143070e2009-04-16 14:10:45 +020040 int list_size; /* number of elements in of_flash_list */
41 struct of_flash_list list[0];
Vitaly Woola2c2fe42006-12-06 13:17:49 +030042};
43
Vitaly Woola2c2fe42006-12-06 13:17:49 +030044#ifdef CONFIG_MTD_PARTITIONS
David Gibsonc4d5e372007-09-20 11:22:25 +100045#define OF_FLASH_PARTS(info) ((info)->parts)
Vitaly Woola2c2fe42006-12-06 13:17:49 +030046
Grant Likely2dc11582010-08-06 09:25:50 -060047static int parse_obsolete_partitions(struct platform_device *dev,
David Gibsonc4d5e372007-09-20 11:22:25 +100048 struct of_flash *info,
David Gibson20991722007-09-07 13:23:53 +100049 struct device_node *dp)
Vitaly Woola2c2fe42006-12-06 13:17:49 +030050{
David Gibson20991722007-09-07 13:23:53 +100051 int i, plen, nr_parts;
52 const struct {
Ian Munsie766f2712010-10-01 17:06:08 +100053 __be32 offset, len;
David Gibson20991722007-09-07 13:23:53 +100054 } *part;
55 const char *names;
Vitaly Woola2c2fe42006-12-06 13:17:49 +030056
David Gibson20991722007-09-07 13:23:53 +100057 part = of_get_property(dp, "partitions", &plen);
58 if (!part)
David Gibsonc4d5e372007-09-20 11:22:25 +100059 return 0; /* No partitions found */
Vitaly Woola2c2fe42006-12-06 13:17:49 +030060
David Gibson20991722007-09-07 13:23:53 +100061 dev_warn(&dev->dev, "Device tree uses obsolete partition map binding\n");
Vitaly Woola2c2fe42006-12-06 13:17:49 +030062
David Gibson20991722007-09-07 13:23:53 +100063 nr_parts = plen / sizeof(part[0]);
Vitaly Woola2c2fe42006-12-06 13:17:49 +030064
David Gibsonc4d5e372007-09-20 11:22:25 +100065 info->parts = kzalloc(nr_parts * sizeof(*info->parts), GFP_KERNEL);
66 if (!info->parts)
David Gibson20991722007-09-07 13:23:53 +100067 return -ENOMEM;
Vitaly Woola2c2fe42006-12-06 13:17:49 +030068
David Gibson20991722007-09-07 13:23:53 +100069 names = of_get_property(dp, "partition-names", &plen);
Vitaly Woola2c2fe42006-12-06 13:17:49 +030070
David Gibson20991722007-09-07 13:23:53 +100071 for (i = 0; i < nr_parts; i++) {
Ian Munsie766f2712010-10-01 17:06:08 +100072 info->parts[i].offset = be32_to_cpu(part->offset);
73 info->parts[i].size = be32_to_cpu(part->len) & ~1;
74 if (be32_to_cpu(part->len) & 1) /* bit 0 set signifies read only partition */
David Gibson20991722007-09-07 13:23:53 +100075 info->parts[i].mask_flags = MTD_WRITEABLE;
Vitaly Woola2c2fe42006-12-06 13:17:49 +030076
David Gibson20991722007-09-07 13:23:53 +100077 if (names && (plen > 0)) {
78 int len = strlen(names) + 1;
Vitaly Woola2c2fe42006-12-06 13:17:49 +030079
David Gibson20991722007-09-07 13:23:53 +100080 info->parts[i].name = (char *)names;
Vitaly Woola2c2fe42006-12-06 13:17:49 +030081 plen -= len;
David Gibson20991722007-09-07 13:23:53 +100082 names += len;
83 } else {
84 info->parts[i].name = "unnamed";
85 }
Vitaly Woola2c2fe42006-12-06 13:17:49 +030086
David Gibson20991722007-09-07 13:23:53 +100087 part++;
Vitaly Woola2c2fe42006-12-06 13:17:49 +030088 }
David Gibson20991722007-09-07 13:23:53 +100089
90 return nr_parts;
Vitaly Woola2c2fe42006-12-06 13:17:49 +030091}
David Gibson20991722007-09-07 13:23:53 +100092#else /* MTD_PARTITIONS */
David Gibsonc4d5e372007-09-20 11:22:25 +100093#define OF_FLASH_PARTS(info) (0)
94#define parse_partitions(info, dev) (0)
David Gibson20991722007-09-07 13:23:53 +100095#endif /* MTD_PARTITIONS */
Vitaly Woola2c2fe42006-12-06 13:17:49 +030096
Grant Likely2dc11582010-08-06 09:25:50 -060097static int of_flash_remove(struct platform_device *dev)
Vitaly Woola2c2fe42006-12-06 13:17:49 +030098{
David Gibsonc4d5e372007-09-20 11:22:25 +100099 struct of_flash *info;
Stefan Roese143070e2009-04-16 14:10:45 +0200100 int i;
Vitaly Woola2c2fe42006-12-06 13:17:49 +0300101
102 info = dev_get_drvdata(&dev->dev);
David Gibsonc4d5e372007-09-20 11:22:25 +1000103 if (!info)
Vitaly Woola2c2fe42006-12-06 13:17:49 +0300104 return 0;
105 dev_set_drvdata(&dev->dev, NULL);
106
Stefan Roese143070e2009-04-16 14:10:45 +0200107 if (info->cmtd != info->list[0].mtd) {
108 del_mtd_device(info->cmtd);
109 mtd_concat_destroy(info->cmtd);
110 }
Stefan Roese143070e2009-04-16 14:10:45 +0200111
112 if (info->cmtd) {
David Gibsonc4d5e372007-09-20 11:22:25 +1000113 if (OF_FLASH_PARTS(info)) {
Stefan Roese143070e2009-04-16 14:10:45 +0200114 del_mtd_partitions(info->cmtd);
David Gibsonc4d5e372007-09-20 11:22:25 +1000115 kfree(OF_FLASH_PARTS(info));
Vitaly Woola2c2fe42006-12-06 13:17:49 +0300116 } else {
Stefan Roese143070e2009-04-16 14:10:45 +0200117 del_mtd_device(info->cmtd);
Vitaly Woola2c2fe42006-12-06 13:17:49 +0300118 }
Vitaly Woola2c2fe42006-12-06 13:17:49 +0300119 }
120
Stefan Roese143070e2009-04-16 14:10:45 +0200121 for (i = 0; i < info->list_size; i++) {
122 if (info->list[i].mtd)
123 map_destroy(info->list[i].mtd);
Vitaly Woola2c2fe42006-12-06 13:17:49 +0300124
Stefan Roese143070e2009-04-16 14:10:45 +0200125 if (info->list[i].map.virt)
126 iounmap(info->list[i].map.virt);
127
128 if (info->list[i].res) {
129 release_resource(info->list[i].res);
130 kfree(info->list[i].res);
131 }
Vitaly Woola2c2fe42006-12-06 13:17:49 +0300132 }
133
Stefan Roese143070e2009-04-16 14:10:45 +0200134 kfree(info);
135
Vitaly Woola2c2fe42006-12-06 13:17:49 +0300136 return 0;
137}
138
David Gibson20991722007-09-07 13:23:53 +1000139/* Helper function to handle probing of the obsolete "direct-mapped"
140 * compatible binding, which has an extra "probe-type" property
141 * describing the type of flash probe necessary. */
Grant Likely2dc11582010-08-06 09:25:50 -0600142static struct mtd_info * __devinit obsolete_probe(struct platform_device *dev,
David Gibson20991722007-09-07 13:23:53 +1000143 struct map_info *map)
144{
Grant Likely61c7a082010-04-13 16:12:29 -0700145 struct device_node *dp = dev->dev.of_node;
David Gibson20991722007-09-07 13:23:53 +1000146 const char *of_probe;
147 struct mtd_info *mtd;
148 static const char *rom_probe_types[]
149 = { "cfi_probe", "jedec_probe", "map_rom"};
150 int i;
151
152 dev_warn(&dev->dev, "Device tree uses obsolete \"direct-mapped\" "
153 "flash binding\n");
154
155 of_probe = of_get_property(dp, "probe-type", NULL);
156 if (!of_probe) {
157 for (i = 0; i < ARRAY_SIZE(rom_probe_types); i++) {
158 mtd = do_map_probe(rom_probe_types[i], map);
159 if (mtd)
160 return mtd;
161 }
162 return NULL;
163 } else if (strcmp(of_probe, "CFI") == 0) {
164 return do_map_probe("cfi_probe", map);
165 } else if (strcmp(of_probe, "JEDEC") == 0) {
166 return do_map_probe("jedec_probe", map);
167 } else {
168 if (strcmp(of_probe, "ROM") != 0)
David Gibsonc4d5e372007-09-20 11:22:25 +1000169 dev_warn(&dev->dev, "obsolete_probe: don't know probe "
170 "type '%s', mapping as rom\n", of_probe);
David Gibson20991722007-09-07 13:23:53 +1000171 return do_map_probe("mtd_rom", map);
172 }
173}
174
Jason Gunthorpe9d5da3a2010-03-09 12:27:56 -0700175#ifdef CONFIG_MTD_PARTITIONS
176/* When partitions are set we look for a linux,part-probe property which
177 specifies the list of partition probers to use. If none is given then the
178 default is use. These take precedence over other device tree
179 information. */
180static const char *part_probe_types_def[] = { "cmdlinepart", "RedBoot", NULL };
181static const char ** __devinit of_get_probes(struct device_node *dp)
182{
183 const char *cp;
184 int cplen;
185 unsigned int l;
186 unsigned int count;
187 const char **res;
188
189 cp = of_get_property(dp, "linux,part-probe", &cplen);
190 if (cp == NULL)
191 return part_probe_types_def;
192
193 count = 0;
194 for (l = 0; l != cplen; l++)
195 if (cp[l] == 0)
196 count++;
197
198 res = kzalloc((count + 1)*sizeof(*res), GFP_KERNEL);
199 count = 0;
200 while (cplen > 0) {
201 res[count] = cp;
202 l = strlen(cp) + 1;
203 cp += l;
204 cplen -= l;
205 count++;
206 }
207 return res;
208}
209
210static void __devinit of_free_probes(const char **probes)
211{
212 if (probes != part_probe_types_def)
213 kfree(probes);
214}
215#endif
216
Grant Likelyb1608d62011-05-18 11:19:24 -0600217static struct of_device_id of_flash_match[];
Grant Likely1c48a5c2011-02-17 02:43:24 -0700218static int __devinit of_flash_probe(struct platform_device *dev)
Vitaly Woola2c2fe42006-12-06 13:17:49 +0300219{
Scott Wood9a310d22008-01-15 17:54:43 -0600220#ifdef CONFIG_MTD_PARTITIONS
Jason Gunthorpe9d5da3a2010-03-09 12:27:56 -0700221 const char **part_probe_types;
Scott Wood9a310d22008-01-15 17:54:43 -0600222#endif
Grant Likelyb1608d62011-05-18 11:19:24 -0600223 const struct of_device_id *match;
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;
Grant Likely1c48a5c2011-02-17 02:43:24 -0700227 const char *probe_type;
Ian Munsie766f2712010-10-01 17:06:08 +1000228 const __be32 *width;
Vitaly Woola2c2fe42006-12-06 13:17:49 +0300229 int err;
Stefan Roese143070e2009-04-16 14:10:45 +0200230 int i;
231 int count;
Ian Munsie766f2712010-10-01 17:06:08 +1000232 const __be32 *p;
Stefan Roese143070e2009-04-16 14:10:45 +0200233 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
Grant Likelyb1608d62011-05-18 11:19:24 -0600237 match = of_match_device(of_flash_match, &dev->dev);
238 if (!match)
Grant Likely1c48a5c2011-02-17 02:43:24 -0700239 return -EINVAL;
Grant Likelyb1608d62011-05-18 11:19:24 -0600240 probe_type = match->data;
Grant Likely1c48a5c2011-02-17 02:43:24 -0700241
Stefan Roese143070e2009-04-16 14:10:45 +0200242 reg_tuple_size = (of_n_addr_cells(dp) + of_n_size_cells(dp)) * sizeof(u32);
243
244 /*
245 * Get number of "reg" tuples. Scan for MTD devices on area's
246 * described by each "reg" region. This makes it possible (including
247 * the concat support) to support the Intel P30 48F4400 chips which
248 * consists internally of 2 non-identical NOR chips on one die.
249 */
250 p = of_get_property(dp, "reg", &count);
251 if (count % reg_tuple_size != 0) {
252 dev_err(&dev->dev, "Malformed reg property on %s\n",
Grant Likely61c7a082010-04-13 16:12:29 -0700253 dev->dev.of_node->full_name);
Stefan Roese143070e2009-04-16 14:10:45 +0200254 err = -EINVAL;
vimal singhad4fbc72009-07-30 20:54:27 +0530255 goto err_flash_remove;
Vitaly Woola2c2fe42006-12-06 13:17:49 +0300256 }
Stefan Roese143070e2009-04-16 14:10:45 +0200257 count /= reg_tuple_size;
Vitaly Woola2c2fe42006-12-06 13:17:49 +0300258
David Gibsonc4d5e372007-09-20 11:22:25 +1000259 err = -ENOMEM;
Stefan Roese143070e2009-04-16 14:10:45 +0200260 info = kzalloc(sizeof(struct of_flash) +
261 sizeof(struct of_flash_list) * count, GFP_KERNEL);
262 if (!info)
vimal singhad4fbc72009-07-30 20:54:27 +0530263 goto err_flash_remove;
Vitaly Woola2c2fe42006-12-06 13:17:49 +0300264
265 dev_set_drvdata(&dev->dev, info);
266
Julia Lawalle0262552009-12-29 20:15:23 +0100267 mtd_list = kzalloc(sizeof(*mtd_list) * count, GFP_KERNEL);
vimal singhad4fbc72009-07-30 20:54:27 +0530268 if (!mtd_list)
269 goto err_flash_remove;
270
Stefan Roese143070e2009-04-16 14:10:45 +0200271 for (i = 0; i < count; i++) {
272 err = -ENXIO;
273 if (of_address_to_resource(dp, i, &res)) {
Stefan Roese940fe282010-10-08 14:41:27 +0200274 /*
275 * Continue with next register tuple if this
276 * one is not mappable
277 */
278 continue;
Stefan Roese143070e2009-04-16 14:10:45 +0200279 }
Vitaly Woola2c2fe42006-12-06 13:17:49 +0300280
Joe Perchesf9a52792010-11-12 13:37:57 -0800281 dev_dbg(&dev->dev, "of_flash device: %pR\n", &res);
Stefan Roese143070e2009-04-16 14:10:45 +0200282
283 err = -EBUSY;
Wolfram Sang2763c502009-07-17 17:54:14 +0200284 res_size = resource_size(&res);
285 info->list[i].res = request_mem_region(res.start, res_size,
Stefan Roese143070e2009-04-16 14:10:45 +0200286 dev_name(&dev->dev));
287 if (!info->list[i].res)
288 goto err_out;
289
290 err = -ENXIO;
291 width = of_get_property(dp, "bank-width", NULL);
292 if (!width) {
293 dev_err(&dev->dev, "Can't get bank width from device"
294 " tree\n");
295 goto err_out;
296 }
297
298 info->list[i].map.name = dev_name(&dev->dev);
299 info->list[i].map.phys = res.start;
Wolfram Sang2763c502009-07-17 17:54:14 +0200300 info->list[i].map.size = res_size;
Ian Munsie766f2712010-10-01 17:06:08 +1000301 info->list[i].map.bankwidth = be32_to_cpup(width);
Stefan Roese143070e2009-04-16 14:10:45 +0200302
303 err = -ENOMEM;
304 info->list[i].map.virt = ioremap(info->list[i].map.phys,
305 info->list[i].map.size);
306 if (!info->list[i].map.virt) {
307 dev_err(&dev->dev, "Failed to ioremap() flash"
308 " region\n");
309 goto err_out;
310 }
311
312 simple_map_init(&info->list[i].map);
313
314 if (probe_type) {
315 info->list[i].mtd = do_map_probe(probe_type,
316 &info->list[i].map);
317 } else {
318 info->list[i].mtd = obsolete_probe(dev,
319 &info->list[i].map);
320 }
321 mtd_list[i] = info->list[i].mtd;
322
323 err = -ENXIO;
324 if (!info->list[i].mtd) {
325 dev_err(&dev->dev, "do_map_probe() failed\n");
326 goto err_out;
327 } else {
328 info->list_size++;
329 }
330 info->list[i].mtd->owner = THIS_MODULE;
331 info->list[i].mtd->dev.parent = &dev->dev;
Vitaly Woola2c2fe42006-12-06 13:17:49 +0300332 }
333
Stefan Roese143070e2009-04-16 14:10:45 +0200334 err = 0;
335 if (info->list_size == 1) {
336 info->cmtd = info->list[0].mtd;
337 } else if (info->list_size > 1) {
338 /*
339 * We detected multiple devices. Concatenate them together.
340 */
Stefan Roese143070e2009-04-16 14:10:45 +0200341 info->cmtd = mtd_concat_create(mtd_list, info->list_size,
342 dev_name(&dev->dev));
343 if (info->cmtd == NULL)
344 err = -ENXIO;
Vitaly Woola2c2fe42006-12-06 13:17:49 +0300345 }
Stefan Roese143070e2009-04-16 14:10:45 +0200346 if (err)
Vitaly Woola2c2fe42006-12-06 13:17:49 +0300347 goto err_out;
Vitaly Woola2c2fe42006-12-06 13:17:49 +0300348
Scott Wood9a310d22008-01-15 17:54:43 -0600349#ifdef CONFIG_MTD_PARTITIONS
Jason Gunthorpe9d5da3a2010-03-09 12:27:56 -0700350 part_probe_types = of_get_probes(dp);
Stefan Roese143070e2009-04-16 14:10:45 +0200351 err = parse_mtd_partitions(info->cmtd, part_probe_types,
352 &info->parts, 0);
Jason Gunthorpe9d5da3a2010-03-09 12:27:56 -0700353 if (err < 0) {
354 of_free_probes(part_probe_types);
Julia Lawall00b275d2010-06-01 16:34:20 +0200355 goto err_out;
Jason Gunthorpe9d5da3a2010-03-09 12:27:56 -0700356 }
357 of_free_probes(part_probe_types);
Scott Wood9a310d22008-01-15 17:54:43 -0600358
359#ifdef CONFIG_MTD_OF_PARTS
360 if (err == 0) {
Sebastian Andrzej Siewior69fd3a82008-10-12 16:18:36 +0200361 err = of_mtd_parse_partitions(&dev->dev, dp, &info->parts);
Scott Wood9a310d22008-01-15 17:54:43 -0600362 if (err < 0)
Julia Lawall00b275d2010-06-01 16:34:20 +0200363 goto err_out;
Scott Wood9a310d22008-01-15 17:54:43 -0600364 }
365#endif
366
367 if (err == 0) {
368 err = parse_obsolete_partitions(dev, info, dp);
369 if (err < 0)
Julia Lawall00b275d2010-06-01 16:34:20 +0200370 goto err_out;
Scott Wood9a310d22008-01-15 17:54:43 -0600371 }
Vitaly Woola2c2fe42006-12-06 13:17:49 +0300372
David Gibsonc4d5e372007-09-20 11:22:25 +1000373 if (err > 0)
Stefan Roese143070e2009-04-16 14:10:45 +0200374 add_mtd_partitions(info->cmtd, info->parts, err);
David Gibsonc4d5e372007-09-20 11:22:25 +1000375 else
Scott Wood9a310d22008-01-15 17:54:43 -0600376#endif
Stefan Roese143070e2009-04-16 14:10:45 +0200377 add_mtd_device(info->cmtd);
378
379 kfree(mtd_list);
Vitaly Woola2c2fe42006-12-06 13:17:49 +0300380
Vitaly Woola2c2fe42006-12-06 13:17:49 +0300381 return 0;
382
383err_out:
Stefan Roese143070e2009-04-16 14:10:45 +0200384 kfree(mtd_list);
vimal singhad4fbc72009-07-30 20:54:27 +0530385err_flash_remove:
David Gibsonc4d5e372007-09-20 11:22:25 +1000386 of_flash_remove(dev);
Stefan Roese143070e2009-04-16 14:10:45 +0200387
Vitaly Woola2c2fe42006-12-06 13:17:49 +0300388 return err;
Vitaly Woola2c2fe42006-12-06 13:17:49 +0300389}
390
David Gibsonc4d5e372007-09-20 11:22:25 +1000391static struct of_device_id of_flash_match[] = {
Vitaly Woola2c2fe42006-12-06 13:17:49 +0300392 {
David Gibson20991722007-09-07 13:23:53 +1000393 .compatible = "cfi-flash",
394 .data = (void *)"cfi_probe",
395 },
396 {
397 /* FIXME: JEDEC chips can't be safely and reliably
398 * probed, although the mtd code gets it right in
399 * practice most of the time. We should use the
400 * vendor and device ids specified by the binding to
401 * bypass the heuristic probe code, but the mtd layer
402 * provides, at present, no interface for doing so
403 * :(. */
404 .compatible = "jedec-flash",
405 .data = (void *)"jedec_probe",
406 },
Vitaly Woola2c2fe42006-12-06 13:17:49 +0300407 {
Wolfram Sangfc28c39f2009-07-17 14:39:23 +0200408 .compatible = "mtd-ram",
409 .data = (void *)"map_ram",
410 },
411 {
Vitaly Woola2c2fe42006-12-06 13:17:49 +0300412 .type = "rom",
413 .compatible = "direct-mapped"
414 },
415 { },
416};
David Gibsonc4d5e372007-09-20 11:22:25 +1000417MODULE_DEVICE_TABLE(of, of_flash_match);
Vitaly Woola2c2fe42006-12-06 13:17:49 +0300418
Grant Likely1c48a5c2011-02-17 02:43:24 -0700419static struct platform_driver of_flash_driver = {
Grant Likely40182942010-04-13 16:13:02 -0700420 .driver = {
421 .name = "of-flash",
422 .owner = THIS_MODULE,
423 .of_match_table = of_flash_match,
424 },
David Gibsonc4d5e372007-09-20 11:22:25 +1000425 .probe = of_flash_probe,
426 .remove = of_flash_remove,
Vitaly Woola2c2fe42006-12-06 13:17:49 +0300427};
428
David Gibsonc4d5e372007-09-20 11:22:25 +1000429static int __init of_flash_init(void)
Vitaly Woola2c2fe42006-12-06 13:17:49 +0300430{
Grant Likely1c48a5c2011-02-17 02:43:24 -0700431 return platform_driver_register(&of_flash_driver);
Vitaly Woola2c2fe42006-12-06 13:17:49 +0300432}
433
David Gibsonc4d5e372007-09-20 11:22:25 +1000434static void __exit of_flash_exit(void)
Vitaly Woola2c2fe42006-12-06 13:17:49 +0300435{
Grant Likely1c48a5c2011-02-17 02:43:24 -0700436 platform_driver_unregister(&of_flash_driver);
Vitaly Woola2c2fe42006-12-06 13:17:49 +0300437}
438
David Gibsonc4d5e372007-09-20 11:22:25 +1000439module_init(of_flash_init);
440module_exit(of_flash_exit);
Vitaly Woola2c2fe42006-12-06 13:17:49 +0300441
442MODULE_LICENSE("GPL");
443MODULE_AUTHOR("Vitaly Wool <vwool@ru.mvista.com>");
David Gibsonc4d5e372007-09-20 11:22:25 +1000444MODULE_DESCRIPTION("Device tree based MTD map driver");