From: Alexander Clouter <alex@digriz.org.uk>
To: linux-input@vger.kernel.org
Subject: Re: [PATCH] input: gpio_keys: polling mode support
Date: Thu, 8 Jul 2010 17:26:01 +0100 [thread overview]
Message-ID: <ppahg7-ahn.ln1@chipmunk.wormnet.eu> (raw)
In-Reply-To: 20100706190128.GB24655@chipmunk
ping...?
Alexander Clouter <alex@digriz.org.uk> wrote:
>
> This implements an optional polling mode for the gpio_keys driver,
> necessary for GPIOs that are not able to generate IRQs.
>
> gpio_keys_platform_data has been extended with poll_interval
> which specifies the polling interval in ms, this is passed onto
> input-polldev.
>
> This work was based on the patch[1] originally conceived by Paul
> Mundt but now the absolute dependency on INPUT_POLLDEV has been
> removed (so existing users of gpio_keys can compile out polldev)
> plus some un-necessary code has been removed.
>
> N.B. untested on an IRQ driven gpio_keys using platform as I have
> none available to me, but looks like it should still work
>
> [1] http://article.gmane.org/gmane.linux.kernel.input/5814
>
> Signed-off-by: Alexander Clouter <alex@digriz.org.uk>
> ---
> drivers/input/keyboard/gpio_keys.c | 122 +++++++++++++++++++++++++++++++-----
> include/linux/gpio_keys.h | 1 +
> 2 files changed, 106 insertions(+), 17 deletions(-)
>
> diff --git a/drivers/input/keyboard/gpio_keys.c b/drivers/input/keyboard/gpio_keys.c
> index b8213fd..c790b45 100644
> --- a/drivers/input/keyboard/gpio_keys.c
> +++ b/drivers/input/keyboard/gpio_keys.c
> @@ -1,7 +1,9 @@
> /*
> - * Driver for keys on GPIO lines capable of generating interrupts.
> + * Driver for keys on GPIO lines, either IRQ-driven or polled.
> *
> * Copyright 2005 Phil Blundell
> + * Copyright 2008 Paul Mundt
> + * Copyright 2010 Alexander Clouter <alex@digriz.org.uk>
> *
> * This program is free software; you can redistribute it and/or modify
> * it under the terms of the GNU General Public License version 2 as
> @@ -25,6 +27,7 @@
> #include <linux/gpio_keys.h>
> #include <linux/workqueue.h>
> #include <linux/gpio.h>
> +#include <linux/input-polldev.h>
>
> struct gpio_button_data {
> struct gpio_keys_button *button;
> @@ -36,6 +39,9 @@ struct gpio_button_data {
>
> struct gpio_keys_drvdata {
> struct input_dev *input;
> +#if defined(CONFIG_INPUT_POLLDEV) || defined(CONFIG_INPUT_POLLDEV_MODULE)
> + struct input_polled_dev *poll_dev;
> +#endif
> struct mutex disable_lock;
> unsigned int n_buttons;
> struct gpio_button_data data[0];
> @@ -340,6 +346,16 @@ static void gpio_keys_timer(unsigned long _data)
> schedule_work(&data->work);
> }
>
> +static void gpio_handle_button_event(struct gpio_keys_button *button,
> + struct gpio_button_data *bdata)
> +{
> + if (button->debounce_interval)
> + mod_timer(&bdata->timer,
> + jiffies + msecs_to_jiffies(button->debounce_interval));
> + else
> + gpio_keys_report_event(bdata);
> +}
> +
> static irqreturn_t gpio_keys_isr(int irq, void *dev_id)
> {
> struct gpio_button_data *bdata = dev_id;
> @@ -347,15 +363,26 @@ static irqreturn_t gpio_keys_isr(int irq, void *dev_id)
>
> BUG_ON(irq != gpio_to_irq(button->gpio));
>
> - if (button->debounce_interval)
> - mod_timer(&bdata->timer,
> - jiffies + msecs_to_jiffies(button->debounce_interval));
> - else
> - schedule_work(&bdata->work);
> + gpio_handle_button_event(button, bdata);
>
> return IRQ_HANDLED;
> }
>
> +#if defined(CONFIG_INPUT_POLLDEV) || defined(CONFIG_INPUT_POLLDEV_MODULE)
> +static void gpio_keys_poll(struct input_polled_dev *dev)
> +{
> + struct gpio_keys_drvdata *ddata = dev->private;
> + int i;
> +
> + for (i = 0; i < ddata->n_buttons; i++) {
> + struct gpio_button_data *bdata = &ddata->data[i];
> + struct gpio_keys_button *button = bdata->button;
> +
> + gpio_handle_button_event(button, bdata);
> + }
> +}
> +#endif
> +
> static int __devinit gpio_keys_setup_key(struct platform_device *pdev,
> struct gpio_button_data *bdata,
> struct gpio_keys_button *button)
> @@ -422,23 +449,52 @@ static int __devinit gpio_keys_probe(struct platform_device *pdev)
> struct input_dev *input;
> int i, error;
> int wakeup = 0;
> +#if defined(CONFIG_INPUT_POLLDEV) || defined(CONFIG_INPUT_POLLDEV_MODULE)
> + struct input_polled_dev *poll_dev;
> +#else
> +
> + if (pdata->poll_interval) {
> + dev_err(dev, "device needs polling (enable INPUT_POLLDEV)\n");
> + return -EINVAL;
> + }
> +#endif
>
> ddata = kzalloc(sizeof(struct gpio_keys_drvdata) +
> pdata->nbuttons * sizeof(struct gpio_button_data),
> GFP_KERNEL);
> - input = input_allocate_device();
> +#if defined(CONFIG_INPUT_POLLDEV) || defined(CONFIG_INPUT_POLLDEV_MODULE)
> + if (pdata->poll_interval) {
> + poll_dev = input_allocate_polled_device();
> + if (poll_dev)
> + input = poll_dev->input;
> + } else
> +#endif
> + input = input_allocate_device();
> if (!ddata || !input) {
> dev_err(dev, "failed to allocate state\n");
> error = -ENOMEM;
> goto fail1;
> }
>
> - ddata->input = input;
> +#if defined(CONFIG_INPUT_POLLDEV) || defined(CONFIG_INPUT_POLLDEV_MODULE)
> + if (pdata->poll_interval) {
> + ddata->poll_dev = poll_dev;
> + } else
> +#endif
> + ddata->input = input;
> ddata->n_buttons = pdata->nbuttons;
> mutex_init(&ddata->disable_lock);
>
> platform_set_drvdata(pdev, ddata);
>
> +#if defined(CONFIG_INPUT_POLLDEV) || defined(CONFIG_INPUT_POLLDEV_MODULE)
> + if (pdata->poll_interval) {
> + poll_dev->private = ddata;
> + poll_dev->poll = gpio_keys_poll;
> + poll_dev->poll_interval = pdata->poll_interval;
> + }
> +#endif
> +
> input->name = pdev->name;
> input->phys = "gpio-keys/input0";
> input->dev.parent = &pdev->dev;
> @@ -460,14 +516,17 @@ static int __devinit gpio_keys_probe(struct platform_device *pdev)
> bdata->input = input;
> bdata->button = button;
>
> + input_set_capability(input, type, button->code);
> +
> + if (pdata->poll_interval)
> + continue;
> +
> error = gpio_keys_setup_key(pdev, bdata, button);
> if (error)
> goto fail2;
>
> if (button->wakeup)
> wakeup = 1;
> -
> - input_set_capability(input, type, button->code);
> }
>
> error = sysfs_create_group(&pdev->dev.kobj, &gpio_keys_attr_group);
> @@ -477,7 +536,12 @@ static int __devinit gpio_keys_probe(struct platform_device *pdev)
> goto fail2;
> }
>
> - error = input_register_device(input);
> +#if defined(CONFIG_INPUT_POLLDEV) || defined(CONFIG_INPUT_POLLDEV_MODULE)
> + if (pdata->poll_interval)
> + error = input_register_polled_device(poll_dev);
> + else
> +#endif
> + error = input_register_device(input);
> if (error) {
> dev_err(dev, "Unable to register input device, error: %d\n",
> error);
> @@ -497,7 +561,9 @@ static int __devinit gpio_keys_probe(struct platform_device *pdev)
> sysfs_remove_group(&pdev->dev.kobj, &gpio_keys_attr_group);
> fail2:
> while (--i >= 0) {
> - free_irq(gpio_to_irq(pdata->buttons[i].gpio), &ddata->data[i]);
> + if (!pdata->poll_interval)
> + free_irq(gpio_to_irq(pdata->buttons[i].gpio),
> + &ddata->data[i]);
> if (pdata->buttons[i].debounce_interval)
> del_timer_sync(&ddata->data[i].timer);
> cancel_work_sync(&ddata->data[i].work);
> @@ -506,7 +572,12 @@ static int __devinit gpio_keys_probe(struct platform_device *pdev)
>
> platform_set_drvdata(pdev, NULL);
> fail1:
> - input_free_device(input);
> +#if defined(CONFIG_INPUT_POLLDEV) || defined(CONFIG_INPUT_POLLDEV_MODULE)
> + if (pdata->poll_interval)
> + input_free_polled_device(poll_dev);
> + else
> +#endif
> + input_free_device(input);
> kfree(ddata);
>
> return error;
> @@ -516,23 +587,40 @@ static int __devexit gpio_keys_remove(struct platform_device *pdev)
> {
> struct gpio_keys_platform_data *pdata = pdev->dev.platform_data;
> struct gpio_keys_drvdata *ddata = platform_get_drvdata(pdev);
> - struct input_dev *input = ddata->input;
> + struct input_dev *input;
> int i;
> +#if defined(CONFIG_INPUT_POLLDEV) || defined(CONFIG_INPUT_POLLDEV_MODULE)
> + struct input_polled_dev *poll_dev;
> +#endif
>
> sysfs_remove_group(&pdev->dev.kobj, &gpio_keys_attr_group);
>
> device_init_wakeup(&pdev->dev, 0);
>
> for (i = 0; i < pdata->nbuttons; i++) {
> - int irq = gpio_to_irq(pdata->buttons[i].gpio);
> - free_irq(irq, &ddata->data[i]);
> + if (!pdata->poll_interval) {
> + int irq = gpio_to_irq(pdata->buttons[i].gpio);
> + free_irq(irq, &ddata->data[i]);
> + }
> if (pdata->buttons[i].debounce_interval)
> del_timer_sync(&ddata->data[i].timer);
> cancel_work_sync(&ddata->data[i].work);
> gpio_free(pdata->buttons[i].gpio);
> }
>
> - input_unregister_device(input);
> +#if defined(CONFIG_INPUT_POLLDEV) || defined(CONFIG_INPUT_POLLDEV_MODULE)
> + if (pdata->poll_interval) {
> + poll_dev = ddata->poll_dev;
> + input_unregister_polled_device(poll_dev);
> + input_free_polled_device(poll_dev);
> + } else {
> +#endif
> + input = ddata->input;
> + input_unregister_device(input);
> + input_free_device(input);
> +#if defined(CONFIG_INPUT_POLLDEV) || defined(CONFIG_INPUT_POLLDEV_MODULE)
> + }
> +#endif
>
> return 0;
> }
> diff --git a/include/linux/gpio_keys.h b/include/linux/gpio_keys.h
> index cd0b3f3..7dd075b 100644
> --- a/include/linux/gpio_keys.h
> +++ b/include/linux/gpio_keys.h
> @@ -17,6 +17,7 @@ struct gpio_keys_platform_data {
> struct gpio_keys_button *buttons;
> int nbuttons;
> unsigned int rep:1; /* enable input subsystem auto repeat */
> + unsigned int poll_interval; /* polling interval in ms */
> };
>
> #endif
> --
> 1.7.1
> --
> To unsubscribe from this list: send the line "unsubscribe linux-input" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at http://vger.kernel.org/majordomo-info.html
>
--
Alexander Clouter
.sigmonster says: Men seldom show dimples to girls who have pimples.
next prev parent reply other threads:[~2010-07-08 18:55 UTC|newest]
Thread overview: 17+ messages / expand[flat|nested] mbox.gz Atom feed top
2010-07-06 19:01 [PATCH] input: gpio_keys: polling mode support Alexander Clouter
2010-07-08 16:26 ` Alexander Clouter [this message]
2010-07-12 19:29 ` Alexander Clouter
2010-07-13 1:17 ` Paul Mundt
2010-07-13 1:28 ` Dmitry Torokhov
2010-07-13 7:26 ` Alexander Clouter
2010-07-13 19:57 ` [PATCHv2] " Alexander Clouter
2010-07-13 20:04 ` [PATCHv3] " Alexander Clouter
2010-07-19 21:26 ` Ferenc Wagner
2010-07-24 7:46 ` Dmitry Torokhov
2010-07-24 19:17 ` Ferenc Wagner
-- strict thread matches above, loose matches on Subject: below --
2008-10-21 8:38 [PATCH] input: gpio_keys: Polling " Paul Mundt
2008-10-28 10:18 ` Paul Mundt
2008-10-29 3:51 ` Dmitry Torokhov
2008-11-25 20:43 ` Paul Mundt
2008-12-08 3:32 ` Paul Mundt
2008-12-24 1:47 ` Paul Mundt
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=ppahg7-ahn.ln1@chipmunk.wormnet.eu \
--to=alex@digriz.org.uk \
--cc=linux-input@vger.kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).