aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/spi/spi-s3c64xx.c
diff options
context:
space:
mode:
authorMark Brown <broonie@opensource.wolfsonmicro.com>2011-11-10 05:57:32 -0500
committerMark Brown <broonie@opensource.wolfsonmicro.com>2012-01-21 08:09:37 -0500
commitc2573128ad1ff36a7e231799c102be2413a2f756 (patch)
tree7f6e037e0065193fcda7b4d3305110f5159f92f6 /drivers/spi/spi-s3c64xx.c
parent805a6af8dba5dfdd35ec35dc52ec0122400b2610 (diff)
spi/s3c64xx: Log error interrupts
Although the hardware supports interrupts we're not currently using them at all since for small transfers the overhead is greater than that for busy waiting and for large transfers we have interrupts from the DMA. This means that if the hardware reports an error (especially one which might not stall transfer) we might miss it. Take a first pass at dealing with such errors by enabling the interrupt if we can and logging the errors if they happen. Ideally we'd report the error via the affected transfer but since we're in master mode it's very difficult to trigger errors at present and this code is much simpler. Signed-off-by: Mark Brown <broonie@opensource.wolfsonmicro.com> Acked-by: Linus Walleij <linus.walleij@linaro.org>
Diffstat (limited to 'drivers/spi/spi-s3c64xx.c')
-rw-r--r--drivers/spi/spi-s3c64xx.c57
1 files changed, 55 insertions, 2 deletions
diff --git a/drivers/spi/spi-s3c64xx.c b/drivers/spi/spi-s3c64xx.c
index 019a7163572f..d56066bcbb94 100644
--- a/drivers/spi/spi-s3c64xx.c
+++ b/drivers/spi/spi-s3c64xx.c
@@ -20,6 +20,7 @@
20#include <linux/init.h> 20#include <linux/init.h>
21#include <linux/module.h> 21#include <linux/module.h>
22#include <linux/workqueue.h> 22#include <linux/workqueue.h>
23#include <linux/interrupt.h>
23#include <linux/delay.h> 24#include <linux/delay.h>
24#include <linux/clk.h> 25#include <linux/clk.h>
25#include <linux/dma-mapping.h> 26#include <linux/dma-mapping.h>
@@ -153,6 +154,7 @@ struct s3c64xx_spi_dma_data {
153 * @tx_dmach: Controller's DMA channel for Tx. 154 * @tx_dmach: Controller's DMA channel for Tx.
154 * @sfr_start: BUS address of SPI controller regs. 155 * @sfr_start: BUS address of SPI controller regs.
155 * @regs: Pointer to ioremap'ed controller registers. 156 * @regs: Pointer to ioremap'ed controller registers.
157 * @irq: interrupt
156 * @xfer_completion: To indicate completion of xfer task. 158 * @xfer_completion: To indicate completion of xfer task.
157 * @cur_mode: Stores the active configuration of the controller. 159 * @cur_mode: Stores the active configuration of the controller.
158 * @cur_bpw: Stores the active bits per word settings. 160 * @cur_bpw: Stores the active bits per word settings.
@@ -930,6 +932,33 @@ setup_exit:
930 return err; 932 return err;
931} 933}
932 934
935static irqreturn_t s3c64xx_spi_irq(int irq, void *data)
936{
937 struct s3c64xx_spi_driver_data *sdd = data;
938 struct spi_master *spi = sdd->master;
939 unsigned int val;
940
941 val = readl(sdd->regs + S3C64XX_SPI_PENDING_CLR);
942
943 val &= S3C64XX_SPI_PND_RX_OVERRUN_CLR |
944 S3C64XX_SPI_PND_RX_UNDERRUN_CLR |
945 S3C64XX_SPI_PND_TX_OVERRUN_CLR |
946 S3C64XX_SPI_PND_TX_UNDERRUN_CLR;
947
948 writel(val, sdd->regs + S3C64XX_SPI_PENDING_CLR);
949
950 if (val & S3C64XX_SPI_PND_RX_OVERRUN_CLR)
951 dev_err(&spi->dev, "RX overrun\n");
952 if (val & S3C64XX_SPI_PND_RX_UNDERRUN_CLR)
953 dev_err(&spi->dev, "RX underrun\n");
954 if (val & S3C64XX_SPI_PND_TX_OVERRUN_CLR)
955 dev_err(&spi->dev, "TX overrun\n");
956 if (val & S3C64XX_SPI_PND_TX_UNDERRUN_CLR)
957 dev_err(&spi->dev, "TX underrun\n");
958
959 return IRQ_HANDLED;
960}
961
933static void s3c64xx_spi_hwinit(struct s3c64xx_spi_driver_data *sdd, int channel) 962static void s3c64xx_spi_hwinit(struct s3c64xx_spi_driver_data *sdd, int channel)
934{ 963{
935 struct s3c64xx_spi_info *sci = sdd->cntrlr_info; 964 struct s3c64xx_spi_info *sci = sdd->cntrlr_info;
@@ -970,7 +999,8 @@ static int __init s3c64xx_spi_probe(struct platform_device *pdev)
970 struct s3c64xx_spi_driver_data *sdd; 999 struct s3c64xx_spi_driver_data *sdd;
971 struct s3c64xx_spi_info *sci; 1000 struct s3c64xx_spi_info *sci;
972 struct spi_master *master; 1001 struct spi_master *master;
973 int ret; 1002 int ret, irq;
1003 char clk_name[16];
974 1004
975 if (pdev->id < 0) { 1005 if (pdev->id < 0) {
976 dev_err(&pdev->dev, 1006 dev_err(&pdev->dev,
@@ -1010,6 +1040,12 @@ static int __init s3c64xx_spi_probe(struct platform_device *pdev)
1010 return -ENXIO; 1040 return -ENXIO;
1011 } 1041 }
1012 1042
1043 irq = platform_get_irq(pdev, 0);
1044 if (irq < 0) {
1045 dev_warn(&pdev->dev, "Failed to get IRQ: %d\n", irq);
1046 return irq;
1047 }
1048
1013 master = spi_alloc_master(&pdev->dev, 1049 master = spi_alloc_master(&pdev->dev,
1014 sizeof(struct s3c64xx_spi_driver_data)); 1050 sizeof(struct s3c64xx_spi_driver_data));
1015 if (master == NULL) { 1051 if (master == NULL) {
@@ -1104,10 +1140,21 @@ static int __init s3c64xx_spi_probe(struct platform_device *pdev)
1104 INIT_WORK(&sdd->work, s3c64xx_spi_work); 1140 INIT_WORK(&sdd->work, s3c64xx_spi_work);
1105 INIT_LIST_HEAD(&sdd->queue); 1141 INIT_LIST_HEAD(&sdd->queue);
1106 1142
1143 ret = request_irq(irq, s3c64xx_spi_irq, 0, "spi-s3c64xx", sdd);
1144 if (ret != 0) {
1145 dev_err(&pdev->dev, "Failed to request IRQ %d: %d\n",
1146 irq, ret);
1147 goto err8;
1148 }
1149
1150 writel(S3C64XX_SPI_INT_RX_OVERRUN_EN | S3C64XX_SPI_INT_RX_UNDERRUN_EN |
1151 S3C64XX_SPI_INT_TX_OVERRUN_EN | S3C64XX_SPI_INT_TX_UNDERRUN_EN,
1152 sdd->regs + S3C64XX_SPI_INT_EN);
1153
1107 if (spi_register_master(master)) { 1154 if (spi_register_master(master)) {
1108 dev_err(&pdev->dev, "cannot register SPI master\n"); 1155 dev_err(&pdev->dev, "cannot register SPI master\n");
1109 ret = -EBUSY; 1156 ret = -EBUSY;
1110 goto err8; 1157 goto err9;
1111 } 1158 }
1112 1159
1113 dev_dbg(&pdev->dev, "Samsung SoC SPI Driver loaded for Bus SPI-%d " 1160 dev_dbg(&pdev->dev, "Samsung SoC SPI Driver loaded for Bus SPI-%d "
@@ -1119,6 +1166,8 @@ static int __init s3c64xx_spi_probe(struct platform_device *pdev)
1119 1166
1120 return 0; 1167 return 0;
1121 1168
1169err9:
1170 free_irq(irq, sdd);
1122err8: 1171err8:
1123 destroy_workqueue(sdd->workqueue); 1172 destroy_workqueue(sdd->workqueue);
1124err7: 1173err7:
@@ -1157,6 +1206,10 @@ static int s3c64xx_spi_remove(struct platform_device *pdev)
1157 1206
1158 spi_unregister_master(master); 1207 spi_unregister_master(master);
1159 1208
1209 writel(0, sdd->regs + S3C64XX_SPI_INT_EN);
1210
1211 free_irq(platform_get_irq(pdev, 0), sdd);
1212
1160 destroy_workqueue(sdd->workqueue); 1213 destroy_workqueue(sdd->workqueue);
1161 1214
1162 clk_disable(sdd->src_clk); 1215 clk_disable(sdd->src_clk);