This patch fixes PIO mode transfer to use PIO bit in SPI_COMMAND1 register.
Current driver uses DMA_EN instead of PIO bit.
Signed-off-by: Sowjanya Komatineni <[email protected]>
---
drivers/spi/spi-tegra114.c | 5 +++--
1 file changed, 3 insertions(+), 2 deletions(-)
diff --git a/drivers/spi/spi-tegra114.c b/drivers/spi/spi-tegra114.c
index 6bb40e46da91..ba1639310282 100644
--- a/drivers/spi/spi-tegra114.c
+++ b/drivers/spi/spi-tegra114.c
@@ -641,8 +641,9 @@ static int tegra_spi_start_cpu_based_transfer(
tspi->is_curr_dma_xfer = false;
- val |= SPI_DMA_EN;
- tegra_spi_writel(tspi, val, SPI_DMA_CTL);
+ val = tspi->command1_reg;
+ val |= SPI_PIO;
+ tegra_spi_writel(tspi, val, SPI_COMMAND1);
return 0;
}
--
2.7.4
This patch adds 3 wire transfer support to SPI mode list along with
its implementation.
3 wire or Bi-directional mode uses only one serial data pin for the
transfer. SPI in master mode uses MOSI data line only and MISO data
line is not used.
Signed-off-by: Sowjanya Komatineni <[email protected]>
---
drivers/spi/spi-tegra114.c | 7 ++++++-
1 file changed, 6 insertions(+), 1 deletion(-)
diff --git a/drivers/spi/spi-tegra114.c b/drivers/spi/spi-tegra114.c
index 239fb0c8c31f..212bb90aa0cb 100644
--- a/drivers/spi/spi-tegra114.c
+++ b/drivers/spi/spi-tegra114.c
@@ -755,6 +755,11 @@ static u32 tegra_spi_setup_transfer_one(struct spi_device *spi,
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);
@@ -1159,7 +1164,7 @@ static int tegra_spi_probe(struct platform_device *pdev)
/* the spi->mode bits understood by this driver: */
master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH | SPI_LSB_FIRST |
- SPI_TX_DUAL | SPI_RX_DUAL;
+ 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;
--
2.7.4
Tegra SPI controller supports both HW and SW based CS control
for SPI transfers.
This patch adds support for HW based CS control where CS is driven
to active state during the transfer and is driven inactive at the
end of the transfer directly by the HW.
This patch enables the use of HW based CS only for single transfers
without cs_change request.
Signed-off-by: Sowjanya Komatineni <[email protected]>
---
drivers/spi/spi-tegra114.c | 38 ++++++++++++++++++++++++++------------
1 file changed, 26 insertions(+), 12 deletions(-)
diff --git a/drivers/spi/spi-tegra114.c b/drivers/spi/spi-tegra114.c
index 209ec05a349f..5cc347b345b1 100644
--- a/drivers/spi/spi-tegra114.c
+++ b/drivers/spi/spi-tegra114.c
@@ -198,6 +198,7 @@ struct tegra_spi_data {
unsigned dma_buf_size;
unsigned max_buf_size;
bool is_curr_dma_xfer;
+ bool use_hw_based_cs;
struct completion rx_dma_complete;
struct completion tx_dma_complete;
@@ -728,7 +729,8 @@ static void tegra_spi_deinit_dma_param(struct tegra_spi_data *tspi,
}
static u32 tegra_spi_setup_transfer_one(struct spi_device *spi,
- struct spi_transfer *t, bool is_first_of_msg)
+ struct spi_transfer *t, bool is_first_of_msg,
+ bool is_single_xfer)
{
struct tegra_spi_data *tspi = spi_master_get_devdata(spi->master);
struct tegra_spi_client_state *cstate = spi->controller_state;
@@ -787,11 +789,17 @@ static u32 tegra_spi_setup_transfer_one(struct spi_device *spi,
} else
tegra_spi_writel(tspi, command1, SPI_COMMAND1);
- command1 |= SPI_CS_SW_HW;
- if (spi->mode & SPI_CS_HIGH)
- command1 |= SPI_CS_SW_VAL;
- else
- command1 &= ~SPI_CS_SW_VAL;
+ if (is_single_xfer && !(t->cs_change)) {
+ tspi->use_hw_based_cs = true;
+ command1 &= ~(SPI_CS_SW_HW | SPI_CS_SW_VAL);
+ } else {
+ tspi->use_hw_based_cs = false;
+ command1 |= SPI_CS_SW_HW;
+ if (spi->mode & SPI_CS_HIGH)
+ command1 |= SPI_CS_SW_VAL;
+ else
+ command1 &= ~SPI_CS_SW_VAL;
+ }
if (cstate->cs_gpio_valid) {
int val = (spi->mode & SPI_CS_HIGH) ? 1 : 0;
@@ -956,11 +964,14 @@ static void tegra_spi_transfer_end(struct spi_device *spi)
if (cstate->cs_gpio_valid)
gpio_set_value(spi->cs_gpio, cs_val);
- if (cs_val)
- tspi->command1_reg |= SPI_CS_SW_VAL;
- else
- tspi->command1_reg &= ~SPI_CS_SW_VAL;
- tegra_spi_writel(tspi, tspi->command1_reg, SPI_COMMAND1);
+ if (!tspi->use_hw_based_cs) {
+ if (cs_val)
+ tspi->command1_reg |= SPI_CS_SW_VAL;
+ else
+ tspi->command1_reg &= ~SPI_CS_SW_VAL;
+ tegra_spi_writel(tspi, tspi->command1_reg, SPI_COMMAND1);
+ }
+
tegra_spi_writel(tspi, tspi->def_command1_reg, SPI_COMMAND1);
}
@@ -987,16 +998,19 @@ static int tegra_spi_transfer_one_message(struct spi_master *master,
struct spi_device *spi = msg->spi;
int ret;
bool skip = false;
+ int single_xfer;
msg->status = 0;
msg->actual_length = 0;
+ single_xfer = list_is_singular(&msg->transfers);
list_for_each_entry(xfer, &msg->transfers, transfer_list) {
u32 cmd1;
reinit_completion(&tspi->xfer_completion);
- cmd1 = tegra_spi_setup_transfer_one(spi, xfer, is_first_msg);
+ cmd1 = tegra_spi_setup_transfer_one(spi, xfer, is_first_msg,
+ single_xfer);
if (!xfer->len) {
ret = 0;
--
2.7.4
Packed mode expects minimum transfer length of 4 bytes.
This patch fixes this by using unpacked mode for transfers less
than 4 bytes.
Signed-off-by: Sowjanya Komatineni <[email protected]>
---
drivers/spi/spi-tegra114.c | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/drivers/spi/spi-tegra114.c b/drivers/spi/spi-tegra114.c
index ba1639310282..3042521c3785 100644
--- a/drivers/spi/spi-tegra114.c
+++ b/drivers/spi/spi-tegra114.c
@@ -259,7 +259,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 || bits_per_word == 32) {
+ 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 {
--
2.7.4
This patch implements set_cs_timing SPI controller method to allow
SPI client driver to configure device specific SPI CS timings.
Signed-off-by: Sowjanya Komatineni <[email protected]>
---
drivers/spi/spi-tegra114.c | 48 ++++++++++++++++++++++++++++++++++++++++++++--
1 file changed, 46 insertions(+), 2 deletions(-)
diff --git a/drivers/spi/spi-tegra114.c b/drivers/spi/spi-tegra114.c
index 5cc347b345b1..34dee28554ef 100644
--- a/drivers/spi/spi-tegra114.c
+++ b/drivers/spi/spi-tegra114.c
@@ -96,8 +96,10 @@
(reg = (((val) & 0x1) << ((cs) * 8 + 5)) | \
((reg) & ~(1 << ((cs) * 8 + 5))))
#define SPI_SET_CYCLES_BETWEEN_PACKETS(reg, cs, val) \
- (reg = (((val) & 0xF) << ((cs) * 8)) | \
- ((reg) & ~(0xF << ((cs) * 8))))
+ (reg = (((val) & 0x1F) << ((cs) * 8)) | \
+ ((reg) & ~(0x1F << ((cs) * 8))))
+#define MAX_SETUP_HOLD_CYCLES 16
+#define MAX_INACTIVE_CYCLES 32
#define SPI_TRANS_STATUS 0x010
#define SPI_BLK_CNT(val) (((val) >> 0) & 0xFFFF)
@@ -211,6 +213,8 @@ struct tegra_spi_data {
u32 command1_reg;
u32 dma_control_reg;
u32 def_command1_reg;
+ u32 spi_cs_timing1;
+ u32 spi_cs_timing2;
struct completion xfer_completion;
struct spi_transfer *curr_xfer;
@@ -728,6 +732,43 @@ static void tegra_spi_deinit_dma_param(struct tegra_spi_data *tspi,
dma_release_channel(dma_chan);
}
+static void tegra_spi_set_hw_cs_timing(struct spi_device *spi, u8 setup_dly,
+ u8 hold_dly, u8 inactive_dly)
+{
+ struct tegra_spi_data *tspi = spi_master_get_devdata(spi->master);
+ u32 setup_hold;
+ u32 spi_cs_timing;
+ u32 inactive_cycles;
+ u8 cs_state;
+
+ setup_dly = min_t(u8, setup_dly, MAX_SETUP_HOLD_CYCLES);
+ hold_dly = min_t(u8, hold_dly, MAX_SETUP_HOLD_CYCLES);
+ if (setup_dly && hold_dly) {
+ setup_hold = SPI_SETUP_HOLD(setup_dly - 1, hold_dly - 1);
+ spi_cs_timing = SPI_CS_SETUP_HOLD(tspi->spi_cs_timing1,
+ spi->chip_select,
+ setup_hold);
+ if (tspi->spi_cs_timing1 != spi_cs_timing) {
+ tspi->spi_cs_timing1 = spi_cs_timing;
+ tegra_spi_writel(tspi, spi_cs_timing, SPI_CS_TIMING1);
+ }
+ }
+
+ inactive_cycles = min_t(u8, inactive_dly, MAX_INACTIVE_CYCLES);
+ if (inactive_cycles)
+ inactive_cycles--;
+ cs_state = inactive_cycles ? 0 : 1;
+ spi_cs_timing = tspi->spi_cs_timing2;
+ SPI_SET_CS_ACTIVE_BETWEEN_PACKETS(spi_cs_timing, spi->chip_select,
+ cs_state);
+ SPI_SET_CYCLES_BETWEEN_PACKETS(spi_cs_timing, spi->chip_select,
+ inactive_cycles);
+ if (tspi->spi_cs_timing2 != spi_cs_timing) {
+ tspi->spi_cs_timing2 = spi_cs_timing;
+ tegra_spi_writel(tspi, spi_cs_timing, SPI_CS_TIMING2);
+ }
+}
+
static u32 tegra_spi_setup_transfer_one(struct spi_device *spi,
struct spi_transfer *t, bool is_first_of_msg,
bool is_single_xfer)
@@ -1283,6 +1324,7 @@ static int tegra_spi_probe(struct platform_device *pdev)
master->setup = tegra_spi_setup;
master->cleanup = tegra_spi_cleanup;
master->transfer_one_message = tegra_spi_transfer_one_message;
+ master->set_cs_timing = tegra_spi_set_hw_cs_timing;
master->num_chipselect = MAX_CHIP_SELECT;
master->auto_runtime_pm = true;
bus_num = of_alias_get_id(pdev->dev.of_node, "spi");
@@ -1358,6 +1400,8 @@ static int tegra_spi_probe(struct platform_device *pdev)
reset_control_deassert(tspi->rst);
tspi->def_command1_reg = SPI_M_S;
tegra_spi_writel(tspi, tspi->def_command1_reg, SPI_COMMAND1);
+ tspi->spi_cs_timing1 = tegra_spi_readl(tspi, SPI_CS_TIMING1);
+ tspi->spi_cs_timing2 = tegra_spi_readl(tspi, SPI_CS_TIMING2);
pm_runtime_put(&pdev->dev);
ret = request_threaded_irq(tspi->irq, tegra_spi_isr,
tegra_spi_isr_thread, IRQF_ONESHOT,
--
2.7.4
This patch adds support for dual mode SPI transfer.
Dual mode uses both MOSI and MISO lines in parallel where the data
is interleaved on MOSI and MISO lines increasing the throughput.
Packet from Tx FIFO is transmitted on both MOSI and MISO lines and
packet to Rx FIFO is received from both MOSI and MISO lines. Even
bits are transmitted or received on the MOSI data line and odd bits
are transmitted or received on the MISO data line.
Signed-off-by: Sowjanya Komatineni <[email protected]>
---
drivers/spi/spi-tegra114.c | 8 +++++++-
1 file changed, 7 insertions(+), 1 deletion(-)
diff --git a/drivers/spi/spi-tegra114.c b/drivers/spi/spi-tegra114.c
index 58f5059b339f..239fb0c8c31f 100644
--- a/drivers/spi/spi-tegra114.c
+++ b/drivers/spi/spi-tegra114.c
@@ -787,6 +787,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
@@ -1153,7 +1158,8 @@ 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 | SPI_LSB_FIRST;
+ master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH | SPI_LSB_FIRST |
+ SPI_TX_DUAL | SPI_RX_DUAL;
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;
--
2.7.4
This patch dumps SPI registers on transfer error or timeout for debug
purpose.
Signed-off-by: Sowjanya Komatineni <[email protected]>
---
drivers/spi/spi-tegra114.c | 18 ++++++++++++++++++
1 file changed, 18 insertions(+)
diff --git a/drivers/spi/spi-tegra114.c b/drivers/spi/spi-tegra114.c
index d928a2c92a3d..e0f20fad5df2 100644
--- a/drivers/spi/spi-tegra114.c
+++ b/drivers/spi/spi-tegra114.c
@@ -876,6 +876,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)
{
@@ -922,6 +936,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);
@@ -932,6 +947,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;
@@ -973,6 +989,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);
@@ -1047,6 +1064,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);
--
2.7.4
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 <[email protected]>
---
drivers/spi/spi-tegra114.c | 53 +++++++++++++++++++++++++++++++++++++++++-----
1 file changed, 48 insertions(+), 5 deletions(-)
diff --git a/drivers/spi/spi-tegra114.c b/drivers/spi/spi-tegra114.c
index d3b95bba2361..f4e39eb3857c 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);
@@ -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;
@@ -853,6 +862,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)
@@ -1141,8 +1156,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);
@@ -1184,6 +1220,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)) {
--
2.7.4
Some SPI devices expects SPI transfers to be in Least significant byte
first order and some devices expect Most significant byte first order.
This patch adds SPI_LSBYTE_FIRST to the supported SPI mode list and also
configures Tegra SPI controller accordingly.
Signed-off-by: Sowjanya Komatineni <[email protected]>
---
drivers/spi/spi-tegra114.c | 8 +++++++-
1 file changed, 7 insertions(+), 1 deletion(-)
diff --git a/drivers/spi/spi-tegra114.c b/drivers/spi/spi-tegra114.c
index 212bb90aa0cb..d3b95bba2361 100644
--- a/drivers/spi/spi-tegra114.c
+++ b/drivers/spi/spi-tegra114.c
@@ -755,6 +755,11 @@ static u32 tegra_spi_setup_transfer_one(struct spi_device *spi,
else
command1 &= ~SPI_LSBIT_FE;
+ if (spi->mode & SPI_LSBYTE_FIRST)
+ command1 |= SPI_LSBYTE_FE;
+ else
+ command1 &= ~SPI_LSBYTE_FE;
+
if (spi->mode & SPI_3WIRE)
command1 |= SPI_BIDIROE;
else
@@ -1164,7 +1169,8 @@ static int tegra_spi_probe(struct platform_device *pdev)
/* the spi->mode bits understood by this driver: */
master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH | SPI_LSB_FIRST |
- SPI_TX_DUAL | SPI_RX_DUAL | SPI_3WIRE;
+ SPI_TX_DUAL | SPI_RX_DUAL | SPI_3WIRE |
+ SPI_LSBYTE_FIRST;
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;
--
2.7.4
This patch sets SPI device id from the device tree as the bus number.
Signed-off-by: Sowjanya Komatineni <[email protected]>
---
drivers/spi/spi-tegra114.c | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/drivers/spi/spi-tegra114.c b/drivers/spi/spi-tegra114.c
index 191233eae149..58f5059b339f 100644
--- a/drivers/spi/spi-tegra114.c
+++ b/drivers/spi/spi-tegra114.c
@@ -1138,6 +1138,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) {
@@ -1158,6 +1159,9 @@ static int tegra_spi_probe(struct platform_device *pdev)
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;
--
2.7.4
This patch moves SPI controller reset out of spin lock.
Signed-off-by: Sowjanya Komatineni <[email protected]>
---
drivers/spi/spi-tegra114.c | 9 +++++----
1 file changed, 5 insertions(+), 4 deletions(-)
diff --git a/drivers/spi/spi-tegra114.c b/drivers/spi/spi-tegra114.c
index c60e40cab0a0..d928a2c92a3d 100644
--- a/drivers/spi/spi-tegra114.c
+++ b/drivers/spi/spi-tegra114.c
@@ -974,11 +974,12 @@ static irqreturn_t handle_cpu_based_xfer(struct tegra_spi_data *tspi)
dev_err(tspi->dev, "CpuXfer 0x%08x:0x%08x\n",
tspi->command1_reg, tspi->dma_control_reg);
tegra_spi_flush_fifos(tspi);
+ complete(&tspi->xfer_completion);
+ spin_unlock_irqrestore(&tspi->lock, flags);
reset_control_assert(tspi->rst);
udelay(2);
reset_control_deassert(tspi->rst);
- complete(&tspi->xfer_completion);
- goto exit;
+ return IRQ_HANDLED;
}
if (tspi->cur_direction & DATA_DIR_RX)
@@ -1047,11 +1048,11 @@ static irqreturn_t handle_dma_based_xfer(struct tegra_spi_data *tspi)
dev_err(tspi->dev, "DmaXfer 0x%08x:0x%08x\n",
tspi->command1_reg, tspi->dma_control_reg);
tegra_spi_flush_fifos(tspi);
+ complete(&tspi->xfer_completion);
+ spin_unlock_irqrestore(&tspi->lock, flags);
reset_control_assert(tspi->rst);
udelay(2);
reset_control_deassert(tspi->rst);
- complete(&tspi->xfer_completion);
- spin_unlock_irqrestore(&tspi->lock, flags);
return IRQ_HANDLED;
}
--
2.7.4
Tegra SPI supports 4 through 32 bits per word.
This patch sets bits_per_word_mask accordingly to support transfer
with these bits per word.
Signed-off-by: Sowjanya Komatineni <[email protected]>
---
drivers/spi/spi-tegra114.c | 1 +
1 file changed, 1 insertion(+)
diff --git a/drivers/spi/spi-tegra114.c b/drivers/spi/spi-tegra114.c
index e0f20fad5df2..191233eae149 100644
--- a/drivers/spi/spi-tegra114.c
+++ b/drivers/spi/spi-tegra114.c
@@ -1153,6 +1153,7 @@ static int tegra_spi_probe(struct platform_device *pdev)
/* the spi->mode bits understood by this driver: */
master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH | SPI_LSB_FIRST;
+ 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;
--
2.7.4
This patch adds supports for chip select control using GPIO if valid
CS gpio exists.
Signed-off-by: Sowjanya Komatineni <[email protected]>
---
drivers/spi/spi-tegra114.c | 59 ++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 59 insertions(+)
diff --git a/drivers/spi/spi-tegra114.c b/drivers/spi/spi-tegra114.c
index f4e39eb3857c..209ec05a349f 100644
--- a/drivers/spi/spi-tegra114.c
+++ b/drivers/spi/spi-tegra114.c
@@ -23,6 +23,7 @@
#include <linux/dma-mapping.h>
#include <linux/dmapool.h>
#include <linux/err.h>
+#include <linux/gpio.h>
#include <linux/interrupt.h>
#include <linux/io.h>
#include <linux/kernel.h>
@@ -167,6 +168,10 @@ struct tegra_spi_soc_data {
bool has_intr_mask_reg;
};
+struct tegra_spi_client_state {
+ bool cs_gpio_valid;
+};
+
struct tegra_spi_data {
struct device *dev;
struct spi_master *master;
@@ -726,6 +731,7 @@ static u32 tegra_spi_setup_transfer_one(struct spi_device *spi,
struct spi_transfer *t, bool is_first_of_msg)
{
struct tegra_spi_data *tspi = spi_master_get_devdata(spi->master);
+ struct tegra_spi_client_state *cstate = spi->controller_state;
u32 speed = t->speed_hz;
u8 bits_per_word = t->bits_per_word;
u32 command1;
@@ -787,6 +793,12 @@ static u32 tegra_spi_setup_transfer_one(struct spi_device *spi,
else
command1 &= ~SPI_CS_SW_VAL;
+ if (cstate->cs_gpio_valid) {
+ int val = (spi->mode & SPI_CS_HIGH) ? 1 : 0;
+
+ gpio_set_value(spi->cs_gpio, val);
+ }
+
tegra_spi_writel(tspi, 0, SPI_COMMAND2);
} else {
command1 = tspi->command1_reg;
@@ -843,9 +855,20 @@ static int tegra_spi_start_transfer_one(struct spi_device *spi,
return ret;
}
+static void tegra_spi_cleanup(struct spi_device *spi)
+{
+ struct tegra_spi_client_state *cstate = spi->controller_state;
+
+ spi->controller_state = NULL;
+ if (cstate && cstate->cs_gpio_valid)
+ gpio_free(spi->cs_gpio);
+ kfree(cstate);
+}
+
static int tegra_spi_setup(struct spi_device *spi)
{
struct tegra_spi_data *tspi = spi_master_get_devdata(spi->master);
+ struct tegra_spi_client_state *cstate = spi->controller_state;
u32 val;
unsigned long flags;
int ret;
@@ -856,9 +879,40 @@ static int tegra_spi_setup(struct spi_device *spi)
spi->mode & SPI_CPHA ? "" : "~",
spi->max_speed_hz);
+ if (!cstate) {
+ cstate = kzalloc(sizeof(*cstate), GFP_KERNEL);
+ if (!cstate)
+ return -ENOMEM;
+ spi->controller_state = cstate;
+ }
+
+ if (spi->master->cs_gpios && gpio_is_valid(spi->cs_gpio)) {
+ if (!cstate->cs_gpio_valid) {
+ int gpio_flag = GPIOF_OUT_INIT_HIGH;
+
+ if (spi->mode & SPI_CS_HIGH)
+ gpio_flag = GPIOF_OUT_INIT_LOW;
+
+ ret = gpio_request_one(spi->cs_gpio, gpio_flag,
+ "cs_gpio");
+ if (ret < 0) {
+ dev_err(&spi->dev,
+ "GPIO request failed: %d\n", ret);
+ tegra_spi_cleanup(spi);
+ return ret;
+ }
+ cstate->cs_gpio_valid = true;
+ } else {
+ int val = (spi->mode & SPI_CS_HIGH) ? 0 : 1;
+
+ gpio_set_value(spi->cs_gpio, val);
+ }
+ }
+
ret = pm_runtime_get_sync(tspi->dev);
if (ret < 0) {
dev_err(tspi->dev, "pm runtime failed, e = %d\n", ret);
+ tegra_spi_cleanup(spi);
return ret;
}
@@ -896,8 +950,12 @@ static void tegra_spi_transfer_delay(int delay)
static void tegra_spi_transfer_end(struct spi_device *spi)
{
struct tegra_spi_data *tspi = spi_master_get_devdata(spi->master);
+ struct tegra_spi_client_state *cstate = spi->controller_state;
int cs_val = (spi->mode & SPI_CS_HIGH) ? 0 : 1;
+ if (cstate->cs_gpio_valid)
+ gpio_set_value(spi->cs_gpio, cs_val);
+
if (cs_val)
tspi->command1_reg |= SPI_CS_SW_VAL;
else
@@ -1209,6 +1267,7 @@ static int tegra_spi_probe(struct platform_device *pdev)
SPI_LSBYTE_FIRST;
master->bits_per_word_mask = SPI_BPW_RANGE_MASK(4, 32);
master->setup = tegra_spi_setup;
+ master->cleanup = tegra_spi_cleanup;
master->transfer_one_message = tegra_spi_transfer_one_message;
master->num_chipselect = MAX_CHIP_SELECT;
master->auto_runtime_pm = true;
--
2.7.4
This patch creates set_cs_timing SPI master optional method for
SPI masters to implement configuring CS timing if applicable.
This patch also creates spi_cs_timing accessory for SPI clients to
use for requesting SPI master controllers to configure device requested
CS setup time, hold time and inactive delay.
Signed-off-by: Sowjanya Komatineni <[email protected]>
---
drivers/spi/spi.c | 15 +++++++++++++++
include/linux/spi/spi.h | 15 +++++++++++++++
2 files changed, 30 insertions(+)
diff --git a/drivers/spi/spi.c b/drivers/spi/spi.c
index 97ce047a776b..0f92329e990f 100644
--- a/drivers/spi/spi.c
+++ b/drivers/spi/spi.c
@@ -2995,6 +2995,21 @@ int spi_setup(struct spi_device *spi)
}
EXPORT_SYMBOL_GPL(spi_setup);
+/**
+ * spi_set_cs_timing - configure CS setup, hold, and inactive delays
+ * @spi: the device that requires specific CS timing configuration
+ * @setup: CS setup time in terms of clock count
+ * @hold: CS hold time in terms of clock count
+ * @inactive_dly: CS inactive delay between transfers in terms of clock count
+ */
+void spi_set_cs_timing(struct spi_device *spi, u8 setup, u8 hold,
+ u8 inactive_dly)
+{
+ if (spi->controller->set_cs_timing)
+ spi->controller->set_cs_timing(spi, setup, hold, inactive_dly);
+}
+EXPORT_SYMBOL_GPL(spi_set_cs_timing);
+
static int __spi_validate(struct spi_device *spi, struct spi_message *message)
{
struct spi_controller *ctlr = spi->controller;
diff --git a/include/linux/spi/spi.h b/include/linux/spi/spi.h
index d5c86b763f43..fc4d21b4c2e4 100644
--- a/include/linux/spi/spi.h
+++ b/include/linux/spi/spi.h
@@ -331,6 +331,9 @@ static inline void spi_unregister_driver(struct spi_driver *sdrv)
* must fail if an unrecognized or unsupported mode is requested.
* It's always safe to call this unless transfers are pending on
* the device whose settings are being modified.
+ * @set_cs_timing: optional hook for SPI devices to request SPI master
+ * controller for configuring specific CS setup time, hold time and inactive
+ * delay interms of clock counts
* @transfer: adds a message to the controller's transfer queue.
* @cleanup: frees controller-specific state
* @can_dma: determine whether this controller supports DMA
@@ -364,6 +367,7 @@ static inline void spi_unregister_driver(struct spi_driver *sdrv)
* @unprepare_transfer_hardware: there are currently no more messages on the
* queue so the subsystem notifies the driver that it may relax the
* hardware by issuing this call
+ *
* @set_cs: set the logic level of the chip select line. May be called
* from interrupt context.
* @prepare_message: set up the controller to transfer a single message,
@@ -489,6 +493,17 @@ struct spi_controller {
*/
int (*setup)(struct spi_device *spi);
+ /*
+ * set_cs_timing() method is for SPI controllers that supports
+ * configuring CS timing.
+ *
+ * This hook allows SPI client drivers to request SPI controllers
+ * to configure specific CS timing through spi_set_cs_timing() after
+ * spi_setup().
+ */
+ void (*set_cs_timing)(struct spi_device *spi, u8 setup_clk_cycles,
+ u8 hold_clk_cycles, u8 inactive_clk_cycles);
+
/* bidirectional bulk transfers
*
* + The transfer() method may not sleep; its main role is
--
2.7.4
Some SPI Master controllers support configuring Least significant byte
first or Most significant byte first order for transfers. Also some SPI
slave devices expect bytes to be in Least significant first order and
some devices expect Most significant first order.
SPI driver declares mode and mode_bits as u16 and all bits are used.
This patch changes mode and mode_bits to be u32 to allow for more mode
configurations.
This patch also creates SPI_LSBYTE_FIRST mode to allow SPI clients to
choose LSByte order or MSByte order through the device tree property
spi-lsbyte-first.
Signed-off-by: Sowjanya Komatineni <[email protected]>
---
drivers/spi/spi.c | 5 ++++-
include/linux/spi/spi.h | 7 ++++---
2 files changed, 8 insertions(+), 4 deletions(-)
diff --git a/drivers/spi/spi.c b/drivers/spi/spi.c
index bd2a424672df..97ce047a776b 100644
--- a/drivers/spi/spi.c
+++ b/drivers/spi/spi.c
@@ -1638,6 +1638,8 @@ static int of_spi_parse_dt(struct spi_controller *ctlr, struct spi_device *spi,
spi->mode |= SPI_3WIRE;
if (of_property_read_bool(nc, "spi-lsb-first"))
spi->mode |= SPI_LSB_FIRST;
+ if (of_property_read_bool(nc, "spi-lsbyte-first"))
+ spi->mode |= SPI_LSBYTE_FIRST;
/*
* For descriptors associated with the device, polarity inversion is
@@ -2979,10 +2981,11 @@ int spi_setup(struct spi_device *spi)
spi_set_cs(spi, false);
- dev_dbg(&spi->dev, "setup mode %d, %s%s%s%s%u bits/w, %u Hz max --> %d\n",
+ dev_dbg(&spi->dev, "setup mode %d, %s%s%s%s%s%u bits/w, %u Hz max --> %d\n",
(int) (spi->mode & (SPI_CPOL | SPI_CPHA)),
(spi->mode & SPI_CS_HIGH) ? "cs_high, " : "",
(spi->mode & SPI_LSB_FIRST) ? "lsb, " : "",
+ (spi->mode & SPI_LSBYTE_FIRST) ? "lsbyte, " : "",
(spi->mode & SPI_3WIRE) ? "3wire, " : "",
(spi->mode & SPI_LOOP) ? "loopback, " : "",
spi->bits_per_word, spi->max_speed_hz,
diff --git a/include/linux/spi/spi.h b/include/linux/spi/spi.h
index a0975cf76cf6..d5c86b763f43 100644
--- a/include/linux/spi/spi.h
+++ b/include/linux/spi/spi.h
@@ -143,7 +143,7 @@ struct spi_device {
u32 max_speed_hz;
u8 chip_select;
u8 bits_per_word;
- u16 mode;
+ u32 mode;
#define SPI_CPHA 0x01 /* clock phase */
#define SPI_CPOL 0x02 /* clock polarity */
#define SPI_MODE_0 (0|0) /* (original MicroWire) */
@@ -164,6 +164,7 @@ struct spi_device {
#define SPI_TX_OCTAL 0x2000 /* transmit with 8 wires */
#define SPI_RX_OCTAL 0x4000 /* receive with 8 wires */
#define SPI_3WIRE_HIZ 0x8000 /* high impedance turnaround */
+#define SPI_LSBYTE_FIRST 0x10000 /* per-word bytes-on-wire */
int irq;
void *controller_state;
void *controller_data;
@@ -439,7 +440,7 @@ struct spi_controller {
u16 dma_alignment;
/* spi_device.mode flags understood by this controller driver */
- u16 mode_bits;
+ u32 mode_bits;
/* bitmask of supported bits_per_word for transfers */
u32 bits_per_word_mask;
@@ -1276,7 +1277,7 @@ struct spi_board_info {
/* mode becomes spi_device.mode, and is essential for chips
* where the default of SPI_CS_HIGH = 0 is wrong.
*/
- u16 mode;
+ u32 mode;
/* ... may need additional spi_device chip config data here.
* avoid stuff protocol drivers can set; but include stuff
--
2.7.4
spi-lsbyte-first optional property allows SPI slaves to choose byte
order of little endian for transfers.
Signed-off-by: Sowjanya Komatineni <[email protected]>
---
Documentation/devicetree/bindings/spi/spi-bus.txt | 1 +
1 file changed, 1 insertion(+)
diff --git a/Documentation/devicetree/bindings/spi/spi-bus.txt b/Documentation/devicetree/bindings/spi/spi-bus.txt
index 1f6e86f787ef..b455c24a80df 100644
--- a/Documentation/devicetree/bindings/spi/spi-bus.txt
+++ b/Documentation/devicetree/bindings/spi/spi-bus.txt
@@ -71,6 +71,7 @@ All slave nodes can contain the following optional properties:
active high.
- spi-3wire - Empty property indicating device requires 3-wire mode.
- spi-lsb-first - Empty property indicating device requires LSB first mode.
+- spi-lsbyte-first - Empty property indicating device requires LSByte first mode.
- spi-tx-bus-width - The bus width (number of data wires) that is used for MOSI.
Defaults to 1 if not present.
- spi-rx-bus-width - The bus width (number of data wires) that is used for MISO.
--
2.7.4
With SW CS, during the transfer completion CS is de-asserted by writing
default command1 register value to SPI_COMMAND1 register. With this both
mode and CS state are set at the same time and if current transfer mode
is different to default SPI mode and if mode change happens prior to CS
de-assert, clock polarity can change while CS is active before transfer
finishes.
This causes Slave to see spurious clock edges resulting in data mismatch.
This patch fixes this by de-asserting CS before writing SPI_COMMAND1 to
its default value so through out the transfer it will be in same SPI mode.
Signed-off-by: Sowjanya Komatineni <[email protected]>
---
drivers/spi/spi-tegra114.c | 22 ++++++++++++++++------
1 file changed, 16 insertions(+), 6 deletions(-)
diff --git a/drivers/spi/spi-tegra114.c b/drivers/spi/spi-tegra114.c
index 3042521c3785..c60e40cab0a0 100644
--- a/drivers/spi/spi-tegra114.c
+++ b/drivers/spi/spi-tegra114.c
@@ -863,6 +863,19 @@ static void tegra_spi_transfer_delay(int delay)
udelay(delay % 1000);
}
+static void tegra_spi_transfer_end(struct spi_device *spi)
+{
+ struct tegra_spi_data *tspi = spi_master_get_devdata(spi->master);
+ int cs_val = (spi->mode & SPI_CS_HIGH) ? 0 : 1;
+
+ if (cs_val)
+ tspi->command1_reg |= SPI_CS_SW_VAL;
+ else
+ tspi->command1_reg &= ~SPI_CS_SW_VAL;
+ tegra_spi_writel(tspi, tspi->command1_reg, SPI_COMMAND1);
+ tegra_spi_writel(tspi, tspi->def_command1_reg, SPI_COMMAND1);
+}
+
static int tegra_spi_transfer_one_message(struct spi_master *master,
struct spi_message *msg)
{
@@ -925,8 +938,7 @@ static int tegra_spi_transfer_one_message(struct spi_master *master,
complete_xfer:
if (ret < 0 || skip) {
- tegra_spi_writel(tspi, tspi->def_command1_reg,
- SPI_COMMAND1);
+ tegra_spi_transfer_end(spi);
tegra_spi_transfer_delay(xfer->delay_usecs);
goto exit;
} else if (list_is_last(&xfer->transfer_list,
@@ -934,13 +946,11 @@ static int tegra_spi_transfer_one_message(struct spi_master *master,
if (xfer->cs_change)
tspi->cs_control = spi;
else {
- tegra_spi_writel(tspi, tspi->def_command1_reg,
- SPI_COMMAND1);
+ tegra_spi_transfer_end(spi);
tegra_spi_transfer_delay(xfer->delay_usecs);
}
} else if (xfer->cs_change) {
- tegra_spi_writel(tspi, tspi->def_command1_reg,
- SPI_COMMAND1);
+ tegra_spi_transfer_end(spi);
tegra_spi_transfer_delay(xfer->delay_usecs);
}
--
2.7.4
Tegra SPI controller has TX_CLK_TAP_DELAY and RX_CLK_TAP_DELAY in
COMMAND2 register to tune the delay of the clock going out to external
device during transmit and also for the clock coming in from external
device during receive.
TX/RX clock tap delays may vary based on the trace lengths of the
platform design for each of the slaves on the SPI bus.
This patch adds support for configuring TX/RX clock delays specified
through device tree properties.
Signed-off-by: Sowjanya Komatineni <[email protected]>
---
drivers/spi/spi-tegra114.c | 63 +++++++++++++++++++++++++++++++++++++++++++++-
1 file changed, 62 insertions(+), 1 deletion(-)
diff --git a/drivers/spi/spi-tegra114.c b/drivers/spi/spi-tegra114.c
index 34dee28554ef..9854e6fbddff 100644
--- a/drivers/spi/spi-tegra114.c
+++ b/drivers/spi/spi-tegra114.c
@@ -170,6 +170,11 @@ struct tegra_spi_soc_data {
bool has_intr_mask_reg;
};
+struct tegra_spi_client_data {
+ int tx_clk_tap_delay;
+ int rx_clk_tap_delay;
+};
+
struct tegra_spi_client_state {
bool cs_gpio_valid;
};
@@ -213,8 +218,10 @@ struct tegra_spi_data {
u32 command1_reg;
u32 dma_control_reg;
u32 def_command1_reg;
+ u32 def_command2_reg;
u32 spi_cs_timing1;
u32 spi_cs_timing2;
+ u8 last_used_cs;
struct completion xfer_completion;
struct spi_transfer *curr_xfer;
@@ -774,11 +781,13 @@ static u32 tegra_spi_setup_transfer_one(struct spi_device *spi,
bool is_single_xfer)
{
struct tegra_spi_data *tspi = spi_master_get_devdata(spi->master);
+ struct tegra_spi_client_data *cdata = spi->controller_data;
struct tegra_spi_client_state *cstate = spi->controller_state;
u32 speed = t->speed_hz;
u8 bits_per_word = t->bits_per_word;
- u32 command1;
+ u32 command1, command2;
int req_mode;
+ u32 tx_tap = 0, rx_tap = 0;
if (speed != tspi->cur_speed) {
clk_set_rate(tspi->clk, speed);
@@ -848,6 +857,18 @@ static u32 tegra_spi_setup_transfer_one(struct spi_device *spi,
gpio_set_value(spi->cs_gpio, val);
}
+ if (tspi->last_used_cs != spi->chip_select) {
+ if (cdata && cdata->tx_clk_tap_delay)
+ tx_tap = cdata->tx_clk_tap_delay;
+ if (cdata && cdata->rx_clk_tap_delay)
+ rx_tap = cdata->rx_clk_tap_delay;
+ command2 = SPI_TX_TAP_DELAY(tx_tap) |
+ SPI_RX_TAP_DELAY(rx_tap);
+ if (command2 != tspi->def_command2_reg)
+ tegra_spi_writel(tspi, command2, SPI_COMMAND2);
+ tspi->last_used_cs = spi->chip_select;
+ }
+
tegra_spi_writel(tspi, 0, SPI_COMMAND2);
} else {
command1 = tspi->command1_reg;
@@ -904,19 +925,47 @@ static int tegra_spi_start_transfer_one(struct spi_device *spi,
return ret;
}
+static struct tegra_spi_client_data
+ *tegra_spi_parse_cdata_dt(struct spi_device *spi)
+{
+ struct tegra_spi_client_data *cdata;
+ struct device_node *slave_np;
+
+ slave_np = spi->dev.of_node;
+ if (!slave_np) {
+ dev_dbg(&spi->dev, "device node not found\n");
+ return NULL;
+ }
+
+ cdata = kzalloc(sizeof(*cdata), GFP_KERNEL);
+ if (!cdata)
+ return NULL;
+
+ of_property_read_u32(slave_np, "nvidia,tx-clk-tap-delay",
+ &cdata->tx_clk_tap_delay);
+ of_property_read_u32(slave_np, "nvidia,rx-clk-tap-delay",
+ &cdata->rx_clk_tap_delay);
+ return cdata;
+}
+
static void tegra_spi_cleanup(struct spi_device *spi)
{
struct tegra_spi_client_state *cstate = spi->controller_state;
+ struct tegra_spi_client_data *cdata = spi->controller_data;
spi->controller_state = NULL;
if (cstate && cstate->cs_gpio_valid)
gpio_free(spi->cs_gpio);
kfree(cstate);
+ spi->controller_data = NULL;
+ if (spi->dev.of_node)
+ kfree(cdata);
}
static int tegra_spi_setup(struct spi_device *spi)
{
struct tegra_spi_data *tspi = spi_master_get_devdata(spi->master);
+ struct tegra_spi_client_data *cdata = spi->controller_data;
struct tegra_spi_client_state *cstate = spi->controller_state;
u32 val;
unsigned long flags;
@@ -935,6 +984,11 @@ static int tegra_spi_setup(struct spi_device *spi)
spi->controller_state = cstate;
}
+ if (!cdata) {
+ cdata = tegra_spi_parse_cdata_dt(spi);
+ spi->controller_data = cdata;
+ }
+
if (spi->master->cs_gpios && gpio_is_valid(spi->cs_gpio)) {
if (!cstate->cs_gpio_valid) {
int gpio_flag = GPIOF_OUT_INIT_HIGH;
@@ -1084,6 +1138,7 @@ static int tegra_spi_transfer_one_message(struct spi_master *master,
reset_control_assert(tspi->rst);
udelay(2);
reset_control_deassert(tspi->rst);
+ tspi->last_used_cs = master->num_chipselect + 1;
goto complete_xfer;
}
@@ -1139,6 +1194,7 @@ static irqreturn_t handle_cpu_based_xfer(struct tegra_spi_data *tspi)
reset_control_assert(tspi->rst);
udelay(2);
reset_control_deassert(tspi->rst);
+ tspi->last_used_cs = master->num_chipselect + 1;
return IRQ_HANDLED;
}
@@ -1214,6 +1270,7 @@ static irqreturn_t handle_dma_based_xfer(struct tegra_spi_data *tspi)
reset_control_assert(tspi->rst);
udelay(2);
reset_control_deassert(tspi->rst);
+ tspi->last_used_cs = master->num_chipselect + 1;
return IRQ_HANDLED;
}
@@ -1402,6 +1459,8 @@ static int tegra_spi_probe(struct platform_device *pdev)
tegra_spi_writel(tspi, tspi->def_command1_reg, SPI_COMMAND1);
tspi->spi_cs_timing1 = tegra_spi_readl(tspi, SPI_CS_TIMING1);
tspi->spi_cs_timing2 = tegra_spi_readl(tspi, SPI_CS_TIMING2);
+ tspi->def_command2_reg = tegra_spi_readl(tspi, SPI_COMMAND2);
+ tspi->last_used_cs = master->num_chipselect + 1;
pm_runtime_put(&pdev->dev);
ret = request_threaded_irq(tspi->irq, tegra_spi_isr,
tegra_spi_isr_thread, IRQF_ONESHOT,
@@ -1474,6 +1533,8 @@ static int tegra_spi_resume(struct device *dev)
return ret;
}
tegra_spi_writel(tspi, tspi->command1_reg, SPI_COMMAND1);
+ tegra_spi_writel(tspi, tspi->def_command2_reg, SPI_COMMAND2);
+ tspi->last_used_cs = master->num_chipselect + 1;
pm_runtime_put(dev);
return spi_master_resume(master);
--
2.7.4
This patch documents set_cs_timing SPI master method.
Signed-off-by: Sowjanya Komatineni <[email protected]>
---
Documentation/spi/spi-summary | 6 ++++++
1 file changed, 6 insertions(+)
diff --git a/Documentation/spi/spi-summary b/Documentation/spi/spi-summary
index 1721c1b570c3..1a63194b74d7 100644
--- a/Documentation/spi/spi-summary
+++ b/Documentation/spi/spi-summary
@@ -572,6 +572,12 @@ SPI MASTER METHODS
0: transfer is finished
1: transfer is still in progress
+ master->set_cs_timing(struct spi_device *spi, u8 setup_clk_cycles,
+ u8 hold_clk_cycles, u8 inactive_clk_cycles)
+ This method allows SPI client drivers to request SPI master controller
+ for configuring device specific CS setup, hold and inactive timing
+ requirements.
+
DEPRECATED METHODS
master->transfer(struct spi_device *spi, struct spi_message *message)
--
2.7.4
Tegra SPI controller has TX and RX trimmers to tuning the delay of
SPI master clock with respect to the data.
TX and RX tap values are based on the platform validation across the
PVT and the trimmer values vary based on the trace lengths to the
corresponding SPI devices.
Signed-off-by: Sowjanya Komatineni <[email protected]>
---
.../devicetree/bindings/spi/nvidia,tegra114-spi.txt | 20 ++++++++++++++++++++
1 file changed, 20 insertions(+)
diff --git a/Documentation/devicetree/bindings/spi/nvidia,tegra114-spi.txt b/Documentation/devicetree/bindings/spi/nvidia,tegra114-spi.txt
index 9ba7c5a273b4..db8e0d71c5bc 100644
--- a/Documentation/devicetree/bindings/spi/nvidia,tegra114-spi.txt
+++ b/Documentation/devicetree/bindings/spi/nvidia,tegra114-spi.txt
@@ -23,6 +23,18 @@ Required properties:
Recommended properties:
- spi-max-frequency: Definition as per
Documentation/devicetree/bindings/spi/spi-bus.txt
+Optional properties:
+- nvidia,tx-clk-tap-delay: Delays the clock going out to the external device
+ with this tap value. This property is used to tune the outgoing data from
+ Tegra SPI master with respect to outgoing Tegra SPI master clock.
+ Tap values vary based on the platform design trace lengths from Tegra SPI
+ to corresponding slave devices. Valid tap values are from 0 thru 63.
+- nvidia,rx-clk-tap-delay: Delays the clock coming in from the external device
+ with this tap value. This property is used to adjust the Tegra SPI master
+ clock with respect to the data from the SPI slave device.
+ Tap values vary based on the platform design trace lengths from Tegra SPI
+ to corresponding slave devices. Valid tap values are from 0 thru 63.
+
Example:
spi@7000d600 {
@@ -38,4 +50,12 @@ spi@7000d600 {
reset-names = "spi";
dmas = <&apbdma 16>, <&apbdma 16>;
dma-names = "rx", "tx";
+ <spi-client>@<bus_num> {
+ ...
+ ...
+ nvidia,rx-clk-tap-delay = <0>;
+ nvidia,tx-clk-tap-delay = <16>;
+ ...
+ };
+
};
--
2.7.4
The patch
spi: tegra114: set supported bits per word
has been applied to the spi tree at
https://git.kernel.org/pub/scm/linux/kernel/git/broonie/spi.git
All being well this means that it will be integrated into the linux-next
tree (usually sometime in the next 24 hours) and sent to Linus during
the next merge window (or sooner if it is a bug fix), however if
problems are discovered then the patch may be dropped or reverted.
You may get further e-mails resulting from automated or manual testing
and review of the tree, please engage with people reporting problems and
send followup patches addressing any issues that are reported if needed.
If any updates are required or you are submitting further changes they
should be sent as incremental updates against current git, existing
patches will not be replaced.
Please add any relevant lists and maintainers to the CCs when replying
to this mail.
Thanks,
Mark
From f0a0bc90c6e7060778911c2b55d085105809d6cf Mon Sep 17 00:00:00 2001
From: Sowjanya Komatineni <[email protected]>
Date: Thu, 4 Apr 2019 17:14:05 -0700
Subject: [PATCH] spi: tegra114: set supported bits per word
Tegra SPI supports 4 through 32 bits per word.
This patch sets bits_per_word_mask accordingly to support transfer
with these bits per word.
Signed-off-by: Sowjanya Komatineni <[email protected]>
Signed-off-by: Mark Brown <[email protected]>
---
drivers/spi/spi-tegra114.c | 1 +
1 file changed, 1 insertion(+)
diff --git a/drivers/spi/spi-tegra114.c b/drivers/spi/spi-tegra114.c
index 99019f6d2d84..c2ebf1ae632d 100644
--- a/drivers/spi/spi-tegra114.c
+++ b/drivers/spi/spi-tegra114.c
@@ -1151,6 +1151,7 @@ static int tegra_spi_probe(struct platform_device *pdev)
/* the spi->mode bits understood by this driver: */
master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH | SPI_LSB_FIRST;
+ 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;
--
2.20.1
The patch
spi: tegra114: dump SPI registers during timeout
has been applied to the spi tree at
https://git.kernel.org/pub/scm/linux/kernel/git/broonie/spi.git
All being well this means that it will be integrated into the linux-next
tree (usually sometime in the next 24 hours) and sent to Linus during
the next merge window (or sooner if it is a bug fix), however if
problems are discovered then the patch may be dropped or reverted.
You may get further e-mails resulting from automated or manual testing
and review of the tree, please engage with people reporting problems and
send followup patches addressing any issues that are reported if needed.
If any updates are required or you are submitting further changes they
should be sent as incremental updates against current git, existing
patches will not be replaced.
Please add any relevant lists and maintainers to the CCs when replying
to this mail.
Thanks,
Mark
From a0253c8fa18129f423c22f175a83d81423e60715 Mon Sep 17 00:00:00 2001
From: Sowjanya Komatineni <[email protected]>
Date: Thu, 4 Apr 2019 17:14:04 -0700
Subject: [PATCH] spi: tegra114: dump SPI registers during timeout
This patch dumps SPI registers on transfer error or timeout for debug
purpose.
Signed-off-by: Sowjanya Komatineni <[email protected]>
Signed-off-by: Mark Brown <[email protected]>
---
drivers/spi/spi-tegra114.c | 18 ++++++++++++++++++
1 file changed, 18 insertions(+)
diff --git a/drivers/spi/spi-tegra114.c b/drivers/spi/spi-tegra114.c
index 8c33bf056196..99019f6d2d84 100644
--- a/drivers/spi/spi-tegra114.c
+++ b/drivers/spi/spi-tegra114.c
@@ -874,6 +874,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)
{
@@ -920,6 +934,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);
@@ -930,6 +945,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;
@@ -971,6 +987,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);
@@ -1045,6 +1062,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);
--
2.20.1
The patch
spi: tegra114: avoid reset call in atomic context
has been applied to the spi tree at
https://git.kernel.org/pub/scm/linux/kernel/git/broonie/spi.git
All being well this means that it will be integrated into the linux-next
tree (usually sometime in the next 24 hours) and sent to Linus during
the next merge window (or sooner if it is a bug fix), however if
problems are discovered then the patch may be dropped or reverted.
You may get further e-mails resulting from automated or manual testing
and review of the tree, please engage with people reporting problems and
send followup patches addressing any issues that are reported if needed.
If any updates are required or you are submitting further changes they
should be sent as incremental updates against current git, existing
patches will not be replaced.
Please add any relevant lists and maintainers to the CCs when replying
to this mail.
Thanks,
Mark
From a026525d4e45e3d9690bffd0b05d018ff5638b5a Mon Sep 17 00:00:00 2001
From: Sowjanya Komatineni <[email protected]>
Date: Thu, 4 Apr 2019 17:14:03 -0700
Subject: [PATCH] spi: tegra114: avoid reset call in atomic context
This patch moves SPI controller reset out of spin lock.
Signed-off-by: Sowjanya Komatineni <[email protected]>
Signed-off-by: Mark Brown <[email protected]>
---
drivers/spi/spi-tegra114.c | 9 +++++----
1 file changed, 5 insertions(+), 4 deletions(-)
diff --git a/drivers/spi/spi-tegra114.c b/drivers/spi/spi-tegra114.c
index 8de002fc6943..b57f10182fae 100644
--- a/drivers/spi/spi-tegra114.c
+++ b/drivers/spi/spi-tegra114.c
@@ -967,11 +967,12 @@ static irqreturn_t handle_cpu_based_xfer(struct tegra_spi_data *tspi)
dev_err(tspi->dev, "CpuXfer 0x%08x:0x%08x\n",
tspi->command1_reg, tspi->dma_control_reg);
tegra_spi_flush_fifos(tspi);
+ complete(&tspi->xfer_completion);
+ spin_unlock_irqrestore(&tspi->lock, flags);
reset_control_assert(tspi->rst);
udelay(2);
reset_control_deassert(tspi->rst);
- complete(&tspi->xfer_completion);
- goto exit;
+ return IRQ_HANDLED;
}
if (tspi->cur_direction & DATA_DIR_RX)
@@ -1040,11 +1041,11 @@ static irqreturn_t handle_dma_based_xfer(struct tegra_spi_data *tspi)
dev_err(tspi->dev, "DmaXfer 0x%08x:0x%08x\n",
tspi->command1_reg, tspi->dma_control_reg);
tegra_spi_flush_fifos(tspi);
+ complete(&tspi->xfer_completion);
+ spin_unlock_irqrestore(&tspi->lock, flags);
reset_control_assert(tspi->rst);
udelay(2);
reset_control_deassert(tspi->rst);
- complete(&tspi->xfer_completion);
- spin_unlock_irqrestore(&tspi->lock, flags);
return IRQ_HANDLED;
}
--
2.20.1
The patch
spi: tegra114: de-assert CS before SPI mode change
has been applied to the spi tree at
https://git.kernel.org/pub/scm/linux/kernel/git/broonie/spi.git
All being well this means that it will be integrated into the linux-next
tree (usually sometime in the next 24 hours) and sent to Linus during
the next merge window (or sooner if it is a bug fix), however if
problems are discovered then the patch may be dropped or reverted.
You may get further e-mails resulting from automated or manual testing
and review of the tree, please engage with people reporting problems and
send followup patches addressing any issues that are reported if needed.
If any updates are required or you are submitting further changes they
should be sent as incremental updates against current git, existing
patches will not be replaced.
Please add any relevant lists and maintainers to the CCs when replying
to this mail.
Thanks,
Mark
From f3e182c33e534f4caeb255a3ab927debc0d222aa Mon Sep 17 00:00:00 2001
From: Sowjanya Komatineni <[email protected]>
Date: Thu, 4 Apr 2019 17:14:02 -0700
Subject: [PATCH] spi: tegra114: de-assert CS before SPI mode change
With SW CS, during the transfer completion CS is de-asserted by writing
default command1 register value to SPI_COMMAND1 register. With this both
mode and CS state are set at the same time and if current transfer mode
is different to default SPI mode and if mode change happens prior to CS
de-assert, clock polarity can change while CS is active before transfer
finishes.
This causes Slave to see spurious clock edges resulting in data mismatch.
This patch fixes this by de-asserting CS before writing SPI_COMMAND1 to
its default value so through out the transfer it will be in same SPI mode.
Signed-off-by: Sowjanya Komatineni <[email protected]>
Signed-off-by: Mark Brown <[email protected]>
---
drivers/spi/spi-tegra114.c | 22 ++++++++++++++++------
1 file changed, 16 insertions(+), 6 deletions(-)
diff --git a/drivers/spi/spi-tegra114.c b/drivers/spi/spi-tegra114.c
index 09cfae3abce2..8de002fc6943 100644
--- a/drivers/spi/spi-tegra114.c
+++ b/drivers/spi/spi-tegra114.c
@@ -856,6 +856,19 @@ static void tegra_spi_transfer_delay(int delay)
udelay(delay % 1000);
}
+static void tegra_spi_transfer_end(struct spi_device *spi)
+{
+ struct tegra_spi_data *tspi = spi_master_get_devdata(spi->master);
+ int cs_val = (spi->mode & SPI_CS_HIGH) ? 0 : 1;
+
+ if (cs_val)
+ tspi->command1_reg |= SPI_CS_SW_VAL;
+ else
+ tspi->command1_reg &= ~SPI_CS_SW_VAL;
+ tegra_spi_writel(tspi, tspi->command1_reg, SPI_COMMAND1);
+ tegra_spi_writel(tspi, tspi->def_command1_reg, SPI_COMMAND1);
+}
+
static int tegra_spi_transfer_one_message(struct spi_master *master,
struct spi_message *msg)
{
@@ -918,8 +931,7 @@ static int tegra_spi_transfer_one_message(struct spi_master *master,
complete_xfer:
if (ret < 0 || skip) {
- tegra_spi_writel(tspi, tspi->def_command1_reg,
- SPI_COMMAND1);
+ tegra_spi_transfer_end(spi);
tegra_spi_transfer_delay(xfer->delay_usecs);
goto exit;
} else if (list_is_last(&xfer->transfer_list,
@@ -927,13 +939,11 @@ static int tegra_spi_transfer_one_message(struct spi_master *master,
if (xfer->cs_change)
tspi->cs_control = spi;
else {
- tegra_spi_writel(tspi, tspi->def_command1_reg,
- SPI_COMMAND1);
+ tegra_spi_transfer_end(spi);
tegra_spi_transfer_delay(xfer->delay_usecs);
}
} else if (xfer->cs_change) {
- tegra_spi_writel(tspi, tspi->def_command1_reg,
- SPI_COMMAND1);
+ tegra_spi_transfer_end(spi);
tegra_spi_transfer_delay(xfer->delay_usecs);
}
--
2.20.1
On Thu, Apr 04, 2019 at 05:14:09PM -0700, Sowjanya Komatineni wrote:
> spi-lsbyte-first optional property allows SPI slaves to choose byte
> order of little endian for transfers.
Why make this a DT property - surely it's either a fixed property of the
relevant devices if they are LSB first (in which case we should know we
can use it from the device) or it's something that the driver for the
device can just vary at runtime?
On Thu, Apr 04, 2019 at 05:14:13PM -0700, Sowjanya Komatineni wrote:
> + if (cstate->cs_gpio_valid) {
> + int val = (spi->mode & SPI_CS_HIGH) ? 1 : 0;
> +
> + gpio_set_value(spi->cs_gpio, val);
> + }
This is adding new usage of the numbered GPIO interface but we're in the
process of trying to transition to GPIO descriptors. Please update this
patch to use descriptors instead.
Please also investigate if it's possible to use the core GPIO chip
select support more.
On Thu, Apr 04, 2019 at 05:14:10PM -0700, Sowjanya Komatineni wrote:
> Some SPI Master controllers support configuring Least significant byte
> first or Most significant byte first order for transfers. Also some SPI
> slave devices expect bytes to be in Least significant first order and
> some devices expect Most significant first order.
>
> SPI driver declares mode and mode_bits as u16 and all bits are used.
>
> This patch changes mode and mode_bits to be u32 to allow for more mode
> configurations.
>
> This patch also creates SPI_LSBYTE_FIRST mode to allow SPI clients to
> choose LSByte order or MSByte order through the device tree property
> spi-lsbyte-first.
Please submit one patch per change, each with a clear changelog, as
covered in SubmittingPatches. This makes it much easier to review
things since it's easier to tell if the patch does what it was intended
to do and means that if one part of the patch casues problems it won't
hold up the other parts.
On Thu, Apr 04, 2019 at 05:14:18PM -0700, Sowjanya Komatineni wrote:
> Tegra SPI controller has TX and RX trimmers to tuning the delay of
> SPI master clock with respect to the data.
Please use subject lines matching the style for the subsystem. This
makes it easier for people to identify relevant patches.
The patch
spi: document tx/rx clock delay properties
has been applied to the spi tree at
https://git.kernel.org/pub/scm/linux/kernel/git/broonie/spi.git
All being well this means that it will be integrated into the linux-next
tree (usually sometime in the next 24 hours) and sent to Linus during
the next merge window (or sooner if it is a bug fix), however if
problems are discovered then the patch may be dropped or reverted.
You may get further e-mails resulting from automated or manual testing
and review of the tree, please engage with people reporting problems and
send followup patches addressing any issues that are reported if needed.
If any updates are required or you are submitting further changes they
should be sent as incremental updates against current git, existing
patches will not be replaced.
Please add any relevant lists and maintainers to the CCs when replying
to this mail.
Thanks,
Mark
From 7558f978f9b66a2bc284a0e8c0764b88305bc29f Mon Sep 17 00:00:00 2001
From: Sowjanya Komatineni <[email protected]>
Date: Thu, 4 Apr 2019 17:14:18 -0700
Subject: [PATCH] spi: document tx/rx clock delay properties
Tegra SPI controller has TX and RX trimmers to tuning the delay of
SPI master clock with respect to the data.
TX and RX tap values are based on the platform validation across the
PVT and the trimmer values vary based on the trace lengths to the
corresponding SPI devices.
Signed-off-by: Sowjanya Komatineni <[email protected]>
Signed-off-by: Mark Brown <[email protected]>
---
.../bindings/spi/nvidia,tegra114-spi.txt | 20 +++++++++++++++++++
1 file changed, 20 insertions(+)
diff --git a/Documentation/devicetree/bindings/spi/nvidia,tegra114-spi.txt b/Documentation/devicetree/bindings/spi/nvidia,tegra114-spi.txt
index 9ba7c5a273b4..db8e0d71c5bc 100644
--- a/Documentation/devicetree/bindings/spi/nvidia,tegra114-spi.txt
+++ b/Documentation/devicetree/bindings/spi/nvidia,tegra114-spi.txt
@@ -23,6 +23,18 @@ Required properties:
Recommended properties:
- spi-max-frequency: Definition as per
Documentation/devicetree/bindings/spi/spi-bus.txt
+Optional properties:
+- nvidia,tx-clk-tap-delay: Delays the clock going out to the external device
+ with this tap value. This property is used to tune the outgoing data from
+ Tegra SPI master with respect to outgoing Tegra SPI master clock.
+ Tap values vary based on the platform design trace lengths from Tegra SPI
+ to corresponding slave devices. Valid tap values are from 0 thru 63.
+- nvidia,rx-clk-tap-delay: Delays the clock coming in from the external device
+ with this tap value. This property is used to adjust the Tegra SPI master
+ clock with respect to the data from the SPI slave device.
+ Tap values vary based on the platform design trace lengths from Tegra SPI
+ to corresponding slave devices. Valid tap values are from 0 thru 63.
+
Example:
spi@7000d600 {
@@ -38,4 +50,12 @@ spi@7000d600 {
reset-names = "spi";
dmas = <&apbdma 16>, <&apbdma 16>;
dma-names = "rx", "tx";
+ <spi-client>@<bus_num> {
+ ...
+ ...
+ nvidia,rx-clk-tap-delay = <0>;
+ nvidia,tx-clk-tap-delay = <16>;
+ ...
+ };
+
};
--
2.20.1
The patch
spi: add a method for configuring CS timing
has been applied to the spi tree at
https://git.kernel.org/pub/scm/linux/kernel/git/broonie/spi.git
All being well this means that it will be integrated into the linux-next
tree (usually sometime in the next 24 hours) and sent to Linus during
the next merge window (or sooner if it is a bug fix), however if
problems are discovered then the patch may be dropped or reverted.
You may get further e-mails resulting from automated or manual testing
and review of the tree, please engage with people reporting problems and
send followup patches addressing any issues that are reported if needed.
If any updates are required or you are submitting further changes they
should be sent as incremental updates against current git, existing
patches will not be replaced.
Please add any relevant lists and maintainers to the CCs when replying
to this mail.
Thanks,
Mark
From f1ca9992ced71029735784de138f53446363087f Mon Sep 17 00:00:00 2001
From: Sowjanya Komatineni <[email protected]>
Date: Thu, 4 Apr 2019 17:14:16 -0700
Subject: [PATCH] spi: add a method for configuring CS timing
This patch creates set_cs_timing SPI master optional method for
SPI masters to implement configuring CS timing if applicable.
This patch also creates spi_cs_timing accessory for SPI clients to
use for requesting SPI master controllers to configure device requested
CS setup time, hold time and inactive delay.
Signed-off-by: Sowjanya Komatineni <[email protected]>
Signed-off-by: Mark Brown <[email protected]>
---
drivers/spi/spi.c | 15 +++++++++++++++
include/linux/spi/spi.h | 15 +++++++++++++++
2 files changed, 30 insertions(+)
diff --git a/drivers/spi/spi.c b/drivers/spi/spi.c
index fd1372fe0505..bf4027b54a19 100644
--- a/drivers/spi/spi.c
+++ b/drivers/spi/spi.c
@@ -2995,6 +2995,21 @@ int spi_setup(struct spi_device *spi)
}
EXPORT_SYMBOL_GPL(spi_setup);
+/**
+ * spi_set_cs_timing - configure CS setup, hold, and inactive delays
+ * @spi: the device that requires specific CS timing configuration
+ * @setup: CS setup time in terms of clock count
+ * @hold: CS hold time in terms of clock count
+ * @inactive_dly: CS inactive delay between transfers in terms of clock count
+ */
+void spi_set_cs_timing(struct spi_device *spi, u8 setup, u8 hold,
+ u8 inactive_dly)
+{
+ if (spi->controller->set_cs_timing)
+ spi->controller->set_cs_timing(spi, setup, hold, inactive_dly);
+}
+EXPORT_SYMBOL_GPL(spi_set_cs_timing);
+
static int __spi_validate(struct spi_device *spi, struct spi_message *message)
{
struct spi_controller *ctlr = spi->controller;
diff --git a/include/linux/spi/spi.h b/include/linux/spi/spi.h
index a0975cf76cf6..589f9dc9ac2b 100644
--- a/include/linux/spi/spi.h
+++ b/include/linux/spi/spi.h
@@ -330,6 +330,9 @@ static inline void spi_unregister_driver(struct spi_driver *sdrv)
* must fail if an unrecognized or unsupported mode is requested.
* It's always safe to call this unless transfers are pending on
* the device whose settings are being modified.
+ * @set_cs_timing: optional hook for SPI devices to request SPI master
+ * controller for configuring specific CS setup time, hold time and inactive
+ * delay interms of clock counts
* @transfer: adds a message to the controller's transfer queue.
* @cleanup: frees controller-specific state
* @can_dma: determine whether this controller supports DMA
@@ -363,6 +366,7 @@ static inline void spi_unregister_driver(struct spi_driver *sdrv)
* @unprepare_transfer_hardware: there are currently no more messages on the
* queue so the subsystem notifies the driver that it may relax the
* hardware by issuing this call
+ *
* @set_cs: set the logic level of the chip select line. May be called
* from interrupt context.
* @prepare_message: set up the controller to transfer a single message,
@@ -488,6 +492,17 @@ struct spi_controller {
*/
int (*setup)(struct spi_device *spi);
+ /*
+ * set_cs_timing() method is for SPI controllers that supports
+ * configuring CS timing.
+ *
+ * This hook allows SPI client drivers to request SPI controllers
+ * to configure specific CS timing through spi_set_cs_timing() after
+ * spi_setup().
+ */
+ void (*set_cs_timing)(struct spi_device *spi, u8 setup_clk_cycles,
+ u8 hold_clk_cycles, u8 inactive_clk_cycles);
+
/* bidirectional bulk transfers
*
* + The transfer() method may not sleep; its main role is
--
2.20.1
The patch
spi-summary: document set_cs_timing
has been applied to the spi tree at
https://git.kernel.org/pub/scm/linux/kernel/git/broonie/spi.git
All being well this means that it will be integrated into the linux-next
tree (usually sometime in the next 24 hours) and sent to Linus during
the next merge window (or sooner if it is a bug fix), however if
problems are discovered then the patch may be dropped or reverted.
You may get further e-mails resulting from automated or manual testing
and review of the tree, please engage with people reporting problems and
send followup patches addressing any issues that are reported if needed.
If any updates are required or you are submitting further changes they
should be sent as incremental updates against current git, existing
patches will not be replaced.
Please add any relevant lists and maintainers to the CCs when replying
to this mail.
Thanks,
Mark
From 24496da6927fa7399f7f60ab31b4cea27ec3ed00 Mon Sep 17 00:00:00 2001
From: Sowjanya Komatineni <[email protected]>
Date: Thu, 4 Apr 2019 17:14:15 -0700
Subject: [PATCH] spi-summary: document set_cs_timing
This patch documents set_cs_timing SPI master method.
Signed-off-by: Sowjanya Komatineni <[email protected]>
Signed-off-by: Mark Brown <[email protected]>
---
Documentation/spi/spi-summary | 6 ++++++
1 file changed, 6 insertions(+)
diff --git a/Documentation/spi/spi-summary b/Documentation/spi/spi-summary
index 1721c1b570c3..1a63194b74d7 100644
--- a/Documentation/spi/spi-summary
+++ b/Documentation/spi/spi-summary
@@ -572,6 +572,12 @@ SPI MASTER METHODS
0: transfer is finished
1: transfer is still in progress
+ master->set_cs_timing(struct spi_device *spi, u8 setup_clk_cycles,
+ u8 hold_clk_cycles, u8 inactive_clk_cycles)
+ This method allows SPI client drivers to request SPI master controller
+ for configuring device specific CS setup, hold and inactive timing
+ requirements.
+
DEPRECATED METHODS
master->transfer(struct spi_device *spi, struct spi_message *message)
--
2.20.1
The patch
spi: tegra114: add 3 wire transfer mode support
has been applied to the spi tree at
https://git.kernel.org/pub/scm/linux/kernel/git/broonie/spi.git
All being well this means that it will be integrated into the linux-next
tree (usually sometime in the next 24 hours) and sent to Linus during
the next merge window (or sooner if it is a bug fix), however if
problems are discovered then the patch may be dropped or reverted.
You may get further e-mails resulting from automated or manual testing
and review of the tree, please engage with people reporting problems and
send followup patches addressing any issues that are reported if needed.
If any updates are required or you are submitting further changes they
should be sent as incremental updates against current git, existing
patches will not be replaced.
Please add any relevant lists and maintainers to the CCs when replying
to this mail.
Thanks,
Mark
From 9d199231b000414e420a35912760f2d67e9c56d7 Mon Sep 17 00:00:00 2001
From: Sowjanya Komatineni <[email protected]>
Date: Thu, 4 Apr 2019 17:14:08 -0700
Subject: [PATCH] spi: tegra114: add 3 wire transfer mode support
This patch adds 3 wire transfer support to SPI mode list along with
its implementation.
3 wire or Bi-directional mode uses only one serial data pin for the
transfer. SPI in master mode uses MOSI data line only and MISO data
line is not used.
Signed-off-by: Sowjanya Komatineni <[email protected]>
Signed-off-by: Mark Brown <[email protected]>
---
drivers/spi/spi-tegra114.c | 7 ++++++-
1 file changed, 6 insertions(+), 1 deletion(-)
diff --git a/drivers/spi/spi-tegra114.c b/drivers/spi/spi-tegra114.c
index 1e749ce13029..751672b3bc16 100644
--- a/drivers/spi/spi-tegra114.c
+++ b/drivers/spi/spi-tegra114.c
@@ -754,6 +754,11 @@ static u32 tegra_spi_setup_transfer_one(struct spi_device *spi,
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);
@@ -1158,7 +1163,7 @@ static int tegra_spi_probe(struct platform_device *pdev)
/* the spi->mode bits understood by this driver: */
master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH | SPI_LSB_FIRST |
- SPI_TX_DUAL | SPI_RX_DUAL;
+ 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;
--
2.20.1
The patch
spi: tegra114: add dual mode support
has been applied to the spi tree at
https://git.kernel.org/pub/scm/linux/kernel/git/broonie/spi.git
All being well this means that it will be integrated into the linux-next
tree (usually sometime in the next 24 hours) and sent to Linus during
the next merge window (or sooner if it is a bug fix), however if
problems are discovered then the patch may be dropped or reverted.
You may get further e-mails resulting from automated or manual testing
and review of the tree, please engage with people reporting problems and
send followup patches addressing any issues that are reported if needed.
If any updates are required or you are submitting further changes they
should be sent as incremental updates against current git, existing
patches will not be replaced.
Please add any relevant lists and maintainers to the CCs when replying
to this mail.
Thanks,
Mark
From 9877a347f2056f7aa4e770de9a20048ad288f545 Mon Sep 17 00:00:00 2001
From: Sowjanya Komatineni <[email protected]>
Date: Thu, 4 Apr 2019 17:14:07 -0700
Subject: [PATCH] spi: tegra114: add dual mode support
This patch adds support for dual mode SPI transfer.
Dual mode uses both MOSI and MISO lines in parallel where the data
is interleaved on MOSI and MISO lines increasing the throughput.
Packet from Tx FIFO is transmitted on both MOSI and MISO lines and
packet to Rx FIFO is received from both MOSI and MISO lines. Even
bits are transmitted or received on the MOSI data line and odd bits
are transmitted or received on the MISO data line.
Signed-off-by: Sowjanya Komatineni <[email protected]>
Signed-off-by: Mark Brown <[email protected]>
---
drivers/spi/spi-tegra114.c | 8 +++++++-
1 file changed, 7 insertions(+), 1 deletion(-)
diff --git a/drivers/spi/spi-tegra114.c b/drivers/spi/spi-tegra114.c
index 402799c7f6b7..1e749ce13029 100644
--- a/drivers/spi/spi-tegra114.c
+++ b/drivers/spi/spi-tegra114.c
@@ -786,6 +786,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
@@ -1152,7 +1157,8 @@ 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 | SPI_LSB_FIRST;
+ master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH | SPI_LSB_FIRST |
+ SPI_TX_DUAL | SPI_RX_DUAL;
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;
--
2.20.1
> On Thu, Apr 04, 2019 at 05:14:10PM -0700, Sowjanya Komatineni wrote:
> > Some SPI Master controllers support configuring Least significant byte
> > first or Most significant byte first order for transfers. Also some
> > SPI slave devices expect bytes to be in Least significant first order
> > and some devices expect Most significant first order.
> >
> > SPI driver declares mode and mode_bits as u16 and all bits are used.
> >
> > This patch changes mode and mode_bits to be u32 to allow for more mode
> > configurations.
> >
> > This patch also creates SPI_LSBYTE_FIRST mode to allow SPI clients to
> > choose LSByte order or MSByte order through the device tree property
> > spi-lsbyte-first.
>
> Please submit one patch per change, each with a clear changelog, as covered in SubmittingPatches. This makes it much easier to review things since it's easier to tell if the patch does what it was intended to do and means that if one part of the patch casues problems it won't hold up the other parts.
Hi Mark,
I split changes on SPI code side and SPI Tegra side as separate patches.
Do you meant to have both changes on SPI core and SPI Tegra together in a single patch?
Thanks
Sowjanya
On Thu, Apr 11, 2019 at 07:58:33PM +0000, Sowjanya Komatineni wrote:
> > On Thu, Apr 04, 2019 at 05:14:10PM -0700, Sowjanya Komatineni wrote:
> > > Some SPI Master controllers support configuring Least significant byte
> > > first or Most significant byte first order for transfers. Also some
> > > SPI slave devices expect bytes to be in Least significant first order
> > > and some devices expect Most significant first order.
> > > SPI driver declares mode and mode_bits as u16 and all bits are used.
> > > This patch changes mode and mode_bits to be u32 to allow for more mode
> > > configurations.
> > > This patch also creates SPI_LSBYTE_FIRST mode to allow SPI clients to
> > > choose LSByte order or MSByte order through the device tree property
> > > spi-lsbyte-first.
> > Please submit one patch per change, each with a clear changelog, as covered in SubmittingPatches. This makes it much easier to review things since it's easier to tell if the patch does what it was intended to do and means that if one part of the patch casues problems it won't hold up the other parts.
> I split changes on SPI code side and SPI Tegra side as separate patches.
> Do you meant to have both changes on SPI core and SPI Tegra together in a single patch?
You are expanding the size of the mode variable and adding a new mode in
the same patch. These are two separate changes and should be in two
separate patches, as soon as you start writing "Also..." in a changelog
that should be a warning flag.
Please fix your mail client to word wrap within paragraphs at something
substantially less than 80 columns. Doing this makes your messages much
easier to read and reply to.