Merge "input: touchscreen: power off touch panel during suspend"
diff --git a/Documentation/devicetree/bindings/input/touchscreen/gt9xx/gt9xx.txt b/Documentation/devicetree/bindings/input/touchscreen/gt9xx/gt9xx.txt
index fdba7c2..ac49b02 100644
--- a/Documentation/devicetree/bindings/input/touchscreen/gt9xx/gt9xx.txt
+++ b/Documentation/devicetree/bindings/input/touchscreen/gt9xx/gt9xx.txt
@@ -30,6 +30,7 @@
 				min y, max x and max y values.
  - goodix,i2c-pull-up	: To specify pull up is required.
  - goodix,no-force-update	: To specify force update is allowed.
+ - goodix,enable-power-off	: Power off touchscreen during suspend.
  - goodix,button-map	: Button map of key codes. The number of key codes
 				depend on panel.
  - goodix,cfg-data0	: Touch screen controller config data group 0. Ask vendor
diff --git a/arch/arm/mach-msm/board-8226-gpiomux.c b/arch/arm/mach-msm/board-8226-gpiomux.c
index 4dcbc3a..34e23d1 100644
--- a/arch/arm/mach-msm/board-8226-gpiomux.c
+++ b/arch/arm/mach-msm/board-8226-gpiomux.c
@@ -303,13 +303,13 @@
 
 static struct gpiomux_setting goodix_ldo_en_sus_cfg = {
 	.func = GPIOMUX_FUNC_GPIO,
-	.drv = GPIOMUX_DRV_6MA,
-	.pull = GPIOMUX_PULL_UP,
+	.drv = GPIOMUX_DRV_2MA,
+	.pull = GPIOMUX_PULL_DOWN,
 };
 
 static struct gpiomux_setting goodix_int_act_cfg = {
 	.func = GPIOMUX_FUNC_GPIO,
-	.drv = GPIOMUX_DRV_8MA,
+	.drv = GPIOMUX_DRV_6MA,
 	.pull = GPIOMUX_PULL_UP,
 };
 
@@ -321,14 +321,14 @@
 
 static struct gpiomux_setting goodix_reset_act_cfg = {
 	.func = GPIOMUX_FUNC_GPIO,
-	.drv = GPIOMUX_DRV_8MA,
+	.drv = GPIOMUX_DRV_6MA,
 	.pull = GPIOMUX_PULL_UP,
 };
 
 static struct gpiomux_setting goodix_reset_sus_cfg = {
 	.func = GPIOMUX_FUNC_GPIO,
-	.drv = GPIOMUX_DRV_8MA,
-	.pull = GPIOMUX_PULL_UP,
+	.drv = GPIOMUX_DRV_2MA,
+	.pull = GPIOMUX_PULL_DOWN,
 };
 
 static struct msm_gpiomux_config msm_skuf_blsp_configs[] __initdata = {
diff --git a/drivers/input/touchscreen/gt9xx/gt9xx.c b/drivers/input/touchscreen/gt9xx/gt9xx.c
index 8b08ac9..c3954a1 100644
--- a/drivers/input/touchscreen/gt9xx/gt9xx.c
+++ b/drivers/input/touchscreen/gt9xx/gt9xx.c
@@ -95,6 +95,8 @@
 static void gtp_reset_guitar(struct goodix_ts_data *ts, int ms);
 static void gtp_int_sync(struct goodix_ts_data *ts, int ms);
 static int gtp_i2c_test(struct i2c_client *client);
+static int goodix_power_off(struct goodix_ts_data *ts);
+static int goodix_power_on(struct goodix_ts_data *ts);
 
 #if defined(CONFIG_FB)
 static int fb_notifier_callback(struct notifier_block *self,
@@ -758,7 +760,7 @@
 	ts: private data.
 Output:
 	Executive outcomes.
-	1: succeed, otherwise failed.
+	>0: succeed, otherwise failed.
 *******************************************************/
 static s8 gtp_enter_sleep(struct goodix_ts_data  *ts)
 {
@@ -769,20 +771,37 @@
 		(u8)GTP_REG_SLEEP, 5};
 
 	ret = gpio_direction_output(ts->pdata->irq_gpio, 0);
-	usleep(5000);
-	while (retry++ < 5) {
-		ret = gtp_i2c_write(ts->client, i2c_control_buf, 3);
-		if (ret > 0) {
-			dev_dbg(&ts->client->dev,
-				"GTP enter sleep!");
-			return ret;
+	if (ret)
+		dev_err(&ts->client->dev,
+			"GTP sleep: Cannot reconfig gpio %d.\n",
+			ts->pdata->irq_gpio);
+	if (ts->pdata->enable_power_off) {
+		ret = gpio_direction_output(ts->pdata->reset_gpio, 0);
+		if (ret)
+			dev_err(&ts->client->dev,
+				"GTP sleep: Cannot reconfig gpio %d.\n",
+				ts->pdata->reset_gpio);
+		ret = goodix_power_off(ts);
+		if (ret) {
+			dev_err(&ts->client->dev, "GTP power off failed.\n");
+			return 0;
 		}
-		msleep(20);
+		return 1;
+	} else {
+		usleep(5000);
+		while (retry++ < 5) {
+			ret = gtp_i2c_write(ts->client, i2c_control_buf, 3);
+			if (ret == 1) {
+				dev_dbg(&ts->client->dev, "GTP enter sleep!");
+				return ret;
+			}
+			msleep(20);
+		}
+		dev_err(&ts->client->dev, "GTP send sleep cmd failed.\n");
+		return ret;
 	}
-	dev_err(&ts->client->dev, "GTP send sleep cmd failed.\n");
-	return ret;
 }
-#endif
+#endif /* !GTP_SLIDE_WAKEUP */
 
 /*******************************************************
 Function:
@@ -798,17 +817,36 @@
 	u8 retry = 0;
 	s8 ret = -1;
 
-#if GTP_POWER_CTRL_SLEEP
-	gtp_reset_guitar(ts, 20);
+	if (ts->pdata->enable_power_off) {
+		ret = gpio_direction_output(ts->pdata->irq_gpio, 0);
+		if (ret)
+			dev_err(&ts->client->dev,
+				"GTP wakeup: Cannot reconfig gpio %d.\n",
+				ts->pdata->irq_gpio);
+		ret = gpio_direction_output(ts->pdata->reset_gpio, 0);
+		if (ret)
+			dev_err(&ts->client->dev,
+				"GTP wakeup: Cannot reconfig gpio %d.\n",
+				ts->pdata->reset_gpio);
+		ret = goodix_power_on(ts);
+		if (ret) {
+			dev_err(&ts->client->dev, "GTP power on failed.\n");
+			return 0;
+		}
 
-	ret = gtp_send_cfg(ts);
-	if (ret > 0) {
+		gtp_reset_guitar(ts, 20);
+
+		ret = gtp_send_cfg(ts);
+		if (ret <= 0) {
+			dev_err(&ts->client->dev,
+				"GTP wakeup sleep failed.\n");
+			return ret;
+		}
+
 		dev_dbg(&ts->client->dev,
-			"Wakeup sleep send config success.");
-		return 1;
-	}
-#else
-	while (retry++ < 10) {
+				"Wakeup sleep send config success.");
+	} else {
+err_retry:
 #if GTP_SLIDE_WAKEUP
 		/* wakeup not by slide */
 		if (DOZE_WAKEUP != doze_status)
@@ -825,7 +863,7 @@
 		}
 #endif
 		ret = gtp_i2c_test(ts->client);
-		if (ret > 0) {
+		if (ret == 2) {
 			dev_dbg(&ts->client->dev, "GTP wakeup sleep.");
 #if (!GTP_SLIDE_WAKEUP)
 			if (chip_gt9xxs == 0) {
@@ -839,10 +877,10 @@
 			return ret;
 		}
 		gtp_reset_guitar(ts, 20);
+		if (retry++ < 10)
+			goto err_retry;
+		dev_err(&ts->client->dev, "GTP wakeup sleep failed.\n");
 	}
-#endif
-
-	dev_err(&ts->client->dev, "GTP wakeup sleep failed.\n");
 	return ret;
 }
 #endif /* !CONFIG_HAS_EARLYSUSPEND && !CONFIG_FB*/
@@ -1292,6 +1330,12 @@
 {
 	int ret;
 
+	if (ts->power_on) {
+		dev_info(&ts->client->dev,
+				"Device already power on\n");
+		return 0;
+	}
+
 	if (!IS_ERR(ts->avdd)) {
 		ret = reg_set_optimum_mode_check(ts->avdd,
 			GOODIX_VDD_LOAD_MAX_UA);
@@ -1358,6 +1402,7 @@
 			}
 	}
 
+	ts->power_on = true;
 	return 0;
 
 err_enable_vcc_i2c:
@@ -1376,6 +1421,7 @@
 		regulator_disable(ts->avdd);
 err_enable_avdd:
 err_set_opt_avdd:
+	ts->power_on = false;
 	return ret;
 }
 
@@ -1389,6 +1435,12 @@
 {
 	int ret;
 
+	if (!ts->power_on) {
+		dev_info(&ts->client->dev,
+				"Device already power off\n");
+		return 0;
+	}
+
 	if (!IS_ERR(ts->vcc_i2c)) {
 		ret = regulator_set_voltage(ts->vcc_i2c, 0,
 			GOODIX_I2C_VTG_MAX_UV);
@@ -1421,6 +1473,7 @@
 				"Regulator avdd disable failed ret=%d\n", ret);
 	}
 
+	ts->power_on = false;
 	return 0;
 }
 
@@ -1536,6 +1589,9 @@
 
 	pdata->no_force_update = of_property_read_bool(np,
 						"goodix,no-force-update");
+
+	pdata->enable_power_off = of_property_read_bool(np,
+						"goodix,enable-power-off");
 	/* reset, irq gpio info */
 	pdata->reset_gpio = of_get_named_gpio_flags(np, "reset-gpios",
 				0, &pdata->reset_gpio_flags);
@@ -1662,6 +1718,7 @@
 	spin_lock_init(&ts->irq_lock);
 	i2c_set_clientdata(client, ts);
 	ts->gtp_rawdiff_mode = 0;
+	ts->power_on = false;
 
 	ret = goodix_power_init(ts);
 	if (ret) {
@@ -1712,6 +1769,7 @@
 		goto exit_free_inputdev;
 	}
 
+	mutex_init(&ts->lock);
 #if defined(CONFIG_FB)
 	ts->fb_notif.notifier_call = fb_notifier_callback;
 	ret = fb_register_client(&ts->fb_notif);
@@ -1757,6 +1815,7 @@
 	init_done = true;
 	return 0;
 exit_free_irq:
+	mutex_destroy(&ts->lock);
 #if defined(CONFIG_FB)
 	if (fb_unregister_client(&ts->fb_notif))
 		dev_err(&client->dev,
@@ -1813,6 +1872,7 @@
 #elif defined(CONFIG_HAS_EARLYSUSPEND)
 	unregister_early_suspend(&ts->early_suspend);
 #endif
+	mutex_destroy(&ts->lock);
 
 #if GTP_CREATE_WR_NODE
 	uninit_wr_node();
@@ -1868,6 +1928,7 @@
 {
 	int ret = -1, i;
 
+	mutex_lock(&ts->lock);
 #if GTP_ESD_PROTECT
 	ts->gtp_is_suspend = 1;
 	gtp_esd_switch(ts->client, SWITCH_OFF);
@@ -1888,12 +1949,13 @@
 
 	ret = gtp_enter_sleep(ts);
 #endif
-	if (ret < 0)
+	if (ret <= 0)
 		dev_err(&ts->client->dev, "GTP early suspend failed.\n");
 	/* to avoid waking up while not sleeping,
 	 * delay 48 + 10ms to ensure reliability
 	 */
 	msleep(58);
+	mutex_unlock(&ts->lock);
 }
 
 /*******************************************************
@@ -1908,13 +1970,14 @@
 {
 	int ret = -1;
 
+	mutex_lock(&ts->lock);
 	ret = gtp_wakeup_sleep(ts);
 
 #if GTP_SLIDE_WAKEUP
 	doze_status = DOZE_DISABLED;
 #endif
 
-	if (ret < 0)
+	if (ret <= 0)
 		dev_err(&ts->client->dev, "GTP resume failed.\n");
 
 	if (ts->use_irq)
@@ -1927,6 +1990,7 @@
 	ts->gtp_is_suspend = 0;
 	gtp_esd_switch(ts->client, SWITCH_ON);
 #endif
+	mutex_unlock(&ts->lock);
 }
 
 #if defined(CONFIG_FB)
diff --git a/drivers/input/touchscreen/gt9xx/gt9xx.h b/drivers/input/touchscreen/gt9xx/gt9xx.h
index 1fdbfa3..125f6e6 100644
--- a/drivers/input/touchscreen/gt9xx/gt9xx.h
+++ b/drivers/input/touchscreen/gt9xx/gt9xx.h
@@ -36,6 +36,7 @@
 #include <linux/regulator/consumer.h>
 #include <linux/firmware.h>
 #include <linux/debugfs.h>
+#include <linux/mutex.h>
 
 #if defined(CONFIG_FB)
 #include <linux/notifier.h>
@@ -62,6 +63,7 @@
 	u32 panel_maxy;
 	bool no_force_update;
 	bool i2c_pull_up;
+	bool enable_power_off;
 	size_t config_data_len[GOODIX_MAX_CFG_GROUP];
 	u8 *config_data[GOODIX_MAX_CFG_GROUP];
 };
@@ -89,6 +91,8 @@
 	u8  fixed_cfg;
 	u8  esd_running;
 	u8  fw_error;
+	bool power_on;
+	struct mutex lock;
 	struct regulator *avdd;
 	struct regulator *vdd;
 	struct regulator *vcc_i2c;
@@ -107,7 +111,6 @@
 #define GTP_CHANGE_X2Y			0
 #define GTP_DRIVER_SEND_CFG		1
 #define GTP_HAVE_TOUCH_KEY		1
-#define GTP_POWER_CTRL_SLEEP	0
 
 /* auto updated by .bin file as default */
 #define GTP_AUTO_UPDATE			0
@@ -119,6 +122,7 @@
 #define GTP_ESD_PROTECT			0
 #define GTP_WITH_PEN			0
 
+/* This cannot work when enable-power-off is on */
 #define GTP_SLIDE_WAKEUP		0
 /* double-click wakeup, function together with GTP_SLIDE_WAKEUP */
 #define GTP_DBL_CLK_WAKEUP		0