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

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.comSigned-off-by: default avatarMark Brown <broonie@kernel.org>
parent 06c2afb8
...@@ -83,6 +83,9 @@ ...@@ -83,6 +83,9 @@
#define SUN6I_XMIT_CNT_REG 0x34 #define SUN6I_XMIT_CNT_REG 0x34
#define SUN6I_BURST_CTL_CNT_REG 0x38 #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_TXDATA_REG 0x200
#define SUN6I_RXDATA_REG 0x300 #define SUN6I_RXDATA_REG 0x300
...@@ -90,6 +93,7 @@ ...@@ -90,6 +93,7 @@
struct sun6i_spi_cfg { struct sun6i_spi_cfg {
unsigned long fifo_depth; unsigned long fifo_depth;
bool has_clk_ctl; bool has_clk_ctl;
u32 mode_bits;
}; };
struct sun6i_spi { struct sun6i_spi {
...@@ -266,7 +270,7 @@ static int sun6i_spi_transfer_one(struct spi_master *master, ...@@ -266,7 +270,7 @@ static int sun6i_spi_transfer_one(struct spi_master *master,
unsigned int div, div_cdr1, div_cdr2, timeout; unsigned int div, div_cdr1, div_cdr2, timeout;
unsigned int start, end, tx_time; unsigned int start, end, tx_time;
unsigned int trig_level; 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; bool use_dma;
int ret = 0; int ret = 0;
u32 reg; u32 reg;
...@@ -418,13 +422,29 @@ static int sun6i_spi_transfer_one(struct spi_master *master, ...@@ -418,13 +422,29 @@ static int sun6i_spi_transfer_one(struct spi_master *master,
sun6i_spi_write(sspi, SUN6I_GBL_CTL_REG, reg); sun6i_spi_write(sspi, SUN6I_GBL_CTL_REG, reg);
/* Setup the transfer now... */ /* Setup the transfer now... */
if (sspi->tx_buf) if (sspi->tx_buf) {
tx_len = tfr->len; 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 */ /* 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_BURST_CNT_REG, tfr->len);
sun6i_spi_write(sspi, SUN6I_XMIT_CNT_REG, tx_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) { if (!use_dma) {
/* Fill the TX FIFO */ /* Fill the TX FIFO */
...@@ -623,7 +643,8 @@ static int sun6i_spi_probe(struct platform_device *pdev) ...@@ -623,7 +643,8 @@ static int sun6i_spi_probe(struct platform_device *pdev)
master->set_cs = sun6i_spi_set_cs; master->set_cs = sun6i_spi_set_cs;
master->transfer_one = sun6i_spi_transfer_one; master->transfer_one = sun6i_spi_transfer_one;
master->num_chipselect = 4; 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->bits_per_word_mask = SPI_BPW_MASK(8);
master->dev.of_node = pdev->dev.of_node; master->dev.of_node = pdev->dev.of_node;
master->auto_runtime_pm = true; master->auto_runtime_pm = true;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment