diff mbox series

[v3,5/9] spi: bcm-qspi: Implement the spi_mem interface

Message ID 20180422183522.11118-6-boris.brezillon@bootlin.com
State Superseded
Headers show
Series spi: Extend the framework to generically support memory devices | expand

Commit Message

Boris Brezillon April 22, 2018, 6:35 p.m. UTC
The spi_mem interface is meant to replace the ->spi_flash_read() one.
Implement the ->exec_op() method to ease removal of the old interface.

Not that ->spi_flash_read() is now implemented as a wrapper around the
new bcm_qspi_exec_mem_op() function so that we can easily get rid of
it when ->spi_flash_read() is removed.

Signed-off-by: Boris Brezillon <boris.brezillon@bootlin.com>
---
Changes in v3:
- none

Changes in v2:
- include spi-mem.h
- treat op->addr.val differently since it's now an u64
---
 drivers/spi/spi-bcm-qspi.c | 190 ++++++++++++++++++++++++++-------------------
 1 file changed, 111 insertions(+), 79 deletions(-)

Comments

Kamal Dasu April 24, 2018, 3:19 p.m. UTC | #1
On Sun, Apr 22, 2018 at 2:35 PM, Boris Brezillon
<boris.brezillon@bootlin.com> wrote:
> The spi_mem interface is meant to replace the ->spi_flash_read() one.
> Implement the ->exec_op() method to ease removal of the old interface.
>
> Not that ->spi_flash_read() is now implemented as a wrapper around the
> new bcm_qspi_exec_mem_op() function so that we can easily get rid of
> it when ->spi_flash_read() is removed.
>
> Signed-off-by: Boris Brezillon <boris.brezillon@bootlin.com>

Reviewed-by: Kamal Dasu <kdasu.kdev@gmail.com>
Tested-by: Kamal Dasu <kdasu.kdev@gmail.com>

> ---
> Changes in v3:
> - none
>
> Changes in v2:
> - include spi-mem.h
> - treat op->addr.val differently since it's now an u64
> ---
>  drivers/spi/spi-bcm-qspi.c | 190 ++++++++++++++++++++++++++-------------------
>  1 file changed, 111 insertions(+), 79 deletions(-)
>
> diff --git a/drivers/spi/spi-bcm-qspi.c b/drivers/spi/spi-bcm-qspi.c
> index 1596d35498c5..9f94268a68b5 100644
> --- a/drivers/spi/spi-bcm-qspi.c
> +++ b/drivers/spi/spi-bcm-qspi.c
> @@ -30,6 +30,7 @@
>  #include <linux/platform_device.h>
>  #include <linux/slab.h>
>  #include <linux/spi/spi.h>
> +#include <linux/spi/spi-mem.h>
>  #include <linux/sysfs.h>
>  #include <linux/types.h>
>  #include "spi-bcm-qspi.h"
> @@ -215,10 +216,10 @@ struct bcm_qspi {
>         int bspi_maj_rev;
>         int bspi_min_rev;
>         int bspi_enabled;
> -       struct spi_flash_read_message *bspi_rf_msg;
> -       u32 bspi_rf_msg_idx;
> -       u32 bspi_rf_msg_len;
> -       u32 bspi_rf_msg_status;
> +       const struct spi_mem_op *bspi_rf_op;
> +       u32 bspi_rf_op_idx;
> +       u32 bspi_rf_op_len;
> +       u32 bspi_rf_op_status;
>         struct bcm_xfer_mode xfer_mode;
>         u32 s3_strap_override_ctrl;
>         bool bspi_mode;
> @@ -313,26 +314,26 @@ static inline void bcm_qspi_bspi_lr_clear(struct bcm_qspi *qspi)
>
>  static void bcm_qspi_bspi_lr_data_read(struct bcm_qspi *qspi)
>  {
> -       u32 *buf = (u32 *)qspi->bspi_rf_msg->buf;
> +       u32 *buf = (u32 *)qspi->bspi_rf_op->data.buf.in;
>         u32 data = 0;
>
> -       dev_dbg(&qspi->pdev->dev, "xfer %p rx %p rxlen %d\n", qspi->bspi_rf_msg,
> -               qspi->bspi_rf_msg->buf, qspi->bspi_rf_msg_len);
> +       dev_dbg(&qspi->pdev->dev, "xfer %p rx %p rxlen %d\n", qspi->bspi_rf_op,
> +               qspi->bspi_rf_op->data.buf.in, qspi->bspi_rf_op_len);
>         while (!bcm_qspi_bspi_lr_is_fifo_empty(qspi)) {
>                 data = bcm_qspi_bspi_lr_read_fifo(qspi);
> -               if (likely(qspi->bspi_rf_msg_len >= 4) &&
> +               if (likely(qspi->bspi_rf_op_len >= 4) &&
>                     IS_ALIGNED((uintptr_t)buf, 4)) {
> -                       buf[qspi->bspi_rf_msg_idx++] = data;
> -                       qspi->bspi_rf_msg_len -= 4;
> +                       buf[qspi->bspi_rf_op_idx++] = data;
> +                       qspi->bspi_rf_op_len -= 4;
>                 } else {
>                         /* Read out remaining bytes, make sure*/
> -                       u8 *cbuf = (u8 *)&buf[qspi->bspi_rf_msg_idx];
> +                       u8 *cbuf = (u8 *)&buf[qspi->bspi_rf_op_idx];
>
>                         data = cpu_to_le32(data);
> -                       while (qspi->bspi_rf_msg_len) {
> +                       while (qspi->bspi_rf_op_len) {
>                                 *cbuf++ = (u8)data;
>                                 data >>= 8;
> -                               qspi->bspi_rf_msg_len--;
> +                               qspi->bspi_rf_op_len--;
>                         }
>                 }
>         }
> @@ -349,14 +350,12 @@ static void bcm_qspi_bspi_set_xfer_params(struct bcm_qspi *qspi, u8 cmd_byte,
>  }
>
>  static int bcm_qspi_bspi_set_flex_mode(struct bcm_qspi *qspi,
> -                                      struct spi_flash_read_message *msg,
> -                                      int hp)
> +                                      const struct spi_mem_op *op, int hp)
>  {
>         int bpc = 0, bpp = 0;
> -       u8 command = msg->read_opcode;
> -       int width  = msg->data_nbits ? msg->data_nbits : SPI_NBITS_SINGLE;
> -       int addrlen = msg->addr_width;
> -       int addr_nbits = msg->addr_nbits ? msg->addr_nbits : SPI_NBITS_SINGLE;
> +       u8 command = op->cmd.opcode;
> +       int width  = op->cmd.buswidth ? op->cmd.buswidth : SPI_NBITS_SINGLE;
> +       int addrlen = op->addr.nbytes * 8;
>         int flex_mode = 1;
>
>         dev_dbg(&qspi->pdev->dev, "set flex mode w %x addrlen %x hp %d\n",
> @@ -365,7 +364,7 @@ static int bcm_qspi_bspi_set_flex_mode(struct bcm_qspi *qspi,
>         if (addrlen == BSPI_ADDRLEN_4BYTES)
>                 bpp = BSPI_BPP_ADDR_SELECT_MASK;
>
> -       bpp |= msg->dummy_bytes * (8/addr_nbits);
> +       bpp |= (op->dummy.nbytes * 8) / op->dummy.buswidth;
>
>         switch (width) {
>         case SPI_NBITS_SINGLE:
> @@ -397,11 +396,10 @@ static int bcm_qspi_bspi_set_flex_mode(struct bcm_qspi *qspi,
>  }
>
>  static int bcm_qspi_bspi_set_override(struct bcm_qspi *qspi,
> -                                     struct spi_flash_read_message *msg,
> -                                     int hp)
> +                                     const struct spi_mem_op *op, int hp)
>  {
> -       int width = msg->data_nbits ? msg->data_nbits : SPI_NBITS_SINGLE;
> -       int addrlen = msg->addr_width;
> +       int width = op->data.buswidth ? op->data.buswidth : SPI_NBITS_SINGLE;
> +       int addrlen = op->addr.nbytes;
>         u32 data = bcm_qspi_read(qspi, BSPI, BSPI_STRAP_OVERRIDE_CTRL);
>
>         dev_dbg(&qspi->pdev->dev, "set override mode w %x addrlen %x hp %d\n",
> @@ -437,17 +435,17 @@ static int bcm_qspi_bspi_set_override(struct bcm_qspi *qspi,
>         /* set the override mode */
>         data |= BSPI_STRAP_OVERRIDE_CTRL_OVERRIDE;
>         bcm_qspi_write(qspi, BSPI, BSPI_STRAP_OVERRIDE_CTRL, data);
> -       bcm_qspi_bspi_set_xfer_params(qspi, msg->read_opcode, 0, 0, 0);
> +       bcm_qspi_bspi_set_xfer_params(qspi, op->cmd.opcode, 0, 0, 0);
>
>         return 0;
>  }
>
>  static int bcm_qspi_bspi_set_mode(struct bcm_qspi *qspi,
> -                                 struct spi_flash_read_message *msg, int hp)
> +                                 const struct spi_mem_op *op, int hp)
>  {
>         int error = 0;
> -       int width = msg->data_nbits ? msg->data_nbits : SPI_NBITS_SINGLE;
> -       int addrlen = msg->addr_width;
> +       int width = op->data.buswidth ? op->data.buswidth : SPI_NBITS_SINGLE;
> +       int addrlen = op->addr.nbytes;
>
>         /* default mode */
>         qspi->xfer_mode.flex_mode = true;
> @@ -460,12 +458,12 @@ static int bcm_qspi_bspi_set_mode(struct bcm_qspi *qspi,
>                 if (val & mask || qspi->s3_strap_override_ctrl & mask) {
>                         qspi->xfer_mode.flex_mode = false;
>                         bcm_qspi_write(qspi, BSPI, BSPI_FLEX_MODE_ENABLE, 0);
> -                       error = bcm_qspi_bspi_set_override(qspi, msg, hp);
> +                       error = bcm_qspi_bspi_set_override(qspi, op, hp);
>                 }
>         }
>
>         if (qspi->xfer_mode.flex_mode)
> -               error = bcm_qspi_bspi_set_flex_mode(qspi, msg, hp);
> +               error = bcm_qspi_bspi_set_flex_mode(qspi, op, hp);
>
>         if (error) {
>                 dev_warn(&qspi->pdev->dev,
> @@ -794,19 +792,20 @@ static int write_to_hw(struct bcm_qspi *qspi, struct spi_device *spi)
>         return slot;
>  }
>
> -static int bcm_qspi_bspi_flash_read(struct spi_device *spi,
> -                                   struct spi_flash_read_message *msg)
> +static int bcm_qspi_bspi_exec_mem_op(struct spi_device *spi,
> +                                    const struct spi_mem_op *op)
>  {
>         struct bcm_qspi *qspi = spi_master_get_devdata(spi->master);
> -       u32 addr = 0, len, rdlen, len_words;
> +       u32 addr = 0, len, rdlen, len_words, from = 0;
>         int ret = 0;
>         unsigned long timeo = msecs_to_jiffies(100);
>         struct bcm_qspi_soc_intc *soc_intc = qspi->soc_intc;
>
>         if (bcm_qspi_bspi_ver_three(qspi))
> -               if (msg->addr_width == BSPI_ADDRLEN_4BYTES)
> +               if (op->addr.nbytes == BSPI_ADDRLEN_4BYTES)
>                         return -EIO;
>
> +       from = op->addr.val;
>         bcm_qspi_chip_select(qspi, spi->chip_select);
>         bcm_qspi_write(qspi, MSPI, MSPI_WRITE_LOCK, 0);
>
> @@ -815,15 +814,15 @@ static int bcm_qspi_bspi_flash_read(struct spi_device *spi,
>          * the upper address byte to bspi
>          */
>         if (bcm_qspi_bspi_ver_three(qspi) == false) {
> -               addr = msg->from & 0xff000000;
> +               addr = from & 0xff000000;
>                 bcm_qspi_write(qspi, BSPI,
>                                BSPI_BSPI_FLASH_UPPER_ADDR_BYTE, addr);
>         }
>
>         if (!qspi->xfer_mode.flex_mode)
> -               addr = msg->from;
> +               addr = from;
>         else
> -               addr = msg->from & 0x00ffffff;
> +               addr = from & 0x00ffffff;
>
>         if (bcm_qspi_bspi_ver_three(qspi) == true)
>                 addr = (addr + 0xc00000) & 0xffffff;
> @@ -832,8 +831,8 @@ static int bcm_qspi_bspi_flash_read(struct spi_device *spi,
>          * read into the entire buffer by breaking the reads
>          * into RAF buffer read lengths
>          */
> -       len = msg->len;
> -       qspi->bspi_rf_msg_idx = 0;
> +       len = op->data.nbytes;
> +       qspi->bspi_rf_op_idx = 0;
>
>         do {
>                 if (len > BSPI_READ_LENGTH)
> @@ -844,9 +843,9 @@ static int bcm_qspi_bspi_flash_read(struct spi_device *spi,
>                 reinit_completion(&qspi->bspi_done);
>                 bcm_qspi_enable_bspi(qspi);
>                 len_words = (rdlen + 3) >> 2;
> -               qspi->bspi_rf_msg = msg;
> -               qspi->bspi_rf_msg_status = 0;
> -               qspi->bspi_rf_msg_len = rdlen;
> +               qspi->bspi_rf_op = op;
> +               qspi->bspi_rf_op_status = 0;
> +               qspi->bspi_rf_op_len = rdlen;
>                 dev_dbg(&qspi->pdev->dev,
>                         "bspi xfr addr 0x%x len 0x%x", addr, rdlen);
>                 bcm_qspi_write(qspi, BSPI, BSPI_RAF_START_ADDR, addr);
> @@ -871,7 +870,6 @@ static int bcm_qspi_bspi_flash_read(struct spi_device *spi,
>                 }
>
>                 /* set msg return length */
> -               msg->retlen += rdlen;
>                 addr += rdlen;
>                 len -= rdlen;
>         } while (len);
> @@ -906,61 +904,62 @@ static int bcm_qspi_transfer_one(struct spi_master *master,
>         return 0;
>  }
>
> -static int bcm_qspi_mspi_flash_read(struct spi_device *spi,
> -                                   struct spi_flash_read_message *msg)
> +static int bcm_qspi_mspi_exec_mem_op(struct spi_device *spi,
> +                                    const struct spi_mem_op *op)
>  {
> -       struct bcm_qspi *qspi = spi_master_get_devdata(spi->master);
> +       struct spi_master *master = spi->master;
> +       struct bcm_qspi *qspi = spi_master_get_devdata(master);
>         struct spi_transfer t[2];
> -       u8 cmd[6];
> -       int ret;
> +       u8 cmd[6] = { };
> +       int ret, i;
>
>         memset(cmd, 0, sizeof(cmd));
>         memset(t, 0, sizeof(t));
>
>         /* tx */
>         /* opcode is in cmd[0] */
> -       cmd[0] = msg->read_opcode;
> -       cmd[1] = msg->from >> (msg->addr_width * 8 -  8);
> -       cmd[2] = msg->from >> (msg->addr_width * 8 - 16);
> -       cmd[3] = msg->from >> (msg->addr_width * 8 - 24);
> -       cmd[4] = msg->from >> (msg->addr_width * 8 - 32);
> +       cmd[0] = op->cmd.opcode;
> +       for (i = 0; i < op->addr.nbytes; i++)
> +               cmd[1 + i] = op->addr.val >> (8 * (op->addr.nbytes - i - 1));
> +
>         t[0].tx_buf = cmd;
> -       t[0].len = msg->addr_width + msg->dummy_bytes + 1;
> +       t[0].len = op->addr.nbytes + op->dummy.nbytes + 1;
>         t[0].bits_per_word = spi->bits_per_word;
> -       t[0].tx_nbits = msg->opcode_nbits;
> +       t[0].tx_nbits = op->cmd.buswidth;
>         /* lets mspi know that this is not last transfer */
>         qspi->trans_pos.mspi_last_trans = false;
> -       ret = bcm_qspi_transfer_one(spi->master, spi, &t[0]);
> +       ret = bcm_qspi_transfer_one(master, spi, &t[0]);
>
>         /* rx */
>         qspi->trans_pos.mspi_last_trans = true;
>         if (!ret) {
>                 /* rx */
> -               t[1].rx_buf = msg->buf;
> -               t[1].len = msg->len;
> -               t[1].rx_nbits =  msg->data_nbits;
> +               t[1].rx_buf = op->data.buf.in;
> +               t[1].len = op->data.nbytes;
> +               t[1].rx_nbits =  op->data.buswidth;
>                 t[1].bits_per_word = spi->bits_per_word;
> -               ret = bcm_qspi_transfer_one(spi->master, spi, &t[1]);
> +               ret = bcm_qspi_transfer_one(master, spi, &t[1]);
>         }
>
> -       if (!ret)
> -               msg->retlen = msg->len;
> -
>         return ret;
>  }
>
> -static int bcm_qspi_flash_read(struct spi_device *spi,
> -                              struct spi_flash_read_message *msg)
> +static int bcm_qspi_exec_mem_op(struct spi_device *spi,
> +                               const struct spi_mem_op *op)
>  {
>         struct bcm_qspi *qspi = spi_master_get_devdata(spi->master);
>         int ret = 0;
>         bool mspi_read = false;
> -       u32 addr, len;
> +       u32 addr = 0, len;
>         u_char *buf;
>
> -       buf = msg->buf;
> -       addr = msg->from;
> -       len = msg->len;
> +       if (!op->data.nbytes || !op->addr.nbytes || op->addr.nbytes > 4 ||
> +           op->data.dir != SPI_MEM_DATA_IN)
> +               return -ENOTSUPP;
> +
> +       buf = op->data.buf.in;
> +       addr = op->addr.val;
> +       len = op->data.nbytes;
>
>         if (bcm_qspi_bspi_ver_three(qspi) == true) {
>                 /*
> @@ -982,12 +981,40 @@ static int bcm_qspi_flash_read(struct spi_device *spi,
>                 mspi_read = true;
>
>         if (mspi_read)
> -               return bcm_qspi_mspi_flash_read(spi, msg);
> +               return bcm_qspi_mspi_exec_mem_op(spi, op);
>
> -       ret = bcm_qspi_bspi_set_mode(qspi, msg, -1);
> +       ret = bcm_qspi_bspi_set_mode(qspi, op, -1);
>
>         if (!ret)
> -               ret = bcm_qspi_bspi_flash_read(spi, msg);
> +               ret = bcm_qspi_bspi_exec_mem_op(spi, op);
> +
> +       return ret;
> +}
> +
> +static int bcm_qspi_exec_mem_op_wrapper(struct spi_mem *mem,
> +                                       const struct spi_mem_op *op)
> +{
> +       return bcm_qspi_exec_mem_op(mem->spi, op);
> +}
> +
> +static int bcm_qspi_flash_read_wrapper(struct spi_device *spi,
> +                                      struct spi_flash_read_message *msg)
> +{
> +       int ret;
> +       struct spi_mem_op op = SPI_MEM_OP(SPI_MEM_OP_CMD(msg->read_opcode, 1),
> +                                         SPI_MEM_OP_ADDR(msg->addr_width,
> +                                                         msg->from,
> +                                                         msg->addr_nbits),
> +                                         SPI_MEM_OP_DUMMY(msg->dummy_bytes,
> +                                                          msg->addr_nbits),
> +                                         SPI_MEM_OP_DATA_IN(msg->len,
> +                                                            msg->buf,
> +                                                            msg->data_nbits));
> +
> +       msg->retlen = 0;
> +       ret = bcm_qspi_exec_mem_op(spi, &op);
> +       if (!ret)
> +               msg->retlen = msg->len;
>
>         return ret;
>  }
> @@ -1026,10 +1053,10 @@ static irqreturn_t bcm_qspi_bspi_lr_l2_isr(int irq, void *dev_id)
>         struct bcm_qspi_soc_intc *soc_intc = qspi->soc_intc;
>         u32 status = qspi_dev_id->irqp->mask;
>
> -       if (qspi->bspi_enabled && qspi->bspi_rf_msg) {
> +       if (qspi->bspi_enabled && qspi->bspi_rf_op) {
>                 bcm_qspi_bspi_lr_data_read(qspi);
> -               if (qspi->bspi_rf_msg_len == 0) {
> -                       qspi->bspi_rf_msg = NULL;
> +               if (qspi->bspi_rf_op_len == 0) {
> +                       qspi->bspi_rf_op = NULL;
>                         if (qspi->soc_intc) {
>                                 /* disable soc BSPI interrupt */
>                                 soc_intc->bcm_qspi_int_set(soc_intc, BSPI_DONE,
> @@ -1038,7 +1065,7 @@ static irqreturn_t bcm_qspi_bspi_lr_l2_isr(int irq, void *dev_id)
>                                 status = INTR_BSPI_LR_SESSION_DONE_MASK;
>                         }
>
> -                       if (qspi->bspi_rf_msg_status)
> +                       if (qspi->bspi_rf_op_status)
>                                 bcm_qspi_bspi_lr_clear(qspi);
>                         else
>                                 bcm_qspi_bspi_flush_prefetch_buffers(qspi);
> @@ -1050,7 +1077,7 @@ static irqreturn_t bcm_qspi_bspi_lr_l2_isr(int irq, void *dev_id)
>         }
>
>         status &= INTR_BSPI_LR_SESSION_DONE_MASK;
> -       if (qspi->bspi_enabled && status && qspi->bspi_rf_msg_len == 0)
> +       if (qspi->bspi_enabled && status && qspi->bspi_rf_op_len == 0)
>                 complete(&qspi->bspi_done);
>
>         return IRQ_HANDLED;
> @@ -1063,7 +1090,7 @@ static irqreturn_t bcm_qspi_bspi_lr_err_l2_isr(int irq, void *dev_id)
>         struct bcm_qspi_soc_intc *soc_intc = qspi->soc_intc;
>
>         dev_err(&qspi->pdev->dev, "BSPI INT error\n");
> -       qspi->bspi_rf_msg_status = -EIO;
> +       qspi->bspi_rf_op_status = -EIO;
>         if (qspi->soc_intc)
>                 /* clear soc interrupt */
>                 soc_intc->bcm_qspi_int_ack(soc_intc, BSPI_ERR);
> @@ -1186,6 +1213,10 @@ static void bcm_qspi_hw_uninit(struct bcm_qspi *qspi)
>
>  }
>
> +static const struct spi_controller_mem_ops bcm_qspi_mem_ops = {
> +       .exec_op = bcm_qspi_exec_mem_op_wrapper,
> +};
> +
>  static const struct of_device_id bcm_qspi_of_match[] = {
>         { .compatible = "brcm,spi-bcm-qspi" },
>         {},
> @@ -1228,7 +1259,8 @@ int bcm_qspi_probe(struct platform_device *pdev,
>         master->mode_bits = SPI_CPHA | SPI_CPOL | SPI_RX_DUAL | SPI_RX_QUAD;
>         master->setup = bcm_qspi_setup;
>         master->transfer_one = bcm_qspi_transfer_one;
> -       master->spi_flash_read = bcm_qspi_flash_read;
> +       master->spi_flash_read = bcm_qspi_flash_read_wrapper;
> +       master->mem_ops = &bcm_qspi_mem_ops;
>         master->cleanup = bcm_qspi_cleanup;
>         master->dev.of_node = dev->of_node;
>         master->num_chipselect = NUM_CHIPSELECT;
> --
> 2.14.1
>
diff mbox series

Patch

diff --git a/drivers/spi/spi-bcm-qspi.c b/drivers/spi/spi-bcm-qspi.c
index 1596d35498c5..9f94268a68b5 100644
--- a/drivers/spi/spi-bcm-qspi.c
+++ b/drivers/spi/spi-bcm-qspi.c
@@ -30,6 +30,7 @@ 
 #include <linux/platform_device.h>
 #include <linux/slab.h>
 #include <linux/spi/spi.h>
+#include <linux/spi/spi-mem.h>
 #include <linux/sysfs.h>
 #include <linux/types.h>
 #include "spi-bcm-qspi.h"
@@ -215,10 +216,10 @@  struct bcm_qspi {
 	int bspi_maj_rev;
 	int bspi_min_rev;
 	int bspi_enabled;
-	struct spi_flash_read_message *bspi_rf_msg;
-	u32 bspi_rf_msg_idx;
-	u32 bspi_rf_msg_len;
-	u32 bspi_rf_msg_status;
+	const struct spi_mem_op *bspi_rf_op;
+	u32 bspi_rf_op_idx;
+	u32 bspi_rf_op_len;
+	u32 bspi_rf_op_status;
 	struct bcm_xfer_mode xfer_mode;
 	u32 s3_strap_override_ctrl;
 	bool bspi_mode;
@@ -313,26 +314,26 @@  static inline void bcm_qspi_bspi_lr_clear(struct bcm_qspi *qspi)
 
 static void bcm_qspi_bspi_lr_data_read(struct bcm_qspi *qspi)
 {
-	u32 *buf = (u32 *)qspi->bspi_rf_msg->buf;
+	u32 *buf = (u32 *)qspi->bspi_rf_op->data.buf.in;
 	u32 data = 0;
 
-	dev_dbg(&qspi->pdev->dev, "xfer %p rx %p rxlen %d\n", qspi->bspi_rf_msg,
-		qspi->bspi_rf_msg->buf, qspi->bspi_rf_msg_len);
+	dev_dbg(&qspi->pdev->dev, "xfer %p rx %p rxlen %d\n", qspi->bspi_rf_op,
+		qspi->bspi_rf_op->data.buf.in, qspi->bspi_rf_op_len);
 	while (!bcm_qspi_bspi_lr_is_fifo_empty(qspi)) {
 		data = bcm_qspi_bspi_lr_read_fifo(qspi);
-		if (likely(qspi->bspi_rf_msg_len >= 4) &&
+		if (likely(qspi->bspi_rf_op_len >= 4) &&
 		    IS_ALIGNED((uintptr_t)buf, 4)) {
-			buf[qspi->bspi_rf_msg_idx++] = data;
-			qspi->bspi_rf_msg_len -= 4;
+			buf[qspi->bspi_rf_op_idx++] = data;
+			qspi->bspi_rf_op_len -= 4;
 		} else {
 			/* Read out remaining bytes, make sure*/
-			u8 *cbuf = (u8 *)&buf[qspi->bspi_rf_msg_idx];
+			u8 *cbuf = (u8 *)&buf[qspi->bspi_rf_op_idx];
 
 			data = cpu_to_le32(data);
-			while (qspi->bspi_rf_msg_len) {
+			while (qspi->bspi_rf_op_len) {
 				*cbuf++ = (u8)data;
 				data >>= 8;
-				qspi->bspi_rf_msg_len--;
+				qspi->bspi_rf_op_len--;
 			}
 		}
 	}
@@ -349,14 +350,12 @@  static void bcm_qspi_bspi_set_xfer_params(struct bcm_qspi *qspi, u8 cmd_byte,
 }
 
 static int bcm_qspi_bspi_set_flex_mode(struct bcm_qspi *qspi,
-				       struct spi_flash_read_message *msg,
-				       int hp)
+				       const struct spi_mem_op *op, int hp)
 {
 	int bpc = 0, bpp = 0;
-	u8 command = msg->read_opcode;
-	int width  = msg->data_nbits ? msg->data_nbits : SPI_NBITS_SINGLE;
-	int addrlen = msg->addr_width;
-	int addr_nbits = msg->addr_nbits ? msg->addr_nbits : SPI_NBITS_SINGLE;
+	u8 command = op->cmd.opcode;
+	int width  = op->cmd.buswidth ? op->cmd.buswidth : SPI_NBITS_SINGLE;
+	int addrlen = op->addr.nbytes * 8;
 	int flex_mode = 1;
 
 	dev_dbg(&qspi->pdev->dev, "set flex mode w %x addrlen %x hp %d\n",
@@ -365,7 +364,7 @@  static int bcm_qspi_bspi_set_flex_mode(struct bcm_qspi *qspi,
 	if (addrlen == BSPI_ADDRLEN_4BYTES)
 		bpp = BSPI_BPP_ADDR_SELECT_MASK;
 
-	bpp |= msg->dummy_bytes * (8/addr_nbits);
+	bpp |= (op->dummy.nbytes * 8) / op->dummy.buswidth;
 
 	switch (width) {
 	case SPI_NBITS_SINGLE:
@@ -397,11 +396,10 @@  static int bcm_qspi_bspi_set_flex_mode(struct bcm_qspi *qspi,
 }
 
 static int bcm_qspi_bspi_set_override(struct bcm_qspi *qspi,
-				      struct spi_flash_read_message *msg,
-				      int hp)
+				      const struct spi_mem_op *op, int hp)
 {
-	int width = msg->data_nbits ? msg->data_nbits : SPI_NBITS_SINGLE;
-	int addrlen = msg->addr_width;
+	int width = op->data.buswidth ? op->data.buswidth : SPI_NBITS_SINGLE;
+	int addrlen = op->addr.nbytes;
 	u32 data = bcm_qspi_read(qspi, BSPI, BSPI_STRAP_OVERRIDE_CTRL);
 
 	dev_dbg(&qspi->pdev->dev, "set override mode w %x addrlen %x hp %d\n",
@@ -437,17 +435,17 @@  static int bcm_qspi_bspi_set_override(struct bcm_qspi *qspi,
 	/* set the override mode */
 	data |=	BSPI_STRAP_OVERRIDE_CTRL_OVERRIDE;
 	bcm_qspi_write(qspi, BSPI, BSPI_STRAP_OVERRIDE_CTRL, data);
-	bcm_qspi_bspi_set_xfer_params(qspi, msg->read_opcode, 0, 0, 0);
+	bcm_qspi_bspi_set_xfer_params(qspi, op->cmd.opcode, 0, 0, 0);
 
 	return 0;
 }
 
 static int bcm_qspi_bspi_set_mode(struct bcm_qspi *qspi,
-				  struct spi_flash_read_message *msg, int hp)
+				  const struct spi_mem_op *op, int hp)
 {
 	int error = 0;
-	int width = msg->data_nbits ? msg->data_nbits : SPI_NBITS_SINGLE;
-	int addrlen = msg->addr_width;
+	int width = op->data.buswidth ? op->data.buswidth : SPI_NBITS_SINGLE;
+	int addrlen = op->addr.nbytes;
 
 	/* default mode */
 	qspi->xfer_mode.flex_mode = true;
@@ -460,12 +458,12 @@  static int bcm_qspi_bspi_set_mode(struct bcm_qspi *qspi,
 		if (val & mask || qspi->s3_strap_override_ctrl & mask) {
 			qspi->xfer_mode.flex_mode = false;
 			bcm_qspi_write(qspi, BSPI, BSPI_FLEX_MODE_ENABLE, 0);
-			error = bcm_qspi_bspi_set_override(qspi, msg, hp);
+			error = bcm_qspi_bspi_set_override(qspi, op, hp);
 		}
 	}
 
 	if (qspi->xfer_mode.flex_mode)
-		error = bcm_qspi_bspi_set_flex_mode(qspi, msg, hp);
+		error = bcm_qspi_bspi_set_flex_mode(qspi, op, hp);
 
 	if (error) {
 		dev_warn(&qspi->pdev->dev,
@@ -794,19 +792,20 @@  static int write_to_hw(struct bcm_qspi *qspi, struct spi_device *spi)
 	return slot;
 }
 
-static int bcm_qspi_bspi_flash_read(struct spi_device *spi,
-				    struct spi_flash_read_message *msg)
+static int bcm_qspi_bspi_exec_mem_op(struct spi_device *spi,
+				     const struct spi_mem_op *op)
 {
 	struct bcm_qspi *qspi = spi_master_get_devdata(spi->master);
-	u32 addr = 0, len, rdlen, len_words;
+	u32 addr = 0, len, rdlen, len_words, from = 0;
 	int ret = 0;
 	unsigned long timeo = msecs_to_jiffies(100);
 	struct bcm_qspi_soc_intc *soc_intc = qspi->soc_intc;
 
 	if (bcm_qspi_bspi_ver_three(qspi))
-		if (msg->addr_width == BSPI_ADDRLEN_4BYTES)
+		if (op->addr.nbytes == BSPI_ADDRLEN_4BYTES)
 			return -EIO;
 
+	from = op->addr.val;
 	bcm_qspi_chip_select(qspi, spi->chip_select);
 	bcm_qspi_write(qspi, MSPI, MSPI_WRITE_LOCK, 0);
 
@@ -815,15 +814,15 @@  static int bcm_qspi_bspi_flash_read(struct spi_device *spi,
 	 * the upper address byte to bspi
 	 */
 	if (bcm_qspi_bspi_ver_three(qspi) == false) {
-		addr = msg->from & 0xff000000;
+		addr = from & 0xff000000;
 		bcm_qspi_write(qspi, BSPI,
 			       BSPI_BSPI_FLASH_UPPER_ADDR_BYTE, addr);
 	}
 
 	if (!qspi->xfer_mode.flex_mode)
-		addr = msg->from;
+		addr = from;
 	else
-		addr = msg->from & 0x00ffffff;
+		addr = from & 0x00ffffff;
 
 	if (bcm_qspi_bspi_ver_three(qspi) == true)
 		addr = (addr + 0xc00000) & 0xffffff;
@@ -832,8 +831,8 @@  static int bcm_qspi_bspi_flash_read(struct spi_device *spi,
 	 * read into the entire buffer by breaking the reads
 	 * into RAF buffer read lengths
 	 */
-	len = msg->len;
-	qspi->bspi_rf_msg_idx = 0;
+	len = op->data.nbytes;
+	qspi->bspi_rf_op_idx = 0;
 
 	do {
 		if (len > BSPI_READ_LENGTH)
@@ -844,9 +843,9 @@  static int bcm_qspi_bspi_flash_read(struct spi_device *spi,
 		reinit_completion(&qspi->bspi_done);
 		bcm_qspi_enable_bspi(qspi);
 		len_words = (rdlen + 3) >> 2;
-		qspi->bspi_rf_msg = msg;
-		qspi->bspi_rf_msg_status = 0;
-		qspi->bspi_rf_msg_len = rdlen;
+		qspi->bspi_rf_op = op;
+		qspi->bspi_rf_op_status = 0;
+		qspi->bspi_rf_op_len = rdlen;
 		dev_dbg(&qspi->pdev->dev,
 			"bspi xfr addr 0x%x len 0x%x", addr, rdlen);
 		bcm_qspi_write(qspi, BSPI, BSPI_RAF_START_ADDR, addr);
@@ -871,7 +870,6 @@  static int bcm_qspi_bspi_flash_read(struct spi_device *spi,
 		}
 
 		/* set msg return length */
-		msg->retlen += rdlen;
 		addr += rdlen;
 		len -= rdlen;
 	} while (len);
@@ -906,61 +904,62 @@  static int bcm_qspi_transfer_one(struct spi_master *master,
 	return 0;
 }
 
-static int bcm_qspi_mspi_flash_read(struct spi_device *spi,
-				    struct spi_flash_read_message *msg)
+static int bcm_qspi_mspi_exec_mem_op(struct spi_device *spi,
+				     const struct spi_mem_op *op)
 {
-	struct bcm_qspi *qspi = spi_master_get_devdata(spi->master);
+	struct spi_master *master = spi->master;
+	struct bcm_qspi *qspi = spi_master_get_devdata(master);
 	struct spi_transfer t[2];
-	u8 cmd[6];
-	int ret;
+	u8 cmd[6] = { };
+	int ret, i;
 
 	memset(cmd, 0, sizeof(cmd));
 	memset(t, 0, sizeof(t));
 
 	/* tx */
 	/* opcode is in cmd[0] */
-	cmd[0] = msg->read_opcode;
-	cmd[1] = msg->from >> (msg->addr_width * 8 -  8);
-	cmd[2] = msg->from >> (msg->addr_width * 8 - 16);
-	cmd[3] = msg->from >> (msg->addr_width * 8 - 24);
-	cmd[4] = msg->from >> (msg->addr_width * 8 - 32);
+	cmd[0] = op->cmd.opcode;
+	for (i = 0; i < op->addr.nbytes; i++)
+		cmd[1 + i] = op->addr.val >> (8 * (op->addr.nbytes - i - 1));
+
 	t[0].tx_buf = cmd;
-	t[0].len = msg->addr_width + msg->dummy_bytes + 1;
+	t[0].len = op->addr.nbytes + op->dummy.nbytes + 1;
 	t[0].bits_per_word = spi->bits_per_word;
-	t[0].tx_nbits = msg->opcode_nbits;
+	t[0].tx_nbits = op->cmd.buswidth;
 	/* lets mspi know that this is not last transfer */
 	qspi->trans_pos.mspi_last_trans = false;
-	ret = bcm_qspi_transfer_one(spi->master, spi, &t[0]);
+	ret = bcm_qspi_transfer_one(master, spi, &t[0]);
 
 	/* rx */
 	qspi->trans_pos.mspi_last_trans = true;
 	if (!ret) {
 		/* rx */
-		t[1].rx_buf = msg->buf;
-		t[1].len = msg->len;
-		t[1].rx_nbits =  msg->data_nbits;
+		t[1].rx_buf = op->data.buf.in;
+		t[1].len = op->data.nbytes;
+		t[1].rx_nbits =  op->data.buswidth;
 		t[1].bits_per_word = spi->bits_per_word;
-		ret = bcm_qspi_transfer_one(spi->master, spi, &t[1]);
+		ret = bcm_qspi_transfer_one(master, spi, &t[1]);
 	}
 
-	if (!ret)
-		msg->retlen = msg->len;
-
 	return ret;
 }
 
-static int bcm_qspi_flash_read(struct spi_device *spi,
-			       struct spi_flash_read_message *msg)
+static int bcm_qspi_exec_mem_op(struct spi_device *spi,
+				const struct spi_mem_op *op)
 {
 	struct bcm_qspi *qspi = spi_master_get_devdata(spi->master);
 	int ret = 0;
 	bool mspi_read = false;
-	u32 addr, len;
+	u32 addr = 0, len;
 	u_char *buf;
 
-	buf = msg->buf;
-	addr = msg->from;
-	len = msg->len;
+	if (!op->data.nbytes || !op->addr.nbytes || op->addr.nbytes > 4 ||
+	    op->data.dir != SPI_MEM_DATA_IN)
+		return -ENOTSUPP;
+
+	buf = op->data.buf.in;
+	addr = op->addr.val;
+	len = op->data.nbytes;
 
 	if (bcm_qspi_bspi_ver_three(qspi) == true) {
 		/*
@@ -982,12 +981,40 @@  static int bcm_qspi_flash_read(struct spi_device *spi,
 		mspi_read = true;
 
 	if (mspi_read)
-		return bcm_qspi_mspi_flash_read(spi, msg);
+		return bcm_qspi_mspi_exec_mem_op(spi, op);
 
-	ret = bcm_qspi_bspi_set_mode(qspi, msg, -1);
+	ret = bcm_qspi_bspi_set_mode(qspi, op, -1);
 
 	if (!ret)
-		ret = bcm_qspi_bspi_flash_read(spi, msg);
+		ret = bcm_qspi_bspi_exec_mem_op(spi, op);
+
+	return ret;
+}
+
+static int bcm_qspi_exec_mem_op_wrapper(struct spi_mem *mem,
+					const struct spi_mem_op *op)
+{
+	return bcm_qspi_exec_mem_op(mem->spi, op);
+}
+
+static int bcm_qspi_flash_read_wrapper(struct spi_device *spi,
+				       struct spi_flash_read_message *msg)
+{
+	int ret;
+	struct spi_mem_op op = SPI_MEM_OP(SPI_MEM_OP_CMD(msg->read_opcode, 1),
+					  SPI_MEM_OP_ADDR(msg->addr_width,
+							  msg->from,
+							  msg->addr_nbits),
+					  SPI_MEM_OP_DUMMY(msg->dummy_bytes,
+							   msg->addr_nbits),
+					  SPI_MEM_OP_DATA_IN(msg->len,
+							     msg->buf,
+							     msg->data_nbits));
+
+	msg->retlen = 0;
+	ret = bcm_qspi_exec_mem_op(spi, &op);
+	if (!ret)
+		msg->retlen = msg->len;
 
 	return ret;
 }
@@ -1026,10 +1053,10 @@  static irqreturn_t bcm_qspi_bspi_lr_l2_isr(int irq, void *dev_id)
 	struct bcm_qspi_soc_intc *soc_intc = qspi->soc_intc;
 	u32 status = qspi_dev_id->irqp->mask;
 
-	if (qspi->bspi_enabled && qspi->bspi_rf_msg) {
+	if (qspi->bspi_enabled && qspi->bspi_rf_op) {
 		bcm_qspi_bspi_lr_data_read(qspi);
-		if (qspi->bspi_rf_msg_len == 0) {
-			qspi->bspi_rf_msg = NULL;
+		if (qspi->bspi_rf_op_len == 0) {
+			qspi->bspi_rf_op = NULL;
 			if (qspi->soc_intc) {
 				/* disable soc BSPI interrupt */
 				soc_intc->bcm_qspi_int_set(soc_intc, BSPI_DONE,
@@ -1038,7 +1065,7 @@  static irqreturn_t bcm_qspi_bspi_lr_l2_isr(int irq, void *dev_id)
 				status = INTR_BSPI_LR_SESSION_DONE_MASK;
 			}
 
-			if (qspi->bspi_rf_msg_status)
+			if (qspi->bspi_rf_op_status)
 				bcm_qspi_bspi_lr_clear(qspi);
 			else
 				bcm_qspi_bspi_flush_prefetch_buffers(qspi);
@@ -1050,7 +1077,7 @@  static irqreturn_t bcm_qspi_bspi_lr_l2_isr(int irq, void *dev_id)
 	}
 
 	status &= INTR_BSPI_LR_SESSION_DONE_MASK;
-	if (qspi->bspi_enabled && status && qspi->bspi_rf_msg_len == 0)
+	if (qspi->bspi_enabled && status && qspi->bspi_rf_op_len == 0)
 		complete(&qspi->bspi_done);
 
 	return IRQ_HANDLED;
@@ -1063,7 +1090,7 @@  static irqreturn_t bcm_qspi_bspi_lr_err_l2_isr(int irq, void *dev_id)
 	struct bcm_qspi_soc_intc *soc_intc = qspi->soc_intc;
 
 	dev_err(&qspi->pdev->dev, "BSPI INT error\n");
-	qspi->bspi_rf_msg_status = -EIO;
+	qspi->bspi_rf_op_status = -EIO;
 	if (qspi->soc_intc)
 		/* clear soc interrupt */
 		soc_intc->bcm_qspi_int_ack(soc_intc, BSPI_ERR);
@@ -1186,6 +1213,10 @@  static void bcm_qspi_hw_uninit(struct bcm_qspi *qspi)
 
 }
 
+static const struct spi_controller_mem_ops bcm_qspi_mem_ops = {
+	.exec_op = bcm_qspi_exec_mem_op_wrapper,
+};
+
 static const struct of_device_id bcm_qspi_of_match[] = {
 	{ .compatible = "brcm,spi-bcm-qspi" },
 	{},
@@ -1228,7 +1259,8 @@  int bcm_qspi_probe(struct platform_device *pdev,
 	master->mode_bits = SPI_CPHA | SPI_CPOL | SPI_RX_DUAL | SPI_RX_QUAD;
 	master->setup = bcm_qspi_setup;
 	master->transfer_one = bcm_qspi_transfer_one;
-	master->spi_flash_read = bcm_qspi_flash_read;
+	master->spi_flash_read = bcm_qspi_flash_read_wrapper;
+	master->mem_ops = &bcm_qspi_mem_ops;
 	master->cleanup = bcm_qspi_cleanup;
 	master->dev.of_node = dev->of_node;
 	master->num_chipselect = NUM_CHIPSELECT;