summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChao Fu <B44548@freescale.com>2015-01-23 18:53:15 +0530
committerStefan Agner <stefan.agner@toradex.com>2015-01-23 15:53:36 +0100
commit9a07f10a34d95a0e6b38908d6b20fe6d0b13fc41 (patch)
tree9bdf2eac8644bfb66d1169b046a13aaf9ae07960
parent5b736b7c66eedf8103999db78d9596445553780b (diff)
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 <bhuvanchandra.dv@toradex.com> Signed-off-by: Stefan Agner <stefan.agner@toradex.com>
-rw-r--r--Documentation/devicetree/bindings/spi/spi-fsl-dspi.txt2
-rw-r--r--drivers/spi/spi-fsl-dspi.c74
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");