aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/mtd/devices/m25p80.c
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2009-09-23 13:07:49 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2009-09-23 13:07:49 -0400
commita7c367b95a9d8e65e0f0e7da31f700a556794efb (patch)
tree5b1bb202801e29e3237381aa7aad5aa288378d5b /drivers/mtd/devices/m25p80.c
parent15f964bed054821d6d940d3752508c5f96a9ffd3 (diff)
parente1070211f7327a1f197d535aa886f721a241c32f (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.c137
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 */
143static 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
471static 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
572time_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) {