/drivers/mtd/onenand/generic.c
C | 143 lines | 97 code | 26 blank | 20 comment | 10 complexity | cf3cd9113f77cd826193669ad1ec624b MD5 | raw file
Possible License(s): GPL-2.0, LGPL-2.0, AGPL-1.0
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#include <asm/io.h> 23 24/* 25 * Note: Driver name and platform data format have been updated! 26 * 27 * This version of the driver is named "onenand-flash" and takes struct 28 * onenand_platform_data as platform data. The old ARM-specific version 29 * with the name "onenand" used to take struct flash_platform_data. 30 */ 31#define DRIVER_NAME "onenand-flash" 32 33static const char *part_probes[] = { "cmdlinepart", NULL, }; 34 35struct onenand_info { 36 struct mtd_info mtd; 37 struct mtd_partition *parts; 38 struct onenand_chip onenand; 39}; 40 41static int __devinit generic_onenand_probe(struct platform_device *pdev) 42{ 43 struct onenand_info *info; 44 struct onenand_platform_data *pdata = pdev->dev.platform_data; 45 struct resource *res = pdev->resource; 46 unsigned long size = resource_size(res); 47 int err; 48 49 info = kzalloc(sizeof(struct onenand_info), GFP_KERNEL); 50 if (!info) 51 return -ENOMEM; 52 53 if (!request_mem_region(res->start, size, dev_name(&pdev->dev))) { 54 err = -EBUSY; 55 goto out_free_info; 56 } 57 58 info->onenand.base = ioremap(res->start, size); 59 if (!info->onenand.base) { 60 err = -ENOMEM; 61 goto out_release_mem_region; 62 } 63 64 info->onenand.mmcontrol = pdata ? pdata->mmcontrol : 0; 65 info->onenand.irq = platform_get_irq(pdev, 0); 66 67 info->mtd.name = dev_name(&pdev->dev); 68 info->mtd.priv = &info->onenand; 69 info->mtd.owner = THIS_MODULE; 70 71 if (onenand_scan(&info->mtd, 1)) { 72 err = -ENXIO; 73 goto out_iounmap; 74 } 75 76 err = parse_mtd_partitions(&info->mtd, part_probes, &info->parts, 0); 77 if (err > 0) 78 mtd_device_register(&info->mtd, info->parts, err); 79 else if (err <= 0 && pdata && pdata->parts) 80 mtd_device_register(&info->mtd, pdata->parts, pdata->nr_parts); 81 else 82 err = mtd_device_register(&info->mtd, NULL, 0); 83 84 platform_set_drvdata(pdev, info); 85 86 return 0; 87 88out_iounmap: 89 iounmap(info->onenand.base); 90out_release_mem_region: 91 release_mem_region(res->start, size); 92out_free_info: 93 kfree(info); 94 95 return err; 96} 97 98static int __devexit generic_onenand_remove(struct platform_device *pdev) 99{ 100 struct onenand_info *info = platform_get_drvdata(pdev); 101 struct resource *res = pdev->resource; 102 unsigned long size = resource_size(res); 103 104 platform_set_drvdata(pdev, NULL); 105 106 if (info) { 107 mtd_device_unregister(&info->mtd); 108 onenand_release(&info->mtd); 109 release_mem_region(res->start, size); 110 iounmap(info->onenand.base); 111 kfree(info); 112 } 113 114 return 0; 115} 116 117static struct platform_driver generic_onenand_driver = { 118 .driver = { 119 .name = DRIVER_NAME, 120 .owner = THIS_MODULE, 121 }, 122 .probe = generic_onenand_probe, 123 .remove = __devexit_p(generic_onenand_remove), 124}; 125 126MODULE_ALIAS("platform:" DRIVER_NAME); 127 128static int __init generic_onenand_init(void) 129{ 130 return platform_driver_register(&generic_onenand_driver); 131} 132 133static void __exit generic_onenand_exit(void) 134{ 135 platform_driver_unregister(&generic_onenand_driver); 136} 137 138module_init(generic_onenand_init); 139module_exit(generic_onenand_exit); 140 141MODULE_LICENSE("GPL"); 142MODULE_AUTHOR("Kyungmin Park <kyungmin.park@samsung.com>"); 143MODULE_DESCRIPTION("Glue layer for OneNAND flash on generic boards");