aboutsummaryrefslogtreecommitdiff
path: root/drivers
diff options
context:
space:
mode:
authorShraddha Chaudhari <Shraddha.Chaudhari@imgtec.com>2016-01-05 11:05:42 +0530
committerGerrit Code Review <root@hhgit01>2016-01-08 09:04:11 +0000
commit4b7685e53510535386598dbae871188fd92c4874 (patch)
tree52d3a2a8b8a419e491840a5897d0684c17a93122 /drivers
parentf7fb14340a6115d0111e94f69d1cc1bc0f9f537d (diff)
downloadv4.1-4b7685e53510535386598dbae871188fd92c4874.tar.gz
KIN-1484: mtd: m25p80: add support for read_xfer and write_xfer
These can be used to make SPI transactions not possible using read or write calls. Current implementation doesn't support all the possible configuration using spi_nor_xfer_cfg, also added *retlen to the read_xfer and write_xfer interface to make it similar to read and write. Change-Id: I4d5b4b83b72f0c6783d540518f2311711d10bf70 Signed-off-by: Shraddha Chaudhari <Shraddha.Chaudhari@imgtec.com>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/mtd/devices/m25p80.c112
1 files changed, 100 insertions, 12 deletions
diff --git a/drivers/mtd/devices/m25p80.c b/drivers/mtd/devices/m25p80.c
index 3af137f49ac..90002419c2c 100644
--- a/drivers/mtd/devices/m25p80.c
+++ b/drivers/mtd/devices/m25p80.c
@@ -48,13 +48,15 @@ static int m25p80_read_reg(struct spi_nor *nor, u8 code, u8 *val, int len)
return ret;
}
-static void m25p_addr2cmd(struct spi_nor *nor, unsigned int addr, u8 *cmd)
+static void m25p_addr2cmd(unsigned int addr, unsigned int addr_width, u8 *cmd)
{
- /* opcode is in cmd[0] */
- cmd[1] = addr >> (nor->addr_width * 8 - 8);
- cmd[2] = addr >> (nor->addr_width * 8 - 16);
- cmd[3] = addr >> (nor->addr_width * 8 - 24);
- cmd[4] = addr >> (nor->addr_width * 8 - 32);
+ if (addr_width) {
+ /* opcode is in cmd[0] */
+ cmd[1] = addr >> (addr_width * 8 - 8);
+ cmd[2] = addr >> (addr_width * 8 - 16);
+ cmd[3] = addr >> (addr_width * 8 - 24);
+ cmd[4] = addr >> (addr_width * 8 - 32);
+ }
}
static int m25p_cmdsz(struct spi_nor *nor)
@@ -90,7 +92,7 @@ static void m25p80_write(struct spi_nor *nor, loff_t to, size_t len,
cmd_sz = 1;
flash->command[0] = nor->program_opcode;
- m25p_addr2cmd(nor, to, flash->command);
+ m25p_addr2cmd(to, nor->addr_width, flash->command);
t[0].tx_buf = flash->command;
t[0].len = cmd_sz;
@@ -105,9 +107,9 @@ static void m25p80_write(struct spi_nor *nor, loff_t to, size_t len,
*retlen += m.actual_length - cmd_sz;
}
-static inline unsigned int m25p80_rx_nbits(struct spi_nor *nor)
+static inline unsigned int m25p80_rx_nbits(enum read_mode mode)
{
- switch (nor->flash_read) {
+ switch (mode) {
case SPI_NOR_DUAL:
return 2;
case SPI_NOR_QUAD:
@@ -137,14 +139,14 @@ static int m25p80_read(struct spi_nor *nor, loff_t from, size_t len,
memset(t, 0, (sizeof t));
flash->command[0] = nor->read_opcode;
- m25p_addr2cmd(nor, from, flash->command);
+ m25p_addr2cmd(from, nor->addr_width, flash->command);
t[0].tx_buf = flash->command;
t[0].len = m25p_cmdsz(nor) + dummy;
spi_message_add_tail(&t[0], &m);
t[1].rx_buf = buf;
- t[1].rx_nbits = m25p80_rx_nbits(nor);
+ t[1].rx_nbits = m25p80_rx_nbits(nor->flash_read);
t[1].len = len;
spi_message_add_tail(&t[1], &m);
@@ -163,13 +165,97 @@ static int m25p80_erase(struct spi_nor *nor, loff_t offset)
/* Set up command buffer. */
flash->command[0] = nor->erase_opcode;
- m25p_addr2cmd(nor, offset, flash->command);
+ m25p_addr2cmd(offset, nor->addr_width, flash->command);
spi_write(flash->spi, flash->command, m25p_cmdsz(nor));
return 0;
}
+/* From spi_nor_xfer_cfg, this call ignores cmd_pins, addr_pins, so single I/O
+ * line is used for cmd and addr
+ * mode_pins, mode_cycles are ignored, decides nbits based on mode
+ */
+static int m25p80_read_xfer(struct spi_nor *nor, struct spi_nor_xfer_cfg *cfg,
+ u8 *buf, size_t len, size_t *retlen)
+{
+ struct m25p *flash = nor->priv;
+ struct spi_device *spi = flash->spi;
+ struct spi_transfer t[2];
+ struct spi_message m;
+ u32 dummy = cfg->dummy_cycles/8; /* convert dummy cycles into bytes */
+ u32 cmd_sz = (1 + cfg->addr_width + dummy);
+ int ret;
+
+ if (cfg->addr_width > 4 || cmd_sz > MAX_CMD_SIZE)
+ return -EINVAL;
+
+ spi_message_init(&m);
+ memset(t, 0, sizeof (t));
+
+ memset(flash->command, 0, MAX_CMD_SIZE);
+ flash->command[0] = cfg->cmd;
+ m25p_addr2cmd(cfg->addr, cfg->addr_width, flash->command);
+
+ t[0].tx_buf = flash->command;
+ t[0].len = cmd_sz;
+ spi_message_add_tail(&t[0], &m);
+
+ if (len) {
+ t[1].rx_buf = buf;
+ t[1].rx_nbits = m25p80_rx_nbits(cfg->mode);
+ t[1].len = len;
+ spi_message_add_tail(&t[1], &m);
+ }
+
+ ret = spi_sync(spi, &m);
+
+ if (!ret)
+ *retlen += (m.actual_length - cmd_sz);
+ return ret;
+}
+
+/* From spi_nor_xfer_cfg, this call ignores cmd_pins, addr_pins, mode, mode_pins,
+ * mode_cycles, so single I/O line is used for cmd, addr and data
+ */
+static int m25p80_write_xfer(struct spi_nor *nor, struct spi_nor_xfer_cfg *cfg,
+ u8 *buf, size_t len, size_t *retlen)
+{
+ struct m25p *flash = nor->priv;
+ struct spi_device *spi = flash->spi;
+ struct spi_transfer t[2];
+ struct spi_message m;
+ u32 dummy = cfg->dummy_cycles/8; /* convert dummy cycles into bytes */
+ u32 cmd_sz = (1 + cfg->addr_width + dummy);
+ int ret;
+
+ if (cfg->addr_width > 4 || cmd_sz > MAX_CMD_SIZE)
+ return -EINVAL;
+
+ spi_message_init(&m);
+ memset(t, 0, sizeof(t));
+
+ memset(flash->command, 0, MAX_CMD_SIZE);
+ flash->command[0] = cfg->cmd;
+ m25p_addr2cmd(cfg->addr, cfg->addr_width, flash->command);
+
+ t[0].tx_buf = flash->command;
+ t[0].len = cmd_sz;
+ spi_message_add_tail(&t[0], &m);
+
+ if (len) {
+ t[1].tx_buf = buf;
+ t[1].len = len;
+ spi_message_add_tail(&t[1], &m);
+ }
+
+ ret = spi_sync(spi, &m);
+
+ if (!ret)
+ *retlen += (m.actual_length - cmd_sz);
+ return ret;
+}
+
/*
* board specific setup should have ensured the SPI clock used here
* matches what the READ command supports, at least until this driver
@@ -199,6 +285,8 @@ static int m25p_probe(struct spi_device *spi)
nor->erase = m25p80_erase;
nor->write_reg = m25p80_write_reg;
nor->read_reg = m25p80_read_reg;
+ nor->read_xfer = m25p80_read_xfer;
+ nor->write_xfer = m25p80_write_xfer;
nor->dev = &spi->dev;
nor->mtd = &flash->mtd;