summaryrefslogtreecommitdiff
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
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
-rw-r--r--Documentation/devicetree/bindings/gpio/gpio_keys.txt49
-rw-r--r--drivers/input/keyboard/gpio_keys.c91
2 files changed, 137 insertions, 3 deletions
diff --git a/Documentation/devicetree/bindings/gpio/gpio_keys.txt b/Documentation/devicetree/bindings/gpio/gpio_keys.txt
new file mode 100644
index 000000000000..0a9b31a946ec
--- /dev/null
+++ b/Documentation/devicetree/bindings/gpio/gpio_keys.txt
@@ -0,0 +1,49 @@
+Device-Tree bindings for input/gpio_keys.c keyboard driver
+
+Required properties:
+ - compatible = "gpio-keys";
+
+Optional properties:
+ - input-name: input name of the device.
+ - autorepeat: Boolean, Enable auto repeat feature of Linux input subsystem.
+ - pinctrl-names : This should be defined if a target uses pinctrl framework.
+ See "pinctrl" in Documentation/devicetree/bindings/pinctrl/msm-pinctrl.txt.
+ It should specify the names of the configs that pinctrl can install in drive.
+
+ Following are the pinctrl configs that can be installed:
+ "gpio_ts_active" : Active configuration of pins, this should specify active
+ config defined in pin groups of interrupt and reset gpio.
+ "gpio_ts_suspend" : Disabled configuration of pins, this should specify sleep
+ config defined in pin groups of interrupt and reset gpio.
+
+Each button (key) is represented as a sub-node of "gpio-keys":
+Subnode properties:
+
+ - gpios: OF device-tree gpio specification.
+ - label: Descriptive name of the key.
+ - linux,code: Keycode to emit.
+
+Optional subnode-properties:
+ - linux,input-type: Specify event type this button/key generates.
+ If not specified defaults to <1> == EV_KEY.
+ - debounce-interval: Debouncing interval time in milliseconds.
+ If not specified defaults to 5.
+ - gpio-key,wakeup: Boolean, button can wake-up the system.
+
+Example nodes:
+
+gpio_keys {
+ compatible = "gpio-keys";
+ #address-cells = <1>;
+ #size-cells = <0>;
+ autorepeat;
+ input-name = "gpio-keys";
+ pinctrl-names = "tlmm_gpio_key_active","tlmm_gpio_key_suspend";
+ pinctrl-0 = <&gpio_key_active>;
+ pinctrl-1 = <&gpio_key_suspend>;
+ button@21 {
+ label = "GPIO Key UP";
+ linux,code = <103>;
+ gpios = <&gpio1 0 1>;
+ };
+};
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;
}