misc: isa1200: Add regulator support

Signed-off-by: Mohan Pallaka <mpallaka@codeaurora.org>
diff --git a/drivers/misc/isa1200.c b/drivers/misc/isa1200.c
index bb3f9a8..a58c7d6 100644
--- a/drivers/misc/isa1200.c
+++ b/drivers/misc/isa1200.c
@@ -3,7 +3,7 @@
  *
  *  Copyright (C) 2009 Samsung Electronics
  *  Kyungmin Park <kyungmin.park@samsung.com>
- *  Copyright (c) 2010, Code Aurora Forum. All rights reserved.
+ *  Copyright (c) 2010-2011, Code Aurora Forum. All rights reserved.
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 as
@@ -19,6 +19,7 @@
 #include <linux/pwm.h>
 #include <linux/workqueue.h>
 #include <linux/slab.h>
+#include <linux/regulator/consumer.h>
 #include <linux/i2c/isa1200.h>
 #include "../staging/android/timed_output.h"
 
@@ -42,6 +43,8 @@
 	spinlock_t lock;
 	unsigned int enable;
 	unsigned int period_ns;
+	bool is_len_gpio_valid;
+	struct regulator **regs;
 };
 
 static int isa1200_read_reg(struct i2c_client *client, int reg)
@@ -168,8 +171,14 @@
 	int value, temp, rc;
 
 	gpio_set_value_cansleep(haptic->pdata->hap_en_gpio, 0);
+	if (haptic->is_len_gpio_valid == true)
+		gpio_set_value_cansleep(haptic->pdata->hap_len_gpio, 0);
+
 	udelay(250);
+
 	gpio_set_value_cansleep(haptic->pdata->hap_en_gpio, 1);
+	if (haptic->is_len_gpio_valid == true)
+		gpio_set_value_cansleep(haptic->pdata->hap_len_gpio, 1);
 
 	value =	(haptic->pdata->smart_en << 3) |
 		(haptic->pdata->is_erm << 5) |
@@ -218,6 +227,99 @@
 	return rc;
 }
 
+static int isa1200_reg_power(struct isa1200_chip *haptic, bool on)
+{
+	const struct isa1200_regulator *reg_info =
+				haptic->pdata->regulator_info;
+	u8 i, num_reg = haptic->pdata->num_regulators;
+	int rc;
+
+	for (i = 0; i < num_reg; i++) {
+		rc = regulator_set_optimum_mode(haptic->regs[i],
+					on ? reg_info[i].load_uA : 0);
+		if (rc < 0) {
+			pr_err("%s: regulator_set_optimum_mode failed(%d)\n",
+							__func__, rc);
+			goto regs_fail;
+		}
+
+		rc = on ? regulator_enable(haptic->regs[i]) :
+			regulator_disable(haptic->regs[i]);
+		if (rc < 0) {
+			pr_err("%s: regulator %sable fail %d\n", __func__,
+					on ? "en" : "dis", rc);
+			regulator_set_optimum_mode(haptic->regs[i],
+					!on ? reg_info[i].load_uA : 0);
+			goto regs_fail;
+		}
+	}
+
+	return 0;
+
+regs_fail:
+	while (i--) {
+		regulator_set_optimum_mode(haptic->regs[i],
+				!on ? reg_info[i].load_uA : 0);
+		!on ? regulator_enable(haptic->regs[i]) :
+			regulator_disable(haptic->regs[i]);
+	}
+	return rc;
+}
+
+static int isa1200_reg_setup(struct isa1200_chip *haptic, bool on)
+{
+	const struct isa1200_regulator *reg_info =
+				haptic->pdata->regulator_info;
+	u8 i, num_reg = haptic->pdata->num_regulators;
+	int rc = 0;
+
+	/* put regulators */
+	if (on == false) {
+		i = num_reg;
+		goto put_regs;
+	}
+
+	haptic->regs = kzalloc(num_reg * sizeof(struct regulator *),
+							GFP_KERNEL);
+	if (!haptic->regs) {
+		pr_err("unable to allocate memory\n");
+		return -ENOMEM;
+	}
+
+	for (i = 0; i < num_reg; i++) {
+		haptic->regs[i] = regulator_get(&haptic->client->dev,
+							reg_info[i].name);
+		if (IS_ERR(haptic->regs[i])) {
+			rc = PTR_ERR(haptic->regs[i]);
+			pr_err("%s:regulator get failed(%d)\n",	__func__, rc);
+			goto put_regs;
+		}
+
+		if (regulator_count_voltages(haptic->regs[i]) > 0) {
+			rc = regulator_set_voltage(haptic->regs[i],
+				reg_info[i].min_uV, reg_info[i].max_uV);
+			if (rc) {
+				pr_err("%s: regulator_set_voltage failed(%d)\n",
+								__func__, rc);
+				regulator_put(haptic->regs[i]);
+				goto put_regs;
+			}
+		}
+	}
+
+	return rc;
+
+put_regs:
+	while (i--) {
+		if (regulator_count_voltages(haptic->regs[i]) > 0)
+			regulator_set_voltage(haptic->regs[i], 0,
+						reg_info[i].max_uV);
+		regulator_put(haptic->regs[i]);
+	}
+	kfree(haptic->regs);
+	return rc;
+}
+
 static int __devinit isa1200_probe(struct i2c_client *client,
 			const struct i2c_device_id *id)
 {
@@ -255,6 +357,22 @@
 	haptic->enable = 0;
 	haptic->pdata = pdata;
 
+	if (pdata->regulator_info) {
+		ret = isa1200_reg_setup(haptic, true);
+		if (ret) {
+			dev_err(&client->dev, "%s: regulator setup failed\n",
+							__func__);
+			goto reg_setup_fail;
+		}
+
+		ret = isa1200_reg_power(haptic, true);
+		if (ret) {
+			dev_err(&client->dev, "%s: regulator power failed\n",
+							__func__);
+			goto reg_pwr_fail;
+		}
+	}
+
 	if (pdata->power_on) {
 		ret = pdata->power_on(1);
 		if (ret) {
@@ -282,22 +400,39 @@
 
 	ret = gpio_is_valid(pdata->hap_en_gpio);
 	if (ret) {
-		ret = gpio_request(pdata->hap_en_gpio, "haptic_gpio");
+		ret = gpio_request(pdata->hap_en_gpio, "haptic_en_gpio");
 		if (ret) {
 			dev_err(&client->dev, "%s: gpio %d request failed\n",
 					__func__, pdata->hap_en_gpio);
-			goto gpio_fail;
+			goto hen_gpio_fail;
 		}
 	} else {
 		dev_err(&client->dev, "%s: Invalid gpio %d\n", __func__,
 					pdata->hap_en_gpio);
-		goto gpio_fail;
+		goto hen_gpio_fail;
+	}
+
+	haptic->is_len_gpio_valid = true;
+	ret = gpio_is_valid(haptic->pdata->hap_len_gpio);
+	if (ret) {
+		ret = gpio_request(pdata->hap_len_gpio,
+					"haptic_ldo_gpio");
+		if (ret) {
+			dev_err(&client->dev,
+				"%s: gpio %d request failed\n",
+				__func__, pdata->hap_len_gpio);
+			goto len_gpio_fail;
+		}
+	} else {
+		dev_err(&client->dev, "%s: gpio is not used/Invalid %d\n",
+					__func__, pdata->hap_len_gpio);
+		haptic->is_len_gpio_valid = false;
 	}
 
 	ret = isa1200_setup(client);
 	if (ret) {
 		dev_err(&client->dev, "%s: setup fail %d\n", __func__, ret);
-		goto gpio_fail;
+		goto setup_fail;
 	}
 
 	if (haptic->pdata->mode_ctrl == PWM_INPUT_MODE) {
@@ -316,12 +451,23 @@
 reset_hctrl0:
 	i2c_smbus_write_byte_data(client, ISA1200_HCTRL0,
 					ISA1200_HCTRL0_RESET);
-gpio_fail:
+setup_fail:
+	if (haptic->is_len_gpio_valid == true)
+		gpio_free(pdata->hap_len_gpio);
+len_gpio_fail:
+	gpio_free(pdata->hap_en_gpio);
+hen_gpio_fail:
 	timed_output_dev_unregister(&haptic->dev);
 timed_reg_fail:
 	if (pdata->power_on)
 		pdata->power_on(0);
 pwr_up_fail:
+	if (pdata->regulator_info)
+		isa1200_reg_power(haptic, false);
+reg_pwr_fail:
+	if (pdata->regulator_info)
+		isa1200_reg_setup(haptic, false);
+reg_setup_fail:
 	kfree(haptic);
 mem_alloc_fail:
 	if (pdata->dev_setup)
@@ -343,7 +489,10 @@
 		pwm_free(haptic->pwm);
 
 	timed_output_dev_unregister(&haptic->dev);
+
 	gpio_free(haptic->pdata->hap_en_gpio);
+	if (haptic->is_len_gpio_valid == true)
+		gpio_free(haptic->pdata->hap_len_gpio);
 
 	/* reset hardware registers */
 	i2c_smbus_write_byte_data(client, ISA1200_HCTRL0,
@@ -351,13 +500,19 @@
 	i2c_smbus_write_byte_data(client, ISA1200_HCTRL1,
 				ISA1200_HCTRL1_RESET);
 
-	if (haptic->pdata->dev_setup)
-		haptic->pdata->dev_setup(false);
 
 	/* power-off the chip */
+	if (haptic->pdata->regulator_info) {
+		isa1200_reg_power(haptic, false);
+		isa1200_reg_setup(haptic, false);
+	}
+
 	if (haptic->pdata->power_on)
 		haptic->pdata->power_on(0);
 
+	if (haptic->pdata->dev_setup)
+		haptic->pdata->dev_setup(false);
+
 	kfree(haptic);
 	return 0;
 }
@@ -373,6 +528,13 @@
 	/* turn-off current vibration */
 	isa1200_vib_set(haptic, 0);
 
+	gpio_set_value_cansleep(haptic->pdata->hap_en_gpio, 0);
+	if (haptic->is_len_gpio_valid == true)
+		gpio_set_value_cansleep(haptic->pdata->hap_len_gpio, 0);
+
+	if (haptic->pdata->regulator_info)
+		isa1200_reg_power(haptic, false);
+
 	if (haptic->pdata->power_on) {
 		ret = haptic->pdata->power_on(0);
 		if (ret) {
@@ -389,6 +551,9 @@
 	struct isa1200_chip *haptic = i2c_get_clientdata(client);
 	int ret;
 
+	if (haptic->pdata->regulator_info)
+		isa1200_reg_power(haptic, true);
+
 	if (haptic->pdata->power_on) {
 		ret = haptic->pdata->power_on(1);
 		if (ret) {