[V3] : This patch series version includes
- only patches that are not applied from V2.
- splitted expanding mode and adding LSByte First support
in separate patches and removed DT property for selecting
LSByte First.
- Updated GPIO based chip select control to use spi_set_cs
from SPI core.
- HW based chip select implementation is same as V2 but V3
has this patch updated to be on top of above changes.
- HW CS timing implementation is same as V2 but V3
has this patch updated to be on top of above changes.
- support for TX and RX trimmers implementation is same as V2
but V3 has this patch updated to be on top of above changes
and updated commit description.
[V2] : This patch series version includes
- only patches that are not applied from V1.
- changed order of patches to include all fixes prior to new features
support.
- Removed HW CS timing from DT properties and created set_cs_timing
SPI master optional method for SPI controllers to implement and
created API spi_cs_timing for SPI client drivers to request CS
setup, hold and inactive delay timing configuration.
- Fixed HW based CS decision to be based on single transfer and
cs_change. Remove selection of HW based CS through DT.
Sowjanya Komatineni (9):
spi: tegra114: fix PIO transfer
spi: expand mode support
spi: add SPI_LSBYTE_FIRST mode
spi: tegra114: add support for Tegra SPI LSBYTE_FIRST
spi: export spi core function spi_set_cs
spi: tegra114: add support for gpio based CS
spi: tegra114: add support for hw based cs
spi: tegra114: add support for HW CS timing
spi: tegra114: add support for TX and RX trimmers
drivers/spi/spi-tegra114.c | 175 ++++++++++++++++++++++++++++++++++++++++-----
drivers/spi/spi.c | 21 +++---
include/linux/spi/spi.h | 8 ++-
3 files changed, 174 insertions(+), 30 deletions(-)
--
2.7.4
This patch changes mode and mode_bits from u16 to u32 to allow more
mode configurations.
Signed-off-by: Sowjanya Komatineni <[email protected]>
---
include/linux/spi/spi.h | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/include/linux/spi/spi.h b/include/linux/spi/spi.h
index 589f9dc9ac2b..053abd22ad31 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) */
@@ -443,7 +443,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;
@@ -1291,7 +1291,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
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 | 39 +++++++++++++++++++++++++++------------
1 file changed, 27 insertions(+), 12 deletions(-)
diff --git a/drivers/spi/spi-tegra114.c b/drivers/spi/spi-tegra114.c
index 0b04eba242c0..732347d83366 100644
--- a/drivers/spi/spi-tegra114.c
+++ b/drivers/spi/spi-tegra114.c
@@ -193,6 +193,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;
@@ -723,7 +724,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);
u32 speed = t->speed_hz;
@@ -784,11 +786,17 @@ static u32 tegra_spi_setup_transfer_one(struct spi_device *spi,
/* GPIO based chip select control */
spi_set_cs(spi, true);
- 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;
+ }
tegra_spi_writel(tspi, 0, SPI_COMMAND2);
} else {
@@ -905,11 +913,15 @@ static void tegra_spi_transfer_end(struct spi_device *spi)
/* GPIO based chip select control */
spi_set_cs(spi, false);
- 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);
}
@@ -936,16 +948,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
Tegra SPI master controller has programmable trimmers to adjust the
data with respect to the clock.
These trimmers are programmed in TX_CLK_TAP_DELAY and RX_CLK_TAP_DELAY
fields of COMMAND2 register.
SPI TX trimmer is to adjust the outgoing data with respect to the
outgoing clock and SPI RX trimmer is to adjust the loopback clock with
respect to the incoming data from the slave device.
These trimmers vary based on trace lengths of the platform design for
each of the slaves on the SPI bus and optimal value programmed is from
the platform validation across PVT.
This patch adds support for configuring TX and RX clock delay trimmers
through the device tree properties.
Signed-off-by: Sowjanya Komatineni <[email protected]>
---
drivers/spi/spi-tegra114.c | 68 +++++++++++++++++++++++++++++++++++++++++++++-
1 file changed, 67 insertions(+), 1 deletion(-)
diff --git a/drivers/spi/spi-tegra114.c b/drivers/spi/spi-tegra114.c
index 8476a38cf4fb..20a413aef133 100644
--- a/drivers/spi/spi-tegra114.c
+++ b/drivers/spi/spi-tegra114.c
@@ -169,6 +169,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_data {
struct device *dev;
struct spi_master *master;
@@ -208,8 +213,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;
@@ -769,10 +776,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;
u32 speed = t->speed_hz;
u8 bits_per_word = t->bits_per_word;
u32 command1;
+ u32 command2;
int req_mode;
+ u32 tx_tap = 0, rx_tap = 0;
if (speed != tspi->cur_speed) {
clk_set_rate(tspi->clk, speed);
@@ -839,7 +849,18 @@ static u32 tegra_spi_setup_transfer_one(struct spi_device *spi,
command1 &= ~SPI_CS_SW_VAL;
}
- tegra_spi_writel(tspi, 0, SPI_COMMAND2);
+ 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;
+ }
+
} else {
command1 = tspi->command1_reg;
command1 &= ~SPI_BIT_LENGTH(~0);
@@ -895,9 +916,42 @@ 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_data *cdata = spi->controller_data;
+
+ 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;
u32 val;
unsigned long flags;
int ret;
@@ -908,6 +962,11 @@ static int tegra_spi_setup(struct spi_device *spi)
spi->mode & SPI_CPHA ? "" : "~",
spi->max_speed_hz);
+ if (!cdata) {
+ cdata = tegra_spi_parse_cdata_dt(spi);
+ spi->controller_data = cdata;
+ }
+
ret = pm_runtime_get_sync(tspi->dev);
if (ret < 0) {
dev_err(tspi->dev, "pm runtime failed, e = %d\n", ret);
@@ -1034,6 +1093,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;
}
@@ -1089,6 +1149,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;
}
@@ -1164,6 +1225,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;
}
@@ -1351,6 +1413,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,
@@ -1423,6 +1487,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 exports spi_set_cs of the spi core to allow SPI masters
to use when gpio based chip select is needed.
Signed-off-by: Sowjanya Komatineni <[email protected]>
---
drivers/spi/spi.c | 3 ++-
include/linux/spi/spi.h | 1 +
2 files changed, 3 insertions(+), 1 deletion(-)
diff --git a/drivers/spi/spi.c b/drivers/spi/spi.c
index 59b1e57cae74..fa70e595f17a 100644
--- a/drivers/spi/spi.c
+++ b/drivers/spi/spi.c
@@ -773,7 +773,7 @@ int spi_register_board_info(struct spi_board_info const *info, unsigned n)
/*-------------------------------------------------------------------------*/
-static void spi_set_cs(struct spi_device *spi, bool enable)
+void spi_set_cs(struct spi_device *spi, bool enable)
{
if (spi->mode & SPI_CS_HIGH)
enable = !enable;
@@ -801,6 +801,7 @@ static void spi_set_cs(struct spi_device *spi, bool enable)
spi->controller->set_cs(spi, !enable);
}
}
+EXPORT_SYMBOL_GPL(spi_set_cs);
#ifdef CONFIG_HAS_DMA
int spi_map_buf(struct spi_controller *ctlr, struct device *dev,
diff --git a/include/linux/spi/spi.h b/include/linux/spi/spi.h
index fc4d21b4c2e4..c7ca95f26725 100644
--- a/include/linux/spi/spi.h
+++ b/include/linux/spi/spi.h
@@ -973,6 +973,7 @@ extern int spi_async(struct spi_device *spi, struct spi_message *message);
extern int spi_async_locked(struct spi_device *spi,
struct spi_message *message);
extern int spi_slave_abort(struct spi_device *spi);
+extern void spi_set_cs(struct spi_device *spi, bool enable);
static inline size_t
spi_max_message_size(struct spi_device *spi)
--
2.7.4
Tegra SPI master controller supports configuring least significant
first byte order or most significant first byte order for transfers.
This patch adds SPI_LSBYTE_FIRST to supported mode list and also
configures byte order based on the mode request for transfer.
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 b1f31bb16659..f4e39eb3857c 100644
--- a/drivers/spi/spi-tegra114.c
+++ b/drivers/spi/spi-tegra114.c
@@ -764,6 +764,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
@@ -1200,7 +1205,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
Some SPI slaves expect bytes to be in least significant first order
and some expects most significant first oder.
This patch adds support for requesting SPI master controllers for
least significant first order using SPI_LSBYTE_FIRST mode.
Signed-off-by: Sowjanya Komatineni <[email protected]>
---
drivers/spi/spi.c | 18 ++++++++++--------
include/linux/spi/spi.h | 1 +
2 files changed, 11 insertions(+), 8 deletions(-)
diff --git a/drivers/spi/spi.c b/drivers/spi/spi.c
index bf4027b54a19..59b1e57cae74 100644
--- a/drivers/spi/spi.c
+++ b/drivers/spi/spi.c
@@ -2982,14 +2982,16 @@ 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",
- (int) (spi->mode & (SPI_CPOL | SPI_CPHA)),
- (spi->mode & SPI_CS_HIGH) ? "cs_high, " : "",
- (spi->mode & SPI_LSB_FIRST) ? "lsb, " : "",
- (spi->mode & SPI_3WIRE) ? "3wire, " : "",
- (spi->mode & SPI_LOOP) ? "loopback, " : "",
- spi->bits_per_word, spi->max_speed_hz,
- status);
+ 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,
+ status);
return status;
}
diff --git a/include/linux/spi/spi.h b/include/linux/spi/spi.h
index 053abd22ad31..fc4d21b4c2e4 100644
--- a/include/linux/spi/spi.h
+++ b/include/linux/spi/spi.h
@@ -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;
--
2.7.4
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 b8c6393e2190..b1f31bb16659 100644
--- a/drivers/spi/spi-tegra114.c
+++ b/drivers/spi/spi-tegra114.c
@@ -651,8 +651,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 support for GPIO based CS control through SPI core
function spi_set_cs.
Signed-off-by: Sowjanya Komatineni <[email protected]>
---
drivers/spi/spi-tegra114.c | 7 +++++++
1 file changed, 7 insertions(+)
diff --git a/drivers/spi/spi-tegra114.c b/drivers/spi/spi-tegra114.c
index f4e39eb3857c..0b04eba242c0 100644
--- a/drivers/spi/spi-tegra114.c
+++ b/drivers/spi/spi-tegra114.c
@@ -781,6 +781,9 @@ static u32 tegra_spi_setup_transfer_one(struct spi_device *spi,
} else
tegra_spi_writel(tspi, command1, SPI_COMMAND1);
+ /* GPIO based chip select control */
+ spi_set_cs(spi, true);
+
command1 |= SPI_CS_SW_HW;
if (spi->mode & SPI_CS_HIGH)
command1 |= SPI_CS_SW_VAL;
@@ -869,6 +872,8 @@ static int tegra_spi_setup(struct spi_device *spi)
}
spin_lock_irqsave(&tspi->lock, flags);
+ /* GPIO based chip select control */
+ spi_set_cs(spi, false);
val = tspi->def_command1_reg;
if (spi->mode & SPI_CS_HIGH)
val &= ~SPI_CS_POL_INACTIVE(spi->chip_select);
@@ -898,6 +903,8 @@ 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;
+ /* GPIO based chip select control */
+ spi_set_cs(spi, false);
if (cs_val)
tspi->command1_reg |= SPI_CS_SW_VAL;
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 732347d83366..8476a38cf4fb 100644
--- a/drivers/spi/spi-tegra114.c
+++ b/drivers/spi/spi-tegra114.c
@@ -95,8 +95,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)
@@ -206,6 +208,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;
@@ -723,6 +727,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)
@@ -1232,6 +1273,7 @@ static int tegra_spi_probe(struct platform_device *pdev)
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->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");
@@ -1307,6 +1349,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
The patch
spi: tegra114: fix PIO transfer
has been applied to the spi tree at
https://git.kernel.org/pub/scm/linux/kernel/git/broonie/spi.git for-5.1
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 3f6e3f7843a6a1667ed890ca51a1388fc7bf3429 Mon Sep 17 00:00:00 2001
From: Sowjanya Komatineni <[email protected]>
Date: Mon, 15 Apr 2019 14:30:26 -0700
Subject: [PATCH] spi: tegra114: fix PIO transfer
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]>
Signed-off-by: Mark Brown <[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 b57f10182fae..21e4fdad013f 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.20.1
The patch
spi: expand mode support
has been applied to the spi tree at
https://git.kernel.org/pub/scm/linux/kernel/git/broonie/spi.git for-5.2
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 4b490710d4d24f95e95a07baac6f3f98bb94cf3b Mon Sep 17 00:00:00 2001
From: Sowjanya Komatineni <[email protected]>
Date: Mon, 15 Apr 2019 14:30:27 -0700
Subject: [PATCH] spi: expand mode support
This patch changes mode and mode_bits from u16 to u32 to allow more
mode configurations.
Signed-off-by: Sowjanya Komatineni <[email protected]>
Signed-off-by: Mark Brown <[email protected]>
---
include/linux/spi/spi.h | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/include/linux/spi/spi.h b/include/linux/spi/spi.h
index 589f9dc9ac2b..053abd22ad31 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) */
@@ -443,7 +443,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;
@@ -1291,7 +1291,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.20.1
On Mon, Apr 15, 2019 at 02:30:30PM -0700, Sowjanya Komatineni wrote:
> This patch exports spi_set_cs of the spi core to allow SPI masters
> to use when gpio based chip select is needed.
This isn't really what I meant when I said it'd be good to use the core
GPIO code - this function doesn't do a huge amount really and the usage
of it in your subsequent patch for the driver isn't exactly joined up
with the little it does (which is mainly swapping in the GPIO chip
select instead of the hardware chip select) isn't used in your driver
usage of this as far as I can see. The bulk of the chip select handling
code in the core is actually in transfer_one_message() which your driver
doesn't use as it's got it's own implementation of that; I've not looked
in enough detail to figure out if it could use it.
On Mon, Apr 15, 2019 at 02:30:28PM -0700, Sowjanya Komatineni wrote:
> Some SPI slaves expect bytes to be in least significant first order
> and some expects most significant first oder.
>
> This patch adds support for requesting SPI master controllers for
> least significant first order using SPI_LSBYTE_FIRST mode.
This is byte ordering as opposed to bit ordering which the core already
supports. Do you have any examples of devices that need this or is it
just being added for completeness? If devices are going to rely on this
we probably need emulation support in the core I guess given that this
is a pretty unusual controller feature.
> On Mon, Apr 15, 2019 at 02:30:28PM -0700, Sowjanya Komatineni wrote:
> > Some SPI slaves expect bytes to be in least significant first order
> > and some expects most significant first oder.
> >
> > This patch adds support for requesting SPI master controllers for
> > least significant first order using SPI_LSBYTE_FIRST mode.
>
> This is byte ordering as opposed to bit ordering which the core already supports. Do you have any examples of devices that need this or is it just being added for completeness? If devices are going to rely on this we probably need emulation > support in the core I guess given that this is a pretty unusual controller feature.
Current upstream platforms have no specific device requirement but added this feature as Tegra support it for specific requirements of some slaves.
[Changed mail client message format word wrap limit to 74 columns]
Thanks
Sowjanya
Hi Mark,
I don't see below patches that I see as applied in latest linux-next.
Can you please confirm if they are applied?
Applied "spi: tegra114: fix PIO transfer" to the spi tree
Applied "spi: expand mode support" to the spi tree
Thanks
Sowjanya
> The patch
> spi: tegra114: fix PIO transfer
> has been applied to the spi tree at
> https://git.kernel.org/pub/scm/linux/kernel/git/broonie/spi.git for-5.1
> 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 3f6e3f7843a6a1667ed890ca51a1388fc7bf3429 Mon Sep 17 00:00:00 2001
> From: Sowjanya Komatineni <[email protected]>
> Date: Mon, 15 Apr 2019 14:30:26 -0700
> Subject: [PATCH] spi: tegra114: fix PIO transfer
>
> 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]>
> Signed-off-by: Mark Brown <[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 b57f10182fae..21e4fdad013f 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.20.1
> On Mon, Apr 15, 2019 at 02:30:30PM -0700, Sowjanya Komatineni wrote:
> > This patch exports spi_set_cs of the spi core to allow SPI masters to
> > use when gpio based chip select is needed.
>
> This isn't really what I meant when I said it'd be good to use the core GPIO code - this function doesn't do a huge amount really and the usage of it in your subsequent patch for the > driver isn't exactly joined up with the little it does (which is mainly swapping in the GPIO chip select instead of the hardware chip select) isn't used in your driver usage of this as far as I can see. The bulk of the chip select handling code in the core is actually in transfer_one_message() which your driver doesn't use as it's got it's own implementation of that; I've not looked in enough detail to figure out if it could use it.
>
>
>
In SPI Tegra driver, we wanted to have GPIO based CS control when cs-gpios is specified in parallel to HW/SW CS. Having parallel GPIO based CS is to mimic some of the timing stuff that's needed for some spi devices by not actually using HW CS on platform but only for SPI HW design logic inside the chip.
Tegra spi driver don't use set_cs callback so looking into spi_set_cs from spi core implementation when cs-gpios property is used it exactly the same that is needed for GPIO control CS. So used this in V3.
Can you please provide more details on what you are suggesting?
Do you prefer not to use SPI core spi_set_cs and gpio_set_values APIs and instead implement in tegra SPI driver using GPIO descriptors ?
Thanks
Sowjanya
The patch
spi: expand 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 937e6d756422637eeb212c645ded69569a67fabc Mon Sep 17 00:00:00 2001
From: Sowjanya Komatineni <[email protected]>
Date: Mon, 15 Apr 2019 14:30:27 -0700
Subject: [PATCH] spi: expand mode support
This patch changes mode and mode_bits from u16 to u32 to allow more
mode configurations.
Signed-off-by: Sowjanya Komatineni <[email protected]>
Signed-off-by: Mark Brown <[email protected]>
---
include/linux/spi/spi.h | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/include/linux/spi/spi.h b/include/linux/spi/spi.h
index 589f9dc9ac2b..053abd22ad31 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) */
@@ -443,7 +443,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;
@@ -1291,7 +1291,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.20.1
On Mon, Apr 29, 2019 at 09:42:39PM +0000, Sowjanya Komatineni wrote:
> Hi Mark,
>
> I don't see below patches that I see as applied in latest linux-next.
> Can you please confirm if they are applied?
>
> Applied "spi: tegra114: fix PIO transfer" to the spi tree
> Applied "spi: expand mode support" to the spi tree
Check again, they should be restored now.
On Mon, Apr 29, 2019 at 10:02:46PM +0000, Sowjanya Komatineni wrote:
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.
> > On Mon, Apr 15, 2019 at 02:30:30PM -0700, Sowjanya Komatineni wrote:
> > > This patch exports spi_set_cs of the spi core to allow SPI masters to
> > > use when gpio based chip select is needed.
> > This isn't really what I meant when I said it'd be good to use the
> > core GPIO code - this function doesn't do a huge amount really and
> > the usage of it in your subsequent patch for the > driver isn't
> > exactly joined up with the little it does (which is mainly swapping
> > in the GPIO chip select instead of the hardware chip select) isn't
> > used in your driver usage of this as far as I can see. The bulk of
> > the chip select handling code in the core is actually in
> > transfer_one_message() which your driver doesn't use as it's got
> > it's own implementation of that; I've not looked in enough detail to
> > figure out if it could use it.
> In SPI Tegra driver, we wanted to have GPIO based CS control when
> cs-gpios is specified in parallel to HW/SW CS. Having parallel GPIO
> based CS is to mimic some of the timing stuff that's needed for some
> spi devices by not actually using HW CS on platform but only for SPI
> HW design logic inside the chip.
> Tegra spi driver don't use set_cs callback so looking into spi_set_cs
> from spi core implementation when cs-gpios property is used it exactly
> the same that is needed for GPIO control CS. So used this in V3.
> Can you please provide more details on what you are suggesting?
> Do you prefer not to use SPI core spi_set_cs and gpio_set_values APIs
> and instead implement in tegra SPI driver using GPIO descriptors ?
You're probably best open coding in the driver if there's value in using
the hardware chip select.
On Sat, Apr 27, 2019 at 12:32:58AM +0000, Sowjanya Komatineni wrote:
> > On Mon, Apr 15, 2019 at 02:30:28PM -0700, Sowjanya Komatineni wrote:
> > This is byte ordering as opposed to bit ordering which the core
> > already supports. Do you have any examples of devices that need
> > this or is it just being added for completeness? If devices are
> > going to rely on this we probably need emulation > support in the
> > core I guess given that this is a pretty unusual controller feature.
> Current upstream platforms have no specific device requirement but
> added this feature as Tegra support it for specific requirements of
> some slaves.
Do we have any examples of such devices? In any case I think the main
thing here would be a software implementation of the feature so that
drivers can use it sensibly - at the minute they'd have to provide code
to work without the feature anyway and it seems like a relatively small
optimization for most things.
> [Changed mail client message format word wrap limit to 74 columns]
It's not working, and it's also mangling quoted sections of the mail
too.
> On Mon, Apr 29, 2019 at 10:02:46PM +0000, Sowjanya Komatineni wrote:
>
> 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.
>
> > > On Mon, Apr 15, 2019 at 02:30:30PM -0700, Sowjanya Komatineni wrote:
> > > > This patch exports spi_set_cs of the spi core to allow SPI masters
> > > > to use when gpio based chip select is needed.
>
> > > This isn't really what I meant when I said it'd be good to use the
> > > core GPIO code - this function doesn't do a huge amount really and
> > > the usage of it in your subsequent patch for the > driver isn't
> > > exactly joined up with the little it does (which is mainly swapping
> > > in the GPIO chip select instead of the hardware chip select) isn't
> > > used in your driver usage of this as far as I can see. The bulk of
> > > the chip select handling code in the core is actually in
> > > transfer_one_message() which your driver doesn't use as it's got
> > > it's own implementation of that; I've not looked in enough detail to
> > > figure out if it could use it.
>
> > In SPI Tegra driver, we wanted to have GPIO based CS control when
> > cs-gpios is specified in parallel to HW/SW CS. Having parallel GPIO
> > based CS is to mimic some of the timing stuff that's needed for some
> > spi devices by not actually using HW CS on platform but only for SPI
> > HW design logic inside the chip.
>
> > Tegra spi driver don't use set_cs callback so looking into spi_set_cs
> > from spi core implementation when cs-gpios property is used it exactly
> > the same that is needed for GPIO control CS. So used this in V3.
>
> > Can you please provide more details on what you are suggesting?
> > Do you prefer not to use SPI core spi_set_cs and gpio_set_values APIs
> > and instead implement in tegra SPI driver using GPIO descriptors ?
>
> You're probably best open coding in the driver if there's value in using the hardware chip select.
Sorry, Just to be clear on my understanding of your suggestion,
3 ways of CS control implementation is needed for Tegra SPI
- SW CS thru SPI Controller
- HW CS thru SPI Controller
- Direct GPIO based CS control
Patch Series includes both HW CS and also direct GPIO based CS.
Regarding direct GPIO based CS, I understood you prefer to use GPIO descriptors.
I see SPI core set_cs API also uses GPIO descriptor for direct GPIO control of CS.
Tegra SPI driver need parallel implementation of direct gpio based cs to hw/sw based
CS control thru SPI controller.
Since SPI core set_cs already has implementation using gpio descriptors, in V3 I am using
the same API.
Any concerns for using set_cs API from SPI core as it already does direct gpio based cs using
Descriptors?
Thanks
Sowjanya
On Fri, May 10, 2019 at 06:53:25PM +0000, Sowjanya Komatineni wrote:
> > On Mon, Apr 29, 2019 at 10:02:46PM +0000, Sowjanya Komatineni wrote:
To reiterate:
> > 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.
> Any concerns for using set_cs API from SPI core as it already does direct gpio based cs using
> Descriptors?
Yes, that is precisely what I'm telling you not to do. That function
doesn't do enough to make it worth exporting and the code that uses it
assumes it's managing the chip select entirely, adding a single other
use will make things fragile as it will mean that there's a chance
someone will change what the core is doing without taking into account
the different things that the Tegra code is doing. Either let the core
handle chip select entirely or open code it.