From patchwork Tue Nov 16 19:39:34 2010 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Ben Gardiner X-Patchwork-Id: 329071 Received: from bear.ext.ti.com (bear.ext.ti.com [192.94.94.41]) by demeter1.kernel.org (8.14.4/8.14.3) with ESMTP id oAGJgj1k030354 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-SHA bits=256 verify=OK) for ; Tue, 16 Nov 2010 19:43:07 GMT Received: from dlep34.itg.ti.com ([157.170.170.115]) by bear.ext.ti.com (8.13.7/8.13.7) with ESMTP id oAGJewkp010190 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-SHA bits=256 verify=NO); Tue, 16 Nov 2010 13:40:59 -0600 Received: from linux.omap.com (localhost [127.0.0.1]) by dlep34.itg.ti.com (8.13.7/8.13.7) with ESMTP id oAGJerWd011948; Tue, 16 Nov 2010 13:40:53 -0600 (CST) Received: from linux.omap.com (localhost [127.0.0.1]) by linux.omap.com (Postfix) with ESMTP id B71D2806F0; Tue, 16 Nov 2010 13:40:16 -0600 (CST) X-Original-To: davinci-linux-open-source@linux.davincidsp.com Delivered-To: davinci-linux-open-source@linux.davincidsp.com Received: from dflp52.itg.ti.com (dflp52.itg.ti.com [128.247.22.96]) by linux.omap.com (Postfix) with ESMTP id 1456E8062E for ; Tue, 16 Nov 2010 13:39:44 -0600 (CST) Received: from white.ext.ti.com (localhost [127.0.0.1]) by dflp52.itg.ti.com (8.13.7/8.13.7) with ESMTP id oAGJdhGM012769 for ; Tue, 16 Nov 2010 13:39:43 -0600 (CST) Received: from psmtp.com (na3sys009amx168.postini.com [74.125.149.94]) by white.ext.ti.com (8.13.7/8.13.7) with SMTP id oAGJdf8G012904 for ; Tue, 16 Nov 2010 13:39:42 -0600 Received: from source ([74.125.149.201]) by na3sys009amx168.postini.com ([74.125.148.10]) with SMTP; Tue, 16 Nov 2010 11:39:42 PST Received: from source ([209.85.212.45]) by na3sys009aob109.postini.com ([74.125.148.12]) with SMTP ID DSNKTOLd/QXtskgrhQLM53IjTycMCzYnu/0R@postini.com; Tue, 16 Nov 2010 11:39:42 PST Received: by mail-vw0-f45.google.com with SMTP id 5so556454vws.18 for ; Tue, 16 Nov 2010 11:39:41 -0800 (PST) Received: by 10.220.201.139 with SMTP id fa11mr1878859vcb.217.1289936380610; Tue, 16 Nov 2010 11:39:40 -0800 (PST) Received: from localhost.localdomain ([206.191.47.130]) by mx.google.com with ESMTPS id j13sm457716vcr.41.2010.11.16.11.39.39 (version=TLSv1/SSLv3 cipher=RC4-MD5); Tue, 16 Nov 2010 11:39:40 -0800 (PST) From: Ben Gardiner To: Kevin Hilman , davinci-linux-open-source@linux.davincidsp.com, linux-input@vger.kernel.org, Dmitry Torokhov Subject: [PATCH v2 1/4] input: gpio_keys: polling mode support Date: Tue, 16 Nov 2010 14:39:34 -0500 Message-Id: <5778af1b3a740718b3c8d3c727b386e5b1872d16.1289935504.git.bengardiner@nanometrics.ca> X-Mailer: git-send-email 1.7.0.4 In-Reply-To: References: X-pstn-neptune: 0/0/0.00/0 X-pstn-levels: (S:71.66872/99.90000 CV:99.9000 FC:95.5390 LC:95.5390 R:95.9108 P:95.9108 M:88.1613 C:98.6951 ) X-pstn-settings: 2 (0.5000:0.0750) s cv GT3 gt2 gt1 r p m c X-pstn-addresses: from [db-null] Cc: Paul Mundt , linux-kernel@vger.kernel.org, Alexander Clouter , Chris Cordahi X-BeenThere: davinci-linux-open-source@linux.davincidsp.com X-Mailman-Version: 2.1.12 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Sender: davinci-linux-open-source-bounces@linux.davincidsp.com Errors-To: davinci-linux-open-source-bounces@linux.davincidsp.com X-Greylist: Sender succeeded STARTTLS authentication, not delayed by milter-greylist-4.2.3 (demeter1.kernel.org [140.211.167.41]); Tue, 16 Nov 2010 19:43:12 +0000 (UTC) diff --git a/drivers/input/keyboard/gpio_keys.c b/drivers/input/keyboard/gpio_keys.c index 6069abe..d2f23d9 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 * * 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 #include #include +#include struct gpio_button_data { struct gpio_keys_button *button; @@ -37,6 +40,7 @@ struct gpio_button_data { struct gpio_keys_drvdata { struct input_dev *input; + struct input_polled_dev *poll_dev; struct mutex disable_lock; unsigned int n_buttons; int (*enable)(struct device *dev); @@ -44,6 +48,30 @@ struct gpio_keys_drvdata { struct gpio_button_data data[0]; }; +#if (!defined(CONFIG_INPUT_POLLDEV) && !defined(CONFIG_INPUT_POLLDEV_MODULE)) \ + || (defined(CONFIG_INPUT_POLLDEV_MODULE) \ + && !defined(CONFIG_KEYBOARD_GPIO_MODULE)) + +static inline struct input_polled_dev *allocate_polled_device( + const struct device *dev) +{ + dev_err(dev, "device needs polling (enable INPUT_POLLDEV)\n"); + return NULL; +} + +#define free_polled_device(x) do { } while (0) +#define register_polled_device(x) (-ENXIO) +#define unregister_polled_device(x) do { } while (0) + +#else + +#define allocate_polled_device(x) input_allocate_polled_device() +#define free_polled_device(x) input_free_polled_device(x) +#define register_polled_device(x) input_register_polled_device(x) +#define unregister_polled_device(x) input_unregister_polled_device(x) + +#endif + /* * SYSFS interface for enabling/disabling keys and switches: * @@ -322,7 +350,8 @@ static void gpio_keys_report_event(struct gpio_button_data *bdata) struct gpio_keys_button *button = bdata->button; struct input_dev *input = bdata->input; unsigned int type = button->type ?: EV_KEY; - int state = (gpio_get_value(button->gpio) ? 1 : 0) ^ button->active_low; + int state = (gpio_get_value_cansleep(button->gpio) ? 1 : 0) + ^ button->active_low; input_event(input, type, button->code, !!state); input_sync(input); @@ -343,6 +372,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 (bdata->timer_debounce) + mod_timer(&bdata->timer, + jiffies + msecs_to_jiffies(bdata->timer_debounce)); + else + gpio_keys_report_event(bdata); +} + static irqreturn_t gpio_keys_isr(int irq, void *dev_id) { struct gpio_button_data *bdata = dev_id; @@ -350,15 +389,24 @@ static irqreturn_t gpio_keys_isr(int irq, void *dev_id) BUG_ON(irq != gpio_to_irq(button->gpio)); - if (bdata->timer_debounce) - mod_timer(&bdata->timer, - jiffies + msecs_to_jiffies(bdata->timer_debounce)); - else - schedule_work(&bdata->work); + gpio_handle_button_event(button, bdata); return IRQ_HANDLED; } +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); + } +} + static int __devinit gpio_keys_setup_key(struct platform_device *pdev, struct gpio_button_data *bdata, struct gpio_keys_button *button) @@ -446,20 +494,28 @@ static int __devinit gpio_keys_probe(struct platform_device *pdev) struct gpio_keys_drvdata *ddata; struct device *dev = &pdev->dev; struct input_dev *input; + struct input_polled_dev *poll_dev; int i, error; int wakeup = 0; ddata = kzalloc(sizeof(struct gpio_keys_drvdata) + pdata->nbuttons * sizeof(struct gpio_button_data), GFP_KERNEL); - input = input_allocate_device(); + if (pdata->poll_interval) { + poll_dev = allocate_polled_device(dev); + input = poll_dev ? poll_dev->input : 0; + } else + input = input_allocate_device(); if (!ddata || !input) { dev_err(dev, "failed to allocate state\n"); error = -ENOMEM; goto fail1; } - ddata->input = input; + if (pdata->poll_interval) + ddata->poll_dev = poll_dev; + else + ddata->input = input; ddata->n_buttons = pdata->nbuttons; ddata->enable = pdata->enable; ddata->disable = pdata->disable; @@ -468,6 +524,12 @@ static int __devinit gpio_keys_probe(struct platform_device *pdev) platform_set_drvdata(pdev, ddata); input_set_drvdata(input, ddata); + if (pdata->poll_interval) { + poll_dev->private = ddata; + poll_dev->poll = gpio_keys_poll; + poll_dev->poll_interval = pdata->poll_interval; + } + input->name = pdev->name; input->phys = "gpio-keys/input0"; input->dev.parent = &pdev->dev; @@ -491,14 +553,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); @@ -508,7 +573,10 @@ static int __devinit gpio_keys_probe(struct platform_device *pdev) goto fail2; } - error = input_register_device(input); + if (pdata->poll_interval) + error = register_polled_device(poll_dev); + else + error = input_register_device(input); if (error) { dev_err(dev, "Unable to register input device, error: %d\n", error); @@ -528,7 +596,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 (ddata->data[i].timer_debounce) del_timer_sync(&ddata->data[i].timer); cancel_work_sync(&ddata->data[i].work); @@ -537,7 +607,10 @@ static int __devinit gpio_keys_probe(struct platform_device *pdev) platform_set_drvdata(pdev, NULL); fail1: - input_free_device(input); + if (pdata->poll_interval) + free_polled_device(poll_dev); + else + input_free_device(input); kfree(ddata); return error; @@ -547,7 +620,8 @@ 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; + struct input_polled_dev *poll_dev; int i; sysfs_remove_group(&pdev->dev.kobj, &gpio_keys_attr_group); @@ -555,15 +629,25 @@ static int __devexit gpio_keys_remove(struct platform_device *pdev) 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 (ddata->data[i].timer_debounce) 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 (pdata->poll_interval) { + poll_dev = ddata->poll_dev; + unregister_polled_device(poll_dev); + free_polled_device(poll_dev); + } else { + input = ddata->input; + input_unregister_device(input); + input_free_device(input); + } return 0; } diff --git a/include/linux/gpio_keys.h b/include/linux/gpio_keys.h index ce73a30..5fdd495 100644 --- a/include/linux/gpio_keys.h +++ b/include/linux/gpio_keys.h @@ -19,6 +19,7 @@ struct gpio_keys_platform_data { unsigned int rep:1; /* enable input subsystem auto repeat */ int (*enable)(struct device *dev); void (*disable)(struct device *dev); + unsigned int poll_interval; /* polling interval in ms */ }; #endif