diff options
Diffstat (limited to 'drivers/spi/spi-fsl-dspi.c')
| -rw-r--r-- | drivers/spi/spi-fsl-dspi.c | 46 | 
1 files changed, 45 insertions, 1 deletions
| diff --git a/drivers/spi/spi-fsl-dspi.c b/drivers/spi/spi-fsl-dspi.c index 067c954cb6ea..863781ba6c16 100644 --- a/drivers/spi/spi-fsl-dspi.c +++ b/drivers/spi/spi-fsl-dspi.c @@ -1,7 +1,7 @@  // SPDX-License-Identifier: GPL-2.0+  //  // Copyright 2013 Freescale Semiconductor, Inc. -// Copyright 2020 NXP +// Copyright 2020-2025 NXP  //  // Freescale DSPI driver  // This file contains a driver for the Freescale DSPI @@ -62,6 +62,7 @@  #define SPI_SR_TFIWF			BIT(18)  #define SPI_SR_RFDF			BIT(17)  #define SPI_SR_CMDFFF			BIT(16) +#define SPI_SR_TXRXS			BIT(30)  #define SPI_SR_CLEAR			(SPI_SR_TCFQF | \  					SPI_SR_TFUF | SPI_SR_TFFF | \  					SPI_SR_CMDTCF | SPI_SR_SPEF | \ @@ -921,9 +922,20 @@ static int dspi_transfer_one_message(struct spi_controller *ctlr,  	struct spi_transfer *transfer;  	bool cs = false;  	int status = 0; +	u32 val = 0; +	bool cs_change = false;  	message->actual_length = 0; +	/* Put DSPI in running mode if halted. */ +	regmap_read(dspi->regmap, SPI_MCR, &val); +	if (val & SPI_MCR_HALT) { +		regmap_update_bits(dspi->regmap, SPI_MCR, SPI_MCR_HALT, 0); +		while (regmap_read(dspi->regmap, SPI_SR, &val) >= 0 && +		       !(val & SPI_SR_TXRXS)) +			; +	} +  	list_for_each_entry(transfer, &message->transfers, transfer_list) {  		dspi->cur_transfer = transfer;  		dspi->cur_msg = message; @@ -953,6 +965,7 @@ static int dspi_transfer_one_message(struct spi_controller *ctlr,  				dspi->tx_cmd |= SPI_PUSHR_CMD_CONT;  		} +		cs_change = transfer->cs_change;  		dspi->tx = transfer->tx_buf;  		dspi->rx = transfer->rx_buf;  		dspi->len = transfer->len; @@ -962,6 +975,8 @@ static int dspi_transfer_one_message(struct spi_controller *ctlr,  				   SPI_MCR_CLR_TXF | SPI_MCR_CLR_RXF,  				   SPI_MCR_CLR_TXF | SPI_MCR_CLR_RXF); +		regmap_write(dspi->regmap, SPI_SR, SPI_SR_CLEAR); +  		spi_take_timestamp_pre(dspi->ctlr, dspi->cur_transfer,  				       dspi->progress, !dspi->irq); @@ -988,6 +1003,15 @@ static int dspi_transfer_one_message(struct spi_controller *ctlr,  			dspi_deassert_cs(spi, &cs);  	} +	if (status || !cs_change) { +		/* Put DSPI in stop mode */ +		regmap_update_bits(dspi->regmap, SPI_MCR, +				   SPI_MCR_HALT, SPI_MCR_HALT); +		while (regmap_read(dspi->regmap, SPI_SR, &val) >= 0 && +		       val & SPI_SR_TXRXS) +			; +	} +  	message->status = status;  	spi_finalize_current_message(ctlr); @@ -1167,6 +1191,20 @@ static int dspi_resume(struct device *dev)  static SIMPLE_DEV_PM_OPS(dspi_pm, dspi_suspend, dspi_resume); +static const struct regmap_range dspi_yes_ranges[] = { +	regmap_reg_range(SPI_MCR, SPI_MCR), +	regmap_reg_range(SPI_TCR, SPI_CTAR(3)), +	regmap_reg_range(SPI_SR, SPI_TXFR3), +	regmap_reg_range(SPI_RXFR0, SPI_RXFR3), +	regmap_reg_range(SPI_CTARE(0), SPI_CTARE(3)), +	regmap_reg_range(SPI_SREX, SPI_SREX), +}; + +static const struct regmap_access_table dspi_access_table = { +	.yes_ranges	= dspi_yes_ranges, +	.n_yes_ranges	= ARRAY_SIZE(dspi_yes_ranges), +}; +  static const struct regmap_range dspi_volatile_ranges[] = {  	regmap_reg_range(SPI_MCR, SPI_TCR),  	regmap_reg_range(SPI_SR, SPI_SR), @@ -1184,6 +1222,8 @@ static const struct regmap_config dspi_regmap_config = {  	.reg_stride	= 4,  	.max_register	= 0x88,  	.volatile_table	= &dspi_volatile_table, +	.rd_table	= &dspi_access_table, +	.wr_table	= &dspi_access_table,  };  static const struct regmap_range dspi_xspi_volatile_ranges[] = { @@ -1205,6 +1245,8 @@ static const struct regmap_config dspi_xspi_regmap_config[] = {  		.reg_stride	= 4,  		.max_register	= 0x13c,  		.volatile_table	= &dspi_xspi_volatile_table, +		.rd_table	= &dspi_access_table, +		.wr_table	= &dspi_access_table,  	},  	{  		.name		= "pushr", @@ -1227,6 +1269,8 @@ static int dspi_init(struct fsl_dspi *dspi)  	if (!spi_controller_is_target(dspi->ctlr))  		mcr |= SPI_MCR_HOST; +	mcr |= SPI_MCR_HALT; +  	regmap_write(dspi->regmap, SPI_MCR, mcr);  	regmap_write(dspi->regmap, SPI_SR, SPI_SR_CLEAR); | 
