summaryrefslogtreecommitdiff
path: root/drivers
diff options
context:
space:
mode:
authorShantanu Jain <shjain@codeaurora.org>2014-03-11 16:09:57 +0530
committerShantanu Jain <shjain@codeaurora.org>2017-02-10 17:29:50 +0530
commitc26a324755f986614785921594510b7b57779af2 (patch)
tree4d46015fe70c465d553e86a55d3a03338fab818d /drivers
parent2aa89ab3ff59a788321bc6af782d639cfc8dab1f (diff)
input: gpio_keys: Add support for pinctrl framework
Add pinctrl framework support for gpio configuration to gpio_keys driver. Signed-off-by: Shantanu Jain <shjain@codeaurora.org> Change-Id: I50c46caca0a65f8906f816e04f89610497956eea
Diffstat (limited to 'drivers')
-rw-r--r--drivers/input/keyboard/gpio_keys.c91
1 files changed, 88 insertions, 3 deletions
diff --git a/drivers/input/keyboard/gpio_keys.c b/drivers/input/keyboard/gpio_keys.c
index cbf603ed5916..517b08b3bc0c 100644
--- a/drivers/input/keyboard/gpio_keys.c
+++ b/drivers/input/keyboard/gpio_keys.c
@@ -31,6 +31,7 @@
#include <linux/of_gpio.h>
#include <linux/of_irq.h>
#include <linux/spinlock.h>
+#include <linux/pinctrl/consumer.h>
struct gpio_button_data {
const struct gpio_keys_button *button;
@@ -50,6 +51,7 @@ struct gpio_button_data {
struct gpio_keys_drvdata {
const struct gpio_keys_platform_data *pdata;
+ struct pinctrl *key_pinctrl;
struct input_dev *input;
struct mutex disable_lock;
struct gpio_button_data data[0];
@@ -564,6 +566,41 @@ static void gpio_keys_report_state(struct gpio_keys_drvdata *ddata)
input_sync(input);
}
+static int gpio_keys_pinctrl_configure(struct gpio_keys_drvdata *ddata,
+ bool active)
+{
+ struct pinctrl_state *set_state;
+ int retval;
+
+ if (active) {
+ set_state =
+ pinctrl_lookup_state(ddata->key_pinctrl,
+ "tlmm_gpio_key_active");
+ if (IS_ERR(set_state)) {
+ dev_err(&ddata->input->dev,
+ "cannot get ts pinctrl active state\n");
+ return PTR_ERR(set_state);
+ }
+ } else {
+ set_state =
+ pinctrl_lookup_state(ddata->key_pinctrl,
+ "tlmm_gpio_key_suspend");
+ if (IS_ERR(set_state)) {
+ dev_err(&ddata->input->dev,
+ "cannot get gpiokey pinctrl sleep state\n");
+ return PTR_ERR(set_state);
+ }
+ }
+ retval = pinctrl_select_state(ddata->key_pinctrl, set_state);
+ if (retval) {
+ dev_err(&ddata->input->dev,
+ "cannot set ts pinctrl active state\n");
+ return retval;
+ }
+
+ return 0;
+}
+
static int gpio_keys_open(struct input_dev *input)
{
struct gpio_keys_drvdata *ddata = input_get_drvdata(input);
@@ -708,6 +745,7 @@ static int gpio_keys_probe(struct platform_device *pdev)
size_t size;
int i, error;
int wakeup = 0;
+ struct pinctrl_state *set_state;
if (!pdata) {
pdata = gpio_keys_get_devtree_pdata(dev);
@@ -751,13 +789,31 @@ static int gpio_keys_probe(struct platform_device *pdev)
if (pdata->rep)
__set_bit(EV_REP, input->evbit);
+ /* Get pinctrl if target uses pinctrl */
+ ddata->key_pinctrl = devm_pinctrl_get(dev);
+ if (IS_ERR(ddata->key_pinctrl)) {
+ if (PTR_ERR(ddata->key_pinctrl) == -EPROBE_DEFER)
+ return -EPROBE_DEFER;
+
+ pr_debug("Target does not use pinctrl\n");
+ ddata->key_pinctrl = NULL;
+ }
+
+ if (ddata->key_pinctrl) {
+ error = gpio_keys_pinctrl_configure(ddata, true);
+ if (error) {
+ dev_err(dev, "cannot set ts pinctrl active state\n");
+ return error;
+ }
+ }
+
for (i = 0; i < pdata->nbuttons; i++) {
const struct gpio_keys_button *button = &pdata->buttons[i];
struct gpio_button_data *bdata = &ddata->data[i];
error = gpio_keys_setup_key(pdev, input, bdata, button);
if (error)
- return error;
+ goto err_setup_key;
if (button->wakeup)
wakeup = 1;
@@ -767,7 +823,7 @@ static int gpio_keys_probe(struct platform_device *pdev)
if (error) {
dev_err(dev, "Unable to export keys/switches, error: %d\n",
error);
- return error;
+ goto err_create_sysfs;
}
error = input_register_device(input);
@@ -783,6 +839,18 @@ static int gpio_keys_probe(struct platform_device *pdev)
err_remove_group:
sysfs_remove_group(&pdev->dev.kobj, &gpio_keys_attr_group);
+err_create_sysfs:
+err_setup_key:
+ if (ddata->key_pinctrl) {
+ set_state =
+ pinctrl_lookup_state(ddata->key_pinctrl,
+ "tlmm_gpio_key_suspend");
+ if (IS_ERR(set_state))
+ dev_err(dev, "cannot get gpiokey pinctrl sleep state\n");
+ else
+ pinctrl_select_state(ddata->key_pinctrl, set_state);
+ }
+
return error;
}
@@ -800,7 +868,7 @@ static int gpio_keys_suspend(struct device *dev)
{
struct gpio_keys_drvdata *ddata = dev_get_drvdata(dev);
struct input_dev *input = ddata->input;
- int i;
+ int i, ret;
if (device_may_wakeup(dev)) {
for (i = 0; i < ddata->pdata->nbuttons; i++) {
@@ -815,6 +883,14 @@ static int gpio_keys_suspend(struct device *dev)
mutex_unlock(&input->mutex);
}
+ if (ddata->key_pinctrl) {
+ ret = gpio_keys_pinctrl_configure(ddata, false);
+ if (ret) {
+ dev_err(dev, "failed to put the pin in suspend state\n");
+ return ret;
+ }
+ }
+
return 0;
}
@@ -841,6 +917,15 @@ static int gpio_keys_resume(struct device *dev)
if (error)
return error;
+ if (ddata->key_pinctrl) {
+ error = gpio_keys_pinctrl_configure(ddata, true);
+ if (error) {
+ dev_err(dev, "failed to put the pin in resume state\n");
+ return error;
+ }
+ }
+
+
gpio_keys_report_state(ddata);
return 0;
}