aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/mtd/devices
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
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')
-rw-r--r--drivers/mtd/devices/Kconfig10
-rw-r--r--drivers/mtd/devices/Makefile1
-rw-r--r--drivers/mtd/devices/lart.c6
-rw-r--r--drivers/mtd/devices/m25p80.c137
-rw-r--r--drivers/mtd/devices/mtd_dataflash.c4
-rw-r--r--drivers/mtd/devices/phram.c25
-rw-r--r--drivers/mtd/devices/slram.c2
-rw-r--r--drivers/mtd/devices/sst25l.c512
8 files changed, 677 insertions, 20 deletions
diff --git a/drivers/mtd/devices/Kconfig b/drivers/mtd/devices/Kconfig
index 325fab92a62c..c222514bb70d 100644
--- a/drivers/mtd/devices/Kconfig
+++ b/drivers/mtd/devices/Kconfig
@@ -104,6 +104,16 @@ config M25PXX_USE_FAST_READ
104 help 104 help
105 This option enables FAST_READ access supported by ST M25Pxx. 105 This option enables FAST_READ access supported by ST M25Pxx.
106 106
107config MTD_SST25L
108 tristate "Support SST25L (non JEDEC) SPI Flash chips"
109 depends on SPI_MASTER
110 help
111 This enables access to the non JEDEC SST25L SPI flash chips, used
112 for program and data storage.
113
114 Set up your spi devices with the right board-specific platform data,
115 if you want to specify device partitioning.
116
107config MTD_SLRAM 117config MTD_SLRAM
108 tristate "Uncached system RAM" 118 tristate "Uncached system RAM"
109 help 119 help
diff --git a/drivers/mtd/devices/Makefile b/drivers/mtd/devices/Makefile
index 0993d5cf3923..ab5c9b92ac82 100644
--- a/drivers/mtd/devices/Makefile
+++ b/drivers/mtd/devices/Makefile
@@ -16,3 +16,4 @@ obj-$(CONFIG_MTD_LART) += lart.o
16obj-$(CONFIG_MTD_BLOCK2MTD) += block2mtd.o 16obj-$(CONFIG_MTD_BLOCK2MTD) += block2mtd.o
17obj-$(CONFIG_MTD_DATAFLASH) += mtd_dataflash.o 17obj-$(CONFIG_MTD_DATAFLASH) += mtd_dataflash.o
18obj-$(CONFIG_MTD_M25P80) += m25p80.o 18obj-$(CONFIG_MTD_M25P80) += m25p80.o
19obj-$(CONFIG_MTD_SST25L) += sst25l.o
diff --git a/drivers/mtd/devices/lart.c b/drivers/mtd/devices/lart.c
index 578de1c67bfe..f4359fe7150f 100644
--- a/drivers/mtd/devices/lart.c
+++ b/drivers/mtd/devices/lart.c
@@ -393,7 +393,8 @@ static int flash_erase (struct mtd_info *mtd,struct erase_info *instr)
393 * erase range is aligned with the erase size which is in 393 * erase range is aligned with the erase size which is in
394 * effect here. 394 * effect here.
395 */ 395 */
396 if (instr->addr & (mtd->eraseregions[i].erasesize - 1)) return (-EINVAL); 396 if (i < 0 || (instr->addr & (mtd->eraseregions[i].erasesize - 1)))
397 return -EINVAL;
397 398
398 /* Remember the erase region we start on */ 399 /* Remember the erase region we start on */
399 first = i; 400 first = i;
@@ -409,7 +410,8 @@ static int flash_erase (struct mtd_info *mtd,struct erase_info *instr)
409 i--; 410 i--;
410 411
411 /* is the end aligned on a block boundary? */ 412 /* is the end aligned on a block boundary? */
412 if ((instr->addr + instr->len) & (mtd->eraseregions[i].erasesize - 1)) return (-EINVAL); 413 if (i < 0 || ((instr->addr + instr->len) & (mtd->eraseregions[i].erasesize - 1)))
414 return -EINVAL;
413 415
414 addr = instr->addr; 416 addr = instr->addr;
415 len = instr->len; 417 len = instr->len;
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) {
diff --git a/drivers/mtd/devices/mtd_dataflash.c b/drivers/mtd/devices/mtd_dataflash.c
index 211c27acd01e..93e3627be74c 100644
--- a/drivers/mtd/devices/mtd_dataflash.c
+++ b/drivers/mtd/devices/mtd_dataflash.c
@@ -401,7 +401,7 @@ static int dataflash_write(struct mtd_info *mtd, loff_t to, size_t len,
401 (void) dataflash_waitready(priv->spi); 401 (void) dataflash_waitready(priv->spi);
402 402
403 403
404#ifdef CONFIG_MTD_DATAFLASH_VERIFY_WRITE 404#ifdef CONFIG_MTD_DATAFLASH_WRITE_VERIFY
405 405
406 /* (3) Compare to Buffer1 */ 406 /* (3) Compare to Buffer1 */
407 addr = pageaddr << priv->page_offset; 407 addr = pageaddr << priv->page_offset;
@@ -430,7 +430,7 @@ static int dataflash_write(struct mtd_info *mtd, loff_t to, size_t len,
430 } else 430 } else
431 status = 0; 431 status = 0;
432 432
433#endif /* CONFIG_MTD_DATAFLASH_VERIFY_WRITE */ 433#endif /* CONFIG_MTD_DATAFLASH_WRITE_VERIFY */
434 434
435 remaining = remaining - writelen; 435 remaining = remaining - writelen;
436 pageaddr++; 436 pageaddr++;
diff --git a/drivers/mtd/devices/phram.c b/drivers/mtd/devices/phram.c
index 088fbb7595b5..1696bbecaa7e 100644
--- a/drivers/mtd/devices/phram.c
+++ b/drivers/mtd/devices/phram.c
@@ -14,6 +14,9 @@
14 * Example: 14 * Example:
15 * phram=swap,64Mi,128Mi phram=test,900Mi,1Mi 15 * phram=swap,64Mi,128Mi phram=test,900Mi,1Mi
16 */ 16 */
17
18#define pr_fmt(fmt) "phram: " fmt
19
17#include <asm/io.h> 20#include <asm/io.h>
18#include <linux/init.h> 21#include <linux/init.h>
19#include <linux/kernel.h> 22#include <linux/kernel.h>
@@ -23,8 +26,6 @@
23#include <linux/slab.h> 26#include <linux/slab.h>
24#include <linux/mtd/mtd.h> 27#include <linux/mtd/mtd.h>
25 28
26#define ERROR(fmt, args...) printk(KERN_ERR "phram: " fmt , ## args)
27
28struct phram_mtd_list { 29struct phram_mtd_list {
29 struct mtd_info mtd; 30 struct mtd_info mtd;
30 struct list_head list; 31 struct list_head list;
@@ -132,7 +133,7 @@ static int register_device(char *name, unsigned long start, unsigned long len)
132 ret = -EIO; 133 ret = -EIO;
133 new->mtd.priv = ioremap(start, len); 134 new->mtd.priv = ioremap(start, len);
134 if (!new->mtd.priv) { 135 if (!new->mtd.priv) {
135 ERROR("ioremap failed\n"); 136 pr_err("ioremap failed\n");
136 goto out1; 137 goto out1;
137 } 138 }
138 139
@@ -152,7 +153,7 @@ static int register_device(char *name, unsigned long start, unsigned long len)
152 153
153 ret = -EAGAIN; 154 ret = -EAGAIN;
154 if (add_mtd_device(&new->mtd)) { 155 if (add_mtd_device(&new->mtd)) {
155 ERROR("Failed to register new device\n"); 156 pr_err("Failed to register new device\n");
156 goto out2; 157 goto out2;
157 } 158 }
158 159
@@ -227,8 +228,8 @@ static inline void kill_final_newline(char *str)
227 228
228 229
229#define parse_err(fmt, args...) do { \ 230#define parse_err(fmt, args...) do { \
230 ERROR(fmt , ## args); \ 231 pr_err(fmt , ## args); \
231 return 0; \ 232 return 1; \
232} while (0) 233} while (0)
233 234
234static int phram_setup(const char *val, struct kernel_param *kp) 235static int phram_setup(const char *val, struct kernel_param *kp)
@@ -256,12 +257,8 @@ static int phram_setup(const char *val, struct kernel_param *kp)
256 parse_err("not enough arguments\n"); 257 parse_err("not enough arguments\n");
257 258
258 ret = parse_name(&name, token[0]); 259 ret = parse_name(&name, token[0]);
259 if (ret == -ENOMEM)
260 parse_err("out of memory\n");
261 if (ret == -ENOSPC)
262 parse_err("name too long\n");
263 if (ret) 260 if (ret)
264 return 0; 261 return ret;
265 262
266 ret = parse_num32(&start, token[1]); 263 ret = parse_num32(&start, token[1]);
267 if (ret) { 264 if (ret) {
@@ -275,9 +272,11 @@ static int phram_setup(const char *val, struct kernel_param *kp)
275 parse_err("illegal device length\n"); 272 parse_err("illegal device length\n");
276 } 273 }
277 274
278 register_device(name, start, len); 275 ret = register_device(name, start, len);
276 if (!ret)
277 pr_info("%s device: %#x at %#x\n", name, len, start);
279 278
280 return 0; 279 return ret;
281} 280}
282 281
283module_param_call(phram, phram_setup, NULL, NULL, 000); 282module_param_call(phram, phram_setup, NULL, NULL, 000);
diff --git a/drivers/mtd/devices/slram.c b/drivers/mtd/devices/slram.c
index 7d846e9173da..3aa05cd18ea1 100644
--- a/drivers/mtd/devices/slram.c
+++ b/drivers/mtd/devices/slram.c
@@ -341,7 +341,7 @@ static int __init init_slram(void)
341#else 341#else
342 int count; 342 int count;
343 343
344 for (count = 0; (map[count]) && (count < SLRAM_MAX_DEVICES_PARAMS); 344 for (count = 0; count < SLRAM_MAX_DEVICES_PARAMS && map[count];
345 count++) { 345 count++) {
346 } 346 }
347 347
diff --git a/drivers/mtd/devices/sst25l.c b/drivers/mtd/devices/sst25l.c
new file mode 100644
index 000000000000..c2baf3353f84
--- /dev/null
+++ b/drivers/mtd/devices/sst25l.c
@@ -0,0 +1,512 @@
1/*
2 * sst25l.c
3 *
4 * Driver for SST25L SPI Flash chips
5 *
6 * Copyright © 2009 Bluewater Systems Ltd
7 * Author: Andre Renaud <andre@bluewatersys.com>
8 * Author: Ryan Mallon <ryan@bluewatersys.com>
9 *
10 * Based on m25p80.c
11 *
12 * This code is free software; you can redistribute it and/or modify
13 * it under the terms of the GNU General Public License version 2 as
14 * published by the Free Software Foundation.
15 *
16 */
17
18#include <linux/init.h>
19#include <linux/module.h>
20#include <linux/device.h>
21#include <linux/mutex.h>
22#include <linux/interrupt.h>
23
24#include <linux/mtd/mtd.h>
25#include <linux/mtd/partitions.h>
26
27#include <linux/spi/spi.h>
28#include <linux/spi/flash.h>
29
30/* Erases can take up to 3 seconds! */
31#define MAX_READY_WAIT_JIFFIES msecs_to_jiffies(3000)
32
33#define SST25L_CMD_WRSR 0x01 /* Write status register */
34#define SST25L_CMD_WRDI 0x04 /* Write disable */
35#define SST25L_CMD_RDSR 0x05 /* Read status register */
36#define SST25L_CMD_WREN 0x06 /* Write enable */
37#define SST25L_CMD_READ 0x03 /* High speed read */
38
39#define SST25L_CMD_EWSR 0x50 /* Enable write status register */
40#define SST25L_CMD_SECTOR_ERASE 0x20 /* Erase sector */
41#define SST25L_CMD_READ_ID 0x90 /* Read device ID */
42#define SST25L_CMD_AAI_PROGRAM 0xaf /* Auto address increment */
43
44#define SST25L_STATUS_BUSY (1 << 0) /* Chip is busy */
45#define SST25L_STATUS_WREN (1 << 1) /* Write enabled */
46#define SST25L_STATUS_BP0 (1 << 2) /* Block protection 0 */
47#define SST25L_STATUS_BP1 (1 << 3) /* Block protection 1 */
48
49struct sst25l_flash {
50 struct spi_device *spi;
51 struct mutex lock;
52 struct mtd_info mtd;
53
54 int partitioned;
55};
56
57struct flash_info {
58 const char *name;
59 uint16_t device_id;
60 unsigned page_size;
61 unsigned nr_pages;
62 unsigned erase_size;
63};
64
65#define to_sst25l_flash(x) container_of(x, struct sst25l_flash, mtd)
66
67static struct flash_info __initdata sst25l_flash_info[] = {
68 {"sst25lf020a", 0xbf43, 256, 1024, 4096},
69 {"sst25lf040a", 0xbf44, 256, 2048, 4096},
70};
71
72static int sst25l_status(struct sst25l_flash *flash, int *status)
73{
74 unsigned char command, response;
75 int err;
76
77 command = SST25L_CMD_RDSR;
78 err = spi_write_then_read(flash->spi, &command, 1, &response, 1);
79 if (err < 0)
80 return err;
81
82 *status = response;
83 return 0;
84}
85
86static int sst25l_write_enable(struct sst25l_flash *flash, int enable)
87{
88 unsigned char command[2];
89 int status, err;
90
91 command[0] = enable ? SST25L_CMD_WREN : SST25L_CMD_WRDI;
92 err = spi_write(flash->spi, command, 1);
93 if (err)
94 return err;
95
96 command[0] = SST25L_CMD_EWSR;
97 err = spi_write(flash->spi, command, 1);
98 if (err)
99 return err;
100
101 command[0] = SST25L_CMD_WRSR;
102 command[1] = enable ? 0 : SST25L_STATUS_BP0 | SST25L_STATUS_BP1;
103 err = spi_write(flash->spi, command, 2);
104 if (err)
105 return err;
106
107 if (enable) {
108 err = sst25l_status(flash, &status);
109 if (err)
110 return err;
111 if (!(status & SST25L_STATUS_WREN))
112 return -EROFS;
113 }
114
115 return 0;
116}
117
118static int sst25l_wait_till_ready(struct sst25l_flash *flash)
119{
120 unsigned long deadline;
121 int status, err;
122
123 deadline = jiffies + MAX_READY_WAIT_JIFFIES;
124 do {
125 err = sst25l_status(flash, &status);
126 if (err)
127 return err;
128 if (!(status & SST25L_STATUS_BUSY))
129 return 0;
130
131 cond_resched();
132 } while (!time_after_eq(jiffies, deadline));
133
134 return -ETIMEDOUT;
135}
136
137static int sst25l_erase_sector(struct sst25l_flash *flash, uint32_t offset)
138{
139 unsigned char command[4];
140 int err;
141
142 err = sst25l_write_enable(flash, 1);
143 if (err)
144 return err;
145
146 command[0] = SST25L_CMD_SECTOR_ERASE;
147 command[1] = offset >> 16;
148 command[2] = offset >> 8;
149 command[3] = offset;
150 err = spi_write(flash->spi, command, 4);
151 if (err)
152 return err;
153
154 err = sst25l_wait_till_ready(flash);
155 if (err)
156 return err;
157
158 return sst25l_write_enable(flash, 0);
159}
160
161static int sst25l_erase(struct mtd_info *mtd, struct erase_info *instr)
162{
163 struct sst25l_flash *flash = to_sst25l_flash(mtd);
164 uint32_t addr, end;
165 int err;
166
167 /* Sanity checks */
168 if (instr->addr + instr->len > flash->mtd.size)
169 return -EINVAL;
170
171 if ((uint32_t)instr->len % mtd->erasesize)
172 return -EINVAL;
173
174 if ((uint32_t)instr->addr % mtd->erasesize)
175 return -EINVAL;
176
177 addr = instr->addr;
178 end = addr + instr->len;
179
180 mutex_lock(&flash->lock);
181
182 err = sst25l_wait_till_ready(flash);
183 if (err) {
184 mutex_unlock(&flash->lock);
185 return err;
186 }
187
188 while (addr < end) {
189 err = sst25l_erase_sector(flash, addr);
190 if (err) {
191 mutex_unlock(&flash->lock);
192 instr->state = MTD_ERASE_FAILED;
193 dev_err(&flash->spi->dev, "Erase failed\n");
194 return err;
195 }
196
197 addr += mtd->erasesize;
198 }
199
200 mutex_unlock(&flash->lock);
201
202 instr->state = MTD_ERASE_DONE;
203 mtd_erase_callback(instr);
204 return 0;
205}
206
207static int sst25l_read(struct mtd_info *mtd, loff_t from, size_t len,
208 size_t *retlen, unsigned char *buf)
209{
210 struct sst25l_flash *flash = to_sst25l_flash(mtd);
211 struct spi_transfer transfer[2];
212 struct spi_message message;
213 unsigned char command[4];
214 int ret;
215
216 /* Sanity checking */
217 if (len == 0)
218 return 0;
219
220 if (from + len > flash->mtd.size)
221 return -EINVAL;
222
223 if (retlen)
224 *retlen = 0;
225
226 spi_message_init(&message);
227 memset(&transfer, 0, sizeof(transfer));
228
229 command[0] = SST25L_CMD_READ;
230 command[1] = from >> 16;
231 command[2] = from >> 8;
232 command[3] = from;
233
234 transfer[0].tx_buf = command;
235 transfer[0].len = sizeof(command);
236 spi_message_add_tail(&transfer[0], &message);
237
238 transfer[1].rx_buf = buf;
239 transfer[1].len = len;
240 spi_message_add_tail(&transfer[1], &message);
241
242 mutex_lock(&flash->lock);
243
244 /* Wait for previous write/erase to complete */
245 ret = sst25l_wait_till_ready(flash);
246 if (ret) {
247 mutex_unlock(&flash->lock);
248 return ret;
249 }
250
251 spi_sync(flash->spi, &message);
252
253 if (retlen && message.actual_length > sizeof(command))
254 *retlen += message.actual_length - sizeof(command);
255
256 mutex_unlock(&flash->lock);
257 return 0;
258}
259
260static int sst25l_write(struct mtd_info *mtd, loff_t to, size_t len,
261 size_t *retlen, const unsigned char *buf)
262{
263 struct sst25l_flash *flash = to_sst25l_flash(mtd);
264 int i, j, ret, bytes, copied = 0;
265 unsigned char command[5];
266
267 /* Sanity checks */
268 if (!len)
269 return 0;
270
271 if (to + len > flash->mtd.size)
272 return -EINVAL;
273
274 if ((uint32_t)to % mtd->writesize)
275 return -EINVAL;
276
277 mutex_lock(&flash->lock);
278
279 ret = sst25l_write_enable(flash, 1);
280 if (ret)
281 goto out;
282
283 for (i = 0; i < len; i += mtd->writesize) {
284 ret = sst25l_wait_till_ready(flash);
285 if (ret)
286 goto out;
287
288 /* Write the first byte of the page */
289 command[0] = SST25L_CMD_AAI_PROGRAM;
290 command[1] = (to + i) >> 16;
291 command[2] = (to + i) >> 8;
292 command[3] = (to + i);
293 command[4] = buf[i];
294 ret = spi_write(flash->spi, command, 5);
295 if (ret < 0)
296 goto out;
297 copied++;
298
299 /*
300 * Write the remaining bytes using auto address
301 * increment mode
302 */
303 bytes = min_t(uint32_t, mtd->writesize, len - i);
304 for (j = 1; j < bytes; j++, copied++) {
305 ret = sst25l_wait_till_ready(flash);
306 if (ret)
307 goto out;
308
309 command[1] = buf[i + j];
310 ret = spi_write(flash->spi, command, 2);
311 if (ret)
312 goto out;
313 }
314 }
315
316out:
317 ret = sst25l_write_enable(flash, 0);
318
319 if (retlen)
320 *retlen = copied;
321
322 mutex_unlock(&flash->lock);
323 return ret;
324}
325
326static struct flash_info *__init sst25l_match_device(struct spi_device *spi)
327{
328 struct flash_info *flash_info = NULL;
329 unsigned char command[4], response;
330 int i, err;
331 uint16_t id;
332
333 command[0] = SST25L_CMD_READ_ID;
334 command[1] = 0;
335 command[2] = 0;
336 command[3] = 0;
337 err = spi_write_then_read(spi, command, sizeof(command), &response, 1);
338 if (err < 0) {
339 dev_err(&spi->dev, "error reading device id msb\n");
340 return NULL;
341 }
342
343 id = response << 8;
344
345 command[0] = SST25L_CMD_READ_ID;
346 command[1] = 0;
347 command[2] = 0;
348 command[3] = 1;
349 err = spi_write_then_read(spi, command, sizeof(command), &response, 1);
350 if (err < 0) {
351 dev_err(&spi->dev, "error reading device id lsb\n");
352 return NULL;
353 }
354
355 id |= response;
356
357 for (i = 0; i < ARRAY_SIZE(sst25l_flash_info); i++)
358 if (sst25l_flash_info[i].device_id == id)
359 flash_info = &sst25l_flash_info[i];
360
361 if (!flash_info)
362 dev_err(&spi->dev, "unknown id %.4x\n", id);
363
364 return flash_info;
365}
366
367static int __init sst25l_probe(struct spi_device *spi)
368{
369 struct flash_info *flash_info;
370 struct sst25l_flash *flash;
371 struct flash_platform_data *data;
372 int ret, i;
373
374 flash_info = sst25l_match_device(spi);
375 if (!flash_info)
376 return -ENODEV;
377
378 flash = kzalloc(sizeof(struct sst25l_flash), GFP_KERNEL);
379 if (!flash)
380 return -ENOMEM;
381
382 flash->spi = spi;
383 mutex_init(&flash->lock);
384 dev_set_drvdata(&spi->dev, flash);
385
386 data = spi->dev.platform_data;
387 if (data && data->name)
388 flash->mtd.name = data->name;
389 else
390 flash->mtd.name = dev_name(&spi->dev);
391
392 flash->mtd.type = MTD_NORFLASH;
393 flash->mtd.flags = MTD_CAP_NORFLASH;
394 flash->mtd.erasesize = flash_info->erase_size;
395 flash->mtd.writesize = flash_info->page_size;
396 flash->mtd.size = flash_info->page_size * flash_info->nr_pages;
397 flash->mtd.erase = sst25l_erase;
398 flash->mtd.read = sst25l_read;
399 flash->mtd.write = sst25l_write;
400
401 dev_info(&spi->dev, "%s (%lld KiB)\n", flash_info->name,
402 (long long)flash->mtd.size >> 10);
403
404 DEBUG(MTD_DEBUG_LEVEL2,
405 "mtd .name = %s, .size = 0x%llx (%lldMiB) "
406 ".erasesize = 0x%.8x (%uKiB) .numeraseregions = %d\n",
407 flash->mtd.name,
408 (long long)flash->mtd.size, (long long)(flash->mtd.size >> 20),
409 flash->mtd.erasesize, flash->mtd.erasesize / 1024,
410 flash->mtd.numeraseregions);
411
412 if (flash->mtd.numeraseregions)
413 for (i = 0; i < flash->mtd.numeraseregions; i++)
414 DEBUG(MTD_DEBUG_LEVEL2,
415 "mtd.eraseregions[%d] = { .offset = 0x%llx, "
416 ".erasesize = 0x%.8x (%uKiB), "
417 ".numblocks = %d }\n",
418 i, (long long)flash->mtd.eraseregions[i].offset,
419 flash->mtd.eraseregions[i].erasesize,
420 flash->mtd.eraseregions[i].erasesize / 1024,
421 flash->mtd.eraseregions[i].numblocks);
422
423 if (mtd_has_partitions()) {
424 struct mtd_partition *parts = NULL;
425 int nr_parts = 0;
426
427 if (mtd_has_cmdlinepart()) {
428 static const char *part_probes[] =
429 {"cmdlinepart", NULL};
430
431 nr_parts = parse_mtd_partitions(&flash->mtd,
432 part_probes,
433 &parts, 0);
434 }
435
436 if (nr_parts <= 0 && data && data->parts) {
437 parts = data->parts;
438 nr_parts = data->nr_parts;
439 }
440
441 if (nr_parts > 0) {
442 for (i = 0; i < nr_parts; i++) {
443 DEBUG(MTD_DEBUG_LEVEL2, "partitions[%d] = "
444 "{.name = %s, .offset = 0x%llx, "
445 ".size = 0x%llx (%lldKiB) }\n",
446 i, parts[i].name,
447 (long long)parts[i].offset,
448 (long long)parts[i].size,
449 (long long)(parts[i].size >> 10));
450 }
451
452 flash->partitioned = 1;
453 return add_mtd_partitions(&flash->mtd,
454 parts, nr_parts);
455 }
456
457 } else if (data->nr_parts) {
458 dev_warn(&spi->dev, "ignoring %d default partitions on %s\n",
459 data->nr_parts, data->name);
460 }
461
462 ret = add_mtd_device(&flash->mtd);
463 if (ret == 1) {
464 kfree(flash);
465 dev_set_drvdata(&spi->dev, NULL);
466 return -ENODEV;
467 }
468
469 return 0;
470}
471
472static int __exit sst25l_remove(struct spi_device *spi)
473{
474 struct sst25l_flash *flash = dev_get_drvdata(&spi->dev);
475 int ret;
476
477 if (mtd_has_partitions() && flash->partitioned)
478 ret = del_mtd_partitions(&flash->mtd);
479 else
480 ret = del_mtd_device(&flash->mtd);
481 if (ret == 0)
482 kfree(flash);
483 return ret;
484}
485
486static struct spi_driver sst25l_driver = {
487 .driver = {
488 .name = "sst25l",
489 .bus = &spi_bus_type,
490 .owner = THIS_MODULE,
491 },
492 .probe = sst25l_probe,
493 .remove = __exit_p(sst25l_remove),
494};
495
496static int __init sst25l_init(void)
497{
498 return spi_register_driver(&sst25l_driver);
499}
500
501static void __exit sst25l_exit(void)
502{
503 spi_unregister_driver(&sst25l_driver);
504}
505
506module_init(sst25l_init);
507module_exit(sst25l_exit);
508
509MODULE_DESCRIPTION("MTD SPI driver for SST25L Flash chips");
510MODULE_AUTHOR("Andre Renaud <andre@bluewatersys.com>, "
511 "Ryan Mallon <ryan@bluewatersys.com>");
512MODULE_LICENSE("GPL");