Merge branch 'parisc-4.9-1' of git://git.kernel.org/pub/scm/linux/kernel/git/deller...
[cascardo/linux.git] / drivers / gpio / gpiolib.c
index 53ff25a..f0fc3a0 100644 (file)
@@ -71,6 +71,8 @@ LIST_HEAD(gpio_devices);
 
 static void gpiochip_free_hogs(struct gpio_chip *chip);
 static void gpiochip_irqchip_remove(struct gpio_chip *gpiochip);
+static int gpiochip_irqchip_init_valid_mask(struct gpio_chip *gpiochip);
+static void gpiochip_irqchip_free_valid_mask(struct gpio_chip *gpiochip);
 
 static bool gpiolib_initialized;
 
@@ -1167,6 +1169,10 @@ int gpiochip_add_data(struct gpio_chip *chip, void *data)
        if (status)
                goto err_remove_from_list;
 
+       status = gpiochip_irqchip_init_valid_mask(chip);
+       if (status)
+               goto err_remove_from_list;
+
        status = of_gpiochip_add(chip);
        if (status)
                goto err_remove_chip;
@@ -1192,6 +1198,7 @@ err_remove_chip:
        acpi_gpiochip_remove(chip);
        gpiochip_free_hogs(chip);
        of_gpiochip_remove(chip);
+       gpiochip_irqchip_free_valid_mask(chip);
 err_remove_from_list:
        spin_lock_irqsave(&gpio_lock, flags);
        list_del(&gdev->list);
@@ -1363,19 +1370,15 @@ struct gpio_chip *gpiochip_find(void *data,
                                             void *data))
 {
        struct gpio_device *gdev;
-       struct gpio_chip *chip;
+       struct gpio_chip *chip = NULL;
        unsigned long flags;
 
        spin_lock_irqsave(&gpio_lock, flags);
        list_for_each_entry(gdev, &gpio_devices, list)
-               if (gdev->chip && match(gdev->chip, data))
+               if (gdev->chip && match(gdev->chip, data)) {
+                       chip = gdev->chip;
                        break;
-
-       /* No match? */
-       if (&gdev->list == &gpio_devices)
-               chip = NULL;
-       else
-               chip = gdev->chip;
+               }
 
        spin_unlock_irqrestore(&gpio_lock, flags);
 
@@ -1401,6 +1404,40 @@ static struct gpio_chip *find_chip_by_name(const char *name)
  * The following is irqchip helper code for gpiochips.
  */
 
+static int gpiochip_irqchip_init_valid_mask(struct gpio_chip *gpiochip)
+{
+       int i;
+
+       if (!gpiochip->irq_need_valid_mask)
+               return 0;
+
+       gpiochip->irq_valid_mask = kcalloc(BITS_TO_LONGS(gpiochip->ngpio),
+                                          sizeof(long), GFP_KERNEL);
+       if (!gpiochip->irq_valid_mask)
+               return -ENOMEM;
+
+       /* Assume by default all GPIOs are valid */
+       for (i = 0; i < gpiochip->ngpio; i++)
+               set_bit(i, gpiochip->irq_valid_mask);
+
+       return 0;
+}
+
+static void gpiochip_irqchip_free_valid_mask(struct gpio_chip *gpiochip)
+{
+       kfree(gpiochip->irq_valid_mask);
+       gpiochip->irq_valid_mask = NULL;
+}
+
+static bool gpiochip_irqchip_irq_valid(const struct gpio_chip *gpiochip,
+                                      unsigned int offset)
+{
+       /* No mask means all valid */
+       if (likely(!gpiochip->irq_valid_mask))
+               return true;
+       return test_bit(offset, gpiochip->irq_valid_mask);
+}
+
 /**
  * gpiochip_set_chained_irqchip() - sets a chained irqchip to a gpiochip
  * @gpiochip: the gpiochip to set the irqchip chain to
@@ -1442,9 +1479,12 @@ void gpiochip_set_chained_irqchip(struct gpio_chip *gpiochip,
        }
 
        /* Set the parent IRQ for all affected IRQs */
-       for (offset = 0; offset < gpiochip->ngpio; offset++)
+       for (offset = 0; offset < gpiochip->ngpio; offset++) {
+               if (!gpiochip_irqchip_irq_valid(gpiochip, offset))
+                       continue;
                irq_set_parent(irq_find_mapping(gpiochip->irqdomain, offset),
                               parent_irq);
+       }
 }
 EXPORT_SYMBOL_GPL(gpiochip_set_chained_irqchip);
 
@@ -1551,9 +1591,12 @@ static void gpiochip_irqchip_remove(struct gpio_chip *gpiochip)
 
        /* Remove all IRQ mappings and delete the domain */
        if (gpiochip->irqdomain) {
-               for (offset = 0; offset < gpiochip->ngpio; offset++)
+               for (offset = 0; offset < gpiochip->ngpio; offset++) {
+                       if (!gpiochip_irqchip_irq_valid(gpiochip, offset))
+                               continue;
                        irq_dispose_mapping(
                                irq_find_mapping(gpiochip->irqdomain, offset));
+               }
                irq_domain_remove(gpiochip->irqdomain);
        }
 
@@ -1562,6 +1605,8 @@ static void gpiochip_irqchip_remove(struct gpio_chip *gpiochip)
                gpiochip->irqchip->irq_release_resources = NULL;
                gpiochip->irqchip = NULL;
        }
+
+       gpiochip_irqchip_free_valid_mask(gpiochip);
 }
 
 /**
@@ -1597,6 +1642,7 @@ int _gpiochip_irqchip_add(struct gpio_chip *gpiochip,
                          struct lock_class_key *lock_key)
 {
        struct device_node *of_node;
+       bool irq_base_set = false;
        unsigned int offset;
        unsigned irq_base = 0;
 
@@ -1617,6 +1663,20 @@ int _gpiochip_irqchip_add(struct gpio_chip *gpiochip,
        if (gpiochip->of_node)
                of_node = gpiochip->of_node;
 #endif
+       /*
+        * Specifying a default trigger is a terrible idea if DT or ACPI is
+        * used to configure the interrupts, as you may end-up with
+        * conflicting triggers. Tell the user, and reset to NONE.
+        */
+       if (WARN(of_node && type != IRQ_TYPE_NONE,
+                "%s: Ignoring %d default trigger\n", of_node->full_name, type))
+               type = IRQ_TYPE_NONE;
+       if (has_acpi_companion(gpiochip->parent) && type != IRQ_TYPE_NONE) {
+               acpi_handle_warn(ACPI_HANDLE(gpiochip->parent),
+                                "Ignoring %d default trigger\n", type);
+               type = IRQ_TYPE_NONE;
+       }
+
        gpiochip->irqchip = irqchip;
        gpiochip->irq_handler = handler;
        gpiochip->irq_default_type = type;
@@ -1646,13 +1706,17 @@ int _gpiochip_irqchip_add(struct gpio_chip *gpiochip,
         * necessary to allocate descriptors for all IRQs.
         */
        for (offset = 0; offset < gpiochip->ngpio; offset++) {
+               if (!gpiochip_irqchip_irq_valid(gpiochip, offset))
+                       continue;
                irq_base = irq_create_mapping(gpiochip->irqdomain, offset);
-               if (offset == 0)
+               if (!irq_base_set) {
                        /*
                         * Store the base into the gpiochip to be used when
                         * unmapping the irqs.
                         */
                        gpiochip->irq_base = irq_base;
+                       irq_base_set = true;
+               }
        }
 
        acpi_gpiochip_request_interrupts(gpiochip);
@@ -1664,6 +1728,12 @@ EXPORT_SYMBOL_GPL(_gpiochip_irqchip_add);
 #else /* CONFIG_GPIOLIB_IRQCHIP */
 
 static void gpiochip_irqchip_remove(struct gpio_chip *gpiochip) {}
+static inline int gpiochip_irqchip_init_valid_mask(struct gpio_chip *gpiochip)
+{
+       return 0;
+}
+static inline void gpiochip_irqchip_free_valid_mask(struct gpio_chip *gpiochip)
+{ }
 
 #endif /* CONFIG_GPIOLIB_IRQCHIP */
 
@@ -2813,94 +2883,6 @@ void gpiod_remove_lookup_table(struct gpiod_lookup_table *table)
        mutex_unlock(&gpio_lookup_lock);
 }
 
-static struct gpio_desc *of_find_gpio(struct device *dev, const char *con_id,
-                                     unsigned int idx,
-                                     enum gpio_lookup_flags *flags)
-{
-       char prop_name[32]; /* 32 is max size of property name */
-       enum of_gpio_flags of_flags;
-       struct gpio_desc *desc;
-       unsigned int i;
-
-       for (i = 0; i < ARRAY_SIZE(gpio_suffixes); i++) {
-               if (con_id)
-                       snprintf(prop_name, sizeof(prop_name), "%s-%s", con_id,
-                                gpio_suffixes[i]);
-               else
-                       snprintf(prop_name, sizeof(prop_name), "%s",
-                                gpio_suffixes[i]);
-
-               desc = of_get_named_gpiod_flags(dev->of_node, prop_name, idx,
-                                               &of_flags);
-               if (!IS_ERR(desc) || (PTR_ERR(desc) != -ENOENT))
-                       break;
-       }
-
-       if (IS_ERR(desc))
-               return desc;
-
-       if (of_flags & OF_GPIO_ACTIVE_LOW)
-               *flags |= GPIO_ACTIVE_LOW;
-
-       if (of_flags & OF_GPIO_SINGLE_ENDED) {
-               if (of_flags & OF_GPIO_ACTIVE_LOW)
-                       *flags |= GPIO_OPEN_DRAIN;
-               else
-                       *flags |= GPIO_OPEN_SOURCE;
-       }
-
-       return desc;
-}
-
-static struct gpio_desc *acpi_find_gpio(struct device *dev,
-                                       const char *con_id,
-                                       unsigned int idx,
-                                       enum gpiod_flags flags,
-                                       enum gpio_lookup_flags *lookupflags)
-{
-       struct acpi_device *adev = ACPI_COMPANION(dev);
-       struct acpi_gpio_info info;
-       struct gpio_desc *desc;
-       char propname[32];
-       int i;
-
-       /* Try first from _DSD */
-       for (i = 0; i < ARRAY_SIZE(gpio_suffixes); i++) {
-               if (con_id && strcmp(con_id, "gpios")) {
-                       snprintf(propname, sizeof(propname), "%s-%s",
-                                con_id, gpio_suffixes[i]);
-               } else {
-                       snprintf(propname, sizeof(propname), "%s",
-                                gpio_suffixes[i]);
-               }
-
-               desc = acpi_get_gpiod_by_index(adev, propname, idx, &info);
-               if (!IS_ERR(desc) || (PTR_ERR(desc) == -EPROBE_DEFER))
-                       break;
-       }
-
-       /* Then from plain _CRS GPIOs */
-       if (IS_ERR(desc)) {
-               if (!acpi_can_fallback_to_crs(adev, con_id))
-                       return ERR_PTR(-ENOENT);
-
-               desc = acpi_get_gpiod_by_index(adev, NULL, idx, &info);
-               if (IS_ERR(desc))
-                       return desc;
-
-               if ((flags == GPIOD_OUT_LOW || flags == GPIOD_OUT_HIGH) &&
-                   info.gpioint) {
-                       dev_dbg(dev, "refusing GpioInt() entry when doing GPIOD_OUT_* lookup\n");
-                       return ERR_PTR(-ENOENT);
-               }
-       }
-
-       if (info.polarity == GPIO_ACTIVE_LOW)
-               *lookupflags |= GPIO_ACTIVE_LOW;
-
-       return desc;
-}
-
 static struct gpiod_lookup_table *gpiod_find_lookup_table(struct device *dev)
 {
        const char *dev_id = dev ? dev_name(dev) : NULL;