Linux kernel & device driver programming

Cross-Referenced Linux and Device Driver Code

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