]> git.karo-electronics.de Git - karo-tx-linux.git/blobdiff - drivers/base/regmap/regmap-irq.c
Merge tag 'armsoc-dt' of git://git.kernel.org/pub/scm/linux/kernel/git/arm/arm-soc
[karo-tx-linux.git] / drivers / base / regmap / regmap-irq.c
index 9b0d202414d065bf6e03a6f39bb33c9925dee4db..26f799e71c82355e02ef58ff9847cef33545e444 100644 (file)
@@ -379,6 +379,7 @@ static int regmap_irq_map(struct irq_domain *h, unsigned int virq,
        irq_set_chip_data(virq, data);
        irq_set_chip(virq, &data->irq_chip);
        irq_set_nested_thread(virq, 1);
+       irq_set_parent(virq, data->irq);
        irq_set_noprobe(virq);
 
        return 0;
@@ -655,13 +656,34 @@ EXPORT_SYMBOL_GPL(regmap_add_irq_chip);
  *
  * @irq: Primary IRQ for the device
  * @d:   regmap_irq_chip_data allocated by regmap_add_irq_chip()
+ *
+ * This function also dispose all mapped irq on chip.
  */
 void regmap_del_irq_chip(int irq, struct regmap_irq_chip_data *d)
 {
+       unsigned int virq;
+       int hwirq;
+
        if (!d)
                return;
 
        free_irq(irq, d);
+
+       /* Dispose all virtual irq from irq domain before removing it */
+       for (hwirq = 0; hwirq < d->chip->num_irqs; hwirq++) {
+               /* Ignore hwirq if holes in the IRQ list */
+               if (!d->chip->irqs[hwirq].mask)
+                       continue;
+
+               /*
+                * Find the virtual irq of hwirq on chip and if it is
+                * there then dispose it
+                */
+               virq = irq_find_mapping(d->domain, hwirq);
+               if (virq)
+                       irq_dispose_mapping(virq);
+       }
+
        irq_domain_remove(d->domain);
        kfree(d->type_buf);
        kfree(d->type_buf_def);
@@ -674,6 +696,88 @@ void regmap_del_irq_chip(int irq, struct regmap_irq_chip_data *d)
 }
 EXPORT_SYMBOL_GPL(regmap_del_irq_chip);
 
+static void devm_regmap_irq_chip_release(struct device *dev, void *res)
+{
+       struct regmap_irq_chip_data *d = *(struct regmap_irq_chip_data **)res;
+
+       regmap_del_irq_chip(d->irq, d);
+}
+
+static int devm_regmap_irq_chip_match(struct device *dev, void *res, void *data)
+
+{
+       struct regmap_irq_chip_data **r = res;
+
+       if (!r || !*r) {
+               WARN_ON(!r || !*r);
+               return 0;
+       }
+       return *r == data;
+}
+
+/**
+ * devm_regmap_add_irq_chip(): Resource manager regmap_add_irq_chip()
+ *
+ * @dev:       The device pointer on which irq_chip belongs to.
+ * @map:       The regmap for the device.
+ * @irq:       The IRQ the device uses to signal interrupts
+ * @irq_flags: The IRQF_ flags to use for the primary interrupt.
+ * @chip:      Configuration for the interrupt controller.
+ * @data:      Runtime data structure for the controller, allocated on success
+ *
+ * Returns 0 on success or an errno on failure.
+ *
+ * The regmap_irq_chip data automatically be released when the device is
+ * unbound.
+ */
+int devm_regmap_add_irq_chip(struct device *dev, struct regmap *map, int irq,
+                            int irq_flags, int irq_base,
+                            const struct regmap_irq_chip *chip,
+                            struct regmap_irq_chip_data **data)
+{
+       struct regmap_irq_chip_data **ptr, *d;
+       int ret;
+
+       ptr = devres_alloc(devm_regmap_irq_chip_release, sizeof(*ptr),
+                          GFP_KERNEL);
+       if (!ptr)
+               return -ENOMEM;
+
+       ret = regmap_add_irq_chip(map, irq, irq_flags, irq_base,
+                                 chip, &d);
+       if (ret < 0) {
+               devres_free(ptr);
+               return ret;
+       }
+
+       *ptr = d;
+       devres_add(dev, ptr);
+       *data = d;
+       return 0;
+}
+EXPORT_SYMBOL_GPL(devm_regmap_add_irq_chip);
+
+/**
+ * devm_regmap_del_irq_chip(): Resource managed regmap_del_irq_chip()
+ *
+ * @dev: Device for which which resource was allocated.
+ * @irq: Primary IRQ for the device
+ * @d:   regmap_irq_chip_data allocated by regmap_add_irq_chip()
+ */
+void devm_regmap_del_irq_chip(struct device *dev, int irq,
+                             struct regmap_irq_chip_data *data)
+{
+       int rc;
+
+       WARN_ON(irq != data->irq);
+       rc = devres_release(dev, devm_regmap_irq_chip_release,
+                           devm_regmap_irq_chip_match, data);
+
+       if (rc != 0)
+               WARN_ON(rc);
+}
+EXPORT_SYMBOL_GPL(devm_regmap_del_irq_chip);
+
 /**
  * regmap_irq_chip_get_base(): Retrieve interrupt base for a regmap IRQ chip
  *