diff options
author | Mark Brown <broonie@kernel.org> | 2019-05-02 04:20:29 +0200 |
---|---|---|
committer | Mark Brown <broonie@kernel.org> | 2019-05-02 04:20:29 +0200 |
commit | 2e5f081003f033d37be3faf052aaccc8b6a44aa5 (patch) | |
tree | 6d07a9bfff47b20f997ecce96162b8ca9cf7b19c /drivers/spi/spi-tegra114.c | |
parent | Merge branch 'spi-5.1' into spi-linus (diff) | |
parent | spi: Clear SPI_CS_HIGH flag from bad_bits for GPIO chip-select (diff) | |
download | linux-2e5f081003f033d37be3faf052aaccc8b6a44aa5.tar.xz linux-2e5f081003f033d37be3faf052aaccc8b6a44aa5.zip |
Merge branch 'spi-5.2' into spi-next
Diffstat (limited to 'drivers/spi/spi-tegra114.c')
-rw-r--r-- | drivers/spi/spi-tegra114.c | 97 |
1 files changed, 90 insertions, 7 deletions
diff --git a/drivers/spi/spi-tegra114.c b/drivers/spi/spi-tegra114.c index 21e4fdad013f..b1f31bb16659 100644 --- a/drivers/spi/spi-tegra114.c +++ b/drivers/spi/spi-tegra114.c @@ -149,6 +149,8 @@ #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) @@ -161,6 +163,10 @@ #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); @@ -259,7 +266,8 @@ static unsigned tegra_spi_calculate_curr_xfer_param( tspi->bytes_per_word = DIV_ROUND_UP(bits_per_word, 8); - if (bits_per_word == 8 || bits_per_word == 16) { + if ((bits_per_word == 8 || bits_per_word == 16 || + bits_per_word == 32) && t->len > 3) { tspi->is_packed = 1; tspi->words_per_32bit = 32/bits_per_word; } else { @@ -553,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; @@ -749,6 +759,16 @@ static u32 tegra_spi_setup_transfer_one(struct spi_device *spi, else if (req_mode == SPI_MODE_3) command1 |= SPI_CONTROL_MODE_3; + if (spi->mode & SPI_LSB_FIRST) + command1 |= SPI_LSBIT_FE; + else + command1 &= ~SPI_LSBIT_FE; + + if (spi->mode & SPI_3WIRE) + command1 |= SPI_BIDIROE; + else + command1 &= ~SPI_BIDIROE; + if (tspi->cs_control) { if (tspi->cs_control != spi) tegra_spi_writel(tspi, command1, SPI_COMMAND1); @@ -781,6 +801,11 @@ static int tegra_spi_start_transfer_one(struct spi_device *spi, total_fifo_words = tegra_spi_calculate_curr_xfer_param(spi, tspi, t); + if (t->rx_nbits == SPI_NBITS_DUAL || t->tx_nbits == SPI_NBITS_DUAL) + command1 |= SPI_BOTH_EN_BIT; + else + command1 &= ~SPI_BOTH_EN_BIT; + if (tspi->is_packed) command1 |= SPI_PACKED; else @@ -832,6 +857,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) @@ -870,6 +901,20 @@ static void tegra_spi_transfer_end(struct spi_device *spi) tegra_spi_writel(tspi, tspi->def_command1_reg, SPI_COMMAND1); } +static void tegra_spi_dump_regs(struct tegra_spi_data *tspi) +{ + dev_dbg(tspi->dev, "============ SPI REGISTER DUMP ============\n"); + dev_dbg(tspi->dev, "Command1: 0x%08x | Command2: 0x%08x\n", + tegra_spi_readl(tspi, SPI_COMMAND1), + tegra_spi_readl(tspi, SPI_COMMAND2)); + dev_dbg(tspi->dev, "DMA_CTL: 0x%08x | DMA_BLK: 0x%08x\n", + tegra_spi_readl(tspi, SPI_DMA_CTL), + tegra_spi_readl(tspi, SPI_DMA_BLK)); + dev_dbg(tspi->dev, "TRANS_STAT: 0x%08x | FIFO_STATUS: 0x%08x\n", + tegra_spi_readl(tspi, SPI_TRANS_STATUS), + tegra_spi_readl(tspi, SPI_FIFO_STATUS)); +} + static int tegra_spi_transfer_one_message(struct spi_master *master, struct spi_message *msg) { @@ -916,6 +961,7 @@ static int tegra_spi_transfer_one_message(struct spi_master *master, (tspi->cur_direction & DATA_DIR_RX)) dmaengine_terminate_all(tspi->rx_dma_chan); ret = -EIO; + tegra_spi_dump_regs(tspi); tegra_spi_flush_fifos(tspi); reset_control_assert(tspi->rst); udelay(2); @@ -926,6 +972,7 @@ static int tegra_spi_transfer_one_message(struct spi_master *master, if (tspi->tx_status || tspi->rx_status) { dev_err(tspi->dev, "Error in Transfer\n"); ret = -EIO; + tegra_spi_dump_regs(tspi); goto complete_xfer; } msg->actual_length += xfer->len; @@ -967,6 +1014,7 @@ static irqreturn_t handle_cpu_based_xfer(struct tegra_spi_data *tspi) tspi->status_reg); dev_err(tspi->dev, "CpuXfer 0x%08x:0x%08x\n", tspi->command1_reg, tspi->dma_control_reg); + tegra_spi_dump_regs(tspi); tegra_spi_flush_fifos(tspi); complete(&tspi->xfer_completion); spin_unlock_irqrestore(&tspi->lock, flags); @@ -1041,6 +1089,7 @@ static irqreturn_t handle_dma_based_xfer(struct tegra_spi_data *tspi) tspi->status_reg); dev_err(tspi->dev, "DmaXfer 0x%08x:0x%08x\n", tspi->command1_reg, tspi->dma_control_reg); + tegra_spi_dump_regs(tspi); tegra_spi_flush_fifos(tspi); complete(&tspi->xfer_completion); spin_unlock_irqrestore(&tspi->lock, flags); @@ -1102,8 +1151,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); @@ -1114,6 +1184,7 @@ static int tegra_spi_probe(struct platform_device *pdev) struct tegra_spi_data *tspi; struct resource *r; int ret, spi_irq; + int bus_num; master = spi_alloc_master(&pdev->dev, sizeof(*tspi)); if (!master) { @@ -1128,16 +1199,28 @@ static int tegra_spi_probe(struct platform_device *pdev) master->max_speed_hz = 25000000; /* 25MHz */ /* the spi->mode bits understood by this driver: */ - master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH; + master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH | SPI_LSB_FIRST | + SPI_TX_DUAL | SPI_RX_DUAL | SPI_3WIRE; + master->bits_per_word_mask = SPI_BPW_RANGE_MASK(4, 32); master->setup = tegra_spi_setup; master->transfer_one_message = tegra_spi_transfer_one_message; master->num_chipselect = MAX_CHIP_SELECT; master->auto_runtime_pm = true; + bus_num = of_alias_get_id(pdev->dev.of_node, "spi"); + if (bus_num >= 0) + master->bus_num = bus_num; tspi->master = master; 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)) { |