Unverified Commit 0605d9fb authored by Maksim Kiselev's avatar Maksim Kiselev Committed by Mark Brown
Browse files

spi: sun6i: add quirk for dual and quad SPI modes support



New Allwinner's SPI controllers can support dual and quad SPI modes.
To enable one of these modes, we should set the corresponding bit in
the SUN6I_BURST_CTL_CNT_REG register. DRM (28 bits) for dual mode and
Quad_EN (29 bits) for quad transmission.

Signed-off-by: default avatarMaksim Kiselev <bigunclemax@gmail.com>
Link: https://lore.kernel.org/r/20230624131632.2972546-2-bigunclemax@gmail.com


Signed-off-by: default avatarMark Brown <broonie@kernel.org>
parent 06c2afb8
Loading
Loading
Loading
Loading
+25 −4
Original line number Diff line number Diff line
@@ -83,6 +83,9 @@
#define SUN6I_XMIT_CNT_REG		0x34

#define SUN6I_BURST_CTL_CNT_REG		0x38
#define SUN6I_BURST_CTL_CNT_STC_MASK		GENMASK(23, 0)
#define SUN6I_BURST_CTL_CNT_DRM			BIT(28)
#define SUN6I_BURST_CTL_CNT_QUAD_EN		BIT(29)

#define SUN6I_TXDATA_REG		0x200
#define SUN6I_RXDATA_REG		0x300
@@ -90,6 +93,7 @@
struct sun6i_spi_cfg {
	unsigned long		fifo_depth;
	bool			has_clk_ctl;
	u32			mode_bits;
};

struct sun6i_spi {
@@ -266,7 +270,7 @@ static int sun6i_spi_transfer_one(struct spi_master *master,
	unsigned int div, div_cdr1, div_cdr2, timeout;
	unsigned int start, end, tx_time;
	unsigned int trig_level;
	unsigned int tx_len = 0, rx_len = 0;
	unsigned int tx_len = 0, rx_len = 0, nbits = 0;
	bool use_dma;
	int ret = 0;
	u32 reg;
@@ -418,13 +422,29 @@ static int sun6i_spi_transfer_one(struct spi_master *master,
	sun6i_spi_write(sspi, SUN6I_GBL_CTL_REG, reg);

	/* Setup the transfer now... */
	if (sspi->tx_buf)
	if (sspi->tx_buf) {
		tx_len = tfr->len;
		nbits = tfr->tx_nbits;
	} else if (tfr->rx_buf) {
		nbits = tfr->rx_nbits;
	}

	switch (nbits) {
	case SPI_NBITS_DUAL:
		reg = SUN6I_BURST_CTL_CNT_DRM;
		break;
	case SPI_NBITS_QUAD:
		reg = SUN6I_BURST_CTL_CNT_QUAD_EN;
		break;
	case SPI_NBITS_SINGLE:
	default:
		reg = FIELD_PREP(SUN6I_BURST_CTL_CNT_STC_MASK, tx_len);
	}

	/* Setup the counters */
	sun6i_spi_write(sspi, SUN6I_BURST_CTL_CNT_REG, reg);
	sun6i_spi_write(sspi, SUN6I_BURST_CNT_REG, tfr->len);
	sun6i_spi_write(sspi, SUN6I_XMIT_CNT_REG, tx_len);
	sun6i_spi_write(sspi, SUN6I_BURST_CTL_CNT_REG, tx_len);

	if (!use_dma) {
		/* Fill the TX FIFO */
@@ -623,7 +643,8 @@ static int sun6i_spi_probe(struct platform_device *pdev)
	master->set_cs = sun6i_spi_set_cs;
	master->transfer_one = sun6i_spi_transfer_one;
	master->num_chipselect = 4;
	master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH | SPI_LSB_FIRST;
	master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH | SPI_LSB_FIRST |
			    sspi->cfg->mode_bits;
	master->bits_per_word_mask = SPI_BPW_MASK(8);
	master->dev.of_node = pdev->dev.of_node;
	master->auto_runtime_pm = true;