From 501c7c779a3444cd62222e0c79d6498a08c966c5 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Ond=C5=99ej=20Jirman?= <megi@xff.cz>
Date: Sun, 25 Apr 2021 03:16:42 +0200
Subject: [PATCH 084/463] Input: goodix: Add option to power off the controller
 during suspend

For whatever reason the controller is not suspended on Pinephone
by the default procedure. It consumes quite a bit of power (~40mW)
during system sleep, and more when the screen is touched.

Let's power off the controller during system sleep instead.

Signed-off-by: Ondrej Jirman <megi@xff.cz>
---
 drivers/input/touchscreen/goodix.c | 37 ++++++++++++++++++++++++++++++
 drivers/input/touchscreen/goodix.h |  1 +
 2 files changed, 38 insertions(+)

diff --git a/drivers/input/touchscreen/goodix.c b/drivers/input/touchscreen/goodix.c
index b0a506ed45d61..9feff31d4157d 100644
--- a/drivers/input/touchscreen/goodix.c
+++ b/drivers/input/touchscreen/goodix.c
@@ -1309,6 +1309,7 @@ static void goodix_disable_regulators(void *arg)
 
 static int goodix_ts_probe(struct i2c_client *client)
 {
+	struct device_node *np = client->dev.of_node;
 	struct goodix_ts_data *ts;
 	const char *cfg_name;
 	int error;
@@ -1328,6 +1329,7 @@ static int goodix_ts_probe(struct i2c_client *client)
 	i2c_set_clientdata(client, ts);
 	init_completion(&ts->firmware_loading_complete);
 	ts->contact_size = GOODIX_CONTACT_SIZE;
+	ts->poweroff_in_suspend = of_property_read_bool(np, "poweroff-in-suspend");
 
 	error = goodix_get_gpio_config(ts);
 	if (error)
@@ -1437,6 +1439,15 @@ static int goodix_suspend(struct device *dev)
 	if (ts->load_cfg_from_disk)
 		wait_for_completion(&ts->firmware_loading_complete);
 
+	if (ts->poweroff_in_suspend) {
+		goodix_free_irq(ts);
+		goodix_irq_direction_output(ts, 0);
+		gpiod_direction_output(ts->gpiod_rst, 0);
+		regulator_disable(ts->avdd28);
+		regulator_disable(ts->vddio);
+		return 0;
+	}
+
 	/* We need gpio pins to suspend/resume */
 	if (ts->irq_pin_access_method == IRQ_PIN_ACCESS_NONE) {
 		disable_irq(client->irq);
@@ -1482,6 +1493,32 @@ static int goodix_resume(struct device *dev)
 	u8 config_ver;
 	int error;
 
+	if (ts->poweroff_in_suspend) {
+		error = regulator_enable(ts->avdd28);
+		if (error) {
+			dev_err(dev, "Regulator avdd28 enable failed.\n");
+			return error;
+		}
+
+		error = regulator_enable(ts->vddio);
+		if (error) {
+			dev_err(dev, "Regulator vddio enable failed.\n");
+			return error;
+		}
+
+		error = goodix_reset(ts);
+		if (error) {
+			dev_err(dev, "Controller reset failed.\n");
+			return error;
+		}
+
+		error = goodix_request_irq(ts);
+		if (error)
+			return error;
+
+		return 0;
+	}
+
 	if (ts->irq_pin_access_method == IRQ_PIN_ACCESS_NONE) {
 		enable_irq(client->irq);
 		return 0;
diff --git a/drivers/input/touchscreen/goodix.h b/drivers/input/touchscreen/goodix.h
index 7c44aa110ee64..db9f03149b111 100644
--- a/drivers/input/touchscreen/goodix.h
+++ b/drivers/input/touchscreen/goodix.h
@@ -105,6 +105,7 @@ struct goodix_ts_data {
 	int bak_ref_len;
 	u8 *bak_ref;
         struct dentry *debug_root;
+        bool poweroff_in_suspend;
 };
 
 int goodix_i2c_read(struct i2c_client *client, u16 reg, u8 *buf, int len);
-- 
2.46.0

