spi: dw: Detach SPI device specific CR0 config method
authorSerge Semin <Sergey.Semin@baikalelectronics.ru>
Wed, 7 Oct 2020 23:54:52 +0000 (02:54 +0300)
committerMark Brown <broonie@kernel.org>
Thu, 8 Oct 2020 22:00:07 +0000 (23:00 +0100)
Indeed there is no point in detecting the SPI peripheral device parameters
and initializing the CR0 register fields each time an SPI transfer is
executed. Instead let's define a dedicated CR0 chip-data member, which
will be initialized in accordance with the SPI device settings at the
moment of setting it up.

By doing so we'll finally make the SPI device chip_data serving as it's
supposed to - to preserve the SPI device specific DW SPI configuration.
See spi-fsl-dspi.c, spi-pl022.c, spi-pxa2xx.c drivers for example of the
way the chip data is utilized.

Signed-off-by: Serge Semin <Sergey.Semin@baikalelectronics.ru>
Link: https://lore.kernel.org/r/20201007235511.4935-4-Sergey.Semin@baikalelectronics.ru
Signed-off-by: Mark Brown <broonie@kernel.org>
drivers/spi/spi-dw-core.c

index be16fda..f7a2d19 100644 (file)
@@ -27,6 +27,7 @@ struct chip_data {
        u16 clk_div;            /* baud rate divider */
        u32 speed_hz;           /* baud rate */
 
+       u32 cr0;
        u32 rx_sample_dly;      /* RX sample delay */
 };
 
@@ -228,14 +229,9 @@ static irqreturn_t dw_spi_irq(int irq, void *dev_id)
        return dws->transfer_handler(dws);
 }
 
-static void dw_spi_update_cr0(struct dw_spi *dws, struct spi_device *spi,
-                             struct spi_transfer *transfer)
+static u32 dw_spi_prepare_cr0(struct dw_spi *dws, struct spi_device *spi)
 {
-       struct chip_data *chip = spi_get_ctldata(spi);
-       u32 cr0;
-
-       /* CTRLR0[ 4/3: 0] Data Frame Size */
-       cr0 = (transfer->bits_per_word - 1);
+       u32 cr0 = 0;
 
        if (!(dws->caps & DW_SPI_CAP_DWC_SSI)) {
                /* CTRLR0[ 5: 4] Frame Format */
@@ -251,9 +247,6 @@ static void dw_spi_update_cr0(struct dw_spi *dws, struct spi_device *spi,
 
                /* CTRLR0[11] Shift Register Loop */
                cr0 |= ((spi->mode & SPI_LOOP) ? 1 : 0) << SPI_SRL_OFFSET;
-
-               /* CTRLR0[ 9:8] Transfer Mode */
-               cr0 |= chip->tmode << SPI_TMOD_OFFSET;
        } else {
                /* CTRLR0[ 7: 6] Frame Format */
                cr0 |= SSI_MOTO_SPI << DWC_SSI_CTRLR0_FRF_OFFSET;
@@ -269,13 +262,29 @@ static void dw_spi_update_cr0(struct dw_spi *dws, struct spi_device *spi,
                /* CTRLR0[13] Shift Register Loop */
                cr0 |= ((spi->mode & SPI_LOOP) ? 1 : 0) << DWC_SSI_CTRLR0_SRL_OFFSET;
 
-               /* CTRLR0[11:10] Transfer Mode */
-               cr0 |= chip->tmode << DWC_SSI_CTRLR0_TMOD_OFFSET;
-
                if (dws->caps & DW_SPI_CAP_KEEMBAY_MST)
                        cr0 |= DWC_SSI_CTRLR0_KEEMBAY_MST;
        }
 
+       return cr0;
+}
+
+static void dw_spi_update_cr0(struct dw_spi *dws, struct spi_device *spi,
+                             struct spi_transfer *transfer)
+{
+       struct chip_data *chip = spi_get_ctldata(spi);
+       u32 cr0 = chip->cr0;
+
+       /* CTRLR0[ 4/3: 0] Data Frame Size */
+       cr0 |= (transfer->bits_per_word - 1);
+
+       if (!(dws->caps & DW_SPI_CAP_DWC_SSI))
+               /* CTRLR0[ 9:8] Transfer Mode */
+               cr0 |= chip->tmode << SPI_TMOD_OFFSET;
+       else
+               /* CTRLR0[11:10] Transfer Mode */
+               cr0 |= chip->tmode << DWC_SSI_CTRLR0_TMOD_OFFSET;
+
        dw_writel(dws, DW_SPI_CTRLR0, cr0);
 }
 
@@ -373,6 +382,7 @@ static void dw_spi_handle_err(struct spi_controller *master,
 /* This may be called twice for each spi dev */
 static int dw_spi_setup(struct spi_device *spi)
 {
+       struct dw_spi *dws = spi_controller_get_devdata(spi->controller);
        struct chip_data *chip;
 
        /* Only alloc on first setup */
@@ -396,6 +406,13 @@ static int dw_spi_setup(struct spi_device *spi)
                                                        dws->max_freq);
        }
 
+       /*
+        * Update CR0 data each time the setup callback is invoked since
+        * the device parameters could have been changed, for instance, by
+        * the MMC SPI driver or something else.
+        */
+       chip->cr0 = dw_spi_prepare_cr0(dws, spi);
+
        chip->tmode = SPI_TMOD_TR;
 
        return 0;