regmap: Convert regmap_irq to use irq_domain
[linux-2.6.git] / drivers / base / regmap / regmap-irq.c
index a91636f..4fac4b9 100644 (file)
@@ -15,6 +15,7 @@
 #include <linux/regmap.h>
 #include <linux/irq.h>
 #include <linux/interrupt.h>
+#include <linux/irqdomain.h>
 #include <linux/slab.h>
 
 #include "internal.h"
@@ -26,6 +27,7 @@ struct regmap_irq_chip_data {
        struct regmap_irq_chip *chip;
 
        int irq_base;
+       struct irq_domain *domain;
 
        unsigned int *status_buf;
        unsigned int *mask_buf;
@@ -38,7 +40,7 @@ static inline const
 struct regmap_irq *irq_to_regmap_irq(struct regmap_irq_chip_data *data,
                                     int irq)
 {
-       return &data->chip->irqs[irq - data->irq_base];
+       return &data->chip->irqs[irq];
 }
 
 static void regmap_irq_lock(struct irq_data *data)
@@ -76,7 +78,7 @@ static void regmap_irq_enable(struct irq_data *data)
 {
        struct regmap_irq_chip_data *d = irq_data_get_irq_chip_data(data);
        struct regmap *map = d->map;
-       const struct regmap_irq *irq_data = irq_to_regmap_irq(d, data->irq);
+       const struct regmap_irq *irq_data = irq_to_regmap_irq(d, data->hwirq);
 
        d->mask_buf[irq_data->reg_offset / map->reg_stride] &= ~irq_data->mask;
 }
@@ -85,7 +87,7 @@ static void regmap_irq_disable(struct irq_data *data)
 {
        struct regmap_irq_chip_data *d = irq_data_get_irq_chip_data(data);
        struct regmap *map = d->map;
-       const struct regmap_irq *irq_data = irq_to_regmap_irq(d, data->irq);
+       const struct regmap_irq *irq_data = irq_to_regmap_irq(d, data->hwirq);
 
        d->mask_buf[irq_data->reg_offset / map->reg_stride] |= irq_data->mask;
 }
@@ -141,7 +143,7 @@ static irqreturn_t regmap_irq_thread(int irq, void *d)
        for (i = 0; i < chip->num_irqs; i++) {
                if (data->status_buf[chip->irqs[i].reg_offset /
                                     map->reg_stride] & chip->irqs[i].mask) {
-                       handle_nested_irq(data->irq_base + i);
+                       handle_nested_irq(irq_find_mapping(data->domain, i));
                        handled = true;
                }
        }
@@ -152,6 +154,31 @@ static irqreturn_t regmap_irq_thread(int irq, void *d)
                return IRQ_NONE;
 }
 
+static int regmap_irq_map(struct irq_domain *h, unsigned int virq,
+                         irq_hw_number_t hw)
+{
+       struct regmap_irq_chip_data *data = h->host_data;
+
+       irq_set_chip_data(virq, data);
+       irq_set_chip_and_handler(virq, &regmap_irq_chip, handle_edge_irq);
+       irq_set_nested_thread(virq, 1);
+
+       /* ARM needs us to explicitly flag the IRQ as valid
+        * and will set them noprobe when we do so. */
+#ifdef CONFIG_ARM
+       set_irq_flags(virq, IRQF_VALID);
+#else
+       irq_set_noprobe(virq);
+#endif
+
+       return 0;
+}
+
+static struct irq_domain_ops regmap_domain_ops = {
+       .map    = regmap_irq_map,
+       .xlate  = irq_domain_xlate_twocell,
+};
+
 /**
  * regmap_add_irq_chip(): Use standard regmap IRQ controller handling
  *
@@ -172,7 +199,7 @@ int regmap_add_irq_chip(struct regmap *map, int irq, int irq_flags,
                        struct regmap_irq_chip_data **data)
 {
        struct regmap_irq_chip_data *d;
-       int cur_irq, i;
+       int i;
        int ret = -ENOMEM;
 
        for (i = 0; i < chip->num_irqs; i++) {
@@ -183,11 +210,13 @@ int regmap_add_irq_chip(struct regmap *map, int irq, int irq_flags,
                        return -EINVAL;
        }
 
-       irq_base = irq_alloc_descs(irq_base, 0, chip->num_irqs, 0);
-       if (irq_base < 0) {
-               dev_warn(map->dev, "Failed to allocate IRQs: %d\n",
-                        irq_base);
-               return irq_base;
+       if (irq_base) {
+               irq_base = irq_alloc_descs(irq_base, 0, chip->num_irqs, 0);
+               if (irq_base < 0) {
+                       dev_warn(map->dev, "Failed to allocate IRQs: %d\n",
+                                irq_base);
+                       return irq_base;
+               }
        }
 
        d = kzalloc(sizeof(*d), GFP_KERNEL);
@@ -239,33 +268,31 @@ int regmap_add_irq_chip(struct regmap *map, int irq, int irq_flags,
                }
        }
 
-       /* Register them with genirq */
-       for (cur_irq = irq_base;
-            cur_irq < chip->num_irqs + irq_base;
-            cur_irq++) {
-               irq_set_chip_data(cur_irq, d);
-               irq_set_chip_and_handler(cur_irq, &regmap_irq_chip,
-                                        handle_edge_irq);
-               irq_set_nested_thread(cur_irq, 1);
-
-               /* ARM needs us to explicitly flag the IRQ as valid
-                * and will set them noprobe when we do so. */
-#ifdef CONFIG_ARM
-               set_irq_flags(cur_irq, IRQF_VALID);
-#else
-               irq_set_noprobe(cur_irq);
-#endif
+       if (irq_base)
+               d->domain = irq_domain_add_legacy(map->dev->of_node,
+                                                 chip->num_irqs, irq_base, 0,
+                                                 &regmap_domain_ops, d);
+       else
+               d->domain = irq_domain_add_linear(map->dev->of_node,
+                                                 chip->num_irqs,
+                                                 &regmap_domain_ops, d);
+       if (!d->domain) {
+               dev_err(map->dev, "Failed to create IRQ domain\n");
+               ret = -ENOMEM;
+               goto err_alloc;
        }
 
        ret = request_threaded_irq(irq, NULL, regmap_irq_thread, irq_flags,
                                   chip->name, d);
        if (ret != 0) {
                dev_err(map->dev, "Failed to request IRQ %d: %d\n", irq, ret);
-               goto err_alloc;
+               goto err_domain;
        }
 
        return 0;
 
+err_domain:
+       /* Should really dispose of the domain but... */
 err_alloc:
        kfree(d->mask_buf_def);
        kfree(d->mask_buf);
@@ -287,6 +314,7 @@ void regmap_del_irq_chip(int irq, struct regmap_irq_chip_data *d)
                return;
 
        free_irq(irq, d);
+       /* We should unmap the domain but... */
        kfree(d->mask_buf_def);
        kfree(d->mask_buf);
        kfree(d->status_buf);
@@ -303,6 +331,21 @@ EXPORT_SYMBOL_GPL(regmap_del_irq_chip);
  */
 int regmap_irq_chip_get_base(struct regmap_irq_chip_data *data)
 {
+       WARN_ON(!data->irq_base);
        return data->irq_base;
 }
 EXPORT_SYMBOL_GPL(regmap_irq_chip_get_base);
+
+/**
+ * regmap_irq_get_virq(): Map an interrupt on a chip to a virtual IRQ
+ *
+ * Useful for drivers to request their own IRQs.
+ *
+ * @data: regmap_irq controller to operate on.
+ * @irq: index of the interrupt requested in the chip IRQs
+ */
+int regmap_irq_get_virq(struct regmap_irq_chip_data *data, int irq)
+{
+       return irq_create_mapping(data->domain, irq);
+}
+EXPORT_SYMBOL_GPL(regmap_irq_get_virq);