IPVS: fix netns if reading ip_vs_* procfs entries
[linux-2.6/linux-mips.git] / drivers / mtd / maps / sa1100-flash.c
blobda875908ea8e04e20e08edb2785ecac37ef96a31
1 /*
2 * Flash memory access on SA11x0 based devices
4 * (C) 2000 Nicolas Pitre <nico@fluxnic.net>
5 */
6 #include <linux/module.h>
7 #include <linux/types.h>
8 #include <linux/ioport.h>
9 #include <linux/kernel.h>
10 #include <linux/init.h>
11 #include <linux/errno.h>
12 #include <linux/slab.h>
13 #include <linux/platform_device.h>
14 #include <linux/err.h>
15 #include <linux/io.h>
17 #include <linux/mtd/mtd.h>
18 #include <linux/mtd/map.h>
19 #include <linux/mtd/partitions.h>
20 #include <linux/mtd/concat.h>
22 #include <mach/hardware.h>
23 #include <asm/sizes.h>
24 #include <asm/mach/flash.h>
26 #if 0
28 * This is here for documentation purposes only - until these people
29 * submit their machine types. It will be gone January 2005.
31 static struct mtd_partition consus_partitions[] = {
33 .name = "Consus boot firmware",
34 .offset = 0,
35 .size = 0x00040000,
36 .mask_flags = MTD_WRITABLE, /* force read-only */
37 }, {
38 .name = "Consus kernel",
39 .offset = 0x00040000,
40 .size = 0x00100000,
41 .mask_flags = 0,
42 }, {
43 .name = "Consus disk",
44 .offset = 0x00140000,
45 /* The rest (up to 16M) for jffs. We could put 0 and
46 make it find the size automatically, but right now
47 i have 32 megs. jffs will use all 32 megs if given
48 the chance, and this leads to horrible problems
49 when you try to re-flash the image because blob
50 won't erase the whole partition. */
51 .size = 0x01000000 - 0x00140000,
52 .mask_flags = 0,
53 }, {
54 /* this disk is a secondary disk, which can be used as
55 needed, for simplicity, make it the size of the other
56 consus partition, although realistically it could be
57 the remainder of the disk (depending on the file
58 system used) */
59 .name = "Consus disk2",
60 .offset = 0x01000000,
61 .size = 0x01000000 - 0x00140000,
62 .mask_flags = 0,
66 /* Frodo has 2 x 16M 28F128J3A flash chips in bank 0: */
67 static struct mtd_partition frodo_partitions[] =
70 .name = "bootloader",
71 .size = 0x00040000,
72 .offset = 0x00000000,
73 .mask_flags = MTD_WRITEABLE
74 }, {
75 .name = "bootloader params",
76 .size = 0x00040000,
77 .offset = MTDPART_OFS_APPEND,
78 .mask_flags = MTD_WRITEABLE
79 }, {
80 .name = "kernel",
81 .size = 0x00100000,
82 .offset = MTDPART_OFS_APPEND,
83 .mask_flags = MTD_WRITEABLE
84 }, {
85 .name = "ramdisk",
86 .size = 0x00400000,
87 .offset = MTDPART_OFS_APPEND,
88 .mask_flags = MTD_WRITEABLE
89 }, {
90 .name = "file system",
91 .size = MTDPART_SIZ_FULL,
92 .offset = MTDPART_OFS_APPEND
96 static struct mtd_partition jornada56x_partitions[] = {
98 .name = "bootldr",
99 .size = 0x00040000,
100 .offset = 0,
101 .mask_flags = MTD_WRITEABLE,
102 }, {
103 .name = "rootfs",
104 .size = MTDPART_SIZ_FULL,
105 .offset = MTDPART_OFS_APPEND,
109 static void jornada56x_set_vpp(int vpp)
111 if (vpp)
112 GPSR = GPIO_GPIO26;
113 else
114 GPCR = GPIO_GPIO26;
115 GPDR |= GPIO_GPIO26;
119 * Machine Phys Size set_vpp
120 * Consus : SA1100_CS0_PHYS SZ_32M
121 * Frodo : SA1100_CS0_PHYS SZ_32M
122 * Jornada56x: SA1100_CS0_PHYS SZ_32M jornada56x_set_vpp
124 #endif
126 struct sa_subdev_info {
127 char name[16];
128 struct map_info map;
129 struct mtd_info *mtd;
130 struct flash_platform_data *plat;
133 struct sa_info {
134 struct mtd_partition *parts;
135 struct mtd_info *mtd;
136 int num_subdev;
137 unsigned int nr_parts;
138 struct sa_subdev_info subdev[0];
141 static void sa1100_set_vpp(struct map_info *map, int on)
143 struct sa_subdev_info *subdev = container_of(map, struct sa_subdev_info, map);
144 subdev->plat->set_vpp(on);
147 static void sa1100_destroy_subdev(struct sa_subdev_info *subdev)
149 if (subdev->mtd)
150 map_destroy(subdev->mtd);
151 if (subdev->map.virt)
152 iounmap(subdev->map.virt);
153 release_mem_region(subdev->map.phys, subdev->map.size);
156 static int sa1100_probe_subdev(struct sa_subdev_info *subdev, struct resource *res)
158 unsigned long phys;
159 unsigned int size;
160 int ret;
162 phys = res->start;
163 size = res->end - phys + 1;
166 * Retrieve the bankwidth from the MSC registers.
167 * We currently only implement CS0 and CS1 here.
169 switch (phys) {
170 default:
171 printk(KERN_WARNING "SA1100 flash: unknown base address "
172 "0x%08lx, assuming CS0\n", phys);
174 case SA1100_CS0_PHYS:
175 subdev->map.bankwidth = (MSC0 & MSC_RBW) ? 2 : 4;
176 break;
178 case SA1100_CS1_PHYS:
179 subdev->map.bankwidth = ((MSC0 >> 16) & MSC_RBW) ? 2 : 4;
180 break;
183 if (!request_mem_region(phys, size, subdev->name)) {
184 ret = -EBUSY;
185 goto out;
188 if (subdev->plat->set_vpp)
189 subdev->map.set_vpp = sa1100_set_vpp;
191 subdev->map.phys = phys;
192 subdev->map.size = size;
193 subdev->map.virt = ioremap(phys, size);
194 if (!subdev->map.virt) {
195 ret = -ENOMEM;
196 goto err;
199 simple_map_init(&subdev->map);
202 * Now let's probe for the actual flash. Do it here since
203 * specific machine settings might have been set above.
205 subdev->mtd = do_map_probe(subdev->plat->map_name, &subdev->map);
206 if (subdev->mtd == NULL) {
207 ret = -ENXIO;
208 goto err;
210 subdev->mtd->owner = THIS_MODULE;
212 printk(KERN_INFO "SA1100 flash: CFI device at 0x%08lx, %uMiB, %d-bit\n",
213 phys, (unsigned)(subdev->mtd->size >> 20),
214 subdev->map.bankwidth * 8);
216 return 0;
218 err:
219 sa1100_destroy_subdev(subdev);
220 out:
221 return ret;
224 static void sa1100_destroy(struct sa_info *info, struct flash_platform_data *plat)
226 int i;
228 if (info->mtd) {
229 if (info->nr_parts == 0)
230 del_mtd_device(info->mtd);
231 #ifdef CONFIG_MTD_PARTITIONS
232 else
233 del_mtd_partitions(info->mtd);
234 #endif
235 if (info->mtd != info->subdev[0].mtd)
236 mtd_concat_destroy(info->mtd);
239 kfree(info->parts);
241 for (i = info->num_subdev - 1; i >= 0; i--)
242 sa1100_destroy_subdev(&info->subdev[i]);
243 kfree(info);
245 if (plat->exit)
246 plat->exit();
249 static struct sa_info *__devinit
250 sa1100_setup_mtd(struct platform_device *pdev, struct flash_platform_data *plat)
252 struct sa_info *info;
253 int nr, size, i, ret = 0;
256 * Count number of devices.
258 for (nr = 0; ; nr++)
259 if (!platform_get_resource(pdev, IORESOURCE_MEM, nr))
260 break;
262 if (nr == 0) {
263 ret = -ENODEV;
264 goto out;
267 size = sizeof(struct sa_info) + sizeof(struct sa_subdev_info) * nr;
270 * Allocate the map_info structs in one go.
272 info = kzalloc(size, GFP_KERNEL);
273 if (!info) {
274 ret = -ENOMEM;
275 goto out;
278 if (plat->init) {
279 ret = plat->init();
280 if (ret)
281 goto err;
285 * Claim and then map the memory regions.
287 for (i = 0; i < nr; i++) {
288 struct sa_subdev_info *subdev = &info->subdev[i];
289 struct resource *res;
291 res = platform_get_resource(pdev, IORESOURCE_MEM, i);
292 if (!res)
293 break;
295 subdev->map.name = subdev->name;
296 sprintf(subdev->name, "%s-%d", plat->name, i);
297 subdev->plat = plat;
299 ret = sa1100_probe_subdev(subdev, res);
300 if (ret)
301 break;
304 info->num_subdev = i;
307 * ENXIO is special. It means we didn't find a chip when we probed.
309 if (ret != 0 && !(ret == -ENXIO && info->num_subdev > 0))
310 goto err;
313 * If we found one device, don't bother with concat support. If
314 * we found multiple devices, use concat if we have it available,
315 * otherwise fail. Either way, it'll be called "sa1100".
317 if (info->num_subdev == 1) {
318 strcpy(info->subdev[0].name, plat->name);
319 info->mtd = info->subdev[0].mtd;
320 ret = 0;
321 } else if (info->num_subdev > 1) {
322 struct mtd_info *cdev[nr];
324 * We detected multiple devices. Concatenate them together.
326 for (i = 0; i < info->num_subdev; i++)
327 cdev[i] = info->subdev[i].mtd;
329 info->mtd = mtd_concat_create(cdev, info->num_subdev,
330 plat->name);
331 if (info->mtd == NULL)
332 ret = -ENXIO;
335 if (ret == 0)
336 return info;
338 err:
339 sa1100_destroy(info, plat);
340 out:
341 return ERR_PTR(ret);
344 static const char *part_probes[] = { "cmdlinepart", "RedBoot", NULL };
346 static int __devinit sa1100_mtd_probe(struct platform_device *pdev)
348 struct flash_platform_data *plat = pdev->dev.platform_data;
349 struct mtd_partition *parts;
350 const char *part_type = NULL;
351 struct sa_info *info;
352 int err, nr_parts = 0;
354 if (!plat)
355 return -ENODEV;
357 info = sa1100_setup_mtd(pdev, plat);
358 if (IS_ERR(info)) {
359 err = PTR_ERR(info);
360 goto out;
364 * Partition selection stuff.
366 #ifdef CONFIG_MTD_PARTITIONS
367 nr_parts = parse_mtd_partitions(info->mtd, part_probes, &parts, 0);
368 if (nr_parts > 0) {
369 info->parts = parts;
370 part_type = "dynamic";
371 } else
372 #endif
374 parts = plat->parts;
375 nr_parts = plat->nr_parts;
376 part_type = "static";
379 if (nr_parts == 0) {
380 printk(KERN_NOTICE "SA1100 flash: no partition info "
381 "available, registering whole flash\n");
382 add_mtd_device(info->mtd);
383 } else {
384 printk(KERN_NOTICE "SA1100 flash: using %s partition "
385 "definition\n", part_type);
386 add_mtd_partitions(info->mtd, parts, nr_parts);
389 info->nr_parts = nr_parts;
391 platform_set_drvdata(pdev, info);
392 err = 0;
394 out:
395 return err;
398 static int __exit sa1100_mtd_remove(struct platform_device *pdev)
400 struct sa_info *info = platform_get_drvdata(pdev);
401 struct flash_platform_data *plat = pdev->dev.platform_data;
403 platform_set_drvdata(pdev, NULL);
404 sa1100_destroy(info, plat);
406 return 0;
409 #ifdef CONFIG_PM
410 static void sa1100_mtd_shutdown(struct platform_device *dev)
412 struct sa_info *info = platform_get_drvdata(dev);
413 if (info && info->mtd->suspend(info->mtd) == 0)
414 info->mtd->resume(info->mtd);
416 #else
417 #define sa1100_mtd_shutdown NULL
418 #endif
420 static struct platform_driver sa1100_mtd_driver = {
421 .probe = sa1100_mtd_probe,
422 .remove = __exit_p(sa1100_mtd_remove),
423 .shutdown = sa1100_mtd_shutdown,
424 .driver = {
425 .name = "sa1100-mtd",
426 .owner = THIS_MODULE,
430 static int __init sa1100_mtd_init(void)
432 return platform_driver_register(&sa1100_mtd_driver);
435 static void __exit sa1100_mtd_exit(void)
437 platform_driver_unregister(&sa1100_mtd_driver);
440 module_init(sa1100_mtd_init);
441 module_exit(sa1100_mtd_exit);
443 MODULE_AUTHOR("Nicolas Pitre");
444 MODULE_DESCRIPTION("SA1100 CFI map driver");
445 MODULE_LICENSE("GPL");
446 MODULE_ALIAS("platform:sa1100-mtd");