gpio: simplify adding threaded interrupts
[linux-2.6-block.git] / drivers / gpio / gpiolib.c
index f0fc3a0d37c829de62e3c136f37cdb7a835a11b7..7be4fdafb1a3bad0ba63869e96973daf39cea3fc 100644 (file)
@@ -1439,7 +1439,7 @@ static bool gpiochip_irqchip_irq_valid(const struct gpio_chip *gpiochip,
 }
 
 /**
- * gpiochip_set_chained_irqchip() - sets a chained irqchip to a gpiochip
+ * gpiochip_set_cascaded_irqchip() - connects a cascaded irqchip to a gpiochip
  * @gpiochip: the gpiochip to set the irqchip chain to
  * @irqchip: the irqchip to chain to the gpiochip
  * @parent_irq: the irq number corresponding to the parent IRQ for this
@@ -1448,10 +1448,10 @@ static bool gpiochip_irqchip_irq_valid(const struct gpio_chip *gpiochip,
  * coming out of the gpiochip. If the interrupt is nested rather than
  * cascaded, pass NULL in this handler argument
  */
-void gpiochip_set_chained_irqchip(struct gpio_chip *gpiochip,
-                                 struct irq_chip *irqchip,
-                                 int parent_irq,
-                                 irq_flow_handler_t parent_handler)
+static void gpiochip_set_cascaded_irqchip(struct gpio_chip *gpiochip,
+                                         struct irq_chip *irqchip,
+                                         int parent_irq,
+                                         irq_flow_handler_t parent_handler)
 {
        unsigned int offset;
 
@@ -1475,7 +1475,7 @@ void gpiochip_set_chained_irqchip(struct gpio_chip *gpiochip,
                irq_set_chained_handler_and_data(parent_irq, parent_handler,
                                                 gpiochip);
 
-               gpiochip->irq_parent = parent_irq;
+               gpiochip->irq_chained_parent = parent_irq;
        }
 
        /* Set the parent IRQ for all affected IRQs */
@@ -1486,8 +1486,47 @@ void gpiochip_set_chained_irqchip(struct gpio_chip *gpiochip,
                               parent_irq);
        }
 }
+
+/**
+ * gpiochip_set_chained_irqchip() - connects a chained irqchip to a gpiochip
+ * @gpiochip: the gpiochip to set the irqchip chain to
+ * @irqchip: the irqchip to chain to the gpiochip
+ * @parent_irq: the irq number corresponding to the parent IRQ for this
+ * chained irqchip
+ * @parent_handler: the parent interrupt handler for the accumulated IRQ
+ * coming out of the gpiochip. If the interrupt is nested rather than
+ * cascaded, pass NULL in this handler argument
+ */
+void gpiochip_set_chained_irqchip(struct gpio_chip *gpiochip,
+                                 struct irq_chip *irqchip,
+                                 int parent_irq,
+                                 irq_flow_handler_t parent_handler)
+{
+       gpiochip_set_cascaded_irqchip(gpiochip, irqchip, parent_irq,
+                                     parent_handler);
+}
 EXPORT_SYMBOL_GPL(gpiochip_set_chained_irqchip);
 
+/**
+ * gpiochip_set_nested_irqchip() - connects a nested irqchip to a gpiochip
+ * @gpiochip: the gpiochip to set the irqchip nested handler to
+ * @irqchip: the irqchip to nest to the gpiochip
+ * @parent_irq: the irq number corresponding to the parent IRQ for this
+ * nested irqchip
+ */
+void gpiochip_set_nested_irqchip(struct gpio_chip *gpiochip,
+                                struct irq_chip *irqchip,
+                                int parent_irq)
+{
+       if (!gpiochip->irq_nested) {
+               chip_err(gpiochip, "tried to nest a chained gpiochip\n");
+               return;
+       }
+       gpiochip_set_cascaded_irqchip(gpiochip, irqchip, parent_irq,
+                                     NULL);
+}
+EXPORT_SYMBOL_GPL(gpiochip_set_nested_irqchip);
+
 /**
  * gpiochip_irq_map() - maps an IRQ into a GPIO irqchip
  * @d: the irqdomain used by this irqchip
@@ -1510,8 +1549,8 @@ static int gpiochip_irq_map(struct irq_domain *d, unsigned int irq,
         */
        irq_set_lockdep_class(irq, chip->lock_key);
        irq_set_chip_and_handler(irq, chip->irqchip, chip->irq_handler);
-       /* Chips that can sleep need nested thread handlers */
-       if (chip->can_sleep && !chip->irq_not_threaded)
+       /* Chips that use nested thread handlers have them marked */
+       if (chip->irq_nested)
                irq_set_nested_thread(irq, 1);
        irq_set_noprobe(irq);
 
@@ -1529,7 +1568,7 @@ static void gpiochip_irq_unmap(struct irq_domain *d, unsigned int irq)
 {
        struct gpio_chip *chip = d->host_data;
 
-       if (chip->can_sleep)
+       if (chip->irq_nested)
                irq_set_nested_thread(irq, 0);
        irq_set_chip_and_handler(irq, NULL, NULL);
        irq_set_chip_data(irq, NULL);
@@ -1584,9 +1623,9 @@ static void gpiochip_irqchip_remove(struct gpio_chip *gpiochip)
 
        acpi_gpiochip_free_interrupts(gpiochip);
 
-       if (gpiochip->irq_parent) {
-               irq_set_chained_handler(gpiochip->irq_parent, NULL);
-               irq_set_handler_data(gpiochip->irq_parent, NULL);
+       if (gpiochip->irq_chained_parent) {
+               irq_set_chained_handler(gpiochip->irq_chained_parent, NULL);
+               irq_set_handler_data(gpiochip->irq_chained_parent, NULL);
        }
 
        /* Remove all IRQ mappings and delete the domain */
@@ -1610,7 +1649,7 @@ static void gpiochip_irqchip_remove(struct gpio_chip *gpiochip)
 }
 
 /**
- * gpiochip_irqchip_add() - adds an irqchip to a gpiochip
+ * _gpiochip_irqchip_add() - adds an irqchip to a gpiochip
  * @gpiochip: the gpiochip to add the irqchip to
  * @irqchip: the irqchip to add to the gpiochip
  * @first_irq: if not dynamically assigned, the base (first) IRQ to
@@ -1618,6 +1657,8 @@ static void gpiochip_irqchip_remove(struct gpio_chip *gpiochip)
  * @handler: the irq handler to use (often a predefined irq core function)
  * @type: the default type for IRQs on this irqchip, pass IRQ_TYPE_NONE
  * to have the core avoid setting up any default type in the hardware.
+ * @nested: whether this is a nested irqchip calling handle_nested_irq()
+ * in its IRQ handler
  * @lock_key: lockdep class
  *
  * This function closely associates a certain irqchip with a certain
@@ -1639,6 +1680,7 @@ int _gpiochip_irqchip_add(struct gpio_chip *gpiochip,
                          unsigned int first_irq,
                          irq_flow_handler_t handler,
                          unsigned int type,
+                         bool nested,
                          struct lock_class_key *lock_key)
 {
        struct device_node *of_node;
@@ -1653,6 +1695,7 @@ int _gpiochip_irqchip_add(struct gpio_chip *gpiochip,
                pr_err("missing gpiochip .dev parent pointer\n");
                return -EINVAL;
        }
+       gpiochip->irq_nested = nested;
        of_node = gpiochip->parent->of_node;
 #ifdef CONFIG_OF_GPIO
        /*