diff options
author | Geert Uytterhoeven <geert+renesas@linux-m68k.org> | 2014-01-24 03:43:58 -0500 |
---|---|---|
committer | Mark Brown <broonie@linaro.org> | 2014-01-27 15:05:34 -0500 |
commit | 9372220678cd4c62992f7637b2ee36b47fa58d37 (patch) | |
tree | 92b77a96b9c1ea9e23c33a2baefc1cbadb18bfe1 /drivers/spi/spi-rspi.c | |
parent | 340a15e6f0d6cd436c55693f7328a1de02fcdb96 (diff) |
spi: rspi: Add support for more than one interrupt
Add support for multiple interrupts, based on the SDK reference code.
This is needed for RZ/A1H, which supports 3 interrupts.
When using multiple interrupts, they must be called "rx" (SPRI) and "tx"
(SPTI). The error interrupt (SPEI) is not used, as it matters for slave
mode only.
When using a single interrupt, it may be called "mux". If it cannot be
found, the first interrupt in the device's resources will be used.
Signed-off-by: Geert Uytterhoeven <geert+renesas@linux-m68k.org>
Signed-off-by: Mark Brown <broonie@linaro.org>
Diffstat (limited to 'drivers/spi/spi-rspi.c')
-rw-r--r-- | drivers/spi/spi-rspi.c | 106 |
1 files changed, 87 insertions, 19 deletions
diff --git a/drivers/spi/spi-rspi.c b/drivers/spi/spi-rspi.c index 5d39cd3eba62..d2ade5e09f58 100644 --- a/drivers/spi/spi-rspi.c +++ b/drivers/spi/spi-rspi.c | |||
@@ -1,7 +1,7 @@ | |||
1 | /* | 1 | /* |
2 | * SH RSPI driver | 2 | * SH RSPI driver |
3 | * | 3 | * |
4 | * Copyright (C) 2012 Renesas Solutions Corp. | 4 | * Copyright (C) 2012, 2013 Renesas Solutions Corp. |
5 | * | 5 | * |
6 | * Based on spi-sh.c: | 6 | * Based on spi-sh.c: |
7 | * Copyright (C) 2011 Renesas Solutions Corp. | 7 | * Copyright (C) 2011 Renesas Solutions Corp. |
@@ -183,12 +183,12 @@ struct rspi_data { | |||
183 | struct clk *clk; | 183 | struct clk *clk; |
184 | u8 spsr; | 184 | u8 spsr; |
185 | u16 spcmd; | 185 | u16 spcmd; |
186 | int rx_irq, tx_irq; | ||
186 | const struct spi_ops *ops; | 187 | const struct spi_ops *ops; |
187 | 188 | ||
188 | /* for dmaengine */ | 189 | /* for dmaengine */ |
189 | struct dma_chan *chan_tx; | 190 | struct dma_chan *chan_tx; |
190 | struct dma_chan *chan_rx; | 191 | struct dma_chan *chan_rx; |
191 | int irq; | ||
192 | 192 | ||
193 | unsigned dma_width_16bit:1; | 193 | unsigned dma_width_16bit:1; |
194 | unsigned dma_callbacked:1; | 194 | unsigned dma_callbacked:1; |
@@ -440,7 +440,7 @@ static int rspi_send_dma(struct rspi_data *rspi, struct spi_transfer *t) | |||
440 | struct scatterlist sg; | 440 | struct scatterlist sg; |
441 | const void *buf = NULL; | 441 | const void *buf = NULL; |
442 | struct dma_async_tx_descriptor *desc; | 442 | struct dma_async_tx_descriptor *desc; |
443 | unsigned len; | 443 | unsigned int len; |
444 | int ret = 0; | 444 | int ret = 0; |
445 | 445 | ||
446 | if (rspi->dma_width_16bit) { | 446 | if (rspi->dma_width_16bit) { |
@@ -478,7 +478,7 @@ static int rspi_send_dma(struct rspi_data *rspi, struct spi_transfer *t) | |||
478 | * DMAC needs SPTIE, but if SPTIE is set, this IRQ routine will be | 478 | * DMAC needs SPTIE, but if SPTIE is set, this IRQ routine will be |
479 | * called. So, this driver disables the IRQ while DMA transfer. | 479 | * called. So, this driver disables the IRQ while DMA transfer. |
480 | */ | 480 | */ |
481 | disable_irq(rspi->irq); | 481 | disable_irq(rspi->tx_irq); |
482 | 482 | ||
483 | rspi_write8(rspi, rspi_read8(rspi, RSPI_SPCR) | SPCR_TXMD, RSPI_SPCR); | 483 | rspi_write8(rspi, rspi_read8(rspi, RSPI_SPCR) | SPCR_TXMD, RSPI_SPCR); |
484 | rspi_enable_irq(rspi, SPCR_SPTIE); | 484 | rspi_enable_irq(rspi, SPCR_SPTIE); |
@@ -497,7 +497,7 @@ static int rspi_send_dma(struct rspi_data *rspi, struct spi_transfer *t) | |||
497 | ret = -ETIMEDOUT; | 497 | ret = -ETIMEDOUT; |
498 | rspi_disable_irq(rspi, SPCR_SPTIE); | 498 | rspi_disable_irq(rspi, SPCR_SPTIE); |
499 | 499 | ||
500 | enable_irq(rspi->irq); | 500 | enable_irq(rspi->tx_irq); |
501 | 501 | ||
502 | end: | 502 | end: |
503 | rspi_dma_unmap_sg(&sg, rspi->chan_tx, DMA_TO_DEVICE); | 503 | rspi_dma_unmap_sg(&sg, rspi->chan_tx, DMA_TO_DEVICE); |
@@ -536,7 +536,7 @@ static int rspi_receive_dma(struct rspi_data *rspi, struct spi_transfer *t) | |||
536 | struct scatterlist sg, sg_dummy; | 536 | struct scatterlist sg, sg_dummy; |
537 | void *dummy = NULL, *rx_buf = NULL; | 537 | void *dummy = NULL, *rx_buf = NULL; |
538 | struct dma_async_tx_descriptor *desc, *desc_dummy; | 538 | struct dma_async_tx_descriptor *desc, *desc_dummy; |
539 | unsigned len; | 539 | unsigned int len; |
540 | int ret = 0; | 540 | int ret = 0; |
541 | 541 | ||
542 | if (rspi->dma_width_16bit) { | 542 | if (rspi->dma_width_16bit) { |
@@ -594,7 +594,9 @@ static int rspi_receive_dma(struct rspi_data *rspi, struct spi_transfer *t) | |||
594 | * DMAC needs SPTIE, but if SPTIE is set, this IRQ routine will be | 594 | * DMAC needs SPTIE, but if SPTIE is set, this IRQ routine will be |
595 | * called. So, this driver disables the IRQ while DMA transfer. | 595 | * called. So, this driver disables the IRQ while DMA transfer. |
596 | */ | 596 | */ |
597 | disable_irq(rspi->irq); | 597 | disable_irq(rspi->tx_irq); |
598 | if (rspi->rx_irq != rspi->tx_irq) | ||
599 | disable_irq(rspi->rx_irq); | ||
598 | 600 | ||
599 | rspi_write8(rspi, rspi_read8(rspi, RSPI_SPCR) & ~SPCR_TXMD, RSPI_SPCR); | 601 | rspi_write8(rspi, rspi_read8(rspi, RSPI_SPCR) & ~SPCR_TXMD, RSPI_SPCR); |
600 | rspi_enable_irq(rspi, SPCR_SPTIE | SPCR_SPRIE); | 602 | rspi_enable_irq(rspi, SPCR_SPTIE | SPCR_SPRIE); |
@@ -617,7 +619,9 @@ static int rspi_receive_dma(struct rspi_data *rspi, struct spi_transfer *t) | |||
617 | ret = -ETIMEDOUT; | 619 | ret = -ETIMEDOUT; |
618 | rspi_disable_irq(rspi, SPCR_SPTIE | SPCR_SPRIE); | 620 | rspi_disable_irq(rspi, SPCR_SPTIE | SPCR_SPRIE); |
619 | 621 | ||
620 | enable_irq(rspi->irq); | 622 | enable_irq(rspi->tx_irq); |
623 | if (rspi->rx_irq != rspi->tx_irq) | ||
624 | enable_irq(rspi->rx_irq); | ||
621 | 625 | ||
622 | end: | 626 | end: |
623 | rspi_dma_unmap_sg(&sg, rspi->chan_rx, DMA_FROM_DEVICE); | 627 | rspi_dma_unmap_sg(&sg, rspi->chan_rx, DMA_FROM_DEVICE); |
@@ -775,7 +779,7 @@ static int rspi_unprepare_message(struct spi_master *master, | |||
775 | return 0; | 779 | return 0; |
776 | } | 780 | } |
777 | 781 | ||
778 | static irqreturn_t rspi_irq(int irq, void *_sr) | 782 | static irqreturn_t rspi_irq_mux(int irq, void *_sr) |
779 | { | 783 | { |
780 | struct rspi_data *rspi = _sr; | 784 | struct rspi_data *rspi = _sr; |
781 | u8 spsr; | 785 | u8 spsr; |
@@ -797,6 +801,36 @@ static irqreturn_t rspi_irq(int irq, void *_sr) | |||
797 | return ret; | 801 | return ret; |
798 | } | 802 | } |
799 | 803 | ||
804 | static irqreturn_t rspi_irq_rx(int irq, void *_sr) | ||
805 | { | ||
806 | struct rspi_data *rspi = _sr; | ||
807 | u8 spsr; | ||
808 | |||
809 | rspi->spsr = spsr = rspi_read8(rspi, RSPI_SPSR); | ||
810 | if (spsr & SPSR_SPRF) { | ||
811 | rspi_disable_irq(rspi, SPCR_SPRIE); | ||
812 | wake_up(&rspi->wait); | ||
813 | return IRQ_HANDLED; | ||
814 | } | ||
815 | |||
816 | return 0; | ||
817 | } | ||
818 | |||
819 | static irqreturn_t rspi_irq_tx(int irq, void *_sr) | ||
820 | { | ||
821 | struct rspi_data *rspi = _sr; | ||
822 | u8 spsr; | ||
823 | |||
824 | rspi->spsr = spsr = rspi_read8(rspi, RSPI_SPSR); | ||
825 | if (spsr & SPSR_SPTEF) { | ||
826 | rspi_disable_irq(rspi, SPCR_SPTIE); | ||
827 | wake_up(&rspi->wait); | ||
828 | return IRQ_HANDLED; | ||
829 | } | ||
830 | |||
831 | return 0; | ||
832 | } | ||
833 | |||
800 | static int rspi_request_dma(struct rspi_data *rspi, | 834 | static int rspi_request_dma(struct rspi_data *rspi, |
801 | struct platform_device *pdev) | 835 | struct platform_device *pdev) |
802 | { | 836 | { |
@@ -868,12 +902,25 @@ static int rspi_remove(struct platform_device *pdev) | |||
868 | return 0; | 902 | return 0; |
869 | } | 903 | } |
870 | 904 | ||
905 | static int rspi_request_irq(struct device *dev, unsigned int irq, | ||
906 | irq_handler_t handler, const char *suffix, | ||
907 | void *dev_id) | ||
908 | { | ||
909 | const char *base = dev_name(dev); | ||
910 | size_t len = strlen(base) + strlen(suffix) + 2; | ||
911 | char *name = devm_kzalloc(dev, len, GFP_KERNEL); | ||
912 | if (!name) | ||
913 | return -ENOMEM; | ||
914 | snprintf(name, len, "%s:%s", base, suffix); | ||
915 | return devm_request_irq(dev, irq, handler, 0, name, dev_id); | ||
916 | } | ||
917 | |||
871 | static int rspi_probe(struct platform_device *pdev) | 918 | static int rspi_probe(struct platform_device *pdev) |
872 | { | 919 | { |
873 | struct resource *res; | 920 | struct resource *res; |
874 | struct spi_master *master; | 921 | struct spi_master *master; |
875 | struct rspi_data *rspi; | 922 | struct rspi_data *rspi; |
876 | int ret, irq; | 923 | int ret; |
877 | char clk_name[16]; | 924 | char clk_name[16]; |
878 | const struct rspi_plat_data *rspi_pd = dev_get_platdata(&pdev->dev); | 925 | const struct rspi_plat_data *rspi_pd = dev_get_platdata(&pdev->dev); |
879 | const struct spi_ops *ops; | 926 | const struct spi_ops *ops; |
@@ -886,12 +933,6 @@ static int rspi_probe(struct platform_device *pdev) | |||
886 | return -ENODEV; | 933 | return -ENODEV; |
887 | } | 934 | } |
888 | 935 | ||
889 | irq = platform_get_irq(pdev, 0); | ||
890 | if (irq < 0) { | ||
891 | dev_err(&pdev->dev, "platform_get_irq error\n"); | ||
892 | return -ENODEV; | ||
893 | } | ||
894 | |||
895 | master = spi_alloc_master(&pdev->dev, sizeof(struct rspi_data)); | 936 | master = spi_alloc_master(&pdev->dev, sizeof(struct rspi_data)); |
896 | if (master == NULL) { | 937 | if (master == NULL) { |
897 | dev_err(&pdev->dev, "spi_alloc_master error.\n"); | 938 | dev_err(&pdev->dev, "spi_alloc_master error.\n"); |
@@ -934,14 +975,41 @@ static int rspi_probe(struct platform_device *pdev) | |||
934 | master->unprepare_message = rspi_unprepare_message; | 975 | master->unprepare_message = rspi_unprepare_message; |
935 | master->mode_bits = SPI_CPHA | SPI_CPOL; | 976 | master->mode_bits = SPI_CPHA | SPI_CPOL; |
936 | 977 | ||
937 | ret = devm_request_irq(&pdev->dev, irq, rspi_irq, 0, | 978 | ret = platform_get_irq_byname(pdev, "rx"); |
938 | dev_name(&pdev->dev), rspi); | 979 | if (ret < 0) { |
980 | ret = platform_get_irq_byname(pdev, "mux"); | ||
981 | if (ret < 0) | ||
982 | ret = platform_get_irq(pdev, 0); | ||
983 | if (ret >= 0) | ||
984 | rspi->rx_irq = rspi->tx_irq = ret; | ||
985 | } else { | ||
986 | rspi->rx_irq = ret; | ||
987 | ret = platform_get_irq_byname(pdev, "tx"); | ||
988 | if (ret >= 0) | ||
989 | rspi->tx_irq = ret; | ||
990 | } | ||
991 | if (ret < 0) { | ||
992 | dev_err(&pdev->dev, "platform_get_irq error\n"); | ||
993 | goto error2; | ||
994 | } | ||
995 | |||
996 | if (rspi->rx_irq == rspi->tx_irq) { | ||
997 | /* Single multiplexed interrupt */ | ||
998 | ret = rspi_request_irq(&pdev->dev, rspi->rx_irq, rspi_irq_mux, | ||
999 | "mux", rspi); | ||
1000 | } else { | ||
1001 | /* Multi-interrupt mode, only SPRI and SPTI are used */ | ||
1002 | ret = rspi_request_irq(&pdev->dev, rspi->rx_irq, rspi_irq_rx, | ||
1003 | "rx", rspi); | ||
1004 | if (!ret) | ||
1005 | ret = rspi_request_irq(&pdev->dev, rspi->tx_irq, | ||
1006 | rspi_irq_tx, "tx", rspi); | ||
1007 | } | ||
939 | if (ret < 0) { | 1008 | if (ret < 0) { |
940 | dev_err(&pdev->dev, "request_irq error\n"); | 1009 | dev_err(&pdev->dev, "request_irq error\n"); |
941 | goto error2; | 1010 | goto error2; |
942 | } | 1011 | } |
943 | 1012 | ||
944 | rspi->irq = irq; | ||
945 | ret = rspi_request_dma(rspi, pdev); | 1013 | ret = rspi_request_dma(rspi, pdev); |
946 | if (ret < 0) { | 1014 | if (ret < 0) { |
947 | dev_err(&pdev->dev, "rspi_request_dma failed.\n"); | 1015 | dev_err(&pdev->dev, "rspi_request_dma failed.\n"); |