diff options
Diffstat (limited to 'drivers/mtd/chips/sharp.c')
-rw-r--r-- | drivers/mtd/chips/sharp.c | 596 |
1 files changed, 596 insertions, 0 deletions
diff --git a/drivers/mtd/chips/sharp.c b/drivers/mtd/chips/sharp.c new file mode 100644 index 000000000000..c3cf0f63bc93 --- /dev/null +++ b/drivers/mtd/chips/sharp.c | |||
@@ -0,0 +1,596 @@ | |||
1 | /* | ||
2 | * MTD chip driver for pre-CFI Sharp flash chips | ||
3 | * | ||
4 | * Copyright 2000,2001 David A. Schleef <ds@schleef.org> | ||
5 | * 2000,2001 Lineo, Inc. | ||
6 | * | ||
7 | * $Id: sharp.c,v 1.14 2004/08/09 13:19:43 dwmw2 Exp $ | ||
8 | * | ||
9 | * Devices supported: | ||
10 | * LH28F016SCT Symmetrical block flash memory, 2Mx8 | ||
11 | * LH28F008SCT Symmetrical block flash memory, 1Mx8 | ||
12 | * | ||
13 | * Documentation: | ||
14 | * http://www.sharpmeg.com/datasheets/memic/flashcmp/ | ||
15 | * http://www.sharpmeg.com/datasheets/memic/flashcmp/01symf/16m/016sctl9.pdf | ||
16 | * 016sctl9.pdf | ||
17 | * | ||
18 | * Limitations: | ||
19 | * This driver only supports 4x1 arrangement of chips. | ||
20 | * Not tested on anything but PowerPC. | ||
21 | */ | ||
22 | |||
23 | #include <linux/kernel.h> | ||
24 | #include <linux/module.h> | ||
25 | #include <linux/types.h> | ||
26 | #include <linux/sched.h> | ||
27 | #include <linux/errno.h> | ||
28 | #include <linux/interrupt.h> | ||
29 | #include <linux/mtd/map.h> | ||
30 | #include <linux/mtd/mtd.h> | ||
31 | #include <linux/mtd/cfi.h> | ||
32 | #include <linux/delay.h> | ||
33 | #include <linux/init.h> | ||
34 | |||
35 | #define CMD_RESET 0xffffffff | ||
36 | #define CMD_READ_ID 0x90909090 | ||
37 | #define CMD_READ_STATUS 0x70707070 | ||
38 | #define CMD_CLEAR_STATUS 0x50505050 | ||
39 | #define CMD_BLOCK_ERASE_1 0x20202020 | ||
40 | #define CMD_BLOCK_ERASE_2 0xd0d0d0d0 | ||
41 | #define CMD_BYTE_WRITE 0x40404040 | ||
42 | #define CMD_SUSPEND 0xb0b0b0b0 | ||
43 | #define CMD_RESUME 0xd0d0d0d0 | ||
44 | #define CMD_SET_BLOCK_LOCK_1 0x60606060 | ||
45 | #define CMD_SET_BLOCK_LOCK_2 0x01010101 | ||
46 | #define CMD_SET_MASTER_LOCK_1 0x60606060 | ||
47 | #define CMD_SET_MASTER_LOCK_2 0xf1f1f1f1 | ||
48 | #define CMD_CLEAR_BLOCK_LOCKS_1 0x60606060 | ||
49 | #define CMD_CLEAR_BLOCK_LOCKS_2 0xd0d0d0d0 | ||
50 | |||
51 | #define SR_READY 0x80808080 // 1 = ready | ||
52 | #define SR_ERASE_SUSPEND 0x40404040 // 1 = block erase suspended | ||
53 | #define SR_ERROR_ERASE 0x20202020 // 1 = error in block erase or clear lock bits | ||
54 | #define SR_ERROR_WRITE 0x10101010 // 1 = error in byte write or set lock bit | ||
55 | #define SR_VPP 0x08080808 // 1 = Vpp is low | ||
56 | #define SR_WRITE_SUSPEND 0x04040404 // 1 = byte write suspended | ||
57 | #define SR_PROTECT 0x02020202 // 1 = lock bit set | ||
58 | #define SR_RESERVED 0x01010101 | ||
59 | |||
60 | #define SR_ERRORS (SR_ERROR_ERASE|SR_ERROR_WRITE|SR_VPP|SR_PROTECT) | ||
61 | |||
62 | /* Configuration options */ | ||
63 | |||
64 | #undef AUTOUNLOCK /* automatically unlocks blocks before erasing */ | ||
65 | |||
66 | struct mtd_info *sharp_probe(struct map_info *); | ||
67 | |||
68 | static int sharp_probe_map(struct map_info *map,struct mtd_info *mtd); | ||
69 | |||
70 | static int sharp_read(struct mtd_info *mtd, loff_t from, size_t len, | ||
71 | size_t *retlen, u_char *buf); | ||
72 | static int sharp_write(struct mtd_info *mtd, loff_t from, size_t len, | ||
73 | size_t *retlen, const u_char *buf); | ||
74 | static int sharp_erase(struct mtd_info *mtd, struct erase_info *instr); | ||
75 | static void sharp_sync(struct mtd_info *mtd); | ||
76 | static int sharp_suspend(struct mtd_info *mtd); | ||
77 | static void sharp_resume(struct mtd_info *mtd); | ||
78 | static void sharp_destroy(struct mtd_info *mtd); | ||
79 | |||
80 | static int sharp_write_oneword(struct map_info *map, struct flchip *chip, | ||
81 | unsigned long adr, __u32 datum); | ||
82 | static int sharp_erase_oneblock(struct map_info *map, struct flchip *chip, | ||
83 | unsigned long adr); | ||
84 | #ifdef AUTOUNLOCK | ||
85 | static void sharp_unlock_oneblock(struct map_info *map, struct flchip *chip, | ||
86 | unsigned long adr); | ||
87 | #endif | ||
88 | |||
89 | |||
90 | struct sharp_info{ | ||
91 | struct flchip *chip; | ||
92 | int bogus; | ||
93 | int chipshift; | ||
94 | int numchips; | ||
95 | struct flchip chips[1]; | ||
96 | }; | ||
97 | |||
98 | struct mtd_info *sharp_probe(struct map_info *map); | ||
99 | static void sharp_destroy(struct mtd_info *mtd); | ||
100 | |||
101 | static struct mtd_chip_driver sharp_chipdrv = { | ||
102 | .probe = sharp_probe, | ||
103 | .destroy = sharp_destroy, | ||
104 | .name = "sharp", | ||
105 | .module = THIS_MODULE | ||
106 | }; | ||
107 | |||
108 | |||
109 | struct mtd_info *sharp_probe(struct map_info *map) | ||
110 | { | ||
111 | struct mtd_info *mtd = NULL; | ||
112 | struct sharp_info *sharp = NULL; | ||
113 | int width; | ||
114 | |||
115 | mtd = kmalloc(sizeof(*mtd), GFP_KERNEL); | ||
116 | if(!mtd) | ||
117 | return NULL; | ||
118 | |||
119 | sharp = kmalloc(sizeof(*sharp), GFP_KERNEL); | ||
120 | if(!sharp) { | ||
121 | kfree(mtd); | ||
122 | return NULL; | ||
123 | } | ||
124 | |||
125 | memset(mtd, 0, sizeof(*mtd)); | ||
126 | |||
127 | width = sharp_probe_map(map,mtd); | ||
128 | if(!width){ | ||
129 | kfree(mtd); | ||
130 | kfree(sharp); | ||
131 | return NULL; | ||
132 | } | ||
133 | |||
134 | mtd->priv = map; | ||
135 | mtd->type = MTD_NORFLASH; | ||
136 | mtd->erase = sharp_erase; | ||
137 | mtd->read = sharp_read; | ||
138 | mtd->write = sharp_write; | ||
139 | mtd->sync = sharp_sync; | ||
140 | mtd->suspend = sharp_suspend; | ||
141 | mtd->resume = sharp_resume; | ||
142 | mtd->flags = MTD_CAP_NORFLASH; | ||
143 | mtd->name = map->name; | ||
144 | |||
145 | memset(sharp, 0, sizeof(*sharp)); | ||
146 | sharp->chipshift = 23; | ||
147 | sharp->numchips = 1; | ||
148 | sharp->chips[0].start = 0; | ||
149 | sharp->chips[0].state = FL_READY; | ||
150 | sharp->chips[0].mutex = &sharp->chips[0]._spinlock; | ||
151 | sharp->chips[0].word_write_time = 0; | ||
152 | init_waitqueue_head(&sharp->chips[0].wq); | ||
153 | spin_lock_init(&sharp->chips[0]._spinlock); | ||
154 | |||
155 | map->fldrv = &sharp_chipdrv; | ||
156 | map->fldrv_priv = sharp; | ||
157 | |||
158 | __module_get(THIS_MODULE); | ||
159 | return mtd; | ||
160 | } | ||
161 | |||
162 | static int sharp_probe_map(struct map_info *map,struct mtd_info *mtd) | ||
163 | { | ||
164 | unsigned long tmp; | ||
165 | unsigned long base = 0; | ||
166 | u32 read0, read4; | ||
167 | int width = 4; | ||
168 | |||
169 | tmp = map_read32(map, base+0); | ||
170 | |||
171 | map_write32(map, CMD_READ_ID, base+0); | ||
172 | |||
173 | read0=map_read32(map, base+0); | ||
174 | read4=map_read32(map, base+4); | ||
175 | if(read0 == 0x89898989){ | ||
176 | printk("Looks like sharp flash\n"); | ||
177 | switch(read4){ | ||
178 | case 0xaaaaaaaa: | ||
179 | case 0xa0a0a0a0: | ||
180 | /* aa - LH28F016SCT-L95 2Mx8, 32 64k blocks*/ | ||
181 | /* a0 - LH28F016SCT-Z4 2Mx8, 32 64k blocks*/ | ||
182 | mtd->erasesize = 0x10000 * width; | ||
183 | mtd->size = 0x200000 * width; | ||
184 | return width; | ||
185 | case 0xa6a6a6a6: | ||
186 | /* a6 - LH28F008SCT-L12 1Mx8, 16 64k blocks*/ | ||
187 | /* a6 - LH28F008SCR-L85 1Mx8, 16 64k blocks*/ | ||
188 | mtd->erasesize = 0x10000 * width; | ||
189 | mtd->size = 0x100000 * width; | ||
190 | return width; | ||
191 | #if 0 | ||
192 | case 0x00000000: /* unknown */ | ||
193 | /* XX - LH28F004SCT 512kx8, 8 64k blocks*/ | ||
194 | mtd->erasesize = 0x10000 * width; | ||
195 | mtd->size = 0x80000 * width; | ||
196 | return width; | ||
197 | #endif | ||
198 | default: | ||
199 | printk("Sort-of looks like sharp flash, 0x%08x 0x%08x\n", | ||
200 | read0,read4); | ||
201 | } | ||
202 | }else if((map_read32(map, base+0) == CMD_READ_ID)){ | ||
203 | /* RAM, probably */ | ||
204 | printk("Looks like RAM\n"); | ||
205 | map_write32(map, tmp, base+0); | ||
206 | }else{ | ||
207 | printk("Doesn't look like sharp flash, 0x%08x 0x%08x\n", | ||
208 | read0,read4); | ||
209 | } | ||
210 | |||
211 | return 0; | ||
212 | } | ||
213 | |||
214 | /* This function returns with the chip->mutex lock held. */ | ||
215 | static int sharp_wait(struct map_info *map, struct flchip *chip) | ||
216 | { | ||
217 | __u16 status; | ||
218 | unsigned long timeo = jiffies + HZ; | ||
219 | DECLARE_WAITQUEUE(wait, current); | ||
220 | int adr = 0; | ||
221 | |||
222 | retry: | ||
223 | spin_lock_bh(chip->mutex); | ||
224 | |||
225 | switch(chip->state){ | ||
226 | case FL_READY: | ||
227 | map_write32(map,CMD_READ_STATUS,adr); | ||
228 | chip->state = FL_STATUS; | ||
229 | case FL_STATUS: | ||
230 | status = map_read32(map,adr); | ||
231 | //printk("status=%08x\n",status); | ||
232 | |||
233 | udelay(100); | ||
234 | if((status & SR_READY)!=SR_READY){ | ||
235 | //printk(".status=%08x\n",status); | ||
236 | udelay(100); | ||
237 | } | ||
238 | break; | ||
239 | default: | ||
240 | printk("Waiting for chip\n"); | ||
241 | |||
242 | set_current_state(TASK_INTERRUPTIBLE); | ||
243 | add_wait_queue(&chip->wq, &wait); | ||
244 | |||
245 | spin_unlock_bh(chip->mutex); | ||
246 | |||
247 | schedule(); | ||
248 | remove_wait_queue(&chip->wq, &wait); | ||
249 | |||
250 | if(signal_pending(current)) | ||
251 | return -EINTR; | ||
252 | |||
253 | timeo = jiffies + HZ; | ||
254 | |||
255 | goto retry; | ||
256 | } | ||
257 | |||
258 | map_write32(map,CMD_RESET, adr); | ||
259 | |||
260 | chip->state = FL_READY; | ||
261 | |||
262 | return 0; | ||
263 | } | ||
264 | |||
265 | static void sharp_release(struct flchip *chip) | ||
266 | { | ||
267 | wake_up(&chip->wq); | ||
268 | spin_unlock_bh(chip->mutex); | ||
269 | } | ||
270 | |||
271 | static int sharp_read(struct mtd_info *mtd, loff_t from, size_t len, | ||
272 | size_t *retlen, u_char *buf) | ||
273 | { | ||
274 | struct map_info *map = mtd->priv; | ||
275 | struct sharp_info *sharp = map->fldrv_priv; | ||
276 | int chipnum; | ||
277 | int ret = 0; | ||
278 | int ofs = 0; | ||
279 | |||
280 | chipnum = (from >> sharp->chipshift); | ||
281 | ofs = from & ((1 << sharp->chipshift)-1); | ||
282 | |||
283 | *retlen = 0; | ||
284 | |||
285 | while(len){ | ||
286 | unsigned long thislen; | ||
287 | |||
288 | if(chipnum>=sharp->numchips) | ||
289 | break; | ||
290 | |||
291 | thislen = len; | ||
292 | if(ofs+thislen >= (1<<sharp->chipshift)) | ||
293 | thislen = (1<<sharp->chipshift) - ofs; | ||
294 | |||
295 | ret = sharp_wait(map,&sharp->chips[chipnum]); | ||
296 | if(ret<0) | ||
297 | break; | ||
298 | |||
299 | map_copy_from(map,buf,ofs,thislen); | ||
300 | |||
301 | sharp_release(&sharp->chips[chipnum]); | ||
302 | |||
303 | *retlen += thislen; | ||
304 | len -= thislen; | ||
305 | buf += thislen; | ||
306 | |||
307 | ofs = 0; | ||
308 | chipnum++; | ||
309 | } | ||
310 | return ret; | ||
311 | } | ||
312 | |||
313 | static int sharp_write(struct mtd_info *mtd, loff_t to, size_t len, | ||
314 | size_t *retlen, const u_char *buf) | ||
315 | { | ||
316 | struct map_info *map = mtd->priv; | ||
317 | struct sharp_info *sharp = map->fldrv_priv; | ||
318 | int ret = 0; | ||
319 | int i,j; | ||
320 | int chipnum; | ||
321 | unsigned long ofs; | ||
322 | union { u32 l; unsigned char uc[4]; } tbuf; | ||
323 | |||
324 | *retlen = 0; | ||
325 | |||
326 | while(len){ | ||
327 | tbuf.l = 0xffffffff; | ||
328 | chipnum = to >> sharp->chipshift; | ||
329 | ofs = to & ((1<<sharp->chipshift)-1); | ||
330 | |||
331 | j=0; | ||
332 | for(i=ofs&3;i<4 && len;i++){ | ||
333 | tbuf.uc[i] = *buf; | ||
334 | buf++; | ||
335 | to++; | ||
336 | len--; | ||
337 | j++; | ||
338 | } | ||
339 | sharp_write_oneword(map, &sharp->chips[chipnum], ofs&~3, tbuf.l); | ||
340 | if(ret<0) | ||
341 | return ret; | ||
342 | (*retlen)+=j; | ||
343 | } | ||
344 | |||
345 | return 0; | ||
346 | } | ||
347 | |||
348 | static int sharp_write_oneword(struct map_info *map, struct flchip *chip, | ||
349 | unsigned long adr, __u32 datum) | ||
350 | { | ||
351 | int ret; | ||
352 | int timeo; | ||
353 | int try; | ||
354 | int i; | ||
355 | int status = 0; | ||
356 | |||
357 | ret = sharp_wait(map,chip); | ||
358 | |||
359 | for(try=0;try<10;try++){ | ||
360 | map_write32(map,CMD_BYTE_WRITE,adr); | ||
361 | /* cpu_to_le32 -> hack to fix the writel be->le conversion */ | ||
362 | map_write32(map,cpu_to_le32(datum),adr); | ||
363 | |||
364 | chip->state = FL_WRITING; | ||
365 | |||
366 | timeo = jiffies + (HZ/2); | ||
367 | |||
368 | map_write32(map,CMD_READ_STATUS,adr); | ||
369 | for(i=0;i<100;i++){ | ||
370 | status = map_read32(map,adr); | ||
371 | if((status & SR_READY)==SR_READY) | ||
372 | break; | ||
373 | } | ||
374 | if(i==100){ | ||
375 | printk("sharp: timed out writing\n"); | ||
376 | } | ||
377 | |||
378 | if(!(status&SR_ERRORS)) | ||
379 | break; | ||
380 | |||
381 | printk("sharp: error writing byte at addr=%08lx status=%08x\n",adr,status); | ||
382 | |||
383 | map_write32(map,CMD_CLEAR_STATUS,adr); | ||
384 | } | ||
385 | map_write32(map,CMD_RESET,adr); | ||
386 | chip->state = FL_READY; | ||
387 | |||
388 | wake_up(&chip->wq); | ||
389 | spin_unlock_bh(chip->mutex); | ||
390 | |||
391 | return 0; | ||
392 | } | ||
393 | |||
394 | static int sharp_erase(struct mtd_info *mtd, struct erase_info *instr) | ||
395 | { | ||
396 | struct map_info *map = mtd->priv; | ||
397 | struct sharp_info *sharp = map->fldrv_priv; | ||
398 | unsigned long adr,len; | ||
399 | int chipnum, ret=0; | ||
400 | |||
401 | //printk("sharp_erase()\n"); | ||
402 | if(instr->addr & (mtd->erasesize - 1)) | ||
403 | return -EINVAL; | ||
404 | if(instr->len & (mtd->erasesize - 1)) | ||
405 | return -EINVAL; | ||
406 | if(instr->len + instr->addr > mtd->size) | ||
407 | return -EINVAL; | ||
408 | |||
409 | chipnum = instr->addr >> sharp->chipshift; | ||
410 | adr = instr->addr & ((1<<sharp->chipshift)-1); | ||
411 | len = instr->len; | ||
412 | |||
413 | while(len){ | ||
414 | ret = sharp_erase_oneblock(map, &sharp->chips[chipnum], adr); | ||
415 | if(ret)return ret; | ||
416 | |||
417 | adr += mtd->erasesize; | ||
418 | len -= mtd->erasesize; | ||
419 | if(adr >> sharp->chipshift){ | ||
420 | adr = 0; | ||
421 | chipnum++; | ||
422 | if(chipnum>=sharp->numchips) | ||
423 | break; | ||
424 | } | ||
425 | } | ||
426 | |||
427 | instr->state = MTD_ERASE_DONE; | ||
428 | mtd_erase_callback(instr); | ||
429 | |||
430 | return 0; | ||
431 | } | ||
432 | |||
433 | static int sharp_do_wait_for_ready(struct map_info *map, struct flchip *chip, | ||
434 | unsigned long adr) | ||
435 | { | ||
436 | int ret; | ||
437 | unsigned long timeo; | ||
438 | int status; | ||
439 | DECLARE_WAITQUEUE(wait, current); | ||
440 | |||
441 | map_write32(map,CMD_READ_STATUS,adr); | ||
442 | status = map_read32(map,adr); | ||
443 | |||
444 | timeo = jiffies + HZ; | ||
445 | |||
446 | while(time_before(jiffies, timeo)){ | ||
447 | map_write32(map,CMD_READ_STATUS,adr); | ||
448 | status = map_read32(map,adr); | ||
449 | if((status & SR_READY)==SR_READY){ | ||
450 | ret = 0; | ||
451 | goto out; | ||
452 | } | ||
453 | set_current_state(TASK_INTERRUPTIBLE); | ||
454 | add_wait_queue(&chip->wq, &wait); | ||
455 | |||
456 | //spin_unlock_bh(chip->mutex); | ||
457 | |||
458 | schedule_timeout(1); | ||
459 | schedule(); | ||
460 | remove_wait_queue(&chip->wq, &wait); | ||
461 | |||
462 | //spin_lock_bh(chip->mutex); | ||
463 | |||
464 | if (signal_pending(current)){ | ||
465 | ret = -EINTR; | ||
466 | goto out; | ||
467 | } | ||
468 | |||
469 | } | ||
470 | ret = -ETIME; | ||
471 | out: | ||
472 | return ret; | ||
473 | } | ||
474 | |||
475 | static int sharp_erase_oneblock(struct map_info *map, struct flchip *chip, | ||
476 | unsigned long adr) | ||
477 | { | ||
478 | int ret; | ||
479 | //int timeo; | ||
480 | int status; | ||
481 | //int i; | ||
482 | |||
483 | //printk("sharp_erase_oneblock()\n"); | ||
484 | |||
485 | #ifdef AUTOUNLOCK | ||
486 | /* This seems like a good place to do an unlock */ | ||
487 | sharp_unlock_oneblock(map,chip,adr); | ||
488 | #endif | ||
489 | |||
490 | map_write32(map,CMD_BLOCK_ERASE_1,adr); | ||
491 | map_write32(map,CMD_BLOCK_ERASE_2,adr); | ||
492 | |||
493 | chip->state = FL_ERASING; | ||
494 | |||
495 | ret = sharp_do_wait_for_ready(map,chip,adr); | ||
496 | if(ret<0)return ret; | ||
497 | |||
498 | map_write32(map,CMD_READ_STATUS,adr); | ||
499 | status = map_read32(map,adr); | ||
500 | |||
501 | if(!(status&SR_ERRORS)){ | ||
502 | map_write32(map,CMD_RESET,adr); | ||
503 | chip->state = FL_READY; | ||
504 | //spin_unlock_bh(chip->mutex); | ||
505 | return 0; | ||
506 | } | ||
507 | |||
508 | printk("sharp: error erasing block at addr=%08lx status=%08x\n",adr,status); | ||
509 | map_write32(map,CMD_CLEAR_STATUS,adr); | ||
510 | |||
511 | //spin_unlock_bh(chip->mutex); | ||
512 | |||
513 | return -EIO; | ||
514 | } | ||
515 | |||
516 | #ifdef AUTOUNLOCK | ||
517 | static void sharp_unlock_oneblock(struct map_info *map, struct flchip *chip, | ||
518 | unsigned long adr) | ||
519 | { | ||
520 | int i; | ||
521 | int status; | ||
522 | |||
523 | map_write32(map,CMD_CLEAR_BLOCK_LOCKS_1,adr); | ||
524 | map_write32(map,CMD_CLEAR_BLOCK_LOCKS_2,adr); | ||
525 | |||
526 | udelay(100); | ||
527 | |||
528 | status = map_read32(map,adr); | ||
529 | printk("status=%08x\n",status); | ||
530 | |||
531 | for(i=0;i<1000;i++){ | ||
532 | //map_write32(map,CMD_READ_STATUS,adr); | ||
533 | status = map_read32(map,adr); | ||
534 | if((status & SR_READY)==SR_READY) | ||
535 | break; | ||
536 | udelay(100); | ||
537 | } | ||
538 | if(i==1000){ | ||
539 | printk("sharp: timed out unlocking block\n"); | ||
540 | } | ||
541 | |||
542 | if(!(status&SR_ERRORS)){ | ||
543 | map_write32(map,CMD_RESET,adr); | ||
544 | chip->state = FL_READY; | ||
545 | return; | ||
546 | } | ||
547 | |||
548 | printk("sharp: error unlocking block at addr=%08lx status=%08x\n",adr,status); | ||
549 | map_write32(map,CMD_CLEAR_STATUS,adr); | ||
550 | } | ||
551 | #endif | ||
552 | |||
553 | static void sharp_sync(struct mtd_info *mtd) | ||
554 | { | ||
555 | //printk("sharp_sync()\n"); | ||
556 | } | ||
557 | |||
558 | static int sharp_suspend(struct mtd_info *mtd) | ||
559 | { | ||
560 | printk("sharp_suspend()\n"); | ||
561 | return -EINVAL; | ||
562 | } | ||
563 | |||
564 | static void sharp_resume(struct mtd_info *mtd) | ||
565 | { | ||
566 | printk("sharp_resume()\n"); | ||
567 | |||
568 | } | ||
569 | |||
570 | static void sharp_destroy(struct mtd_info *mtd) | ||
571 | { | ||
572 | printk("sharp_destroy()\n"); | ||
573 | |||
574 | } | ||
575 | |||
576 | int __init sharp_probe_init(void) | ||
577 | { | ||
578 | printk("MTD Sharp chip driver <ds@lineo.com>\n"); | ||
579 | |||
580 | register_mtd_chip_driver(&sharp_chipdrv); | ||
581 | |||
582 | return 0; | ||
583 | } | ||
584 | |||
585 | static void __exit sharp_probe_exit(void) | ||
586 | { | ||
587 | unregister_mtd_chip_driver(&sharp_chipdrv); | ||
588 | } | ||
589 | |||
590 | module_init(sharp_probe_init); | ||
591 | module_exit(sharp_probe_exit); | ||
592 | |||
593 | |||
594 | MODULE_LICENSE("GPL"); | ||
595 | MODULE_AUTHOR("David Schleef <ds@schleef.org>"); | ||
596 | MODULE_DESCRIPTION("Old MTD chip driver for pre-CFI Sharp flash chips"); | ||