at v2.6.21 147 lines 3.5 kB view raw
1/* 2 * linux/drivers/mtd/onenand/generic.c 3 * 4 * Copyright (c) 2005 Samsung Electronics 5 * Kyungmin Park <kyungmin.park@samsung.com> 6 * 7 * This program is free software; you can redistribute it and/or modify 8 * it under the terms of the GNU General Public License version 2 as 9 * published by the Free Software Foundation. 10 * 11 * Overview: 12 * This is a device driver for the OneNAND flash for generic boards. 13 */ 14 15#include <linux/module.h> 16#include <linux/init.h> 17#include <linux/slab.h> 18#include <linux/platform_device.h> 19#include <linux/mtd/mtd.h> 20#include <linux/mtd/onenand.h> 21#include <linux/mtd/partitions.h> 22 23#include <asm/io.h> 24#include <asm/mach/flash.h> 25 26#define DRIVER_NAME "onenand" 27 28 29#ifdef CONFIG_MTD_PARTITIONS 30static const char *part_probes[] = { "cmdlinepart", NULL, }; 31#endif 32 33struct onenand_info { 34 struct mtd_info mtd; 35 struct mtd_partition *parts; 36 struct onenand_chip onenand; 37}; 38 39static int __devinit generic_onenand_probe(struct device *dev) 40{ 41 struct onenand_info *info; 42 struct platform_device *pdev = to_platform_device(dev); 43 struct flash_platform_data *pdata = pdev->dev.platform_data; 44 struct resource *res = pdev->resource; 45 unsigned long size = res->end - res->start + 1; 46 int err; 47 48 info = kzalloc(sizeof(struct onenand_info), GFP_KERNEL); 49 if (!info) 50 return -ENOMEM; 51 52 if (!request_mem_region(res->start, size, dev->driver->name)) { 53 err = -EBUSY; 54 goto out_free_info; 55 } 56 57 info->onenand.base = ioremap(res->start, size); 58 if (!info->onenand.base) { 59 err = -ENOMEM; 60 goto out_release_mem_region; 61 } 62 63 info->onenand.mmcontrol = pdata->mmcontrol; 64 info->onenand.irq = platform_get_irq(pdev, 0); 65 66 info->mtd.name = pdev->dev.bus_id; 67 info->mtd.priv = &info->onenand; 68 info->mtd.owner = THIS_MODULE; 69 70 if (onenand_scan(&info->mtd, 1)) { 71 err = -ENXIO; 72 goto out_iounmap; 73 } 74 75#ifdef CONFIG_MTD_PARTITIONS 76 err = parse_mtd_partitions(&info->mtd, part_probes, &info->parts, 0); 77 if (err > 0) 78 add_mtd_partitions(&info->mtd, info->parts, err); 79 else if (err < 0 && pdata->parts) 80 add_mtd_partitions(&info->mtd, pdata->parts, pdata->nr_parts); 81 else 82#endif 83 err = add_mtd_device(&info->mtd); 84 85 dev_set_drvdata(&pdev->dev, info); 86 87 return 0; 88 89out_iounmap: 90 iounmap(info->onenand.base); 91out_release_mem_region: 92 release_mem_region(res->start, size); 93out_free_info: 94 kfree(info); 95 96 return err; 97} 98 99static int __devexit generic_onenand_remove(struct device *dev) 100{ 101 struct platform_device *pdev = to_platform_device(dev); 102 struct onenand_info *info = dev_get_drvdata(&pdev->dev); 103 struct resource *res = pdev->resource; 104 unsigned long size = res->end - res->start + 1; 105 106 dev_set_drvdata(&pdev->dev, NULL); 107 108 if (info) { 109 if (info->parts) 110 del_mtd_partitions(&info->mtd); 111 else 112 del_mtd_device(&info->mtd); 113 114 onenand_release(&info->mtd); 115 release_mem_region(res->start, size); 116 iounmap(info->onenand.base); 117 kfree(info); 118 } 119 120 return 0; 121} 122 123static struct device_driver generic_onenand_driver = { 124 .name = DRIVER_NAME, 125 .bus = &platform_bus_type, 126 .probe = generic_onenand_probe, 127 .remove = __devexit_p(generic_onenand_remove), 128}; 129 130MODULE_ALIAS(DRIVER_NAME); 131 132static int __init generic_onenand_init(void) 133{ 134 return driver_register(&generic_onenand_driver); 135} 136 137static void __exit generic_onenand_exit(void) 138{ 139 driver_unregister(&generic_onenand_driver); 140} 141 142module_init(generic_onenand_init); 143module_exit(generic_onenand_exit); 144 145MODULE_LICENSE("GPL"); 146MODULE_AUTHOR("Kyungmin Park <kyungmin.park@samsung.com>"); 147MODULE_DESCRIPTION("Glue layer for OneNAND flash on generic boards");