spi: tegra114: add support for interrupt mask
authorSowjanya Komatineni <skomatineni@nvidia.com>
Fri, 5 Apr 2019 00:14:12 +0000 (17:14 -0700)
committerMark Brown <broonie@kernel.org>
Mon, 8 Apr 2019 07:13:06 +0000 (14:13 +0700)
This patch creates tegra_spi_soc_data structure to maintain and implement
SPI HW feature differences between different Tegra chips and also creates
a separate compatible string for T124/T210.

Tegra210 and later has a separate interrupt mask register SPI_INTR_MASK
for enabling or disabling interrupts while Tegra124 and prior uses
interrupt enable bits in SPI_DMA_CTL register.

This patch creates flag has_intr_mask_reg in tegra_spi_soc_data to
identify this and implements accordingly.

Signed-off-by: Sowjanya Komatineni <skomatineni@nvidia.com>
Signed-off-by: Mark Brown <broonie@kernel.org>
drivers/spi/spi-tegra114.c

index 751672b3bc16a4bae6fbb6d0efa5142fb4abf20e..b8c6393e219019b13f7387c9f6af48c77e19a06c 100644 (file)
 
 #define SPI_TX_FIFO                            0x108
 #define SPI_RX_FIFO                            0x188
+#define SPI_INTR_MASK                          0x18c
+#define SPI_INTR_ALL_MASK                      (0x1fUL << 25)
 #define MAX_CHIP_SELECT                                4
 #define SPI_FIFO_DEPTH                         64
 #define DATA_DIR_TX                            (1 << 0)
 #define MAX_HOLD_CYCLES                                16
 #define SPI_DEFAULT_SPEED                      25000000
 
+struct tegra_spi_soc_data {
+       bool has_intr_mask_reg;
+};
+
 struct tegra_spi_data {
        struct device                           *dev;
        struct spi_master                       *master;
@@ -211,6 +217,7 @@ struct tegra_spi_data {
        u32                                     *tx_dma_buf;
        dma_addr_t                              tx_dma_phys;
        struct dma_async_tx_descriptor          *tx_dma_desc;
+       const struct tegra_spi_soc_data         *soc_data;
 };
 
 static int tegra_spi_runtime_suspend(struct device *dev);
@@ -554,11 +561,13 @@ static int tegra_spi_start_dma_based_transfer(
                dma_burst = 8;
        }
 
-       if (tspi->cur_direction & DATA_DIR_TX)
-               val |= SPI_IE_TX;
+       if (!tspi->soc_data->has_intr_mask_reg) {
+               if (tspi->cur_direction & DATA_DIR_TX)
+                       val |= SPI_IE_TX;
 
-       if (tspi->cur_direction & DATA_DIR_RX)
-               val |= SPI_IE_RX;
+               if (tspi->cur_direction & DATA_DIR_RX)
+                       val |= SPI_IE_RX;
+       }
 
        tegra_spi_writel(tspi, val, SPI_DMA_CTL);
        tspi->dma_control_reg = val;
@@ -847,6 +856,12 @@ static int tegra_spi_setup(struct spi_device *spi)
                return ret;
        }
 
+       if (tspi->soc_data->has_intr_mask_reg) {
+               val = tegra_spi_readl(tspi, SPI_INTR_MASK);
+               val &= ~SPI_INTR_ALL_MASK;
+               tegra_spi_writel(tspi, val, SPI_INTR_MASK);
+       }
+
        spin_lock_irqsave(&tspi->lock, flags);
        val = tspi->def_command1_reg;
        if (spi->mode & SPI_CS_HIGH)
@@ -1135,8 +1150,29 @@ static irqreturn_t tegra_spi_isr(int irq, void *context_data)
        return IRQ_WAKE_THREAD;
 }
 
+static struct tegra_spi_soc_data tegra114_spi_soc_data = {
+       .has_intr_mask_reg = false,
+};
+
+static struct tegra_spi_soc_data tegra124_spi_soc_data = {
+       .has_intr_mask_reg = false,
+};
+
+static struct tegra_spi_soc_data tegra210_spi_soc_data = {
+       .has_intr_mask_reg = true,
+};
+
 static const struct of_device_id tegra_spi_of_match[] = {
-       { .compatible = "nvidia,tegra114-spi", },
+       {
+               .compatible = "nvidia,tegra114-spi",
+               .data       = &tegra114_spi_soc_data,
+       }, {
+               .compatible = "nvidia,tegra124-spi",
+               .data       = &tegra124_spi_soc_data,
+       }, {
+               .compatible = "nvidia,tegra210-spi",
+               .data       = &tegra210_spi_soc_data,
+       },
        {}
 };
 MODULE_DEVICE_TABLE(of, tegra_spi_of_match);
@@ -1177,6 +1213,13 @@ static int tegra_spi_probe(struct platform_device *pdev)
        tspi->dev = &pdev->dev;
        spin_lock_init(&tspi->lock);
 
+       tspi->soc_data = of_device_get_match_data(&pdev->dev);
+       if (!tspi->soc_data) {
+               dev_err(&pdev->dev, "unsupported tegra\n");
+               ret = -ENODEV;
+               goto exit_free_master;
+       }
+
        r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
        tspi->base = devm_ioremap_resource(&pdev->dev, r);
        if (IS_ERR(tspi->base)) {