From 8c550e94b8835170593169a45b5ba30d3fc72a70 Mon Sep 17 00:00:00 2001 From: Drew Fustini Date: Sat, 21 Sep 2019 12:25:23 +0200 Subject: 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 Link: https://lore.kernel.org/r/20190921102522.8970-1-drew@pdp7.com Signed-off-by: Linus Walleij --- include/uapi/linux/gpio.h | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'include') diff --git a/include/uapi/linux/gpio.h b/include/uapi/linux/gpio.h index 4ebfe0ac6c5b..c2d1f7d908d6 100644 --- a/include/uapi/linux/gpio.h +++ b/include/uapi/linux/gpio.h @@ -33,6 +33,8 @@ struct gpiochip_info { #define GPIOLINE_FLAG_ACTIVE_LOW (1UL << 2) #define GPIOLINE_FLAG_OPEN_DRAIN (1UL << 3) #define GPIOLINE_FLAG_OPEN_SOURCE (1UL << 4) +#define GPIOLINE_FLAG_PULL_UP (1UL << 5) +#define GPIOLINE_FLAG_PULL_DOWN (1UL << 6) /** * struct gpioline_info - Information about a certain GPIO line @@ -62,6 +64,8 @@ struct gpioline_info { #define GPIOHANDLE_REQUEST_ACTIVE_LOW (1UL << 2) #define GPIOHANDLE_REQUEST_OPEN_DRAIN (1UL << 3) #define GPIOHANDLE_REQUEST_OPEN_SOURCE (1UL << 4) +#define GPIOHANDLE_REQUEST_PULL_UP (1UL << 5) +#define GPIOHANDLE_REQUEST_PULL_DOWN (1UL << 6) /** * struct gpiohandle_request - Information about a GPIO handle request -- cgit v1.2.3 From 9208b1e77d6e8e9776f34f46ef4079ecac9c3c25 Mon Sep 17 00:00:00 2001 From: Matti Vaittinen Date: Wed, 6 Nov 2019 10:51:47 +0200 Subject: gpio: Add definition for GPIO direction At least for me it is difficult to remember the meaning of GPIO direction values. Define GPIO_LINE_DIRECTION_IN and GPIO_LINE_DIRECTION_OUT so that occasional GPIO contributors would not need to always check the meaning of hard coded values 1 and 0. Signed-off-by: Matti Vaittinen Signed-off-by: Linus Walleij --- include/linux/gpio/driver.h | 3 +++ 1 file changed, 3 insertions(+) (limited to 'include') diff --git a/include/linux/gpio/driver.h b/include/linux/gpio/driver.h index 5dd9c982e2cb..cc9ade4552d9 100644 --- a/include/linux/gpio/driver.h +++ b/include/linux/gpio/driver.h @@ -22,6 +22,9 @@ enum gpio_lookup_flags; struct gpio_chip; +#define GPIO_LINE_DIRECTION_IN 1 +#define GPIO_LINE_DIRECTION_OUT 0 + /** * struct gpio_irq_chip - GPIO interrupt controller */ -- cgit v1.2.3 From 70d97e099bb426ecb3ad4bf31e88dbf2ef4b2e4c Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Fri, 8 Nov 2019 13:37:54 +0100 Subject: Revert "gpio: expose pull-up/pull-down line flags to userspace" This reverts commit 8c550e94b8835170593169a45b5ba30d3fc72a70. This was prematurely applied and we need to back it out to merge a better version of the development track for this feature. Signed-off-by: Linus Walleij --- drivers/gpio/gpiolib.c | 12 ------------ include/uapi/linux/gpio.h | 4 ---- 2 files changed, 16 deletions(-) (limited to 'include') diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c index 618d71f0540b..731d732cdc2b 100644 --- a/drivers/gpio/gpiolib.c +++ b/drivers/gpio/gpiolib.c @@ -422,8 +422,6 @@ 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) @@ -595,10 +593,6 @@ 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) @@ -1098,10 +1092,6 @@ 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; @@ -2795,8 +2785,6 @@ 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; } diff --git a/include/uapi/linux/gpio.h b/include/uapi/linux/gpio.h index c2d1f7d908d6..4ebfe0ac6c5b 100644 --- a/include/uapi/linux/gpio.h +++ b/include/uapi/linux/gpio.h @@ -33,8 +33,6 @@ struct gpiochip_info { #define GPIOLINE_FLAG_ACTIVE_LOW (1UL << 2) #define GPIOLINE_FLAG_OPEN_DRAIN (1UL << 3) #define GPIOLINE_FLAG_OPEN_SOURCE (1UL << 4) -#define GPIOLINE_FLAG_PULL_UP (1UL << 5) -#define GPIOLINE_FLAG_PULL_DOWN (1UL << 6) /** * struct gpioline_info - Information about a certain GPIO line @@ -64,8 +62,6 @@ struct gpioline_info { #define GPIOHANDLE_REQUEST_ACTIVE_LOW (1UL << 2) #define GPIOHANDLE_REQUEST_OPEN_DRAIN (1UL << 3) #define GPIOHANDLE_REQUEST_OPEN_SOURCE (1UL << 4) -#define GPIOHANDLE_REQUEST_PULL_UP (1UL << 5) -#define GPIOHANDLE_REQUEST_PULL_DOWN (1UL << 6) /** * struct gpiohandle_request - Information about a GPIO handle request -- cgit v1.2.3 From 9225d5169d110734099a82c39c073a11e399cb3f Mon Sep 17 00:00:00 2001 From: Drew Fustini Date: Tue, 5 Nov 2019 10:04:23 +0800 Subject: 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 [Kent: added BIAS to GPIO flag names and restrict application to input lines] Signed-off-by: Kent Gibson Signed-off-by: Bartosz Golaszewski --- drivers/gpio/gpiolib.c | 18 ++++++++++++++++++ include/uapi/linux/gpio.h | 4 ++++ 2 files changed, 22 insertions(+) (limited to 'include') 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; } diff --git a/include/uapi/linux/gpio.h b/include/uapi/linux/gpio.h index 4ebfe0ac6c5b..39e6c7854d63 100644 --- a/include/uapi/linux/gpio.h +++ b/include/uapi/linux/gpio.h @@ -33,6 +33,8 @@ struct gpiochip_info { #define GPIOLINE_FLAG_ACTIVE_LOW (1UL << 2) #define GPIOLINE_FLAG_OPEN_DRAIN (1UL << 3) #define GPIOLINE_FLAG_OPEN_SOURCE (1UL << 4) +#define GPIOLINE_FLAG_BIAS_PULL_UP (1UL << 5) +#define GPIOLINE_FLAG_BIAS_PULL_DOWN (1UL << 6) /** * struct gpioline_info - Information about a certain GPIO line @@ -62,6 +64,8 @@ struct gpioline_info { #define GPIOHANDLE_REQUEST_ACTIVE_LOW (1UL << 2) #define GPIOHANDLE_REQUEST_OPEN_DRAIN (1UL << 3) #define GPIOHANDLE_REQUEST_OPEN_SOURCE (1UL << 4) +#define GPIOHANDLE_REQUEST_BIAS_PULL_UP (1UL << 5) +#define GPIOHANDLE_REQUEST_BIAS_PULL_DOWN (1UL << 6) /** * struct gpiohandle_request - Information about a GPIO handle request -- cgit v1.2.3 From 2148ad7790ea4f1f0081e6404fbb776bdbc793bb Mon Sep 17 00:00:00 2001 From: Kent Gibson Date: Tue, 5 Nov 2019 10:04:25 +0800 Subject: gpiolib: add support for disabling line bias Allow pull up/down bias to be disabled, allowing the line to float or to be biased only by external circuitry. Use case is for where the bias has been applied previously, either by default or by the user, but that setting may conflict with the current use of the line. Signed-off-by: Kent Gibson Signed-off-by: Bartosz Golaszewski --- drivers/gpio/gpiolib.c | 61 +++++++++++++++++++++++++++++++++++++++-------- drivers/gpio/gpiolib.h | 1 + include/uapi/linux/gpio.h | 2 ++ 3 files changed, 54 insertions(+), 10 deletions(-) (limited to 'include') diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c index b7d7bb8bd20d..996911660306 100644 --- a/drivers/gpio/gpiolib.c +++ b/drivers/gpio/gpiolib.c @@ -424,6 +424,7 @@ struct linehandle_state { GPIOHANDLE_REQUEST_ACTIVE_LOW | \ GPIOHANDLE_REQUEST_BIAS_PULL_UP | \ GPIOHANDLE_REQUEST_BIAS_PULL_DOWN | \ + GPIOHANDLE_REQUEST_BIAS_DISABLE | \ GPIOHANDLE_REQUEST_OPEN_DRAIN | \ GPIOHANDLE_REQUEST_OPEN_SOURCE) @@ -555,12 +556,21 @@ 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. */ + /* Bias flags only allowed for input mode. */ if (!(lflags & GPIOHANDLE_REQUEST_INPUT) && - ((lflags & GPIOHANDLE_REQUEST_BIAS_PULL_UP) || + ((lflags & GPIOHANDLE_REQUEST_BIAS_DISABLE) || + (lflags & GPIOHANDLE_REQUEST_BIAS_PULL_UP) || (lflags & GPIOHANDLE_REQUEST_BIAS_PULL_DOWN))) return -EINVAL; + /* Only one bias flag can be set. */ + if (((lflags & GPIOHANDLE_REQUEST_BIAS_DISABLE) && + (lflags & (GPIOHANDLE_REQUEST_BIAS_PULL_DOWN | + GPIOHANDLE_REQUEST_BIAS_PULL_UP))) || + ((lflags & GPIOHANDLE_REQUEST_BIAS_PULL_DOWN) && + (lflags & GPIOHANDLE_REQUEST_BIAS_PULL_UP))) + return -EINVAL; + lh = kzalloc(sizeof(*lh), GFP_KERNEL); if (!lh) return -ENOMEM; @@ -601,6 +611,8 @@ 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_DISABLE) + set_bit(FLAG_BIAS_DISABLE, &desc->flags); if (lflags & GPIOHANDLE_REQUEST_BIAS_PULL_DOWN) set_bit(FLAG_PULL_DOWN, &desc->flags); if (lflags & GPIOHANDLE_REQUEST_BIAS_PULL_UP) @@ -925,6 +937,14 @@ static int lineevent_create(struct gpio_device *gdev, void __user *ip) (lflags & GPIOHANDLE_REQUEST_OPEN_SOURCE)) return -EINVAL; + /* Only one bias flag can be set. */ + if (((lflags & GPIOHANDLE_REQUEST_BIAS_DISABLE) && + (lflags & (GPIOHANDLE_REQUEST_BIAS_PULL_DOWN | + GPIOHANDLE_REQUEST_BIAS_PULL_UP))) || + ((lflags & GPIOHANDLE_REQUEST_BIAS_PULL_DOWN) && + (lflags & GPIOHANDLE_REQUEST_BIAS_PULL_UP))) + return -EINVAL; + le = kzalloc(sizeof(*le), GFP_KERNEL); if (!le) return -ENOMEM; @@ -951,6 +971,8 @@ static int lineevent_create(struct gpio_device *gdev, void __user *ip) if (lflags & GPIOHANDLE_REQUEST_ACTIVE_LOW) set_bit(FLAG_ACTIVE_LOW, &desc->flags); + if (lflags & GPIOHANDLE_REQUEST_BIAS_DISABLE) + set_bit(FLAG_BIAS_DISABLE, &desc->flags); if (lflags & GPIOHANDLE_REQUEST_BIAS_PULL_DOWN) set_bit(FLAG_PULL_DOWN, &desc->flags); if (lflags & GPIOHANDLE_REQUEST_BIAS_PULL_UP) @@ -1108,6 +1130,8 @@ 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_BIAS_DISABLE, &desc->flags)) + lineinfo.flags |= GPIOLINE_FLAG_BIAS_DISABLE; if (test_bit(FLAG_PULL_DOWN, &desc->flags)) lineinfo.flags |= GPIOLINE_FLAG_BIAS_PULL_DOWN; if (test_bit(FLAG_PULL_UP, &desc->flags)) @@ -2807,6 +2831,7 @@ static bool gpiod_free_commit(struct gpio_desc *desc) clear_bit(FLAG_OPEN_SOURCE, &desc->flags); clear_bit(FLAG_PULL_UP, &desc->flags); clear_bit(FLAG_PULL_DOWN, &desc->flags); + clear_bit(FLAG_BIAS_DISABLE, &desc->flags); clear_bit(FLAG_IS_HOGGED, &desc->flags); ret = true; } @@ -2933,6 +2958,7 @@ static int gpio_set_config(struct gpio_chip *gc, unsigned offset, unsigned arg; switch (mode) { + case PIN_CONFIG_BIAS_DISABLE: case PIN_CONFIG_BIAS_PULL_DOWN: case PIN_CONFIG_BIAS_PULL_UP: arg = 1; @@ -2946,6 +2972,26 @@ static int gpio_set_config(struct gpio_chip *gc, unsigned offset, return gc->set_config ? gc->set_config(gc, offset, config) : -ENOTSUPP; } +static int gpio_set_bias(struct gpio_chip *chip, struct gpio_desc *desc) +{ + int bias = 0; + int ret = 0; + + if (test_bit(FLAG_BIAS_DISABLE, &desc->flags)) + bias = PIN_CONFIG_BIAS_DISABLE; + else if (test_bit(FLAG_PULL_UP, &desc->flags)) + bias = PIN_CONFIG_BIAS_PULL_UP; + else if (test_bit(FLAG_PULL_DOWN, &desc->flags)) + bias = PIN_CONFIG_BIAS_PULL_DOWN; + + if (bias) { + ret = gpio_set_config(chip, gpio_chip_hwgpio(desc), bias); + if (ret != -ENOTSUPP) + return ret; + } + return 0; +} + /** * gpiod_direction_input - set the GPIO direction to input * @desc: GPIO to set to input @@ -2990,15 +3036,10 @@ int gpiod_direction_input(struct gpio_desc *desc) __func__); return -EIO; } - if (ret == 0) + if (ret == 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); + ret = gpio_set_bias(chip, desc); + } trace_gpio_direction(desc_to_gpio(desc), 1, ret); diff --git a/drivers/gpio/gpiolib.h b/drivers/gpio/gpiolib.h index b8b10a409c7b..ca9bc1e4803c 100644 --- a/drivers/gpio/gpiolib.h +++ b/drivers/gpio/gpiolib.h @@ -110,6 +110,7 @@ struct gpio_desc { #define FLAG_TRANSITORY 12 /* GPIO may lose value in sleep or reset */ #define FLAG_PULL_UP 13 /* GPIO has pull up enabled */ #define FLAG_PULL_DOWN 14 /* GPIO has pull down enabled */ +#define FLAG_BIAS_DISABLE 15 /* GPIO has pull disabled */ /* Connection label */ const char *label; diff --git a/include/uapi/linux/gpio.h b/include/uapi/linux/gpio.h index 39e6c7854d63..7cc21c3b0839 100644 --- a/include/uapi/linux/gpio.h +++ b/include/uapi/linux/gpio.h @@ -35,6 +35,7 @@ struct gpiochip_info { #define GPIOLINE_FLAG_OPEN_SOURCE (1UL << 4) #define GPIOLINE_FLAG_BIAS_PULL_UP (1UL << 5) #define GPIOLINE_FLAG_BIAS_PULL_DOWN (1UL << 6) +#define GPIOLINE_FLAG_BIAS_DISABLE (1UL << 7) /** * struct gpioline_info - Information about a certain GPIO line @@ -66,6 +67,7 @@ struct gpioline_info { #define GPIOHANDLE_REQUEST_OPEN_SOURCE (1UL << 4) #define GPIOHANDLE_REQUEST_BIAS_PULL_UP (1UL << 5) #define GPIOHANDLE_REQUEST_BIAS_PULL_DOWN (1UL << 6) +#define GPIOHANDLE_REQUEST_BIAS_DISABLE (1UL << 7) /** * struct gpiohandle_request - Information about a GPIO handle request -- cgit v1.2.3 From e588bb1eae31be73fbec2b731be986a7c09635a4 Mon Sep 17 00:00:00 2001 From: Kent Gibson Date: Tue, 5 Nov 2019 10:04:29 +0800 Subject: gpio: add new SET_CONFIG ioctl() to gpio chardev Add the GPIOHANDLE_SET_CONFIG_IOCTL to the gpio chardev. The ioctl allows some of the configuration of a requested handle to be changed without having to release the line. The primary use case is the changing of direction for bi-directional lines. Based on initial work by Bartosz Golaszewski Signed-off-by: Kent Gibson Signed-off-by: Bartosz Golaszewski --- drivers/gpio/gpiolib.c | 69 +++++++++++++++++++++++++++++++++++++++++++++++ include/uapi/linux/gpio.h | 18 +++++++++++++ 2 files changed, 87 insertions(+) (limited to 'include') diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c index a9826627f347..dba5f08f308c 100644 --- a/drivers/gpio/gpiolib.c +++ b/drivers/gpio/gpiolib.c @@ -476,6 +476,73 @@ static int linehandle_validate_flags(u32 flags) return 0; } +static void linehandle_configure_flag(unsigned long *flagsp, + u32 bit, bool active) +{ + if (active) + set_bit(bit, flagsp); + else + clear_bit(bit, flagsp); +} + +static long linehandle_set_config(struct linehandle_state *lh, + void __user *ip) +{ + struct gpiohandle_config gcnf; + struct gpio_desc *desc; + int i, ret; + u32 lflags; + unsigned long *flagsp; + + if (copy_from_user(&gcnf, ip, sizeof(gcnf))) + return -EFAULT; + + lflags = gcnf.flags; + ret = linehandle_validate_flags(lflags); + if (ret) + return ret; + + for (i = 0; i < lh->numdescs; i++) { + desc = lh->descs[i]; + flagsp = &desc->flags; + + linehandle_configure_flag(flagsp, FLAG_ACTIVE_LOW, + lflags & GPIOHANDLE_REQUEST_ACTIVE_LOW); + + linehandle_configure_flag(flagsp, FLAG_OPEN_DRAIN, + lflags & GPIOHANDLE_REQUEST_OPEN_DRAIN); + + linehandle_configure_flag(flagsp, FLAG_OPEN_SOURCE, + lflags & GPIOHANDLE_REQUEST_OPEN_SOURCE); + + linehandle_configure_flag(flagsp, FLAG_PULL_UP, + lflags & GPIOHANDLE_REQUEST_BIAS_PULL_UP); + + linehandle_configure_flag(flagsp, FLAG_PULL_DOWN, + lflags & GPIOHANDLE_REQUEST_BIAS_PULL_DOWN); + + linehandle_configure_flag(flagsp, FLAG_BIAS_DISABLE, + lflags & GPIOHANDLE_REQUEST_BIAS_DISABLE); + + /* + * Lines have to be requested explicitly for input + * or output, else the line will be treated "as is". + */ + if (lflags & GPIOHANDLE_REQUEST_OUTPUT) { + int val = !!gcnf.default_values[i]; + + ret = gpiod_direction_output(desc, val); + if (ret) + return ret; + } else if (lflags & GPIOHANDLE_REQUEST_INPUT) { + ret = gpiod_direction_input(desc); + if (ret) + return ret; + } + } + return 0; +} + static long linehandle_ioctl(struct file *filep, unsigned int cmd, unsigned long arg) { @@ -526,6 +593,8 @@ static long linehandle_ioctl(struct file *filep, unsigned int cmd, lh->descs, NULL, vals); + } else if (cmd == GPIOHANDLE_SET_CONFIG_IOCTL) { + return linehandle_set_config(lh, ip); } return -EINVAL; } diff --git a/include/uapi/linux/gpio.h b/include/uapi/linux/gpio.h index 7cc21c3b0839..799cf823d493 100644 --- a/include/uapi/linux/gpio.h +++ b/include/uapi/linux/gpio.h @@ -100,6 +100,24 @@ struct gpiohandle_request { int fd; }; +/** + * struct gpiohandle_config - Configuration for a GPIO handle request + * @flags: updated flags for the requested GPIO lines, such as + * GPIOHANDLE_REQUEST_OUTPUT, GPIOHANDLE_REQUEST_ACTIVE_LOW etc, OR:ed + * together + * @default_values: if the GPIOHANDLE_REQUEST_OUTPUT is set in flags, + * this specifies the default output value, should be 0 (low) or + * 1 (high), anything else than 0 or 1 will be interpreted as 1 (high) + * @padding: reserved for future use and should be zero filled + */ +struct gpiohandle_config { + __u32 flags; + __u8 default_values[GPIOHANDLES_MAX]; + __u32 padding[4]; /* padding for future use */ +}; + +#define GPIOHANDLE_SET_CONFIG_IOCTL _IOWR(0xB4, 0x0a, struct gpiohandle_config) + /** * struct gpiohandle_data - Information of values on a GPIO handle * @values: when getting the state of lines this contains the current -- cgit v1.2.3 From b056ca1c2f01b2d261c2dd6d167c17ac27977034 Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Mon, 4 Nov 2019 18:09:39 +0200 Subject: gpiolib: Introduce ->add_pin_ranges() callback When IRQ chip is being added by GPIO library, the ACPI based platform expects GPIO <-> pin mapping ranges to be initialized in order to correctly initialize ACPI event mechanism on affected platforms. Unfortunately this step is missed. Introduce ->add_pin_ranges() callback to fill the above mentioned gap. Signed-off-by: Andy Shevchenko Reviewed-by: Linus Walleij Reviewed-by: Mika Westerberg Reviewed-by: Hans de Goede Tested-by: Hans de Goede --- drivers/gpio/gpiolib.c | 12 ++++++++++++ include/linux/gpio/driver.h | 5 +++++ 2 files changed, 17 insertions(+) (limited to 'include') diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c index 731d732cdc2b..1dc144f83483 100644 --- a/drivers/gpio/gpiolib.c +++ b/drivers/gpio/gpiolib.c @@ -390,6 +390,14 @@ static void gpiochip_free_valid_mask(struct gpio_chip *gpiochip) gpiochip->valid_mask = NULL; } +static int gpiochip_add_pin_ranges(struct gpio_chip *gc) +{ + if (gc->add_pin_ranges) + return gc->add_pin_ranges(gc); + + return 0; +} + bool gpiochip_line_is_valid(const struct gpio_chip *gpiochip, unsigned int offset) { @@ -1397,6 +1405,10 @@ int gpiochip_add_data_with_key(struct gpio_chip *chip, void *data, } } + ret = gpiochip_add_pin_ranges(chip); + if (ret) + goto err_remove_of_chip; + acpi_gpiochip_add(chip); machine_gpiochip_add(chip); diff --git a/include/linux/gpio/driver.h b/include/linux/gpio/driver.h index cc9ade4552d9..e2480ef94c55 100644 --- a/include/linux/gpio/driver.h +++ b/include/linux/gpio/driver.h @@ -289,6 +289,9 @@ struct gpio_irq_chip { * state (such as pullup/pulldown configuration). * @init_valid_mask: optional routine to initialize @valid_mask, to be used if * not all GPIOs are valid. + * @add_pin_ranges: optional routine to initialize pin ranges, to be used when + * requires special mapping of the pins that provides GPIO functionality. + * It is called after adding GPIO chip and before adding IRQ chip. * @base: identifies the first GPIO number handled by this chip; * or, if negative during registration, requests dynamic ID allocation. * DEPRECATION: providing anything non-negative and nailing the base @@ -379,6 +382,8 @@ struct gpio_chip { unsigned long *valid_mask, unsigned int ngpios); + int (*add_pin_ranges)(struct gpio_chip *chip); + int base; u16 ngpio; const char *const *names; -- cgit v1.2.3