diff options
| author | Shantanu Jain <shjain@codeaurora.org> | 2014-06-05 14:23:04 +0530 |
|---|---|---|
| committer | Shantanu Jain <shjain@codeaurora.org> | 2017-03-22 14:39:37 +0530 |
| commit | 141fe25708a418e4d123c8c086a4c3fe88d9d95b (patch) | |
| tree | 383b9189090686c5a1d2a5451b30aeb4f67be3d5 /drivers/input | |
| parent | c1ef16be6d3c5606edb7a23398611d010b405aa8 (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.c | 77 |
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); |
