usb: gadget: hsic: Add support for VDDCX corner voting

This change add support in ci13xxx_msm_hsic driver and
ehci-msm-hsic driver for VDDCX corner voting.
In case a VDDCX corner resource is supported by the platform,
it will be used. Else, the legacy voting for specific voltage
level will be used.

Change-Id: Iae91d1c945f9b61340628b2fc7c7727e4cca6a1e
CRs-Fixed: 354458
Signed-off-by: Amit Blay <ablay@codeaurora.org>
Signed-off-by: David Collins <collinsd@codeaurora.org>
diff --git a/drivers/usb/gadget/ci13xxx_msm_hsic.c b/drivers/usb/gadget/ci13xxx_msm_hsic.c
index 39d4720..30b45eb 100644
--- a/drivers/usb/gadget/ci13xxx_msm_hsic.c
+++ b/drivers/usb/gadget/ci13xxx_msm_hsic.c
@@ -30,16 +30,16 @@
 #include <mach/clk.h>
 #include <mach/msm_iomap.h>
 #include <mach/msm_xo.h>
+#include <mach/rpm-regulator.h>
 
 #include "ci13xxx_udc.c"
 
 #define MSM_USB_BASE	(mhsic->regs)
 
 #define ULPI_IO_TIMEOUT_USEC			(10 * 1000)
-#define USB_PHY_VDD_DIG_VOL_SUSP_MIN	500000 /* uV */
+#define USB_PHY_VDD_DIG_VOL_NONE		0 /*uV */
 #define USB_PHY_VDD_DIG_VOL_MIN			1045000 /* uV */
 #define USB_PHY_VDD_DIG_VOL_MAX			1320000 /* uV */
-#define USB_PHY_VDD_DIG_LOAD			49360	/* uA */
 #define LINK_RESET_TIMEOUT_USEC			(250 * 1000)
 #define PHY_SUSPEND_TIMEOUT_USEC		(500 * 1000)
 #define PHY_RESUME_TIMEOUT_USEC			(100 * 1000)
@@ -66,38 +66,56 @@
 	struct workqueue_struct *wq;
 	struct work_struct	suspend_w;
 	struct msm_hsic_peripheral_platform_data *pdata;
+	enum usb_vdd_type	vdd_type;
+};
+
+static const int vdd_val[VDD_TYPE_MAX][VDD_VAL_MAX] = {
+		{   /* VDD_CX CORNER Voting */
+			[VDD_NONE]	= RPM_VREG_CORNER_NONE,
+			[VDD_MIN]	= RPM_VREG_CORNER_NOMINAL,
+			[VDD_MAX]	= RPM_VREG_CORNER_HIGH,
+		},
+		{   /* VDD_CX Voltage Voting */
+			[VDD_NONE]	= USB_PHY_VDD_DIG_VOL_NONE,
+			[VDD_MIN]	= USB_PHY_VDD_DIG_VOL_MIN,
+			[VDD_MAX]	= USB_PHY_VDD_DIG_VOL_MAX,
+		},
 };
 
 static int msm_hsic_init_vddcx(struct msm_hsic_per *mhsic, int init)
 {
 	int ret = 0;
+	int none_vol, min_vol, max_vol;
+
+	if (!mhsic->hsic_vddcx) {
+		mhsic->vdd_type = VDDCX_CORNER;
+		mhsic->hsic_vddcx = devm_regulator_get(mhsic->dev,
+			"hsic_vdd_dig");
+		if (IS_ERR(mhsic->hsic_vddcx)) {
+			mhsic->hsic_vddcx = devm_regulator_get(mhsic->dev,
+				"HSIC_VDDCX");
+			if (IS_ERR(mhsic->hsic_vddcx)) {
+				dev_err(mhsic->dev, "unable to get hsic vddcx\n");
+				return PTR_ERR(mhsic->hsic_vddcx);
+			}
+			mhsic->vdd_type = VDDCX;
+		}
+	}
+
+	none_vol = vdd_val[mhsic->vdd_type][VDD_NONE];
+	min_vol = vdd_val[mhsic->vdd_type][VDD_MIN];
+	max_vol = vdd_val[mhsic->vdd_type][VDD_MAX];
 
 	if (!init)
 		goto disable_reg;
 
-	mhsic->hsic_vddcx = regulator_get(mhsic->dev, "HSIC_VDDCX");
-	if (IS_ERR(mhsic->hsic_vddcx)) {
-		dev_err(mhsic->dev, "unable to get hsic vddcx\n");
-		return PTR_ERR(mhsic->hsic_vddcx);
-	}
-
-	ret = regulator_set_voltage(mhsic->hsic_vddcx,
-			USB_PHY_VDD_DIG_VOL_MIN,
-			USB_PHY_VDD_DIG_VOL_MAX);
+	ret = regulator_set_voltage(mhsic->hsic_vddcx, min_vol, max_vol);
 	if (ret) {
 		dev_err(mhsic->dev, "unable to set the voltage"
 				"for hsic vddcx\n");
 		goto reg_set_voltage_err;
 	}
 
-	ret = regulator_set_optimum_mode(mhsic->hsic_vddcx,
-				USB_PHY_VDD_DIG_LOAD);
-	if (ret < 0) {
-		pr_err("%s: Unable to set optimum mode of the regulator:"
-					"VDDCX\n", __func__);
-		goto reg_optimum_mode_err;
-	}
-
 	ret = regulator_enable(mhsic->hsic_vddcx);
 	if (ret) {
 		dev_err(mhsic->dev, "unable to enable hsic vddcx\n");
@@ -109,12 +127,8 @@
 disable_reg:
 	regulator_disable(mhsic->hsic_vddcx);
 reg_enable_err:
-	regulator_set_optimum_mode(mhsic->hsic_vddcx, 0);
-reg_optimum_mode_err:
-	regulator_set_voltage(mhsic->hsic_vddcx, 0,
-				USB_PHY_VDD_DIG_VOL_MIN);
+	regulator_set_voltage(mhsic->hsic_vddcx, none_vol, max_vol);
 reg_set_voltage_err:
-	regulator_put(mhsic->hsic_vddcx);
 
 	return ret;
 
@@ -323,6 +337,7 @@
 {
 	int cnt = 0, ret;
 	u32 val;
+	int none_vol, max_vol;
 
 	if (atomic_read(&mhsic->in_lpm)) {
 		dev_dbg(mhsic->dev, "%s called while in lpm\n", __func__);
@@ -378,11 +393,12 @@
 		dev_err(mhsic->dev, "%s failed to devote for TCXO %d\n"
 				, __func__, ret);
 
-	ret = regulator_set_voltage(mhsic->hsic_vddcx,
-				USB_PHY_VDD_DIG_VOL_SUSP_MIN,
-				USB_PHY_VDD_DIG_VOL_MAX);
+	none_vol = vdd_val[mhsic->vdd_type][VDD_NONE];
+	max_vol = vdd_val[mhsic->vdd_type][VDD_MAX];
+
+	ret = regulator_set_voltage(mhsic->hsic_vddcx, none_vol, max_vol);
 	if (ret < 0)
-		dev_err(mhsic->dev, "unable to set vddcx voltage: min:0.5v max:1.32v\n");
+		dev_err(mhsic->dev, "unable to set vddcx voltage for VDD MIN\n");
 
 	if (device_may_wakeup(mhsic->dev))
 		enable_irq_wake(mhsic->irq);
@@ -400,6 +416,7 @@
 {
 	int cnt = 0, ret;
 	unsigned temp;
+	int min_vol, max_vol;
 
 	if (!atomic_read(&mhsic->in_lpm)) {
 		dev_dbg(mhsic->dev, "%s called while not in lpm\n", __func__);
@@ -407,12 +424,14 @@
 	}
 
 	wake_lock(&mhsic->wlock);
-	ret = regulator_set_voltage(mhsic->hsic_vddcx,
-				USB_PHY_VDD_DIG_VOL_MIN,
-				USB_PHY_VDD_DIG_VOL_MAX);
+
+	min_vol = vdd_val[mhsic->vdd_type][VDD_MIN];
+	max_vol = vdd_val[mhsic->vdd_type][VDD_MAX];
+
+	ret = regulator_set_voltage(mhsic->hsic_vddcx, min_vol, max_vol);
 	if (ret < 0)
 		dev_err(mhsic->dev,
-				"unable to set vddcx voltage: min:1.045v max:1.32v\n");
+			"unable to set nominal vddcx voltage (no VDD MIN)\n");
 
 	ret = msm_xo_mode_vote(mhsic->xo_handle, MSM_XO_MODE_ON);
 	if (ret)
diff --git a/drivers/usb/host/ehci-msm-hsic.c b/drivers/usb/host/ehci-msm-hsic.c
index 5ed16cc..a6b7dee 100644
--- a/drivers/usb/host/ehci-msm-hsic.c
+++ b/drivers/usb/host/ehci-msm-hsic.c
@@ -30,16 +30,19 @@
 #include <linux/wakelock.h>
 #include <linux/pm_runtime.h>
 #include <linux/regulator/consumer.h>
-#include <mach/msm_bus.h>
 
 #include <linux/usb/msm_hsusb_hw.h>
 #include <linux/usb/msm_hsusb.h>
 #include <linux/gpio.h>
+#include <linux/spinlock.h>
+
+#include <mach/msm_bus.h>
 #include <mach/clk.h>
 #include <mach/msm_iomap.h>
 #include <mach/msm_xo.h>
 #include <linux/spinlock.h>
 #include <linux/cpu.h>
+#include <mach/rpm-regulator.h>
 
 #define MSM_USB_BASE (hcd->regs)
 
@@ -62,6 +65,7 @@
 	atomic_t		pm_usage_cnt;
 	uint32_t		bus_perf_client;
 	uint32_t		wakeup_int_cnt;
+	enum usb_vdd_type	vdd_type;
 };
 
 static bool debug_bus_voting_enabled = true;
@@ -254,43 +258,59 @@
 
 #define ULPI_IO_TIMEOUT_USEC	(10 * 1000)
 
-#define USB_PHY_VDD_DIG_VOL_SUSP_MIN	500000 /* uV */
+#define USB_PHY_VDD_DIG_VOL_NONE	0 /*uV */
 #define USB_PHY_VDD_DIG_VOL_MIN		1000000 /* uV */
 #define USB_PHY_VDD_DIG_VOL_MAX		1320000 /* uV */
-#define USB_PHY_VDD_DIG_LOAD		49360	/* uA */
 
 #define HSIC_DBG1_REG		0x38
 
+static const int vdd_val[VDD_TYPE_MAX][VDD_VAL_MAX] = {
+		{   /* VDD_CX CORNER Voting */
+			[VDD_NONE]	= RPM_VREG_CORNER_NONE,
+			[VDD_MIN]	= RPM_VREG_CORNER_NOMINAL,
+			[VDD_MAX]	= RPM_VREG_CORNER_HIGH,
+		},
+		{   /* VDD_CX Voltage Voting */
+			[VDD_NONE]	= USB_PHY_VDD_DIG_VOL_NONE,
+			[VDD_MIN]	= USB_PHY_VDD_DIG_VOL_MIN,
+			[VDD_MAX]	= USB_PHY_VDD_DIG_VOL_MAX,
+		},
+};
+
 static int msm_hsic_init_vddcx(struct msm_hsic_hcd *mehci, int init)
 {
 	int ret = 0;
+	int none_vol, min_vol, max_vol;
+
+	if (!mehci->hsic_vddcx) {
+		mehci->vdd_type = VDDCX_CORNER;
+		mehci->hsic_vddcx = devm_regulator_get(mehci->dev,
+			"hsic_vdd_dig");
+		if (IS_ERR(mehci->hsic_vddcx)) {
+			mehci->hsic_vddcx = devm_regulator_get(mehci->dev,
+				"HSIC_VDDCX");
+			if (IS_ERR(mehci->hsic_vddcx)) {
+				dev_err(mehci->dev, "unable to get hsic vddcx\n");
+				return PTR_ERR(mehci->hsic_vddcx);
+			}
+			mehci->vdd_type = VDDCX;
+		}
+	}
+
+	none_vol = vdd_val[mehci->vdd_type][VDD_NONE];
+	min_vol = vdd_val[mehci->vdd_type][VDD_MIN];
+	max_vol = vdd_val[mehci->vdd_type][VDD_MAX];
 
 	if (!init)
 		goto disable_reg;
 
-	mehci->hsic_vddcx = devm_regulator_get(mehci->dev, "HSIC_VDDCX");
-	if (IS_ERR(mehci->hsic_vddcx)) {
-		dev_err(mehci->dev, "unable to get hsic vddcx\n");
-		return PTR_ERR(mehci->hsic_vddcx);
-	}
-
-	ret = regulator_set_voltage(mehci->hsic_vddcx,
-			USB_PHY_VDD_DIG_VOL_MIN,
-			USB_PHY_VDD_DIG_VOL_MAX);
+	ret = regulator_set_voltage(mehci->hsic_vddcx, min_vol, max_vol);
 	if (ret) {
 		dev_err(mehci->dev, "unable to set the voltage"
 				"for hsic vddcx\n");
 		return ret;
 	}
 
-	ret = regulator_set_optimum_mode(mehci->hsic_vddcx,
-				USB_PHY_VDD_DIG_LOAD);
-	if (ret < 0) {
-		pr_err("%s: Unable to set optimum mode of the regulator:"
-					"VDDCX\n", __func__);
-		goto reg_optimum_mode_err;
-	}
-
 	ret = regulator_enable(mehci->hsic_vddcx);
 	if (ret) {
 		dev_err(mehci->dev, "unable to enable hsic vddcx\n");
@@ -302,10 +322,8 @@
 disable_reg:
 	regulator_disable(mehci->hsic_vddcx);
 reg_enable_err:
-	regulator_set_optimum_mode(mehci->hsic_vddcx, 0);
-reg_optimum_mode_err:
-	regulator_set_voltage(mehci->hsic_vddcx, 0,
-				USB_PHY_VDD_DIG_VOL_MIN);
+	regulator_set_voltage(mehci->hsic_vddcx, none_vol, max_vol);
+
 	return ret;
 
 }
@@ -528,6 +546,7 @@
 	struct usb_hcd *hcd = hsic_to_hcd(mehci);
 	int cnt = 0, ret;
 	u32 val;
+	int none_vol, max_vol;
 
 	if (atomic_read(&mehci->in_lpm)) {
 		dev_dbg(mehci->dev, "%s called in lpm\n", __func__);
@@ -593,11 +612,12 @@
 	clk_disable_unprepare(mehci->cal_clk);
 	clk_disable_unprepare(mehci->ahb_clk);
 
-	ret = regulator_set_voltage(mehci->hsic_vddcx,
-				USB_PHY_VDD_DIG_VOL_SUSP_MIN,
-				USB_PHY_VDD_DIG_VOL_MAX);
+	none_vol = vdd_val[mehci->vdd_type][VDD_NONE];
+	max_vol = vdd_val[mehci->vdd_type][VDD_MAX];
+
+	ret = regulator_set_voltage(mehci->hsic_vddcx, none_vol, max_vol);
 	if (ret < 0)
-		dev_err(mehci->dev, "unable to set vddcx voltage: min:0.5v max:1.3v\n");
+		dev_err(mehci->dev, "unable to set vddcx voltage for VDD MIN\n");
 
 	if (mehci->bus_perf_client && debug_bus_voting_enabled) {
 		ret = msm_bus_scale_client_update_request(
@@ -626,6 +646,7 @@
 	struct usb_hcd *hcd = hsic_to_hcd(mehci);
 	int cnt = 0, ret;
 	unsigned temp;
+	int min_vol, max_vol;
 
 	if (!atomic_read(&mehci->in_lpm)) {
 		dev_dbg(mehci->dev, "%s called in !in_lpm\n", __func__);
@@ -648,11 +669,12 @@
 				   "bus bandwidth %d\n", __func__, ret);
 	}
 
-	ret = regulator_set_voltage(mehci->hsic_vddcx,
-				USB_PHY_VDD_DIG_VOL_MIN,
-				USB_PHY_VDD_DIG_VOL_MAX);
+	min_vol = vdd_val[mehci->vdd_type][VDD_MIN];
+	max_vol = vdd_val[mehci->vdd_type][VDD_MAX];
+
+	ret = regulator_set_voltage(mehci->hsic_vddcx, min_vol, max_vol);
 	if (ret < 0)
-		dev_err(mehci->dev, "unable to set vddcx voltage: min:1v max:1.3v\n");
+		dev_err(mehci->dev, "unable to set nominal vddcx voltage (no VDD MIN)\n");
 
 	clk_prepare_enable(mehci->core_clk);
 	clk_prepare_enable(mehci->phy_clk);
diff --git a/drivers/usb/otg/msm_otg.c b/drivers/usb/otg/msm_otg.c
index 61fbac0..c0f9346 100644
--- a/drivers/usb/otg/msm_otg.c
+++ b/drivers/usb/otg/msm_otg.c
@@ -87,13 +87,6 @@
 #endif
 }
 
-enum usb_vdd_value {
-	VDD_NONE = 0,
-	VDD_MIN,
-	VDD_MAX,
-	VDD_VAL_MAX,
-};
-
 static const int vdd_val[VDD_TYPE_MAX][VDD_VAL_MAX] = {
 		{  /* VDD_CX CORNER Voting */
 			[VDD_NONE]	= RPM_VREG_CORNER_NONE,