aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/mtd
diff options
context:
space:
mode:
authorGraf Yang <graf.yang@analog.com>2009-06-15 04:23:41 -0400
committerDavid Woodhouse <David.Woodhouse@intel.com>2009-09-19 16:10:16 -0400
commit49aac4aec53c523f16343b4668a5a239b69659f1 (patch)
treea43ad86944551dc05b94058359fdef8a623c7055 /drivers/mtd
parent80f53da0ac752fe16a01ffeddaea658670974a05 (diff)
mtd: m25p80: add support for AAI programming with SST SPI flashes
The SST SPI flashes are a bit non-standard in that they can be programmed one byte at a time (including address!), or they can be written two bytes at a time with auto address incrementing (AAI). The latter form is obviously much better for performance, so let's use it when possible. Signed-off-by: Graf Yang <graf.yang@analog.com> Signed-off-by: Mike Frysinger <vapier@gentoo.org> Signed-off-by: David Woodhouse <David.Woodhouse@intel.com>
Diffstat (limited to 'drivers/mtd')
-rw-r--r--drivers/mtd/devices/m25p80.c126
1 files changed, 125 insertions, 1 deletions
diff --git a/drivers/mtd/devices/m25p80.c b/drivers/mtd/devices/m25p80.c
index 6d8d265ae91a..53de9f05ad50 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
@@ -670,7 +789,12 @@ static int __devinit m25p_probe(struct spi_device *spi)
670 flash->mtd.size = info->sector_size * info->n_sectors; 789 flash->mtd.size = info->sector_size * info->n_sectors;
671 flash->mtd.erase = m25p80_erase; 790 flash->mtd.erase = m25p80_erase;
672 flash->mtd.read = m25p80_read; 791 flash->mtd.read = m25p80_read;
673 flash->mtd.write = m25p80_write; 792
793 /* sst flash chips use AAI word program */
794 if (info->jedec_id >> 16 == 0xbf)
795 flash->mtd.write = sst_write;
796 else
797 flash->mtd.write = m25p80_write;
674 798
675 /* prefer "small sector" erase if possible */ 799 /* prefer "small sector" erase if possible */
676 if (info->flags & SECT_4K) { 800 if (info->flags & SECT_4K) {