Merge tag 'tags/bcm2835-drivers-next-2019-03-12' into soc/fixes
[sfrench/cifs-2.6.git] / drivers / gpio / gpiolib.c
index d1adfdf50fb301b3f0be76af309963b955c31884..144af07335815998c7238b72e01882cf26692ef8 100644 (file)
@@ -1782,6 +1782,43 @@ static const struct irq_domain_ops gpiochip_domain_ops = {
        .xlate  = irq_domain_xlate_twocell,
 };
 
+/**
+ * gpiochip_irq_domain_activate() - Lock a GPIO to be used as an IRQ
+ * @domain: The IRQ domain used by this IRQ chip
+ * @data: Outermost irq_data associated with the IRQ
+ * @reserve: If set, only reserve an interrupt vector instead of assigning one
+ *
+ * This function is a wrapper that calls gpiochip_lock_as_irq() and is to be
+ * used as the activate function for the &struct irq_domain_ops. The host_data
+ * for the IRQ domain must be the &struct gpio_chip.
+ */
+int gpiochip_irq_domain_activate(struct irq_domain *domain,
+                                struct irq_data *data, bool reserve)
+{
+       struct gpio_chip *chip = domain->host_data;
+
+       return gpiochip_lock_as_irq(chip, data->hwirq);
+}
+EXPORT_SYMBOL_GPL(gpiochip_irq_domain_activate);
+
+/**
+ * gpiochip_irq_domain_deactivate() - Unlock a GPIO used as an IRQ
+ * @domain: The IRQ domain used by this IRQ chip
+ * @data: Outermost irq_data associated with the IRQ
+ *
+ * This function is a wrapper that will call gpiochip_unlock_as_irq() and is to
+ * be used as the deactivate function for the &struct irq_domain_ops. The
+ * host_data for the IRQ domain must be the &struct gpio_chip.
+ */
+void gpiochip_irq_domain_deactivate(struct irq_domain *domain,
+                                   struct irq_data *data)
+{
+       struct gpio_chip *chip = domain->host_data;
+
+       return gpiochip_unlock_as_irq(chip, data->hwirq);
+}
+EXPORT_SYMBOL_GPL(gpiochip_irq_domain_deactivate);
+
 static int gpiochip_to_irq(struct gpio_chip *chip, unsigned offset)
 {
        if (!gpiochip_irqchip_irq_valid(chip, offset))
@@ -2525,6 +2562,14 @@ EXPORT_SYMBOL_GPL(gpiochip_free_own_desc);
  * rely on gpio_request() having been called beforehand.
  */
 
+static int gpio_set_config(struct gpio_chip *gc, unsigned offset,
+                          enum pin_config_param mode)
+{
+       unsigned long config = { PIN_CONF_PACKED(mode, 0) };
+
+       return gc->set_config ? gc->set_config(gc, offset, config) : -ENOTSUPP;
+}
+
 /**
  * gpiod_direction_input - set the GPIO direction to input
  * @desc:      GPIO to set to input
@@ -2572,20 +2617,19 @@ int gpiod_direction_input(struct gpio_desc *desc)
        if (status == 0)
                clear_bit(FLAG_IS_OUT, &desc->flags);
 
+       if (test_bit(FLAG_PULL_UP, &desc->flags))
+               gpio_set_config(chip, gpio_chip_hwgpio(desc),
+                               PIN_CONFIG_BIAS_PULL_UP);
+       else if (test_bit(FLAG_PULL_DOWN, &desc->flags))
+               gpio_set_config(chip, gpio_chip_hwgpio(desc),
+                               PIN_CONFIG_BIAS_PULL_DOWN);
+
        trace_gpio_direction(desc_to_gpio(desc), 1, status);
 
        return status;
 }
 EXPORT_SYMBOL_GPL(gpiod_direction_input);
 
-static int gpio_set_drive_single_ended(struct gpio_chip *gc, unsigned offset,
-                                      enum pin_config_param mode)
-{
-       unsigned long config = { PIN_CONF_PACKED(mode, 0) };
-
-       return gc->set_config ? gc->set_config(gc, offset, config) : -ENOTSUPP;
-}
-
 static int gpiod_direction_output_raw_commit(struct gpio_desc *desc, int value)
 {
        struct gpio_chip *gc = desc->gdev->chip;
@@ -2682,8 +2726,8 @@ int gpiod_direction_output(struct gpio_desc *desc, int value)
        gc = desc->gdev->chip;
        if (test_bit(FLAG_OPEN_DRAIN, &desc->flags)) {
                /* First see if we can enable open drain in hardware */
-               ret = gpio_set_drive_single_ended(gc, gpio_chip_hwgpio(desc),
-                                                 PIN_CONFIG_DRIVE_OPEN_DRAIN);
+               ret = gpio_set_config(gc, gpio_chip_hwgpio(desc),
+                                     PIN_CONFIG_DRIVE_OPEN_DRAIN);
                if (!ret)
                        goto set_output_value;
                /* Emulate open drain by not actively driving the line high */
@@ -2691,16 +2735,16 @@ int gpiod_direction_output(struct gpio_desc *desc, int value)
                        return gpiod_direction_input(desc);
        }
        else if (test_bit(FLAG_OPEN_SOURCE, &desc->flags)) {
-               ret = gpio_set_drive_single_ended(gc, gpio_chip_hwgpio(desc),
-                                                 PIN_CONFIG_DRIVE_OPEN_SOURCE);
+               ret = gpio_set_config(gc, gpio_chip_hwgpio(desc),
+                                     PIN_CONFIG_DRIVE_OPEN_SOURCE);
                if (!ret)
                        goto set_output_value;
                /* Emulate open source by not actively driving the line low */
                if (!value)
                        return gpiod_direction_input(desc);
        } else {
-               gpio_set_drive_single_ended(gc, gpio_chip_hwgpio(desc),
-                                           PIN_CONFIG_DRIVE_PUSH_PULL);
+               gpio_set_config(gc, gpio_chip_hwgpio(desc),
+                               PIN_CONFIG_DRIVE_PUSH_PULL);
        }
 
 set_output_value:
@@ -2732,7 +2776,7 @@ int gpiod_set_debounce(struct gpio_desc *desc, unsigned debounce)
        }
 
        config = pinconf_to_config_packed(PIN_CONFIG_INPUT_DEBOUNCE, debounce);
-       return chip->set_config(chip, gpio_chip_hwgpio(desc), config);
+       return gpio_set_config(chip, gpio_chip_hwgpio(desc), config);
 }
 EXPORT_SYMBOL_GPL(gpiod_set_debounce);
 
@@ -2769,7 +2813,7 @@ int gpiod_set_transitory(struct gpio_desc *desc, bool transitory)
        packed = pinconf_to_config_packed(PIN_CONFIG_PERSIST_STATE,
                                          !transitory);
        gpio = gpio_chip_hwgpio(desc);
-       rc = chip->set_config(chip, gpio, packed);
+       rc = gpio_set_config(chip, gpio, packed);
        if (rc == -ENOTSUPP) {
                dev_dbg(&desc->gdev->dev, "Persistence not supported for GPIO %d\n",
                                gpio);
@@ -4057,6 +4101,17 @@ int gpiod_configure_flags(struct gpio_desc *desc, const char *con_id,
        if (lflags & GPIO_OPEN_SOURCE)
                set_bit(FLAG_OPEN_SOURCE, &desc->flags);
 
+       if ((lflags & GPIO_PULL_UP) && (lflags & GPIO_PULL_DOWN)) {
+               gpiod_err(desc,
+                         "both pull-up and pull-down enabled, invalid configuration\n");
+               return -EINVAL;
+       }
+
+       if (lflags & GPIO_PULL_UP)
+               set_bit(FLAG_PULL_UP, &desc->flags);
+       else if (lflags & GPIO_PULL_DOWN)
+               set_bit(FLAG_PULL_DOWN, &desc->flags);
+
        status = gpiod_set_transitory(desc, (lflags & GPIO_TRANSITORY));
        if (status < 0)
                return status;