Tegra Quad SPI controller hardware supports sending dummy bytes based
on programmed dummy clock cycles after the actual transfer bytes.

This patch adds this support of hardware dummy bytes transfer and
skips transfer of dummy bytes from the software.

For dummy cycles more than Tegra Quad SPI hardware maximum dummy
cycles limit, driver transfers dummy bytes from the software.

Signed-off-by: Sowjanya Komatineni <skomatin...@nvidia.com>
---
 drivers/spi/spi-tegra210-quad.c | 41 ++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 40 insertions(+), 1 deletion(-)

diff --git a/drivers/spi/spi-tegra210-quad.c b/drivers/spi/spi-tegra210-quad.c
index e7bee8d..695a296 100644
--- a/drivers/spi/spi-tegra210-quad.c
+++ b/drivers/spi/spi-tegra210-quad.c
@@ -117,6 +117,7 @@
 
 #define QSPI_MISC_REG                           0x194
 #define QSPI_NUM_DUMMY_CYCLE(x)                        (((x) & 0xff) << 0)
+#define QSPI_DUMMY_CYCLES_MAX                  0xff
 
 #define DATA_DIR_TX                            BIT(0)
 #define DATA_DIR_RX                            BIT(1)
@@ -170,6 +171,7 @@ struct tegra_qspi {
        u32                                     def_command2_reg;
        u32                                     spi_cs_timing1;
        u32                                     spi_cs_timing2;
+       u8                                      dummy_cycles;
 
        struct completion                       xfer_completion;
        struct spi_transfer                     *curr_xfer;
@@ -856,6 +858,8 @@ static int tegra_qspi_start_transfer_one(struct spi_device 
*spi,
 
        tqspi->command1_reg = command1;
 
+       tegra_qspi_writel(tqspi, QSPI_NUM_DUMMY_CYCLE(tqspi->dummy_cycles), 
QSPI_MISC_REG);
+
        ret = tegra_qspi_flush_fifos(tqspi, false);
        if (ret < 0)
                return ret;
@@ -974,7 +978,8 @@ static int tegra_qspi_transfer_one_message(struct 
spi_master *master, struct spi
 {
        struct tegra_qspi *tqspi = spi_master_get_devdata(master);
        struct spi_device *spi = msg->spi;
-       struct spi_transfer *xfer;
+       struct spi_transfer *xfer, *next_xfer;
+       bool use_hw_dummy_cycles = false;
        bool is_first_msg = true;
        int ret;
 
@@ -984,8 +989,42 @@ static int tegra_qspi_transfer_one_message(struct 
spi_master *master, struct spi
        tqspi->rx_status = 0;
 
        list_for_each_entry(xfer, &msg->transfers, transfer_list) {
+               u8 dummy_cycles = 0;
                u32 cmd1;
 
+               /*
+                * Skip dummy bytes transfer if they are transferred by the 
hardware along
+                * with previous transfer.
+                */
+               if (xfer->dummy_data && use_hw_dummy_cycles) {
+                       msg->actual_length += xfer->len;
+                       continue;
+               }
+
+               /*
+                * Tegra QSPI hardware supports dummy bytes transfer after 
actual transfer
+                * bytes based on programmed dummy clock cycles in the 
QSPI_MISC register.
+                * So, check if the next transfer is dummy data transfer and 
program dummy
+                * clock cycles along with the current transfer.
+                */
+               if (!list_is_last(&xfer->transfer_list, &msg->transfers)) {
+                       next_xfer = list_next_entry(xfer, transfer_list);
+                       if (next_xfer && next_xfer->dummy_data) {
+                               dummy_cycles = next_xfer->len * 8 / 
next_xfer->tx_nbits;
+                               use_hw_dummy_cycles = true;
+                               /*
+                                * Use software dummy bytes transfer if dummy 
cycles exceeds
+                                * Tegra QSPI hardware maximum dummy cycles 
limit.
+                                */
+                               if (dummy_cycles > QSPI_DUMMY_CYCLES_MAX) {
+                                       use_hw_dummy_cycles = false;
+                                       dummy_cycles = 0;
+                               }
+                       }
+               }
+
+               tqspi->dummy_cycles = dummy_cycles;
+
                reinit_completion(&tqspi->xfer_completion);
 
                cmd1 = tegra_qspi_setup_transfer_one(spi, xfer, is_first_msg);
-- 
2.7.4

Reply via email to