The SPI controller found in the BCM2711 and BCM7211 SoCs is instantiated
5 times, with all instances sharing the same interrupt line. We
specifically match the two compatible strings here to determine whether
it is necessary to request the interrupt with the IRQF_SHARED flag and
to use an appropriate interrupt handler capable of returning IRQ_NONE.

For the BCM2835 case which is deemed performance critical, there is no
overhead since a dedicated handler that does not assume sharing is used.

Signed-off-by: Florian Fainelli <f.faine...@gmail.com>
---
 drivers/spi/spi-bcm2835.c | 48 +++++++++++++++++++++++++++++++--------
 1 file changed, 38 insertions(+), 10 deletions(-)

diff --git a/drivers/spi/spi-bcm2835.c b/drivers/spi/spi-bcm2835.c
index 237bd306c268..2e73ec70ee80 100644
--- a/drivers/spi/spi-bcm2835.c
+++ b/drivers/spi/spi-bcm2835.c
@@ -361,11 +361,10 @@ static void bcm2835_spi_reset_hw(struct spi_controller 
*ctlr)
        bcm2835_wr(bs, BCM2835_SPI_DLEN, 0);
 }
 
-static irqreturn_t bcm2835_spi_interrupt(int irq, void *dev_id)
+static inline irqreturn_t bcm2835_spi_interrupt_common(struct spi_controller 
*ctlr,
+                                                      u32 cs)
 {
-       struct spi_controller *ctlr = dev_id;
        struct bcm2835_spi *bs = spi_controller_get_devdata(ctlr);
-       u32 cs = bcm2835_rd(bs, BCM2835_SPI_CS);
 
        /*
         * An interrupt is signaled either if DONE is set (TX FIFO empty)
@@ -394,6 +393,27 @@ static irqreturn_t bcm2835_spi_interrupt(int irq, void 
*dev_id)
        return IRQ_HANDLED;
 }
 
+static irqreturn_t bcm2835_spi_interrupt(int irq, void *dev_id)
+{
+       struct spi_controller *ctlr = dev_id;
+       struct bcm2835_spi *bs = spi_controller_get_devdata(ctlr);
+       u32 cs = bcm2835_rd(bs, BCM2835_SPI_CS);
+
+       return bcm2835_spi_interrupt_common(ctlr, cs);
+}
+
+static irqreturn_t bcm2835_spi_sh_interrupt(int irq, void *dev_id)
+{
+       struct spi_controller *ctlr = dev_id;
+       struct bcm2835_spi *bs = spi_controller_get_devdata(ctlr);
+       u32 cs = bcm2835_rd(bs, BCM2835_SPI_CS);
+
+       if (!(cs & BCM2835_SPI_CS_INTR))
+               return IRQ_NONE;
+
+       return bcm2835_spi_interrupt_common(ctlr, cs);
+}
+
 static int bcm2835_spi_transfer_one_irq(struct spi_controller *ctlr,
                                        struct spi_device *spi,
                                        struct spi_transfer *tfr,
@@ -1287,12 +1307,26 @@ static int bcm2835_spi_setup(struct spi_device *spi)
        return 0;
 }
 
+static const struct of_device_id bcm2835_spi_match[] = {
+       { .compatible = "brcm,bcm2835-spi", .data = &bcm2835_spi_interrupt },
+       { .compatible = "brcm,bcm2711-spi", .data = &bcm2835_spi_sh_interrupt },
+       { .compatible = "brcm,bcm7211-spi", .data = &bcm2835_spi_sh_interrupt },
+       {}
+};
+MODULE_DEVICE_TABLE(of, bcm2835_spi_match);
+
 static int bcm2835_spi_probe(struct platform_device *pdev)
 {
+       irqreturn_t (*bcm2835_spi_isr_func)(int, void *);
        struct spi_controller *ctlr;
+       unsigned long flags = 0;
        struct bcm2835_spi *bs;
        int err;
 
+       bcm2835_spi_isr_func = of_device_get_match_data(&pdev->dev);
+       if (bcm2835_spi_isr_func == &bcm2835_spi_sh_interrupt)
+               flags = IRQF_SHARED;
+
        ctlr = spi_alloc_master(&pdev->dev, ALIGN(sizeof(*bs),
                                                  dma_get_cache_alignment()));
        if (!ctlr)
@@ -1344,7 +1378,7 @@ static int bcm2835_spi_probe(struct platform_device *pdev)
        bcm2835_wr(bs, BCM2835_SPI_CS,
                   BCM2835_SPI_CS_CLEAR_RX | BCM2835_SPI_CS_CLEAR_TX);
 
-       err = devm_request_irq(&pdev->dev, bs->irq, bcm2835_spi_interrupt, 0,
+       err = devm_request_irq(&pdev->dev, bs->irq, bcm2835_spi_isr_func, flags,
                               dev_name(&pdev->dev), ctlr);
        if (err) {
                dev_err(&pdev->dev, "could not request IRQ: %d\n", err);
@@ -1400,12 +1434,6 @@ static void bcm2835_spi_shutdown(struct platform_device 
*pdev)
                dev_err(&pdev->dev, "failed to shutdown\n");
 }
 
-static const struct of_device_id bcm2835_spi_match[] = {
-       { .compatible = "brcm,bcm2835-spi", },
-       {}
-};
-MODULE_DEVICE_TABLE(of, bcm2835_spi_match);
-
 static struct platform_driver bcm2835_spi_driver = {
        .driver         = {
                .name           = DRV_NAME,
-- 
2.17.1

Reply via email to