ar71xx: allow to specify max read size for m25p80
Reading from the flash chip on the TL-WR2543ND seems buggy. If the SPI flash driver tries to read too much data in one SPI transfer, the flash chip returns bogus values. This can be caused by a buggy flash chip on my board, or it can be a bug in our SPI driver. Add a workaround to the m25p80 driver until I find out the root cause of the problem. The patch allows to specify the maximum numner of bytes which can be read safely withint one SPI transfer. SVN-Revision: 29679
This commit is contained in:
parent
8b567fb508
commit
a56bdeff9d
1 changed files with 112 additions and 0 deletions
|
@ -0,0 +1,112 @@
|
|||
--- a/drivers/mtd/devices/m25p80.c
|
||||
+++ b/drivers/mtd/devices/m25p80.c
|
||||
@@ -94,6 +94,7 @@ struct m25p {
|
||||
u16 addr_width;
|
||||
u8 erase_opcode;
|
||||
u8 *command;
|
||||
+ size_t max_read_len;
|
||||
};
|
||||
|
||||
static inline struct m25p *mtd_to_m25p(struct mtd_info *mtd)
|
||||
@@ -341,6 +342,7 @@ static int m25p80_read(struct mtd_info *
|
||||
struct m25p *flash = mtd_to_m25p(mtd);
|
||||
struct spi_transfer t[2];
|
||||
struct spi_message m;
|
||||
+ loff_t ofs;
|
||||
|
||||
DEBUG(MTD_DEBUG_LEVEL2, "%s: %s %s 0x%08x, len %zd\n",
|
||||
dev_name(&flash->spi->dev), __func__, "from",
|
||||
@@ -364,8 +366,6 @@ static int m25p80_read(struct mtd_info *
|
||||
t[0].len = m25p_cmdsz(flash) + FAST_READ_DUMMY_BYTE;
|
||||
spi_message_add_tail(&t[0], &m);
|
||||
|
||||
- t[1].rx_buf = buf;
|
||||
- t[1].len = len;
|
||||
spi_message_add_tail(&t[1], &m);
|
||||
|
||||
/* Byte count starts at zero. */
|
||||
@@ -373,13 +373,6 @@ static int m25p80_read(struct mtd_info *
|
||||
|
||||
mutex_lock(&flash->lock);
|
||||
|
||||
- /* Wait till previous write/erase is done. */
|
||||
- if (wait_till_ready(flash)) {
|
||||
- /* REVISIT status return?? */
|
||||
- mutex_unlock(&flash->lock);
|
||||
- return 1;
|
||||
- }
|
||||
-
|
||||
/* FIXME switch to OPCODE_FAST_READ. It's required for higher
|
||||
* clocks; and at this writing, every chip this driver handles
|
||||
* supports that opcode.
|
||||
@@ -387,11 +380,44 @@ static int m25p80_read(struct mtd_info *
|
||||
|
||||
/* Set up the write data buffer. */
|
||||
flash->command[0] = OPCODE_READ;
|
||||
- m25p_addr2cmd(flash, from, flash->command);
|
||||
|
||||
- spi_sync(flash->spi, &m);
|
||||
+ ofs = 0;
|
||||
+ while (len) {
|
||||
+ size_t readlen;
|
||||
+ size_t done;
|
||||
+ int ret;
|
||||
+
|
||||
+ ret = wait_till_ready(flash);
|
||||
+ if (ret) {
|
||||
+ mutex_unlock(&flash->lock);
|
||||
+ return 1;
|
||||
+ }
|
||||
+
|
||||
+ if (flash->max_read_len > 0 &&
|
||||
+ flash->max_read_len < len)
|
||||
+ readlen = flash->max_read_len;
|
||||
+ else
|
||||
+ readlen = len;
|
||||
+
|
||||
+ t[1].rx_buf = buf + ofs;
|
||||
+ t[1].len = readlen;
|
||||
+
|
||||
+ m25p_addr2cmd(flash, from + ofs, flash->command);
|
||||
+
|
||||
+ spi_sync(flash->spi, &m);
|
||||
|
||||
- *retlen = m.actual_length - m25p_cmdsz(flash) - FAST_READ_DUMMY_BYTE;
|
||||
+ done = m.actual_length - m25p_cmdsz(flash) -
|
||||
+ FAST_READ_DUMMY_BYTE;
|
||||
+ if (done != readlen) {
|
||||
+ mutex_unlock(&flash->lock);
|
||||
+ return 1;
|
||||
+ }
|
||||
+
|
||||
+ ofs += done;
|
||||
+ len -= done;
|
||||
+ }
|
||||
+
|
||||
+ *retlen = ofs;
|
||||
|
||||
mutex_unlock(&flash->lock);
|
||||
|
||||
@@ -901,6 +927,12 @@ static int __devinit m25p_probe(struct s
|
||||
flash->mtd.erase = m25p80_erase;
|
||||
flash->mtd.read = m25p80_read;
|
||||
|
||||
+ if (data && data->max_read_len) {
|
||||
+ flash->max_read_len = data->max_read_len;
|
||||
+ dev_warn(&spi->dev, "max_read_len set to %d bytes\n",
|
||||
+ flash->max_read_len);
|
||||
+ }
|
||||
+
|
||||
/* sst flash chips use AAI word program */
|
||||
if (info->jedec_id >> 16 == 0xbf)
|
||||
flash->mtd.write = sst_write;
|
||||
--- a/include/linux/spi/flash.h
|
||||
+++ b/include/linux/spi/flash.h
|
||||
@@ -26,6 +26,7 @@ struct flash_platform_data {
|
||||
char *type;
|
||||
const char **part_probes;
|
||||
|
||||
+ size_t max_read_len;
|
||||
/* we'll likely add more ... use JEDEC IDs, etc */
|
||||
};
|
||||
|
Loading…
Reference in a new issue