MOXA linux-2.6.x / linux-2.6.19-uc1 from UC-7110-LX-BOOTLOADER-1.9_VERSION-4.2.tgz
[linux-2.6.19-moxart.git] / drivers / mtd / chips / epcs.c
blob4490c5b21112b865832aadbd5ddd1994ac2aea43
1 /*
2 * Altera EPCS Configuration device MTD Driver
3 * MTD Routines - read/write/erase etc...
5 * Jai Dhar, FPS-Tech <contact@fps-tech.net>
6 *
7 * Currently works with 1,4, 16 and 64 MBit EPCS Devices
8 * Module features:
9 * - Module detects the presence of an EPCS Device, between 1,4,16 and 64 Mbit EPCS chips
10 * - Automatically sets up EPCS Map physical size and erase block size
11 * - Important: The correct base address for the EPCS Avalon component must be specified
12 * in the Kernel configuration. This will not search for the component. The best way
13 * to find the base address is to look at the base address in SOPC Builder, and then
14 * in the SOPC Shell, use "nios2-flash-programmer --debug --epcs --base=<base>"
15 * It will then tell you the base address which the registers were found. This
16 * isn't necessarily the same as <base>.
18 * - Module tested with JFFS2 and ROMFS, both in RW and RO modes
20 * - TODO: Add transaction stats
24 #include <linux/module.h>
25 #include <linux/types.h>
26 #include <linux/kernel.h>
27 #include <asm/io.h>
28 #include <asm/byteorder.h>
29 #include <linux/errno.h>
30 #include <linux/slab.h>
31 #include <linux/init.h>
32 #include <linux/mtd/mtd.h>
33 #include <linux/mtd/map.h>
34 #include <linux/mtd/compatmac.h>
36 #include "epcs.h"
38 static int epcs_read(struct mtd_info *, loff_t, size_t, size_t *, u_char *);
39 static int epcs_write(struct mtd_info *, loff_t, size_t, size_t *, const u_char *);
40 static int epcs_erase(struct mtd_info *, struct erase_info *);
41 static void epcs_nop(struct mtd_info *);
42 static struct mtd_info *epcs_probe(struct map_info *map);
45 static struct mtd_chip_driver epcs_chipdrv = {
46 .probe = epcs_probe,
47 .name = "epcs",
48 .module = THIS_MODULE
51 static struct mtd_info *epcs_probe(struct map_info *map)
53 struct mtd_info *mtd;
54 u_char x;
56 printk(KERN_NOTICE "FPS-Tech EPCS MTD Driver (fps-tech.net)\n");
58 mtd = kmalloc(sizeof(*mtd), GFP_KERNEL);
59 if (!mtd)
60 return NULL;
62 memset(mtd, 0, sizeof(*mtd));
64 #if EPCS_DEBUG2
65 printk(KERN_NOTICE "Resetting EPCS\n");
66 #endif
68 epcs_reset();
70 #if EPCS_DEBUG1
71 printk(KERN_NOTICE "Using Avalon address: 0x%X\n",(u_int) map->phys);
72 #endif
74 #if EPCS_DEBUG2
75 epcs_print_regs();
76 #endif
79 /* Check for EPCS Signature */
80 switch (x=epcs_dev_find())
82 case EPCS_SIG_1MBIT:
83 printk(KERN_NOTICE "1 Mbit EPCS Chip found\n");
84 map->size = EPCS_SIZE_1MBIT;
85 mtd->erasesize = EPCS_SECSIZE_32KB;
86 break;
88 case EPCS_SIG_4MBIT:
89 printk(KERN_NOTICE "4 Mbit EPCS Chip found\n");
90 map->size = EPCS_SIZE_4MBIT;
91 mtd->erasesize = EPCS_SECSIZE_64KB;
92 break;
94 case EPCS_SIG_16MBIT:
95 printk(KERN_NOTICE "16 Mbit EPCS Chip found\n");
96 map->size = EPCS_SIZE_16MBIT;
97 mtd->erasesize = EPCS_SECSIZE_64KB;
98 break;
100 case EPCS_SIG_64MBIT:
101 printk(KERN_NOTICE "64 Mbit EPCS Chip found\n");
102 map->size = EPCS_SIZE_64MBIT;
103 mtd->erasesize = EPCS_SECSIZE_64KB;
104 break;
106 default:
107 printk(KERN_NOTICE "No EPCS Chip found with ID: %d\n",x);
108 return NULL;
113 map->fldrv = &epcs_chipdrv;
114 mtd->priv = map;
115 mtd->name = map->name;
116 mtd->type = MTD_NORFLASH;
117 mtd->size = map->size;
118 mtd->erase = epcs_erase;
119 mtd->read = epcs_read;
120 mtd->write = epcs_write;
121 mtd->sync = epcs_nop;
122 mtd->flags = MTD_CAP_NORFLASH;
125 #if EPCS_DEBUG1
126 printk(KERN_NOTICE "Setting EPCS Page size to %d bytes\n",mtd->erasesize);
127 #endif
129 __module_get(THIS_MODULE);
130 return mtd;
134 static int epcs_read (struct mtd_info *mtd, loff_t from, size_t len, size_t *retlen, u_char *buf)
137 #if EPCS_DEBUG2
138 printk(KERN_NOTICE "epcs_read, len: 0x%lx, from: 0x%lx\n",(u_long) len,(u_long) from);
139 #endif
141 epcs_buf_read(buf,from,len);
142 *retlen = len;
143 return 0;
146 static int epcs_write (struct mtd_info *mtd, loff_t to, size_t len, size_t *retlen, const u_char *buf)
149 #if EPCS_DEBUG2
150 printk(KERN_NOTICE "epcs_write, off: 0x%X, len: 0x%X\n",(u_int) to, (u_int) len);
151 #endif
153 epcs_buf_write (buf, (u_int) to, (u_int) len);
155 *retlen = len;
156 return 0;
159 static int epcs_erase (struct mtd_info *mtd, struct erase_info *instr)
162 #if EPCS_DEBUG2
163 printk(KERN_NOTICE "epcs_erase: off: 0x%X, len: 0x%X\n",(u_int) instr->addr, instr->len);
164 #endif
166 epcs_buf_erase(instr->addr, instr->len, mtd->erasesize);
167 instr->state = MTD_ERASE_DONE;
169 mtd_erase_callback(instr);
171 return 0;
174 static void epcs_nop(struct mtd_info *mtd)
176 #if EPCS_DEBUG2
177 printk(KERN_NOTICE "epcs_nop\n");
178 #endif
182 int __init epcs_init(void)
184 #if EPCS_DEBUG2
185 printk(KERN_NOTICE "epcs_init registering driver\n");
186 #endif
188 register_mtd_chip_driver(&epcs_chipdrv);
189 return 0;
192 void __exit epcs_exit(void)
194 unregister_mtd_chip_driver(&epcs_chipdrv);
195 #if EPCS_DEBUG2
196 printk(KERN_NOTICE "epcs_init un-registering driver\n");
197 #endif
200 module_init(epcs_init);
201 module_exit(epcs_exit);
203 MODULE_LICENSE("GPL");
204 MODULE_AUTHOR("Jai Dhar <contact@fps-tech.net>");
205 MODULE_DESCRIPTION("MTD chip driver for EPCS Chips");