From: Ondrej Jirman <megous@megous.com>
Date: Sun, 25 Apr 2021 03:16:42 +0200
Subject: 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 <megous@megous.com>
---
 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 aaa3c45..81a9bca 100644
--- a/drivers/input/touchscreen/goodix.c
+++ b/drivers/input/touchscreen/goodix.c
@@ -1154,6 +1154,7 @@ static void goodix_disable_regulators(void *arg)
 static int goodix_ts_probe(struct i2c_client *client,
 			   const struct i2c_device_id *id)
 {
+	struct device_node *np = client->dev.of_node;
 	struct goodix_ts_data *ts;
 	const char *cfg_name;
 	int error;
@@ -1173,6 +1174,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)
@@ -1282,6 +1284,15 @@ static int __maybe_unused 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);
@@ -1327,6 +1338,32 @@ static int __maybe_unused 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 02065d1..e265695 100644
--- a/drivers/input/touchscreen/goodix.h
+++ b/drivers/input/touchscreen/goodix.h
@@ -102,6 +102,7 @@ struct goodix_ts_data {
 	u8 main_clk[GOODIX_MAIN_CLK_LEN];
 	int bak_ref_len;
 	u8 *bak_ref;
+	bool poweroff_in_suspend;
 };
 
 int goodix_i2c_read(struct i2c_client *client, u16 reg, u8 *buf, int len);