fix mismerge in ll_rw_blk.c
[linux-2.6] / drivers / mtd / chips / amd_flash.c
1 /*
2  * MTD map driver for AMD compatible flash chips (non-CFI)
3  *
4  * Author: Jonas Holmberg <jonas.holmberg@axis.com>
5  *
6  * $Id: amd_flash.c,v 1.27 2005/02/04 07:43:09 jonashg Exp $
7  *
8  * Copyright (c) 2001 Axis Communications AB
9  *
10  * This file is under GPL.
11  *
12  */
13
14 #include <linux/module.h>
15 #include <linux/types.h>
16 #include <linux/kernel.h>
17 #include <linux/sched.h>
18 #include <linux/errno.h>
19 #include <linux/slab.h>
20 #include <linux/delay.h>
21 #include <linux/interrupt.h>
22 #include <linux/init.h>
23 #include <linux/mtd/map.h>
24 #include <linux/mtd/mtd.h>
25 #include <linux/mtd/flashchip.h>
26
27 /* There's no limit. It exists only to avoid realloc. */
28 #define MAX_AMD_CHIPS 8
29
30 #define DEVICE_TYPE_X8  (8 / 8)
31 #define DEVICE_TYPE_X16 (16 / 8)
32 #define DEVICE_TYPE_X32 (32 / 8)
33
34 /* Addresses */
35 #define ADDR_MANUFACTURER               0x0000
36 #define ADDR_DEVICE_ID                  0x0001
37 #define ADDR_SECTOR_LOCK                0x0002
38 #define ADDR_HANDSHAKE                  0x0003
39 #define ADDR_UNLOCK_1                   0x0555
40 #define ADDR_UNLOCK_2                   0x02AA
41
42 /* Commands */
43 #define CMD_UNLOCK_DATA_1               0x00AA
44 #define CMD_UNLOCK_DATA_2               0x0055
45 #define CMD_MANUFACTURER_UNLOCK_DATA    0x0090
46 #define CMD_UNLOCK_BYPASS_MODE          0x0020
47 #define CMD_PROGRAM_UNLOCK_DATA         0x00A0
48 #define CMD_RESET_DATA                  0x00F0
49 #define CMD_SECTOR_ERASE_UNLOCK_DATA    0x0080
50 #define CMD_SECTOR_ERASE_UNLOCK_DATA_2  0x0030
51
52 #define CMD_UNLOCK_SECTOR               0x0060
53
54 /* Manufacturers */
55 #define MANUFACTURER_AMD        0x0001
56 #define MANUFACTURER_ATMEL      0x001F
57 #define MANUFACTURER_FUJITSU    0x0004
58 #define MANUFACTURER_ST         0x0020
59 #define MANUFACTURER_SST        0x00BF
60 #define MANUFACTURER_TOSHIBA    0x0098
61
62 /* AMD */
63 #define AM29F800BB      0x2258
64 #define AM29F800BT      0x22D6
65 #define AM29LV800BB     0x225B
66 #define AM29LV800BT     0x22DA
67 #define AM29LV160DT     0x22C4
68 #define AM29LV160DB     0x2249
69 #define AM29BDS323D     0x22D1
70
71 /* Atmel */
72 #define AT49xV16x       0x00C0
73 #define AT49xV16xT      0x00C2
74
75 /* Fujitsu */
76 #define MBM29LV160TE    0x22C4
77 #define MBM29LV160BE    0x2249
78 #define MBM29LV800BB    0x225B
79
80 /* ST - www.st.com */
81 #define M29W800T        0x00D7
82 #define M29W160DT       0x22C4
83 #define M29W160DB       0x2249
84
85 /* SST */
86 #define SST39LF800      0x2781
87 #define SST39LF160      0x2782
88
89 /* Toshiba */
90 #define TC58FVT160      0x00C2
91 #define TC58FVB160      0x0043
92
93 #define D6_MASK 0x40
94
95 struct amd_flash_private {
96         int device_type;        
97         int interleave; 
98         int numchips;   
99         unsigned long chipshift;
100 //      const char *im_name;
101         struct flchip chips[0];
102 };
103
104 struct amd_flash_info {
105         const __u16 mfr_id;
106         const __u16 dev_id;
107         const char *name;
108         const u_long size;
109         const int numeraseregions;
110         const struct mtd_erase_region_info regions[4];
111 };
112
113
114
115 static int amd_flash_read(struct mtd_info *, loff_t, size_t, size_t *,
116                           u_char *);
117 static int amd_flash_write(struct mtd_info *, loff_t, size_t, size_t *,
118                            const u_char *);
119 static int amd_flash_erase(struct mtd_info *, struct erase_info *);
120 static void amd_flash_sync(struct mtd_info *);
121 static int amd_flash_suspend(struct mtd_info *);
122 static void amd_flash_resume(struct mtd_info *);
123 static void amd_flash_destroy(struct mtd_info *);
124 static struct mtd_info *amd_flash_probe(struct map_info *map);
125
126
127 static struct mtd_chip_driver amd_flash_chipdrv = {
128         .probe = amd_flash_probe,
129         .destroy = amd_flash_destroy,
130         .name = "amd_flash",
131         .module = THIS_MODULE
132 };
133
134
135
136 static const char im_name[] = "amd_flash";
137
138
139
140 static inline __u32 wide_read(struct map_info *map, __u32 addr)
141 {
142         if (map->buswidth == 1) {
143                 return map_read8(map, addr);
144         } else if (map->buswidth == 2) {
145                 return map_read16(map, addr);
146         } else if (map->buswidth == 4) {
147                 return map_read32(map, addr);
148         }
149
150         return 0;
151 }
152
153 static inline void wide_write(struct map_info *map, __u32 val, __u32 addr)
154 {
155         if (map->buswidth == 1) {
156                 map_write8(map, val, addr);
157         } else if (map->buswidth == 2) {
158                 map_write16(map, val, addr);
159         } else if (map->buswidth == 4) {
160                 map_write32(map, val, addr);
161         }
162 }
163
164 static inline __u32 make_cmd(struct map_info *map, __u32 cmd)
165 {
166         const struct amd_flash_private *private = map->fldrv_priv;
167         if ((private->interleave == 2) &&
168             (private->device_type == DEVICE_TYPE_X16)) {
169                 cmd |= (cmd << 16);
170         }
171
172         return cmd;
173 }
174
175 static inline void send_unlock(struct map_info *map, unsigned long base)
176 {
177         wide_write(map, (CMD_UNLOCK_DATA_1 << 16) | CMD_UNLOCK_DATA_1,
178                    base + (map->buswidth * ADDR_UNLOCK_1));
179         wide_write(map, (CMD_UNLOCK_DATA_2 << 16) | CMD_UNLOCK_DATA_2,
180                    base + (map->buswidth * ADDR_UNLOCK_2));
181 }
182
183 static inline void send_cmd(struct map_info *map, unsigned long base, __u32 cmd)
184 {
185         send_unlock(map, base);
186         wide_write(map, make_cmd(map, cmd),
187                    base + (map->buswidth * ADDR_UNLOCK_1));
188 }
189
190 static inline void send_cmd_to_addr(struct map_info *map, unsigned long base,
191                                     __u32 cmd, unsigned long addr)
192 {
193         send_unlock(map, base);
194         wide_write(map, make_cmd(map, cmd), addr);
195 }
196
197 static inline int flash_is_busy(struct map_info *map, unsigned long addr,
198                                 int interleave)
199 {
200
201         if ((interleave == 2) && (map->buswidth == 4)) {
202                 __u32 read1, read2;
203
204                 read1 = wide_read(map, addr);
205                 read2 = wide_read(map, addr);
206
207                 return (((read1 >> 16) & D6_MASK) !=
208                         ((read2 >> 16) & D6_MASK)) ||
209                        (((read1 & 0xffff) & D6_MASK) !=
210                         ((read2 & 0xffff) & D6_MASK));
211         }
212
213         return ((wide_read(map, addr) & D6_MASK) !=
214                 (wide_read(map, addr) & D6_MASK));
215 }
216
217 static inline void unlock_sector(struct map_info *map, unsigned long sect_addr,
218                                  int unlock)
219 {
220         /* Sector lock address. A6 = 1 for unlock, A6 = 0 for lock */
221         int SLA = unlock ?
222                 (sect_addr |  (0x40 * map->buswidth)) :
223                 (sect_addr & ~(0x40 * map->buswidth)) ;
224
225         __u32 cmd = make_cmd(map, CMD_UNLOCK_SECTOR);
226
227         wide_write(map, make_cmd(map, CMD_RESET_DATA), 0);
228         wide_write(map, cmd, SLA); /* 1st cycle: write cmd to any address */
229         wide_write(map, cmd, SLA); /* 2nd cycle: write cmd to any address */
230         wide_write(map, cmd, SLA); /* 3rd cycle: write cmd to SLA */
231 }
232
233 static inline int is_sector_locked(struct map_info *map,
234                                    unsigned long sect_addr)
235 {
236         int status;
237
238         wide_write(map, CMD_RESET_DATA, 0);
239         send_cmd(map, sect_addr, CMD_MANUFACTURER_UNLOCK_DATA);
240
241         /* status is 0x0000 for unlocked and 0x0001 for locked */
242         status = wide_read(map, sect_addr + (map->buswidth * ADDR_SECTOR_LOCK));
243         wide_write(map, CMD_RESET_DATA, 0);
244         return status;
245 }
246
247 static int amd_flash_do_unlock(struct mtd_info *mtd, loff_t ofs, size_t len,
248                                int is_unlock)
249 {
250         struct map_info *map;
251         struct mtd_erase_region_info *merip;
252         int eraseoffset, erasesize, eraseblocks;
253         int i;
254         int retval = 0;
255         int lock_status;
256       
257         map = mtd->priv;
258
259         /* Pass the whole chip through sector by sector and check for each
260            sector if the sector and the given interval overlap */
261         for(i = 0; i < mtd->numeraseregions; i++) {
262                 merip = &mtd->eraseregions[i];
263
264                 eraseoffset = merip->offset;
265                 erasesize = merip->erasesize;
266                 eraseblocks = merip->numblocks;
267
268                 if (ofs > eraseoffset + erasesize)
269                         continue;
270
271                 while (eraseblocks > 0) {
272                         if (ofs < eraseoffset + erasesize && ofs + len > eraseoffset) {
273                                 unlock_sector(map, eraseoffset, is_unlock);
274
275                                 lock_status = is_sector_locked(map, eraseoffset);
276                                 
277                                 if (is_unlock && lock_status) {
278                                         printk("Cannot unlock sector at address %x length %xx\n",
279                                                eraseoffset, merip->erasesize);
280                                         retval = -1;
281                                 } else if (!is_unlock && !lock_status) {
282                                         printk("Cannot lock sector at address %x length %x\n",
283                                                eraseoffset, merip->erasesize);
284                                         retval = -1;
285                                 }
286                         }
287                         eraseoffset += erasesize;
288                         eraseblocks --;
289                 }
290         }
291         return retval;
292 }
293
294 static int amd_flash_unlock(struct mtd_info *mtd, loff_t ofs, size_t len)
295 {
296         return amd_flash_do_unlock(mtd, ofs, len, 1);
297 }
298
299 static int amd_flash_lock(struct mtd_info *mtd, loff_t ofs, size_t len)
300 {
301         return amd_flash_do_unlock(mtd, ofs, len, 0);
302 }
303
304
305 /*
306  * Reads JEDEC manufacturer ID and device ID and returns the index of the first
307  * matching table entry (-1 if not found or alias for already found chip).
308  */ 
309 static int probe_new_chip(struct mtd_info *mtd, __u32 base,
310                           struct flchip *chips,
311                           struct amd_flash_private *private,
312                           const struct amd_flash_info *table, int table_size)
313 {
314         __u32 mfr_id;
315         __u32 dev_id;
316         struct map_info *map = mtd->priv;
317         struct amd_flash_private temp;
318         int i;
319
320         temp.device_type = DEVICE_TYPE_X16;     // Assume X16 (FIXME)
321         temp.interleave = 2;
322         map->fldrv_priv = &temp;
323
324         /* Enter autoselect mode. */
325         send_cmd(map, base, CMD_RESET_DATA);
326         send_cmd(map, base, CMD_MANUFACTURER_UNLOCK_DATA);
327
328         mfr_id = wide_read(map, base + (map->buswidth * ADDR_MANUFACTURER));
329         dev_id = wide_read(map, base + (map->buswidth * ADDR_DEVICE_ID));
330
331         if ((map->buswidth == 4) && ((mfr_id >> 16) == (mfr_id & 0xffff)) &&
332             ((dev_id >> 16) == (dev_id & 0xffff))) {
333                 mfr_id &= 0xffff;
334                 dev_id &= 0xffff;
335         } else {
336                 temp.interleave = 1;
337         }
338
339         for (i = 0; i < table_size; i++) {
340                 if ((mfr_id == table[i].mfr_id) &&
341                     (dev_id == table[i].dev_id)) {
342                         if (chips) {
343                                 int j;
344
345                                 /* Is this an alias for an already found chip?
346                                  * In that case that chip should be in
347                                  * autoselect mode now.
348                                  */
349                                 for (j = 0; j < private->numchips; j++) {
350                                         __u32 mfr_id_other;
351                                         __u32 dev_id_other;
352
353                                         mfr_id_other =
354                                                 wide_read(map, chips[j].start +
355                                                                (map->buswidth *
356                                                                 ADDR_MANUFACTURER
357                                                                ));
358                                         dev_id_other =
359                                                 wide_read(map, chips[j].start +
360                                                                (map->buswidth *
361                                                                 ADDR_DEVICE_ID));
362                                         if (temp.interleave == 2) {
363                                                 mfr_id_other &= 0xffff;
364                                                 dev_id_other &= 0xffff;
365                                         }
366                                         if ((mfr_id_other == mfr_id) &&
367                                             (dev_id_other == dev_id)) {
368
369                                                 /* Exit autoselect mode. */
370                                                 send_cmd(map, base,
371                                                          CMD_RESET_DATA);
372
373                                                 return -1;
374                                         }
375                                 }
376
377                                 if (private->numchips == MAX_AMD_CHIPS) {
378                                         printk(KERN_WARNING
379                                                "%s: Too many flash chips "
380                                                "detected. Increase "
381                                                "MAX_AMD_CHIPS from %d.\n",
382                                                map->name, MAX_AMD_CHIPS);
383
384                                         return -1;
385                                 }
386
387                                 chips[private->numchips].start = base;
388                                 chips[private->numchips].state = FL_READY;
389                                 chips[private->numchips].mutex =
390                                         &chips[private->numchips]._spinlock;
391                                 private->numchips++;
392                         }
393
394                         printk("%s: Found %d x %ldMiB %s at 0x%x\n", map->name,
395                                temp.interleave, (table[i].size)/(1024*1024),
396                                table[i].name, base);
397
398                         mtd->size += table[i].size * temp.interleave;
399                         mtd->numeraseregions += table[i].numeraseregions;
400
401                         break;
402                 }
403         }
404
405         /* Exit autoselect mode. */
406         send_cmd(map, base, CMD_RESET_DATA);
407
408         if (i == table_size) {
409                 printk(KERN_DEBUG "%s: unknown flash device at 0x%x, "
410                        "mfr id 0x%x, dev id 0x%x\n", map->name,
411                        base, mfr_id, dev_id);
412                 map->fldrv_priv = NULL;
413
414                 return -1;
415         }
416
417         private->device_type = temp.device_type;
418         private->interleave = temp.interleave;
419
420         return i;
421 }
422
423
424
425 static struct mtd_info *amd_flash_probe(struct map_info *map)
426 {
427         static const struct amd_flash_info table[] = {
428         {
429                 .mfr_id = MANUFACTURER_AMD,
430                 .dev_id = AM29LV160DT,
431                 .name = "AMD AM29LV160DT",
432                 .size = 0x00200000,
433                 .numeraseregions = 4,
434                 .regions = {
435                         { .offset = 0x000000, .erasesize = 0x10000, .numblocks = 31 },
436                         { .offset = 0x1F0000, .erasesize = 0x08000, .numblocks =  1 },
437                         { .offset = 0x1F8000, .erasesize = 0x02000, .numblocks =  2 },
438                         { .offset = 0x1FC000, .erasesize = 0x04000, .numblocks =  1 }
439                 }
440         }, {
441                 .mfr_id = MANUFACTURER_AMD,
442                 .dev_id = AM29LV160DB,
443                 .name = "AMD AM29LV160DB",
444                 .size = 0x00200000,
445                 .numeraseregions = 4,
446                 .regions = {
447                         { .offset = 0x000000, .erasesize = 0x04000, .numblocks =  1 },
448                         { .offset = 0x004000, .erasesize = 0x02000, .numblocks =  2 },
449                         { .offset = 0x008000, .erasesize = 0x08000, .numblocks =  1 },
450                         { .offset = 0x010000, .erasesize = 0x10000, .numblocks = 31 }
451                 }
452         }, {
453                 .mfr_id = MANUFACTURER_TOSHIBA,
454                 .dev_id = TC58FVT160,
455                 .name = "Toshiba TC58FVT160",
456                 .size = 0x00200000,
457                 .numeraseregions = 4,
458                 .regions = {
459                         { .offset = 0x000000, .erasesize = 0x10000, .numblocks = 31 },
460                         { .offset = 0x1F0000, .erasesize = 0x08000, .numblocks =  1 },
461                         { .offset = 0x1F8000, .erasesize = 0x02000, .numblocks =  2 },
462                         { .offset = 0x1FC000, .erasesize = 0x04000, .numblocks =  1 }
463                 }
464         }, {
465                 .mfr_id = MANUFACTURER_FUJITSU,
466                 .dev_id = MBM29LV160TE,
467                 .name = "Fujitsu MBM29LV160TE",
468                 .size = 0x00200000,
469                 .numeraseregions = 4,
470                 .regions = {
471                         { .offset = 0x000000, .erasesize = 0x10000, .numblocks = 31 },
472                         { .offset = 0x1F0000, .erasesize = 0x08000, .numblocks =  1 },
473                         { .offset = 0x1F8000, .erasesize = 0x02000, .numblocks =  2 },
474                         { .offset = 0x1FC000, .erasesize = 0x04000, .numblocks =  1 }
475                 }
476         }, {
477                 .mfr_id = MANUFACTURER_TOSHIBA,
478                 .dev_id = TC58FVB160,
479                 .name = "Toshiba TC58FVB160",
480                 .size = 0x00200000,
481                 .numeraseregions = 4,
482                 .regions = {
483                         { .offset = 0x000000, .erasesize = 0x04000, .numblocks =  1 },
484                         { .offset = 0x004000, .erasesize = 0x02000, .numblocks =  2 },
485                         { .offset = 0x008000, .erasesize = 0x08000, .numblocks =  1 },
486                         { .offset = 0x010000, .erasesize = 0x10000, .numblocks = 31 }
487                 }
488         }, {
489                 .mfr_id = MANUFACTURER_FUJITSU,
490                 .dev_id = MBM29LV160BE,
491                 .name = "Fujitsu MBM29LV160BE",
492                 .size = 0x00200000,
493                 .numeraseregions = 4,
494                 .regions = {
495                         { .offset = 0x000000, .erasesize = 0x04000, .numblocks =  1 },
496                         { .offset = 0x004000, .erasesize = 0x02000, .numblocks =  2 },
497                         { .offset = 0x008000, .erasesize = 0x08000, .numblocks =  1 },
498                         { .offset = 0x010000, .erasesize = 0x10000, .numblocks = 31 }
499                 }
500         }, {
501                 .mfr_id = MANUFACTURER_AMD,
502                 .dev_id = AM29LV800BB,
503                 .name = "AMD AM29LV800BB",
504                 .size = 0x00100000,
505                 .numeraseregions = 4,
506                 .regions = {
507                         { .offset = 0x000000, .erasesize = 0x04000, .numblocks =  1 },
508                         { .offset = 0x004000, .erasesize = 0x02000, .numblocks =  2 },
509                         { .offset = 0x008000, .erasesize = 0x08000, .numblocks =  1 },
510                         { .offset = 0x010000, .erasesize = 0x10000, .numblocks = 15 }
511                 }
512         }, {
513                 .mfr_id = MANUFACTURER_AMD,
514                 .dev_id = AM29F800BB,
515                 .name = "AMD AM29F800BB",
516                 .size = 0x00100000,
517                 .numeraseregions = 4,
518                 .regions = {
519                         { .offset = 0x000000, .erasesize = 0x04000, .numblocks =  1 },
520                         { .offset = 0x004000, .erasesize = 0x02000, .numblocks =  2 },
521                         { .offset = 0x008000, .erasesize = 0x08000, .numblocks =  1 },
522                         { .offset = 0x010000, .erasesize = 0x10000, .numblocks = 15 }
523                 }
524         }, {
525                 .mfr_id = MANUFACTURER_AMD,
526                 .dev_id = AM29LV800BT,
527                 .name = "AMD AM29LV800BT",
528                 .size = 0x00100000,
529                 .numeraseregions = 4,
530                 .regions = {
531                         { .offset = 0x000000, .erasesize = 0x10000, .numblocks = 15 },
532                         { .offset = 0x0F0000, .erasesize = 0x08000, .numblocks =  1 },
533                         { .offset = 0x0F8000, .erasesize = 0x02000, .numblocks =  2 },
534                         { .offset = 0x0FC000, .erasesize = 0x04000, .numblocks =  1 }
535                 }
536         }, {
537                 .mfr_id = MANUFACTURER_AMD,
538                 .dev_id = AM29F800BT,
539                 .name = "AMD AM29F800BT",
540                 .size = 0x00100000,
541                 .numeraseregions = 4,
542                 .regions = {
543                         { .offset = 0x000000, .erasesize = 0x10000, .numblocks = 15 },
544                         { .offset = 0x0F0000, .erasesize = 0x08000, .numblocks =  1 },
545                         { .offset = 0x0F8000, .erasesize = 0x02000, .numblocks =  2 },
546                         { .offset = 0x0FC000, .erasesize = 0x04000, .numblocks =  1 }
547                 }
548         }, {
549                 .mfr_id = MANUFACTURER_AMD,
550                 .dev_id = AM29LV800BB,
551                 .name = "AMD AM29LV800BB",
552                 .size = 0x00100000,
553                 .numeraseregions = 4,
554                 .regions = {
555                         { .offset = 0x000000, .erasesize = 0x10000, .numblocks = 15 },
556                         { .offset = 0x0F0000, .erasesize = 0x08000, .numblocks =  1 },
557                         { .offset = 0x0F8000, .erasesize = 0x02000, .numblocks =  2 },
558                         { .offset = 0x0FC000, .erasesize = 0x04000, .numblocks =  1 }
559                 }
560         }, {
561                 .mfr_id = MANUFACTURER_FUJITSU,
562                 .dev_id = MBM29LV800BB,
563                 .name = "Fujitsu MBM29LV800BB",
564                 .size = 0x00100000,
565                 .numeraseregions = 4,
566                 .regions = {
567                         { .offset = 0x000000, .erasesize = 0x04000, .numblocks =  1 },
568                         { .offset = 0x004000, .erasesize = 0x02000, .numblocks =  2 },
569                         { .offset = 0x008000, .erasesize = 0x08000, .numblocks =  1 },
570                         { .offset = 0x010000, .erasesize = 0x10000, .numblocks = 15 }
571                 }
572         }, {
573                 .mfr_id = MANUFACTURER_ST,
574                 .dev_id = M29W800T,
575                 .name = "ST M29W800T",
576                 .size = 0x00100000,
577                 .numeraseregions = 4,
578                 .regions = {
579                         { .offset = 0x000000, .erasesize = 0x10000, .numblocks = 15 },
580                         { .offset = 0x0F0000, .erasesize = 0x08000, .numblocks =  1 },
581                         { .offset = 0x0F8000, .erasesize = 0x02000, .numblocks =  2 },
582                         { .offset = 0x0FC000, .erasesize = 0x04000, .numblocks =  1 }
583                 }
584         }, {
585                 .mfr_id = MANUFACTURER_ST,
586                 .dev_id = M29W160DT,
587                 .name = "ST M29W160DT",
588                 .size = 0x00200000,
589                 .numeraseregions = 4,
590                 .regions = {
591                         { .offset = 0x000000, .erasesize = 0x10000, .numblocks = 31 },
592                         { .offset = 0x1F0000, .erasesize = 0x08000, .numblocks =  1 },
593                         { .offset = 0x1F8000, .erasesize = 0x02000, .numblocks =  2 },
594                         { .offset = 0x1FC000, .erasesize = 0x04000, .numblocks =  1 }
595                 }
596         }, {
597                 .mfr_id = MANUFACTURER_ST,
598                 .dev_id = M29W160DB,
599                 .name = "ST M29W160DB",
600                 .size = 0x00200000,
601                 .numeraseregions = 4,
602                 .regions = {
603                         { .offset = 0x000000, .erasesize = 0x04000, .numblocks =  1 },
604                         { .offset = 0x004000, .erasesize = 0x02000, .numblocks =  2 },
605                         { .offset = 0x008000, .erasesize = 0x08000, .numblocks =  1 },
606                         { .offset = 0x010000, .erasesize = 0x10000, .numblocks = 31 }
607                 }
608         }, {
609                 .mfr_id = MANUFACTURER_AMD,
610                 .dev_id = AM29BDS323D,
611                 .name = "AMD AM29BDS323D",
612                 .size = 0x00400000,
613                 .numeraseregions = 3,
614                 .regions = {
615                         { .offset = 0x000000, .erasesize = 0x10000, .numblocks = 48 },
616                         { .offset = 0x300000, .erasesize = 0x10000, .numblocks = 15 },
617                         { .offset = 0x3f0000, .erasesize = 0x02000, .numblocks =  8 },
618                 }
619         }, {
620                 .mfr_id = MANUFACTURER_ATMEL,
621                 .dev_id = AT49xV16x,
622                 .name = "Atmel AT49xV16x",
623                 .size = 0x00200000,
624                 .numeraseregions = 2,
625                 .regions = {
626                         { .offset = 0x000000, .erasesize = 0x02000, .numblocks =  8 },
627                         { .offset = 0x010000, .erasesize = 0x10000, .numblocks = 31 }
628                 }
629         }, {
630                 .mfr_id = MANUFACTURER_ATMEL,
631                 .dev_id = AT49xV16xT,
632                 .name = "Atmel AT49xV16xT",
633                 .size = 0x00200000,
634                 .numeraseregions = 2,
635                 .regions = {
636                         { .offset = 0x000000, .erasesize = 0x10000, .numblocks = 31 },
637                         { .offset = 0x1F0000, .erasesize = 0x02000, .numblocks =  8 }
638                 }
639         } 
640         };
641
642         struct mtd_info *mtd;
643         struct flchip chips[MAX_AMD_CHIPS];
644         int table_pos[MAX_AMD_CHIPS];
645         struct amd_flash_private temp;
646         struct amd_flash_private *private;
647         u_long size;
648         unsigned long base;
649         int i;
650         int reg_idx;
651         int offset;
652
653         mtd = (struct mtd_info*)kmalloc(sizeof(*mtd), GFP_KERNEL);
654         if (!mtd) {
655                 printk(KERN_WARNING
656                        "%s: kmalloc failed for info structure\n", map->name);
657                 return NULL;
658         }
659         memset(mtd, 0, sizeof(*mtd));
660         mtd->priv = map;
661
662         memset(&temp, 0, sizeof(temp));
663
664         printk("%s: Probing for AMD compatible flash...\n", map->name);
665
666         if ((table_pos[0] = probe_new_chip(mtd, 0, NULL, &temp, table,
667                                            sizeof(table)/sizeof(table[0])))
668             == -1) {
669                 printk(KERN_WARNING
670                        "%s: Found no AMD compatible device at location zero\n",
671                        map->name);
672                 kfree(mtd);
673
674                 return NULL;
675         }
676
677         chips[0].start = 0;
678         chips[0].state = FL_READY;
679         chips[0].mutex = &chips[0]._spinlock;
680         temp.numchips = 1;
681         for (size = mtd->size; size > 1; size >>= 1) {
682                 temp.chipshift++;
683         }
684         switch (temp.interleave) {
685                 case 2:
686                         temp.chipshift += 1;
687                         break;
688                 case 4:
689                         temp.chipshift += 2;
690                         break;
691         }
692
693         /* Find out if there are any more chips in the map. */
694         for (base = (1 << temp.chipshift);
695              base < map->size;
696              base += (1 << temp.chipshift)) {
697                 int numchips = temp.numchips;
698                 table_pos[numchips] = probe_new_chip(mtd, base, chips,
699                         &temp, table, sizeof(table)/sizeof(table[0]));
700         }
701
702         mtd->eraseregions = kmalloc(sizeof(struct mtd_erase_region_info) *
703                                     mtd->numeraseregions, GFP_KERNEL);
704         if (!mtd->eraseregions) { 
705                 printk(KERN_WARNING "%s: Failed to allocate "
706                        "memory for MTD erase region info\n", map->name);
707                 kfree(mtd);
708                 map->fldrv_priv = NULL;
709                 return NULL;
710         }
711
712         reg_idx = 0;
713         offset = 0;
714         for (i = 0; i < temp.numchips; i++) {
715                 int dev_size;
716                 int j;
717
718                 dev_size = 0;
719                 for (j = 0; j < table[table_pos[i]].numeraseregions; j++) {
720                         mtd->eraseregions[reg_idx].offset = offset +
721                                 (table[table_pos[i]].regions[j].offset *
722                                  temp.interleave);
723                         mtd->eraseregions[reg_idx].erasesize =
724                                 table[table_pos[i]].regions[j].erasesize *
725                                 temp.interleave;
726                         mtd->eraseregions[reg_idx].numblocks =
727                                 table[table_pos[i]].regions[j].numblocks;
728                         if (mtd->erasesize <
729                             mtd->eraseregions[reg_idx].erasesize) {
730                                 mtd->erasesize =
731                                         mtd->eraseregions[reg_idx].erasesize;
732                         }
733                         dev_size += mtd->eraseregions[reg_idx].erasesize *
734                                     mtd->eraseregions[reg_idx].numblocks;
735                         reg_idx++;
736                 }
737                 offset += dev_size;
738         }
739         mtd->type = MTD_NORFLASH;
740         mtd->flags = MTD_CAP_NORFLASH;
741         mtd->name = map->name;
742         mtd->erase = amd_flash_erase;   
743         mtd->read = amd_flash_read;     
744         mtd->write = amd_flash_write;   
745         mtd->sync = amd_flash_sync;     
746         mtd->suspend = amd_flash_suspend;       
747         mtd->resume = amd_flash_resume; 
748         mtd->lock = amd_flash_lock;
749         mtd->unlock = amd_flash_unlock;
750
751         private = kmalloc(sizeof(*private) + (sizeof(struct flchip) *
752                                               temp.numchips), GFP_KERNEL);
753         if (!private) {
754                 printk(KERN_WARNING
755                        "%s: kmalloc failed for private structure\n", map->name);
756                 kfree(mtd);
757                 map->fldrv_priv = NULL;
758                 return NULL;
759         }
760         memcpy(private, &temp, sizeof(temp));
761         memcpy(private->chips, chips,
762                sizeof(struct flchip) * private->numchips);
763         for (i = 0; i < private->numchips; i++) {
764                 init_waitqueue_head(&private->chips[i].wq);
765                 spin_lock_init(&private->chips[i]._spinlock);
766         }
767
768         map->fldrv_priv = private;
769
770         map->fldrv = &amd_flash_chipdrv;
771
772         __module_get(THIS_MODULE);
773         return mtd;
774 }
775
776
777
778 static inline int read_one_chip(struct map_info *map, struct flchip *chip,
779                                loff_t adr, size_t len, u_char *buf)
780 {
781         DECLARE_WAITQUEUE(wait, current);
782         unsigned long timeo = jiffies + HZ;
783
784 retry:
785         spin_lock_bh(chip->mutex);
786
787         if (chip->state != FL_READY){
788                 printk(KERN_INFO "%s: waiting for chip to read, state = %d\n",
789                        map->name, chip->state);
790                 set_current_state(TASK_UNINTERRUPTIBLE);
791                 add_wait_queue(&chip->wq, &wait);
792                 
793                 spin_unlock_bh(chip->mutex);
794
795                 schedule();
796                 remove_wait_queue(&chip->wq, &wait);
797
798                 if(signal_pending(current)) {
799                         return -EINTR;
800                 }
801
802                 timeo = jiffies + HZ;
803
804                 goto retry;
805         }       
806
807         adr += chip->start;
808
809         chip->state = FL_READY;
810
811         map_copy_from(map, buf, adr, len);
812
813         wake_up(&chip->wq);
814         spin_unlock_bh(chip->mutex);
815
816         return 0;
817 }
818
819
820
821 static int amd_flash_read(struct mtd_info *mtd, loff_t from, size_t len,
822                           size_t *retlen, u_char *buf)
823 {
824         struct map_info *map = mtd->priv;
825         struct amd_flash_private *private = map->fldrv_priv;
826         unsigned long ofs;
827         int chipnum;
828         int ret = 0;
829
830         if ((from + len) > mtd->size) {
831                 printk(KERN_WARNING "%s: read request past end of device "
832                        "(0x%lx)\n", map->name, (unsigned long)from + len);
833
834                 return -EINVAL;
835         }
836
837         /* Offset within the first chip that the first read should start. */
838         chipnum = (from >> private->chipshift);
839         ofs = from - (chipnum <<  private->chipshift);
840
841         *retlen = 0;
842
843         while (len) {
844                 unsigned long this_len;
845
846                 if (chipnum >= private->numchips) {
847                         break;
848                 }
849
850                 if ((len + ofs - 1) >> private->chipshift) {
851                         this_len = (1 << private->chipshift) - ofs;
852                 } else {
853                         this_len = len;
854                 }
855
856                 ret = read_one_chip(map, &private->chips[chipnum], ofs,
857                                     this_len, buf);
858                 if (ret) {
859                         break;
860                 }
861
862                 *retlen += this_len;
863                 len -= this_len;
864                 buf += this_len;
865
866                 ofs = 0;
867                 chipnum++;
868         }
869
870         return ret;
871 }
872
873
874
875 static int write_one_word(struct map_info *map, struct flchip *chip,
876                           unsigned long adr, __u32 datum)
877 {
878         unsigned long timeo = jiffies + HZ;
879         struct amd_flash_private *private = map->fldrv_priv;
880         DECLARE_WAITQUEUE(wait, current);
881         int ret = 0;
882         int times_left;
883
884 retry:
885         spin_lock_bh(chip->mutex);
886
887         if (chip->state != FL_READY){
888                 printk("%s: waiting for chip to write, state = %d\n",
889                        map->name, chip->state);
890                 set_current_state(TASK_UNINTERRUPTIBLE);
891                 add_wait_queue(&chip->wq, &wait);
892                 
893                 spin_unlock_bh(chip->mutex);
894
895                 schedule();
896                 remove_wait_queue(&chip->wq, &wait);
897                 printk(KERN_INFO "%s: woke up to write\n", map->name);
898                 if(signal_pending(current))
899                         return -EINTR;
900
901                 timeo = jiffies + HZ;
902
903                 goto retry;
904         }       
905
906         chip->state = FL_WRITING;
907
908         adr += chip->start;
909         ENABLE_VPP(map);
910         send_cmd(map, chip->start, CMD_PROGRAM_UNLOCK_DATA);
911         wide_write(map, datum, adr);
912
913         times_left = 500000;
914         while (times_left-- && flash_is_busy(map, adr, private->interleave)) { 
915                 if (need_resched()) {
916                         spin_unlock_bh(chip->mutex);
917                         schedule();
918                         spin_lock_bh(chip->mutex);
919                 }
920         }
921
922         if (!times_left) {
923                 printk(KERN_WARNING "%s: write to 0x%lx timed out!\n",
924                        map->name, adr);
925                 ret = -EIO;
926         } else {
927                 __u32 verify;
928                 if ((verify = wide_read(map, adr)) != datum) {
929                         printk(KERN_WARNING "%s: write to 0x%lx failed. "
930                                "datum = %x, verify = %x\n",
931                                map->name, adr, datum, verify);
932                         ret = -EIO;
933                 }
934         }
935
936         DISABLE_VPP(map);
937         chip->state = FL_READY;
938         wake_up(&chip->wq);
939         spin_unlock_bh(chip->mutex);
940
941         return ret;
942 }
943
944
945
946 static int amd_flash_write(struct mtd_info *mtd, loff_t to , size_t len,
947                            size_t *retlen, const u_char *buf)
948 {
949         struct map_info *map = mtd->priv;
950         struct amd_flash_private *private = map->fldrv_priv;
951         int ret = 0;
952         int chipnum;
953         unsigned long ofs;
954         unsigned long chipstart;
955
956         *retlen = 0;
957         if (!len) {
958                 return 0;
959         }
960
961         chipnum = to >> private->chipshift;
962         ofs = to  - (chipnum << private->chipshift);
963         chipstart = private->chips[chipnum].start;
964
965         /* If it's not bus-aligned, do the first byte write. */
966         if (ofs & (map->buswidth - 1)) {
967                 unsigned long bus_ofs = ofs & ~(map->buswidth - 1);
968                 int i = ofs - bus_ofs;
969                 int n = 0;
970                 u_char tmp_buf[4];
971                 __u32 datum;
972
973                 map_copy_from(map, tmp_buf,
974                                bus_ofs + private->chips[chipnum].start,
975                                map->buswidth);
976                 while (len && i < map->buswidth)
977                         tmp_buf[i++] = buf[n++], len--;
978
979                 if (map->buswidth == 2) {
980                         datum = *(__u16*)tmp_buf;
981                 } else if (map->buswidth == 4) {
982                         datum = *(__u32*)tmp_buf;
983                 } else {
984                         return -EINVAL;  /* should never happen, but be safe */
985                 }
986
987                 ret = write_one_word(map, &private->chips[chipnum], bus_ofs,
988                                      datum);
989                 if (ret) {
990                         return ret;
991                 }
992                 
993                 ofs += n;
994                 buf += n;
995                 (*retlen) += n;
996
997                 if (ofs >> private->chipshift) {
998                         chipnum++;
999                         ofs = 0;
1000                         if (chipnum == private->numchips) {
1001                                 return 0;
1002                         }
1003                 }
1004         }
1005         
1006         /* We are now aligned, write as much as possible. */
1007         while(len >= map->buswidth) {
1008                 __u32 datum;
1009
1010                 if (map->buswidth == 1) {
1011                         datum = *(__u8*)buf;
1012                 } else if (map->buswidth == 2) {
1013                         datum = *(__u16*)buf;
1014                 } else if (map->buswidth == 4) {
1015                         datum = *(__u32*)buf;
1016                 } else {
1017                         return -EINVAL;
1018                 }
1019
1020                 ret = write_one_word(map, &private->chips[chipnum], ofs, datum);
1021
1022                 if (ret) {
1023                         return ret;
1024                 }
1025
1026                 ofs += map->buswidth;
1027                 buf += map->buswidth;
1028                 (*retlen) += map->buswidth;
1029                 len -= map->buswidth;
1030
1031                 if (ofs >> private->chipshift) {
1032                         chipnum++;
1033                         ofs = 0;
1034                         if (chipnum == private->numchips) {
1035                                 return 0;
1036                         }
1037                         chipstart = private->chips[chipnum].start;
1038                 }
1039         }
1040
1041         if (len & (map->buswidth - 1)) {
1042                 int i = 0, n = 0;
1043                 u_char tmp_buf[2];
1044                 __u32 datum;
1045
1046                 map_copy_from(map, tmp_buf,
1047                                ofs + private->chips[chipnum].start,
1048                                map->buswidth);
1049                 while (len--) {
1050                         tmp_buf[i++] = buf[n++];
1051                 }
1052
1053                 if (map->buswidth == 2) {
1054                         datum = *(__u16*)tmp_buf;
1055                 } else if (map->buswidth == 4) {
1056                         datum = *(__u32*)tmp_buf;
1057                 } else {
1058                         return -EINVAL;  /* should never happen, but be safe */
1059                 }
1060
1061                 ret = write_one_word(map, &private->chips[chipnum], ofs, datum);
1062
1063                 if (ret) {
1064                         return ret;
1065                 }
1066                 
1067                 (*retlen) += n;
1068         }
1069
1070         return 0;
1071 }
1072
1073
1074
1075 static inline int erase_one_block(struct map_info *map, struct flchip *chip,
1076                                   unsigned long adr, u_long size)
1077 {
1078         unsigned long timeo = jiffies + HZ;
1079         struct amd_flash_private *private = map->fldrv_priv;
1080         DECLARE_WAITQUEUE(wait, current);
1081
1082 retry:
1083         spin_lock_bh(chip->mutex);
1084
1085         if (chip->state != FL_READY){
1086                 set_current_state(TASK_UNINTERRUPTIBLE);
1087                 add_wait_queue(&chip->wq, &wait);
1088                 
1089                 spin_unlock_bh(chip->mutex);
1090
1091                 schedule();
1092                 remove_wait_queue(&chip->wq, &wait);
1093
1094                 if (signal_pending(current)) {
1095                         return -EINTR;
1096                 }
1097
1098                 timeo = jiffies + HZ;
1099
1100                 goto retry;
1101         }       
1102
1103         chip->state = FL_ERASING;
1104
1105         adr += chip->start;
1106         ENABLE_VPP(map);
1107         send_cmd(map, chip->start, CMD_SECTOR_ERASE_UNLOCK_DATA);
1108         send_cmd_to_addr(map, chip->start, CMD_SECTOR_ERASE_UNLOCK_DATA_2, adr);
1109         
1110         timeo = jiffies + (HZ * 20);
1111
1112         spin_unlock_bh(chip->mutex);
1113         msleep(1000);
1114         spin_lock_bh(chip->mutex);
1115         
1116         while (flash_is_busy(map, adr, private->interleave)) {
1117
1118                 if (chip->state != FL_ERASING) {
1119                         /* Someone's suspended the erase. Sleep */
1120                         set_current_state(TASK_UNINTERRUPTIBLE);
1121                         add_wait_queue(&chip->wq, &wait);
1122                         
1123                         spin_unlock_bh(chip->mutex);
1124                         printk(KERN_INFO "%s: erase suspended. Sleeping\n",
1125                                map->name);
1126                         schedule();
1127                         remove_wait_queue(&chip->wq, &wait);
1128                         
1129                         if (signal_pending(current)) {
1130                                 return -EINTR;
1131                         }
1132                         
1133                         timeo = jiffies + (HZ*2); /* FIXME */
1134                         spin_lock_bh(chip->mutex);
1135                         continue;
1136                 }
1137
1138                 /* OK Still waiting */
1139                 if (time_after(jiffies, timeo)) {
1140                         chip->state = FL_READY;
1141                         spin_unlock_bh(chip->mutex);
1142                         printk(KERN_WARNING "%s: waiting for erase to complete "
1143                                "timed out.\n", map->name);
1144                         DISABLE_VPP(map);
1145
1146                         return -EIO;
1147                 }
1148                 
1149                 /* Latency issues. Drop the lock, wait a while and retry */
1150                 spin_unlock_bh(chip->mutex);
1151
1152                 if (need_resched())
1153                         schedule();
1154                 else
1155                         udelay(1);
1156                 
1157                 spin_lock_bh(chip->mutex);
1158         }
1159
1160         /* Verify every single word */
1161         {
1162                 int address;
1163                 int error = 0;
1164                 __u8 verify;
1165
1166                 for (address = adr; address < (adr + size); address++) {
1167                         if ((verify = map_read8(map, address)) != 0xFF) {
1168                                 error = 1;
1169                                 break;
1170                         }
1171                 }
1172                 if (error) {
1173                         chip->state = FL_READY;
1174                         spin_unlock_bh(chip->mutex);
1175                         printk(KERN_WARNING
1176                                "%s: verify error at 0x%x, size %ld.\n",
1177                                map->name, address, size);
1178                         DISABLE_VPP(map);
1179
1180                         return -EIO;
1181                 }
1182         }
1183         
1184         DISABLE_VPP(map);
1185         chip->state = FL_READY;
1186         wake_up(&chip->wq);
1187         spin_unlock_bh(chip->mutex);
1188
1189         return 0;
1190 }
1191
1192
1193
1194 static int amd_flash_erase(struct mtd_info *mtd, struct erase_info *instr)
1195 {
1196         struct map_info *map = mtd->priv;
1197         struct amd_flash_private *private = map->fldrv_priv;
1198         unsigned long adr, len;
1199         int chipnum;
1200         int ret = 0;
1201         int i;
1202         int first;
1203         struct mtd_erase_region_info *regions = mtd->eraseregions;
1204
1205         if (instr->addr > mtd->size) {
1206                 return -EINVAL;
1207         }
1208
1209         if ((instr->len + instr->addr) > mtd->size) {
1210                 return -EINVAL;
1211         }
1212
1213         /* Check that both start and end of the requested erase are
1214          * aligned with the erasesize at the appropriate addresses.
1215          */
1216
1217         i = 0;
1218
1219         /* Skip all erase regions which are ended before the start of
1220            the requested erase. Actually, to save on the calculations,
1221            we skip to the first erase region which starts after the
1222            start of the requested erase, and then go back one.
1223         */
1224
1225         while ((i < mtd->numeraseregions) &&
1226                (instr->addr >= regions[i].offset)) {
1227                i++;
1228         }
1229         i--;
1230
1231         /* OK, now i is pointing at the erase region in which this
1232          * erase request starts. Check the start of the requested
1233          * erase range is aligned with the erase size which is in
1234          * effect here.
1235          */
1236
1237         if (instr->addr & (regions[i].erasesize-1)) {
1238                 return -EINVAL;
1239         }
1240
1241         /* Remember the erase region we start on. */
1242
1243         first = i;
1244
1245         /* Next, check that the end of the requested erase is aligned
1246          * with the erase region at that address.
1247          */
1248
1249         while ((i < mtd->numeraseregions) && 
1250                ((instr->addr + instr->len) >= regions[i].offset)) {
1251                 i++;
1252         }
1253
1254         /* As before, drop back one to point at the region in which
1255          * the address actually falls.
1256          */
1257
1258         i--;
1259
1260         if ((instr->addr + instr->len) & (regions[i].erasesize-1)) {
1261                 return -EINVAL;
1262         }
1263
1264         chipnum = instr->addr >> private->chipshift;
1265         adr = instr->addr - (chipnum << private->chipshift);
1266         len = instr->len;
1267
1268         i = first;
1269
1270         while (len) {
1271                 ret = erase_one_block(map, &private->chips[chipnum], adr,
1272                                       regions[i].erasesize);
1273
1274                 if (ret) {
1275                         return ret;
1276                 }
1277
1278                 adr += regions[i].erasesize;
1279                 len -= regions[i].erasesize;
1280
1281                 if ((adr % (1 << private->chipshift)) ==
1282                     ((regions[i].offset + (regions[i].erasesize *
1283                                            regions[i].numblocks))
1284                      % (1 << private->chipshift))) {
1285                         i++;
1286                 }
1287
1288                 if (adr >> private->chipshift) {
1289                         adr = 0;
1290                         chipnum++;
1291                         if (chipnum >= private->numchips) {
1292                                 break;
1293                         }
1294                 }
1295         }
1296                 
1297         instr->state = MTD_ERASE_DONE;
1298         mtd_erase_callback(instr);
1299         
1300         return 0;
1301 }
1302
1303
1304
1305 static void amd_flash_sync(struct mtd_info *mtd)
1306 {
1307         struct map_info *map = mtd->priv;
1308         struct amd_flash_private *private = map->fldrv_priv;
1309         int i;
1310         struct flchip *chip;
1311         int ret = 0;
1312         DECLARE_WAITQUEUE(wait, current);
1313
1314         for (i = 0; !ret && (i < private->numchips); i++) {
1315                 chip = &private->chips[i];
1316
1317         retry:
1318                 spin_lock_bh(chip->mutex);
1319
1320                 switch(chip->state) {
1321                 case FL_READY:
1322                 case FL_STATUS:
1323                 case FL_CFI_QUERY:
1324                 case FL_JEDEC_QUERY:
1325                         chip->oldstate = chip->state;
1326                         chip->state = FL_SYNCING;
1327                         /* No need to wake_up() on this state change - 
1328                          * as the whole point is that nobody can do anything
1329                          * with the chip now anyway.
1330                          */
1331                 case FL_SYNCING:
1332                         spin_unlock_bh(chip->mutex);
1333                         break;
1334
1335                 default:
1336                         /* Not an idle state */
1337                         add_wait_queue(&chip->wq, &wait);
1338                         
1339                         spin_unlock_bh(chip->mutex);
1340
1341                         schedule();
1342
1343                         remove_wait_queue(&chip->wq, &wait);
1344                         
1345                         goto retry;
1346                 }
1347         }
1348
1349         /* Unlock the chips again */
1350         for (i--; i >= 0; i--) {
1351                 chip = &private->chips[i];
1352
1353                 spin_lock_bh(chip->mutex);
1354                 
1355                 if (chip->state == FL_SYNCING) {
1356                         chip->state = chip->oldstate;
1357                         wake_up(&chip->wq);
1358                 }
1359                 spin_unlock_bh(chip->mutex);
1360         }
1361 }
1362
1363
1364
1365 static int amd_flash_suspend(struct mtd_info *mtd)
1366 {
1367 printk("amd_flash_suspend(): not implemented!\n");
1368         return -EINVAL;
1369 }
1370
1371
1372
1373 static void amd_flash_resume(struct mtd_info *mtd)
1374 {
1375 printk("amd_flash_resume(): not implemented!\n");
1376 }
1377
1378
1379
1380 static void amd_flash_destroy(struct mtd_info *mtd)
1381 {
1382         struct map_info *map = mtd->priv;
1383         struct amd_flash_private *private = map->fldrv_priv;
1384         kfree(private);
1385 }
1386
1387 int __init amd_flash_init(void)
1388 {
1389         register_mtd_chip_driver(&amd_flash_chipdrv);
1390         return 0;
1391 }
1392
1393 void __exit amd_flash_exit(void)
1394 {
1395         unregister_mtd_chip_driver(&amd_flash_chipdrv);
1396 }
1397
1398 module_init(amd_flash_init);
1399 module_exit(amd_flash_exit);
1400
1401 MODULE_LICENSE("GPL");
1402 MODULE_AUTHOR("Jonas Holmberg <jonas.holmberg@axis.com>");
1403 MODULE_DESCRIPTION("Old MTD chip driver for AMD flash chips");