summaryrefslogtreecommitdiffstats
path: root/drivers/spi/spi-sun6i.c
diff options
context:
space:
mode:
authorMaksim Kiselev <bigunclemax@gmail.com>2023-06-24 16:16:22 +0300
committerMark Brown <broonie@kernel.org>2023-07-09 22:51:26 +0100
commit0605d9fb411f3337482976842a3901d6c125d298 (patch)
tree0e414a88216c7a7cc3e68a8f032e2cd21fd6a106 /drivers/spi/spi-sun6i.c
parent06c2afb862f9da8dc5efa4b6076a0e48c3fbaaa5 (diff)
downloadlinux-stable-0605d9fb411f3337482976842a3901d6c125d298.tar.gz
linux-stable-0605d9fb411f3337482976842a3901d6c125d298.tar.bz2
linux-stable-0605d9fb411f3337482976842a3901d6c125d298.zip
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: Maksim Kiselev <bigunclemax@gmail.com> Link: https://lore.kernel.org/r/20230624131632.2972546-2-bigunclemax@gmail.com Signed-off-by: Mark Brown <broonie@kernel.org>
Diffstat (limited to 'drivers/spi/spi-sun6i.c')
-rw-r--r--drivers/spi/spi-sun6i.c29
1 files changed, 25 insertions, 4 deletions
diff --git a/drivers/spi/spi-sun6i.c b/drivers/spi/spi-sun6i.c
index 30d541612253..cec2747235ab 100644
--- a/drivers/spi/spi-sun6i.c
+++ b/drivers/spi/spi-sun6i.c
@@ -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;