[DRIVER MODEL] Add platform_driver
[deliverable/linux.git] / drivers / mtd / maps / sa1100-flash.c
CommitLineData
1da177e4
LT
1/*
2 * Flash memory access on SA11x0 based devices
69f34c98 3 *
1da177e4 4 * (C) 2000 Nicolas Pitre <nico@cam.org>
69f34c98
TG
5 *
6 * $Id: sa1100-flash.c,v 1.51 2005/11/07 11:14:28 gleixner Exp $
1da177e4
LT
7 */
8#include <linux/config.h>
9#include <linux/module.h>
10#include <linux/types.h>
11#include <linux/ioport.h>
12#include <linux/kernel.h>
13#include <linux/init.h>
14#include <linux/errno.h>
15#include <linux/slab.h>
d052d1be 16#include <linux/platform_device.h>
1da177e4
LT
17#include <linux/err.h>
18
19#include <linux/mtd/mtd.h>
20#include <linux/mtd/map.h>
21#include <linux/mtd/partitions.h>
22#include <linux/mtd/concat.h>
23
674c0453 24#include <asm/hardware.h>
1da177e4
LT
25#include <asm/io.h>
26#include <asm/sizes.h>
27#include <asm/mach/flash.h>
28
29#if 0
30/*
31 * This is here for documentation purposes only - until these people
32 * submit their machine types. It will be gone January 2005.
33 */
34static struct mtd_partition consus_partitions[] = {
35 {
36 .name = "Consus boot firmware",
37 .offset = 0,
38 .size = 0x00040000,
39 .mask_flags = MTD_WRITABLE, /* force read-only */
40 }, {
41 .name = "Consus kernel",
42 .offset = 0x00040000,
43 .size = 0x00100000,
44 .mask_flags = 0,
45 }, {
46 .name = "Consus disk",
47 .offset = 0x00140000,
48 /* The rest (up to 16M) for jffs. We could put 0 and
49 make it find the size automatically, but right now
50 i have 32 megs. jffs will use all 32 megs if given
51 the chance, and this leads to horrible problems
52 when you try to re-flash the image because blob
53 won't erase the whole partition. */
54 .size = 0x01000000 - 0x00140000,
55 .mask_flags = 0,
56 }, {
57 /* this disk is a secondary disk, which can be used as
58 needed, for simplicity, make it the size of the other
59 consus partition, although realistically it could be
60 the remainder of the disk (depending on the file
61 system used) */
62 .name = "Consus disk2",
63 .offset = 0x01000000,
64 .size = 0x01000000 - 0x00140000,
65 .mask_flags = 0,
66 }
67};
68
69/* Frodo has 2 x 16M 28F128J3A flash chips in bank 0: */
70static struct mtd_partition frodo_partitions[] =
71{
72 {
73 .name = "bootloader",
74 .size = 0x00040000,
75 .offset = 0x00000000,
76 .mask_flags = MTD_WRITEABLE
77 }, {
78 .name = "bootloader params",
79 .size = 0x00040000,
80 .offset = MTDPART_OFS_APPEND,
81 .mask_flags = MTD_WRITEABLE
82 }, {
83 .name = "kernel",
84 .size = 0x00100000,
85 .offset = MTDPART_OFS_APPEND,
86 .mask_flags = MTD_WRITEABLE
87 }, {
88 .name = "ramdisk",
89 .size = 0x00400000,
90 .offset = MTDPART_OFS_APPEND,
91 .mask_flags = MTD_WRITEABLE
92 }, {
93 .name = "file system",
94 .size = MTDPART_SIZ_FULL,
95 .offset = MTDPART_OFS_APPEND
96 }
97};
98
99static struct mtd_partition jornada56x_partitions[] = {
100 {
101 .name = "bootldr",
102 .size = 0x00040000,
103 .offset = 0,
104 .mask_flags = MTD_WRITEABLE,
105 }, {
106 .name = "rootfs",
107 .size = MTDPART_SIZ_FULL,
108 .offset = MTDPART_OFS_APPEND,
109 }
110};
111
112static void jornada56x_set_vpp(int vpp)
113{
114 if (vpp)
115 GPSR = GPIO_GPIO26;
116 else
117 GPCR = GPIO_GPIO26;
118 GPDR |= GPIO_GPIO26;
119}
120
121/*
122 * Machine Phys Size set_vpp
123 * Consus : SA1100_CS0_PHYS SZ_32M
124 * Frodo : SA1100_CS0_PHYS SZ_32M
125 * Jornada56x: SA1100_CS0_PHYS SZ_32M jornada56x_set_vpp
126 */
127#endif
128
129struct sa_subdev_info {
130 char name[16];
131 struct map_info map;
132 struct mtd_info *mtd;
57725f0a 133 struct flash_platform_data *plat;
1da177e4
LT
134};
135
136struct sa_info {
137 struct mtd_partition *parts;
138 struct mtd_info *mtd;
139 int num_subdev;
822e5e72 140 unsigned int nr_parts;
1da177e4
LT
141 struct sa_subdev_info subdev[0];
142};
143
144static void sa1100_set_vpp(struct map_info *map, int on)
145{
146 struct sa_subdev_info *subdev = container_of(map, struct sa_subdev_info, map);
57725f0a 147 subdev->plat->set_vpp(on);
1da177e4
LT
148}
149
150static void sa1100_destroy_subdev(struct sa_subdev_info *subdev)
151{
152 if (subdev->mtd)
153 map_destroy(subdev->mtd);
154 if (subdev->map.virt)
155 iounmap(subdev->map.virt);
156 release_mem_region(subdev->map.phys, subdev->map.size);
157}
158
159static int sa1100_probe_subdev(struct sa_subdev_info *subdev, struct resource *res)
160{
161 unsigned long phys;
162 unsigned int size;
163 int ret;
164
165 phys = res->start;
166 size = res->end - phys + 1;
167
168 /*
169 * Retrieve the bankwidth from the MSC registers.
170 * We currently only implement CS0 and CS1 here.
171 */
172 switch (phys) {
173 default:
174 printk(KERN_WARNING "SA1100 flash: unknown base address "
175 "0x%08lx, assuming CS0\n", phys);
176
177 case SA1100_CS0_PHYS:
178 subdev->map.bankwidth = (MSC0 & MSC_RBW) ? 2 : 4;
179 break;
180
181 case SA1100_CS1_PHYS:
182 subdev->map.bankwidth = ((MSC0 >> 16) & MSC_RBW) ? 2 : 4;
183 break;
184 }
185
186 if (!request_mem_region(phys, size, subdev->name)) {
187 ret = -EBUSY;
188 goto out;
189 }
190
57725f0a 191 if (subdev->plat->set_vpp)
1da177e4
LT
192 subdev->map.set_vpp = sa1100_set_vpp;
193
194 subdev->map.phys = phys;
195 subdev->map.size = size;
196 subdev->map.virt = ioremap(phys, size);
197 if (!subdev->map.virt) {
198 ret = -ENOMEM;
199 goto err;
200 }
201
202 simple_map_init(&subdev->map);
203
204 /*
205 * Now let's probe for the actual flash. Do it here since
206 * specific machine settings might have been set above.
207 */
57725f0a 208 subdev->mtd = do_map_probe(subdev->plat->map_name, &subdev->map);
1da177e4
LT
209 if (subdev->mtd == NULL) {
210 ret = -ENXIO;
211 goto err;
212 }
213 subdev->mtd->owner = THIS_MODULE;
214
215 printk(KERN_INFO "SA1100 flash: CFI device at 0x%08lx, %dMiB, "
216 "%d-bit\n", phys, subdev->mtd->size >> 20,
217 subdev->map.bankwidth * 8);
218
219 return 0;
220
221 err:
222 sa1100_destroy_subdev(subdev);
223 out:
224 return ret;
225}
226
0d2ef7d7 227static void sa1100_destroy(struct sa_info *info, struct flash_platform_data *plat)
1da177e4
LT
228{
229 int i;
230
231 if (info->mtd) {
822e5e72
RK
232 if (info->nr_parts == 0)
233 del_mtd_device(info->mtd);
234#ifdef CONFIG_MTD_PARTITIONS
235 else
236 del_mtd_partitions(info->mtd);
237#endif
1da177e4
LT
238#ifdef CONFIG_MTD_CONCAT
239 if (info->mtd != info->subdev[0].mtd)
240 mtd_concat_destroy(info->mtd);
241#endif
242 }
243
fa671646 244 kfree(info->parts);
1da177e4
LT
245
246 for (i = info->num_subdev - 1; i >= 0; i--)
247 sa1100_destroy_subdev(&info->subdev[i]);
248 kfree(info);
0d2ef7d7
RK
249
250 if (plat->exit)
251 plat->exit();
1da177e4
LT
252}
253
254static struct sa_info *__init
57725f0a 255sa1100_setup_mtd(struct platform_device *pdev, struct flash_platform_data *plat)
1da177e4
LT
256{
257 struct sa_info *info;
258 int nr, size, i, ret = 0;
259
260 /*
261 * Count number of devices.
262 */
263 for (nr = 0; ; nr++)
264 if (!platform_get_resource(pdev, IORESOURCE_MEM, nr))
265 break;
266
267 if (nr == 0) {
268 ret = -ENODEV;
269 goto out;
270 }
271
272 size = sizeof(struct sa_info) + sizeof(struct sa_subdev_info) * nr;
273
274 /*
275 * Allocate the map_info structs in one go.
276 */
277 info = kmalloc(size, GFP_KERNEL);
278 if (!info) {
279 ret = -ENOMEM;
280 goto out;
281 }
282
283 memset(info, 0, size);
284
0d2ef7d7
RK
285 if (plat->init) {
286 ret = plat->init();
287 if (ret)
288 goto err;
289 }
290
1da177e4
LT
291 /*
292 * Claim and then map the memory regions.
293 */
294 for (i = 0; i < nr; i++) {
295 struct sa_subdev_info *subdev = &info->subdev[i];
296 struct resource *res;
297
298 res = platform_get_resource(pdev, IORESOURCE_MEM, i);
299 if (!res)
300 break;
301
302 subdev->map.name = subdev->name;
14e66f76 303 sprintf(subdev->name, "%s-%d", plat->name, i);
57725f0a 304 subdev->plat = plat;
1da177e4
LT
305
306 ret = sa1100_probe_subdev(subdev, res);
307 if (ret)
308 break;
309 }
310
311 info->num_subdev = i;
312
313 /*
314 * ENXIO is special. It means we didn't find a chip when we probed.
315 */
316 if (ret != 0 && !(ret == -ENXIO && info->num_subdev > 0))
317 goto err;
318
319 /*
320 * If we found one device, don't bother with concat support. If
321 * we found multiple devices, use concat if we have it available,
322 * otherwise fail. Either way, it'll be called "sa1100".
323 */
324 if (info->num_subdev == 1) {
14e66f76 325 strcpy(info->subdev[0].name, plat->name);
1da177e4
LT
326 info->mtd = info->subdev[0].mtd;
327 ret = 0;
328 } else if (info->num_subdev > 1) {
329#ifdef CONFIG_MTD_CONCAT
330 struct mtd_info *cdev[nr];
331 /*
332 * We detected multiple devices. Concatenate them together.
333 */
334 for (i = 0; i < info->num_subdev; i++)
335 cdev[i] = info->subdev[i].mtd;
336
337 info->mtd = mtd_concat_create(cdev, info->num_subdev,
14e66f76 338 plat->name);
1da177e4
LT
339 if (info->mtd == NULL)
340 ret = -ENXIO;
341#else
342 printk(KERN_ERR "SA1100 flash: multiple devices "
343 "found but MTD concat support disabled.\n");
344 ret = -ENXIO;
345#endif
346 }
347
348 if (ret == 0)
349 return info;
350
351 err:
0d2ef7d7 352 sa1100_destroy(info, plat);
1da177e4
LT
353 out:
354 return ERR_PTR(ret);
355}
356
357static const char *part_probes[] = { "cmdlinepart", "RedBoot", NULL };
358
359static int __init sa1100_mtd_probe(struct device *dev)
360{
361 struct platform_device *pdev = to_platform_device(dev);
57725f0a 362 struct flash_platform_data *plat = pdev->dev.platform_data;
1da177e4
LT
363 struct mtd_partition *parts;
364 const char *part_type = NULL;
365 struct sa_info *info;
366 int err, nr_parts = 0;
367
57725f0a 368 if (!plat)
1da177e4
LT
369 return -ENODEV;
370
57725f0a 371 info = sa1100_setup_mtd(pdev, plat);
1da177e4
LT
372 if (IS_ERR(info)) {
373 err = PTR_ERR(info);
374 goto out;
375 }
376
377 /*
378 * Partition selection stuff.
379 */
380#ifdef CONFIG_MTD_PARTITIONS
381 nr_parts = parse_mtd_partitions(info->mtd, part_probes, &parts, 0);
382 if (nr_parts > 0) {
383 info->parts = parts;
384 part_type = "dynamic";
385 } else
386#endif
387 {
57725f0a
RK
388 parts = plat->parts;
389 nr_parts = plat->nr_parts;
1da177e4
LT
390 part_type = "static";
391 }
392
393 if (nr_parts == 0) {
394 printk(KERN_NOTICE "SA1100 flash: no partition info "
395 "available, registering whole flash\n");
396 add_mtd_device(info->mtd);
397 } else {
398 printk(KERN_NOTICE "SA1100 flash: using %s partition "
399 "definition\n", part_type);
400 add_mtd_partitions(info->mtd, parts, nr_parts);
401 }
402
822e5e72
RK
403 info->nr_parts = nr_parts;
404
1da177e4
LT
405 dev_set_drvdata(dev, info);
406 err = 0;
407
408 out:
409 return err;
410}
411
412static int __exit sa1100_mtd_remove(struct device *dev)
413{
414 struct sa_info *info = dev_get_drvdata(dev);
0d2ef7d7
RK
415 struct flash_platform_data *plat = dev->platform_data;
416
1da177e4 417 dev_set_drvdata(dev, NULL);
0d2ef7d7
RK
418 sa1100_destroy(info, plat);
419
1da177e4
LT
420 return 0;
421}
422
423#ifdef CONFIG_PM
9480e307 424static int sa1100_mtd_suspend(struct device *dev, pm_message_t state)
1da177e4
LT
425{
426 struct sa_info *info = dev_get_drvdata(dev);
427 int ret = 0;
428
9480e307 429 if (info)
1da177e4
LT
430 ret = info->mtd->suspend(info->mtd);
431
432 return ret;
433}
434
9480e307 435static int sa1100_mtd_resume(struct device *dev)
1da177e4
LT
436{
437 struct sa_info *info = dev_get_drvdata(dev);
9480e307 438 if (info)
1da177e4
LT
439 info->mtd->resume(info->mtd);
440 return 0;
441}
13bfb34c
RK
442
443static void sa1100_mtd_shutdown(struct device *dev)
444{
445 struct sa_info *info = dev_get_drvdata(dev);
446 if (info && info->mtd->suspend(info->mtd) == 0)
447 info->mtd->resume(info->mtd);
448}
1da177e4
LT
449#else
450#define sa1100_mtd_suspend NULL
451#define sa1100_mtd_resume NULL
13bfb34c 452#define sa1100_mtd_shutdown NULL
1da177e4
LT
453#endif
454
455static struct device_driver sa1100_mtd_driver = {
456 .name = "flash",
457 .bus = &platform_bus_type,
458 .probe = sa1100_mtd_probe,
459 .remove = __exit_p(sa1100_mtd_remove),
460 .suspend = sa1100_mtd_suspend,
461 .resume = sa1100_mtd_resume,
13bfb34c 462 .shutdown = sa1100_mtd_shutdown,
1da177e4
LT
463};
464
465static int __init sa1100_mtd_init(void)
466{
467 return driver_register(&sa1100_mtd_driver);
468}
469
470static void __exit sa1100_mtd_exit(void)
471{
472 driver_unregister(&sa1100_mtd_driver);
473}
474
475module_init(sa1100_mtd_init);
476module_exit(sa1100_mtd_exit);
477
478MODULE_AUTHOR("Nicolas Pitre");
479MODULE_DESCRIPTION("SA1100 CFI map driver");
480MODULE_LICENSE("GPL");
This page took 0.09445 seconds and 5 git commands to generate.