
Add a single-hit transaction to the spi flash framework. Useful for when the hardware makes it impossible to maintain CS state between disparate command and data calls by requiring a 'frame length' (thus pre-determining how many clock cycles the CS will stay asserted). Such is the case with the Freescale eSPI controller.
Signed-off-by: Can Aydincan.aydin@locatacorp.com
--- drivers/mtd/spi/spi_flash.c | 38 +++++++++++++++++++++++++++++++-- drivers/mtd/spi/spi_flash_internal.h | 9 ++++++++ 2 files changed, 44 insertions(+), 3 deletions(-) mode change 100644 => 100755 drivers/mtd/spi/spi_flash.c mode change 100644 => 100755 drivers/mtd/spi/spi_flash_internal.h
diff --git a/drivers/mtd/spi/spi_flash.c b/drivers/mtd/spi/spi_flash.c old mode 100644 new mode 100755 index ea875dc..7646fc5 --- a/drivers/mtd/spi/spi_flash.c +++ b/drivers/mtd/spi/spi_flash.c @@ -70,12 +70,12 @@ int spi_flash_cmd_write(struct spi_slave *spi, const u8 *cmd, size_t cmd_len,
ret = spi_xfer(spi, cmd_len * 8, cmd, NULL, flags); if (ret) { - debug("SF: Failed to send read command (%zu bytes): %d\n", + debug("SF: Failed to send write command (%zu bytes): %d\n", cmd_len, ret); } else if (data_len != 0) { ret = spi_xfer(spi, data_len * 8, data, NULL, SPI_XFER_END); if (ret) - debug("SF: Failed to read %zu bytes of data: %d\n", + debug("SF: Failed to write %zu bytes of data: %d\n", data_len, ret); }
@@ -96,6 +96,37 @@ int spi_flash_read_common(struct spi_flash *flash, const u8 *cmd, return ret; }
+int spi_flash_cmd_rw_frame(struct spi_slave *spi, const u8 *cmd, + size_t cmd_len, void *data, size_t data_len) +{ + unsigned char *buffer; + int ret; + + buffer = (unsigned char *)malloc(cmd_len + data_len); + if (!buffer) { + debug("SF: Failed to malloc memory.\n"); + return 1; + } + if ( cmd_len&& cmd ) + memcpy(buffer, cmd, cmd_len); + if ( data_len&& data ) + memcpy(buffer+cmd_len, data, data_len); + ret = spi_xfer(spi, (cmd_len + data_len)*8, buffer, buffer, + SPI_XFER_BEGIN|SPI_XFER_END); + if (!ret) { + if ( cmd&& cmd_len ) + memcpy(cmd, buffer,cmd_len); + if ( data&& data_len) + memcpy(data, buffer + cmd_len,data_len); + } else { + debug("SF: Transaction failed (command length: %zu bytes)," + " (data length: %zu bytes) : %d\n", + cmd_len, data_len, ret); + } + free(buffer); + return ret; +} + struct spi_flash *spi_flash_probe(unsigned int bus, unsigned int cs, unsigned int max_hz, unsigned int spi_mode) { @@ -117,7 +148,8 @@ struct spi_flash *spi_flash_probe(unsigned int bus, unsigned int cs, }
/* Read the ID codes */ - ret = spi_flash_cmd(spi, CMD_READ_ID,&idcode, sizeof(idcode)); + idcode[0] = CMD_READ_ID; + ret = spi_flash_cmd_rw_frame(spi,&(idcode[0]), 1, idcode, sizeof(idcode)); if (ret) goto err_read_id;
diff --git a/drivers/mtd/spi/spi_flash_internal.h b/drivers/mtd/spi/spi_flash_internal.h old mode 100644 new mode 100755 index 08546fb..0455dcc --- a/drivers/mtd/spi/spi_flash_internal.h +++ b/drivers/mtd/spi/spi_flash_internal.h @@ -43,6 +43,15 @@ int spi_flash_cmd_write(struct spi_slave *spi, const u8 *cmd, size_t cmd_len, int spi_flash_read_common(struct spi_flash *flash, const u8 *cmd, size_t cmd_len, void *data, size_t data_len);
+/* + * Similar to spi_flash_read_common() but command and data are combined and + * transferred in a single,pre-buffered frame. Useful for when the + * hardware makes it impossible to deterministically maintain CS state between + * disparate command and data calls. + */ +int spi_flash_cmd_rw_frame(struct spi_slave *spi, const u8 *cmd, + size_t cmd_len, void *data, size_t data_len); + /* Manufacturer-specific probe functions */ struct spi_flash *spi_flash_probe_spansion(struct spi_slave *spi, u8 *idcode); struct spi_flash *spi_flash_probe_atmel(struct spi_slave *spi, u8 *idcode);