gpio-addr-flash.c revision d20d5a5780a014bc4d24dbcb6daf7673a9dddf98
1/* 2 * drivers/mtd/maps/gpio-addr-flash.c 3 * 4 * Handle the case where a flash device is mostly addressed using physical 5 * line and supplemented by GPIOs. This way you can hook up say a 8MiB flash 6 * to a 2MiB memory range and use the GPIOs to select a particular range. 7 * 8 * Copyright © 2000 Nicolas Pitre <nico@cam.org> 9 * Copyright © 2005-2009 Analog Devices Inc. 10 * 11 * Enter bugs at http://blackfin.uclinux.org/ 12 * 13 * Licensed under the GPL-2 or later. 14 */ 15 16#include <linux/gpio.h> 17#include <linux/init.h> 18#include <linux/io.h> 19#include <linux/kernel.h> 20#include <linux/module.h> 21#include <linux/mtd/mtd.h> 22#include <linux/mtd/map.h> 23#include <linux/mtd/partitions.h> 24#include <linux/mtd/physmap.h> 25#include <linux/platform_device.h> 26#include <linux/slab.h> 27#include <linux/types.h> 28 29#define pr_devinit(fmt, args...) \ 30 ({ static const char __fmt[] = fmt; printk(__fmt, ## args); }) 31 32#define DRIVER_NAME "gpio-addr-flash" 33#define PFX DRIVER_NAME ": " 34 35/** 36 * struct async_state - keep GPIO flash state 37 * @mtd: MTD state for this mapping 38 * @map: MTD map state for this flash 39 * @gpio_count: number of GPIOs used to address 40 * @gpio_addrs: array of GPIOs to twiddle 41 * @gpio_values: cached GPIO values 42 * @win_size: dedicated memory size (if no GPIOs) 43 */ 44struct async_state { 45 struct mtd_info *mtd; 46 struct map_info map; 47 size_t gpio_count; 48 unsigned *gpio_addrs; 49 int *gpio_values; 50 unsigned long win_size; 51}; 52#define gf_map_info_to_state(mi) ((struct async_state *)(mi)->map_priv_1) 53 54/** 55 * gf_set_gpios() - set GPIO address lines to access specified flash offset 56 * @state: GPIO flash state 57 * @ofs: desired offset to access 58 * 59 * Rather than call the GPIO framework every time, cache the last-programmed 60 * value. This speeds up sequential accesses (which are by far the most common 61 * type). We rely on the GPIO framework to treat non-zero value as high so 62 * that we don't have to normalize the bits. 63 */ 64static void gf_set_gpios(struct async_state *state, unsigned long ofs) 65{ 66 size_t i = 0; 67 int value; 68 ofs /= state->win_size; 69 do { 70 value = ofs & (1 << i); 71 if (state->gpio_values[i] != value) { 72 gpio_set_value(state->gpio_addrs[i], value); 73 state->gpio_values[i] = value; 74 } 75 } while (++i < state->gpio_count); 76} 77 78/** 79 * gf_read() - read a word at the specified offset 80 * @map: MTD map state 81 * @ofs: desired offset to read 82 */ 83static map_word gf_read(struct map_info *map, unsigned long ofs) 84{ 85 struct async_state *state = gf_map_info_to_state(map); 86 uint16_t word; 87 map_word test; 88 89 gf_set_gpios(state, ofs); 90 91 word = readw(map->virt + (ofs % state->win_size)); 92 test.x[0] = word; 93 return test; 94} 95 96/** 97 * gf_copy_from() - copy a chunk of data from the flash 98 * @map: MTD map state 99 * @to: memory to copy to 100 * @from: flash offset to copy from 101 * @len: how much to copy 102 * 103 * We rely on the MTD layer to chunk up copies such that a single request here 104 * will not cross a window size. This allows us to only wiggle the GPIOs once 105 * before falling back to a normal memcpy. Reading the higher layer code shows 106 * that this is indeed the case, but add a BUG_ON() to future proof. 107 */ 108static void gf_copy_from(struct map_info *map, void *to, unsigned long from, ssize_t len) 109{ 110 struct async_state *state = gf_map_info_to_state(map); 111 112 gf_set_gpios(state, from); 113 114 /* BUG if operation crosses the win_size */ 115 BUG_ON(!((from + len) % state->win_size <= (from + len))); 116 117 /* operation does not cross the win_size, so one shot it */ 118 memcpy_fromio(to, map->virt + (from % state->win_size), len); 119} 120 121/** 122 * gf_write() - write a word at the specified offset 123 * @map: MTD map state 124 * @ofs: desired offset to write 125 */ 126static void gf_write(struct map_info *map, map_word d1, unsigned long ofs) 127{ 128 struct async_state *state = gf_map_info_to_state(map); 129 uint16_t d; 130 131 gf_set_gpios(state, ofs); 132 133 d = d1.x[0]; 134 writew(d, map->virt + (ofs % state->win_size)); 135} 136 137/** 138 * gf_copy_to() - copy a chunk of data to the flash 139 * @map: MTD map state 140 * @to: flash offset to copy to 141 * @from: memory to copy from 142 * @len: how much to copy 143 * 144 * See gf_copy_from() caveat. 145 */ 146static void gf_copy_to(struct map_info *map, unsigned long to, 147 const void *from, ssize_t len) 148{ 149 struct async_state *state = gf_map_info_to_state(map); 150 151 gf_set_gpios(state, to); 152 153 /* BUG if operation crosses the win_size */ 154 BUG_ON(!((to + len) % state->win_size <= (to + len))); 155 156 /* operation does not cross the win_size, so one shot it */ 157 memcpy_toio(map->virt + (to % state->win_size), from, len); 158} 159 160static const char * const part_probe_types[] = { 161 "cmdlinepart", "RedBoot", NULL }; 162 163/** 164 * gpio_flash_probe() - setup a mapping for a GPIO assisted flash 165 * @pdev: platform device 166 * 167 * The platform resource layout expected looks something like: 168 * struct mtd_partition partitions[] = { ... }; 169 * struct physmap_flash_data flash_data = { ... }; 170 * unsigned flash_gpios[] = { GPIO_XX, GPIO_XX, ... }; 171 * struct resource flash_resource[] = { 172 * { 173 * .name = "cfi_probe", 174 * .start = 0x20000000, 175 * .end = 0x201fffff, 176 * .flags = IORESOURCE_MEM, 177 * }, { 178 * .start = (unsigned long)flash_gpios, 179 * .end = ARRAY_SIZE(flash_gpios), 180 * .flags = IORESOURCE_IRQ, 181 * } 182 * }; 183 * struct platform_device flash_device = { 184 * .name = "gpio-addr-flash", 185 * .dev = { .platform_data = &flash_data, }, 186 * .num_resources = ARRAY_SIZE(flash_resource), 187 * .resource = flash_resource, 188 * ... 189 * }; 190 */ 191static int gpio_flash_probe(struct platform_device *pdev) 192{ 193 size_t i, arr_size; 194 struct physmap_flash_data *pdata; 195 struct resource *memory; 196 struct resource *gpios; 197 struct async_state *state; 198 199 pdata = dev_get_platdata(&pdev->dev); 200 memory = platform_get_resource(pdev, IORESOURCE_MEM, 0); 201 gpios = platform_get_resource(pdev, IORESOURCE_IRQ, 0); 202 203 if (!memory || !gpios || !gpios->end) 204 return -EINVAL; 205 206 arr_size = sizeof(int) * gpios->end; 207 state = kzalloc(sizeof(*state) + arr_size, GFP_KERNEL); 208 if (!state) 209 return -ENOMEM; 210 211 /* 212 * We cast start/end to known types in the boards file, so cast 213 * away their pointer types here to the known types (gpios->xxx). 214 */ 215 state->gpio_count = gpios->end; 216 state->gpio_addrs = (void *)(unsigned long)gpios->start; 217 state->gpio_values = (void *)(state + 1); 218 state->win_size = resource_size(memory); 219 memset(state->gpio_values, 0xff, arr_size); 220 221 state->map.name = DRIVER_NAME; 222 state->map.read = gf_read; 223 state->map.copy_from = gf_copy_from; 224 state->map.write = gf_write; 225 state->map.copy_to = gf_copy_to; 226 state->map.bankwidth = pdata->width; 227 state->map.size = state->win_size * (1 << state->gpio_count); 228 state->map.virt = ioremap_nocache(memory->start, state->map.size); 229 state->map.phys = NO_XIP; 230 state->map.map_priv_1 = (unsigned long)state; 231 232 platform_set_drvdata(pdev, state); 233 234 i = 0; 235 do { 236 if (gpio_request(state->gpio_addrs[i], DRIVER_NAME)) { 237 pr_devinit(KERN_ERR PFX "failed to request gpio %d\n", 238 state->gpio_addrs[i]); 239 while (i--) 240 gpio_free(state->gpio_addrs[i]); 241 kfree(state); 242 return -EBUSY; 243 } 244 gpio_direction_output(state->gpio_addrs[i], 0); 245 } while (++i < state->gpio_count); 246 247 pr_devinit(KERN_NOTICE PFX "probing %d-bit flash bus\n", 248 state->map.bankwidth * 8); 249 state->mtd = do_map_probe(memory->name, &state->map); 250 if (!state->mtd) { 251 for (i = 0; i < state->gpio_count; ++i) 252 gpio_free(state->gpio_addrs[i]); 253 kfree(state); 254 return -ENXIO; 255 } 256 257 258 mtd_device_parse_register(state->mtd, part_probe_types, NULL, 259 pdata->parts, pdata->nr_parts); 260 261 return 0; 262} 263 264static int gpio_flash_remove(struct platform_device *pdev) 265{ 266 struct async_state *state = platform_get_drvdata(pdev); 267 size_t i = 0; 268 do { 269 gpio_free(state->gpio_addrs[i]); 270 } while (++i < state->gpio_count); 271 mtd_device_unregister(state->mtd); 272 map_destroy(state->mtd); 273 kfree(state); 274 return 0; 275} 276 277static struct platform_driver gpio_flash_driver = { 278 .probe = gpio_flash_probe, 279 .remove = gpio_flash_remove, 280 .driver = { 281 .name = DRIVER_NAME, 282 }, 283}; 284 285module_platform_driver(gpio_flash_driver); 286 287MODULE_AUTHOR("Mike Frysinger <vapier@gentoo.org>"); 288MODULE_DESCRIPTION("MTD map driver for flashes addressed physically and with gpios"); 289MODULE_LICENSE("GPL"); 290