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/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);