Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

at v3.11-rc1 232 lines 5.5 kB view raw
1/* 2 * Interface for NOR flash driver whose high address lines are latched 3 * 4 * Copyright © 2000 Nicolas Pitre <nico@cam.org> 5 * Copyright © 2005-2008 Analog Devices Inc. 6 * Copyright © 2008 MontaVista Software, Inc. <source@mvista.com> 7 * 8 * This file is licensed under the terms of the GNU General Public License 9 * version 2. This program is licensed "as is" without any warranty of any 10 * kind, whether express or implied. 11 */ 12 13#include <linux/init.h> 14#include <linux/kernel.h> 15#include <linux/module.h> 16#include <linux/mtd/mtd.h> 17#include <linux/mtd/map.h> 18#include <linux/mtd/partitions.h> 19#include <linux/platform_device.h> 20#include <linux/mtd/latch-addr-flash.h> 21#include <linux/slab.h> 22 23#define DRIVER_NAME "latch-addr-flash" 24 25struct latch_addr_flash_info { 26 struct mtd_info *mtd; 27 struct map_info map; 28 struct resource *res; 29 30 void (*set_window)(unsigned long offset, void *data); 31 void *data; 32 33 /* cache; could be found out of res */ 34 unsigned long win_mask; 35 36 spinlock_t lock; 37}; 38 39static map_word lf_read(struct map_info *map, unsigned long ofs) 40{ 41 struct latch_addr_flash_info *info; 42 map_word datum; 43 44 info = (struct latch_addr_flash_info *)map->map_priv_1; 45 46 spin_lock(&info->lock); 47 48 info->set_window(ofs, info->data); 49 datum = inline_map_read(map, info->win_mask & ofs); 50 51 spin_unlock(&info->lock); 52 53 return datum; 54} 55 56static void lf_write(struct map_info *map, map_word datum, unsigned long ofs) 57{ 58 struct latch_addr_flash_info *info; 59 60 info = (struct latch_addr_flash_info *)map->map_priv_1; 61 62 spin_lock(&info->lock); 63 64 info->set_window(ofs, info->data); 65 inline_map_write(map, datum, info->win_mask & ofs); 66 67 spin_unlock(&info->lock); 68} 69 70static void lf_copy_from(struct map_info *map, void *to, 71 unsigned long from, ssize_t len) 72{ 73 struct latch_addr_flash_info *info = 74 (struct latch_addr_flash_info *) map->map_priv_1; 75 unsigned n; 76 77 while (len > 0) { 78 n = info->win_mask + 1 - (from & info->win_mask); 79 if (n > len) 80 n = len; 81 82 spin_lock(&info->lock); 83 84 info->set_window(from, info->data); 85 memcpy_fromio(to, map->virt + (from & info->win_mask), n); 86 87 spin_unlock(&info->lock); 88 89 to += n; 90 from += n; 91 len -= n; 92 } 93} 94 95static char *rom_probe_types[] = { "cfi_probe", NULL }; 96 97static int latch_addr_flash_remove(struct platform_device *dev) 98{ 99 struct latch_addr_flash_info *info; 100 struct latch_addr_flash_data *latch_addr_data; 101 102 info = platform_get_drvdata(dev); 103 if (info == NULL) 104 return 0; 105 platform_set_drvdata(dev, NULL); 106 107 latch_addr_data = dev->dev.platform_data; 108 109 if (info->mtd != NULL) { 110 mtd_device_unregister(info->mtd); 111 map_destroy(info->mtd); 112 } 113 114 if (info->map.virt != NULL) 115 iounmap(info->map.virt); 116 117 if (info->res != NULL) 118 release_mem_region(info->res->start, resource_size(info->res)); 119 120 kfree(info); 121 122 if (latch_addr_data->done) 123 latch_addr_data->done(latch_addr_data->data); 124 125 return 0; 126} 127 128static int latch_addr_flash_probe(struct platform_device *dev) 129{ 130 struct latch_addr_flash_data *latch_addr_data; 131 struct latch_addr_flash_info *info; 132 resource_size_t win_base = dev->resource->start; 133 resource_size_t win_size = resource_size(dev->resource); 134 char **probe_type; 135 int chipsel; 136 int err; 137 138 latch_addr_data = dev->dev.platform_data; 139 if (latch_addr_data == NULL) 140 return -ENODEV; 141 142 pr_notice("latch-addr platform flash device: %#llx byte " 143 "window at %#.8llx\n", 144 (unsigned long long)win_size, (unsigned long long)win_base); 145 146 chipsel = dev->id; 147 148 if (latch_addr_data->init) { 149 err = latch_addr_data->init(latch_addr_data->data, chipsel); 150 if (err != 0) 151 return err; 152 } 153 154 info = kzalloc(sizeof(struct latch_addr_flash_info), GFP_KERNEL); 155 if (info == NULL) { 156 err = -ENOMEM; 157 goto done; 158 } 159 160 platform_set_drvdata(dev, info); 161 162 info->res = request_mem_region(win_base, win_size, DRIVER_NAME); 163 if (info->res == NULL) { 164 dev_err(&dev->dev, "Could not reserve memory region\n"); 165 err = -EBUSY; 166 goto free_info; 167 } 168 169 info->map.name = DRIVER_NAME; 170 info->map.size = latch_addr_data->size; 171 info->map.bankwidth = latch_addr_data->width; 172 173 info->map.phys = NO_XIP; 174 info->map.virt = ioremap(win_base, win_size); 175 if (!info->map.virt) { 176 err = -ENOMEM; 177 goto free_res; 178 } 179 180 info->map.map_priv_1 = (unsigned long)info; 181 182 info->map.read = lf_read; 183 info->map.copy_from = lf_copy_from; 184 info->map.write = lf_write; 185 info->set_window = latch_addr_data->set_window; 186 info->data = latch_addr_data->data; 187 info->win_mask = win_size - 1; 188 189 spin_lock_init(&info->lock); 190 191 for (probe_type = rom_probe_types; !info->mtd && *probe_type; 192 probe_type++) 193 info->mtd = do_map_probe(*probe_type, &info->map); 194 195 if (info->mtd == NULL) { 196 dev_err(&dev->dev, "map_probe failed\n"); 197 err = -ENODEV; 198 goto iounmap; 199 } 200 info->mtd->owner = THIS_MODULE; 201 202 mtd_device_parse_register(info->mtd, NULL, NULL, 203 latch_addr_data->parts, 204 latch_addr_data->nr_parts); 205 return 0; 206 207iounmap: 208 iounmap(info->map.virt); 209free_res: 210 release_mem_region(info->res->start, resource_size(info->res)); 211free_info: 212 kfree(info); 213done: 214 if (latch_addr_data->done) 215 latch_addr_data->done(latch_addr_data->data); 216 return err; 217} 218 219static struct platform_driver latch_addr_flash_driver = { 220 .probe = latch_addr_flash_probe, 221 .remove = latch_addr_flash_remove, 222 .driver = { 223 .name = DRIVER_NAME, 224 }, 225}; 226 227module_platform_driver(latch_addr_flash_driver); 228 229MODULE_AUTHOR("David Griego <dgriego@mvista.com>"); 230MODULE_DESCRIPTION("MTD map driver for flashes addressed physically with upper " 231 "address lines being set board specifically"); 232MODULE_LICENSE("GPL v2");