Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 /*
0003  *  Copyright (c) 2005 Samsung Electronics
0004  *  Kyungmin Park <kyungmin.park@samsung.com>
0005  *
0006  *  Overview:
0007  *   This is a device driver for the OneNAND flash for generic boards.
0008  */
0009 
0010 #include <linux/module.h>
0011 #include <linux/slab.h>
0012 #include <linux/platform_device.h>
0013 #include <linux/mtd/mtd.h>
0014 #include <linux/mtd/onenand.h>
0015 #include <linux/mtd/partitions.h>
0016 #include <linux/io.h>
0017 
0018 /*
0019  * Note: Driver name and platform data format have been updated!
0020  *
0021  * This version of the driver is named "onenand-flash" and takes struct
0022  * onenand_platform_data as platform data. The old ARM-specific version
0023  * with the name "onenand" used to take struct flash_platform_data.
0024  */
0025 #define DRIVER_NAME "onenand-flash"
0026 
0027 struct onenand_info {
0028     struct mtd_info     mtd;
0029     struct onenand_chip onenand;
0030 };
0031 
0032 static int generic_onenand_probe(struct platform_device *pdev)
0033 {
0034     struct onenand_info *info;
0035     struct onenand_platform_data *pdata = dev_get_platdata(&pdev->dev);
0036     struct resource *res = pdev->resource;
0037     unsigned long size = resource_size(res);
0038     int err;
0039 
0040     info = kzalloc(sizeof(struct onenand_info), GFP_KERNEL);
0041     if (!info)
0042         return -ENOMEM;
0043 
0044     if (!request_mem_region(res->start, size, dev_name(&pdev->dev))) {
0045         err = -EBUSY;
0046         goto out_free_info;
0047     }
0048 
0049     info->onenand.base = ioremap(res->start, size);
0050     if (!info->onenand.base) {
0051         err = -ENOMEM;
0052         goto out_release_mem_region;
0053     }
0054 
0055     info->onenand.mmcontrol = pdata ? pdata->mmcontrol : NULL;
0056 
0057     err = platform_get_irq(pdev, 0);
0058     if (err < 0)
0059         goto out_iounmap;
0060 
0061     info->onenand.irq = err;
0062 
0063     info->mtd.dev.parent = &pdev->dev;
0064     info->mtd.priv = &info->onenand;
0065 
0066     if (onenand_scan(&info->mtd, 1)) {
0067         err = -ENXIO;
0068         goto out_iounmap;
0069     }
0070 
0071     err = mtd_device_register(&info->mtd, pdata ? pdata->parts : NULL,
0072                   pdata ? pdata->nr_parts : 0);
0073 
0074     platform_set_drvdata(pdev, info);
0075 
0076     return 0;
0077 
0078 out_iounmap:
0079     iounmap(info->onenand.base);
0080 out_release_mem_region:
0081     release_mem_region(res->start, size);
0082 out_free_info:
0083     kfree(info);
0084 
0085     return err;
0086 }
0087 
0088 static int generic_onenand_remove(struct platform_device *pdev)
0089 {
0090     struct onenand_info *info = platform_get_drvdata(pdev);
0091     struct resource *res = pdev->resource;
0092     unsigned long size = resource_size(res);
0093 
0094     if (info) {
0095         onenand_release(&info->mtd);
0096         release_mem_region(res->start, size);
0097         iounmap(info->onenand.base);
0098         kfree(info);
0099     }
0100 
0101     return 0;
0102 }
0103 
0104 static struct platform_driver generic_onenand_driver = {
0105     .driver = {
0106         .name       = DRIVER_NAME,
0107     },
0108     .probe      = generic_onenand_probe,
0109     .remove     = generic_onenand_remove,
0110 };
0111 
0112 module_platform_driver(generic_onenand_driver);
0113 
0114 MODULE_LICENSE("GPL");
0115 MODULE_AUTHOR("Kyungmin Park <kyungmin.park@samsung.com>");
0116 MODULE_DESCRIPTION("Glue layer for OneNAND flash on generic boards");
0117 MODULE_ALIAS("platform:" DRIVER_NAME);