mtd: sst25l: fix multi-part messages with broken spi masters

Linux-MTD Mailing List linux-mtd at lists.infradead.org
Thu May 13 21:59:04 EDT 2010


Gitweb:     http://git.infradead.org/?p=mtd-2.6.git;a=commit;h=0ffe0ce36e07185c693e3ff06ab5b3b6c30780ee
Commit:     0ffe0ce36e07185c693e3ff06ab5b3b6c30780ee
Parent:     46f3e88bd9da010e76a9049d55cf9013560b5903
Author:     H Hartley Sweeten <hartleys at visionengravers.com>
AuthorDate: Thu Apr 29 13:34:24 2010 -0500
Committer:  David Woodhouse <David.Woodhouse at intel.com>
CommitDate: Fri May 14 01:52:24 2010 +0100

    mtd: sst25l: fix multi-part messages with broken spi masters
    
    Some SPI masters (ep93xx) have limitations when using the SFRMOUT
    signal for the spi device chip select.  The SFRMOUT signal is
    only asserted as long as the spi transmit fifo contains data.  As
    soon as the last bit is clocked into the receive fifo it gets
    deasserted.
    
    The functions sst25l_status and sst25l_match_device use the API
    function spi_write_then_read to write a command to the flash then
    read the response back.  This API function creates a two part spi
    message for the write then read.  When this message is transferred
    the SFRMOUT signal ends up getting deasserted after the command
    phase.  This causes the command to get aborted by the device so
    the read phase returns invalid data.
    
    By changing sst25l_status and sst25l_match_device to use a single
    transfer synchronous message, the SFRMOUT signal stays asserted
    during the entire message so the correct data always gets returned.
    
    This change will have no effect on SPI masters which use a chip
    select mechanism (GPIO's, etc.) which does stay asserted correctly.
    As a bonus, the single transfer synchronous messages complete faster
    than multi-part messages.
    
    Signed-off-by: H Hartley Sweeten <hsweeten at visionengravers.com>
    Signed-off-by: David Woodhouse <David.Woodhouse at intel.com>
---
 drivers/mtd/devices/sst25l.c |   57 ++++++++++++++++++++++++-----------------
 1 files changed, 33 insertions(+), 24 deletions(-)

diff --git a/drivers/mtd/devices/sst25l.c b/drivers/mtd/devices/sst25l.c
index bcf040b..ab5d8cd 100644
--- a/drivers/mtd/devices/sst25l.c
+++ b/drivers/mtd/devices/sst25l.c
@@ -73,15 +73,25 @@ static struct flash_info __initdata sst25l_flash_info[] = {
 
 static int sst25l_status(struct sst25l_flash *flash, int *status)
 {
-	unsigned char command, response;
+	struct spi_message m;
+	struct spi_transfer t;
+	unsigned char cmd_resp[2];
 	int err;
 
-	command = SST25L_CMD_RDSR;
-	err = spi_write_then_read(flash->spi, &command, 1, &response, 1);
+	spi_message_init(&m);
+	memset(&t, 0, sizeof(struct spi_transfer));
+
+	cmd_resp[0] = SST25L_CMD_RDSR;
+	cmd_resp[1] = 0xff;
+	t.tx_buf = cmd_resp;
+	t.rx_buf = cmd_resp;
+	t.len = sizeof(cmd_resp);
+	spi_message_add_tail(&t, &m);
+	err = spi_sync(flash->spi, &m);
 	if (err < 0)
 		return err;
 
-	*status = response;
+	*status = cmd_resp[1];
 	return 0;
 }
 
@@ -328,33 +338,32 @@ out:
 static struct flash_info *__init sst25l_match_device(struct spi_device *spi)
 {
 	struct flash_info *flash_info = NULL;
-	unsigned char command[4], response;
+	struct spi_message m;
+	struct spi_transfer t;
+	unsigned char cmd_resp[6];
 	int i, err;
 	uint16_t id;
 
-	command[0] = SST25L_CMD_READ_ID;
-	command[1] = 0;
-	command[2] = 0;
-	command[3] = 0;
-	err = spi_write_then_read(spi, command, sizeof(command), &response, 1);
-	if (err < 0) {
-		dev_err(&spi->dev, "error reading device id msb\n");
-		return NULL;
-	}
-
-	id = response << 8;
-
-	command[0] = SST25L_CMD_READ_ID;
-	command[1] = 0;
-	command[2] = 0;
-	command[3] = 1;
-	err = spi_write_then_read(spi, command, sizeof(command), &response, 1);
+	spi_message_init(&m);
+	memset(&t, 0, sizeof(struct spi_transfer));
+
+	cmd_resp[0] = SST25L_CMD_READ_ID;
+	cmd_resp[1] = 0;
+	cmd_resp[2] = 0;
+	cmd_resp[3] = 0;
+	cmd_resp[4] = 0xff;
+	cmd_resp[5] = 0xff;
+	t.tx_buf = cmd_resp;
+	t.rx_buf = cmd_resp;
+	t.len = sizeof(cmd_resp);
+	spi_message_add_tail(&t, &m);
+	err = spi_sync(spi, &m);
 	if (err < 0) {
-		dev_err(&spi->dev, "error reading device id lsb\n");
+		dev_err(&spi->dev, "error reading device id\n");
 		return NULL;
 	}
 
-	id |= response;
+	id = (cmd_resp[4] << 8) | cmd_resp[5];
 
 	for (i = 0; i < ARRAY_SIZE(sst25l_flash_info); i++)
 		if (sst25l_flash_info[i].device_id == id)



More information about the linux-mtd-cvs mailing list