diff options
Diffstat (limited to 'drivers/spi')
-rw-r--r-- | drivers/spi/spi-fsl-dspi.c | 87 |
1 files changed, 64 insertions, 23 deletions
diff --git a/drivers/spi/spi-fsl-dspi.c b/drivers/spi/spi-fsl-dspi.c index 6d2c7984ab0e..77db43f1290f 100644 --- a/drivers/spi/spi-fsl-dspi.c +++ b/drivers/spi/spi-fsl-dspi.c @@ -647,19 +647,12 @@ static void dspi_eoq_read(struct fsl_dspi *dspi) dspi_push_rx(dspi, fifo_read(dspi)); } -static irqreturn_t dspi_interrupt(int irq, void *dev_id) +static int dspi_rxtx(struct fsl_dspi *dspi) { - struct fsl_dspi *dspi = (struct fsl_dspi *)dev_id; struct spi_message *msg = dspi->cur_msg; enum dspi_trans_mode trans_mode; - u32 spi_sr, spi_tcr; u16 spi_tcnt; - - 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))) - return IRQ_NONE; + u32 spi_tcr; /* Get transfer counter (in number of SPI transfers). It was * reset to 0 when transfer(s) were started. @@ -675,17 +668,55 @@ static irqreturn_t dspi_interrupt(int irq, void *dev_id) else if (trans_mode == DSPI_TCFQ_MODE) dspi_tcfq_read(dspi); - if (!dspi->len) { - dspi->waitflags = 1; - wake_up_interruptible(&dspi->waitq); - return IRQ_HANDLED; - } + if (!dspi->len) + /* Success! */ + return 0; if (trans_mode == DSPI_EOQ_MODE) dspi_eoq_write(dspi); else if (trans_mode == DSPI_TCFQ_MODE) dspi_tcfq_write(dspi); + return -EINPROGRESS; +} + +static int dspi_poll(struct fsl_dspi *dspi) +{ + int tries = 1000; + u32 spi_sr; + + do { + 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)) + break; + } while (--tries); + + if (!tries) + return -ETIMEDOUT; + + return dspi_rxtx(dspi); +} + +static irqreturn_t dspi_interrupt(int irq, void *dev_id) +{ + struct fsl_dspi *dspi = (struct fsl_dspi *)dev_id; + u32 spi_sr; + + 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))) + return IRQ_NONE; + + dspi_rxtx(dspi); + + if (!dspi->len) { + dspi->waitflags = 1; + wake_up_interruptible(&dspi->waitq); + } + return IRQ_HANDLED; } @@ -773,13 +804,18 @@ static int dspi_transfer_one_message(struct spi_controller *ctlr, goto out; } - if (trans_mode != DSPI_DMA_MODE) { - if (wait_event_interruptible(dspi->waitq, - dspi->waitflags)) - dev_err(&dspi->pdev->dev, - "wait transfer complete fail!\n"); + if (!dspi->irq) { + do { + status = dspi_poll(dspi); + } while (status == -EINPROGRESS); + } else if (trans_mode != DSPI_DMA_MODE) { + status = wait_event_interruptible(dspi->waitq, + dspi->waitflags); dspi->waitflags = 0; } + if (status) + dev_err(&dspi->pdev->dev, + "Waiting for transfer to complete failed!\n"); if (transfer->delay_usecs) udelay(transfer->delay_usecs); @@ -1079,10 +1115,13 @@ static int dspi_probe(struct platform_device *pdev) goto out_ctlr_put; dspi_init(dspi); + dspi->irq = platform_get_irq(pdev, 0); - if (dspi->irq < 0) { - ret = dspi->irq; - goto out_clk_put; + if (dspi->irq <= 0) { + dev_info(&pdev->dev, + "can't get platform irq, using poll mode\n"); + dspi->irq = 0; + goto poll_mode; } ret = devm_request_irq(&pdev->dev, dspi->irq, dspi_interrupt, @@ -1092,6 +1131,9 @@ static int dspi_probe(struct platform_device *pdev) goto out_clk_put; } + init_waitqueue_head(&dspi->waitq); + +poll_mode: if (dspi->devtype_data->trans_mode == DSPI_DMA_MODE) { ret = dspi_request_dma(dspi, res->start); if (ret < 0) { @@ -1103,7 +1145,6 @@ static int dspi_probe(struct platform_device *pdev) ctlr->max_speed_hz = clk_get_rate(dspi->clk) / dspi->devtype_data->max_clock_factor; - init_waitqueue_head(&dspi->waitq); platform_set_drvdata(pdev, ctlr); ret = spi_register_controller(ctlr); |