From: Roger Quadros <ext-roger.quadros@nokia.com>
Date: Tue, 19 May 2009 14:15:56 +0300
Subject: [PATCH] OMAP3: PM: Make Smartreflex driver independent of SRF

This removes Smartreflex driver's dependency on SRF layer to get
OPPs for VDD1 and VDD2. Now Smartreflex is usable irrespective of the
underlying PM layer.

Signed-off-by: Roger Quadros <ext-roger.quadros@nokia.com>
---
 arch/arm/mach-omap2/smartreflex.c |   74 ++++++++++++++++++++++++++++++++-----
 1 files changed, 64 insertions(+), 10 deletions(-)

diff --git a/arch/arm/mach-omap2/smartreflex.c b/arch/arm/mach-omap2/smartreflex.c
index b032366..b66d237 100644
--- a/arch/arm/mach-omap2/smartreflex.c
+++ b/arch/arm/mach-omap2/smartreflex.c
@@ -143,6 +143,57 @@ static u32 cal_test_nvalue(u32 sennval, u32 senpval)
 		(rnsenn << NVALUERECIPROCAL_RNSENN_SHIFT));
 }
 
+/* determine the current OPP from the frequency
+ * we need to give this function last element of OPP rate table
+ * and the frequency
+ */
+static u16 get_opp(struct omap_opp *opp_freq_table,
+					unsigned long freq)
+{
+	struct omap_opp *prcm_config;
+
+	prcm_config = opp_freq_table;
+
+	if (prcm_config->rate <= freq)
+		return prcm_config->opp_id; /* Return the Highest OPP */
+	for (; prcm_config->rate; prcm_config--)
+		if (prcm_config->rate < freq)
+			return (prcm_config+1)->opp_id;
+		else if (prcm_config->rate == freq)
+			return prcm_config->opp_id;
+	/* Return the least OPP */
+	return (prcm_config+1)->opp_id;
+}
+
+static u16 get_vdd1_opp(void)
+{
+	u16 opp;
+	struct clk *clk;
+
+	clk = clk_get(NULL, "dpll1_ck");
+
+	if (clk == NULL || IS_ERR(clk) || mpu_opps == NULL)
+		return 0;
+
+	opp = get_opp(mpu_opps + MAX_VDD1_OPP, clk->rate);
+	return opp;
+}
+
+static u16 get_vdd2_opp(void)
+{
+	u16 opp;
+	struct clk *clk;
+
+	clk = clk_get(NULL, "dpll3_m2_ck");
+
+	if (clk == NULL || IS_ERR(clk) || l3_opps == NULL)
+		return 0;
+
+	opp = get_opp(l3_opps + MAX_VDD2_OPP, clk->rate);
+	return opp;
+}
+
+
 static void sr_set_clk_length(struct omap_sr *sr)
 {
 	struct clk *sys_ck;
@@ -248,13 +299,15 @@ static void sr_configure_vp(int srid)
 {
 	u32 vpconfig;
 	u32 vsel;
+	u32 target_opp_no;
 
 	if (srid == SR1) {
-		if (!omap_pm_vdd1_get_opp())
+		target_opp_no = get_vdd1_opp();
+		if (!target_opp_no)
 			/* Assume Nominal OPP as current OPP unknown */
 			vsel = mpu_opps[VDD1_OPP3].vsel;
 		else
-			vsel = mpu_opps[omap_pm_vdd1_get_opp()].vsel;
+			vsel = mpu_opps[target_opp_no].vsel;
 
 		vpconfig = PRM_VP1_CONFIG_ERROROFFSET |
 			PRM_VP1_CONFIG_ERRORGAIN |
@@ -295,11 +348,12 @@ static void sr_configure_vp(int srid)
 				       OMAP3_PRM_VP1_CONFIG_OFFSET);
 
 	} else if (srid == SR2) {
-		if (!omap_pm_vdd2_get_opp())
+		target_opp_no = get_vdd2_opp();
+		if (!target_opp_no)
 			/* Assume Nominal OPP */
 			vsel = l3_opps[VDD2_OPP3].vsel;
 		else
-			vsel = l3_opps[omap_pm_vdd2_get_opp()].vsel;
+			vsel = l3_opps[target_opp_no].vsel;
 
 		vpconfig = PRM_VP2_CONFIG_ERROROFFSET |
 			PRM_VP2_CONFIG_ERRORGAIN |
@@ -397,7 +451,7 @@ static int sr_reset_voltage(int srid)
 	u32 vc_bypass_value;
 
 	if (srid == SR1) {
-		target_opp_no = omap_pm_vdd1_get_opp();
+		target_opp_no = get_vdd1_opp();
 		if (!target_opp_no) {
 			pr_info("Current OPP unknown: Cannot reset voltage\n");
 			return 1;
@@ -405,7 +459,7 @@ static int sr_reset_voltage(int srid)
 		vsel = mpu_opps[target_opp_no].vsel;
 		reg_addr = R_VDD1_SR_CONTROL;
 	} else if (srid == SR2) {
-		target_opp_no = omap_pm_vdd2_get_opp();
+		target_opp_no = get_vdd2_opp();
 		if (!target_opp_no) {
 			pr_info("Current OPP unknown: Cannot reset voltage\n");
 			return 1;
@@ -641,9 +695,9 @@ void enable_smartreflex(int srid)
 			sr_clk_enable(sr);
 
 			if (srid == SR1)
-				target_opp_no = omap_pm_vdd1_get_opp();
+				target_opp_no = get_vdd1_opp();
 			else if (srid == SR2)
-				target_opp_no = omap_pm_vdd2_get_opp();
+				target_opp_no = get_vdd2_opp();
 
 			if (!target_opp_no) {
 				pr_info("Current OPP unknown \
@@ -786,7 +840,7 @@ static ssize_t omap_sr_vdd1_autocomp_store(struct kobject *kobj,
 	if (value == 0) {
 		sr_stop_vddautocomap(SR1);
 	} else {
-		u32 current_vdd1opp_no = omap_pm_vdd1_get_opp();
+		u32 current_vdd1opp_no = get_vdd1_opp();
 		if (!current_vdd1opp_no) {
 			pr_err("sr_vdd1_autocomp: Current VDD1 opp unknown\n");
 			return -EINVAL;
@@ -826,7 +880,7 @@ static ssize_t omap_sr_vdd2_autocomp_store(struct kobject *kobj,
 	if (value == 0) {
 		sr_stop_vddautocomap(SR2);
 	} else {
-		u32 current_vdd2opp_no = omap_pm_vdd2_get_opp();
+		u32 current_vdd2opp_no = get_vdd2_opp();
 		if (!current_vdd2opp_no) {
 			pr_err("sr_vdd2_autocomp: Current VDD2 opp unknown\n");
 			return -EINVAL;
-- 
1.6.0.4

