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