| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 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"); |