diff mbox series

[6/6] Input: edt-ft5x06 - add supply voltage support

Message ID 20190917155808.27818-7-m.felsch@pengutronix.de (mailing list archive)
State Superseded
Headers show
Series EDT-FT5x06 improvements | expand

Commit Message

Marco Felsch Sept. 17, 2019, 3:58 p.m. UTC
Currently the driver do not care about the regulator which supplies the
controller. This can lead into problems since we support (deep-)sleep
because the regulator can be turned off before we send the (deep-)sleep
command to the controller. Using a own regulator improves the power
consumption during sleep even more.

Signed-off-by: Marco Felsch <m.felsch@pengutronix.de>
---
 drivers/input/touchscreen/edt-ft5x06.c | 53 ++++++++++++++++++++++----
 1 file changed, 46 insertions(+), 7 deletions(-)

Comments

Andy Shevchenko Sept. 17, 2019, 4:35 p.m. UTC | #1
On Tue, Sep 17, 2019 at 05:58:08PM +0200, Marco Felsch wrote:
> Currently the driver do not care about the regulator which supplies the
> controller. This can lead into problems since we support (deep-)sleep
> because the regulator can be turned off before we send the (deep-)sleep
> command to the controller. Using a own regulator improves the power
> consumption during sleep even more.

> +	tsdata->vdd = devm_regulator_get(&client->dev, "vdd");
> +	if (IS_ERR(tsdata->vdd)) {
> +		error = PTR_ERR(tsdata->vdd);
> +		if (error == -EPROBE_DEFER)
> +			return error;

Before it worked w/o regulator. You have to make it optional.

> +		dev_err(&client->dev,
> +			"Failed to request vdd-supply, error %d\n", error);
> +		return error;
> +	}
> +
> +	error = regulator_enable(tsdata->vdd);
> +	if (error) {
> +		dev_err(&client->dev,
> +			"Failed to enable vdd-supply, error %d\n", error);
> +		return error;
> +	}
Marco Felsch Sept. 17, 2019, 4:51 p.m. UTC | #2
On 19-09-17 19:35, Andy Shevchenko wrote:
> On Tue, Sep 17, 2019 at 05:58:08PM +0200, Marco Felsch wrote:
> > Currently the driver do not care about the regulator which supplies the
> > controller. This can lead into problems since we support (deep-)sleep
> > because the regulator can be turned off before we send the (deep-)sleep
> > command to the controller. Using a own regulator improves the power
> > consumption during sleep even more.
> 
> > +	tsdata->vdd = devm_regulator_get(&client->dev, "vdd");
> > +	if (IS_ERR(tsdata->vdd)) {
> > +		error = PTR_ERR(tsdata->vdd);
> > +		if (error == -EPROBE_DEFER)
> > +			return error;
> 
> Before it worked w/o regulator. You have to make it optional.

devm_regulator_get will return a dummy regulator if no one is specified
so it is optional.

Regards,
  Marco


> 
> > +		dev_err(&client->dev,
> > +			"Failed to request vdd-supply, error %d\n", error);
> > +		return error;
> > +	}
> > +
> > +	error = regulator_enable(tsdata->vdd);
> > +	if (error) {
> > +		dev_err(&client->dev,
> > +			"Failed to enable vdd-supply, error %d\n", error);
> > +		return error;
> > +	}
> 
> -- 
> With Best Regards,
> Andy Shevchenko
> 
> 
>
Dmitry Torokhov Sept. 17, 2019, 4:52 p.m. UTC | #3
On Tue, Sep 17, 2019 at 07:35:36PM +0300, Andy Shevchenko wrote:
> On Tue, Sep 17, 2019 at 05:58:08PM +0200, Marco Felsch wrote:
> > Currently the driver do not care about the regulator which supplies the
> > controller. This can lead into problems since we support (deep-)sleep
> > because the regulator can be turned off before we send the (deep-)sleep
> > command to the controller. Using a own regulator improves the power
> > consumption during sleep even more.
> 
> > +	tsdata->vdd = devm_regulator_get(&client->dev, "vdd");
> > +	if (IS_ERR(tsdata->vdd)) {
> > +		error = PTR_ERR(tsdata->vdd);
> > +		if (error == -EPROBE_DEFER)
> > +			return error;
> 
> Before it worked w/o regulator. You have to make it optional.

No, regulators are funky this way. If there isn't one declared in the
device tree then a dummy is created automatically. Optional regulators
are only to be used when parts of an IC can be powered up separately.

Thanks.
Andy Shevchenko Sept. 17, 2019, 5:12 p.m. UTC | #4
On Tue, Sep 17, 2019 at 09:52:45AM -0700, Dmitry Torokhov wrote:
> On Tue, Sep 17, 2019 at 07:35:36PM +0300, Andy Shevchenko wrote:
> > On Tue, Sep 17, 2019 at 05:58:08PM +0200, Marco Felsch wrote:
> > > Currently the driver do not care about the regulator which supplies the
> > > controller. This can lead into problems since we support (deep-)sleep
> > > because the regulator can be turned off before we send the (deep-)sleep
> > > command to the controller. Using a own regulator improves the power
> > > consumption during sleep even more.
> > 
> > > +	tsdata->vdd = devm_regulator_get(&client->dev, "vdd");
> > > +	if (IS_ERR(tsdata->vdd)) {
> > > +		error = PTR_ERR(tsdata->vdd);
> > > +		if (error == -EPROBE_DEFER)
> > > +			return error;
> > 
> > Before it worked w/o regulator. You have to make it optional.
> 
> No, regulators are funky this way. If there isn't one declared in the
> device tree then a dummy is created automatically. Optional regulators
> are only to be used when parts of an IC can be powered up separately.

It depends if platform has full constrains or not.
For the former, indeed, you are right, for the latter, we will get -ENODEV.
Dmitry Torokhov Sept. 17, 2019, 5:21 p.m. UTC | #5
On Tue, Sep 17, 2019 at 08:12:46PM +0300, Andy Shevchenko wrote:
> On Tue, Sep 17, 2019 at 09:52:45AM -0700, Dmitry Torokhov wrote:
> > On Tue, Sep 17, 2019 at 07:35:36PM +0300, Andy Shevchenko wrote:
> > > On Tue, Sep 17, 2019 at 05:58:08PM +0200, Marco Felsch wrote:
> > > > Currently the driver do not care about the regulator which supplies the
> > > > controller. This can lead into problems since we support (deep-)sleep
> > > > because the regulator can be turned off before we send the (deep-)sleep
> > > > command to the controller. Using a own regulator improves the power
> > > > consumption during sleep even more.
> > > 
> > > > +	tsdata->vdd = devm_regulator_get(&client->dev, "vdd");
> > > > +	if (IS_ERR(tsdata->vdd)) {
> > > > +		error = PTR_ERR(tsdata->vdd);
> > > > +		if (error == -EPROBE_DEFER)
> > > > +			return error;
> > > 
> > > Before it worked w/o regulator. You have to make it optional.
> > 
> > No, regulators are funky this way. If there isn't one declared in the
> > device tree then a dummy is created automatically. Optional regulators
> > are only to be used when parts of an IC can be powered up separately.
> 
> It depends if platform has full constrains or not.

Full constraints is the default behavior. Do we even have platforms that
are not? ACPI and DT are fully-constrained, so that leaves legacy
boards... But there isn't a single one in the tree that uses this
driver.

Thanks.
Andy Shevchenko Sept. 17, 2019, 5:50 p.m. UTC | #6
On Tue, Sep 17, 2019 at 10:21:05AM -0700, Dmitry Torokhov wrote:
> On Tue, Sep 17, 2019 at 08:12:46PM +0300, Andy Shevchenko wrote:
> > On Tue, Sep 17, 2019 at 09:52:45AM -0700, Dmitry Torokhov wrote:
> > > On Tue, Sep 17, 2019 at 07:35:36PM +0300, Andy Shevchenko wrote:
> > > > On Tue, Sep 17, 2019 at 05:58:08PM +0200, Marco Felsch wrote:
> > > > > Currently the driver do not care about the regulator which supplies the
> > > > > controller. This can lead into problems since we support (deep-)sleep
> > > > > because the regulator can be turned off before we send the (deep-)sleep
> > > > > command to the controller. Using a own regulator improves the power
> > > > > consumption during sleep even more.
> > > > 
> > > > > +	tsdata->vdd = devm_regulator_get(&client->dev, "vdd");
> > > > > +	if (IS_ERR(tsdata->vdd)) {
> > > > > +		error = PTR_ERR(tsdata->vdd);
> > > > > +		if (error == -EPROBE_DEFER)
> > > > > +			return error;
> > > > 
> > > > Before it worked w/o regulator. You have to make it optional.
> > > 
> > > No, regulators are funky this way. If there isn't one declared in the
> > > device tree then a dummy is created automatically. Optional regulators
> > > are only to be used when parts of an IC can be powered up separately.
> > 
> > It depends if platform has full constrains or not.
> 
> Full constraints is the default behavior. Do we even have platforms that
> are not? ACPI and DT are fully-constrained, so that leaves legacy
> boards... But there isn't a single one in the tree that uses this
> driver.

Fine then!
diff mbox series

Patch

diff --git a/drivers/input/touchscreen/edt-ft5x06.c b/drivers/input/touchscreen/edt-ft5x06.c
index b95ce5a7482d..6429e915ec94 100644
--- a/drivers/input/touchscreen/edt-ft5x06.c
+++ b/drivers/input/touchscreen/edt-ft5x06.c
@@ -27,6 +27,7 @@ 
 #include <linux/module.h>
 #include <linux/property.h>
 #include <linux/ratelimit.h>
+#include <linux/regulator/consumer.h>
 #include <linux/slab.h>
 #include <linux/uaccess.h>
 
@@ -96,6 +97,7 @@  struct edt_ft5x06_ts_data {
 
 	struct gpio_desc *reset_gpio;
 	struct gpio_desc *wake_gpio;
+	struct regulator *vdd;
 
 #if defined(CONFIG_DEBUG_FS)
 	struct dentry *debug_dir;
@@ -1090,6 +1092,23 @@  static int edt_ft5x06_ts_probe(struct i2c_client *client,
 		return error;
 	}
 
+	tsdata->vdd = devm_regulator_get(&client->dev, "vdd");
+	if (IS_ERR(tsdata->vdd)) {
+		error = PTR_ERR(tsdata->vdd);
+		if (error == -EPROBE_DEFER)
+			return error;
+		dev_err(&client->dev,
+			"Failed to request vdd-supply, error %d\n", error);
+		return error;
+	}
+
+	error = regulator_enable(tsdata->vdd);
+	if (error) {
+		dev_err(&client->dev,
+			"Failed to enable vdd-supply, error %d\n", error);
+		return error;
+	}
+
 	/*
 	 * We need to go this way to keep backward compatibility with old DT's
 	 * which may assume the default-on mechanism.
@@ -1111,7 +1130,8 @@  static int edt_ft5x06_ts_probe(struct i2c_client *client,
 	input = devm_input_allocate_device(&client->dev);
 	if (!input) {
 		dev_err(&client->dev, "failed to allocate input device.\n");
-		return -ENOMEM;
+		error = -ENOMEM;
+		goto err_reg_disable;
 	}
 
 	mutex_init(&tsdata->mutex);
@@ -1122,7 +1142,7 @@  static int edt_ft5x06_ts_probe(struct i2c_client *client,
 	error = edt_ft5x06_ts_identify(client, tsdata, fw_version);
 	if (error) {
 		dev_err(&client->dev, "touchscreen probe failed\n");
-		return error;
+		goto err_reg_disable;
 	}
 
 	edt_ft5x06_ts_set_regs(tsdata);
@@ -1158,7 +1178,7 @@  static int edt_ft5x06_ts_probe(struct i2c_client *client,
 				INPUT_MT_DIRECT);
 	if (error) {
 		dev_err(&client->dev, "Unable to init MT slots.\n");
-		return error;
+		goto err_reg_disable;
 	}
 
 	i2c_set_clientdata(client, tsdata);
@@ -1173,16 +1193,16 @@  static int edt_ft5x06_ts_probe(struct i2c_client *client,
 					client->name, tsdata);
 	if (error) {
 		dev_err(&client->dev, "Unable to request touchscreen IRQ.\n");
-		return error;
+		goto err_reg_disable;
 	}
 
 	error = devm_device_add_group(&client->dev, &edt_ft5x06_attr_group);
 	if (error)
-		return error;
+		goto err_reg_disable;
 
 	error = input_register_device(input);
 	if (error)
-		return error;
+		goto err_reg_disable;
 
 	edt_ft5x06_ts_prepare_debugfs(tsdata, dev_driver_string(&client->dev));
 	device_init_wakeup(&client->dev, en_wakeup);
@@ -1194,6 +1214,10 @@  static int edt_ft5x06_ts_probe(struct i2c_client *client,
 		tsdata->reset_gpio ? desc_to_gpio(tsdata->reset_gpio) : -1);
 
 	return 0;
+
+err_reg_disable:
+	regulator_disable(tsdata->vdd);
+	return error;
 }
 
 static int edt_ft5x06_ts_remove(struct i2c_client *client)
@@ -1225,8 +1249,16 @@  static int __maybe_unused edt_ft5x06_ts_suspend(struct device *dev)
 
 	ret = edt_ft5x06_register_write(tsdata, PMOD_REGISTER_OPMODE,
 					PMOD_REGISTER_HIBERNATE);
-	if (ret)
+	if (ret) {
 		dev_err(dev, "Failed to set hibernate mode\n");
+		return ret;
+	}
+
+	ret = regulator_disable(tsdata->vdd);
+	if (ret) {
+		dev_err(dev, "Failed to disable vdd\n");
+		return ret;
+	}
 
 	return ret;
 }
@@ -1235,12 +1267,19 @@  static int __maybe_unused edt_ft5x06_ts_resume(struct device *dev)
 {
 	struct i2c_client *client = to_i2c_client(dev);
 	struct edt_ft5x06_ts_data *tsdata = i2c_get_clientdata(client);
+	int error;
 
 	if (device_may_wakeup(dev)) {
 		disable_irq_wake(client->irq);
 		return 0;
 	}
 
+	error = regulator_enable(tsdata->vdd);
+	if (error) {
+		dev_err(&client->dev, "Failed to enable vdd\n");
+		return error;
+	}
+
 	/* Recover from hibernate mode if hardware supports it */
 	if (tsdata->wake_gpio) {
 		gpiod_set_value_cansleep(tsdata->wake_gpio, 0);