diff options
-rw-r--r-- | drivers/mtd/nand/au1550nd.c | 139 |
1 files changed, 139 insertions, 0 deletions
diff --git a/drivers/mtd/nand/au1550nd.c b/drivers/mtd/nand/au1550nd.c index 839b35a386b6..d9a0143e1d3a 100644 --- a/drivers/mtd/nand/au1550nd.c +++ b/drivers/mtd/nand/au1550nd.c | |||
@@ -14,6 +14,7 @@ | |||
14 | #include <linux/slab.h> | 14 | #include <linux/slab.h> |
15 | #include <linux/init.h> | 15 | #include <linux/init.h> |
16 | #include <linux/module.h> | 16 | #include <linux/module.h> |
17 | #include <linux/interrupt.h> | ||
17 | #include <linux/mtd/mtd.h> | 18 | #include <linux/mtd/mtd.h> |
18 | #include <linux/mtd/nand.h> | 19 | #include <linux/mtd/nand.h> |
19 | #include <linux/mtd/partitions.h> | 20 | #include <linux/mtd/partitions.h> |
@@ -318,6 +319,141 @@ int au1550_device_ready(struct mtd_info *mtd) | |||
318 | return ret; | 319 | return ret; |
319 | } | 320 | } |
320 | 321 | ||
322 | /** | ||
323 | * au1550_select_chip - control -CE line | ||
324 | * Forbid driving -CE manually permitting the NAND controller to do this. | ||
325 | * Keeping -CE asserted during the whole sector reads interferes with the | ||
326 | * NOR flash and PCMCIA drivers as it causes contention on the static bus. | ||
327 | * We only have to hold -CE low for the NAND read commands since the flash | ||
328 | * chip needs it to be asserted during chip not ready time but the NAND | ||
329 | * controller keeps it released. | ||
330 | * | ||
331 | * @mtd: MTD device structure | ||
332 | * @chip: chipnumber to select, -1 for deselect | ||
333 | */ | ||
334 | static void au1550_select_chip(struct mtd_info *mtd, int chip) | ||
335 | { | ||
336 | } | ||
337 | |||
338 | /** | ||
339 | * au1550_command - Send command to NAND device | ||
340 | * @mtd: MTD device structure | ||
341 | * @command: the command to be sent | ||
342 | * @column: the column address for this command, -1 if none | ||
343 | * @page_addr: the page address for this command, -1 if none | ||
344 | */ | ||
345 | static void au1550_command(struct mtd_info *mtd, unsigned command, int column, int page_addr) | ||
346 | { | ||
347 | register struct nand_chip *this = mtd->priv; | ||
348 | int ce_override = 0, i; | ||
349 | ulong flags; | ||
350 | |||
351 | /* Begin command latch cycle */ | ||
352 | this->hwcontrol(mtd, NAND_CTL_SETCLE); | ||
353 | /* | ||
354 | * Write out the command to the device. | ||
355 | */ | ||
356 | if (command == NAND_CMD_SEQIN) { | ||
357 | int readcmd; | ||
358 | |||
359 | if (column >= mtd->oobblock) { | ||
360 | /* OOB area */ | ||
361 | column -= mtd->oobblock; | ||
362 | readcmd = NAND_CMD_READOOB; | ||
363 | } else if (column < 256) { | ||
364 | /* First 256 bytes --> READ0 */ | ||
365 | readcmd = NAND_CMD_READ0; | ||
366 | } else { | ||
367 | column -= 256; | ||
368 | readcmd = NAND_CMD_READ1; | ||
369 | } | ||
370 | this->write_byte(mtd, readcmd); | ||
371 | } | ||
372 | this->write_byte(mtd, command); | ||
373 | |||
374 | /* Set ALE and clear CLE to start address cycle */ | ||
375 | this->hwcontrol(mtd, NAND_CTL_CLRCLE); | ||
376 | |||
377 | if (column != -1 || page_addr != -1) { | ||
378 | this->hwcontrol(mtd, NAND_CTL_SETALE); | ||
379 | |||
380 | /* Serially input address */ | ||
381 | if (column != -1) { | ||
382 | /* Adjust columns for 16 bit buswidth */ | ||
383 | if (this->options & NAND_BUSWIDTH_16) | ||
384 | column >>= 1; | ||
385 | this->write_byte(mtd, column); | ||
386 | } | ||
387 | if (page_addr != -1) { | ||
388 | this->write_byte(mtd, (u8)(page_addr & 0xff)); | ||
389 | |||
390 | if (command == NAND_CMD_READ0 || | ||
391 | command == NAND_CMD_READ1 || | ||
392 | command == NAND_CMD_READOOB) { | ||
393 | /* | ||
394 | * NAND controller will release -CE after | ||
395 | * the last address byte is written, so we'll | ||
396 | * have to forcibly assert it. No interrupts | ||
397 | * are allowed while we do this as we don't | ||
398 | * want the NOR flash or PCMCIA drivers to | ||
399 | * steal our precious bytes of data... | ||
400 | */ | ||
401 | ce_override = 1; | ||
402 | local_irq_save(flags); | ||
403 | this->hwcontrol(mtd, NAND_CTL_SETNCE); | ||
404 | } | ||
405 | |||
406 | this->write_byte(mtd, (u8)(page_addr >> 8)); | ||
407 | |||
408 | /* One more address cycle for devices > 32MiB */ | ||
409 | if (this->chipsize > (32 << 20)) | ||
410 | this->write_byte(mtd, (u8)((page_addr >> 16) & 0x0f)); | ||
411 | } | ||
412 | /* Latch in address */ | ||
413 | this->hwcontrol(mtd, NAND_CTL_CLRALE); | ||
414 | } | ||
415 | |||
416 | /* | ||
417 | * Program and erase have their own busy handlers. | ||
418 | * Status and sequential in need no delay. | ||
419 | */ | ||
420 | switch (command) { | ||
421 | |||
422 | case NAND_CMD_PAGEPROG: | ||
423 | case NAND_CMD_ERASE1: | ||
424 | case NAND_CMD_ERASE2: | ||
425 | case NAND_CMD_SEQIN: | ||
426 | case NAND_CMD_STATUS: | ||
427 | return; | ||
428 | |||
429 | case NAND_CMD_RESET: | ||
430 | break; | ||
431 | |||
432 | case NAND_CMD_READ0: | ||
433 | case NAND_CMD_READ1: | ||
434 | case NAND_CMD_READOOB: | ||
435 | /* Check if we're really driving -CE low (just in case) */ | ||
436 | if (unlikely(!ce_override)) | ||
437 | break; | ||
438 | |||
439 | /* Apply a short delay always to ensure that we do wait tWB. */ | ||
440 | ndelay(100); | ||
441 | /* Wait for a chip to become ready... */ | ||
442 | for (i = this->chip_delay; !this->dev_ready(mtd) && i > 0; --i) | ||
443 | udelay(1); | ||
444 | |||
445 | /* Release -CE and re-enable interrupts. */ | ||
446 | this->hwcontrol(mtd, NAND_CTL_CLRNCE); | ||
447 | local_irq_restore(flags); | ||
448 | return; | ||
449 | } | ||
450 | /* Apply this short delay always to ensure that we do wait tWB. */ | ||
451 | ndelay(100); | ||
452 | |||
453 | while(!this->dev_ready(mtd)); | ||
454 | } | ||
455 | |||
456 | |||
321 | /* | 457 | /* |
322 | * Main initialization routine | 458 | * Main initialization routine |
323 | */ | 459 | */ |
@@ -437,6 +573,9 @@ static int __init au1xxx_nand_init(void) | |||
437 | /* Set address of hardware control function */ | 573 | /* Set address of hardware control function */ |
438 | this->hwcontrol = au1550_hwcontrol; | 574 | this->hwcontrol = au1550_hwcontrol; |
439 | this->dev_ready = au1550_device_ready; | 575 | this->dev_ready = au1550_device_ready; |
576 | this->select_chip = au1550_select_chip; | ||
577 | this->cmdfunc = au1550_command; | ||
578 | |||
440 | /* 30 us command delay time */ | 579 | /* 30 us command delay time */ |
441 | this->chip_delay = 30; | 580 | this->chip_delay = 30; |
442 | this->eccmode = NAND_ECC_SOFT; | 581 | this->eccmode = NAND_ECC_SOFT; |