18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * rbtx4939-flash (based on physmap.c) 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * This is a simplified physmap driver with map_init callback function. 68c2ecf20Sopenharmony_ci * 78c2ecf20Sopenharmony_ci * Copyright (C) 2009 Atsushi Nemoto <anemo@mba.ocn.ne.jp> 88c2ecf20Sopenharmony_ci */ 98c2ecf20Sopenharmony_ci 108c2ecf20Sopenharmony_ci#include <linux/module.h> 118c2ecf20Sopenharmony_ci#include <linux/types.h> 128c2ecf20Sopenharmony_ci#include <linux/kernel.h> 138c2ecf20Sopenharmony_ci#include <linux/slab.h> 148c2ecf20Sopenharmony_ci#include <linux/device.h> 158c2ecf20Sopenharmony_ci#include <linux/platform_device.h> 168c2ecf20Sopenharmony_ci#include <linux/mtd/mtd.h> 178c2ecf20Sopenharmony_ci#include <linux/mtd/map.h> 188c2ecf20Sopenharmony_ci#include <linux/mtd/partitions.h> 198c2ecf20Sopenharmony_ci#include <asm/txx9/rbtx4939.h> 208c2ecf20Sopenharmony_ci 218c2ecf20Sopenharmony_cistruct rbtx4939_flash_info { 228c2ecf20Sopenharmony_ci struct mtd_info *mtd; 238c2ecf20Sopenharmony_ci struct map_info map; 248c2ecf20Sopenharmony_ci}; 258c2ecf20Sopenharmony_ci 268c2ecf20Sopenharmony_cistatic int rbtx4939_flash_remove(struct platform_device *dev) 278c2ecf20Sopenharmony_ci{ 288c2ecf20Sopenharmony_ci struct rbtx4939_flash_info *info; 298c2ecf20Sopenharmony_ci 308c2ecf20Sopenharmony_ci info = platform_get_drvdata(dev); 318c2ecf20Sopenharmony_ci if (!info) 328c2ecf20Sopenharmony_ci return 0; 338c2ecf20Sopenharmony_ci 348c2ecf20Sopenharmony_ci if (info->mtd) { 358c2ecf20Sopenharmony_ci mtd_device_unregister(info->mtd); 368c2ecf20Sopenharmony_ci map_destroy(info->mtd); 378c2ecf20Sopenharmony_ci } 388c2ecf20Sopenharmony_ci return 0; 398c2ecf20Sopenharmony_ci} 408c2ecf20Sopenharmony_ci 418c2ecf20Sopenharmony_cistatic const char * const rom_probe_types[] = { 428c2ecf20Sopenharmony_ci "cfi_probe", "jedec_probe", NULL }; 438c2ecf20Sopenharmony_ci 448c2ecf20Sopenharmony_cistatic int rbtx4939_flash_probe(struct platform_device *dev) 458c2ecf20Sopenharmony_ci{ 468c2ecf20Sopenharmony_ci struct rbtx4939_flash_data *pdata; 478c2ecf20Sopenharmony_ci struct rbtx4939_flash_info *info; 488c2ecf20Sopenharmony_ci struct resource *res; 498c2ecf20Sopenharmony_ci const char * const *probe_type; 508c2ecf20Sopenharmony_ci int err = 0; 518c2ecf20Sopenharmony_ci unsigned long size; 528c2ecf20Sopenharmony_ci 538c2ecf20Sopenharmony_ci pdata = dev_get_platdata(&dev->dev); 548c2ecf20Sopenharmony_ci if (!pdata) 558c2ecf20Sopenharmony_ci return -ENODEV; 568c2ecf20Sopenharmony_ci 578c2ecf20Sopenharmony_ci res = platform_get_resource(dev, IORESOURCE_MEM, 0); 588c2ecf20Sopenharmony_ci if (!res) 598c2ecf20Sopenharmony_ci return -ENODEV; 608c2ecf20Sopenharmony_ci info = devm_kzalloc(&dev->dev, sizeof(struct rbtx4939_flash_info), 618c2ecf20Sopenharmony_ci GFP_KERNEL); 628c2ecf20Sopenharmony_ci if (!info) 638c2ecf20Sopenharmony_ci return -ENOMEM; 648c2ecf20Sopenharmony_ci 658c2ecf20Sopenharmony_ci platform_set_drvdata(dev, info); 668c2ecf20Sopenharmony_ci 678c2ecf20Sopenharmony_ci size = resource_size(res); 688c2ecf20Sopenharmony_ci pr_notice("rbtx4939 platform flash device: %pR\n", res); 698c2ecf20Sopenharmony_ci 708c2ecf20Sopenharmony_ci if (!devm_request_mem_region(&dev->dev, res->start, size, 718c2ecf20Sopenharmony_ci dev_name(&dev->dev))) 728c2ecf20Sopenharmony_ci return -EBUSY; 738c2ecf20Sopenharmony_ci 748c2ecf20Sopenharmony_ci info->map.name = dev_name(&dev->dev); 758c2ecf20Sopenharmony_ci info->map.phys = res->start; 768c2ecf20Sopenharmony_ci info->map.size = size; 778c2ecf20Sopenharmony_ci info->map.bankwidth = pdata->width; 788c2ecf20Sopenharmony_ci 798c2ecf20Sopenharmony_ci info->map.virt = devm_ioremap(&dev->dev, info->map.phys, size); 808c2ecf20Sopenharmony_ci if (!info->map.virt) 818c2ecf20Sopenharmony_ci return -EBUSY; 828c2ecf20Sopenharmony_ci 838c2ecf20Sopenharmony_ci if (pdata->map_init) 848c2ecf20Sopenharmony_ci (*pdata->map_init)(&info->map); 858c2ecf20Sopenharmony_ci else 868c2ecf20Sopenharmony_ci simple_map_init(&info->map); 878c2ecf20Sopenharmony_ci 888c2ecf20Sopenharmony_ci probe_type = rom_probe_types; 898c2ecf20Sopenharmony_ci for (; !info->mtd && *probe_type; probe_type++) 908c2ecf20Sopenharmony_ci info->mtd = do_map_probe(*probe_type, &info->map); 918c2ecf20Sopenharmony_ci if (!info->mtd) { 928c2ecf20Sopenharmony_ci dev_err(&dev->dev, "map_probe failed\n"); 938c2ecf20Sopenharmony_ci err = -ENXIO; 948c2ecf20Sopenharmony_ci goto err_out; 958c2ecf20Sopenharmony_ci } 968c2ecf20Sopenharmony_ci info->mtd->dev.parent = &dev->dev; 978c2ecf20Sopenharmony_ci err = mtd_device_register(info->mtd, pdata->parts, pdata->nr_parts); 988c2ecf20Sopenharmony_ci 998c2ecf20Sopenharmony_ci if (err) 1008c2ecf20Sopenharmony_ci goto err_out; 1018c2ecf20Sopenharmony_ci return 0; 1028c2ecf20Sopenharmony_ci 1038c2ecf20Sopenharmony_cierr_out: 1048c2ecf20Sopenharmony_ci rbtx4939_flash_remove(dev); 1058c2ecf20Sopenharmony_ci return err; 1068c2ecf20Sopenharmony_ci} 1078c2ecf20Sopenharmony_ci 1088c2ecf20Sopenharmony_ci#ifdef CONFIG_PM 1098c2ecf20Sopenharmony_cistatic void rbtx4939_flash_shutdown(struct platform_device *dev) 1108c2ecf20Sopenharmony_ci{ 1118c2ecf20Sopenharmony_ci struct rbtx4939_flash_info *info = platform_get_drvdata(dev); 1128c2ecf20Sopenharmony_ci 1138c2ecf20Sopenharmony_ci if (mtd_suspend(info->mtd) == 0) 1148c2ecf20Sopenharmony_ci mtd_resume(info->mtd); 1158c2ecf20Sopenharmony_ci} 1168c2ecf20Sopenharmony_ci#else 1178c2ecf20Sopenharmony_ci#define rbtx4939_flash_shutdown NULL 1188c2ecf20Sopenharmony_ci#endif 1198c2ecf20Sopenharmony_ci 1208c2ecf20Sopenharmony_cistatic struct platform_driver rbtx4939_flash_driver = { 1218c2ecf20Sopenharmony_ci .probe = rbtx4939_flash_probe, 1228c2ecf20Sopenharmony_ci .remove = rbtx4939_flash_remove, 1238c2ecf20Sopenharmony_ci .shutdown = rbtx4939_flash_shutdown, 1248c2ecf20Sopenharmony_ci .driver = { 1258c2ecf20Sopenharmony_ci .name = "rbtx4939-flash", 1268c2ecf20Sopenharmony_ci }, 1278c2ecf20Sopenharmony_ci}; 1288c2ecf20Sopenharmony_ci 1298c2ecf20Sopenharmony_cimodule_platform_driver(rbtx4939_flash_driver); 1308c2ecf20Sopenharmony_ci 1318c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL"); 1328c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("RBTX4939 MTD map driver"); 1338c2ecf20Sopenharmony_ciMODULE_ALIAS("platform:rbtx4939-flash"); 134