Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit c90e4bc7 authored by Shantanu Jain's avatar Shantanu Jain
Browse files

input: gpio_keys: Add support for pinctrl framework



Add pinctrl framework support for gpio configuration
to gpio_keys driver.

Signed-off-by: default avatarShantanu Jain <shjain@codeaurora.org>
Change-Id: I50c46caca0a65f8906f816e04f89610497956eea
parent f0cc8eb8
Loading
Loading
Loading
Loading
+49 −0
Original line number Diff line number Diff line
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>;
			};
+88 −3
Original line number Diff line number Diff line
@@ -30,6 +30,7 @@
#include <linux/of_platform.h>
#include <linux/of_gpio.h>
#include <linux/spinlock.h>
#include <linux/pinctrl/consumer.h>

struct gpio_button_data {
	const struct gpio_keys_button *button;
@@ -45,6 +46,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];
@@ -551,6 +553,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);
@@ -690,6 +727,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);
@@ -733,13 +771,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;
@@ -749,7 +805,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);
@@ -765,6 +821,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;
}

@@ -782,7 +850,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++) {
@@ -797,6 +865,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;
}

@@ -823,6 +899,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;
}