Commit 933174ae authored by Linus Torvalds's avatar Linus Torvalds
Browse files
Pull spi fixes from Mark Brown:
 "A collection of fixes that came in since the merge window, plus an
  update to MAINTAINERS.

  The Cadence fixes are coming from the addition of device mode support,
  they required a couple of incremental updates in order to get
  something that works robustly for both device and controller modes"

* tag 'spi-fix-v6.4-rc3' of git://git.kernel.org/pub/scm/linux/kernel/git/broonie/spi:
  spi: spi-cadence: Interleave write of TX and read of RX FIFO
  spi: dw: Replace spi->chip_select references with function calls
  spi: MAINTAINERS: drop Krzysztof Kozlowski from Samsung SPI
  spi: spi-cadence: Only overlap FIFO transactions in slave mode
  spi: spi-cadence: Avoid read of RX FIFO before its ready
  spi: spi-geni-qcom: Select FIFO mode for chip select
parents f767b330 6afe2ae8
Loading
Loading
Loading
Loading
+0 −1
Original line number Diff line number Diff line
@@ -18703,7 +18703,6 @@ F: include/dt-bindings/clock/samsung,*.h
F:	include/linux/clk/samsung.h
SAMSUNG SPI DRIVERS
M:	Krzysztof Kozlowski <krzysztof.kozlowski@linaro.org>
M:	Andi Shyti <andi.shyti@kernel.org>
L:	linux-spi@vger.kernel.org
L:	linux-samsung-soc@vger.kernel.org
+45 −60
Original line number Diff line number Diff line
@@ -12,6 +12,7 @@
#include <linux/gpio/consumer.h>
#include <linux/interrupt.h>
#include <linux/io.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/of_irq.h>
#include <linux/of_address.h>
@@ -301,49 +302,43 @@ static int cdns_spi_setup_transfer(struct spi_device *spi,
}

/**
 * cdns_spi_fill_tx_fifo - Fills the TX FIFO with as many bytes as possible
 * cdns_spi_process_fifo - Fills the TX FIFO, and drain the RX FIFO
 * @xspi:	Pointer to the cdns_spi structure
 * @ntx:	Number of bytes to pack into the TX FIFO
 * @nrx:	Number of bytes to drain from the RX FIFO
 */
static void cdns_spi_fill_tx_fifo(struct cdns_spi *xspi)
static void cdns_spi_process_fifo(struct cdns_spi *xspi, int ntx, int nrx)
{
	unsigned long trans_cnt = 0;
	ntx = clamp(ntx, 0, xspi->tx_bytes);
	nrx = clamp(nrx, 0, xspi->rx_bytes);

	while ((trans_cnt < xspi->tx_fifo_depth) &&
	       (xspi->tx_bytes > 0)) {
	xspi->tx_bytes -= ntx;
	xspi->rx_bytes -= nrx;

	while (ntx || nrx) {
		/* When xspi in busy condition, bytes may send failed,
		 * then spi control did't work thoroughly, add one byte delay
		 */
		if (cdns_spi_read(xspi, CDNS_SPI_ISR) &
		    CDNS_SPI_IXR_TXFULL)
		if (cdns_spi_read(xspi, CDNS_SPI_ISR) & CDNS_SPI_IXR_TXFULL)
			udelay(10);

		if (ntx) {
			if (xspi->txbuf)
				cdns_spi_write(xspi, CDNS_SPI_TXD, *xspi->txbuf++);
			else
				cdns_spi_write(xspi, CDNS_SPI_TXD, 0);

		xspi->tx_bytes--;
		trans_cnt++;
	}
			ntx--;
		}

/**
 * cdns_spi_read_rx_fifo - Reads the RX FIFO with as many bytes as possible
 * @xspi:       Pointer to the cdns_spi structure
 * @count:	Read byte count
 */
static void cdns_spi_read_rx_fifo(struct cdns_spi *xspi, unsigned long count)
{
	u8 data;
		if (nrx) {
			u8 data = cdns_spi_read(xspi, CDNS_SPI_RXD);

	/* Read out the data from the RX FIFO */
	while (count > 0) {
		data = cdns_spi_read(xspi, CDNS_SPI_RXD);
			if (xspi->rxbuf)
				*xspi->rxbuf++ = data;
		xspi->rx_bytes--;
		count--;

			nrx--;
		}
	}
}

@@ -381,33 +376,22 @@ static irqreturn_t cdns_spi_irq(int irq, void *dev_id)
		spi_finalize_current_transfer(ctlr);
		status = IRQ_HANDLED;
	} else if (intr_status & CDNS_SPI_IXR_TXOW) {
		int trans_cnt = cdns_spi_read(xspi, CDNS_SPI_THLD);
		int threshold = cdns_spi_read(xspi, CDNS_SPI_THLD);
		int trans_cnt = xspi->rx_bytes - xspi->tx_bytes;

		if (threshold > 1)
			trans_cnt -= threshold;

		/* Set threshold to one if number of pending are
		 * less than half fifo
		 */
		if (xspi->tx_bytes < xspi->tx_fifo_depth >> 1)
			cdns_spi_write(xspi, CDNS_SPI_THLD, 1);

		while (trans_cnt) {
			cdns_spi_read_rx_fifo(xspi, 1);

		if (xspi->tx_bytes) {
				if (xspi->txbuf)
					cdns_spi_write(xspi, CDNS_SPI_TXD,
						       *xspi->txbuf++);
				else
					cdns_spi_write(xspi, CDNS_SPI_TXD, 0);
				xspi->tx_bytes--;
			}
			trans_cnt--;
		}
		if (!xspi->tx_bytes) {
			/* Fixed delay due to controller limitation with
			 * RX_NEMPTY incorrect status
			 * Xilinx AR:65885 contains more details
			 */
			udelay(10);
			cdns_spi_read_rx_fifo(xspi, xspi->rx_bytes);
			cdns_spi_process_fifo(xspi, trans_cnt, trans_cnt);
		} else {
			cdns_spi_process_fifo(xspi, 0, trans_cnt);
			cdns_spi_write(xspi, CDNS_SPI_IDR,
				       CDNS_SPI_IXR_DEFAULT);
			spi_finalize_current_transfer(ctlr);
@@ -450,16 +434,17 @@ static int cdns_transfer_one(struct spi_controller *ctlr,
	xspi->tx_bytes = transfer->len;
	xspi->rx_bytes = transfer->len;

	if (!spi_controller_is_slave(ctlr))
	if (!spi_controller_is_slave(ctlr)) {
		cdns_spi_setup_transfer(spi, transfer);

	} else {
		/* Set TX empty threshold to half of FIFO depth
		 * only if TX bytes are more than half FIFO depth.
		 */
	if (xspi->tx_bytes > (xspi->tx_fifo_depth >> 1))
		if (xspi->tx_bytes > xspi->tx_fifo_depth)
			cdns_spi_write(xspi, CDNS_SPI_THLD, xspi->tx_fifo_depth >> 1);
	}

	cdns_spi_fill_tx_fifo(xspi);
	cdns_spi_process_fifo(xspi, xspi->tx_fifo_depth, 0);
	spi_transfer_delay_exec(transfer);

	cdns_spi_write(xspi, CDNS_SPI_IER, CDNS_SPI_IXR_DEFAULT);
+4 −4
Original line number Diff line number Diff line
@@ -264,17 +264,17 @@ static void dw_spi_elba_set_cs(struct spi_device *spi, bool enable)
	struct regmap *syscon = dwsmmio->priv;
	u8 cs;

	cs = spi->chip_select;
	cs = spi_get_chipselect(spi, 0);
	if (cs < 2)
		dw_spi_elba_override_cs(syscon, spi->chip_select, enable);
		dw_spi_elba_override_cs(syscon, spi_get_chipselect(spi, 0), enable);

	/*
	 * The DW SPI controller needs a native CS bit selected to start
	 * the serial engine.
	 */
	spi->chip_select = 0;
	spi_set_chipselect(spi, 0, 0);
	dw_spi_set_cs(spi, enable);
	spi->chip_select = cs;
	spi_get_chipselect(spi, cs);
}

static int dw_spi_elba_init(struct platform_device *pdev,
+2 −0
Original line number Diff line number Diff line
@@ -294,6 +294,8 @@ static void spi_geni_set_cs(struct spi_device *slv, bool set_flag)
	mas->cs_flag = set_flag;
	/* set xfer_mode to FIFO to complete cs_done in isr */
	mas->cur_xfer_mode = GENI_SE_FIFO;
	geni_se_select_mode(se, mas->cur_xfer_mode);

	reinit_completion(&mas->cs_done);
	if (set_flag)
		geni_se_setup_m_cmd(se, SPI_CS_ASSERT, 0);