Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 7910d9af authored by Nicolas Ferre's avatar Nicolas Ferre Committed by Mark Brown
Browse files

spi: atmel: Use core SPI_MASTER_MUST_[RT]X handling



We need both RX and TX data for each transfer in any case (PIO, PDC, DMA).
So convert the driver to the core dummy buffer handling with the
SPI_MASTER_MUST_RX/SPI_MASTER_MUST_TX infrastructure.

This move changes the maximum PDC/DMA buffer handling to 65535 bytes
instead of a single page and sets master->max_dma_len to this value.

All dummy buffer management is removed from the driver.

Signed-off-by: default avatarNicolas Ferre <nicolas.ferre@atmel.com>
Signed-off-by: default avatarMark Brown <broonie@kernel.org>
parent ce24a513
Loading
Loading
Loading
Loading
+35 −96
Original line number Diff line number Diff line
@@ -303,10 +303,6 @@ struct atmel_spi {

	struct completion	xfer_completion;

	/* scratch buffer */
	void			*buffer;
	dma_addr_t		buffer_dma;

	struct atmel_spi_caps	caps;

	bool			use_dma;
@@ -327,7 +323,7 @@ struct atmel_spi_device {
	u32			csr;
};

#define BUFFER_SIZE		PAGE_SIZE
#define SPI_MAX_DMA_XFER	65535 /* true for both PDC and DMA */
#define INVALID_DMA_ADDRESS	0xffffffff

/*
@@ -612,14 +608,10 @@ static void atmel_spi_next_xfer_single(struct spi_master *master,
		cpu_relax();
	}

	if (xfer->tx_buf) {
	if (xfer->bits_per_word > 8)
		spi_writel(as, TDR, *(u16 *)(xfer->tx_buf + xfer_pos));
	else
		spi_writel(as, TDR, *(u8 *)(xfer->tx_buf + xfer_pos));
	} else {
		spi_writel(as, TDR, 0);
	}

	dev_dbg(master->dev.parent,
		"  start pio xfer %p: len %u tx %p rx %p bitpw %d\n",
@@ -666,7 +658,6 @@ static void atmel_spi_next_xfer_fifo(struct spi_master *master,

	/* Fill TX FIFO */
	while (num_data >= 2) {
		if (xfer->tx_buf) {
		if (xfer->bits_per_word > 8) {
			td0 = *words++;
			td1 = *words++;
@@ -674,24 +665,16 @@ static void atmel_spi_next_xfer_fifo(struct spi_master *master,
			td0 = *bytes++;
			td1 = *bytes++;
		}
		} else {
			td0 = 0;
			td1 = 0;
		}

		spi_writel(as, TDR, (td1 << 16) | td0);
		num_data -= 2;
	}

	if (num_data) {
		if (xfer->tx_buf) {
		if (xfer->bits_per_word > 8)
			td0 = *words++;
		else
			td0 = *bytes++;
		} else {
			td0 = 0;
		}

		spi_writew(as, TDR, td0);
		num_data--;
@@ -750,24 +733,14 @@ static int atmel_spi_next_xfer_dma_submit(struct spi_master *master,

	/* prepare the RX dma transfer */
	sg_init_table(&as->dma.sgrx, 1);
	if (xfer->rx_buf) {
	as->dma.sgrx.dma_address = xfer->rx_dma + xfer->len - *plen;
	} else {
		as->dma.sgrx.dma_address = as->buffer_dma;
		if (len > BUFFER_SIZE)
			len = BUFFER_SIZE;
	}

	/* prepare the TX dma transfer */
	sg_init_table(&as->dma.sgtx, 1);
	if (xfer->tx_buf) {
	as->dma.sgtx.dma_address = xfer->tx_dma + xfer->len - *plen;
	} else {
		as->dma.sgtx.dma_address = as->buffer_dma;
		if (len > BUFFER_SIZE)
			len = BUFFER_SIZE;
		memset(as->buffer, 0, len);
	}

	if (len > master->max_dma_len)
		len = master->max_dma_len;

	sg_dma_len(&as->dma.sgtx) = len;
	sg_dma_len(&as->dma.sgrx) = len;
@@ -834,25 +807,10 @@ static void atmel_spi_next_xfer_data(struct spi_master *master,
	struct atmel_spi	*as = spi_master_get_devdata(master);
	u32			len = *plen;

	/* use scratch buffer only when rx or tx data is unspecified */
	if (xfer->rx_buf)
	*rx_dma = xfer->rx_dma + xfer->len - *plen;
	else {
		*rx_dma = as->buffer_dma;
		if (len > BUFFER_SIZE)
			len = BUFFER_SIZE;
	}

	if (xfer->tx_buf)
	*tx_dma = xfer->tx_dma + xfer->len - *plen;
	else {
		*tx_dma = as->buffer_dma;
		if (len > BUFFER_SIZE)
			len = BUFFER_SIZE;
		memset(as->buffer, 0, len);
		dma_sync_single_for_device(&as->pdev->dev,
				as->buffer_dma, len, DMA_TO_DEVICE);
	}
	if (len > master->max_dma_len)
		len = master->max_dma_len;

	*plen = len;
}
@@ -1026,7 +984,6 @@ atmel_spi_pump_single_data(struct atmel_spi *as, struct spi_transfer *xfer)
	u16		*rxp16;
	unsigned long	xfer_pos = xfer->len - as->current_remaining_bytes;

	if (xfer->rx_buf) {
	if (xfer->bits_per_word > 8) {
		rxp16 = (u16 *)(((u8 *)xfer->rx_buf) + xfer_pos);
		*rxp16 = spi_readl(as, RDR);
@@ -1034,9 +991,6 @@ atmel_spi_pump_single_data(struct atmel_spi *as, struct spi_transfer *xfer)
		rxp = ((u8 *)xfer->rx_buf) + xfer_pos;
		*rxp = spi_readl(as, RDR);
	}
	} else {
		spi_readl(as, RDR);
	}
	if (xfer->bits_per_word > 8) {
		if (as->current_remaining_bytes > 2)
			as->current_remaining_bytes -= 2;
@@ -1074,12 +1028,10 @@ atmel_spi_pump_fifo_data(struct atmel_spi *as, struct spi_transfer *xfer)
	/* Read data */
	while (num_data) {
		rd = spi_readl(as, RDR);
		if (xfer->rx_buf) {
		if (xfer->bits_per_word > 8)
			*words++ = rd;
		else
			*bytes++ = rd;
		}
		num_data--;
	}
}
@@ -1561,29 +1513,22 @@ static int atmel_spi_probe(struct platform_device *pdev)
	master->bus_num = pdev->id;
	master->num_chipselect = master->dev.of_node ? 0 : 4;
	master->setup = atmel_spi_setup;
	master->flags = (SPI_MASTER_MUST_RX | SPI_MASTER_MUST_TX);
	master->transfer_one_message = atmel_spi_transfer_one_message;
	master->cleanup = atmel_spi_cleanup;
	master->auto_runtime_pm = true;
	master->max_dma_len = SPI_MAX_DMA_XFER;
	platform_set_drvdata(pdev, master);

	as = spi_master_get_devdata(master);

	/*
	 * Scratch buffer is used for throwaway rx and tx data.
	 * It's coherent to minimize dcache pollution.
	 */
	as->buffer = dma_alloc_coherent(&pdev->dev, BUFFER_SIZE,
					&as->buffer_dma, GFP_KERNEL);
	if (!as->buffer)
		goto out_free;

	spin_lock_init(&as->lock);

	as->pdev = pdev;
	as->regs = devm_ioremap_resource(&pdev->dev, regs);
	if (IS_ERR(as->regs)) {
		ret = PTR_ERR(as->regs);
		goto out_free_buffer;
		goto out_unmap_regs;
	}
	as->phybase = regs->start;
	as->irq = irq;
@@ -1681,9 +1626,6 @@ static int atmel_spi_probe(struct platform_device *pdev)
	clk_disable_unprepare(clk);
out_free_irq:
out_unmap_regs:
out_free_buffer:
	dma_free_coherent(&pdev->dev, BUFFER_SIZE, as->buffer,
			as->buffer_dma);
out_free:
	spi_master_put(master);
	return ret;
@@ -1708,9 +1650,6 @@ static int atmel_spi_remove(struct platform_device *pdev)
	spi_readl(as, SR);
	spin_unlock_irq(&as->lock);

	dma_free_coherent(&pdev->dev, BUFFER_SIZE, as->buffer,
			as->buffer_dma);

	clk_disable_unprepare(as->clk);

	pm_runtime_put_noidle(&pdev->dev);