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

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

input: synaptics: release pinctrl resources on probe failure



devm_pinctrl_get() does not release the ownership of mux function
of pins in the associated pin-group whenever a failure occurs in
driver probe routine. i.e struct pin_desc's mux_owner field is
still marked as being in use after a failure occurs in probe.
As a result of this, if another driver tries to acquire the
ownership of same pin, it gets an error while applying that
setting. To fix this, explicitly release the mux function
ownership of the the pin, by adding a new pin-group in pinctrl
DT and a new pinctrl state in touch device's DT node. This new
pin-group does not have a function setting (qcom,pin-func property).
This new state is explicitly activated during a probe failure
and driver remove routine to release the mux function ownership.

The patch also reorganizes the pinctrl related code in driver.

Change-Id: I6726aa2fb5cca47012d72713ce0c13737e472a3e
Signed-off-by: default avatarShantanu Jain <shjain@codeaurora.org>
parent b31147a7
Loading
Loading
Loading
Loading
+4 −1
Original line number Diff line number Diff line
@@ -17,6 +17,8 @@ Required properties:
			config defined in pin groups of interrupt and reset gpio.
			"pmx_ts_suspend" : Disabled configuration of pins, this should specify sleep
			config defined in pin groups of interrupt and reset gpio.
			"pmx_ts_release" : Release configuration of pins, this should specify
			release config defined in pin groups of interrupt and reset gpio.
Optional property:
 - vdd-supply		: Analog power supply needed to power device
 - vcc_i2c-supply		: Power source required to pull up i2c bus
@@ -76,9 +78,10 @@ Example:
			interrupts = <17 0x2>;
			vdd-supply = <&pm8226_l19>;
			vcc_i2c-supply = <&pm8226_lvs1>;
			pinctrl-names = "pmx_ts_active","pmx_ts_suspend";
			pinctrl-names = "pmx_ts_active","pmx_ts_suspend","pmx_ts_release";
			pinctrl-0 = <&ts_int_active &ts_reset_active>;
			pinctrl-1 = <&ts_int_suspend &ts_reset_suspend>;
			pinctrl-1 = <&ts_release>;
			synaptics,reset-gpio = <&msmgpio 16 0x00>;
			synaptics,irq-gpio = <&msmgpio 17 0x00>;
			synaptics,i2c-pull-up;
+77 −65
Original line number Diff line number Diff line
@@ -3163,58 +3163,51 @@ static int synaptics_rmi4_pinctrl_init(struct synaptics_rmi4_data *rmi4_data)
	/* Get pinctrl if target uses pinctrl */
	rmi4_data->ts_pinctrl = devm_pinctrl_get(&(rmi4_data->i2c_client->dev));
	if (IS_ERR_OR_NULL(rmi4_data->ts_pinctrl)) {
		dev_dbg(&rmi4_data->i2c_client->dev,
			"Target does not use pinctrl\n");
		retval = PTR_ERR(rmi4_data->ts_pinctrl);
		rmi4_data->ts_pinctrl = NULL;
		return retval;
	}

	rmi4_data->gpio_state_active
		= pinctrl_lookup_state(rmi4_data->ts_pinctrl, "pmx_ts_active");
	if (IS_ERR_OR_NULL(rmi4_data->gpio_state_active)) {
		dev_dbg(&rmi4_data->i2c_client->dev,
			"Can not get ts default pinstate\n");
		retval = PTR_ERR(rmi4_data->gpio_state_active);
		rmi4_data->ts_pinctrl = NULL;
		return retval;
			"Target does not use pinctrl %d\n", retval);
		goto err_pinctrl_get;
	}

	rmi4_data->gpio_state_suspend
		= pinctrl_lookup_state(rmi4_data->ts_pinctrl, "pmx_ts_suspend");
	if (IS_ERR_OR_NULL(rmi4_data->gpio_state_suspend)) {
		dev_dbg(&rmi4_data->i2c_client->dev,
			"Can not get ts sleep pinstate\n");
		retval = PTR_ERR(rmi4_data->gpio_state_suspend);
		rmi4_data->ts_pinctrl = NULL;
		return retval;
	rmi4_data->pinctrl_state_active
		= pinctrl_lookup_state(rmi4_data->ts_pinctrl,
				PINCTRL_STATE_ACTIVE);
	if (IS_ERR_OR_NULL(rmi4_data->pinctrl_state_active)) {
		retval = PTR_ERR(rmi4_data->pinctrl_state_active);
		dev_err(&rmi4_data->i2c_client->dev,
			"Can not lookup %s pinstate %d\n",
			PINCTRL_STATE_ACTIVE, retval);
		goto err_pinctrl_lookup;
	}

	return 0;
	rmi4_data->pinctrl_state_suspend
		= pinctrl_lookup_state(rmi4_data->ts_pinctrl,
				PINCTRL_STATE_SUSPEND);
	if (IS_ERR_OR_NULL(rmi4_data->pinctrl_state_suspend)) {
		retval = PTR_ERR(rmi4_data->pinctrl_state_suspend);
		dev_err(&rmi4_data->i2c_client->dev,
			"Can not lookup %s pinstate %d\n",
			PINCTRL_STATE_SUSPEND, retval);
		goto err_pinctrl_lookup;
	}

static int synpatics_rmi4_pinctrl_select(struct synaptics_rmi4_data *rmi4_data,
						bool on)
{
	struct pinctrl_state *pins_state;
	int ret;

	pins_state = on ? rmi4_data->gpio_state_active
		: rmi4_data->gpio_state_suspend;
	if (!IS_ERR_OR_NULL(pins_state)) {
		ret = pinctrl_select_state(rmi4_data->ts_pinctrl, pins_state);
		if (ret) {
			dev_err(&rmi4_data->i2c_client->dev,
				"can not set %s pins\n",
				on ? "pmx_ts_active" : "pmx_ts_suspend");
			return ret;
	rmi4_data->pinctrl_state_release
		= pinctrl_lookup_state(rmi4_data->ts_pinctrl,
			PINCTRL_STATE_RELEASE);
	if (IS_ERR_OR_NULL(rmi4_data->pinctrl_state_release)) {
		retval = PTR_ERR(rmi4_data->pinctrl_state_release);
		dev_dbg(&rmi4_data->i2c_client->dev,
			"Can not lookup %s pinstate %d\n",
			PINCTRL_STATE_RELEASE, retval);
	}
	} else
		dev_err(&rmi4_data->i2c_client->dev,
			"not a valid '%s' pinstate\n",
				on ? "pmx_ts_active" : "pmx_ts_suspend");

	return 0;

err_pinctrl_lookup:
	devm_pinctrl_put(rmi4_data->ts_pinctrl);
err_pinctrl_get:
	rmi4_data->ts_pinctrl = NULL;
	return retval;
}

static int synaptics_rmi4_gpio_configure(struct synaptics_rmi4_data *rmi4_data,
@@ -3440,15 +3433,18 @@ static int synaptics_rmi4_probe(struct i2c_client *client,

	retval = synaptics_rmi4_pinctrl_init(rmi4_data);
	if (!retval && rmi4_data->ts_pinctrl) {
		retval = synpatics_rmi4_pinctrl_select(rmi4_data, true);
		retval = pinctrl_select_state(rmi4_data->ts_pinctrl,
					rmi4_data->pinctrl_state_active);
		if (retval < 0)
			goto err_gpio_config;
			goto err_pinctrl_select;
	} else {
		goto err_pinctrl_init;
	}

	retval = synaptics_rmi4_gpio_configure(rmi4_data, true);
	if (retval < 0) {
		dev_err(&client->dev, "Failed to configure gpios\n");
		goto pinctrl_sleep;
		goto err_gpio_config;
	}

	init_waitqueue_head(&rmi4_data->wait);
@@ -3661,13 +3657,20 @@ err_free_gpios:
		gpio_free(rmi4_data->board->reset_gpio);
	if (gpio_is_valid(rmi4_data->board->irq_gpio))
		gpio_free(rmi4_data->board->irq_gpio);
pinctrl_sleep:
err_gpio_config:
err_pinctrl_select:
	if (rmi4_data->ts_pinctrl) {
		retval = synpatics_rmi4_pinctrl_select(rmi4_data, false);
		if (retval < 0)
			pr_err("Cannot get idle pinctrl state\n");
		if (IS_ERR_OR_NULL(rmi4_data->pinctrl_state_release)) {
			devm_pinctrl_put(rmi4_data->ts_pinctrl);
			rmi4_data->ts_pinctrl = NULL;
		} else {
			retval = pinctrl_select_state(rmi4_data->ts_pinctrl,
					rmi4_data->pinctrl_state_release);
			if (retval)
				pr_err("failed to select release pinctrl state\n");
		}
err_gpio_config:
	}
err_pinctrl_init:
	synaptics_rmi4_power_on(rmi4_data, false);
err_power_device:
	synaptics_rmi4_regulator_configure(rmi4_data, false);
@@ -3739,9 +3742,15 @@ static int synaptics_rmi4_remove(struct i2c_client *client)
		gpio_free(rmi4_data->board->irq_gpio);

	if (rmi4_data->ts_pinctrl) {
		retval = synpatics_rmi4_pinctrl_select(rmi4_data, false);
		if (IS_ERR_OR_NULL(rmi4_data->pinctrl_state_release)) {
			devm_pinctrl_put(rmi4_data->ts_pinctrl);
			rmi4_data->ts_pinctrl = NULL;
		} else {
			retval = pinctrl_select_state(rmi4_data->ts_pinctrl,
					rmi4_data->pinctrl_state_release);
			if (retval < 0)
			pr_err("Cannot get idle pinctrl state\n");
				pr_err("failed to select release pinctrl state\n");
		}
	}

	synaptics_rmi4_power_on(rmi4_data, false);
@@ -4151,10 +4160,10 @@ static int synaptics_rmi4_suspend(struct device *dev)

	if (rmi4_data->board->disable_gpios) {
		if (rmi4_data->ts_pinctrl) {
			retval = synpatics_rmi4_pinctrl_select(rmi4_data,
								 false);
			retval = pinctrl_select_state(rmi4_data->ts_pinctrl,
					rmi4_data->pinctrl_state_suspend);
			if (retval < 0)
				dev_err(dev, "Cannot get idle pinctrl state\n");
				dev_err(dev, "failed to select idle pinctrl state\n");
		}

		retval = synaptics_rmi4_gpio_configure(rmi4_data, false);
@@ -4169,9 +4178,10 @@ static int synaptics_rmi4_suspend(struct device *dev)

err_gpio_configure:
	if (rmi4_data->ts_pinctrl) {
		retval = synpatics_rmi4_pinctrl_select(rmi4_data, true);
		retval = pinctrl_select_state(rmi4_data->ts_pinctrl,
					rmi4_data->pinctrl_state_active);
		if (retval < 0)
			dev_err(dev, "Cannot get default pinctrl state\n");
			dev_err(dev, "failed to select get default pinctrl state\n");
	}
	synaptics_rmi4_regulator_lpm(rmi4_data, false);

@@ -4218,9 +4228,10 @@ static int synaptics_rmi4_resume(struct device *dev)

	if (rmi4_data->board->disable_gpios) {
		if (rmi4_data->ts_pinctrl) {
			retval = synpatics_rmi4_pinctrl_select(rmi4_data, true);
			retval = pinctrl_select_state(rmi4_data->ts_pinctrl,
					rmi4_data->pinctrl_state_active);
			if (retval < 0)
				dev_err(dev, "Cannot get default pinctrl state\n");
				dev_err(dev, "failed to select default pinctrl state\n");
		}

		retval = synaptics_rmi4_gpio_configure(rmi4_data, true);
@@ -4250,10 +4261,10 @@ err_check_configuration:

	if (rmi4_data->board->disable_gpios) {
		if (rmi4_data->ts_pinctrl) {
			retval = synpatics_rmi4_pinctrl_select(rmi4_data,
								false);
			retval = pinctrl_select_state(rmi4_data->ts_pinctrl,
					rmi4_data->pinctrl_state_suspend);
			if (retval < 0)
				dev_err(dev, "Cannot get idle pinctrl state\n");
				dev_err(dev, "failed to select idle pinctrl state\n");
		}

		synaptics_rmi4_gpio_configure(rmi4_data, false);
@@ -4265,9 +4276,10 @@ err_check_configuration:

err_gpio_configure:
	if (rmi4_data->ts_pinctrl) {
		retval = synpatics_rmi4_pinctrl_select(rmi4_data, false);
		retval = pinctrl_select_state(rmi4_data->ts_pinctrl,
					rmi4_data->pinctrl_state_suspend);
		if (retval < 0)
			pr_err("Cannot get idle pinctrl state\n");
			pr_err("failed to select idle pinctrl state\n");
	}
	synaptics_rmi4_regulator_lpm(rmi4_data, true);
	wake_up(&rmi4_data->wait);
+7 −2
Original line number Diff line number Diff line
@@ -76,6 +76,10 @@

#define NAME_BUFFER_SIZE 256

#define PINCTRL_STATE_ACTIVE	"pmx_ts_active"
#define PINCTRL_STATE_SUSPEND	"pmx_ts_suspend"
#define PINCTRL_STATE_RELEASE	"pmx_ts_release"

/*
 * struct synaptics_rmi4_fn_desc - function descriptor fields in PDT
 * @query_base_addr: base address for query registers
@@ -270,8 +274,9 @@ struct synaptics_rmi4_data {
#endif
#endif
	struct pinctrl *ts_pinctrl;
	struct pinctrl_state *gpio_state_active;
	struct pinctrl_state *gpio_state_suspend;
	struct pinctrl_state *pinctrl_state_active;
	struct pinctrl_state *pinctrl_state_suspend;
	struct pinctrl_state *pinctrl_state_release;
#if defined(CONFIG_SECURE_TOUCH)
	atomic_t st_enabled;
	atomic_t st_pending_irqs;