Merge "input: sensor: Add power init and enable/disable function for stk3x1x"
diff --git a/drivers/input/misc/stk3x1x.c b/drivers/input/misc/stk3x1x.c
index 3e7dd07..732e3e4 100644
--- a/drivers/input/misc/stk3x1x.c
+++ b/drivers/input/misc/stk3x1x.c
@@ -43,6 +43,7 @@
 #include <linux/gpio.h>
 #include <linux/fs.h>
 #include <linux/uaccess.h>
+#include <linux/regulator/consumer.h>
 #ifdef CONFIG_OF
 #include <linux/of_gpio.h>
 #endif
@@ -172,6 +173,12 @@
 #define ALS_NAME "lightsensor-level"
 #define PS_NAME "proximity"
 
+/* POWER SUPPLY VOLTAGE RANGE */
+#define STK3X1X_VDD_MIN_UV	2000000
+#define STK3X1X_VDD_MAX_UV	3300000
+#define STK3X1X_VIO_MIN_UV	1750000
+#define STK3X1X_VIO_MAX_UV	1950000
+
 struct stk3x1x_data {
 	struct i2c_client *client;
 #if (!defined(STK_POLL_PS) || !defined(STK_POLL_ALS))
@@ -208,6 +215,9 @@
     struct work_struct stk_als_work;
 	struct workqueue_struct *stk_als_wq;
 #endif
+	struct regulator *vdd;
+	struct regulator *vio;
+	bool power_enabled;
 };
 
 #if( !defined(CONFIG_STK_PS_ALS_USE_CHANGE_THRESHOLD))
@@ -1796,6 +1806,116 @@
 }
 #endif	//#ifdef CONFIG_HAS_EARLYSUSPEND
 
+static int stk3x1x_power_on(struct stk3x1x_data *data, bool on)
+{
+	int ret = 0;
+
+	if (!on && data->power_enabled) {
+		ret = regulator_disable(data->vdd);
+		if (ret) {
+			dev_err(&data->client->dev,
+				"Regulator vdd disable failed ret=%d\n", ret);
+			return ret;
+		}
+
+		ret = regulator_disable(data->vio);
+		if (ret) {
+			dev_err(&data->client->dev,
+				"Regulator vio disable failed ret=%d\n", ret);
+			regulator_enable(data->vdd);
+		}
+	} else if (on && !data->power_enabled) {
+
+		ret = regulator_enable(data->vdd);
+		if (ret) {
+			dev_err(&data->client->dev,
+				"Regulator vdd enable failed ret=%d\n", ret);
+			return ret;
+		}
+
+		ret = regulator_enable(data->vio);
+		if (ret) {
+			dev_err(&data->client->dev,
+				"Regulator vio enable failed ret=%d\n", ret);
+			regulator_disable(data->vdd);
+		}
+	} else {
+		dev_warn(&data->client->dev,
+				"Power on=%d. enabled=%d\n",
+				on, data->power_enabled);
+	}
+
+	return ret;
+}
+
+static int stk3x1x_power_init(struct stk3x1x_data *data, bool on)
+{
+	int ret;
+
+	if (!on) {
+		if (regulator_count_voltages(data->vdd) > 0)
+			regulator_set_voltage(data->vdd,
+					0, STK3X1X_VDD_MAX_UV);
+
+		regulator_put(data->vdd);
+
+		if (regulator_count_voltages(data->vio) > 0)
+			regulator_set_voltage(data->vio,
+					0, STK3X1X_VIO_MAX_UV);
+
+		regulator_put(data->vio);
+	} else {
+		data->vdd = regulator_get(&data->client->dev, "vdd");
+		if (IS_ERR(data->vdd)) {
+			ret = PTR_ERR(data->vdd);
+			dev_err(&data->client->dev,
+				"Regulator get failed vdd ret=%d\n", ret);
+			return ret;
+		}
+
+		if (regulator_count_voltages(data->vdd) > 0) {
+			ret = regulator_set_voltage(data->vdd,
+					STK3X1X_VDD_MIN_UV,
+					STK3X1X_VDD_MAX_UV);
+			if (ret) {
+				dev_err(&data->client->dev,
+					"Regulator set failed vdd ret=%d\n",
+					ret);
+				goto reg_vdd_put;
+			}
+		}
+
+		data->vio = regulator_get(&data->client->dev, "vio");
+		if (IS_ERR(data->vio)) {
+			ret = PTR_ERR(data->vio);
+			dev_err(&data->client->dev,
+				"Regulator get failed vio ret=%d\n", ret);
+			goto reg_vdd_set;
+		}
+
+		if (regulator_count_voltages(data->vio) > 0) {
+			ret = regulator_set_voltage(data->vio,
+					STK3X1X_VIO_MIN_UV,
+					STK3X1X_VIO_MAX_UV);
+			if (ret) {
+				dev_err(&data->client->dev,
+				"Regulator set failed vio ret=%d\n", ret);
+				goto reg_vio_put;
+			}
+		}
+	}
+
+	return 0;
+
+reg_vio_put:
+	regulator_put(data->vio);
+reg_vdd_set:
+	if (regulator_count_voltages(data->vdd) > 0)
+		regulator_set_voltage(data->vdd, 0, STK3X1X_VDD_MAX_UV);
+reg_vdd_put:
+	regulator_put(data->vdd);
+	return ret;
+}
 
 #ifdef CONFIG_OF
 static int stk3x1x_parse_dt(struct device *dev,
@@ -2018,6 +2138,14 @@
 		goto err_stk3x1x_setup_irq;
 #endif
 
+	err = stk3x1x_power_init(ps_data, true);
+	if (err)
+		goto err_power_init;
+
+	err = stk3x1x_power_on(ps_data, true);
+	if (err)
+		goto err_power_on;
+
 	err = stk3x1x_init_all_setting(client, plat_data);
 	if(err < 0)
 		goto err_init_all_setting;
@@ -2031,6 +2159,10 @@
 	return 0;
 
 err_init_all_setting:
+	stk3x1x_power_on(ps_data, false);
+err_power_on:
+	stk3x1x_power_init(ps_data, false);
+err_power_init:
 #ifndef STK_POLL_PS
 	free_irq(ps_data->irq, ps_data);
 	gpio_free(plat_data->int_pin);