gpiolib: fix incorrect IRQ requesting of an active-low lineevent [Linux 4.14.137]

This Linux kernel change "gpiolib: fix incorrect IRQ requesting of an active-low lineevent" is included in the Linux 4.14.137 release. This change is authored by Michael Wu <michael.wu [at] vatics.com> on Mon Jul 8 13:23:08 2019 +0800. The commit for this change in Linux stable tree is 2a14a26 (patch) which is from upstream commit 223ecaf. The same Linux upstream change may have been applied to various maintained Linux releases and you can find all Linux releases containing changes from upstream 223ecaf.

gpiolib: fix incorrect IRQ requesting of an active-low lineevent

commit 223ecaf140b1dd1c1d2a1a1d96281efc5c906984 upstream.

When a pin is active-low, logical trigger edge should be inverted to match
the same interrupt opportunity.

For example, a button pushed triggers falling edge in ACTIVE_HIGH case; in
ACTIVE_LOW case, the button pushed triggers rising edge. For user space the
IRQ requesting doesn't need to do any modification except to configuring
GPIOHANDLE_REQUEST_ACTIVE_LOW.

For example, we want to catch the event when the button is pushed. The
button on the original board drives level to be low when it is pushed, and
drives level to be high when it is released.

In user space we can do:

    req.handleflags = GPIOHANDLE_REQUEST_INPUT;
    req.eventflags = GPIOEVENT_REQUEST_FALLING_EDGE;

    while (1) {
        read(fd, &dat, sizeof(dat));
        if (dat.id == GPIOEVENT_EVENT_FALLING_EDGE)
            printf("button pushed\n");
    }

Run the same logic on another board which the polarity of the button is
inverted; it drives level to be high when pushed, and level to be low when
released. For this inversion we add flag GPIOHANDLE_REQUEST_ACTIVE_LOW:

    req.handleflags = GPIOHANDLE_REQUEST_INPUT |
        GPIOHANDLE_REQUEST_ACTIVE_LOW;
    req.eventflags = GPIOEVENT_REQUEST_FALLING_EDGE;

At the result, there are no any events caught when the button is pushed.
By the way, button releasing will emit a "falling" event. The timing of
"falling" catching is not expected.

Cc: stable@vger.kernel.org
Signed-off-by: Michael Wu <michael.wu@vatics.com>
Tested-by: Bartosz Golaszewski <bgolaszewski@baylibre.com>
Signed-off-by: Bartosz Golaszewski <bgolaszewski@baylibre.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>

There are 6 lines of Linux source code added/deleted in this change. Code changes to Linux kernel are as follows.

 drivers/gpio/gpiolib.c | 6 ++++--
 1 file changed, 4 insertions(+), 2 deletions(-)

diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c
index 3db0a9b..25351b6 100644
--- a/drivers/gpio/gpiolib.c
+++ b/drivers/gpio/gpiolib.c
@@ -835,9 +835,11 @@ static int lineevent_create(struct gpio_device *gdev, void __user *ip)
    }

    if (eflags & GPIOEVENT_REQUEST_RISING_EDGE)
-       irqflags |= IRQF_TRIGGER_RISING;
+       irqflags |= test_bit(FLAG_ACTIVE_LOW, &desc->flags) ?
+           IRQF_TRIGGER_FALLING : IRQF_TRIGGER_RISING;
    if (eflags & GPIOEVENT_REQUEST_FALLING_EDGE)
-       irqflags |= IRQF_TRIGGER_FALLING;
+       irqflags |= test_bit(FLAG_ACTIVE_LOW, &desc->flags) ?
+           IRQF_TRIGGER_RISING : IRQF_TRIGGER_FALLING;
    irqflags |= IRQF_ONESHOT;
    irqflags |= IRQF_SHARED;

Leave a Reply

Your email address will not be published. Required fields are marked *