|
@@ -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_data(virq, data);
|
|
irq_set_chip(virq, &data->irq_chip);
|
|
irq_set_chip(virq, &data->irq_chip);
|
|
irq_set_nested_thread(virq, 1);
|
|
irq_set_nested_thread(virq, 1);
|
|
|
|
+ irq_set_parent(virq, data->irq);
|
|
irq_set_noprobe(virq);
|
|
irq_set_noprobe(virq);
|
|
|
|
|
|
return 0;
|
|
return 0;
|
|
@@ -655,13 +656,34 @@ EXPORT_SYMBOL_GPL(regmap_add_irq_chip);
|
|
*
|
|
*
|
|
* @irq: Primary IRQ for the device
|
|
* @irq: Primary IRQ for the device
|
|
* @d: regmap_irq_chip_data allocated by regmap_add_irq_chip()
|
|
* @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)
|
|
void regmap_del_irq_chip(int irq, struct regmap_irq_chip_data *d)
|
|
{
|
|
{
|
|
|
|
+ unsigned int virq;
|
|
|
|
+ int hwirq;
|
|
|
|
+
|
|
if (!d)
|
|
if (!d)
|
|
return;
|
|
return;
|
|
|
|
|
|
free_irq(irq, d);
|
|
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);
|
|
irq_domain_remove(d->domain);
|
|
kfree(d->type_buf);
|
|
kfree(d->type_buf);
|
|
kfree(d->type_buf_def);
|
|
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);
|
|
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
|
|
* regmap_irq_chip_get_base(): Retrieve interrupt base for a regmap IRQ chip
|
|
*
|
|
*
|