diff --git a/drivers/spi/spi-tegra114.c b/drivers/spi/spi-tegra114.c index f47417dd9edb..0cb0932d32fd 100644 --- a/drivers/spi/spi-tegra114.c +++ b/drivers/spi/spi-tegra114.c @@ -193,6 +193,7 @@ struct tegra_spi_data { unsigned dma_buf_size; unsigned max_buf_size; bool is_curr_dma_xfer; + bool use_hw_based_cs; struct completion rx_dma_complete; struct completion tx_dma_complete; @@ -723,7 +724,9 @@ static void tegra_spi_deinit_dma_param(struct tegra_spi_data *tspi, } static u32 tegra_spi_setup_transfer_one(struct spi_device *spi, - struct spi_transfer *t, bool is_first_of_msg) + struct spi_transfer *t, + bool is_first_of_msg, + bool is_single_xfer) { struct tegra_spi_data *tspi = spi_master_get_devdata(spi->master); u32 speed = t->speed_hz; @@ -780,11 +783,17 @@ static u32 tegra_spi_setup_transfer_one(struct spi_device *spi, if (spi->cs_gpiod) gpiod_set_value(spi->cs_gpiod, 1); - command1 |= SPI_CS_SW_HW; - if (spi->mode & SPI_CS_HIGH) - command1 |= SPI_CS_SW_VAL; - else - command1 &= ~SPI_CS_SW_VAL; + if (is_single_xfer && !(t->cs_change)) { + tspi->use_hw_based_cs = true; + command1 &= ~(SPI_CS_SW_HW | SPI_CS_SW_VAL); + } else { + tspi->use_hw_based_cs = false; + command1 |= SPI_CS_SW_HW; + if (spi->mode & SPI_CS_HIGH) + command1 |= SPI_CS_SW_VAL; + else + command1 &= ~SPI_CS_SW_VAL; + } tegra_spi_writel(tspi, 0, SPI_COMMAND2); } else { @@ -905,11 +914,14 @@ static void tegra_spi_transfer_end(struct spi_device *spi) if (spi->cs_gpiod) gpiod_set_value(spi->cs_gpiod, 0); - if (cs_val) - tspi->command1_reg |= SPI_CS_SW_VAL; - else - tspi->command1_reg &= ~SPI_CS_SW_VAL; - tegra_spi_writel(tspi, tspi->command1_reg, SPI_COMMAND1); + if (!tspi->use_hw_based_cs) { + if (cs_val) + tspi->command1_reg |= SPI_CS_SW_VAL; + else + tspi->command1_reg &= ~SPI_CS_SW_VAL; + tegra_spi_writel(tspi, tspi->command1_reg, SPI_COMMAND1); + } + tegra_spi_writel(tspi, tspi->def_command1_reg, SPI_COMMAND1); } @@ -936,16 +948,19 @@ static int tegra_spi_transfer_one_message(struct spi_master *master, struct spi_device *spi = msg->spi; int ret; bool skip = false; + int single_xfer; msg->status = 0; msg->actual_length = 0; + single_xfer = list_is_singular(&msg->transfers); list_for_each_entry(xfer, &msg->transfers, transfer_list) { u32 cmd1; reinit_completion(&tspi->xfer_completion); - cmd1 = tegra_spi_setup_transfer_one(spi, xfer, is_first_msg); + cmd1 = tegra_spi_setup_transfer_one(spi, xfer, is_first_msg, + single_xfer); if (!xfer->len) { ret = 0;