Merge branch 'spi-5.2' into spi-next
This commit is contained in:
@@ -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)) {
|
||||
|
Reference in New Issue
Block a user