Unverified Commit bac70b54 authored by Lars Povlsen's avatar Lars Povlsen Committed by Mark Brown
Browse files

spi: dw: Add support for RX sample delay register



This add support for the RX_SAMPLE_DLY register. If enabled in the
Designware IP, it allows tuning of the rx data signal by means of an
internal rx sample fifo.

The register is controlled by the rx-sample-delay-ns DT property,
which is defined per SPI slave as well on controller level.

The controller level rx-sample-delay-ns will apply to all slaves
without the property explicitly defined.

The register is located at offset 0xf0, and if the option is not
enabled in the IP, changing the register will have no effect. The
register will only be written if any slave defines a nonzero value
(after scaling by the clock period).

Signed-off-by: default avatarLars Povlsen <lars.povlsen@microchip.com>
Link: https://lore.kernel.org/r/20200824203010.2033-2-lars.povlsen@microchip.com


Signed-off-by: default avatarMark Brown <broonie@kernel.org>
parent 2abaad67
Loading
Loading
Loading
Loading
+26 −0
Original line number Original line Diff line number Diff line
@@ -12,6 +12,7 @@
#include <linux/delay.h>
#include <linux/delay.h>
#include <linux/slab.h>
#include <linux/slab.h>
#include <linux/spi/spi.h>
#include <linux/spi/spi.h>
#include <linux/of.h>


#include "spi-dw.h"
#include "spi-dw.h"


@@ -26,6 +27,8 @@ struct chip_data {


	u16 clk_div;		/* baud rate divider */
	u16 clk_div;		/* baud rate divider */
	u32 speed_hz;		/* baud rate */
	u32 speed_hz;		/* baud rate */

	u32 rx_sample_dly;	/* RX sample delay */
};
};


#ifdef CONFIG_DEBUG_FS
#ifdef CONFIG_DEBUG_FS
@@ -52,6 +55,7 @@ static const struct debugfs_reg32 dw_spi_dbgfs_regs[] = {
	DW_SPI_DBGFS_REG("DMACR", DW_SPI_DMACR),
	DW_SPI_DBGFS_REG("DMACR", DW_SPI_DMACR),
	DW_SPI_DBGFS_REG("DMATDLR", DW_SPI_DMATDLR),
	DW_SPI_DBGFS_REG("DMATDLR", DW_SPI_DMATDLR),
	DW_SPI_DBGFS_REG("DMARDLR", DW_SPI_DMARDLR),
	DW_SPI_DBGFS_REG("DMARDLR", DW_SPI_DMARDLR),
	DW_SPI_DBGFS_REG("RX_SAMPLE_DLY", DW_SPI_RX_SAMPLE_DLY),
};
};


static int dw_spi_debugfs_init(struct dw_spi *dws)
static int dw_spi_debugfs_init(struct dw_spi *dws)
@@ -328,6 +332,12 @@ static int dw_spi_transfer_one(struct spi_controller *master,
	if (master->can_dma && master->can_dma(master, spi, transfer))
	if (master->can_dma && master->can_dma(master, spi, transfer))
		dws->dma_mapped = master->cur_msg_mapped;
		dws->dma_mapped = master->cur_msg_mapped;


	/* Update RX sample delay if required */
	if (dws->cur_rx_sample_dly != chip->rx_sample_dly) {
		dw_writel(dws, DW_SPI_RX_SAMPLE_DLY, chip->rx_sample_dly);
		dws->cur_rx_sample_dly = chip->rx_sample_dly;
	}

	/* For poll mode just disable all interrupts */
	/* For poll mode just disable all interrupts */
	spi_mask_intr(dws, 0xff);
	spi_mask_intr(dws, 0xff);


@@ -380,10 +390,22 @@ static int dw_spi_setup(struct spi_device *spi)
	/* Only alloc on first setup */
	/* Only alloc on first setup */
	chip = spi_get_ctldata(spi);
	chip = spi_get_ctldata(spi);
	if (!chip) {
	if (!chip) {
		struct dw_spi *dws = spi_controller_get_devdata(spi->controller);
		u32 rx_sample_dly_ns;

		chip = kzalloc(sizeof(struct chip_data), GFP_KERNEL);
		chip = kzalloc(sizeof(struct chip_data), GFP_KERNEL);
		if (!chip)
		if (!chip)
			return -ENOMEM;
			return -ENOMEM;
		spi_set_ctldata(spi, chip);
		spi_set_ctldata(spi, chip);
		/* Get specific / default rx-sample-delay */
		if (device_property_read_u32(&spi->dev,
					     "rx-sample-delay-ns",
					     &rx_sample_dly_ns) != 0)
			/* Use default controller value */
			rx_sample_dly_ns = dws->def_rx_sample_dly_ns;
		chip->rx_sample_dly = DIV_ROUND_CLOSEST(rx_sample_dly_ns,
							NSEC_PER_SEC /
							dws->max_freq);
	}
	}


	chip->tmode = SPI_TMOD_TR;
	chip->tmode = SPI_TMOD_TR;
@@ -472,6 +494,10 @@ int dw_spi_add_host(struct device *dev, struct dw_spi *dws)
	if (dws->set_cs)
	if (dws->set_cs)
		master->set_cs = dws->set_cs;
		master->set_cs = dws->set_cs;


	/* Get default rx sample delay */
	device_property_read_u32(dev, "rx-sample-delay-ns",
				 &dws->def_rx_sample_dly_ns);

	/* Basic HW init */
	/* Basic HW init */
	spi_hw_init(dev, dws);
	spi_hw_init(dev, dws);


+3 −0
Original line number Original line Diff line number Diff line
@@ -34,6 +34,7 @@
#define DW_SPI_IDR			0x58
#define DW_SPI_IDR			0x58
#define DW_SPI_VERSION			0x5c
#define DW_SPI_VERSION			0x5c
#define DW_SPI_DR			0x60
#define DW_SPI_DR			0x60
#define DW_SPI_RX_SAMPLE_DLY		0xf0
#define DW_SPI_CS_OVERRIDE		0xf4
#define DW_SPI_CS_OVERRIDE		0xf4


/* Bit fields in CTRLR0 */
/* Bit fields in CTRLR0 */
@@ -140,6 +141,8 @@ struct dw_spi {
	u8			n_bytes;	/* current is a 1/2 bytes op */
	u8			n_bytes;	/* current is a 1/2 bytes op */
	irqreturn_t		(*transfer_handler)(struct dw_spi *dws);
	irqreturn_t		(*transfer_handler)(struct dw_spi *dws);
	u32			current_freq;	/* frequency in hz */
	u32			current_freq;	/* frequency in hz */
	u32			cur_rx_sample_dly;
	u32			def_rx_sample_dly_ns;


	/* DMA info */
	/* DMA info */
	struct dma_chan		*txchan;
	struct dma_chan		*txchan;