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