diff options
author | Shantanu Jain <shjain@codeaurora.org> | 2014-03-11 16:09:57 +0530 |
---|---|---|
committer | Shantanu Jain <shjain@codeaurora.org> | 2017-02-10 17:29:50 +0530 |
commit | c26a324755f986614785921594510b7b57779af2 (patch) | |
tree | 4d46015fe70c465d553e86a55d3a03338fab818d | |
parent | 2aa89ab3ff59a788321bc6af782d639cfc8dab1f (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.txt | 49 | ||||
-rw-r--r-- | drivers/input/keyboard/gpio_keys.c | 91 |
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; } |