Merge tag 'v5.4-rc6' into devel
[linux-2.6-microblaze.git] / drivers / gpio / gpiolib.c
index 104ed29..9afbc06 100644 (file)
@@ -422,6 +422,8 @@ struct linehandle_state {
        (GPIOHANDLE_REQUEST_INPUT | \
        GPIOHANDLE_REQUEST_OUTPUT | \
        GPIOHANDLE_REQUEST_ACTIVE_LOW | \
+       GPIOHANDLE_REQUEST_PULL_UP | \
+       GPIOHANDLE_REQUEST_PULL_DOWN | \
        GPIOHANDLE_REQUEST_OPEN_DRAIN | \
        GPIOHANDLE_REQUEST_OPEN_SOURCE)
 
@@ -593,6 +595,10 @@ static int linehandle_create(struct gpio_device *gdev, void __user *ip)
                        set_bit(FLAG_OPEN_DRAIN, &desc->flags);
                if (lflags & GPIOHANDLE_REQUEST_OPEN_SOURCE)
                        set_bit(FLAG_OPEN_SOURCE, &desc->flags);
+               if (lflags & GPIOHANDLE_REQUEST_PULL_DOWN)
+                       set_bit(FLAG_PULL_DOWN, &desc->flags);
+               if (lflags & GPIOHANDLE_REQUEST_PULL_UP)
+                       set_bit(FLAG_PULL_UP, &desc->flags);
 
                ret = gpiod_set_transitory(desc, false);
                if (ret < 0)
@@ -895,6 +901,24 @@ static int lineevent_create(struct gpio_device *gdev, void __user *ip)
        if (copy_from_user(&eventreq, ip, sizeof(eventreq)))
                return -EFAULT;
 
+       offset = eventreq.lineoffset;
+       lflags = eventreq.handleflags;
+       eflags = eventreq.eventflags;
+
+       if (offset >= gdev->ngpio)
+               return -EINVAL;
+
+       /* Return an error if a unknown flag is set */
+       if ((lflags & ~GPIOHANDLE_REQUEST_VALID_FLAGS) ||
+           (eflags & ~GPIOEVENT_REQUEST_VALID_FLAGS))
+               return -EINVAL;
+
+       /* This is just wrong: we don't look for events on output lines */
+       if ((lflags & GPIOHANDLE_REQUEST_OUTPUT) ||
+           (lflags & GPIOHANDLE_REQUEST_OPEN_DRAIN) ||
+           (lflags & GPIOHANDLE_REQUEST_OPEN_SOURCE))
+               return -EINVAL;
+
        le = kzalloc(sizeof(*le), GFP_KERNEL);
        if (!le)
                return -ENOMEM;
@@ -912,30 +936,6 @@ static int lineevent_create(struct gpio_device *gdev, void __user *ip)
                }
        }
 
-       offset = eventreq.lineoffset;
-       lflags = eventreq.handleflags;
-       eflags = eventreq.eventflags;
-
-       if (offset >= gdev->ngpio) {
-               ret = -EINVAL;
-               goto out_free_label;
-       }
-
-       /* Return an error if a unknown flag is set */
-       if ((lflags & ~GPIOHANDLE_REQUEST_VALID_FLAGS) ||
-           (eflags & ~GPIOEVENT_REQUEST_VALID_FLAGS)) {
-               ret = -EINVAL;
-               goto out_free_label;
-       }
-
-       /* This is just wrong: we don't look for events on output lines */
-       if ((lflags & GPIOHANDLE_REQUEST_OUTPUT) ||
-           (lflags & GPIOHANDLE_REQUEST_OPEN_DRAIN) ||
-           (lflags & GPIOHANDLE_REQUEST_OPEN_SOURCE)) {
-               ret = -EINVAL;
-               goto out_free_label;
-       }
-
        desc = &gdev->descs[offset];
        ret = gpiod_request(desc, le->label);
        if (ret)
@@ -1098,6 +1098,10 @@ static long gpio_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
                if (test_bit(FLAG_OPEN_SOURCE, &desc->flags))
                        lineinfo.flags |= (GPIOLINE_FLAG_OPEN_SOURCE |
                                           GPIOLINE_FLAG_IS_OUT);
+               if (test_bit(FLAG_PULL_DOWN, &desc->flags))
+                       lineinfo.flags |= GPIOLINE_FLAG_PULL_DOWN;
+               if (test_bit(FLAG_PULL_UP, &desc->flags))
+                       lineinfo.flags |= GPIOLINE_FLAG_PULL_UP;
 
                if (copy_to_user(ip, &lineinfo, sizeof(lineinfo)))
                        return -EFAULT;
@@ -2790,6 +2794,8 @@ static bool gpiod_free_commit(struct gpio_desc *desc)
                clear_bit(FLAG_REQUESTED, &desc->flags);
                clear_bit(FLAG_OPEN_DRAIN, &desc->flags);
                clear_bit(FLAG_OPEN_SOURCE, &desc->flags);
+               clear_bit(FLAG_PULL_UP, &desc->flags);
+               clear_bit(FLAG_PULL_DOWN, &desc->flags);
                clear_bit(FLAG_IS_HOGGED, &desc->flags);
                ret = true;
        }
@@ -4355,6 +4361,54 @@ static int platform_gpio_count(struct device *dev, const char *con_id)
        return count;
 }
 
+/**
+ * fwnode_gpiod_get_index - obtain a GPIO from firmware node
+ * @fwnode:    handle of the firmware node
+ * @con_id:    function within the GPIO consumer
+ * @index:     index of the GPIO to obtain for the consumer
+ * @flags:     GPIO initialization flags
+ * @label:     label to attach to the requested GPIO
+ *
+ * This function can be used for drivers that get their configuration
+ * from opaque firmware.
+ *
+ * The function properly finds the corresponding GPIO using whatever is the
+ * underlying firmware interface and then makes sure that the GPIO
+ * descriptor is requested before it is returned to the caller.
+ *
+ * Returns:
+ * On successful request the GPIO pin is configured in accordance with
+ * provided @flags.
+ *
+ * In case of error an ERR_PTR() is returned.
+ */
+struct gpio_desc *fwnode_gpiod_get_index(struct fwnode_handle *fwnode,
+                                        const char *con_id, int index,
+                                        enum gpiod_flags flags,
+                                        const char *label)
+{
+       struct gpio_desc *desc;
+       char prop_name[32]; /* 32 is max size of property name */
+       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 = fwnode_get_named_gpiod(fwnode, prop_name, index, flags,
+                                             label);
+               if (!IS_ERR(desc) || (PTR_ERR(desc) != -ENOENT))
+                       break;
+       }
+
+       return desc;
+}
+EXPORT_SYMBOL_GPL(fwnode_gpiod_get_index);
+
 /**
  * gpiod_count - return the number of GPIOs associated with a device / function
  *             or -ENOENT if no GPIO has been assigned to the requested function