summaryrefslogtreecommitdiff
path: root/drivers/gpio
diff options
context:
space:
mode:
authorDrew Fustini <drew@pdp7.com>2019-11-05 05:04:23 +0300
committerBartosz Golaszewski <bgolaszewski@baylibre.com>2019-11-12 18:30:30 +0300
commit9225d5169d110734099a82c39c073a11e399cb3f (patch)
treece801bf8c51d4dc21533dca65d8c2f8d87562a2a /drivers/gpio
parentf932a68695e4c7d92e721d2c23580d9f35494662 (diff)
downloadlinux-9225d5169d110734099a82c39c073a11e399cb3f.tar.xz
gpio: expose pull-up/pull-down line flags to userspace
Add pull-up/pull-down flags to the gpio line get and set ioctl() calls. Use cases include a push button that does not have an external resistor. Addition use cases described by Limor Fried (ladyada) of Adafruit in this PR for Adafruit_Blinka Python lib: https://github.com/adafruit/Adafruit_Blinka/pull/59 Signed-off-by: Drew Fustini <drew@pdp7.com> [Kent: added BIAS to GPIO flag names and restrict application to input lines] Signed-off-by: Kent Gibson <warthog618@gmail.com> Signed-off-by: Bartosz Golaszewski <bgolaszewski@baylibre.com>
Diffstat (limited to 'drivers/gpio')
-rw-r--r--drivers/gpio/gpiolib.c18
1 files changed, 18 insertions, 0 deletions
diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c
index 731d732cdc2b..53086724c051 100644
--- a/drivers/gpio/gpiolib.c
+++ b/drivers/gpio/gpiolib.c
@@ -422,6 +422,8 @@ struct linehandle_state {
(GPIOHANDLE_REQUEST_INPUT | \
GPIOHANDLE_REQUEST_OUTPUT | \
GPIOHANDLE_REQUEST_ACTIVE_LOW | \
+ GPIOHANDLE_REQUEST_BIAS_PULL_UP | \
+ GPIOHANDLE_REQUEST_BIAS_PULL_DOWN | \
GPIOHANDLE_REQUEST_OPEN_DRAIN | \
GPIOHANDLE_REQUEST_OPEN_SOURCE)
@@ -553,6 +555,12 @@ static int linehandle_create(struct gpio_device *gdev, void __user *ip)
(lflags & GPIOHANDLE_REQUEST_OPEN_SOURCE)))
return -EINVAL;
+ /* PULL_UP and PULL_DOWN flags only make sense for input mode. */
+ if (!(lflags & GPIOHANDLE_REQUEST_INPUT) &&
+ ((lflags & GPIOHANDLE_REQUEST_BIAS_PULL_UP) ||
+ (lflags & GPIOHANDLE_REQUEST_BIAS_PULL_DOWN)))
+ return -EINVAL;
+
lh = kzalloc(sizeof(*lh), GFP_KERNEL);
if (!lh)
return -ENOMEM;
@@ -593,6 +601,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_BIAS_PULL_DOWN)
+ set_bit(FLAG_PULL_DOWN, &desc->flags);
+ if (lflags & GPIOHANDLE_REQUEST_BIAS_PULL_UP)
+ set_bit(FLAG_PULL_UP, &desc->flags);
ret = gpiod_set_transitory(desc, false);
if (ret < 0)
@@ -1092,6 +1104,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_BIAS_PULL_DOWN;
+ if (test_bit(FLAG_PULL_UP, &desc->flags))
+ lineinfo.flags |= GPIOLINE_FLAG_BIAS_PULL_UP;
if (copy_to_user(ip, &lineinfo, sizeof(lineinfo)))
return -EFAULT;
@@ -2785,6 +2801,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;
}