Merge tag 'io_uring-5.19-2022-07-01' of git://git.kernel.dk/linux-block
[linux-2.6-microblaze.git] / drivers / gpio / gpiolib.c
index b769417..9535f48 100644 (file)
@@ -189,9 +189,8 @@ static int gpiochip_find_base(int ngpio)
                /* found a free space? */
                if (gdev->base + gdev->ngpio <= base)
                        break;
-               else
-                       /* nope, check the space right before the chip */
-                       base = gdev->base - ngpio;
+               /* nope, check the space right before the chip */
+               base = gdev->base - ngpio;
        }
 
        if (gpio_is_valid(base)) {
@@ -289,7 +288,6 @@ static int gpiodev_add_to_list(struct gpio_device *gdev)
                }
        }
 
-       dev_err(&gdev->dev, "GPIO integer space overlap, cannot add chip\n");
        return -EBUSY;
 }
 
@@ -310,15 +308,10 @@ static struct gpio_desc *gpio_name_to_desc(const char * const name)
        spin_lock_irqsave(&gpio_lock, flags);
 
        list_for_each_entry(gdev, &gpio_devices, list) {
-               int i;
+               struct gpio_desc *desc;
 
-               for (i = 0; i != gdev->ngpio; ++i) {
-                       struct gpio_desc *desc = &gdev->descs[i];
-
-                       if (!desc->name)
-                               continue;
-
-                       if (!strcmp(desc->name, name)) {
+               for_each_gpio_desc(gdev->chip, desc) {
+                       if (desc->name && !strcmp(desc->name, name)) {
                                spin_unlock_irqrestore(&gpio_lock, flags);
                                return desc;
                        }
@@ -728,6 +721,7 @@ int gpiochip_add_data_with_key(struct gpio_chip *gc, void *data,
        ret = gpiodev_add_to_list(gdev);
        if (ret) {
                spin_unlock_irqrestore(&gpio_lock, flags);
+               chip_err(gc, "GPIO integer space overlap, cannot add chip\n");
                goto err_free_label;
        }
 
@@ -1433,19 +1427,21 @@ static int gpiochip_to_irq(struct gpio_chip *gc, unsigned int offset)
        return irq_create_mapping(domain, offset);
 }
 
-static int gpiochip_irq_reqres(struct irq_data *d)
+int gpiochip_irq_reqres(struct irq_data *d)
 {
        struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
 
        return gpiochip_reqres_irq(gc, d->hwirq);
 }
+EXPORT_SYMBOL(gpiochip_irq_reqres);
 
-static void gpiochip_irq_relres(struct irq_data *d)
+void gpiochip_irq_relres(struct irq_data *d)
 {
        struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
 
        gpiochip_relres_irq(gc, d->hwirq);
 }
+EXPORT_SYMBOL(gpiochip_irq_relres);
 
 static void gpiochip_irq_mask(struct irq_data *d)
 {
@@ -1485,6 +1481,11 @@ static void gpiochip_set_irq_hooks(struct gpio_chip *gc)
 {
        struct irq_chip *irqchip = gc->irq.chip;
 
+       if (irqchip->flags & IRQCHIP_IMMUTABLE)
+               return;
+
+       chip_warn(gc, "not an immutable chip, please consider fixing it!\n");
+
        if (!irqchip->irq_request_resources &&
            !irqchip->irq_release_resources) {
                irqchip->irq_request_resources = gpiochip_irq_reqres;
@@ -1652,7 +1653,7 @@ static void gpiochip_irqchip_remove(struct gpio_chip *gc)
                irq_domain_remove(gc->irq.domain);
        }
 
-       if (irqchip) {
+       if (irqchip && !(irqchip->flags & IRQCHIP_IMMUTABLE)) {
                if (irqchip->irq_request_resources == gpiochip_irq_reqres) {
                        irqchip->irq_request_resources = NULL;
                        irqchip->irq_release_resources = NULL;
@@ -2420,8 +2421,7 @@ int gpiod_direction_output(struct gpio_desc *desc, int value)
                        ret = gpiod_direction_input(desc);
                        goto set_output_flag;
                }
-       }
-       else if (test_bit(FLAG_OPEN_SOURCE, &desc->flags)) {
+       } else if (test_bit(FLAG_OPEN_SOURCE, &desc->flags)) {
                ret = gpio_set_config(desc, PIN_CONFIG_DRIVE_OPEN_SOURCE);
                if (!ret)
                        goto set_output_value;
@@ -2453,6 +2453,64 @@ set_output_flag:
 }
 EXPORT_SYMBOL_GPL(gpiod_direction_output);
 
+/**
+ * gpiod_enable_hw_timestamp_ns - Enable hardware timestamp in nanoseconds.
+ *
+ * @desc: GPIO to enable.
+ * @flags: Flags related to GPIO edge.
+ *
+ * Return 0 in case of success, else negative error code.
+ */
+int gpiod_enable_hw_timestamp_ns(struct gpio_desc *desc, unsigned long flags)
+{
+       int ret = 0;
+       struct gpio_chip *gc;
+
+       VALIDATE_DESC(desc);
+
+       gc = desc->gdev->chip;
+       if (!gc->en_hw_timestamp) {
+               gpiod_warn(desc, "%s: hw ts not supported\n", __func__);
+               return -ENOTSUPP;
+       }
+
+       ret = gc->en_hw_timestamp(gc, gpio_chip_hwgpio(desc), flags);
+       if (ret)
+               gpiod_warn(desc, "%s: hw ts request failed\n", __func__);
+
+       return ret;
+}
+EXPORT_SYMBOL_GPL(gpiod_enable_hw_timestamp_ns);
+
+/**
+ * gpiod_disable_hw_timestamp_ns - Disable hardware timestamp.
+ *
+ * @desc: GPIO to disable.
+ * @flags: Flags related to GPIO edge, same value as used during enable call.
+ *
+ * Return 0 in case of success, else negative error code.
+ */
+int gpiod_disable_hw_timestamp_ns(struct gpio_desc *desc, unsigned long flags)
+{
+       int ret = 0;
+       struct gpio_chip *gc;
+
+       VALIDATE_DESC(desc);
+
+       gc = desc->gdev->chip;
+       if (!gc->dis_hw_timestamp) {
+               gpiod_warn(desc, "%s: hw ts not supported\n", __func__);
+               return -ENOTSUPP;
+       }
+
+       ret = gc->dis_hw_timestamp(gc, gpio_chip_hwgpio(desc), flags);
+       if (ret)
+               gpiod_warn(desc, "%s: hw ts release failed\n", __func__);
+
+       return ret;
+}
+EXPORT_SYMBOL_GPL(gpiod_disable_hw_timestamp_ns);
+
 /**
  * gpiod_set_config - sets @config for a GPIO
  * @desc: descriptor of the GPIO for which to set the configuration
@@ -2539,6 +2597,11 @@ void gpiod_toggle_active_low(struct gpio_desc *desc)
 }
 EXPORT_SYMBOL_GPL(gpiod_toggle_active_low);
 
+static int gpio_chip_get_value(struct gpio_chip *gc, const struct gpio_desc *desc)
+{
+       return gc->get ? gc->get(gc, gpio_chip_hwgpio(desc)) : -EIO;
+}
+
 /* I/O calls are only valid after configuration completed; the relevant
  * "is this a valid GPIO" error checks should already have been done.
  *
@@ -2564,12 +2627,10 @@ EXPORT_SYMBOL_GPL(gpiod_toggle_active_low);
 static int gpiod_get_raw_value_commit(const struct gpio_desc *desc)
 {
        struct gpio_chip        *gc;
-       int offset;
        int value;
 
        gc = desc->gdev->chip;
-       offset = gpio_chip_hwgpio(desc);
-       value = gc->get ? gc->get(gc, offset) : -EIO;
+       value = gpio_chip_get_value(gc, desc);
        value = value < 0 ? value : !!value;
        trace_gpio_value(desc_to_gpio(desc), 1, value);
        return value;
@@ -2578,9 +2639,9 @@ static int gpiod_get_raw_value_commit(const struct gpio_desc *desc)
 static int gpio_chip_get_multiple(struct gpio_chip *gc,
                                  unsigned long *mask, unsigned long *bits)
 {
-       if (gc->get_multiple) {
+       if (gc->get_multiple)
                return gc->get_multiple(gc, mask, bits);
-       } else if (gc->get) {
+       if (gc->get) {
                int i, value;
 
                for_each_set_bit(i, mask, gc->ngpio) {
@@ -4140,9 +4201,8 @@ int gpiod_hog(struct gpio_desc *desc, const char *name,
 static void gpiochip_free_hogs(struct gpio_chip *gc)
 {
        struct gpio_desc *desc;
-       int id;
 
-       for_each_gpio_desc_with_flag(id, gc, desc, FLAG_IS_HOGGED)
+       for_each_gpio_desc_with_flag(gc, desc, FLAG_IS_HOGGED)
                gpiochip_free_own_desc(desc);
 }
 
@@ -4402,34 +4462,32 @@ core_initcall(gpiolib_dev_init);
 
 static void gpiolib_dbg_show(struct seq_file *s, struct gpio_device *gdev)
 {
-       unsigned                i;
        struct gpio_chip        *gc = gdev->chip;
+       struct gpio_desc        *desc;
        unsigned                gpio = gdev->base;
-       struct gpio_desc        *gdesc = &gdev->descs[0];
+       int                     value;
        bool                    is_out;
        bool                    is_irq;
        bool                    active_low;
 
-       for (i = 0; i < gdev->ngpio; i++, gpio++, gdesc++) {
-               if (!test_bit(FLAG_REQUESTED, &gdesc->flags)) {
-                       if (gdesc->name) {
-                               seq_printf(s, " gpio-%-3d (%-20.20s)\n",
-                                          gpio, gdesc->name);
-                       }
-                       continue;
+       for_each_gpio_desc(gc, desc) {
+               if (test_bit(FLAG_REQUESTED, &desc->flags)) {
+                       gpiod_get_direction(desc);
+                       is_out = test_bit(FLAG_IS_OUT, &desc->flags);
+                       value = gpio_chip_get_value(gc, desc);
+                       is_irq = test_bit(FLAG_USED_AS_IRQ, &desc->flags);
+                       active_low = test_bit(FLAG_ACTIVE_LOW, &desc->flags);
+                       seq_printf(s, " gpio-%-3d (%-20.20s|%-20.20s) %s %s %s%s\n",
+                                  gpio, desc->name ?: "", desc->label,
+                                  is_out ? "out" : "in ",
+                                  value >= 0 ? (value ? "hi" : "lo") : "?  ",
+                                  is_irq ? "IRQ " : "",
+                                  active_low ? "ACTIVE LOW" : "");
+               } else if (desc->name) {
+                       seq_printf(s, " gpio-%-3d (%-20.20s)\n", gpio, desc->name);
                }
 
-               gpiod_get_direction(gdesc);
-               is_out = test_bit(FLAG_IS_OUT, &gdesc->flags);
-               is_irq = test_bit(FLAG_USED_AS_IRQ, &gdesc->flags);
-               active_low = test_bit(FLAG_ACTIVE_LOW, &gdesc->flags);
-               seq_printf(s, " gpio-%-3d (%-20.20s|%-20.20s) %s %s %s%s",
-                       gpio, gdesc->name ? gdesc->name : "", gdesc->label,
-                       is_out ? "out" : "in ",
-                       gc->get ? (gc->get(gc, i) ? "hi" : "lo") : "?  ",
-                       is_irq ? "IRQ " : "",
-                       active_low ? "ACTIVE LOW" : "");
-               seq_printf(s, "\n");
+               gpio++;
        }
 }