From: Esben Haabendal <[email protected]>
This patch series contains a number of fixes and cleanups for the spi-fsl-dspi
driver (commit 1-7), and on top of that, implementation of XSPI mode for
LS1021A allowing for SPI transfers larger than 16 bits (commit 8-12).
User visible changes (improvements) are:
* Support for all transfer sizes between 4 and 16, not just 4 (which I believe
were broken anyway), 8 and 16 bits per word.
* Full support for transfer->cs_change flag. Setting cs_change in last
transfer leaves CS asserted.
* Support for all transfers sizes between 4 and 32 bits per word for LS1021A.
The XSPI mode can be trivially enabled for other target using TCQF mode.
Enable for targets using EOQ mode requires additional work due to the split
of TX FIFO into command and data FIFO.
If you like, I will happily squash the last 5 commits into a single XSPI mode
commit.
Esben Haabendal (12):
spi: spi-fsl-dspi: Drop unreachable else if statement
spi: spi-fsl-dspi: Drop unneeded use of dataflags bits
spi: spi-fsl-dspi: Fix per transfer cs_change handling
spi: spi-fsl-dspi: Simplify transfer counter handling
spi: spi-fsl-dspi: Support 4 to 16 bits per word transfers
spi: spi-fsl-dspi: Fixup regmap configuration
spi: spi-fsl-dspi: Fix MCR register handling
spi: spi-fsl-dspi: Add support for XSPI mode registers
spi: spi-fsl-dspi: Framesize control for XSPI mode
spi: spi-fsl-dspi: XSPI FIFO handling (in TCFQ mode)
spi: spi-fsl-dspi: Advertise 32 bit for XSPI mode
spi: spi-fsl-dspi: Enable extended SPI mode
drivers/spi/spi-fsl-dspi.c | 458 ++++++++++++++++++++-----------------
1 file changed, 250 insertions(+), 208 deletions(-)
--
2.17.1
From: Esben Haabendal <[email protected]>
Signed-off-by: Esben Haabendal <[email protected]>
Cc: Martin Hundebøll <[email protected]>
---
drivers/spi/spi-fsl-dspi.c | 6 +++++-
1 file changed, 5 insertions(+), 1 deletion(-)
diff --git a/drivers/spi/spi-fsl-dspi.c b/drivers/spi/spi-fsl-dspi.c
index 67cd2e901255..eed55491b2c9 100644
--- a/drivers/spi/spi-fsl-dspi.c
+++ b/drivers/spi/spi-fsl-dspi.c
@@ -1001,7 +1001,6 @@ static int dspi_probe(struct platform_device *pdev)
master->cleanup = dspi_cleanup;
master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_LSB_FIRST;
- master->bits_per_word_mask = SPI_BPW_RANGE_MASK(4, 16);
pdata = dev_get_platdata(&pdev->dev);
if (pdata) {
@@ -1033,6 +1032,11 @@ static int dspi_probe(struct platform_device *pdev)
}
}
+ if (dspi->devtype_data->xspi_mode)
+ master->bits_per_word_mask = SPI_BPW_RANGE_MASK(4, 32);
+ else
+ master->bits_per_word_mask = SPI_BPW_RANGE_MASK(4, 16);
+
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
base = devm_ioremap_resource(&pdev->dev, res);
if (IS_ERR(base)) {
--
2.17.1
From: Esben Haabendal <[email protected]>
The MCR register is not changed, so initialize it in dspi_init().
The exception is the CLR_TXF and CLR_RXF bits, which should be written to
before each transfer to make sure we start with empty FIFOs. With MCR
register now configured as volatile, the regmap_update_bits will do a real
read-modify-write cycle.
Signed-off-by: Esben Haabendal <[email protected]>
Cc: Martin Hundebøll <[email protected]>
---
drivers/spi/spi-fsl-dspi.c | 10 +++-------
1 file changed, 3 insertions(+), 7 deletions(-)
diff --git a/drivers/spi/spi-fsl-dspi.c b/drivers/spi/spi-fsl-dspi.c
index 5c5905b6509f..d83d3496d538 100644
--- a/drivers/spi/spi-fsl-dspi.c
+++ b/drivers/spi/spi-fsl-dspi.c
@@ -120,7 +120,6 @@
#define DMA_COMPLETION_TIMEOUT msecs_to_jiffies(3000)
struct chip_data {
- u32 mcr_val;
u32 ctar_val;
u16 void_write_data;
};
@@ -644,10 +643,9 @@ static int dspi_transfer_one_message(struct spi_master *master,
else
dspi->bytes_per_word = 2;
- regmap_write(dspi->regmap, SPI_MCR, dspi->cur_chip->mcr_val);
regmap_update_bits(dspi->regmap, SPI_MCR,
- SPI_MCR_CLR_TXF | SPI_MCR_CLR_RXF,
- SPI_MCR_CLR_TXF | SPI_MCR_CLR_RXF);
+ SPI_MCR_CLR_TXF | SPI_MCR_CLR_RXF,
+ SPI_MCR_CLR_TXF | SPI_MCR_CLR_RXF);
regmap_write(dspi->regmap, SPI_CTAR(0),
dspi->cur_chip->ctar_val |
SPI_FRAME_BITS(transfer->bits_per_word));
@@ -725,9 +723,6 @@ static int dspi_setup(struct spi_device *spi)
sck_cs_delay = pdata->sck_cs_delay;
}
- chip->mcr_val = SPI_MCR_MASTER | SPI_MCR_PCSIS |
- SPI_MCR_CLR_TXF | SPI_MCR_CLR_RXF;
-
chip->void_write_data = 0;
clkrate = clk_get_rate(dspi->clk);
@@ -883,6 +878,7 @@ static const struct regmap_config dspi_regmap_config = {
static void dspi_init(struct fsl_dspi *dspi)
{
+ regmap_write(dspi->regmap, SPI_MCR, SPI_MCR_MASTER | SPI_MCR_PCSIS);
regmap_write(dspi->regmap, SPI_SR, SPI_SR_CLEAR);
}
--
2.17.1
From: Esben Haabendal <[email protected]>
Simplify driver by avoiding counter wrapping by clearing transfer counter
on first SPI transfer per interrupt instead of tracking what it was before.
Signed-off-by: Esben Haabendal <[email protected]>
Cc: Martin Hundebøll <[email protected]>
---
drivers/spi/spi-fsl-dspi.c | 39 ++++++++++++++------------------------
1 file changed, 14 insertions(+), 25 deletions(-)
diff --git a/drivers/spi/spi-fsl-dspi.c b/drivers/spi/spi-fsl-dspi.c
index c0c3b8bf2781..2371b9978e65 100644
--- a/drivers/spi/spi-fsl-dspi.c
+++ b/drivers/spi/spi-fsl-dspi.c
@@ -119,8 +119,6 @@
#define SPI_CS_ASSERT 0x02
#define SPI_CS_DROP 0x04
-#define SPI_TCR_TCNT_MAX 0x10000
-
#define DMA_COMPLETION_TIMEOUT msecs_to_jiffies(3000)
struct chip_data {
@@ -201,7 +199,6 @@ struct fsl_dspi {
wait_queue_head_t waitq;
u32 waitflags;
- u32 spi_tcnt;
struct fsl_dspi_dma *dma;
};
@@ -594,6 +591,10 @@ static int dspi_eoq_write(struct fsl_dspi *dspi)
/* request EOQ flag for last transfer in queue */
dspi_pushr |= SPI_PUSHR_EOQ;
+ /* Clear transfer counter on first transfer (in FIFO) */
+ if (tx_count == 0)
+ dspi_pushr |= SPI_PUSHR_CTCNT;
+
regmap_write(dspi->regmap, SPI_PUSHR, dspi_pushr);
tx_count++;
@@ -635,6 +636,9 @@ static int dspi_tcfq_write(struct fsl_dspi *dspi)
dspi_pushr = dspi_data_to_pushr(dspi, tx_word);
+ /* Clear transfer counter on each transfer */
+ dspi_pushr |= SPI_PUSHR_CTCNT;
+
regmap_write(dspi->regmap, SPI_PUSHR, dspi_pushr);
return tx_word + 1;
@@ -658,10 +662,6 @@ static int dspi_transfer_one_message(struct spi_master *master,
struct spi_transfer *transfer;
int status = 0;
enum dspi_trans_mode trans_mode;
- u32 spi_tcr;
-
- regmap_read(dspi->regmap, SPI_TCR, &spi_tcr);
- dspi->spi_tcnt = SPI_TCR_GET_TCNT(spi_tcr);
message->actual_length = 0;
@@ -831,7 +831,7 @@ static irqreturn_t dspi_interrupt(int irq, void *dev_id)
struct spi_message *msg = dspi->cur_msg;
enum dspi_trans_mode trans_mode;
u32 spi_sr, spi_tcr;
- u32 spi_tcnt, tcnt_diff;
+ u16 spi_tcnt;
int tx_word;
regmap_read(dspi->regmap, SPI_SR, &spi_sr);
@@ -841,26 +841,15 @@ static irqreturn_t dspi_interrupt(int irq, void *dev_id)
if (spi_sr & (SPI_SR_EOQF | SPI_SR_TCFQF)) {
tx_word = is_double_byte_mode(dspi);
+ /* Get transfer counter (in number of SPI transfers). It was
+ * reset to 0 when transfer(s) were started.
+ */
regmap_read(dspi->regmap, SPI_TCR, &spi_tcr);
spi_tcnt = SPI_TCR_GET_TCNT(spi_tcr);
- /*
- * The width of SPI Transfer Counter in SPI_TCR is 16bits,
- * so the max couner is 65535. When the counter reach 65535,
- * it will wrap around, counter reset to zero.
- * spi_tcnt my be less than dspi->spi_tcnt, it means the
- * counter already wrapped around.
- * SPI Transfer Counter is a counter of transmitted frames.
- * The size of frame maybe two bytes.
- */
- tcnt_diff = ((spi_tcnt + SPI_TCR_TCNT_MAX) - dspi->spi_tcnt)
- % SPI_TCR_TCNT_MAX;
- tcnt_diff *= (tx_word + 1);
- if (dspi->dataflags & TRAN_STATE_WORD_ODD_NUM)
- tcnt_diff--;
-
- msg->actual_length += tcnt_diff;
- dspi->spi_tcnt = spi_tcnt;
+ /* Update total number of bytes that were transferred */
+ msg->actual_length += spi_tcnt * (tx_word + 1) -
+ (dspi->dataflags & TRAN_STATE_WORD_ODD_NUM ? 1 : 0);
trans_mode = dspi->devtype_data->trans_mode;
switch (trans_mode) {
--
2.17.1
From: Esben Haabendal <[email protected]>
This prepares for adding support for extended SPI mode (XSPI), by extending
the regmap with the extra SREX and CTAREx registers.
An additional register map is made for allowing 16 bit access to CMD and TX
FIFO of the PUSHR register separately, which is also needed for XSPI mode
support.
Signed-off-by: Esben Haabendal <[email protected]>
Cc: Martin Hundebøll <[email protected]>
---
drivers/spi/spi-fsl-dspi.c | 63 ++++++++++++++++++++++++++++++++++++--
1 file changed, 61 insertions(+), 2 deletions(-)
diff --git a/drivers/spi/spi-fsl-dspi.c b/drivers/spi/spi-fsl-dspi.c
index d83d3496d538..3e9dd645ee54 100644
--- a/drivers/spi/spi-fsl-dspi.c
+++ b/drivers/spi/spi-fsl-dspi.c
@@ -108,11 +108,21 @@
#define SPI_RXFR2 0x84
#define SPI_RXFR3 0x88
+#define SPI_CTARE(x) (0x11c + (((x) & 0x3) * 4))
+#define SPI_CTARE_FMSZE(x) (((x) & 0x1) << 16)
+#define SPI_CTARE_DTCP(x) ((x) & 0x7ff)
+
+#define SPI_SREX 0x13c
+
#define SPI_FRAME_BITS(bits) SPI_CTAR_FMSZ((bits) - 1)
#define SPI_FRAME_BITS_MASK SPI_CTAR_FMSZ(0xf)
#define SPI_FRAME_BITS_16 SPI_CTAR_FMSZ(0xf)
#define SPI_FRAME_BITS_8 SPI_CTAR_FMSZ(0x7)
+/* Register offsets for regmap_pushr */
+#define PUSHR_CMD 0x0
+#define PUSHR_TX 0x2
+
#define SPI_CS_INIT 0x01
#define SPI_CS_ASSERT 0x02
#define SPI_CS_DROP 0x04
@@ -133,6 +143,7 @@ enum dspi_trans_mode {
struct fsl_dspi_devtype_data {
enum dspi_trans_mode trans_mode;
u8 max_clock_factor;
+ bool xspi_mode;
};
static const struct fsl_dspi_devtype_data vf610_data = {
@@ -143,6 +154,7 @@ static const struct fsl_dspi_devtype_data vf610_data = {
static const struct fsl_dspi_devtype_data ls1021a_v1_data = {
.trans_mode = DSPI_TCFQ_MODE,
.max_clock_factor = 8,
+ .xspi_mode = true,
};
static const struct fsl_dspi_devtype_data ls2085a_data = {
@@ -177,6 +189,7 @@ struct fsl_dspi {
struct platform_device *pdev;
struct regmap *regmap;
+ struct regmap *regmap_pushr;
int irq;
struct clk *clk;
@@ -876,6 +889,35 @@ static const struct regmap_config dspi_regmap_config = {
.volatile_table = &dspi_volatile_table,
};
+static const struct regmap_range dspi_xspi_volatile_ranges[] = {
+ regmap_reg_range(SPI_MCR, SPI_TCR),
+ regmap_reg_range(SPI_SR, SPI_SR),
+ regmap_reg_range(SPI_PUSHR, SPI_RXFR3),
+ regmap_reg_range(SPI_SREX, SPI_SREX),
+};
+
+static const struct regmap_access_table dspi_xspi_volatile_table = {
+ .yes_ranges = dspi_xspi_volatile_ranges,
+ .n_yes_ranges = ARRAY_SIZE(dspi_xspi_volatile_ranges),
+};
+
+static const struct regmap_config dspi_xspi_regmap_config[] = {
+ {
+ .reg_bits = 32,
+ .val_bits = 32,
+ .reg_stride = 4,
+ .max_register = 0x13c,
+ .volatile_table = &dspi_xspi_volatile_table,
+ },
+ {
+ .name = "pushr",
+ .reg_bits = 16,
+ .val_bits = 16,
+ .reg_stride = 2,
+ .max_register = 0x2,
+ },
+};
+
static void dspi_init(struct fsl_dspi *dspi)
{
regmap_write(dspi->regmap, SPI_MCR, SPI_MCR_MASTER | SPI_MCR_PCSIS);
@@ -888,6 +930,7 @@ static int dspi_probe(struct platform_device *pdev)
struct spi_master *master;
struct fsl_dspi *dspi;
struct resource *res;
+ const struct regmap_config *regmap_config;
void __iomem *base;
struct fsl_dspi_platform_data *pdata;
int ret = 0, cs_num, bus_num;
@@ -946,8 +989,11 @@ static int dspi_probe(struct platform_device *pdev)
goto out_master_put;
}
- dspi->regmap = devm_regmap_init_mmio_clk(&pdev->dev, NULL, base,
- &dspi_regmap_config);
+ if (dspi->devtype_data->xspi_mode)
+ regmap_config = &dspi_xspi_regmap_config[0];
+ else
+ regmap_config = &dspi_regmap_config;
+ dspi->regmap = devm_regmap_init_mmio(&pdev->dev, base, regmap_config);
if (IS_ERR(dspi->regmap)) {
dev_err(&pdev->dev, "failed to init regmap: %ld\n",
PTR_ERR(dspi->regmap));
@@ -955,6 +1001,19 @@ static int dspi_probe(struct platform_device *pdev)
goto out_master_put;
}
+ if (dspi->devtype_data->xspi_mode) {
+ dspi->regmap_pushr = devm_regmap_init_mmio(
+ &pdev->dev, base + SPI_PUSHR,
+ &dspi_xspi_regmap_config[1]);
+ if (IS_ERR(dspi->regmap_pushr)) {
+ dev_err(&pdev->dev,
+ "failed to init pushr regmap: %ld\n",
+ PTR_ERR(dspi->regmap_pushr));
+ ret = PTR_ERR(dspi->regmap);
+ goto out_master_put;
+ }
+ }
+
dspi_init(dspi);
dspi->irq = platform_get_irq(pdev, 0);
if (dspi->irq < 0) {
--
2.17.1
From: Esben Haabendal <[email protected]>
Set the XSPI bit for devices configured for XSPI mode (currently LS1021A),
and thereby switch to extended SPI mode, allowing for SPI transfers using
from 4 to 32 bits per word instead of 4 to 16 bits per word.
Signed-off-by: Esben Haabendal <[email protected]>
Cc: Martin Hundebøll <[email protected]>
---
drivers/spi/spi-fsl-dspi.c | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/drivers/spi/spi-fsl-dspi.c b/drivers/spi/spi-fsl-dspi.c
index eed55491b2c9..1f85dcdb2203 100644
--- a/drivers/spi/spi-fsl-dspi.c
+++ b/drivers/spi/spi-fsl-dspi.c
@@ -46,6 +46,7 @@
#define SPI_MCR_PCSIS (0x3F << 16)
#define SPI_MCR_CLR_TXF (1 << 11)
#define SPI_MCR_CLR_RXF (1 << 10)
+#define SPI_MCR_XSPI (1 << 3)
#define SPI_TCR 0x08
#define SPI_TCR_GET_TCNT(x) (((x) & 0xffff0000) >> 16)
@@ -968,7 +969,8 @@ static const struct regmap_config dspi_xspi_regmap_config[] = {
static void dspi_init(struct fsl_dspi *dspi)
{
- regmap_write(dspi->regmap, SPI_MCR, SPI_MCR_MASTER | SPI_MCR_PCSIS);
+ regmap_write(dspi->regmap, SPI_MCR, SPI_MCR_MASTER | SPI_MCR_PCSIS |
+ (dspi->devtype_data->xspi_mode ? SPI_MCR_XSPI : 0));
regmap_write(dspi->regmap, SPI_SR, SPI_SR_CLEAR);
if (dspi->devtype_data->xspi_mode)
regmap_write(dspi->regmap, SPI_CTARE(0),
--
2.17.1
From: Esben Haabendal <[email protected]>
Signed-off-by: Esben Haabendal <[email protected]>
Cc: Martin Hundebøll <[email protected]>
---
drivers/spi/spi-fsl-dspi.c | 10 ++++++++++
1 file changed, 10 insertions(+)
diff --git a/drivers/spi/spi-fsl-dspi.c b/drivers/spi/spi-fsl-dspi.c
index 3e9dd645ee54..ba83ff4512c9 100644
--- a/drivers/spi/spi-fsl-dspi.c
+++ b/drivers/spi/spi-fsl-dspi.c
@@ -119,6 +119,9 @@
#define SPI_FRAME_BITS_16 SPI_CTAR_FMSZ(0xf)
#define SPI_FRAME_BITS_8 SPI_CTAR_FMSZ(0x7)
+#define SPI_FRAME_EBITS(bits) SPI_CTARE_FMSZE(((bits) - 1) >> 4)
+#define SPI_FRAME_EBITS_MASK SPI_CTARE_FMSZE(1)
+
/* Register offsets for regmap_pushr */
#define PUSHR_CMD 0x0
#define PUSHR_TX 0x2
@@ -662,6 +665,10 @@ static int dspi_transfer_one_message(struct spi_master *master,
regmap_write(dspi->regmap, SPI_CTAR(0),
dspi->cur_chip->ctar_val |
SPI_FRAME_BITS(transfer->bits_per_word));
+ if (dspi->devtype_data->xspi_mode)
+ regmap_write(dspi->regmap, SPI_CTARE(0),
+ SPI_FRAME_EBITS(transfer->bits_per_word)
+ | SPI_CTARE_DTCP(1));
trans_mode = dspi->devtype_data->trans_mode;
switch (trans_mode) {
@@ -922,6 +929,9 @@ static void dspi_init(struct fsl_dspi *dspi)
{
regmap_write(dspi->regmap, SPI_MCR, SPI_MCR_MASTER | SPI_MCR_PCSIS);
regmap_write(dspi->regmap, SPI_SR, SPI_SR_CLEAR);
+ if (dspi->devtype_data->xspi_mode)
+ regmap_write(dspi->regmap, SPI_CTARE(0),
+ SPI_CTARE_FMSZE(0) | SPI_CTARE_DTCP(1));
}
static int dspi_probe(struct platform_device *pdev)
--
2.17.1
From: Esben Haabendal <[email protected]>
Mark volatile registers to avoid caching bugs.
Note: SPI_MCR is marked volatile because of CLR_TXF and CLR_RXF bits.
Signed-off-by: Esben Haabendal <[email protected]>
Cc: Martin Hundebøll <[email protected]>
---
drivers/spi/spi-fsl-dspi.c | 12 ++++++++++++
1 file changed, 12 insertions(+)
diff --git a/drivers/spi/spi-fsl-dspi.c b/drivers/spi/spi-fsl-dspi.c
index df07dd4722fb..5c5905b6509f 100644
--- a/drivers/spi/spi-fsl-dspi.c
+++ b/drivers/spi/spi-fsl-dspi.c
@@ -862,11 +862,23 @@ static int dspi_resume(struct device *dev)
static SIMPLE_DEV_PM_OPS(dspi_pm, dspi_suspend, dspi_resume);
+static const struct regmap_range dspi_volatile_ranges[] = {
+ regmap_reg_range(SPI_MCR, SPI_TCR),
+ regmap_reg_range(SPI_SR, SPI_SR),
+ regmap_reg_range(SPI_PUSHR, SPI_RXFR3),
+};
+
+static const struct regmap_access_table dspi_volatile_table = {
+ .yes_ranges = dspi_volatile_ranges,
+ .n_yes_ranges = ARRAY_SIZE(dspi_volatile_ranges),
+};
+
static const struct regmap_config dspi_regmap_config = {
.reg_bits = 32,
.val_bits = 32,
.reg_stride = 4,
.max_register = 0x88,
+ .volatile_table = &dspi_volatile_table,
};
static void dspi_init(struct fsl_dspi *dspi)
--
2.17.1
From: Esben Haabendal <[email protected]>
As of 92dc20d83adec565378254c0630e839ff5674e14, transfer->cs_change has
been supported for non-last transfers, but not for last transfer.
This change brings handling of cs_change in line with the specification in
spi.h, implementing handling of transfer->cs_change for all transfers.
The value for CMD FIFO is precalculated with transfer->cs_change field
taken into account, allowing for CS de-activate between transfers and
keeping CS activated after last transfer.
Signed-off-by: Esben Haabendal <[email protected]>
Cc: Martin Hundebøll <[email protected]>
fixup! spi: spi-fsl-dspi: Fix per transfer cs_change handling
---
drivers/spi/spi-fsl-dspi.c | 68 ++++++++++++++++++++++----------------
1 file changed, 40 insertions(+), 28 deletions(-)
diff --git a/drivers/spi/spi-fsl-dspi.c b/drivers/spi/spi-fsl-dspi.c
index 3bf135bf8b93..c0c3b8bf2781 100644
--- a/drivers/spi/spi-fsl-dspi.c
+++ b/drivers/spi/spi-fsl-dspi.c
@@ -84,11 +84,16 @@
#define SPI_RSER_TCFQE 0x80000000
#define SPI_PUSHR 0x34
-#define SPI_PUSHR_CONT (1 << 31)
-#define SPI_PUSHR_CTAS(x) (((x) & 0x00000003) << 28)
-#define SPI_PUSHR_EOQ (1 << 27)
-#define SPI_PUSHR_CTCNT (1 << 26)
-#define SPI_PUSHR_PCS(x) (((1 << x) & 0x0000003f) << 16)
+#define SPI_PUSHR_CMD_CONT (1 << 15)
+#define SPI_PUSHR_CONT (SPI_PUSHR_CMD_CONT << 16)
+#define SPI_PUSHR_CMD_CTAS(x) (((x) & 0x0003) << 12)
+#define SPI_PUSHR_CTAS(x) (SPI_PUSHR_CMD_CTAS(x) << 16)
+#define SPI_PUSHR_CMD_EOQ (1 << 11)
+#define SPI_PUSHR_EOQ (SPI_PUSHR_CMD_EOQ << 16)
+#define SPI_PUSHR_CMD_CTCNT (1 << 10)
+#define SPI_PUSHR_CTCNT (SPI_PUSHR_CMD_CTCNT << 16)
+#define SPI_PUSHR_CMD_PCS(x) ((1 << x) & 0x003f)
+#define SPI_PUSHR_PCS(x) (SPI_PUSHR_CMD_PCS(x) << 16)
#define SPI_PUSHR_TXDATA(x) ((x) & 0x0000ffff)
#define SPI_PUSHR_SLAVE 0x34
@@ -189,9 +194,8 @@ struct fsl_dspi {
void *rx;
void *rx_end;
char dataflags;
- u8 cs;
u16 void_write_data;
- u32 cs_change;
+ u16 tx_cmd;
const struct fsl_dspi_devtype_data *devtype_data;
wait_queue_head_t waitq;
@@ -254,8 +258,6 @@ static int dspi_next_xfer_dma_submit(struct fsl_dspi *dspi)
for (i = 0; i < dma->curr_xfer_len; i++) {
dspi->dma->tx_dma_buf[i] = dspi_data_to_pushr(dspi, tx_word);
- if ((dspi->cs_change) && (!dspi->len))
- dspi->dma->tx_dma_buf[i] &= ~SPI_PUSHR_CONT;
}
dma->tx_desc = dmaengine_prep_slave_single(dma->chan_tx,
@@ -534,21 +536,22 @@ static void ns_delay_scale(char *psc, char *sc, int delay_ns,
static u32 dspi_data_to_pushr(struct fsl_dspi *dspi, int tx_word)
{
- u16 d16;
+ u16 data, cmd;
if (dspi->tx) {
- d16 = tx_word ? *(u16 *)dspi->tx : *(u8 *)dspi->tx;
+ data = tx_word ? *(u16 *)dspi->tx : *(u8 *)dspi->tx;
dspi->tx += tx_word + 1;
} else {
- d16 = dspi->void_write_data;
+ data = dspi->void_write_data;
}
dspi->len -= tx_word + 1;
- return SPI_PUSHR_TXDATA(d16) |
- SPI_PUSHR_PCS(dspi->cs) |
- SPI_PUSHR_CTAS(0) |
- SPI_PUSHR_CONT;
+ cmd = dspi->tx_cmd;
+ if (dspi->len > 0)
+ cmd |= SPI_PUSHR_CMD_CONT;
+
+ return (cmd << 16) | SPI_PUSHR_TXDATA(data);
}
static void dspi_data_from_popr(struct fsl_dspi *dspi, int rx_word)
@@ -587,12 +590,9 @@ static int dspi_eoq_write(struct fsl_dspi *dspi)
dspi_pushr = dspi_data_to_pushr(dspi, tx_word);
- if (dspi->len == 0 || tx_count == DSPI_FIFO_SIZE - 1) {
- /* last transfer in the transfer */
+ if (dspi->len == 0 || tx_count == DSPI_FIFO_SIZE - 1)
+ /* request EOQ flag for last transfer in queue */
dspi_pushr |= SPI_PUSHR_EOQ;
- if ((dspi->cs_change) && (!dspi->len))
- dspi_pushr &= ~SPI_PUSHR_CONT;
- }
regmap_write(dspi->regmap, SPI_PUSHR, dspi_pushr);
@@ -635,9 +635,6 @@ static int dspi_tcfq_write(struct fsl_dspi *dspi)
dspi_pushr = dspi_data_to_pushr(dspi, tx_word);
- if ((dspi->cs_change) && (!dspi->len))
- dspi_pushr &= ~SPI_PUSHR_CONT;
-
regmap_write(dspi->regmap, SPI_PUSHR, dspi_pushr);
return tx_word + 1;
@@ -672,11 +669,26 @@ static int dspi_transfer_one_message(struct spi_master *master,
dspi->cur_transfer = transfer;
dspi->cur_msg = message;
dspi->cur_chip = spi_get_ctldata(spi);
- dspi->cs = spi->chip_select;
- dspi->cs_change = 0;
+ /* Prepare command word for CMD FIFO */
+ dspi->tx_cmd = SPI_PUSHR_CMD_CTAS(0) |
+ SPI_PUSHR_CMD_PCS(spi->chip_select);
if (list_is_last(&dspi->cur_transfer->transfer_list,
- &dspi->cur_msg->transfers) || transfer->cs_change)
- dspi->cs_change = 1;
+ &dspi->cur_msg->transfers)) {
+ /* Leave PCS activated after last transfer when
+ * cs_change is set.
+ */
+ if (transfer->cs_change)
+ dspi->tx_cmd |= SPI_PUSHR_CMD_CONT;
+ } else {
+ /* Keep PCS active between transfers in same message
+ * when cs_change is not set, and de-activate PCS
+ * between transfers in the same message when
+ * cs_change is set.
+ */
+ if (!transfer->cs_change)
+ dspi->tx_cmd |= SPI_PUSHR_CMD_CONT;
+ }
+
dspi->void_write_data = dspi->cur_chip->void_write_data;
dspi->dataflags = 0;
--
2.17.1
On 2018-06-20 09:34, Esben Haabendal wrote:
> From: Esben Haabendal <[email protected]>
>
> The if statement just above this if/else statement triggers on the same
> condition, and then invalidates it.
>
> Signed-off-by: Esben Haabendal <[email protected]>
> Cc: Martin Hundebøll <[email protected]>
For the entire series:
Acked-by: Martin Hundebøll <[email protected]>
> ---
> drivers/spi/spi-fsl-dspi.c | 3 +--
> 1 file changed, 1 insertion(+), 2 deletions(-)
>
> diff --git a/drivers/spi/spi-fsl-dspi.c b/drivers/spi/spi-fsl-dspi.c
> index 0630962ce442..3ca9b9608801 100644
> --- a/drivers/spi/spi-fsl-dspi.c
> +++ b/drivers/spi/spi-fsl-dspi.c
> @@ -593,8 +593,7 @@ static int dspi_eoq_write(struct fsl_dspi *dspi)
> dspi_pushr |= SPI_PUSHR_EOQ;
> if ((dspi->cs_change) && (!dspi->len))
> dspi_pushr &= ~SPI_PUSHR_CONT;
> - } else if (tx_word && (dspi->len == 1))
> - dspi_pushr |= SPI_PUSHR_EOQ;
> + }
>
> regmap_write(dspi->regmap, SPI_PUSHR, dspi_pushr);
>
>
--
Kind regards,
Martin Hundebøll
Embedded Linux Consultant
+45 61 65 54 61
[email protected]
Geanix IVS
DK39600706
From: Esben Haabendal <[email protected]>
The if statement just above this if/else statement triggers on the same
condition, and then invalidates it.
Signed-off-by: Esben Haabendal <[email protected]>
Cc: Martin Hundebøll <[email protected]>
---
drivers/spi/spi-fsl-dspi.c | 3 +--
1 file changed, 1 insertion(+), 2 deletions(-)
diff --git a/drivers/spi/spi-fsl-dspi.c b/drivers/spi/spi-fsl-dspi.c
index 0630962ce442..3ca9b9608801 100644
--- a/drivers/spi/spi-fsl-dspi.c
+++ b/drivers/spi/spi-fsl-dspi.c
@@ -593,8 +593,7 @@ static int dspi_eoq_write(struct fsl_dspi *dspi)
dspi_pushr |= SPI_PUSHR_EOQ;
if ((dspi->cs_change) && (!dspi->len))
dspi_pushr &= ~SPI_PUSHR_CONT;
- } else if (tx_word && (dspi->len == 1))
- dspi_pushr |= SPI_PUSHR_EOQ;
+ }
regmap_write(dspi->regmap, SPI_PUSHR, dspi_pushr);
--
2.17.1
From: Esben Haabendal <[email protected]>
Checking directly against pointer value should be at least as fast as doing
bitmasking and compare, so let's keep it simple.
Signed-off-by: Esben Haabendal <[email protected]>
Cc: Martin Hundebøll <[email protected]>
---
drivers/spi/spi-fsl-dspi.c | 23 ++++++++---------------
1 file changed, 8 insertions(+), 15 deletions(-)
diff --git a/drivers/spi/spi-fsl-dspi.c b/drivers/spi/spi-fsl-dspi.c
index 3ca9b9608801..3bf135bf8b93 100644
--- a/drivers/spi/spi-fsl-dspi.c
+++ b/drivers/spi/spi-fsl-dspi.c
@@ -38,8 +38,6 @@
#define DRIVER_NAME "fsl-dspi"
-#define TRAN_STATE_RX_VOID 0x01
-#define TRAN_STATE_TX_VOID 0x02
#define TRAN_STATE_WORD_ODD_NUM 0x04
#define DSPI_FIFO_SIZE 4
@@ -232,7 +230,7 @@ static void dspi_rx_dma_callback(void *arg)
rx_word = is_double_byte_mode(dspi);
- if (!(dspi->dataflags & TRAN_STATE_RX_VOID)) {
+ if (dspi->rx) {
for (i = 0; i < dma->curr_xfer_len; i++) {
d = dspi->dma->rx_dma_buf[i];
rx_word ? (*(u16 *)dspi->rx = d) :
@@ -538,12 +536,13 @@ static u32 dspi_data_to_pushr(struct fsl_dspi *dspi, int tx_word)
{
u16 d16;
- if (!(dspi->dataflags & TRAN_STATE_TX_VOID))
+ if (dspi->tx) {
d16 = tx_word ? *(u16 *)dspi->tx : *(u8 *)dspi->tx;
- else
+ dspi->tx += tx_word + 1;
+ } else {
d16 = dspi->void_write_data;
+ }
- dspi->tx += tx_word + 1;
dspi->len -= tx_word + 1;
return SPI_PUSHR_TXDATA(d16) |
@@ -560,10 +559,10 @@ static void dspi_data_from_popr(struct fsl_dspi *dspi, int rx_word)
regmap_read(dspi->regmap, SPI_POPR, &val);
d = SPI_POPR_RXDATA(val);
- if (!(dspi->dataflags & TRAN_STATE_RX_VOID))
+ if (dspi->rx) {
rx_word ? (*(u16 *)dspi->rx = d) : (*(u8 *)dspi->rx = d);
-
- dspi->rx += rx_word + 1;
+ dspi->rx += rx_word + 1;
+ }
}
static int dspi_eoq_write(struct fsl_dspi *dspi)
@@ -687,12 +686,6 @@ static int dspi_transfer_one_message(struct spi_master *master,
dspi->rx_end = dspi->rx + transfer->len;
dspi->len = transfer->len;
- if (!dspi->rx)
- dspi->dataflags |= TRAN_STATE_RX_VOID;
-
- if (!dspi->tx)
- dspi->dataflags |= TRAN_STATE_TX_VOID;
-
regmap_write(dspi->regmap, SPI_MCR, dspi->cur_chip->mcr_val);
regmap_update_bits(dspi->regmap, SPI_MCR,
SPI_MCR_CLR_TXF | SPI_MCR_CLR_RXF,
--
2.17.1
From: Esben Haabendal <[email protected]>
This implements handling of split CMD and TX FIFO queues for XSPI when
running in TCFQ mode.
It should be simple to add it to EOQ mode also. Currently, EOQ mode is
only used with coldfire. So if coldfire DSPI supports XSPI, XSPI FIFO
handling should be added to EOQ mode also.
Signed-off-by: Esben Haabendal <[email protected]>
Cc: Martin Hundebøll <[email protected]>
---
drivers/spi/spi-fsl-dspi.c | 55 +++++++++++++++++++++++++++++++++-----
1 file changed, 48 insertions(+), 7 deletions(-)
diff --git a/drivers/spi/spi-fsl-dspi.c b/drivers/spi/spi-fsl-dspi.c
index ba83ff4512c9..67cd2e901255 100644
--- a/drivers/spi/spi-fsl-dspi.c
+++ b/drivers/spi/spi-fsl-dspi.c
@@ -215,15 +215,17 @@ struct fsl_dspi {
struct fsl_dspi_dma *dma;
};
-static u16 dspi_pop_tx(struct fsl_dspi *dspi)
+static u32 dspi_pop_tx(struct fsl_dspi *dspi)
{
- u16 txdata = 0;
+ u32 txdata = 0;
if (dspi->tx) {
if (dspi->bytes_per_word == 1)
txdata = *(u8 *)dspi->tx;
- else /* dspi->bytes_per_word == 2 */
+ else if (dspi->bytes_per_word == 2)
txdata = *(u16 *)dspi->tx;
+ else /* dspi->bytes_per_word == 4 */
+ txdata = *(u32 *)dspi->tx;
dspi->tx += dspi->bytes_per_word;
}
dspi->len -= dspi->bytes_per_word;
@@ -249,8 +251,10 @@ static void dspi_push_rx(struct fsl_dspi *dspi, u32 rxdata)
if (dspi->bytes_per_word == 1)
*(u8 *)dspi->rx = rxdata;
- else /* dspi->bytes_per_word == 2 */
+ else if (dspi->bytes_per_word == 2)
*(u16 *)dspi->rx = rxdata;
+ else /* dspi->bytes_per_word == 4 */
+ *(u32 *)dspi->rx = rxdata;
dspi->rx += dspi->bytes_per_word;
}
@@ -564,12 +568,47 @@ static void fifo_write(struct fsl_dspi *dspi)
regmap_write(dspi->regmap, SPI_PUSHR, dspi_pop_tx_pushr(dspi));
}
+static void cmd_fifo_write(struct fsl_dspi *dspi)
+{
+ u16 cmd = dspi->tx_cmd;
+
+ if (dspi->len > 0)
+ cmd |= SPI_PUSHR_CMD_CONT;
+ regmap_write(dspi->regmap_pushr, PUSHR_CMD, cmd);
+}
+
+static void tx_fifo_write(struct fsl_dspi *dspi, u16 txdata)
+{
+ regmap_write(dspi->regmap_pushr, PUSHR_TX, txdata);
+}
+
static void dspi_tcfq_write(struct fsl_dspi *dspi)
{
/* Clear transfer count */
dspi->tx_cmd |= SPI_PUSHR_CMD_CTCNT;
- /* Write one entry to both TX FIFO and CMD FIFO simultaneously */
- fifo_write(dspi);
+
+ if (dspi->devtype_data->xspi_mode && dspi->bits_per_word > 16) {
+ /* Write two TX FIFO entries first, and then the corresponding
+ * CMD FIFO entry.
+ */
+ u32 data = dspi_pop_tx(dspi);
+
+ if (dspi->cur_chip->ctar_val & SPI_CTAR_LSBFE(1)) {
+ /* LSB */
+ tx_fifo_write(dspi, data & 0xFFFF);
+ tx_fifo_write(dspi, data >> 16);
+ } else {
+ /* MSB */
+ tx_fifo_write(dspi, data >> 16);
+ tx_fifo_write(dspi, data & 0xFFFF);
+ }
+ cmd_fifo_write(dspi);
+ } else {
+ /* Write one entry to both TX FIFO and CMD FIFO
+ * simultaneously.
+ */
+ fifo_write(dspi);
+ }
}
static u32 fifo_read(struct fsl_dspi *dspi)
@@ -656,8 +695,10 @@ static int dspi_transfer_one_message(struct spi_master *master,
dspi->bits_per_word = transfer->bits_per_word;
if (transfer->bits_per_word <= 8)
dspi->bytes_per_word = 1;
- else
+ else if (transfer->bits_per_word <= 16)
dspi->bytes_per_word = 2;
+ else
+ dspi->bytes_per_word = 4;
regmap_update_bits(dspi->regmap, SPI_MCR,
SPI_MCR_CLR_TXF | SPI_MCR_CLR_RXF,
--
2.17.1
From: Esben Haabendal <[email protected]>
This extends the driver with support for all SPI framesizes from 4 to 16
bits, and adds support for per transfer specific bits_per_word, while at
the same time reducing code size and complexity.
Signed-off-by: Esben Haabendal <[email protected]>
Cc: Martin Hundebøll <[email protected]>
---
drivers/spi/spi-fsl-dspi.c | 251 +++++++++++++------------------------
1 file changed, 88 insertions(+), 163 deletions(-)
diff --git a/drivers/spi/spi-fsl-dspi.c b/drivers/spi/spi-fsl-dspi.c
index 2371b9978e65..df07dd4722fb 100644
--- a/drivers/spi/spi-fsl-dspi.c
+++ b/drivers/spi/spi-fsl-dspi.c
@@ -38,8 +38,6 @@
#define DRIVER_NAME "fsl-dspi"
-#define TRAN_STATE_WORD_ODD_NUM 0x04
-
#define DSPI_FIFO_SIZE 4
#define DSPI_DMA_BUFSIZE (DSPI_FIFO_SIZE * 1024)
@@ -187,13 +185,13 @@ struct fsl_dspi {
struct spi_message *cur_msg;
struct chip_data *cur_chip;
size_t len;
- void *tx;
- void *tx_end;
+ const void *tx;
void *rx;
void *rx_end;
- char dataflags;
u16 void_write_data;
u16 tx_cmd;
+ u8 bits_per_word;
+ u8 bytes_per_word;
const struct fsl_dspi_devtype_data *devtype_data;
wait_queue_head_t waitq;
@@ -202,15 +200,43 @@ struct fsl_dspi {
struct fsl_dspi_dma *dma;
};
-static u32 dspi_data_to_pushr(struct fsl_dspi *dspi, int tx_word);
+static u16 dspi_pop_tx(struct fsl_dspi *dspi)
+{
+ u16 txdata = 0;
+
+ if (dspi->tx) {
+ if (dspi->bytes_per_word == 1)
+ txdata = *(u8 *)dspi->tx;
+ else /* dspi->bytes_per_word == 2 */
+ txdata = *(u16 *)dspi->tx;
+ dspi->tx += dspi->bytes_per_word;
+ }
+ dspi->len -= dspi->bytes_per_word;
+ return txdata;
+}
-static inline int is_double_byte_mode(struct fsl_dspi *dspi)
+static u32 dspi_pop_tx_pushr(struct fsl_dspi *dspi)
{
- unsigned int val;
+ u16 cmd = dspi->tx_cmd, data = dspi_pop_tx(dspi);
- regmap_read(dspi->regmap, SPI_CTAR(0), &val);
+ if (dspi->len > 0)
+ cmd |= SPI_PUSHR_CMD_CONT;
+ return cmd << 16 | data;
+}
+
+static void dspi_push_rx(struct fsl_dspi *dspi, u32 rxdata)
+{
+ if (!dspi->rx)
+ return;
+
+ /* Mask of undefined bits */
+ rxdata &= (1 << dspi->bits_per_word) - 1;
- return ((val & SPI_FRAME_BITS_MASK) == SPI_FRAME_BITS(8)) ? 0 : 1;
+ if (dspi->bytes_per_word == 1)
+ *(u8 *)dspi->rx = rxdata;
+ else /* dspi->bytes_per_word == 2 */
+ *(u16 *)dspi->rx = rxdata;
+ dspi->rx += dspi->bytes_per_word;
}
static void dspi_tx_dma_callback(void *arg)
@@ -225,19 +251,11 @@ static void dspi_rx_dma_callback(void *arg)
{
struct fsl_dspi *dspi = arg;
struct fsl_dspi_dma *dma = dspi->dma;
- int rx_word;
int i;
- u16 d;
-
- rx_word = is_double_byte_mode(dspi);
if (dspi->rx) {
- for (i = 0; i < dma->curr_xfer_len; i++) {
- d = dspi->dma->rx_dma_buf[i];
- rx_word ? (*(u16 *)dspi->rx = d) :
- (*(u8 *)dspi->rx = d);
- dspi->rx += rx_word + 1;
- }
+ for (i = 0; i < dma->curr_xfer_len; i++)
+ dspi_push_rx(dspi, dspi->dma->rx_dma_buf[i]);
}
complete(&dma->cmd_rx_complete);
@@ -248,14 +266,10 @@ static int dspi_next_xfer_dma_submit(struct fsl_dspi *dspi)
struct fsl_dspi_dma *dma = dspi->dma;
struct device *dev = &dspi->pdev->dev;
int time_left;
- int tx_word;
int i;
- tx_word = is_double_byte_mode(dspi);
-
- for (i = 0; i < dma->curr_xfer_len; i++) {
- dspi->dma->tx_dma_buf[i] = dspi_data_to_pushr(dspi, tx_word);
- }
+ for (i = 0; i < dma->curr_xfer_len; i++)
+ dspi->dma->tx_dma_buf[i] = dspi_pop_tx_pushr(dspi);
dma->tx_desc = dmaengine_prep_slave_single(dma->chan_tx,
dma->tx_dma_phys,
@@ -326,16 +340,14 @@ static int dspi_dma_xfer(struct fsl_dspi *dspi)
struct device *dev = &dspi->pdev->dev;
int curr_remaining_bytes;
int bytes_per_buffer;
- int word = 1;
int ret = 0;
- if (is_double_byte_mode(dspi))
- word = 2;
curr_remaining_bytes = dspi->len;
bytes_per_buffer = DSPI_DMA_BUFSIZE / DSPI_FIFO_SIZE;
while (curr_remaining_bytes) {
/* Check if current transfer fits the DMA buffer */
- dma->curr_xfer_len = curr_remaining_bytes / word;
+ dma->curr_xfer_len = curr_remaining_bytes
+ / dspi->bytes_per_word;
if (dma->curr_xfer_len > bytes_per_buffer)
dma->curr_xfer_len = bytes_per_buffer;
@@ -345,7 +357,8 @@ static int dspi_dma_xfer(struct fsl_dspi *dspi)
goto exit;
} else {
- curr_remaining_bytes -= dma->curr_xfer_len * word;
+ curr_remaining_bytes -= dma->curr_xfer_len
+ * dspi->bytes_per_word;
if (curr_remaining_bytes < 0)
curr_remaining_bytes = 0;
}
@@ -531,127 +544,56 @@ static void ns_delay_scale(char *psc, char *sc, int delay_ns,
}
}
-static u32 dspi_data_to_pushr(struct fsl_dspi *dspi, int tx_word)
+static void fifo_write(struct fsl_dspi *dspi)
{
- u16 data, cmd;
-
- if (dspi->tx) {
- data = tx_word ? *(u16 *)dspi->tx : *(u8 *)dspi->tx;
- dspi->tx += tx_word + 1;
- } else {
- data = dspi->void_write_data;
- }
-
- dspi->len -= tx_word + 1;
-
- cmd = dspi->tx_cmd;
- if (dspi->len > 0)
- cmd |= SPI_PUSHR_CMD_CONT;
-
- return (cmd << 16) | SPI_PUSHR_TXDATA(data);
+ regmap_write(dspi->regmap, SPI_PUSHR, dspi_pop_tx_pushr(dspi));
}
-static void dspi_data_from_popr(struct fsl_dspi *dspi, int rx_word)
+static void dspi_tcfq_write(struct fsl_dspi *dspi)
{
- u16 d;
- unsigned int val;
-
- regmap_read(dspi->regmap, SPI_POPR, &val);
- d = SPI_POPR_RXDATA(val);
-
- if (dspi->rx) {
- rx_word ? (*(u16 *)dspi->rx = d) : (*(u8 *)dspi->rx = d);
- dspi->rx += rx_word + 1;
- }
+ /* Clear transfer count */
+ dspi->tx_cmd |= SPI_PUSHR_CMD_CTCNT;
+ /* Write one entry to both TX FIFO and CMD FIFO simultaneously */
+ fifo_write(dspi);
}
-static int dspi_eoq_write(struct fsl_dspi *dspi)
+static u32 fifo_read(struct fsl_dspi *dspi)
{
- int tx_count = 0;
- int tx_word;
- u32 dspi_pushr = 0;
-
- tx_word = is_double_byte_mode(dspi);
+ u32 rxdata = 0;
- while (dspi->len && (tx_count < DSPI_FIFO_SIZE)) {
- /* If we are in word mode, only have a single byte to transfer
- * switch to byte mode temporarily. Will switch back at the
- * end of the transfer.
- */
- if (tx_word && (dspi->len == 1)) {
- dspi->dataflags |= TRAN_STATE_WORD_ODD_NUM;
- regmap_update_bits(dspi->regmap, SPI_CTAR(0),
- SPI_FRAME_BITS_MASK, SPI_FRAME_BITS(8));
- tx_word = 0;
- }
-
- dspi_pushr = dspi_data_to_pushr(dspi, tx_word);
-
- if (dspi->len == 0 || tx_count == DSPI_FIFO_SIZE - 1)
- /* request EOQ flag for last transfer in queue */
- dspi_pushr |= SPI_PUSHR_EOQ;
-
- /* Clear transfer counter on first transfer (in FIFO) */
- if (tx_count == 0)
- dspi_pushr |= SPI_PUSHR_CTCNT;
-
- regmap_write(dspi->regmap, SPI_PUSHR, dspi_pushr);
-
- tx_count++;
- }
-
- return tx_count * (tx_word + 1);
+ regmap_read(dspi->regmap, SPI_POPR, &rxdata);
+ return rxdata;
}
-static int dspi_eoq_read(struct fsl_dspi *dspi)
+static void dspi_tcfq_read(struct fsl_dspi *dspi)
{
- int rx_count = 0;
- int rx_word = is_double_byte_mode(dspi);
-
- while ((dspi->rx < dspi->rx_end)
- && (rx_count < DSPI_FIFO_SIZE)) {
- if (rx_word && (dspi->rx_end - dspi->rx) == 1)
- rx_word = 0;
-
- dspi_data_from_popr(dspi, rx_word);
- rx_count++;
- }
-
- return rx_count;
+ dspi_push_rx(dspi, fifo_read(dspi));
}
-static int dspi_tcfq_write(struct fsl_dspi *dspi)
+static void dspi_eoq_write(struct fsl_dspi *dspi)
{
- int tx_word;
- u32 dspi_pushr = 0;
-
- tx_word = is_double_byte_mode(dspi);
-
- if (tx_word && (dspi->len == 1)) {
- dspi->dataflags |= TRAN_STATE_WORD_ODD_NUM;
- regmap_update_bits(dspi->regmap, SPI_CTAR(0),
- SPI_FRAME_BITS_MASK, SPI_FRAME_BITS(8));
- tx_word = 0;
+ int fifo_size = DSPI_FIFO_SIZE;
+
+ /* Fill TX FIFO with as many transfers as possible */
+ while (dspi->len && fifo_size--) {
+ /* Request EOQF for last transfer in FIFO */
+ if (dspi->len == dspi->bytes_per_word || fifo_size == 0)
+ dspi->tx_cmd |= SPI_PUSHR_CMD_EOQ;
+ /* Clear transfer count for first transfer in FIFO */
+ if (fifo_size == (DSPI_FIFO_SIZE - 1))
+ dspi->tx_cmd |= SPI_PUSHR_CMD_CTCNT;
+ /* Write combined TX FIFO and CMD FIFO entry */
+ fifo_write(dspi);
}
-
- dspi_pushr = dspi_data_to_pushr(dspi, tx_word);
-
- /* Clear transfer counter on each transfer */
- dspi_pushr |= SPI_PUSHR_CTCNT;
-
- regmap_write(dspi->regmap, SPI_PUSHR, dspi_pushr);
-
- return tx_word + 1;
}
-static void dspi_tcfq_read(struct fsl_dspi *dspi)
+static void dspi_eoq_read(struct fsl_dspi *dspi)
{
- int rx_word = is_double_byte_mode(dspi);
-
- if (rx_word && (dspi->rx_end - dspi->rx) == 1)
- rx_word = 0;
+ int fifo_size = DSPI_FIFO_SIZE;
- dspi_data_from_popr(dspi, rx_word);
+ /* Read one FIFO entry at and push to rx buffer */
+ while ((dspi->rx < dspi->rx_end) && fifo_size--)
+ dspi_push_rx(dspi, fifo_read(dspi));
}
static int dspi_transfer_one_message(struct spi_master *master,
@@ -691,19 +633,24 @@ static int dspi_transfer_one_message(struct spi_master *master,
dspi->void_write_data = dspi->cur_chip->void_write_data;
- dspi->dataflags = 0;
- dspi->tx = (void *)transfer->tx_buf;
- dspi->tx_end = dspi->tx + transfer->len;
+ dspi->tx = transfer->tx_buf;
dspi->rx = transfer->rx_buf;
dspi->rx_end = dspi->rx + transfer->len;
dspi->len = transfer->len;
+ /* Validated transfer specific frame size (defaults applied) */
+ dspi->bits_per_word = transfer->bits_per_word;
+ if (transfer->bits_per_word <= 8)
+ dspi->bytes_per_word = 1;
+ else
+ dspi->bytes_per_word = 2;
regmap_write(dspi->regmap, SPI_MCR, dspi->cur_chip->mcr_val);
regmap_update_bits(dspi->regmap, SPI_MCR,
SPI_MCR_CLR_TXF | SPI_MCR_CLR_RXF,
SPI_MCR_CLR_TXF | SPI_MCR_CLR_RXF);
regmap_write(dspi->regmap, SPI_CTAR(0),
- dspi->cur_chip->ctar_val);
+ dspi->cur_chip->ctar_val |
+ SPI_FRAME_BITS(transfer->bits_per_word));
trans_mode = dspi->devtype_data->trans_mode;
switch (trans_mode) {
@@ -754,16 +701,9 @@ static int dspi_setup(struct spi_device *spi)
struct fsl_dspi_platform_data *pdata;
u32 cs_sck_delay = 0, sck_cs_delay = 0;
unsigned char br = 0, pbr = 0, pcssck = 0, cssck = 0;
- unsigned char pasc = 0, asc = 0, fmsz = 0;
+ unsigned char pasc = 0, asc = 0;
unsigned long clkrate;
- if ((spi->bits_per_word >= 4) && (spi->bits_per_word <= 16)) {
- fmsz = spi->bits_per_word - 1;
- } else {
- pr_err("Invalid wordsize\n");
- return -ENODEV;
- }
-
/* Only alloc on first setup */
chip = spi_get_ctldata(spi);
if (chip == NULL) {
@@ -799,8 +739,7 @@ static int dspi_setup(struct spi_device *spi)
/* Set After SCK delay scale values */
ns_delay_scale(&pasc, &asc, sck_cs_delay, clkrate);
- chip->ctar_val = SPI_CTAR_FMSZ(fmsz)
- | SPI_CTAR_CPOL(spi->mode & SPI_CPOL ? 1 : 0)
+ chip->ctar_val = SPI_CTAR_CPOL(spi->mode & SPI_CPOL ? 1 : 0)
| SPI_CTAR_CPHA(spi->mode & SPI_CPHA ? 1 : 0)
| SPI_CTAR_LSBFE(spi->mode & SPI_LSB_FIRST ? 1 : 0)
| SPI_CTAR_PCSSCK(pcssck)
@@ -832,24 +771,19 @@ static irqreturn_t dspi_interrupt(int irq, void *dev_id)
enum dspi_trans_mode trans_mode;
u32 spi_sr, spi_tcr;
u16 spi_tcnt;
- int tx_word;
regmap_read(dspi->regmap, SPI_SR, &spi_sr);
regmap_write(dspi->regmap, SPI_SR, spi_sr);
if (spi_sr & (SPI_SR_EOQF | SPI_SR_TCFQF)) {
- tx_word = is_double_byte_mode(dspi);
-
/* Get transfer counter (in number of SPI transfers). It was
* reset to 0 when transfer(s) were started.
*/
regmap_read(dspi->regmap, SPI_TCR, &spi_tcr);
spi_tcnt = SPI_TCR_GET_TCNT(spi_tcr);
-
/* Update total number of bytes that were transferred */
- msg->actual_length += spi_tcnt * (tx_word + 1) -
- (dspi->dataflags & TRAN_STATE_WORD_ODD_NUM ? 1 : 0);
+ msg->actual_length += spi_tcnt * dspi->bytes_per_word;
trans_mode = dspi->devtype_data->trans_mode;
switch (trans_mode) {
@@ -866,14 +800,6 @@ static irqreturn_t dspi_interrupt(int irq, void *dev_id)
}
if (!dspi->len) {
- if (dspi->dataflags & TRAN_STATE_WORD_ODD_NUM) {
- regmap_update_bits(dspi->regmap,
- SPI_CTAR(0),
- SPI_FRAME_BITS_MASK,
- SPI_FRAME_BITS(16));
- dspi->dataflags &= ~TRAN_STATE_WORD_ODD_NUM;
- }
-
dspi->waitflags = 1;
wake_up_interruptible(&dspi->waitq);
} else {
@@ -973,8 +899,7 @@ static int dspi_probe(struct platform_device *pdev)
master->cleanup = dspi_cleanup;
master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_LSB_FIRST;
- master->bits_per_word_mask = SPI_BPW_MASK(4) | SPI_BPW_MASK(8) |
- SPI_BPW_MASK(16);
+ master->bits_per_word_mask = SPI_BPW_RANGE_MASK(4, 16);
pdata = dev_get_platdata(&pdev->dev);
if (pdata) {
--
2.17.1
On Wed, Jun 20, 2018 at 09:34:33AM +0200, Esben Haabendal wrote:
> As of 92dc20d83adec565378254c0630e839ff5674e14, transfer->cs_change has
> been supported for non-last transfers, but not for last transfer.
Please include human readable descriptions of things like commits and
issues being discussed in e-mail in your mails, this makes them much
easier for humans to read especially when they have no internet access.
I do frequently catch up on my mail on flights or while otherwise
travelling so this is even more pressing for me than just being about
making things a bit easier to read.
Mark Brown <[email protected]> writes:
> On Wed, Jun 20, 2018 at 09:34:33AM +0200, Esben Haabendal wrote:
>
>> As of 92dc20d83adec565378254c0630e839ff5674e14, transfer->cs_change has
>> been supported for non-last transfers, but not for last transfer.
>
> Please include human readable descriptions of things like commits and
> issues being discussed in e-mail in your mails, this makes them much
> easier for humans to read especially when they have no internet access.
> I do frequently catch up on my mail on flights or while otherwise
> travelling so this is even more pressing for me than just being about
> making things a bit easier to read.
Ok. I will add the commit title to v2.
/Esben