@@ -54,6 +54,10 @@ struct sst25l_flash {
struct mtd_info mtd;
int partitioned;
+
+ bool use_fifo;
+ int fifo_size;
+ unsigned char *bounce_buf;
};
struct flash_info {
@@ -269,6 +273,79 @@ static int sst25l_read(struct mtd_info *mtd, loff_t from, size_t len,
return 0;
}
+static int sst25l_read_use_fifo(struct mtd_info *mtd, loff_t from, size_t len,
+ size_t *retlen, unsigned char *buf)
+{
+ struct sst25l_flash *flash = to_sst25l_flash(mtd);
+ struct spi_message message;
+ struct spi_transfer transfer;
+ loff_t addr;
+ size_t count;
+ int xfer_size = flash->fifo_size - 4;
+ int ret, i;
+
+ /* Sanity checking */
+ if (len == 0)
+ return 0;
+
+ if (from + len > flash->mtd.size)
+ return -EINVAL;
+
+ if (retlen)
+ *retlen = 0;
+
+ mutex_lock(&flash->lock);
+
+ /* Wait for previous write/erase to complete */
+ ret = sst25l_wait_till_ready(flash);
+ if (ret) {
+ mutex_unlock(&flash->lock);
+ return ret;
+ }
+
+ for (addr = from, count = 0; addr < from + len; addr += xfer_size) {
+ spi_message_init(&message);
+ memset(&transfer, 0, sizeof(transfer));
+
+ /* Fill the bounce buffer with known data */
+ memset(flash->bounce_buf, 0xff, flash->fifo_size);
+
+ /*
+ * Send the 4 byte Read command and read back as much
+ * data as possible (fifo_size - 4) into the bounce buffer.
+ */
+ flash->bounce_buf[0] = SST25L_CMD_READ;
+ flash->bounce_buf[1] = addr >> 16;
+ flash->bounce_buf[2] = addr >> 8;
+ flash->bounce_buf[3] = addr;
+
+ transfer.tx_buf = flash->bounce_buf;
+ transfer.rx_buf = flash->bounce_buf;
+ transfer.len = flash->fifo_size;
+ spi_message_add_tail(&transfer, &message);
+ ret = spi_sync(flash->spi, &message);
+ if (ret < 0) {
+ mutex_unlock(&flash->lock);
+ return ret;
+ }
+
+ /*
+ * Copy the read data from the bounce buffer to the
+ * passed buffer. Don't overflow the passed buffer.
+ */
+ for (i = 0; i < xfer_size; i++) {
+ if (count < len)
+ buf[count++] = flash->bounce_buf[4+i];
+ }
+ }
+
+ if (retlen)
+ *retlen += count;
+
+ mutex_unlock(&flash->lock);
+ return 0;
+}
+
static int sst25l_write(struct mtd_info *mtd, loff_t to, size_t len,
size_t *retlen, const unsigned char *buf)
{
@@ -400,13 +477,25 @@ static int __devinit sst25l_probe(struct spi_device *spi)
else
flash->mtd.name = dev_name(&spi->dev);
+ flash->use_fifo = data->use_fifo;
+ flash->fifo_size = data->fifo_size;
+
flash->mtd.type = MTD_NORFLASH;
flash->mtd.flags = MTD_CAP_NORFLASH;
flash->mtd.erasesize = flash_info->erase_size;
flash->mtd.writesize = flash_info->page_size;
flash->mtd.size = flash_info->page_size * flash_info->nr_pages;
flash->mtd.erase = sst25l_erase;
- flash->mtd.read = sst25l_read;
+ if (flash->use_fifo) {
+ flash->bounce_buf = kzalloc(flash->fifo_size, GFP_KERNEL);
+ if (!flash->bounce_buf) {
+ ret = -ENOMEM;
+ goto err;
+ }
+ flash->mtd.read = sst25l_read_use_fifo;
+ } else {
+ flash->mtd.read = sst25l_read;
+ }
flash->mtd.write = sst25l_write;
dev_info(&spi->dev, "%s (%lld KiB)\n", flash_info->name,
@@ -461,12 +550,17 @@ static int __devinit sst25l_probe(struct spi_device *spi)
ret = add_mtd_device(&flash->mtd);
if (ret == 1) {
- kfree(flash);
- dev_set_drvdata(&spi->dev, NULL);
- return -ENODEV;
+ ret = -ENODEV;
+ goto err;
}
return 0;
+
+err:
+ kfree(flash->bounce_buf);
+ kfree(flash);
+ dev_set_drvdata(&spi->dev, NULL);
+ return ret;
}
static int __exit sst25l_remove(struct spi_device *spi)
@@ -478,8 +572,10 @@ static int __exit sst25l_remove(struct spi_device *spi)
ret = del_mtd_partitions(&flash->mtd);
else
ret = del_mtd_device(&flash->mtd);
- if (ret == 0)
+ if (ret == 0) {
+ kfree(flash->bounce_buf);
kfree(flash);
+ }
return ret;
}
@@ -10,6 +10,10 @@ struct mtd_partition;
* @nr_parts: number of mtd_partitions for static partitoning
* @type: optional flash device type (e.g. m25p80 vs m25p64), for use
* with chips that can't be queried for JEDEC or other IDs
+ * @use_fifo: optional flag to read/write data using the SPI master's
+ * fifo limitations (for broken SPI masters that deassert the
+ * chip select during multi-part transfers)
+ * @fifo_size: optional fifo size used with broken SPI masters
*
* Board init code (in arch/.../mach-xxx/board-yyy.c files) can
* provide information about SPI flash parts (such as DataFlash) to
@@ -25,6 +29,9 @@ struct flash_platform_data {
char *type;
+ bool use_fifo;
+ int fifo_size;
+
/* we'll likely add more ... use JEDEC IDs, etc */
};