summaryrefslogtreecommitdiff
path: root/drivers/input
diff options
context:
space:
mode:
authorShantanu Jain <shjain@codeaurora.org>2014-06-05 14:23:04 +0530
committerShantanu Jain <shjain@codeaurora.org>2017-03-22 14:39:37 +0530
commit141fe25708a418e4d123c8c086a4c3fe88d9d95b (patch)
tree383b9189090686c5a1d2a5451b30aeb4f67be3d5 /drivers/input
parentc1ef16be6d3c5606edb7a23398611d010b405aa8 (diff)
input: keyboard: add syscore_ops support to gpio_key driver
Add syscore_ops support for gpio-keys driver to service wakeable irq handler before the CPUs resume after suspend state. Signed-off-by: Shantanu Jain <shjain@codeaurora.org> Change-Id: I7fe266661abfd469c68309a66aed0cb0fa2de33e
Diffstat (limited to 'drivers/input')
-rw-r--r--drivers/input/keyboard/gpio_keys.c77
1 files changed, 74 insertions, 3 deletions
diff --git a/drivers/input/keyboard/gpio_keys.c b/drivers/input/keyboard/gpio_keys.c
index cf29f2756b84..c93dd193a496 100644
--- a/drivers/input/keyboard/gpio_keys.c
+++ b/drivers/input/keyboard/gpio_keys.c
@@ -3,6 +3,7 @@
*
* Copyright 2005 Phil Blundell
* Copyright 2010, 2011 David Jander <david@protonic.nl>
+ * Copyright (c) 2015, 2017, The Linux Foundation. All rights reserved.
*
* 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
@@ -32,6 +33,7 @@
#include <linux/of_irq.h>
#include <linux/spinlock.h>
#include <linux/pinctrl/consumer.h>
+#include <linux/syscore_ops.h>
struct gpio_button_data {
const struct gpio_keys_button *button;
@@ -57,6 +59,11 @@ struct gpio_keys_drvdata {
struct gpio_button_data data[0];
};
+static struct device *global_dev;
+static struct syscore_ops gpio_keys_syscore_pm_ops;
+
+static void gpio_keys_syscore_resume(void);
+
/*
* SYSFS interface for enabling/disabling keys and switches:
*
@@ -343,14 +350,14 @@ static void gpio_keys_gpio_report_event(struct gpio_button_data *bdata)
const 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_cansleep(button->gpio);
+ int state;
+ state = (__gpio_get_value(button->gpio) ? 1 : 0) ^ button->active_low;
if (state < 0) {
dev_err(input->dev.parent, "failed to get gpio state\n");
return;
}
- state = (state ? 1 : 0) ^ button->active_low;
if (type == EV_ABS) {
if (state)
input_event(input, type, button->code, button->value);
@@ -664,6 +671,8 @@ gpio_keys_get_devtree_pdata(struct device *dev)
pdata->nbuttons = nbuttons;
pdata->rep = !!of_get_property(node, "autorepeat", NULL);
+ pdata->name = of_get_property(node, "input-name", NULL);
+ pdata->use_syscore = of_property_read_bool(node, "use-syscore");
i = 0;
for_each_child_of_node(node, pp) {
@@ -710,7 +719,7 @@ gpio_keys_get_devtree_pdata(struct device *dev)
button->can_disable = !!of_get_property(pp, "linux,can-disable", NULL);
if (of_property_read_u32(pp, "debounce-interval",
- &button->debounce_interval))
+ &button->debounce_interval))
button->debounce_interval = 5;
}
@@ -767,6 +776,7 @@ static int gpio_keys_probe(struct platform_device *pdev)
return -ENOMEM;
}
+ global_dev = dev;
ddata->pdata = pdata;
ddata->input = input;
mutex_init(&ddata->disable_lock);
@@ -835,6 +845,11 @@ static int gpio_keys_probe(struct platform_device *pdev)
device_init_wakeup(&pdev->dev, wakeup);
+ if (pdata->use_syscore)
+ gpio_keys_syscore_pm_ops.resume = gpio_keys_syscore_resume;
+
+ register_syscore_ops(&gpio_keys_syscore_pm_ops);
+
return 0;
err_remove_group:
@@ -857,6 +872,7 @@ err_setup_key:
static int gpio_keys_remove(struct platform_device *pdev)
{
sysfs_remove_group(&pdev->dev.kobj, &gpio_keys_attr_group);
+ unregister_syscore_ops(&gpio_keys_syscore_pm_ops);
device_init_wakeup(&pdev->dev, 0);
@@ -864,6 +880,41 @@ static int gpio_keys_remove(struct platform_device *pdev)
}
#ifdef CONFIG_PM_SLEEP
+static void gpio_keys_syscore_resume(void)
+{
+ struct gpio_keys_drvdata *ddata = dev_get_drvdata(global_dev);
+ struct input_dev *input = ddata->input;
+ struct gpio_button_data *bdata = NULL;
+ int error = 0;
+ int i;
+
+ if (ddata->key_pinctrl) {
+ error = gpio_keys_pinctrl_configure(ddata, true);
+ if (error) {
+ dev_err(global_dev, "failed to put the pin in resume state\n");
+ return;
+ }
+ }
+
+ if (device_may_wakeup(global_dev)) {
+ for (i = 0; i < ddata->pdata->nbuttons; i++) {
+ bdata = &ddata->data[i];
+ if (bdata->button->wakeup)
+ disable_irq_wake(bdata->irq);
+ }
+ } else {
+ mutex_lock(&input->mutex);
+ if (input->users)
+ error = gpio_keys_open(input);
+ mutex_unlock(&input->mutex);
+ }
+
+ if (error)
+ return;
+
+ gpio_keys_report_state(ddata);
+}
+
static int gpio_keys_suspend(struct device *dev)
{
struct gpio_keys_drvdata *ddata = dev_get_drvdata(dev);
@@ -901,6 +952,11 @@ static int gpio_keys_resume(struct device *dev)
int error = 0;
int i;
+ if (ddata->pdata->use_syscore == true) {
+ dev_dbg(global_dev, "Using syscore resume, no need of this resume.\n");
+ return 0;
+ }
+
if (ddata->key_pinctrl) {
error = gpio_keys_pinctrl_configure(ddata, true);
if (error) {
@@ -928,6 +984,21 @@ static int gpio_keys_resume(struct device *dev)
gpio_keys_report_state(ddata);
return 0;
}
+
+#else
+
+static void gpio_keys_syscore_resume(void){}
+
+static int gpio_keys_suspend(struct device *dev)
+{
+ return 0;
+}
+
+static int gpio_keys_resume(struct device *dev)
+{
+ return 0;
+}
+
#endif
static SIMPLE_DEV_PM_OPS(gpio_keys_pm_ops, gpio_keys_suspend, gpio_keys_resume);