1/* 2 * rbtx4939-flash (based on physmap.c) 3 * 4 * This is a simplified physmap driver with map_init callback function. 5 * 6 * This program is free software; you can redistribute it and/or modify 7 * it under the terms of the GNU General Public License version 2 as 8 * published by the Free Software Foundation. 9 * 10 * Copyright (C) 2009 Atsushi Nemoto <anemo@mba.ocn.ne.jp> 11 */ 12 13#include <linux/module.h> 14#include <linux/types.h> 15#include <linux/kernel.h> 16#include <linux/slab.h> 17#include <linux/device.h> 18#include <linux/platform_device.h> 19#include <linux/mtd/mtd.h> 20#include <linux/mtd/map.h> 21#include <linux/mtd/partitions.h> 22#include <asm/txx9/rbtx4939.h> 23 24struct rbtx4939_flash_info { 25 struct mtd_info *mtd; 26 struct map_info map; 27}; 28 29static int rbtx4939_flash_remove(struct platform_device *dev) 30{ 31 struct rbtx4939_flash_info *info; 32 33 info = platform_get_drvdata(dev); 34 if (!info) 35 return 0; 36 37 if (info->mtd) { 38 mtd_device_unregister(info->mtd); 39 map_destroy(info->mtd); 40 } 41 return 0; 42} 43 44static const char * const rom_probe_types[] = { 45 "cfi_probe", "jedec_probe", NULL }; 46 47static int rbtx4939_flash_probe(struct platform_device *dev) 48{ 49 struct rbtx4939_flash_data *pdata; 50 struct rbtx4939_flash_info *info; 51 struct resource *res; 52 const char * const *probe_type; 53 int err = 0; 54 unsigned long size; 55 56 pdata = dev_get_platdata(&dev->dev); 57 if (!pdata) 58 return -ENODEV; 59 60 res = platform_get_resource(dev, IORESOURCE_MEM, 0); 61 if (!res) 62 return -ENODEV; 63 info = devm_kzalloc(&dev->dev, sizeof(struct rbtx4939_flash_info), 64 GFP_KERNEL); 65 if (!info) 66 return -ENOMEM; 67 68 platform_set_drvdata(dev, info); 69 70 size = resource_size(res); 71 pr_notice("rbtx4939 platform flash device: %pR\n", res); 72 73 if (!devm_request_mem_region(&dev->dev, res->start, size, 74 dev_name(&dev->dev))) 75 return -EBUSY; 76 77 info->map.name = dev_name(&dev->dev); 78 info->map.phys = res->start; 79 info->map.size = size; 80 info->map.bankwidth = pdata->width; 81 82 info->map.virt = devm_ioremap(&dev->dev, info->map.phys, size); 83 if (!info->map.virt) 84 return -EBUSY; 85 86 if (pdata->map_init) 87 (*pdata->map_init)(&info->map); 88 else 89 simple_map_init(&info->map); 90 91 probe_type = rom_probe_types; 92 for (; !info->mtd && *probe_type; probe_type++) 93 info->mtd = do_map_probe(*probe_type, &info->map); 94 if (!info->mtd) { 95 dev_err(&dev->dev, "map_probe failed\n"); 96 err = -ENXIO; 97 goto err_out; 98 } 99 info->mtd->dev.parent = &dev->dev; 100 err = mtd_device_parse_register(info->mtd, NULL, NULL, pdata->parts, 101 pdata->nr_parts); 102 103 if (err) 104 goto err_out; 105 return 0; 106 107err_out: 108 rbtx4939_flash_remove(dev); 109 return err; 110} 111 112#ifdef CONFIG_PM 113static void rbtx4939_flash_shutdown(struct platform_device *dev) 114{ 115 struct rbtx4939_flash_info *info = platform_get_drvdata(dev); 116 117 if (mtd_suspend(info->mtd) == 0) 118 mtd_resume(info->mtd); 119} 120#else 121#define rbtx4939_flash_shutdown NULL 122#endif 123 124static struct platform_driver rbtx4939_flash_driver = { 125 .probe = rbtx4939_flash_probe, 126 .remove = rbtx4939_flash_remove, 127 .shutdown = rbtx4939_flash_shutdown, 128 .driver = { 129 .name = "rbtx4939-flash", 130 }, 131}; 132 133module_platform_driver(rbtx4939_flash_driver); 134 135MODULE_LICENSE("GPL"); 136MODULE_DESCRIPTION("RBTX4939 MTD map driver"); 137MODULE_ALIAS("platform:rbtx4939-flash"); 138