input: synaptics_i2c_rmi4: Allow GPIOs to suspend during sleep

In order to save power, enable GPIOs to go into suspened mode
during sleep by freeing them, and re-requesting on wake.

Change-Id: I5b1839f5a15fff0bad13b636be35079a8687fa6a
Signed-off-by: Amy Maloche <amaloche@codeaurora.org>
diff --git a/drivers/input/touchscreen/synaptics_i2c_rmi4.c b/drivers/input/touchscreen/synaptics_i2c_rmi4.c
index 438f701..0b234ce 100644
--- a/drivers/input/touchscreen/synaptics_i2c_rmi4.c
+++ b/drivers/input/touchscreen/synaptics_i2c_rmi4.c
@@ -1058,6 +1058,8 @@
 			"synaptics,i2c-pull-up");
 	rmi4_pdata->power_down_enable = of_property_read_bool(np,
 			"synaptics,power-down");
+	rmi4_pdata->disable_gpios = of_property_read_bool(np,
+			"synaptics,disable-gpios");
 	rmi4_pdata->x_flip = of_property_read_bool(np, "synaptics,x-flip");
 	rmi4_pdata->y_flip = of_property_read_bool(np, "synaptics,y-flip");
 
@@ -2022,6 +2024,85 @@
 	return 0;
 }
 
+static int synaptics_rmi4_gpio_configure(struct synaptics_rmi4_data *rmi4_data,
+					bool on)
+{
+	int retval = 0;
+
+	if (on) {
+		if (gpio_is_valid(rmi4_data->board->irq_gpio)) {
+			/* configure touchscreen irq gpio */
+			retval = gpio_request(rmi4_data->board->irq_gpio,
+				"rmi4_irq_gpio");
+			if (retval) {
+				dev_err(&rmi4_data->i2c_client->dev,
+					"unable to request gpio [%d]\n",
+					rmi4_data->board->irq_gpio);
+				goto err_irq_gpio_req;
+			}
+			retval = gpio_direction_input(rmi4_data->board->\
+				irq_gpio);
+			if (retval) {
+				dev_err(&rmi4_data->i2c_client->dev,
+					"unable to set direction for gpio " \
+					"[%d]\n", rmi4_data->board->irq_gpio);
+				goto err_irq_gpio_dir;
+			}
+		} else {
+			dev_err(&rmi4_data->i2c_client->dev,
+				"irq gpio not provided\n");
+			goto err_irq_gpio_req;
+		}
+
+		if (gpio_is_valid(rmi4_data->board->reset_gpio)) {
+			/* configure touchscreen reset out gpio */
+			retval = gpio_request(rmi4_data->board->reset_gpio,
+					"rmi4_reset_gpio");
+			if (retval) {
+				dev_err(&rmi4_data->i2c_client->dev,
+					"unable to request gpio [%d]\n",
+					rmi4_data->board->reset_gpio);
+				goto err_irq_gpio_dir;
+			}
+
+			retval = gpio_direction_output(rmi4_data->board->\
+				reset_gpio, 1);
+			if (retval) {
+				dev_err(&rmi4_data->i2c_client->dev,
+					"unable to set direction for gpio " \
+					"[%d]\n", rmi4_data->board->reset_gpio);
+				goto err_reset_gpio_dir;
+			}
+
+			gpio_set_value(rmi4_data->board->reset_gpio, 0);
+			usleep(RMI4_GPIO_SLEEP_LOW_US);
+			gpio_set_value(rmi4_data->board->reset_gpio, 1);
+			msleep(RESET_DELAY);
+		} else
+			synaptics_rmi4_reset_command(rmi4_data);
+
+		return 0;
+	} else {
+		if (rmi4_data->board->disable_gpios) {
+			if (gpio_is_valid(rmi4_data->board->irq_gpio))
+				gpio_free(rmi4_data->board->irq_gpio);
+			if (gpio_is_valid(rmi4_data->board->reset_gpio))
+				gpio_free(rmi4_data->board->reset_gpio);
+		}
+
+		return 0;
+	}
+
+err_reset_gpio_dir:
+	if (gpio_is_valid(rmi4_data->board->reset_gpio))
+		gpio_free(rmi4_data->board->reset_gpio);
+err_irq_gpio_dir:
+	if (gpio_is_valid(rmi4_data->board->irq_gpio))
+		gpio_free(rmi4_data->board->irq_gpio);
+err_irq_gpio_req:
+	return retval;
+}
+
  /**
  * synaptics_rmi4_probe()
  *
@@ -2151,52 +2232,12 @@
 		goto err_power_device;
 	}
 
-	if (gpio_is_valid(platform_data->irq_gpio)) {
-		/* configure touchscreen irq gpio */
-		retval = gpio_request(platform_data->irq_gpio, "rmi4_irq_gpio");
-		if (retval) {
-			dev_err(&client->dev, "unable to request gpio [%d]\n",
-						platform_data->irq_gpio);
-			goto err_irq_gpio_req;
-		}
-		retval = gpio_direction_input(platform_data->irq_gpio);
-		if (retval) {
-			dev_err(&client->dev,
-				"unable to set direction for gpio [%d]\n",
-				platform_data->irq_gpio);
-			goto err_irq_gpio_dir;
-		}
-	} else {
-		dev_err(&client->dev, "irq gpio not provided\n");
-		goto err_irq_gpio_req;
+	retval = synaptics_rmi4_gpio_configure(rmi4_data, true);
+	if (retval < 0) {
+		dev_err(&client->dev, "Failed to configure gpios\n");
+		goto err_gpio_config;
 	}
 
-	if (gpio_is_valid(platform_data->reset_gpio)) {
-		/* configure touchscreen reset out gpio */
-		retval = gpio_request(platform_data->reset_gpio,
-				"rmi4_reset_gpio");
-		if (retval) {
-			dev_err(&client->dev, "unable to request gpio [%d]\n",
-						platform_data->reset_gpio);
-			goto err_irq_gpio_dir;
-		}
-
-		retval = gpio_direction_output(platform_data->reset_gpio, 1);
-		if (retval) {
-			dev_err(&client->dev,
-				"unable to set direction for gpio [%d]\n",
-				platform_data->reset_gpio);
-			goto err_reset_gpio_dir;
-		}
-
-		gpio_set_value(platform_data->reset_gpio, 0);
-		usleep(RMI4_GPIO_SLEEP_LOW_US);
-		gpio_set_value(platform_data->reset_gpio, 1);
-		msleep(RESET_DELAY);
-	} else
-		synaptics_rmi4_reset_command(rmi4_data);
-
-
 	init_waitqueue_head(&rmi4_data->wait);
 	mutex_init(&(rmi4_data->rmi4_io_ctrl_mutex));
 
@@ -2205,7 +2246,7 @@
 		dev_err(&client->dev,
 				"%s: Failed to query device\n",
 				__func__);
-		goto err_reset_gpio_dir;
+		goto err_free_gpios;
 	}
 
 	input_set_abs_params(rmi4_data->input_dev,
@@ -2348,13 +2389,12 @@
 			kfree(fhandler);
 		}
 	}
-err_reset_gpio_dir:
-	if (gpio_is_valid(platform_data->reset_gpio))
-		gpio_free(platform_data->reset_gpio);
-err_irq_gpio_dir:
-	if (gpio_is_valid(platform_data->irq_gpio))
-		gpio_free(platform_data->irq_gpio);
-err_irq_gpio_req:
+err_free_gpios:
+	if (gpio_is_valid(rmi4_data->board->reset_gpio))
+		gpio_free(rmi4_data->board->reset_gpio);
+	if (gpio_is_valid(rmi4_data->board->irq_gpio))
+		gpio_free(rmi4_data->board->irq_gpio);
+err_gpio_config:
 	synaptics_rmi4_power_on(rmi4_data, false);
 err_power_device:
 	synaptics_rmi4_regulator_configure(rmi4_data, false);
@@ -2685,16 +2725,6 @@
 		}
 	}
 
-	if (rmi4_data->board->power_down_enable) {
-		retval = synaptics_rmi4_reset_device(rmi4_data);
-		if (retval < 0) {
-			dev_err(&rmi4_data->i2c_client->dev,
-				"%s: Failed to issue reset command, rc = %d\n",
-					__func__, retval);
-			return retval;
-		}
-	}
-
 	return 0;
 
 fail_regulator_lpm:
@@ -2755,6 +2785,13 @@
 		return 0;
 	}
 
+	if (rmi4_data->board->disable_gpios) {
+		retval = synaptics_rmi4_gpio_configure(rmi4_data, false);
+		if (retval < 0) {
+			dev_err(dev, "failed to put gpios in suspend state\n");
+			return retval;
+		}
+	}
 	rmi4_data->suspended = true;
 
 	return 0;
@@ -2780,6 +2817,14 @@
 		return 0;
 	}
 
+	if (rmi4_data->board->disable_gpios) {
+		retval = synaptics_rmi4_gpio_configure(rmi4_data, true);
+		if (retval < 0) {
+			dev_err(dev, "failed to put gpios in active state\n");
+			return retval;
+		}
+	}
+
 	retval = synaptics_rmi4_regulator_lpm(rmi4_data, false);
 	if (retval < 0) {
 		dev_err(dev, "failed to enter active power mode\n");
@@ -2790,6 +2835,17 @@
 	rmi4_data->touch_stopped = false;
 	synaptics_rmi4_irq_enable(rmi4_data, true);
 
+	if (rmi4_data->board->power_down_enable ||
+			rmi4_data->board->disable_gpios) {
+		retval = synaptics_rmi4_reset_device(rmi4_data);
+		if (retval < 0) {
+			dev_err(&rmi4_data->i2c_client->dev,
+				"%s: Failed to issue reset command, " \
+				"rc = %d\n", __func__, retval);
+			return retval;
+		}
+	}
+
 	rmi4_data->suspended = false;
 
 	return 0;