From 9a07f10a34d95a0e6b38908d6b20fe6d0b13fc41 Mon Sep 17 00:00:00 2001 From: Chao Fu Date: Fri, 23 Jan 2015 18:53:15 +0530 Subject: spi: spi-fsl-dspi: Add support for TCFQ transfer mode TCFQ is interrupt of Transfer Complete Flag in DSPI module. EOQ is interrupt of End of Queue Flag in DSPI module. For adopting of different platform, either of them is a way of DSPI transfer data. This patch add TCF support for DSPI module in other platform. Signed-off-by: Bhuvanchandra DV Signed-off-by: Stefan Agner --- .../devicetree/bindings/spi/spi-fsl-dspi.txt | 2 + drivers/spi/spi-fsl-dspi.c | 74 +++++++++++++++++++--- 2 files changed, 68 insertions(+), 8 deletions(-) diff --git a/Documentation/devicetree/bindings/spi/spi-fsl-dspi.txt b/Documentation/devicetree/bindings/spi/spi-fsl-dspi.txt index cbbe16ed3874..b50439f6cab6 100644 --- a/Documentation/devicetree/bindings/spi/spi-fsl-dspi.txt +++ b/Documentation/devicetree/bindings/spi/spi-fsl-dspi.txt @@ -15,6 +15,8 @@ Optional property: - big-endian: If present the dspi device's registers are implemented in big endian mode, otherwise in native mode(same with CPU), for more detail please see: Documentation/devicetree/bindings/regmap/regmap.txt. +- tcfq-mode: If present, the data transfer will be done at TCFQ interrupt. + By default, driver chooses EOQ interrupt if 'tcfq-mode' property was not set. Example: diff --git a/drivers/spi/spi-fsl-dspi.c b/drivers/spi/spi-fsl-dspi.c index 492f0714fc78..440c1646b7e3 100644 --- a/drivers/spi/spi-fsl-dspi.c +++ b/drivers/spi/spi-fsl-dspi.c @@ -63,9 +63,11 @@ #define SPI_CTAR0_SLAVE 0x0c #define SPI_SR 0x2c +#define SPI_SR_TCFQF 0x80000000 #define SPI_SR_EOQF 0x10000000 #define SPI_RSER 0x30 +#define SPI_RSER_TCFQE 0x80000000 #define SPI_RSER_EOQFE 0x10000000 #define SPI_PUSHR 0x34 @@ -105,6 +107,12 @@ struct chip_data { u16 void_write_data; }; +enum dspi_trans_mode { + DSPI_EOQ_MODE = 0, + DSPI_TCFQ_MODE, + DSPI_DMA_MODE, /*TODO*/ +}; + struct fsl_dspi { struct spi_master *master; struct platform_device *pdev; @@ -125,6 +133,7 @@ struct fsl_dspi { u8 cs; u16 void_write_data; u32 cs_change; + enum dspi_trans_mode trans_mode; wait_queue_head_t waitq; u32 waitflags; @@ -225,7 +234,7 @@ static void dspi_data_from_popr(struct fsl_dspi *dspi, int rx_word) } } -static int dspi_transfer_write(struct fsl_dspi *dspi) +static int dspi_eoq_write(struct fsl_dspi *dspi) { int tx_count = 0; int tx_word; @@ -269,7 +278,7 @@ static int dspi_transfer_write(struct fsl_dspi *dspi) return tx_count * (tx_word + 1); } -static int dspi_transfer_read(struct fsl_dspi *dspi) +static int dspi_eoq_read(struct fsl_dspi *dspi) { int rx_count = 0; int rx_word = is_double_byte_mode(dspi); @@ -283,6 +292,37 @@ static int dspi_transfer_read(struct fsl_dspi *dspi) return rx_count; } +static int dspi_tcfq_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(dspi->cs), + SPI_FRAME_BITS_MASK, SPI_FRAME_BITS(8)); + tx_word = 0; + } + + 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; +} + +static void dspi_tcfq_read(struct fsl_dspi *dspi) +{ + int rx_word = is_double_byte_mode(dspi); + + dspi_data_from_popr(dspi, rx_word); +} + static int dspi_transfer_one_message(struct spi_master *master, struct spi_message *message) { @@ -326,8 +366,13 @@ static int dspi_transfer_one_message(struct spi_master *master, regmap_write(dspi->regmap, SPI_CTAR(dspi->cs), dspi->cur_chip->ctar_val); - regmap_write(dspi->regmap, SPI_RSER, SPI_RSER_EOQFE); - message->actual_length += dspi_transfer_write(dspi); + if (dspi->trans_mode == DSPI_EOQ_MODE) { + regmap_write(dspi->regmap, SPI_RSER, SPI_RSER_EOQFE); + message->actual_length += dspi_eoq_write(dspi); + } else if (dspi->trans_mode == DSPI_TCFQ_MODE) { + regmap_write(dspi->regmap, SPI_RSER, SPI_RSER_TCFQE); + message->actual_length += dspi_tcfq_write(dspi); + } if (wait_event_interruptible(dspi->waitq, dspi->waitflags)) dev_err(&dspi->pdev->dev, "wait transfer complete fail!\n"); @@ -399,8 +444,13 @@ static irqreturn_t dspi_interrupt(int irq, void *dev_id) struct spi_message *msg = dspi->cur_msg; - regmap_write(dspi->regmap, SPI_SR, SPI_SR_EOQF); - dspi_transfer_read(dspi); + if (dspi->trans_mode == DSPI_EOQ_MODE) { + regmap_write(dspi->regmap, SPI_SR, SPI_SR_EOQF); + dspi_eoq_read(dspi); + } else if (dspi->trans_mode == DSPI_TCFQ_MODE) { + regmap_write(dspi->regmap, SPI_SR, SPI_SR_TCFQF); + dspi_tcfq_read(dspi); + } if (!dspi->len) { if (dspi->dataflags & TRAN_STATE_WORD_ODD_NUM) @@ -409,8 +459,12 @@ static irqreturn_t dspi_interrupt(int irq, void *dev_id) dspi->waitflags = 1; wake_up_interruptible(&dspi->waitq); - } else - msg->actual_length += dspi_transfer_write(dspi); + } else { + if (dspi->trans_mode == DSPI_EOQ_MODE) + msg->actual_length += dspi_eoq_write(dspi); + else if (dspi->trans_mode == DSPI_TCFQ_MODE) + msg->actual_length += dspi_tcfq_write(dspi); + } return IRQ_HANDLED; } @@ -470,6 +524,7 @@ static int dspi_probe(struct platform_device *pdev) dspi = spi_master_get_devdata(master); dspi->pdev = pdev; dspi->master = master; + dspi->trans_mode = DSPI_EOQ_MODE; master->transfer = NULL; master->setup = dspi_setup; @@ -481,6 +536,9 @@ static int dspi_probe(struct platform_device *pdev) master->bits_per_word_mask = SPI_BPW_MASK(4) | SPI_BPW_MASK(8) | SPI_BPW_MASK(16); + if (of_property_read_bool(np, "tcfq-mode")) + dspi->trans_mode = DSPI_TCFQ_MODE; + ret = of_property_read_u32(np, "spi-num-chipselects", &cs_num); if (ret < 0) { dev_err(&pdev->dev, "can't get spi-num-chipselects\n"); -- cgit v1.2.3