blob: 3db0cb083d312207f0ca3dd9446a448ddcc4399c [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#ifdef CONFIG_MTD_CONCAT
108 if (info->cmtd != info->list[0].mtd) {
109 del_mtd_device(info->cmtd);
110 mtd_concat_destroy(info->cmtd);
111 }
112#endif
113
114 if (info->cmtd) {
David Gibsonc4d5e372007-09-20 11:22:25 +1000115 if (OF_FLASH_PARTS(info)) {
Stefan Roese143070e2009-04-16 14:10:45 +0200116 del_mtd_partitions(info->cmtd);
David Gibsonc4d5e372007-09-20 11:22:25 +1000117 kfree(OF_FLASH_PARTS(info));
Vitaly Woola2c2fe42006-12-06 13:17:49 +0300118 } else {
Stefan Roese143070e2009-04-16 14:10:45 +0200119 del_mtd_device(info->cmtd);
Vitaly Woola2c2fe42006-12-06 13:17:49 +0300120 }
Vitaly Woola2c2fe42006-12-06 13:17:49 +0300121 }
122
Stefan Roese143070e2009-04-16 14:10:45 +0200123 for (i = 0; i < info->list_size; i++) {
124 if (info->list[i].mtd)
125 map_destroy(info->list[i].mtd);
Vitaly Woola2c2fe42006-12-06 13:17:49 +0300126
Stefan Roese143070e2009-04-16 14:10:45 +0200127 if (info->list[i].map.virt)
128 iounmap(info->list[i].map.virt);
129
130 if (info->list[i].res) {
131 release_resource(info->list[i].res);
132 kfree(info->list[i].res);
133 }
Vitaly Woola2c2fe42006-12-06 13:17:49 +0300134 }
135
Stefan Roese143070e2009-04-16 14:10:45 +0200136 kfree(info);
137
Vitaly Woola2c2fe42006-12-06 13:17:49 +0300138 return 0;
139}
140
David Gibson20991722007-09-07 13:23:53 +1000141/* Helper function to handle probing of the obsolete "direct-mapped"
142 * compatible binding, which has an extra "probe-type" property
143 * describing the type of flash probe necessary. */
Grant Likely2dc11582010-08-06 09:25:50 -0600144static struct mtd_info * __devinit obsolete_probe(struct platform_device *dev,
David Gibson20991722007-09-07 13:23:53 +1000145 struct map_info *map)
146{
Grant Likely61c7a082010-04-13 16:12:29 -0700147 struct device_node *dp = dev->dev.of_node;
David Gibson20991722007-09-07 13:23:53 +1000148 const char *of_probe;
149 struct mtd_info *mtd;
150 static const char *rom_probe_types[]
151 = { "cfi_probe", "jedec_probe", "map_rom"};
152 int i;
153
154 dev_warn(&dev->dev, "Device tree uses obsolete \"direct-mapped\" "
155 "flash binding\n");
156
157 of_probe = of_get_property(dp, "probe-type", NULL);
158 if (!of_probe) {
159 for (i = 0; i < ARRAY_SIZE(rom_probe_types); i++) {
160 mtd = do_map_probe(rom_probe_types[i], map);
161 if (mtd)
162 return mtd;
163 }
164 return NULL;
165 } else if (strcmp(of_probe, "CFI") == 0) {
166 return do_map_probe("cfi_probe", map);
167 } else if (strcmp(of_probe, "JEDEC") == 0) {
168 return do_map_probe("jedec_probe", map);
169 } else {
170 if (strcmp(of_probe, "ROM") != 0)
David Gibsonc4d5e372007-09-20 11:22:25 +1000171 dev_warn(&dev->dev, "obsolete_probe: don't know probe "
172 "type '%s', mapping as rom\n", of_probe);
David Gibson20991722007-09-07 13:23:53 +1000173 return do_map_probe("mtd_rom", map);
174 }
175}
176
Jason Gunthorpe9d5da3a2010-03-09 12:27:56 -0700177#ifdef CONFIG_MTD_PARTITIONS
178/* When partitions are set we look for a linux,part-probe property which
179 specifies the list of partition probers to use. If none is given then the
180 default is use. These take precedence over other device tree
181 information. */
182static const char *part_probe_types_def[] = { "cmdlinepart", "RedBoot", NULL };
183static const char ** __devinit of_get_probes(struct device_node *dp)
184{
185 const char *cp;
186 int cplen;
187 unsigned int l;
188 unsigned int count;
189 const char **res;
190
191 cp = of_get_property(dp, "linux,part-probe", &cplen);
192 if (cp == NULL)
193 return part_probe_types_def;
194
195 count = 0;
196 for (l = 0; l != cplen; l++)
197 if (cp[l] == 0)
198 count++;
199
200 res = kzalloc((count + 1)*sizeof(*res), GFP_KERNEL);
201 count = 0;
202 while (cplen > 0) {
203 res[count] = cp;
204 l = strlen(cp) + 1;
205 cp += l;
206 cplen -= l;
207 count++;
208 }
209 return res;
210}
211
212static void __devinit of_free_probes(const char **probes)
213{
214 if (probes != part_probe_types_def)
215 kfree(probes);
216}
217#endif
218
Grant Likely1c48a5c2011-02-17 02:43:24 -0700219static int __devinit of_flash_probe(struct platform_device *dev)
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;
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 Likely1c48a5c2011-02-17 02:43:24 -0700237 if (!dev->dev.of_match)
238 return -EINVAL;
239 probe_type = dev->dev.of_match->data;
240
Stefan Roese143070e2009-04-16 14:10:45 +0200241 reg_tuple_size = (of_n_addr_cells(dp) + of_n_size_cells(dp)) * sizeof(u32);
242
243 /*
244 * Get number of "reg" tuples. Scan for MTD devices on area's
245 * described by each "reg" region. This makes it possible (including
246 * the concat support) to support the Intel P30 48F4400 chips which
247 * consists internally of 2 non-identical NOR chips on one die.
248 */
249 p = of_get_property(dp, "reg", &count);
250 if (count % reg_tuple_size != 0) {
251 dev_err(&dev->dev, "Malformed reg property on %s\n",
Grant Likely61c7a082010-04-13 16:12:29 -0700252 dev->dev.of_node->full_name);
Stefan Roese143070e2009-04-16 14:10:45 +0200253 err = -EINVAL;
vimal singhad4fbc72009-07-30 20:54:27 +0530254 goto err_flash_remove;
Vitaly Woola2c2fe42006-12-06 13:17:49 +0300255 }
Stefan Roese143070e2009-04-16 14:10:45 +0200256 count /= reg_tuple_size;
Vitaly Woola2c2fe42006-12-06 13:17:49 +0300257
David Gibsonc4d5e372007-09-20 11:22:25 +1000258 err = -ENOMEM;
Stefan Roese143070e2009-04-16 14:10:45 +0200259 info = kzalloc(sizeof(struct of_flash) +
260 sizeof(struct of_flash_list) * count, GFP_KERNEL);
261 if (!info)
vimal singhad4fbc72009-07-30 20:54:27 +0530262 goto err_flash_remove;
Vitaly Woola2c2fe42006-12-06 13:17:49 +0300263
264 dev_set_drvdata(&dev->dev, info);
265
Julia Lawalle0262552009-12-29 20:15:23 +0100266 mtd_list = kzalloc(sizeof(*mtd_list) * count, GFP_KERNEL);
vimal singhad4fbc72009-07-30 20:54:27 +0530267 if (!mtd_list)
268 goto err_flash_remove;
269
Stefan Roese143070e2009-04-16 14:10:45 +0200270 for (i = 0; i < count; i++) {
271 err = -ENXIO;
272 if (of_address_to_resource(dp, i, &res)) {
Stefan Roese940fe282010-10-08 14:41:27 +0200273 /*
274 * Continue with next register tuple if this
275 * one is not mappable
276 */
277 continue;
Stefan Roese143070e2009-04-16 14:10:45 +0200278 }
Vitaly Woola2c2fe42006-12-06 13:17:49 +0300279
Joe Perchesf9a52792010-11-12 13:37:57 -0800280 dev_dbg(&dev->dev, "of_flash device: %pR\n", &res);
Stefan Roese143070e2009-04-16 14:10:45 +0200281
282 err = -EBUSY;
Wolfram Sang2763c502009-07-17 17:54:14 +0200283 res_size = resource_size(&res);
284 info->list[i].res = request_mem_region(res.start, res_size,
Stefan Roese143070e2009-04-16 14:10:45 +0200285 dev_name(&dev->dev));
286 if (!info->list[i].res)
287 goto err_out;
288
289 err = -ENXIO;
290 width = of_get_property(dp, "bank-width", NULL);
291 if (!width) {
292 dev_err(&dev->dev, "Can't get bank width from device"
293 " tree\n");
294 goto err_out;
295 }
296
297 info->list[i].map.name = dev_name(&dev->dev);
298 info->list[i].map.phys = res.start;
Wolfram Sang2763c502009-07-17 17:54:14 +0200299 info->list[i].map.size = res_size;
Ian Munsie766f2712010-10-01 17:06:08 +1000300 info->list[i].map.bankwidth = be32_to_cpup(width);
Stefan Roese143070e2009-04-16 14:10:45 +0200301
302 err = -ENOMEM;
303 info->list[i].map.virt = ioremap(info->list[i].map.phys,
304 info->list[i].map.size);
305 if (!info->list[i].map.virt) {
306 dev_err(&dev->dev, "Failed to ioremap() flash"
307 " region\n");
308 goto err_out;
309 }
310
311 simple_map_init(&info->list[i].map);
312
313 if (probe_type) {
314 info->list[i].mtd = do_map_probe(probe_type,
315 &info->list[i].map);
316 } else {
317 info->list[i].mtd = obsolete_probe(dev,
318 &info->list[i].map);
319 }
320 mtd_list[i] = info->list[i].mtd;
321
322 err = -ENXIO;
323 if (!info->list[i].mtd) {
324 dev_err(&dev->dev, "do_map_probe() failed\n");
325 goto err_out;
326 } else {
327 info->list_size++;
328 }
329 info->list[i].mtd->owner = THIS_MODULE;
330 info->list[i].mtd->dev.parent = &dev->dev;
Vitaly Woola2c2fe42006-12-06 13:17:49 +0300331 }
332
Stefan Roese143070e2009-04-16 14:10:45 +0200333 err = 0;
334 if (info->list_size == 1) {
335 info->cmtd = info->list[0].mtd;
336 } else if (info->list_size > 1) {
337 /*
338 * We detected multiple devices. Concatenate them together.
339 */
340#ifdef CONFIG_MTD_CONCAT
341 info->cmtd = mtd_concat_create(mtd_list, info->list_size,
342 dev_name(&dev->dev));
343 if (info->cmtd == NULL)
344 err = -ENXIO;
345#else
346 printk(KERN_ERR "physmap_of: multiple devices "
347 "found but MTD concat support disabled.\n");
348 err = -ENXIO;
349#endif
Vitaly Woola2c2fe42006-12-06 13:17:49 +0300350 }
Stefan Roese143070e2009-04-16 14:10:45 +0200351 if (err)
Vitaly Woola2c2fe42006-12-06 13:17:49 +0300352 goto err_out;
Vitaly Woola2c2fe42006-12-06 13:17:49 +0300353
Scott Wood9a310d22008-01-15 17:54:43 -0600354#ifdef CONFIG_MTD_PARTITIONS
Jason Gunthorpe9d5da3a2010-03-09 12:27:56 -0700355 part_probe_types = of_get_probes(dp);
Stefan Roese143070e2009-04-16 14:10:45 +0200356 err = parse_mtd_partitions(info->cmtd, part_probe_types,
357 &info->parts, 0);
Jason Gunthorpe9d5da3a2010-03-09 12:27:56 -0700358 if (err < 0) {
359 of_free_probes(part_probe_types);
Julia Lawall00b275d2010-06-01 16:34:20 +0200360 goto err_out;
Jason Gunthorpe9d5da3a2010-03-09 12:27:56 -0700361 }
362 of_free_probes(part_probe_types);
Scott Wood9a310d22008-01-15 17:54:43 -0600363
364#ifdef CONFIG_MTD_OF_PARTS
365 if (err == 0) {
Sebastian Andrzej Siewior69fd3a82008-10-12 16:18:36 +0200366 err = of_mtd_parse_partitions(&dev->dev, dp, &info->parts);
Scott Wood9a310d22008-01-15 17:54:43 -0600367 if (err < 0)
Julia Lawall00b275d2010-06-01 16:34:20 +0200368 goto err_out;
Scott Wood9a310d22008-01-15 17:54:43 -0600369 }
370#endif
371
372 if (err == 0) {
373 err = parse_obsolete_partitions(dev, info, dp);
374 if (err < 0)
Julia Lawall00b275d2010-06-01 16:34:20 +0200375 goto err_out;
Scott Wood9a310d22008-01-15 17:54:43 -0600376 }
Vitaly Woola2c2fe42006-12-06 13:17:49 +0300377
David Gibsonc4d5e372007-09-20 11:22:25 +1000378 if (err > 0)
Stefan Roese143070e2009-04-16 14:10:45 +0200379 add_mtd_partitions(info->cmtd, info->parts, err);
David Gibsonc4d5e372007-09-20 11:22:25 +1000380 else
Scott Wood9a310d22008-01-15 17:54:43 -0600381#endif
Stefan Roese143070e2009-04-16 14:10:45 +0200382 add_mtd_device(info->cmtd);
383
384 kfree(mtd_list);
Vitaly Woola2c2fe42006-12-06 13:17:49 +0300385
Vitaly Woola2c2fe42006-12-06 13:17:49 +0300386 return 0;
387
388err_out:
Stefan Roese143070e2009-04-16 14:10:45 +0200389 kfree(mtd_list);
vimal singhad4fbc72009-07-30 20:54:27 +0530390err_flash_remove:
David Gibsonc4d5e372007-09-20 11:22:25 +1000391 of_flash_remove(dev);
Stefan Roese143070e2009-04-16 14:10:45 +0200392
Vitaly Woola2c2fe42006-12-06 13:17:49 +0300393 return err;
Vitaly Woola2c2fe42006-12-06 13:17:49 +0300394}
395
David Gibsonc4d5e372007-09-20 11:22:25 +1000396static struct of_device_id of_flash_match[] = {
Vitaly Woola2c2fe42006-12-06 13:17:49 +0300397 {
David Gibson20991722007-09-07 13:23:53 +1000398 .compatible = "cfi-flash",
399 .data = (void *)"cfi_probe",
400 },
401 {
402 /* FIXME: JEDEC chips can't be safely and reliably
403 * probed, although the mtd code gets it right in
404 * practice most of the time. We should use the
405 * vendor and device ids specified by the binding to
406 * bypass the heuristic probe code, but the mtd layer
407 * provides, at present, no interface for doing so
408 * :(. */
409 .compatible = "jedec-flash",
410 .data = (void *)"jedec_probe",
411 },
Vitaly Woola2c2fe42006-12-06 13:17:49 +0300412 {
Wolfram Sangfc28c39f2009-07-17 14:39:23 +0200413 .compatible = "mtd-ram",
414 .data = (void *)"map_ram",
415 },
416 {
Vitaly Woola2c2fe42006-12-06 13:17:49 +0300417 .type = "rom",
418 .compatible = "direct-mapped"
419 },
420 { },
421};
David Gibsonc4d5e372007-09-20 11:22:25 +1000422MODULE_DEVICE_TABLE(of, of_flash_match);
Vitaly Woola2c2fe42006-12-06 13:17:49 +0300423
Grant Likely1c48a5c2011-02-17 02:43:24 -0700424static struct platform_driver of_flash_driver = {
Grant Likely40182942010-04-13 16:13:02 -0700425 .driver = {
426 .name = "of-flash",
427 .owner = THIS_MODULE,
428 .of_match_table = of_flash_match,
429 },
David Gibsonc4d5e372007-09-20 11:22:25 +1000430 .probe = of_flash_probe,
431 .remove = of_flash_remove,
Vitaly Woola2c2fe42006-12-06 13:17:49 +0300432};
433
David Gibsonc4d5e372007-09-20 11:22:25 +1000434static int __init of_flash_init(void)
Vitaly Woola2c2fe42006-12-06 13:17:49 +0300435{
Grant Likely1c48a5c2011-02-17 02:43:24 -0700436 return platform_driver_register(&of_flash_driver);
Vitaly Woola2c2fe42006-12-06 13:17:49 +0300437}
438
David Gibsonc4d5e372007-09-20 11:22:25 +1000439static void __exit of_flash_exit(void)
Vitaly Woola2c2fe42006-12-06 13:17:49 +0300440{
Grant Likely1c48a5c2011-02-17 02:43:24 -0700441 platform_driver_unregister(&of_flash_driver);
Vitaly Woola2c2fe42006-12-06 13:17:49 +0300442}
443
David Gibsonc4d5e372007-09-20 11:22:25 +1000444module_init(of_flash_init);
445module_exit(of_flash_exit);
Vitaly Woola2c2fe42006-12-06 13:17:49 +0300446
447MODULE_LICENSE("GPL");
448MODULE_AUTHOR("Vitaly Wool <vwool@ru.mvista.com>");
David Gibsonc4d5e372007-09-20 11:22:25 +1000449MODULE_DESCRIPTION("Device tree based MTD map driver");