summaryrefslogtreecommitdiffstats
path: root/drivers/mtd
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/mtd')
-rw-r--r--drivers/mtd/devices/Kconfig1
-rw-r--r--drivers/mtd/devices/m25p80.c144
2 files changed, 63 insertions, 82 deletions
diff --git a/drivers/mtd/devices/Kconfig b/drivers/mtd/devices/Kconfig
index 9c3925b..25db10a 100644
--- a/drivers/mtd/devices/Kconfig
+++ b/drivers/mtd/devices/Kconfig
@@ -23,6 +23,7 @@ config MTD_M25P80
tristate "Support most SPI Flash chips (AT26DF, M25P, W25X, ...)"
depends on SPI
select MTD_SPI_NOR
+ select SPI_MEM
help
This enables access to most modern SPI flash chips, used for
program and data storage. Series supported include Atmel AT26DF,
diff --git a/drivers/mtd/devices/m25p80.c b/drivers/mtd/devices/m25p80.c
index 8c4659c..09a8714 100644
--- a/drivers/mtd/devices/m25p80.c
+++ b/drivers/mtd/devices/m25p80.c
@@ -27,12 +27,13 @@
#include <clock.h>
#include <linux/mtd/mtd.h>
#include <linux/mtd/spi-nor.h>
+#include <linux/spi/spi-mem.h>
#include <linux/mod_devicetable.h>
#define MAX_CMD_SIZE 6
struct m25p {
- struct spi_device *spi;
+ struct spi_mem *spimem;
struct spi_nor spi_nor;
struct mtd_info mtd;
u8 command[MAX_CMD_SIZE];
@@ -41,70 +42,60 @@ struct m25p {
static int m25p80_read_reg(struct spi_nor *nor, u8 code, u8 *val, int len)
{
struct m25p *flash = nor->priv;
- struct spi_device *spi = flash->spi;
+ struct spi_mem_op op = SPI_MEM_OP(SPI_MEM_OP_CMD(code, 1),
+ SPI_MEM_OP_NO_ADDR,
+ SPI_MEM_OP_NO_DUMMY,
+ SPI_MEM_OP_DATA_IN(len, val, 1));
int ret;
- ret = spi_write_then_read(spi, &code, 1, val, len);
+ ret = spi_mem_exec_op(flash->spimem, &op);
if (ret < 0)
- dev_err(&spi->dev, "error %d reading %x\n", ret, code);
+ dev_err(&flash->spimem->spi->dev, "error %d reading %x\n", ret,
+ code);
return ret;
}
-static void m25p_addr2cmd(struct spi_nor *nor, unsigned int addr, 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);
-}
-
-static int m25p_cmdsz(struct spi_nor *nor)
-{
- return 1 + nor->addr_width;
-}
-
static int m25p80_write_reg(struct spi_nor *nor, u8 opcode, u8 *buf, int len)
{
struct m25p *flash = nor->priv;
- struct spi_device *spi = flash->spi;
-
- flash->command[0] = opcode;
- if (buf)
- memcpy(&flash->command[1], buf, len);
+ struct spi_mem_op op = SPI_MEM_OP(SPI_MEM_OP_CMD(opcode, 1),
+ SPI_MEM_OP_NO_ADDR,
+ SPI_MEM_OP_NO_DUMMY,
+ SPI_MEM_OP_DATA_OUT(len, buf, 1));
- return spi_write(spi, flash->command, len + 1);
+ return spi_mem_exec_op(flash->spimem, &op);
}
static void m25p80_write(struct spi_nor *nor, loff_t to, size_t len,
size_t *retlen, const u_char *buf)
{
struct m25p *flash = nor->priv;
- struct spi_device *spi = flash->spi;
- struct spi_transfer t[2] = {};
- struct spi_message m;
- int cmd_sz = m25p_cmdsz(nor);
+ struct spi_mem_op op =
+ SPI_MEM_OP(SPI_MEM_OP_CMD(nor->program_opcode, 1),
+ SPI_MEM_OP_ADDR(nor->addr_width, to, 1),
+ SPI_MEM_OP_NO_DUMMY,
+ SPI_MEM_OP_DATA_OUT(len, buf, 1));
+ int ret;
- spi_message_init(&m);
+ op.cmd.buswidth = spi_nor_get_protocol_inst_nbits(nor->write_proto);
+ op.addr.buswidth = spi_nor_get_protocol_addr_nbits(nor->write_proto);
+ op.data.buswidth = spi_nor_get_protocol_data_nbits(nor->write_proto);
if (nor->program_opcode == SPINOR_OP_AAI_WP && nor->sst_write_second)
- cmd_sz = 1;
-
- flash->command[0] = nor->program_opcode;
- m25p_addr2cmd(nor, to, flash->command);
+ op.addr.nbytes = 0;
- t[0].tx_buf = flash->command;
- t[0].len = cmd_sz;
- spi_message_add_tail(&t[0], &m);
+ ret = spi_mem_adjust_op_size(flash->spimem, &op);
+ if (ret)
+ return;
- t[1].tx_buf = buf;
- t[1].len = len;
- spi_message_add_tail(&t[1], &m);
+ op.data.nbytes = len < op.data.nbytes ? len : op.data.nbytes;
- spi_sync(spi, &m);
+ ret = spi_mem_exec_op(flash->spimem, &op);
+ if (ret)
+ return;
- *retlen += m.actual_length - cmd_sz;
+ *retlen = op.data.nbytes;
}
/*
@@ -115,46 +106,35 @@ static int m25p80_read(struct spi_nor *nor, loff_t from, size_t len,
size_t *retlen, u_char *buf)
{
struct m25p *flash = nor->priv;
- struct spi_device *spi = flash->spi;
- struct spi_transfer t[2];
- struct spi_message m;
- unsigned int dummy = nor->read_dummy;
-
- /* convert the dummy cycles to the number of bytes */
- dummy /= 8;
-
- spi_message_init(&m);
- memset(t, 0, (sizeof t));
-
- flash->command[0] = nor->read_opcode;
- m25p_addr2cmd(nor, from, 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].len = len;
- spi_message_add_tail(&t[1], &m);
-
- spi_sync(spi, &m);
-
- *retlen = m.actual_length - m25p_cmdsz(nor) - dummy;
- return 0;
-}
-
-static int m25p80_erase(struct spi_nor *nor, loff_t offset)
-{
- struct m25p *flash = nor->priv;
-
- dev_dbg(nor->dev, "%dKiB at 0x%08x\n",
- flash->mtd.erasesize / 1024, (u32)offset);
+ struct spi_mem_op op =
+ SPI_MEM_OP(SPI_MEM_OP_CMD(nor->read_opcode, 1),
+ SPI_MEM_OP_ADDR(nor->addr_width, from, 1),
+ SPI_MEM_OP_DUMMY(nor->read_dummy, 1),
+ SPI_MEM_OP_DATA_IN(len, buf, 1));
+ size_t remaining = len;
+ int ret;
- /* Set up command buffer. */
- flash->command[0] = nor->erase_opcode;
- m25p_addr2cmd(nor, offset, flash->command);
+ op.cmd.buswidth = spi_nor_get_protocol_inst_nbits(nor->read_proto);
+ op.addr.buswidth = spi_nor_get_protocol_addr_nbits(nor->read_proto);
+ op.dummy.buswidth = op.addr.buswidth;
+ op.data.buswidth = spi_nor_get_protocol_data_nbits(nor->read_proto);
+
+ op.dummy.nbytes = (nor->read_dummy * op.dummy.buswidth) / 8;
+
+ while (remaining) {
+ op.data.nbytes = remaining < UINT_MAX ? remaining : UINT_MAX;
+ ret = spi_mem_adjust_op_size(flash->spimem, &op);
+ if (ret)
+ return ret;
+ ret = spi_mem_exec_op(flash->spimem, &op);
+ if (ret)
+ return ret;
+ op.addr.val += op.data.nbytes;
+ remaining -= op.data.nbytes;
+ op.data.buf.in += op.data.nbytes;
+ }
- spi_write(flash->spi, flash->command, m25p_cmdsz(nor));
+ *retlen = len;
return 0;
}
@@ -228,6 +208,7 @@ static const struct platform_device_id m25p_ids[] = {
static int m25p_probe(struct device_d *dev)
{
struct spi_device *spi = (struct spi_device *)dev->type_data;
+ struct spi_mem *spimem = spi->mem;
struct flash_platform_data *data;
struct m25p *flash;
struct spi_nor *nor;
@@ -250,17 +231,16 @@ static int m25p_probe(struct device_d *dev)
/* install the hooks */
nor->read = m25p80_read;
nor->write = m25p80_write;
- nor->erase = m25p80_erase;
nor->write_reg = m25p80_write_reg;
nor->read_reg = m25p80_read_reg;
- nor->dev = dev;
+ nor->dev = &spimem->spi->dev;
nor->mtd = &flash->mtd;
nor->priv = flash;
flash->mtd.priv = nor;
flash->mtd.parent = &spi->dev;
- flash->spi = spi;
+ flash->spimem = spimem;
if (spi->mode & SPI_RX_QUAD)
hwcaps.mask |= SNOR_HWCAPS_READ_1_1_4;