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/slab.h> 17#include <linux/platform_device.h> 18#include <linux/mtd/mtd.h> 19#include <linux/mtd/onenand.h> 20#include <linux/mtd/partitions.h> 21#include <linux/io.h> 22 23/* 24 * Note: Driver name and platform data format have been updated! 25 * 26 * This version of the driver is named "onenand-flash" and takes struct 27 * onenand_platform_data as platform data. The old ARM-specific version 28 * with the name "onenand" used to take struct flash_platform_data. 29 */ 30#define DRIVER_NAME "onenand-flash" 31 32struct onenand_info { 33 struct mtd_info mtd; 34 struct onenand_chip onenand; 35}; 36 37static int generic_onenand_probe(struct platform_device *pdev) 38{ 39 struct onenand_info *info; 40 struct onenand_platform_data *pdata = dev_get_platdata(&pdev->dev); 41 struct resource *res = pdev->resource; 42 unsigned long size = resource_size(res); 43 int err; 44 45 info = kzalloc(sizeof(struct onenand_info), GFP_KERNEL); 46 if (!info) 47 return -ENOMEM; 48 49 if (!request_mem_region(res->start, size, dev_name(&pdev->dev))) { 50 err = -EBUSY; 51 goto out_free_info; 52 } 53 54 info->onenand.base = ioremap(res->start, size); 55 if (!info->onenand.base) { 56 err = -ENOMEM; 57 goto out_release_mem_region; 58 } 59 60 info->onenand.mmcontrol = pdata ? pdata->mmcontrol : NULL; 61 info->onenand.irq = platform_get_irq(pdev, 0); 62 63 info->mtd.dev.parent = &pdev->dev; 64 info->mtd.priv = &info->onenand; 65 66 if (onenand_scan(&info->mtd, 1)) { 67 err = -ENXIO; 68 goto out_iounmap; 69 } 70 71 err = mtd_device_parse_register(&info->mtd, NULL, NULL, 72 pdata ? pdata->parts : NULL, 73 pdata ? pdata->nr_parts : 0); 74 75 platform_set_drvdata(pdev, info); 76 77 return 0; 78 79out_iounmap: 80 iounmap(info->onenand.base); 81out_release_mem_region: 82 release_mem_region(res->start, size); 83out_free_info: 84 kfree(info); 85 86 return err; 87} 88 89static int generic_onenand_remove(struct platform_device *pdev) 90{ 91 struct onenand_info *info = platform_get_drvdata(pdev); 92 struct resource *res = pdev->resource; 93 unsigned long size = resource_size(res); 94 95 if (info) { 96 onenand_release(&info->mtd); 97 release_mem_region(res->start, size); 98 iounmap(info->onenand.base); 99 kfree(info); 100 } 101 102 return 0; 103} 104 105static struct platform_driver generic_onenand_driver = { 106 .driver = { 107 .name = DRIVER_NAME, 108 }, 109 .probe = generic_onenand_probe, 110 .remove = generic_onenand_remove, 111}; 112 113module_platform_driver(generic_onenand_driver); 114 115MODULE_LICENSE("GPL"); 116MODULE_AUTHOR("Kyungmin Park <kyungmin.park@samsung.com>"); 117MODULE_DESCRIPTION("Glue layer for OneNAND flash on generic boards"); 118MODULE_ALIAS("platform:" DRIVER_NAME); 119