aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/mtd
diff options
context:
space:
mode:
authorH Hartley Sweeten <hartleys@visionengravers.com>2010-04-29 14:34:24 -0400
committerDavid Woodhouse <David.Woodhouse@intel.com>2010-05-13 20:52:24 -0400
commit0ffe0ce36e07185c693e3ff06ab5b3b6c30780ee (patch)
tree10fe97a074fae701e167a02024d0252c5e837b52 /drivers/mtd
parent46f3e88bd9da010e76a9049d55cf9013560b5903 (diff)
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@visionengravers.com> Signed-off-by: David Woodhouse <David.Woodhouse@intel.com>
Diffstat (limited to 'drivers/mtd')
-rw-r--r--drivers/mtd/devices/sst25l.c57
1 files changed, 33 insertions, 24 deletions
diff --git a/drivers/mtd/devices/sst25l.c b/drivers/mtd/devices/sst25l.c
index bcf040beb835..ab5d8cd02a15 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[] = {
73 73
74static int sst25l_status(struct sst25l_flash *flash, int *status) 74static int sst25l_status(struct sst25l_flash *flash, int *status)
75{ 75{
76 unsigned char command, response; 76 struct spi_message m;
77 struct spi_transfer t;
78 unsigned char cmd_resp[2];
77 int err; 79 int err;
78 80
79 command = SST25L_CMD_RDSR; 81 spi_message_init(&m);
80 err = spi_write_then_read(flash->spi, &command, 1, &response, 1); 82 memset(&t, 0, sizeof(struct spi_transfer));
83
84 cmd_resp[0] = SST25L_CMD_RDSR;
85 cmd_resp[1] = 0xff;
86 t.tx_buf = cmd_resp;
87 t.rx_buf = cmd_resp;
88 t.len = sizeof(cmd_resp);
89 spi_message_add_tail(&t, &m);
90 err = spi_sync(flash->spi, &m);
81 if (err < 0) 91 if (err < 0)
82 return err; 92 return err;
83 93
84 *status = response; 94 *status = cmd_resp[1];
85 return 0; 95 return 0;
86} 96}
87 97
@@ -328,33 +338,32 @@ out:
328static struct flash_info *__init sst25l_match_device(struct spi_device *spi) 338static struct flash_info *__init sst25l_match_device(struct spi_device *spi)
329{ 339{
330 struct flash_info *flash_info = NULL; 340 struct flash_info *flash_info = NULL;
331 unsigned char command[4], response; 341 struct spi_message m;
342 struct spi_transfer t;
343 unsigned char cmd_resp[6];
332 int i, err; 344 int i, err;
333 uint16_t id; 345 uint16_t id;
334 346
335 command[0] = SST25L_CMD_READ_ID; 347 spi_message_init(&m);
336 command[1] = 0; 348 memset(&t, 0, sizeof(struct spi_transfer));
337 command[2] = 0; 349
338 command[3] = 0; 350 cmd_resp[0] = SST25L_CMD_READ_ID;
339 err = spi_write_then_read(spi, command, sizeof(command), &response, 1); 351 cmd_resp[1] = 0;
340 if (err < 0) { 352 cmd_resp[2] = 0;
341 dev_err(&spi->dev, "error reading device id msb\n"); 353 cmd_resp[3] = 0;
342 return NULL; 354 cmd_resp[4] = 0xff;
343 } 355 cmd_resp[5] = 0xff;
344 356 t.tx_buf = cmd_resp;
345 id = response << 8; 357 t.rx_buf = cmd_resp;
346 358 t.len = sizeof(cmd_resp);
347 command[0] = SST25L_CMD_READ_ID; 359 spi_message_add_tail(&t, &m);
348 command[1] = 0; 360 err = spi_sync(spi, &m);
349 command[2] = 0;
350 command[3] = 1;
351 err = spi_write_then_read(spi, command, sizeof(command), &response, 1);
352 if (err < 0) { 361 if (err < 0) {
353 dev_err(&spi->dev, "error reading device id lsb\n"); 362 dev_err(&spi->dev, "error reading device id\n");
354 return NULL; 363 return NULL;
355 } 364 }
356 365
357 id |= response; 366 id = (cmd_resp[4] << 8) | cmd_resp[5];
358 367
359 for (i = 0; i < ARRAY_SIZE(sst25l_flash_info); i++) 368 for (i = 0; i < ARRAY_SIZE(sst25l_flash_info); i++)
360 if (sst25l_flash_info[i].device_id == id) 369 if (sst25l_flash_info[i].device_id == id)