xref: /linux/drivers/mtd/nand/onenand/generic.c (revision 75bf465f0bc33e9b776a46d6a1b9b990f5fb7c37)
1*d2912cb1SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
268ee4b1cSKyungmin Park /*
368ee4b1cSKyungmin Park  *  Copyright (c) 2005 Samsung Electronics
468ee4b1cSKyungmin Park  *  Kyungmin Park <kyungmin.park@samsung.com>
568ee4b1cSKyungmin Park  *
668ee4b1cSKyungmin Park  *  Overview:
768ee4b1cSKyungmin Park  *   This is a device driver for the OneNAND flash for generic boards.
868ee4b1cSKyungmin Park  */
968ee4b1cSKyungmin Park 
1068ee4b1cSKyungmin Park #include <linux/module.h>
11de25968cSTim Schmielau #include <linux/slab.h>
1227f4e083SKyungmin Park #include <linux/platform_device.h>
1368ee4b1cSKyungmin Park #include <linux/mtd/mtd.h>
1468ee4b1cSKyungmin Park #include <linux/mtd/onenand.h>
1568ee4b1cSKyungmin Park #include <linux/mtd/partitions.h>
162584cf83SDan Williams #include <linux/io.h>
1768ee4b1cSKyungmin Park 
18778dbcc1SMagnus Damm /*
19778dbcc1SMagnus Damm  * Note: Driver name and platform data format have been updated!
20778dbcc1SMagnus Damm  *
21778dbcc1SMagnus Damm  * This version of the driver is named "onenand-flash" and takes struct
22778dbcc1SMagnus Damm  * onenand_platform_data as platform data. The old ARM-specific version
23778dbcc1SMagnus Damm  * with the name "onenand" used to take struct flash_platform_data.
24778dbcc1SMagnus Damm  */
25778dbcc1SMagnus Damm #define DRIVER_NAME	"onenand-flash"
2668ee4b1cSKyungmin Park 
2768ee4b1cSKyungmin Park struct onenand_info {
2868ee4b1cSKyungmin Park 	struct mtd_info		mtd;
2968ee4b1cSKyungmin Park 	struct onenand_chip	onenand;
3068ee4b1cSKyungmin Park };
3168ee4b1cSKyungmin Park 
3206f25510SBill Pemberton static int generic_onenand_probe(struct platform_device *pdev)
3368ee4b1cSKyungmin Park {
3468ee4b1cSKyungmin Park 	struct onenand_info *info;
35e09f7f99SJingoo Han 	struct onenand_platform_data *pdata = dev_get_platdata(&pdev->dev);
3668ee4b1cSKyungmin Park 	struct resource *res = pdev->resource;
37778dbcc1SMagnus Damm 	unsigned long size = resource_size(res);
3868ee4b1cSKyungmin Park 	int err;
3968ee4b1cSKyungmin Park 
4095b93a0cSBurman Yan 	info = kzalloc(sizeof(struct onenand_info), GFP_KERNEL);
4168ee4b1cSKyungmin Park 	if (!info)
4268ee4b1cSKyungmin Park 		return -ENOMEM;
4368ee4b1cSKyungmin Park 
44778dbcc1SMagnus Damm 	if (!request_mem_region(res->start, size, dev_name(&pdev->dev))) {
4568ee4b1cSKyungmin Park 		err = -EBUSY;
4668ee4b1cSKyungmin Park 		goto out_free_info;
4768ee4b1cSKyungmin Park 	}
4868ee4b1cSKyungmin Park 
4968ee4b1cSKyungmin Park 	info->onenand.base = ioremap(res->start, size);
5068ee4b1cSKyungmin Park 	if (!info->onenand.base) {
5168ee4b1cSKyungmin Park 		err = -ENOMEM;
5268ee4b1cSKyungmin Park 		goto out_release_mem_region;
5368ee4b1cSKyungmin Park 	}
5468ee4b1cSKyungmin Park 
558b3ae733SBrian Norris 	info->onenand.mmcontrol = pdata ? pdata->mmcontrol : NULL;
562c22120fSKyungmin Park 	info->onenand.irq = platform_get_irq(pdev, 0);
5768ee4b1cSKyungmin Park 
58fe003bc8SFrans Klaver 	info->mtd.dev.parent = &pdev->dev;
5968ee4b1cSKyungmin Park 	info->mtd.priv = &info->onenand;
6068ee4b1cSKyungmin Park 
6168ee4b1cSKyungmin Park 	if (onenand_scan(&info->mtd, 1)) {
6268ee4b1cSKyungmin Park 		err = -ENXIO;
6368ee4b1cSKyungmin Park 		goto out_iounmap;
6468ee4b1cSKyungmin Park 	}
6568ee4b1cSKyungmin Park 
66e8b0ac39SRafał Miłecki 	err = mtd_device_register(&info->mtd, pdata ? pdata->parts : NULL,
6792ffb00dSDmitry Eremin-Solenikov 				  pdata ? pdata->nr_parts : 0);
6868ee4b1cSKyungmin Park 
697a192ec3SMing Lei 	platform_set_drvdata(pdev, info);
7068ee4b1cSKyungmin Park 
7168ee4b1cSKyungmin Park 	return 0;
7268ee4b1cSKyungmin Park 
7368ee4b1cSKyungmin Park out_iounmap:
7468ee4b1cSKyungmin Park 	iounmap(info->onenand.base);
7568ee4b1cSKyungmin Park out_release_mem_region:
7668ee4b1cSKyungmin Park 	release_mem_region(res->start, size);
7768ee4b1cSKyungmin Park out_free_info:
7868ee4b1cSKyungmin Park 	kfree(info);
7968ee4b1cSKyungmin Park 
8068ee4b1cSKyungmin Park 	return err;
8168ee4b1cSKyungmin Park }
8268ee4b1cSKyungmin Park 
83810b7e06SBill Pemberton static int generic_onenand_remove(struct platform_device *pdev)
8468ee4b1cSKyungmin Park {
857a192ec3SMing Lei 	struct onenand_info *info = platform_get_drvdata(pdev);
8668ee4b1cSKyungmin Park 	struct resource *res = pdev->resource;
87778dbcc1SMagnus Damm 	unsigned long size = resource_size(res);
8868ee4b1cSKyungmin Park 
8968ee4b1cSKyungmin Park 	if (info) {
9068ee4b1cSKyungmin Park 		onenand_release(&info->mtd);
9168ee4b1cSKyungmin Park 		release_mem_region(res->start, size);
9268ee4b1cSKyungmin Park 		iounmap(info->onenand.base);
9368ee4b1cSKyungmin Park 		kfree(info);
9468ee4b1cSKyungmin Park 	}
9568ee4b1cSKyungmin Park 
9668ee4b1cSKyungmin Park 	return 0;
9768ee4b1cSKyungmin Park }
9868ee4b1cSKyungmin Park 
997a192ec3SMing Lei static struct platform_driver generic_onenand_driver = {
1007a192ec3SMing Lei 	.driver = {
10168ee4b1cSKyungmin Park 		.name		= DRIVER_NAME,
1027a192ec3SMing Lei 	},
10368ee4b1cSKyungmin Park 	.probe		= generic_onenand_probe,
1045153b88cSBill Pemberton 	.remove		= generic_onenand_remove,
10568ee4b1cSKyungmin Park };
10668ee4b1cSKyungmin Park 
107f99640deSAxel Lin module_platform_driver(generic_onenand_driver);
10868ee4b1cSKyungmin Park 
10968ee4b1cSKyungmin Park MODULE_LICENSE("GPL");
11068ee4b1cSKyungmin Park MODULE_AUTHOR("Kyungmin Park <kyungmin.park@samsung.com>");
11168ee4b1cSKyungmin Park MODULE_DESCRIPTION("Glue layer for OneNAND flash on generic boards");
112f99640deSAxel Lin MODULE_ALIAS("platform:" DRIVER_NAME);
113