2008-02-18 13:13:14     Kernel-Update: Changes in GPIO-layer?

Document created by Aaronwu Employee on Aug 5, 2013
Version 1Show Document
  • View in full screen mode

2008-02-18 13:13:14     Kernel-Update: Changes in GPIO-layer?

Simon Budig (GERMANY)

Message: 51214    Hi all.

 

We're currently trying to update the kernel in a project from the 2007-1.1RC3-kernel to the 2.6.22-Kernel from trunk (just before the trunk update to 2.6.24). We have some custom drivers here that use the gpio-layer and now have to be adjusted to the new infrastructure.

 

The obvious changes were easy: adding an parameter with the initial PF-value to gpio_direction_output() was straightforward.

 

The pity is: the driver does not work and I am currently a bit lost on what else might have changed. My debugging options are a bit limited at the moment so I cannot really tell what goes wrong (I guess I have to dig out the oscilloscope and fish around for tiny testpoints tomorrow)...

 

One of the troubling points is, that I had quite some workarounds in our custom gpio driver to be able to get edge-triggers for both rising + falling edges and simultaneously being able to figure out the logic level of the pin in question. Unfortunately the value register in the blackfin reads as 1 when an interrupt happened and I did not see an obvious way to determine the "real" logic value.

 

So in the interrupt handler I switch the polarity of the resp. GPIO-Pin like this:

 

static irqreturn_t

gpio_irq_handler (int   irq,

                  void *dev_id)

{

        unsigned long flags;

        gpio_device_t *gdev = dev_id;

        int gpio = irq - IRQ_PF0;

 

        spin_lock_irqsave (gdev->lock, flags);

        gpio_set_value (gpio, 0);

        gdev->irq_active[gpio/16] |= (1 << (gpio%16));

        gdev->value[gpio/16] ^= (1 << (gpio%16));

        set_gpio_polar (gpio, gdev->value[gpio/16] & (1 << (gpio%16)) ? 1 : 0);

        spin_unlock_irqrestore (gdev->lock, flags);

        wake_up_interruptible (&gdev->gpio_wq);

 

        return IRQ_HANDLED;

}

 

 

which works with the old infrastructure, but fails to work with the new one - as soon as one input pin fires an interrupt I see a sequence of lots of interrupts.

 

Anyone an idea what semantic changes happened to the gpio-things?

 

Thanks,

        Simon

QuoteReplyEditDelete

 

 

2008-02-18 13:39:43     Re: Kernel-Update: Changes in GPIO-layer?

Robin Getz (UNITED STATES)

Message: 51215    Simon:

 

I don't have an answer - except to say to - upgrade to the 2008R1 branches - not trunk. It should make things go a little easier.

 

Michael should be able to answer this when he gets back in tomorrow.

 

-Robin

QuoteReplyEditDelete

 

 

2008-02-18 15:02:56     Re: Kernel-Update: Changes in GPIO-layer?

Michael Hennerich (GERMANY)

Message: 51221   

 

Simon,

 

 

 

 

 

How do you request the gpio(s) (flags?).

 

 

 

Do you use set_irq_type?

 

 

 

 

 

Please send me your source to my private e-mail in case you like to get assistance.

 

 

 

 

 

Have a look at the drivers/input/keyboard/gpio-keys.c driver.

 

 

 

Here we use Both Edge Triggered Interrupts with a workaround for getting the pin state.

 

 

 

 

 

-Michael

 

 

 

QuoteReplyEditDelete

 

 

2008-02-25 04:46:32     Re: Kernel-Update: Changes in GPIO-layer?

Simon Budig (GERMANY)

Message: 51591    I request the GPIO-pins like this:

 

        for (i = 0; i < MAX_BLACKFIN_GPIOS; i++) {

                if (gpio_device->mask[i/16] & (1 << (i%16))) {

                        /* gpio_request (i, "gpio"); */

                        if (request_irq (IRQ_PF0 + i,

                                         (void *) gpio_irq_handler, IRQF_DISABLED,

                                         "GPIO-IRQ", gpio_device) < 0) {

                                printk (KERN_INFO "failed to request GPIO-IRQ %d\n", i);

                                gpio_device->mask[i/16] &= ~(1 << (i%16));

                        } else {

                                disable_irq (IRQ_PF0 + i);

                                gpio_direction_output (i, 0);

                                gpio_set_value (i, 0);

                                set_gpio_edge (i, 1);

                        }

                }

        }

 

Typically before actually using the device the user is supposed to do an IOCTL to set the direction of the IO-Pins:

 

        case CMD_GPIO_SET_DIRECTION:

                if (arg) {

                        spin_lock_irqsave (gdev->lock, flags);

                        copy_from_user (&values,

                                        (void *) arg,

                                        sizeof (struct bfin_gpio_values));

 

                        for (i = 0; i < MAX_BLACKFIN_GPIOS; i++) {

                                if (gdev->mask [i/16] & (1 << (i % 16)) &&

                                    values.mask[i/16] & (1 << (i % 16))) {

                                        if (values.values[i/16] & (1 << (i % 16))) {

                                                gpio_direction_input (i);

                                                if (!(gdev->irq_enabled[i/16] & (1 << (i % 16)))) {

                                                        gdev->irq_enabled[i/16] |= (1 << (i % 16));

                                                        enable_irq (IRQ_PF0 + i);

                                                }

                                        } else {

                                                gpio_direction_output (i, 0);

                                                if (gdev->irq_enabled[i/16] & (1 << (i % 16))) {

                                                        gdev->irq_enabled[i/16] &= ~(1 << (i % 16));

                                                        disable_irq (IRQ_PF0 + i);

                                                }

                                        }

                                }

                        }

                        spin_unlock_irqrestore (gdev->lock, flags);

                } else {

                        ret = -EINVAL;

                }

                break;

 

Reading that code again now I get the impression that I really should look at it again and get hide all this shifting in some macros - sorry for that.

 

No, I don't use set_irq_type, will try. Michael: I'll probably get back to your offer, thanks. We also have (not interrupt related) problems with the GPIO-pins in another driver, but I need to look at some Oscilloscope readings before being able to tell more about that...

 

Thanks,

       Simon

QuoteReplyEditDelete

 

 

2008-02-25 09:38:14     Re: Kernel-Update: Changes in GPIO-layer?

Simon Budig (GERMANY)

Message: 51596    (I btw. have changed the kernel to the 2008RC1 - it did not fix any of the problems mentioned above)

 

Thanks,

        Simon

QuoteReplyEditDelete

 

 

2008-02-25 12:53:06     Re: Kernel-Update: Changes in GPIO-layer?

Mike Frysinger (UNITED STATES)

Message: 51601    the limitation you refer to is a hardware limitation, not software.  when you have both rising and falling enabled, the gpio data value does not indicate the level (consult the HRM -- there is a table explaining the meaning).  you need to reconfigure the gpio port temporarily, read the value, and then restore the original configuration.

QuoteReplyEditDelete

 

 

2008-02-25 20:21:55     Re: Kernel-Update: Changes in GPIO-layer?

Simon Budig (GERMANY)

Message: 51633    Yeah, I think I understood that. For this reason the driver for 2007R1.1-RC3 did not trigger on both edges (i.e. it did not set the bit in FIOx_BOTH) and switched the polarity of the gpio in the interrupt handler. That way one always knows about the current state of the pin.

 

Disabeling the edge sensitivity temporarily and reading the value directly indeed seems a bit more straightforward, I guess I'll change that in the driver.

 

How is the semantics of the IRQ-utility functions like set_irq_type? Do they configure the IO-Pins accordingly?

 

Thanks,

        Simon

QuoteReplyEditDelete

 

 

2008-02-25 20:47:34     Re: Kernel-Update: Changes in GPIO-layer?

Mike Frysinger (UNITED STATES)

Message: 51634    set_irq_type() takes the same flags as request_irq() and you can consider the changes to have taken affect as soon as the function returns

QuoteReplyEditDelete

 

 

2008-02-29 13:14:47     Re: Kernel-Update: Changes in GPIO-layer?

Simon Budig (GERMANY)

Message: 51911    Hi all.

 

Thanks for all your help, I have now ported the driver to the new API completely and it works nicely, with the same workaround for the edge-triggered IRQs as in the keyboard driver.

 

I guess using get_gpio_dir() is still OK? Or is there a "new style" way of doing this?

 

Thanks,

         Simon

QuoteReplyEditDelete

 

 

2008-02-29 13:31:46     Re: Kernel-Update: Changes in GPIO-layer?

Mike Frysinger (UNITED STATES)

Message: 51913    look at include/asm-blackfin/gpio.h ... if you see the function prototype in there, it's fair game

 

functions that start with gpio_XXX are part of the common GPIO API while functions that start with get_gpio_XXX or set_gpio_XXX are Blackfin-specific GPIO functions

Attachments

    Outcomes