2011-04-01 22:43:09 GPIO button event and /dev/gpio..
Paul Lau (UNITED STATES)
Message: 99506
I am running uClinux on BF537-ezkit (using BF537-stamp as target) and am using button events.
This work except that I need read the initial GPI state because the button events is set to report edge only.
I have tried using /dev/gpio.. but it crash when I try to open the device. This is understandable as the button events framework could have reserved the resource for exclusive access.
What I don't understand is that even when I try to read PortF data register, it appears that I always read 0. The related registers PortF INEN reads 0x3C, and the PortF Edge reads 0x3C. I tried to change the PortF edge to 0x0000 but it spring back.
Is this because of the Button Event framework that constantly update the PortF registers or for other reason?
Also, it there other ways to get to the GPI initial state after reboot?
QuoteReplyEditDelete
2011-04-02 00:04:40 Re: GPIO button event and /dev/gpio..
Mike Frysinger (UNITED STATES)
Message: 99508
i dont understand what you're trying to do. why do you need to read the initial state ? why not let the keys do their job and send events when you press them ?
QuoteReplyEditDelete
2011-04-02 08:29:38 Re: GPIO button event and /dev/gpio..
Paul Lau (UNITED STATES)
Message: 99534
our application ties the GPIO input pin to an external magnetic window sensor (to sense a door open/close condition), which is active-lo. Even though I enabled triggering on both edges of the GPIO input, during the initial condition when the input has not change state, the application does not know whether it was a hi or lo (and hence the initial state of the door), until the input first change states. Hence I need a way to initally read the pin state to sync with the software (which has different action according to the initial state) before the1st input change state happens.
QuoteReplyEditDelete
2011-04-02 12:49:02 Re: GPIO button event and /dev/gpio..
Mike Frysinger (UNITED STATES)
Message: 99537
that relies on never missing an interrupt
at any rate, looks to me like the gpio_keys driver already reports the current gpio level when reporting an event. so perhaps you should be using the data already sent to you ?
drivers/input/keyboard/gpio_keys.c:gpio_keys_report_event
QuoteReplyEditDelete
2011-04-04 20:07:55 Re: GPIO button event and /dev/gpio..
Paul Lau (UNITED STATES)
Message: 99573
my distribution is old (2008R1) and the gpio_keys.c file don't even have the gpio_keys_report_event() routine. Yet, your suggestion has pointed me to where to look for a possible solution. Thanks, Mike.
Here is what happened:
the interrupt handler would be called right away when the GPIO pin is set to enable edge-trigger irq, but only when the GPIO pin input is a '0'. In case of an initial state of '1', the interrupt handler will only be called at the 1st transition from '1' to '0'. I suspect it is because the driver has a default state of '1' and initial state of '1' won't be detected as a transition right away.
Anyway, either case won't queue up the input event when the input event device is not opened. As a result, input event would be fired only at the next key transition after the user opened the input event device. Hence in my case, it is up to me to read the initial state explicitly and store it to some global variables for later retrieval.
I also experimented with reading the state before/after registering the irq. It appears that once we have set to use irq with dual edge-trigger, trying to set the pin back to level trigger for level reading (as in the interrupt service routine) won't work. This is consistent with what I described in my earlier posting.
I didn't get a chance to verify if the same is true for the latest distribution since the input event mechanism has been updated since. Maybe the initial condition issue get fixed in newer rev of the code.
Here is my patch to retrieve the initial states into an global array button_state[4]
static int __devinit gpio_keys_probe(struct platform_device *pdev)
{
...
button_state = (int *)kmalloc(pdata->nbuttons * sizeof(int), GFP_KERNEL);
for (i = 0; i < pdata->nbuttons; i++)
{
struct gpio_keys_button *button = &pdata->buttons[i];
int gpio = button->gpio;
set_gpio_inen(gpio, 1); // enable this pin as input
set_gpio_dir(gpio, 1);
// NOTE: need to flip state to match with subsequent irq update ?!!
// button_state[i] = (gpio_get_value(gpio) != 0) ^ button->active_low;
button_state[i] = (gpio_get_value(gpio) == 0) ^ button->active_low;
}
// original code continue here ...
for (i = 0; i < pdata->nbuttons; i++) {
struct gpio_keys_button *button = &pdata->buttons[i];
int irq = gpio_to_irq(button->gpio);
unsigned int type = button->type ?: EV_KEY;
set_irq_type(irq, IRQ_TYPE_EDGE_BOTH);
.....