dmaengine: imx-dma: explicitly freeup irq
authorVinod Koul <vinod.koul@intel.com>
Sat, 2 Jul 2016 09:55:01 +0000 (15:25 +0530)
committerVinod Koul <vinod.koul@intel.com>
Sat, 16 Jul 2016 14:49:01 +0000 (20:19 +0530)
dmaengine device should explicitly call devm_free_irq() when using
devm_request_irq().

The irq is still ON when devices remove is executed and irq should be
quiesced before remove is completed.

Signed-off-by: Vinod Koul <vinod.koul@intel.com>
drivers/dma/imx-dma.c

index 48d85f8b95fe1e97a014a47062e3ebcf27afd314..9301d3d09563e49cf10edebe3f843274134f35c3 100644 (file)
@@ -167,6 +167,7 @@ struct imxdma_channel {
        u32                             ccr_to_device;
        bool                            enabled_2d;
        int                             slot_2d;
+       unsigned int                    irq;
 };
 
 enum imx_dma_type {
@@ -186,6 +187,9 @@ struct imxdma_engine {
        struct imx_dma_2d_config        slots_2d[IMX_DMA_2D_SLOTS];
        struct imxdma_channel           channel[IMX_DMA_CHANNELS];
        enum imx_dma_type               devtype;
+       unsigned int                    irq;
+       unsigned int                    irq_err;
+
 };
 
 struct imxdma_filter_data {
@@ -1100,6 +1104,7 @@ static int __init imxdma_probe(struct platform_device *pdev)
                        dev_warn(imxdma->dev, "Can't register IRQ for DMA\n");
                        goto disable_dma_ahb_clk;
                }
+               imxdma->irq = irq;
 
                irq_err = platform_get_irq(pdev, 1);
                if (irq_err < 0) {
@@ -1113,6 +1118,7 @@ static int __init imxdma_probe(struct platform_device *pdev)
                        dev_warn(imxdma->dev, "Can't register ERRIRQ for DMA\n");
                        goto disable_dma_ahb_clk;
                }
+               imxdma->irq_err = irq_err;
        }
 
        /* enable DMA module */
@@ -1150,6 +1156,8 @@ static int __init imxdma_probe(struct platform_device *pdev)
                                         irq + i, i);
                                goto disable_dma_ahb_clk;
                        }
+
+                       imxdmac->irq = irq + i;
                        init_timer(&imxdmac->watchdog);
                        imxdmac->watchdog.function = &imxdma_watchdog;
                        imxdmac->watchdog.data = (unsigned long)imxdmac;
@@ -1217,10 +1225,31 @@ disable_dma_ipg_clk:
        return ret;
 }
 
+static void imxdma_free_irq(struct platform_device *pdev, struct imxdma_engine *imxdma)
+{
+       int i;
+
+       if (is_imx1_dma(imxdma)) {
+               disable_irq(imxdma->irq);
+               disable_irq(imxdma->irq_err);
+       }
+
+       for (i = 0; i < IMX_DMA_CHANNELS; i++) {
+               struct imxdma_channel *imxdmac = &imxdma->channel[i];
+
+               if (!is_imx1_dma(imxdma))
+                       disable_irq(imxdmac->irq);
+
+               tasklet_kill(&imxdmac->dma_tasklet);
+       }
+}
+
 static int imxdma_remove(struct platform_device *pdev)
 {
        struct imxdma_engine *imxdma = platform_get_drvdata(pdev);
 
+       imxdma_free_irq(pdev, imxdma);
+
         dma_async_device_unregister(&imxdma->dma_device);
 
        if (pdev->dev.of_node)