drm/i915: Rename intel_context[engine].ringbuf
[deliverable/linux.git] / drivers / gpio / gpiolib.c
index b747c76fd2b1f4f8f1e117b6ce2836525b1166fd..24f60d28f0c055dbddfcd2750737534071813d26 100644 (file)
@@ -20,6 +20,7 @@
 #include <linux/cdev.h>
 #include <linux/fs.h>
 #include <linux/uaccess.h>
+#include <linux/compat.h>
 #include <uapi/linux/gpio.h>
 
 #include "gpiolib.h"
@@ -316,7 +317,7 @@ static long gpio_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
 {
        struct gpio_device *gdev = filp->private_data;
        struct gpio_chip *chip = gdev->chip;
-       int __user *ip = (int __user *)arg;
+       void __user *ip = (void __user *)arg;
 
        /* We fail any subsequent ioctl():s when the chip is gone */
        if (!chip)
@@ -388,6 +389,14 @@ static long gpio_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
        return -EINVAL;
 }
 
+#ifdef CONFIG_COMPAT
+static long gpio_ioctl_compat(struct file *filp, unsigned int cmd,
+                             unsigned long arg)
+{
+       return gpio_ioctl(filp, cmd, (unsigned long)compat_ptr(arg));
+}
+#endif
+
 /**
  * gpio_chrdev_open() - open the chardev for ioctl operations
  * @inode: inode for this chardev
@@ -431,7 +440,9 @@ static const struct file_operations gpio_fileops = {
        .owner = THIS_MODULE,
        .llseek = noop_llseek,
        .unlocked_ioctl = gpio_ioctl,
-       .compat_ioctl = gpio_ioctl,
+#ifdef CONFIG_COMPAT
+       .compat_ioctl = gpio_ioctl_compat,
+#endif
 };
 
 static void gpiodevice_release(struct device *dev)
@@ -618,21 +629,38 @@ int gpiochip_add_data(struct gpio_chip *chip, void *data)
                goto err_free_label;
        }
 
+       spin_unlock_irqrestore(&gpio_lock, flags);
+
        for (i = 0; i < chip->ngpio; i++) {
                struct gpio_desc *desc = &gdev->descs[i];
 
                desc->gdev = gdev;
-
-               /* REVISIT: most hardware initializes GPIOs as inputs (often
-                * with pullups enabled) so power usage is minimized. Linux
-                * code should set the gpio direction first thing; but until
-                * it does, and in case chip->get_direction is not set, we may
-                * expose the wrong direction in sysfs.
+               /*
+                * REVISIT: most hardware initializes GPIOs as inputs
+                * (often with pullups enabled) so power usage is
+                * minimized. Linux code should set the gpio direction
+                * first thing; but until it does, and in case
+                * chip->get_direction is not set, we may expose the
+                * wrong direction in sysfs.
                 */
-               desc->flags = !chip->direction_input ? (1 << FLAG_IS_OUT) : 0;
-       }
 
-       spin_unlock_irqrestore(&gpio_lock, flags);
+               if (chip->get_direction) {
+                       /*
+                        * If we have .get_direction, set up the initial
+                        * direction flag from the hardware.
+                        */
+                       int dir = chip->get_direction(chip, i);
+
+                       if (!dir)
+                               set_bit(FLAG_IS_OUT, &desc->flags);
+               } else if (!chip->direction_input) {
+                       /*
+                        * If the chip lacks the .direction_input callback
+                        * we logically assume all lines are outputs.
+                        */
+                       set_bit(FLAG_IS_OUT, &desc->flags);
+               }
+       }
 
 #ifdef CONFIG_PINCTRL
        INIT_LIST_HEAD(&gdev->pin_ranges);
@@ -1339,10 +1367,13 @@ done:
 /*
  * This descriptor validation needs to be inserted verbatim into each
  * function taking a descriptor, so we need to use a preprocessor
- * macro to avoid endless duplication.
+ * macro to avoid endless duplication. If the desc is NULL it is an
+ * optional GPIO and calls should just bail out.
  */
 #define VALIDATE_DESC(desc) do { \
-       if (!desc || !desc->gdev) { \
+       if (!desc) \
+               return 0; \
+       if (!desc->gdev) { \
                pr_warn("%s: invalid GPIO\n", __func__); \
                return -EINVAL; \
        } \
@@ -1353,7 +1384,9 @@ done:
        } } while (0)
 
 #define VALIDATE_DESC_VOID(desc) do { \
-       if (!desc || !desc->gdev) { \
+       if (!desc) \
+               return; \
+       if (!desc->gdev) { \
                pr_warn("%s: invalid GPIO\n", __func__); \
                return; \
        } \
@@ -1547,8 +1580,8 @@ EXPORT_SYMBOL_GPL(gpiod_direction_input);
 
 static int _gpiod_direction_output_raw(struct gpio_desc *desc, int value)
 {
-       struct gpio_chip        *chip;
-       int                     status = -EINVAL;
+       struct gpio_chip *gc = desc->gdev->chip;
+       int ret;
 
        /* GPIOs used for IRQs shall not be set as output */
        if (test_bit(FLAG_USED_AS_IRQ, &desc->flags)) {
@@ -1558,28 +1591,50 @@ static int _gpiod_direction_output_raw(struct gpio_desc *desc, int value)
                return -EIO;
        }
 
-       /* Open drain pin should not be driven to 1 */
-       if (value && test_bit(FLAG_OPEN_DRAIN,  &desc->flags))
-               return gpiod_direction_input(desc);
-
-       /* Open source pin should not be driven to 0 */
-       if (!value && test_bit(FLAG_OPEN_SOURCE,  &desc->flags))
-               return gpiod_direction_input(desc);
+       if (test_bit(FLAG_OPEN_DRAIN, &desc->flags)) {
+               /* First see if we can enable open drain in hardware */
+               if (gc->set_single_ended) {
+                       ret = gc->set_single_ended(gc, gpio_chip_hwgpio(desc),
+                                                  LINE_MODE_OPEN_DRAIN);
+                       if (!ret)
+                               goto set_output_value;
+               }
+               /* Emulate open drain by not actively driving the line high */
+               if (value)
+                       return gpiod_direction_input(desc);
+       }
+       else if (test_bit(FLAG_OPEN_SOURCE, &desc->flags)) {
+               if (gc->set_single_ended) {
+                       ret = gc->set_single_ended(gc, gpio_chip_hwgpio(desc),
+                                                  LINE_MODE_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 {
+               /* Make sure to disable open drain/source hardware, if any */
+               if (gc->set_single_ended)
+                       gc->set_single_ended(gc,
+                                            gpio_chip_hwgpio(desc),
+                                            LINE_MODE_PUSH_PULL);
+       }
 
-       chip = desc->gdev->chip;
-       if (!chip->set || !chip->direction_output) {
+set_output_value:
+       if (!gc->set || !gc->direction_output) {
                gpiod_warn(desc,
                       "%s: missing set() or direction_output() operations\n",
                       __func__);
                return -EIO;
        }
 
-       status = chip->direction_output(chip, gpio_chip_hwgpio(desc), value);
-       if (status == 0)
+       ret = gc->direction_output(gc, gpio_chip_hwgpio(desc), value);
+       if (!ret)
                set_bit(FLAG_IS_OUT, &desc->flags);
        trace_gpio_value(desc_to_gpio(desc), 0, value);
-       trace_gpio_direction(desc_to_gpio(desc), 0, status);
-       return status;
+       trace_gpio_direction(desc_to_gpio(desc), 0, ret);
+       return ret;
 }
 
 /**
@@ -1841,10 +1896,10 @@ static void gpio_chip_set_multiple(struct gpio_chip *chip,
        }
 }
 
-static void gpiod_set_array_value_priv(bool raw, bool can_sleep,
-                                      unsigned int array_size,
-                                      struct gpio_desc **desc_array,
-                                      int *value_array)
+void gpiod_set_array_value_complex(bool raw, bool can_sleep,
+                                  unsigned int array_size,
+                                  struct gpio_desc **desc_array,
+                                  int *value_array)
 {
        int i = 0;
 
@@ -1950,8 +2005,8 @@ void gpiod_set_raw_array_value(unsigned int array_size,
 {
        if (!desc_array)
                return;
-       gpiod_set_array_value_priv(true, false, array_size, desc_array,
-                                  value_array);
+       gpiod_set_array_value_complex(true, false, array_size, desc_array,
+                                     value_array);
 }
 EXPORT_SYMBOL_GPL(gpiod_set_raw_array_value);
 
@@ -1972,8 +2027,8 @@ void gpiod_set_array_value(unsigned int array_size,
 {
        if (!desc_array)
                return;
-       gpiod_set_array_value_priv(false, false, array_size, desc_array,
-                                  value_array);
+       gpiod_set_array_value_complex(false, false, array_size, desc_array,
+                                     value_array);
 }
 EXPORT_SYMBOL_GPL(gpiod_set_array_value);
 
@@ -1998,13 +2053,22 @@ EXPORT_SYMBOL_GPL(gpiod_cansleep);
  */
 int gpiod_to_irq(const struct gpio_desc *desc)
 {
-       struct gpio_chip        *chip;
-       int                     offset;
+       struct gpio_chip *chip;
+       int offset;
 
        VALIDATE_DESC(desc);
        chip = desc->gdev->chip;
        offset = gpio_chip_hwgpio(desc);
-       return chip->to_irq ? chip->to_irq(chip, offset) : -ENXIO;
+       if (chip->to_irq) {
+               int retirq = chip->to_irq(chip, offset);
+
+               /* Zero means NO_IRQ */
+               if (!retirq)
+                       return -ENXIO;
+
+               return retirq;
+       }
+       return -ENXIO;
 }
 EXPORT_SYMBOL_GPL(gpiod_to_irq);
 
@@ -2018,17 +2082,30 @@ EXPORT_SYMBOL_GPL(gpiod_to_irq);
  */
 int gpiochip_lock_as_irq(struct gpio_chip *chip, unsigned int offset)
 {
-       if (offset >= chip->ngpio)
-               return -EINVAL;
+       struct gpio_desc *desc;
+
+       desc = gpiochip_get_desc(chip, offset);
+       if (IS_ERR(desc))
+               return PTR_ERR(desc);
+
+       /* Flush direction if something changed behind our back */
+       if (chip->get_direction) {
+               int dir = chip->get_direction(chip, offset);
 
-       if (test_bit(FLAG_IS_OUT, &chip->gpiodev->descs[offset].flags)) {
+               if (dir)
+                       clear_bit(FLAG_IS_OUT, &desc->flags);
+               else
+                       set_bit(FLAG_IS_OUT, &desc->flags);
+       }
+
+       if (test_bit(FLAG_IS_OUT, &desc->flags)) {
                chip_err(chip,
                          "%s: tried to flag a GPIO set as output for IRQ\n",
                          __func__);
                return -EIO;
        }
 
-       set_bit(FLAG_USED_AS_IRQ, &chip->gpiodev->descs[offset].flags);
+       set_bit(FLAG_USED_AS_IRQ, &desc->flags);
        return 0;
 }
 EXPORT_SYMBOL_GPL(gpiochip_lock_as_irq);
@@ -2176,8 +2253,8 @@ void gpiod_set_raw_array_value_cansleep(unsigned int array_size,
        might_sleep_if(extra_checks);
        if (!desc_array)
                return;
-       gpiod_set_array_value_priv(true, true, array_size, desc_array,
-                                  value_array);
+       gpiod_set_array_value_complex(true, true, array_size, desc_array,
+                                     value_array);
 }
 EXPORT_SYMBOL_GPL(gpiod_set_raw_array_value_cansleep);
 
@@ -2199,8 +2276,8 @@ void gpiod_set_array_value_cansleep(unsigned int array_size,
        might_sleep_if(extra_checks);
        if (!desc_array)
                return;
-       gpiod_set_array_value_priv(false, true, array_size, desc_array,
-                                  value_array);
+       gpiod_set_array_value_complex(false, true, array_size, desc_array,
+                                     value_array);
 }
 EXPORT_SYMBOL_GPL(gpiod_set_array_value_cansleep);
 
@@ -2726,15 +2803,16 @@ int gpiod_hog(struct gpio_desc *desc, const char *name,
 
        local_desc = gpiochip_request_own_desc(chip, hwnum, name);
        if (IS_ERR(local_desc)) {
-               pr_err("requesting hog GPIO %s (chip %s, offset %d) failed\n",
-                      name, chip->label, hwnum);
-               return PTR_ERR(local_desc);
+               status = PTR_ERR(local_desc);
+               pr_err("requesting hog GPIO %s (chip %s, offset %d) failed, %d\n",
+                      name, chip->label, hwnum, status);
+               return status;
        }
 
        status = gpiod_configure_flags(desc, name, dflags);
        if (status < 0) {
-               pr_err("setup of hog GPIO %s (chip %s, offset %d) failed\n",
-                      name, chip->label, hwnum);
+               pr_err("setup of hog GPIO %s (chip %s, offset %d) failed, %d\n",
+                      name, chip->label, hwnum, status);
                gpiochip_free_own_desc(desc);
                return status;
        }
This page took 0.028245 seconds and 5 git commands to generate.