bfin-async-flash.c revision 5a0e3ad6af8660be21ca98a971cd00f331318c05
1/* 2 * drivers/mtd/maps/bfin-async-flash.c 3 * 4 * Handle the case where flash memory and ethernet mac/phy are 5 * mapped onto the same async bank. The BF533-STAMP does this 6 * for example. All board-specific configuration goes in your 7 * board resources file. 8 * 9 * Copyright 2000 Nicolas Pitre <nico@fluxnic.net> 10 * Copyright 2005-2008 Analog Devices Inc. 11 * 12 * Enter bugs at http://blackfin.uclinux.org/ 13 * 14 * Licensed under the GPL-2 or later. 15 */ 16 17#include <linux/init.h> 18#include <linux/kernel.h> 19#include <linux/module.h> 20#include <linux/mtd/mtd.h> 21#include <linux/mtd/map.h> 22#include <linux/mtd/partitions.h> 23#include <linux/mtd/physmap.h> 24#include <linux/platform_device.h> 25#include <linux/slab.h> 26#include <linux/types.h> 27 28#include <asm/blackfin.h> 29#include <linux/gpio.h> 30#include <linux/io.h> 31#include <asm/unaligned.h> 32 33#define pr_devinit(fmt, args...) ({ static const __devinitconst char __fmt[] = fmt; printk(__fmt, ## args); }) 34 35#define DRIVER_NAME "bfin-async-flash" 36 37struct async_state { 38 struct mtd_info *mtd; 39 struct map_info map; 40 int enet_flash_pin; 41 uint32_t flash_ambctl0, flash_ambctl1; 42 uint32_t save_ambctl0, save_ambctl1; 43 unsigned long irq_flags; 44#ifdef CONFIG_MTD_PARTITIONS 45 struct mtd_partition *parts; 46#endif 47}; 48 49static void switch_to_flash(struct async_state *state) 50{ 51 local_irq_save(state->irq_flags); 52 53 gpio_set_value(state->enet_flash_pin, 0); 54 55 state->save_ambctl0 = bfin_read_EBIU_AMBCTL0(); 56 state->save_ambctl1 = bfin_read_EBIU_AMBCTL1(); 57 bfin_write_EBIU_AMBCTL0(state->flash_ambctl0); 58 bfin_write_EBIU_AMBCTL1(state->flash_ambctl1); 59 SSYNC(); 60} 61 62static void switch_back(struct async_state *state) 63{ 64 bfin_write_EBIU_AMBCTL0(state->save_ambctl0); 65 bfin_write_EBIU_AMBCTL1(state->save_ambctl1); 66 SSYNC(); 67 68 gpio_set_value(state->enet_flash_pin, 1); 69 70 local_irq_restore(state->irq_flags); 71} 72 73static map_word bfin_read(struct map_info *map, unsigned long ofs) 74{ 75 struct async_state *state = (struct async_state *)map->map_priv_1; 76 uint16_t word; 77 map_word test; 78 79 switch_to_flash(state); 80 81 word = readw(map->virt + ofs); 82 83 switch_back(state); 84 85 test.x[0] = word; 86 return test; 87} 88 89static void bfin_copy_from(struct map_info *map, void *to, unsigned long from, ssize_t len) 90{ 91 struct async_state *state = (struct async_state *)map->map_priv_1; 92 93 switch_to_flash(state); 94 95 memcpy(to, map->virt + from, len); 96 97 switch_back(state); 98} 99 100static void bfin_write(struct map_info *map, map_word d1, unsigned long ofs) 101{ 102 struct async_state *state = (struct async_state *)map->map_priv_1; 103 uint16_t d; 104 105 d = d1.x[0]; 106 107 switch_to_flash(state); 108 109 writew(d, map->virt + ofs); 110 SSYNC(); 111 112 switch_back(state); 113} 114 115static void bfin_copy_to(struct map_info *map, unsigned long to, const void *from, ssize_t len) 116{ 117 struct async_state *state = (struct async_state *)map->map_priv_1; 118 119 switch_to_flash(state); 120 121 memcpy(map->virt + to, from, len); 122 SSYNC(); 123 124 switch_back(state); 125} 126 127#ifdef CONFIG_MTD_PARTITIONS 128static const char *part_probe_types[] = { "cmdlinepart", "RedBoot", NULL }; 129#endif 130 131static int __devinit bfin_flash_probe(struct platform_device *pdev) 132{ 133 int ret; 134 struct physmap_flash_data *pdata = pdev->dev.platform_data; 135 struct resource *memory = platform_get_resource(pdev, IORESOURCE_MEM, 0); 136 struct resource *flash_ambctl = platform_get_resource(pdev, IORESOURCE_MEM, 1); 137 struct async_state *state; 138 139 state = kzalloc(sizeof(*state), GFP_KERNEL); 140 if (!state) 141 return -ENOMEM; 142 143 state->map.name = DRIVER_NAME; 144 state->map.read = bfin_read; 145 state->map.copy_from = bfin_copy_from; 146 state->map.write = bfin_write; 147 state->map.copy_to = bfin_copy_to; 148 state->map.bankwidth = pdata->width; 149 state->map.size = memory->end - memory->start + 1; 150 state->map.virt = (void __iomem *)memory->start; 151 state->map.phys = memory->start; 152 state->map.map_priv_1 = (unsigned long)state; 153 state->enet_flash_pin = platform_get_irq(pdev, 0); 154 state->flash_ambctl0 = flash_ambctl->start; 155 state->flash_ambctl1 = flash_ambctl->end; 156 157 if (gpio_request(state->enet_flash_pin, DRIVER_NAME)) { 158 pr_devinit(KERN_ERR DRIVER_NAME ": Failed to request gpio %d\n", state->enet_flash_pin); 159 kfree(state); 160 return -EBUSY; 161 } 162 gpio_direction_output(state->enet_flash_pin, 1); 163 164 pr_devinit(KERN_NOTICE DRIVER_NAME ": probing %d-bit flash bus\n", state->map.bankwidth * 8); 165 state->mtd = do_map_probe(memory->name, &state->map); 166 if (!state->mtd) { 167 gpio_free(state->enet_flash_pin); 168 kfree(state); 169 return -ENXIO; 170 } 171 172#ifdef CONFIG_MTD_PARTITIONS 173 ret = parse_mtd_partitions(state->mtd, part_probe_types, &pdata->parts, 0); 174 if (ret > 0) { 175 pr_devinit(KERN_NOTICE DRIVER_NAME ": Using commandline partition definition\n"); 176 add_mtd_partitions(state->mtd, pdata->parts, ret); 177 state->parts = pdata->parts; 178 179 } else if (pdata->nr_parts) { 180 pr_devinit(KERN_NOTICE DRIVER_NAME ": Using board partition definition\n"); 181 add_mtd_partitions(state->mtd, pdata->parts, pdata->nr_parts); 182 183 } else 184#endif 185 { 186 pr_devinit(KERN_NOTICE DRIVER_NAME ": no partition info available, registering whole flash at once\n"); 187 add_mtd_device(state->mtd); 188 } 189 190 platform_set_drvdata(pdev, state); 191 192 return 0; 193} 194 195static int __devexit bfin_flash_remove(struct platform_device *pdev) 196{ 197 struct async_state *state = platform_get_drvdata(pdev); 198 gpio_free(state->enet_flash_pin); 199#ifdef CONFIG_MTD_PARTITIONS 200 del_mtd_partitions(state->mtd); 201 kfree(state->parts); 202#endif 203 map_destroy(state->mtd); 204 kfree(state); 205 return 0; 206} 207 208static struct platform_driver bfin_flash_driver = { 209 .probe = bfin_flash_probe, 210 .remove = __devexit_p(bfin_flash_remove), 211 .driver = { 212 .name = DRIVER_NAME, 213 }, 214}; 215 216static int __init bfin_flash_init(void) 217{ 218 return platform_driver_register(&bfin_flash_driver); 219} 220module_init(bfin_flash_init); 221 222static void __exit bfin_flash_exit(void) 223{ 224 platform_driver_unregister(&bfin_flash_driver); 225} 226module_exit(bfin_flash_exit); 227 228MODULE_LICENSE("GPL"); 229MODULE_DESCRIPTION("MTD map driver for Blackfins with flash/ethernet on same async bank"); 230