Commit 5feeca3c authored by Geert Uytterhoeven's avatar Geert Uytterhoeven Committed by Dmitry Torokhov

Input: gpio_keys - add support for GPIO descriptors

GPIO descriptors are the preferred way over legacy GPIO numbers
nowadays. Convert the driver to use GPIO descriptors internally but
still allow passing legacy GPIO numbers from platform data to support
existing platforms.

Based on commits 633a21d8 ("input: gpio_keys_polled: Add support
for GPIO descriptors") and 1ae5ddb6 ("Input: gpio_keys_polled -
request GPIO pin as input.").
Signed-off-by: default avatarGeert Uytterhoeven <geert+renesas@glider.be>
Reviewed-by: default avatarLinus Walleij <linus.walleij@linaro.org>
Tested-by: default avatarMika Westerberg <mika.westerberg@linux.intel.com>
Signed-off-by: default avatarDmitry Torokhov <dmitry.torokhov@gmail.com>
parent 0860913b
...@@ -26,6 +26,7 @@ ...@@ -26,6 +26,7 @@
#include <linux/gpio_keys.h> #include <linux/gpio_keys.h>
#include <linux/workqueue.h> #include <linux/workqueue.h>
#include <linux/gpio.h> #include <linux/gpio.h>
#include <linux/gpio/consumer.h>
#include <linux/of.h> #include <linux/of.h>
#include <linux/of_platform.h> #include <linux/of_platform.h>
#include <linux/of_gpio.h> #include <linux/of_gpio.h>
...@@ -35,6 +36,7 @@ ...@@ -35,6 +36,7 @@
struct gpio_button_data { struct gpio_button_data {
const struct gpio_keys_button *button; const struct gpio_keys_button *button;
struct input_dev *input; struct input_dev *input;
struct gpio_desc *gpiod;
struct timer_list release_timer; struct timer_list release_timer;
unsigned int release_delay; /* in msecs, for IRQ-only buttons */ unsigned int release_delay; /* in msecs, for IRQ-only buttons */
...@@ -140,7 +142,7 @@ static void gpio_keys_disable_button(struct gpio_button_data *bdata) ...@@ -140,7 +142,7 @@ static void gpio_keys_disable_button(struct gpio_button_data *bdata)
*/ */
disable_irq(bdata->irq); disable_irq(bdata->irq);
if (gpio_is_valid(bdata->button->gpio)) if (bdata->gpiod)
cancel_delayed_work_sync(&bdata->work); cancel_delayed_work_sync(&bdata->work);
else else
del_timer_sync(&bdata->release_timer); del_timer_sync(&bdata->release_timer);
...@@ -358,19 +360,20 @@ static void gpio_keys_gpio_report_event(struct gpio_button_data *bdata) ...@@ -358,19 +360,20 @@ static void gpio_keys_gpio_report_event(struct gpio_button_data *bdata)
const struct gpio_keys_button *button = bdata->button; const struct gpio_keys_button *button = bdata->button;
struct input_dev *input = bdata->input; struct input_dev *input = bdata->input;
unsigned int type = button->type ?: EV_KEY; unsigned int type = button->type ?: EV_KEY;
int state = gpio_get_value_cansleep(button->gpio); int state;
state = gpiod_get_value_cansleep(bdata->gpiod);
if (state < 0) { if (state < 0) {
dev_err(input->dev.parent, "failed to get gpio state\n"); dev_err(input->dev.parent,
"failed to get gpio state: %d\n", state);
return; return;
} }
state = (state ? 1 : 0) ^ button->active_low;
if (type == EV_ABS) { if (type == EV_ABS) {
if (state) if (state)
input_event(input, type, button->code, button->value); input_event(input, type, button->code, button->value);
} else { } else {
input_event(input, type, button->code, !!state); input_event(input, type, button->code, state);
} }
input_sync(input); input_sync(input);
} }
...@@ -456,7 +459,7 @@ static void gpio_keys_quiesce_key(void *data) ...@@ -456,7 +459,7 @@ static void gpio_keys_quiesce_key(void *data)
{ {
struct gpio_button_data *bdata = data; struct gpio_button_data *bdata = data;
if (gpio_is_valid(bdata->button->gpio)) if (bdata->gpiod)
cancel_delayed_work_sync(&bdata->work); cancel_delayed_work_sync(&bdata->work);
else else
del_timer_sync(&bdata->release_timer); del_timer_sync(&bdata->release_timer);
...@@ -478,18 +481,30 @@ static int gpio_keys_setup_key(struct platform_device *pdev, ...@@ -478,18 +481,30 @@ static int gpio_keys_setup_key(struct platform_device *pdev,
bdata->button = button; bdata->button = button;
spin_lock_init(&bdata->lock); spin_lock_init(&bdata->lock);
/*
* Legacy GPIO number, so request the GPIO here and
* convert it to descriptor.
*/
if (gpio_is_valid(button->gpio)) { if (gpio_is_valid(button->gpio)) {
unsigned flags = GPIOF_IN;
if (button->active_low)
flags |= GPIOF_ACTIVE_LOW;
error = devm_gpio_request_one(&pdev->dev, button->gpio, error = devm_gpio_request_one(&pdev->dev, button->gpio, flags,
GPIOF_IN, desc); desc);
if (error < 0) { if (error < 0) {
dev_err(dev, "Failed to request GPIO %d, error %d\n", dev_err(dev, "Failed to request GPIO %d, error %d\n",
button->gpio, error); button->gpio, error);
return error; return error;
} }
bdata->gpiod = gpio_to_desc(button->gpio);
if (!bdata->gpiod)
return -EINVAL;
if (button->debounce_interval) { if (button->debounce_interval) {
error = gpio_set_debounce(button->gpio, error = gpiod_set_debounce(bdata->gpiod,
button->debounce_interval * 1000); button->debounce_interval * 1000);
/* use timer if gpiolib doesn't provide debounce */ /* use timer if gpiolib doesn't provide debounce */
if (error < 0) if (error < 0)
...@@ -500,7 +515,7 @@ static int gpio_keys_setup_key(struct platform_device *pdev, ...@@ -500,7 +515,7 @@ static int gpio_keys_setup_key(struct platform_device *pdev,
if (button->irq) { if (button->irq) {
bdata->irq = button->irq; bdata->irq = button->irq;
} else { } else {
irq = gpio_to_irq(button->gpio); irq = gpiod_to_irq(bdata->gpiod);
if (irq < 0) { if (irq < 0) {
error = irq; error = irq;
dev_err(dev, dev_err(dev,
...@@ -575,7 +590,7 @@ static void gpio_keys_report_state(struct gpio_keys_drvdata *ddata) ...@@ -575,7 +590,7 @@ static void gpio_keys_report_state(struct gpio_keys_drvdata *ddata)
for (i = 0; i < ddata->pdata->nbuttons; i++) { for (i = 0; i < ddata->pdata->nbuttons; i++) {
struct gpio_button_data *bdata = &ddata->data[i]; struct gpio_button_data *bdata = &ddata->data[i];
if (gpio_is_valid(bdata->button->gpio)) if (bdata->gpiod)
gpio_keys_gpio_report_event(bdata); gpio_keys_gpio_report_event(bdata);
} }
input_sync(input); input_sync(input);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment