mfd: arizona: Correctly clean up after IRQs
authorCharles Keepax <ckeepax@opensource.wolfsonmicro.com>
Tue, 22 Nov 2016 16:10:28 +0000 (16:10 +0000)
committerLee Jones <lee.jones@linaro.org>
Mon, 13 Feb 2017 09:29:40 +0000 (09:29 +0000)
Currently we leak a lot of things when tearing down the IRQs this patch
fixes this cleaning up both the IRQ mappings and the IRQ domain itself.

Signed-off-by: Charles Keepax <ckeepax@opensource.wolfsonmicro.com>
Signed-off-by: Lee Jones <lee.jones@linaro.org>
drivers/mfd/arizona-irq.c

index 88729cf6cb32073e4617b0d066fe0d4f04405d1e..09cf3699e354415046af18c21eae3d98a445a53e 100644 (file)
@@ -210,6 +210,7 @@ int arizona_irq_init(struct arizona *arizona)
        int ret;
        const struct regmap_irq_chip *aod, *irq;
        struct irq_data *irq_data;
+       unsigned int virq;
 
        arizona->ctrlif_error = true;
 
@@ -321,26 +322,34 @@ int arizona_irq_init(struct arizona *arizona)
        }
 
        if (aod) {
-               ret = regmap_add_irq_chip(arizona->regmap,
-                                         irq_create_mapping(arizona->virq,
-                                                       ARIZONA_AOD_IRQ_INDEX),
-                                         IRQF_ONESHOT, 0, aod,
-                                         &arizona->aod_irq_chip);
+               virq = irq_create_mapping(arizona->virq, ARIZONA_AOD_IRQ_INDEX);
+               if (!virq) {
+                       dev_err(arizona->dev, "Failed to map AOD IRQs\n");
+                       ret = -EINVAL;
+                       goto err_domain;
+               }
+
+               ret = regmap_add_irq_chip(arizona->regmap, virq, IRQF_ONESHOT,
+                                         0, aod, &arizona->aod_irq_chip);
                if (ret != 0) {
                        dev_err(arizona->dev,
                                "Failed to add AOD IRQs: %d\n", ret);
-                       goto err;
+                       goto err_map_aod;
                }
        }
 
-       ret = regmap_add_irq_chip(arizona->regmap,
-                                 irq_create_mapping(arizona->virq,
-                                                    ARIZONA_MAIN_IRQ_INDEX),
-                                 IRQF_ONESHOT, 0, irq,
-                                 &arizona->irq_chip);
+       virq = irq_create_mapping(arizona->virq, ARIZONA_MAIN_IRQ_INDEX);
+       if (!virq) {
+               dev_err(arizona->dev, "Failed to map main IRQs\n");
+               ret = -EINVAL;
+               goto err_aod;
+       }
+
+       ret = regmap_add_irq_chip(arizona->regmap, virq, IRQF_ONESHOT,
+                                 0, irq, &arizona->irq_chip);
        if (ret != 0) {
                dev_err(arizona->dev, "Failed to add main IRQs: %d\n", ret);
-               goto err_aod;
+               goto err_map_main_irq;
        }
 
        /* Used to emulate edge trigger and to work around broken pinmux */
@@ -404,26 +413,40 @@ err_main_irq:
        regmap_del_irq_chip(irq_find_mapping(arizona->virq,
                                             ARIZONA_MAIN_IRQ_INDEX),
                            arizona->irq_chip);
+err_map_main_irq:
+       irq_dispose_mapping(irq_find_mapping(arizona->virq,
+                                            ARIZONA_MAIN_IRQ_INDEX));
 err_aod:
        regmap_del_irq_chip(irq_find_mapping(arizona->virq,
                                             ARIZONA_AOD_IRQ_INDEX),
                            arizona->aod_irq_chip);
+err_map_aod:
+       irq_dispose_mapping(irq_find_mapping(arizona->virq,
+                                            ARIZONA_AOD_IRQ_INDEX));
+err_domain:
+       irq_domain_remove(arizona->virq);
 err:
        return ret;
 }
 
 int arizona_irq_exit(struct arizona *arizona)
 {
+       unsigned int virq;
+
        if (arizona->ctrlif_error)
                arizona_free_irq(arizona, ARIZONA_IRQ_CTRLIF_ERR, arizona);
        arizona_free_irq(arizona, ARIZONA_IRQ_BOOT_DONE, arizona);
 
-       regmap_del_irq_chip(irq_find_mapping(arizona->virq,
-                                            ARIZONA_MAIN_IRQ_INDEX),
-                           arizona->irq_chip);
-       regmap_del_irq_chip(irq_find_mapping(arizona->virq,
-                                            ARIZONA_AOD_IRQ_INDEX),
-                           arizona->aod_irq_chip);
+       virq = irq_find_mapping(arizona->virq, ARIZONA_MAIN_IRQ_INDEX);
+       regmap_del_irq_chip(virq, arizona->irq_chip);
+       irq_dispose_mapping(virq);
+
+       virq = irq_find_mapping(arizona->virq, ARIZONA_AOD_IRQ_INDEX);
+       regmap_del_irq_chip(virq, arizona->aod_irq_chip);
+       irq_dispose_mapping(virq);
+
+       irq_domain_remove(arizona->virq);
+
        free_irq(arizona->irq, arizona);
 
        return 0;