diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2009-09-23 13:07:49 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2009-09-23 13:07:49 -0400 |
commit | a7c367b95a9d8e65e0f0e7da31f700a556794efb (patch) | |
tree | 5b1bb202801e29e3237381aa7aad5aa288378d5b /drivers/mtd/devices/m25p80.c | |
parent | 15f964bed054821d6d940d3752508c5f96a9ffd3 (diff) | |
parent | e1070211f7327a1f197d535aa886f721a241c32f (diff) |
Merge git://git.infradead.org/mtd-2.6
* git://git.infradead.org/mtd-2.6: (58 commits)
mtd: jedec_probe: add PSD4256G6V id
mtd: OneNand support for Nomadik 8815 SoC (on NHK8815 board)
mtd: nand: driver for Nomadik 8815 SoC (on NHK8815 board)
m25p80: Add Spansion S25FL129P serial flashes
jffs2: Use SLAB_HWCACHE_ALIGN for jffs2_raw_{dirent,inode} slabs
mtd: sh_flctl: register sh_flctl using platform_driver_probe()
mtd: nand: txx9ndfmc: transfer 512 byte at a time if possible
mtd: nand: fix tmio_nand ecc correction
mtd: nand: add __nand_correct_data helper function
mtd: cfi_cmdset_0002: add 0xFF intolerance for M29W128G
mtd: inftl: fix fold chain block number
mtd: jedec: fix compilation problem with I28F640C3B definition
mtd: nand: fix ECC Correction bug for SMC ordering for NDFC driver
mtd: ofpart: Check availability of reg property instead of name property
driver/Makefile: Initialize "mtd" and "spi" before "net"
mtd: omap: adding DMA mode support in nand prefetch/post-write
mtd: omap: add support for nand prefetch-read and post-write
mtd: add nand support for w90p910 (v2)
mtd: maps: add mtd-ram support to physmap_of
mtd: pxa3xx_nand: add single-bit error corrections reporting
...
Diffstat (limited to 'drivers/mtd/devices/m25p80.c')
-rw-r--r-- | drivers/mtd/devices/m25p80.c | 137 |
1 files changed, 135 insertions, 2 deletions
diff --git a/drivers/mtd/devices/m25p80.c b/drivers/mtd/devices/m25p80.c index eb495d83064f..379c316f329e 100644 --- a/drivers/mtd/devices/m25p80.c +++ b/drivers/mtd/devices/m25p80.c | |||
@@ -44,6 +44,11 @@ | |||
44 | #define OPCODE_SE 0xd8 /* Sector erase (usually 64KiB) */ | 44 | #define OPCODE_SE 0xd8 /* Sector erase (usually 64KiB) */ |
45 | #define OPCODE_RDID 0x9f /* Read JEDEC ID */ | 45 | #define OPCODE_RDID 0x9f /* Read JEDEC ID */ |
46 | 46 | ||
47 | /* Used for SST flashes only. */ | ||
48 | #define OPCODE_BP 0x02 /* Byte program */ | ||
49 | #define OPCODE_WRDI 0x04 /* Write disable */ | ||
50 | #define OPCODE_AAI_WP 0xad /* Auto address increment word program */ | ||
51 | |||
47 | /* Status Register bits. */ | 52 | /* Status Register bits. */ |
48 | #define SR_WIP 1 /* Write in progress */ | 53 | #define SR_WIP 1 /* Write in progress */ |
49 | #define SR_WEL 2 /* Write enable latch */ | 54 | #define SR_WEL 2 /* Write enable latch */ |
@@ -132,6 +137,15 @@ static inline int write_enable(struct m25p *flash) | |||
132 | return spi_write_then_read(flash->spi, &code, 1, NULL, 0); | 137 | return spi_write_then_read(flash->spi, &code, 1, NULL, 0); |
133 | } | 138 | } |
134 | 139 | ||
140 | /* | ||
141 | * Send write disble instruction to the chip. | ||
142 | */ | ||
143 | static inline int write_disable(struct m25p *flash) | ||
144 | { | ||
145 | u8 code = OPCODE_WRDI; | ||
146 | |||
147 | return spi_write_then_read(flash->spi, &code, 1, NULL, 0); | ||
148 | } | ||
135 | 149 | ||
136 | /* | 150 | /* |
137 | * Service routine to read status register until ready, or timeout occurs. | 151 | * Service routine to read status register until ready, or timeout occurs. |
@@ -454,6 +468,111 @@ static int m25p80_write(struct mtd_info *mtd, loff_t to, size_t len, | |||
454 | return 0; | 468 | return 0; |
455 | } | 469 | } |
456 | 470 | ||
471 | static int sst_write(struct mtd_info *mtd, loff_t to, size_t len, | ||
472 | size_t *retlen, const u_char *buf) | ||
473 | { | ||
474 | struct m25p *flash = mtd_to_m25p(mtd); | ||
475 | struct spi_transfer t[2]; | ||
476 | struct spi_message m; | ||
477 | size_t actual; | ||
478 | int cmd_sz, ret; | ||
479 | |||
480 | if (retlen) | ||
481 | *retlen = 0; | ||
482 | |||
483 | /* sanity checks */ | ||
484 | if (!len) | ||
485 | return 0; | ||
486 | |||
487 | if (to + len > flash->mtd.size) | ||
488 | return -EINVAL; | ||
489 | |||
490 | spi_message_init(&m); | ||
491 | memset(t, 0, (sizeof t)); | ||
492 | |||
493 | t[0].tx_buf = flash->command; | ||
494 | t[0].len = CMD_SIZE; | ||
495 | spi_message_add_tail(&t[0], &m); | ||
496 | |||
497 | t[1].tx_buf = buf; | ||
498 | spi_message_add_tail(&t[1], &m); | ||
499 | |||
500 | mutex_lock(&flash->lock); | ||
501 | |||
502 | /* Wait until finished previous write command. */ | ||
503 | ret = wait_till_ready(flash); | ||
504 | if (ret) | ||
505 | goto time_out; | ||
506 | |||
507 | write_enable(flash); | ||
508 | |||
509 | actual = to % 2; | ||
510 | /* Start write from odd address. */ | ||
511 | if (actual) { | ||
512 | flash->command[0] = OPCODE_BP; | ||
513 | flash->command[1] = to >> 16; | ||
514 | flash->command[2] = to >> 8; | ||
515 | flash->command[3] = to; | ||
516 | |||
517 | /* write one byte. */ | ||
518 | t[1].len = 1; | ||
519 | spi_sync(flash->spi, &m); | ||
520 | ret = wait_till_ready(flash); | ||
521 | if (ret) | ||
522 | goto time_out; | ||
523 | *retlen += m.actual_length - CMD_SIZE; | ||
524 | } | ||
525 | to += actual; | ||
526 | |||
527 | flash->command[0] = OPCODE_AAI_WP; | ||
528 | flash->command[1] = to >> 16; | ||
529 | flash->command[2] = to >> 8; | ||
530 | flash->command[3] = to; | ||
531 | |||
532 | /* Write out most of the data here. */ | ||
533 | cmd_sz = CMD_SIZE; | ||
534 | for (; actual < len - 1; actual += 2) { | ||
535 | t[0].len = cmd_sz; | ||
536 | /* write two bytes. */ | ||
537 | t[1].len = 2; | ||
538 | t[1].tx_buf = buf + actual; | ||
539 | |||
540 | spi_sync(flash->spi, &m); | ||
541 | ret = wait_till_ready(flash); | ||
542 | if (ret) | ||
543 | goto time_out; | ||
544 | *retlen += m.actual_length - cmd_sz; | ||
545 | cmd_sz = 1; | ||
546 | to += 2; | ||
547 | } | ||
548 | write_disable(flash); | ||
549 | ret = wait_till_ready(flash); | ||
550 | if (ret) | ||
551 | goto time_out; | ||
552 | |||
553 | /* Write out trailing byte if it exists. */ | ||
554 | if (actual != len) { | ||
555 | write_enable(flash); | ||
556 | flash->command[0] = OPCODE_BP; | ||
557 | flash->command[1] = to >> 16; | ||
558 | flash->command[2] = to >> 8; | ||
559 | flash->command[3] = to; | ||
560 | t[0].len = CMD_SIZE; | ||
561 | t[1].len = 1; | ||
562 | t[1].tx_buf = buf + actual; | ||
563 | |||
564 | spi_sync(flash->spi, &m); | ||
565 | ret = wait_till_ready(flash); | ||
566 | if (ret) | ||
567 | goto time_out; | ||
568 | *retlen += m.actual_length - CMD_SIZE; | ||
569 | write_disable(flash); | ||
570 | } | ||
571 | |||
572 | time_out: | ||
573 | mutex_unlock(&flash->lock); | ||
574 | return ret; | ||
575 | } | ||
457 | 576 | ||
458 | /****************************************************************************/ | 577 | /****************************************************************************/ |
459 | 578 | ||
@@ -501,7 +620,10 @@ static struct flash_info __devinitdata m25p_data [] = { | |||
501 | { "at26df321", 0x1f4701, 0, 64 * 1024, 64, SECT_4K, }, | 620 | { "at26df321", 0x1f4701, 0, 64 * 1024, 64, SECT_4K, }, |
502 | 621 | ||
503 | /* Macronix */ | 622 | /* Macronix */ |
623 | { "mx25l3205d", 0xc22016, 0, 64 * 1024, 64, }, | ||
624 | { "mx25l6405d", 0xc22017, 0, 64 * 1024, 128, }, | ||
504 | { "mx25l12805d", 0xc22018, 0, 64 * 1024, 256, }, | 625 | { "mx25l12805d", 0xc22018, 0, 64 * 1024, 256, }, |
626 | { "mx25l12855e", 0xc22618, 0, 64 * 1024, 256, }, | ||
505 | 627 | ||
506 | /* Spansion -- single (large) sector size only, at least | 628 | /* Spansion -- single (large) sector size only, at least |
507 | * for the chips listed here (without boot sectors). | 629 | * for the chips listed here (without boot sectors). |
@@ -511,14 +633,20 @@ static struct flash_info __devinitdata m25p_data [] = { | |||
511 | { "s25sl016a", 0x010214, 0, 64 * 1024, 32, }, | 633 | { "s25sl016a", 0x010214, 0, 64 * 1024, 32, }, |
512 | { "s25sl032a", 0x010215, 0, 64 * 1024, 64, }, | 634 | { "s25sl032a", 0x010215, 0, 64 * 1024, 64, }, |
513 | { "s25sl064a", 0x010216, 0, 64 * 1024, 128, }, | 635 | { "s25sl064a", 0x010216, 0, 64 * 1024, 128, }, |
514 | { "s25sl12800", 0x012018, 0x0300, 256 * 1024, 64, }, | 636 | { "s25sl12800", 0x012018, 0x0300, 256 * 1024, 64, }, |
515 | { "s25sl12801", 0x012018, 0x0301, 64 * 1024, 256, }, | 637 | { "s25sl12801", 0x012018, 0x0301, 64 * 1024, 256, }, |
638 | { "s25fl129p0", 0x012018, 0x4d00, 256 * 1024, 64, }, | ||
639 | { "s25fl129p1", 0x012018, 0x4d01, 64 * 1024, 256, }, | ||
516 | 640 | ||
517 | /* SST -- large erase sizes are "overlays", "sectors" are 4K */ | 641 | /* SST -- large erase sizes are "overlays", "sectors" are 4K */ |
518 | { "sst25vf040b", 0xbf258d, 0, 64 * 1024, 8, SECT_4K, }, | 642 | { "sst25vf040b", 0xbf258d, 0, 64 * 1024, 8, SECT_4K, }, |
519 | { "sst25vf080b", 0xbf258e, 0, 64 * 1024, 16, SECT_4K, }, | 643 | { "sst25vf080b", 0xbf258e, 0, 64 * 1024, 16, SECT_4K, }, |
520 | { "sst25vf016b", 0xbf2541, 0, 64 * 1024, 32, SECT_4K, }, | 644 | { "sst25vf016b", 0xbf2541, 0, 64 * 1024, 32, SECT_4K, }, |
521 | { "sst25vf032b", 0xbf254a, 0, 64 * 1024, 64, SECT_4K, }, | 645 | { "sst25vf032b", 0xbf254a, 0, 64 * 1024, 64, SECT_4K, }, |
646 | { "sst25wf512", 0xbf2501, 0, 64 * 1024, 1, SECT_4K, }, | ||
647 | { "sst25wf010", 0xbf2502, 0, 64 * 1024, 2, SECT_4K, }, | ||
648 | { "sst25wf020", 0xbf2503, 0, 64 * 1024, 4, SECT_4K, }, | ||
649 | { "sst25wf040", 0xbf2504, 0, 64 * 1024, 8, SECT_4K, }, | ||
522 | 650 | ||
523 | /* ST Microelectronics -- newer production may have feature updates */ | 651 | /* ST Microelectronics -- newer production may have feature updates */ |
524 | { "m25p05", 0x202010, 0, 32 * 1024, 2, }, | 652 | { "m25p05", 0x202010, 0, 32 * 1024, 2, }, |
@@ -667,7 +795,12 @@ static int __devinit m25p_probe(struct spi_device *spi) | |||
667 | flash->mtd.size = info->sector_size * info->n_sectors; | 795 | flash->mtd.size = info->sector_size * info->n_sectors; |
668 | flash->mtd.erase = m25p80_erase; | 796 | flash->mtd.erase = m25p80_erase; |
669 | flash->mtd.read = m25p80_read; | 797 | flash->mtd.read = m25p80_read; |
670 | flash->mtd.write = m25p80_write; | 798 | |
799 | /* sst flash chips use AAI word program */ | ||
800 | if (info->jedec_id >> 16 == 0xbf) | ||
801 | flash->mtd.write = sst_write; | ||
802 | else | ||
803 | flash->mtd.write = m25p80_write; | ||
671 | 804 | ||
672 | /* prefer "small sector" erase if possible */ | 805 | /* prefer "small sector" erase if possible */ |
673 | if (info->flags & SECT_4K) { | 806 | if (info->flags & SECT_4K) { |