diff mbox

[RFC,2/2] OMAP3:PM:SR: SmartReflex Refactor Rev2.0

Message ID 1254443465-13006-3-git-send-email-nm@ti.com (mailing list archive)
State Superseded
Delegated to: Kevin Hilman
Headers show

Commit Message

Nishanth Menon Oct. 2, 2009, 12:31 a.m. UTC
None
diff mbox

Patch

diff --git a/arch/arm/mach-omap2/resource34xx.c b/arch/arm/mach-omap2/resource34xx.c
index 1693e9b..6710c86 100644
--- a/arch/arm/mach-omap2/resource34xx.c
+++ b/arch/arm/mach-omap2/resource34xx.c
@@ -287,17 +287,23 @@  static int program_opp(int res, struct omap_opp *opp, int target_level,
 	else
 		raise = 0;
 
+#ifdef CONFIG_OMAP_SMARTREFLEX
+	sr_vp_disable_both(t_opp, c_opp);
+#endif
 	for (i = 0; i < 2; i++) {
 		if (i == raise)
 			ret = program_opp_freq(res, target_level,
 					current_level);
 #ifdef CONFIG_OMAP_SMARTREFLEX
 		else
-			sr_voltagescale_vcbypass(t_opp, c_opp,
+			sr_voltage_set(t_opp, c_opp,
 				opp[target_level].vsel,
 				opp[current_level].vsel);
 #endif
 	}
+#ifdef CONFIG_OMAP_SMARTREFLEX
+	sr_vp_enable_both(t_opp, c_opp);
+#endif
 
 	return ret;
 }
diff --git a/arch/arm/mach-omap2/smartreflex.c b/arch/arm/mach-omap2/smartreflex.c
new file mode 100644
index 0000000..d881e8e
--- /dev/null
+++ b/arch/arm/mach-omap2/smartreflex.c
@@ -0,0 +1,1346 @@ 
+/*
+ * linux/arch/arm/mach-omap3/smartreflex.c
+ *
+ * OMAP34XX SmartReflex Voltage Control
+ *
+ * Copyright (C) 2009 Texas Instruments, Inc.
+ * Nishanth Menon
+ *
+ * Copyright (C) 2008 Nokia Corporation
+ * Kalle Jokiniemi
+ *
+ * Copyright (C) 2007 Texas Instruments, Inc.
+ * Lesly A M <x0080970@ti.com>
+ *
+ * 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
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/module.h>
+#include <linux/delay.h>
+#include <linux/err.h>
+#include <linux/clk.h>
+#include <linux/sysfs.h>
+#include <linux/kobject.h>
+#include <linux/i2c/twl4030.h>
+#include <linux/io.h>
+
+#include <mach/omap34xx.h>
+#include <mach/control.h>
+#include <mach/clock.h>
+#include <mach/omap-pm.h>
+#include <mach/resource.h>
+#include <mach/powerdomain.h>
+
+#include "prm.h"
+#include "smartreflex.h"
+#include "prm-regbits-34xx.h"
+
+/* MCUDISACK is expected to happen within 1uSec. */
+#define COUNT_TIMEOUT_MCUDISACK		50
+
+/* VPINIDLE is expected to happen within 100uSec. Typical is 2uSec */
+#define COUNT_TIMEOUT_VPINIDLE		200
+
+/* Time taken for setting the device - worst case as FS I2C
+ * Depends on SMPSWAITIME MIN/MAX Typical is 200uSec
+ */
+#define COUNT_TIMEOUT_TRANSDONE_SET	400
+
+/* Time to clear out multiple transdone events typical is 3uSec */
+#define COUNT_TIMEOUT_TRANSDONE_CLR	50
+
+/* Time For VCBypass mode for TWL4030 derivative chip. */
+#define COUNT_TIMEOUT_TWL4030_VCBYPASS	500
+
+/* How many retries to do for I2C errors seen on bus for Forceupdate? */
+#define COUNT_RETRY_SMPSNOACK		4
+
+#define SR_REGADDR(offset)	(sr->srbase_addr + (offset))
+
+/* Which function to use for setting voltage */
+#ifdef CONFIG_OMAP_VC_BYPASS_UPDATE
+#define SR_CHOSEN_VOLTAGE_UPDATE_MECH  sr_vc_bypass
+#else
+#define SR_CHOSEN_VOLTAGE_UPDATE_MECH  sr_vp_forceupdate
+#endif
+
+/* Using SMART REFLEX TEST nVALUES - for devices without EFUSE */
+#ifdef CONFIG_OMAP_SMARTREFLEX_TESTING_NVALUES
+#warning "SR TESTING NVALUES BUILD- Hope you know what you are doing!!!!!"
+
+/* 5 values each for the valid OPP please.. */
+static u32 __initdata sr1_test_nvalues[] = {
+	/* *INDENT-OFF* */
+	0x00000000,	0x00000000,
+	0x00AAB48A,	0x00ABA2E6,
+	0x00AB90D3
+	/* *INDENT-ON* */
+};
+#define SR1_N_MOD 0x3
+#define SR1_P_MOD 0x3
+
+/* 3 values each for the valid OPP please.. */
+static u32 __initdata sr2_test_nvalues[] = {
+	/* *INDENT-OFF* */
+	0x00000000,	0x00000000,
+	0x00AAC695
+	/* *INDENT-ON* */
+};
+#define SR2_N_MOD 0x3
+#define SR2_P_MOD 0x3
+
+#endif			/* CONFIG_OMAP_SMARTREFLEX_TESTING_NVALUES */
+
+/* Structure for Voltage processor */
+struct omap_sr_vp {
+	/* Store the commonly used register offsets.
+	 * this saves a if condition decision
+	 */
+	u16 prm_vpx_status_offset;
+	u16 prm_vpx_config_offset;
+	u16 prm_vpx_stepmin_offset;
+	u16 prm_vpx_stepmax_offset;
+	u16 prm_vpx_limito_offset;
+	/* Store the defaults
+	 * allowing us to save OCP read
+	 * operation
+	 */
+	u32 vpconfig_value;
+	u32 vpstepmin_value;
+	u32 vpstepmax_value;
+	u32 vplimito_value;
+	u32 vpenable_mask;
+	u32 irqmask_trans_done;
+	u32 irqmask_smps_noack;
+};
+
+/* Structure for Smart Reflex */
+struct omap_sr {
+	int srid;
+	/* SR activity marker */
+	u8 is_sr_reset;
+	u8 is_autocomp_active;
+	u32 req_opp_no;
+	u32 opp_nvalue[5];
+	u32 sr_config_value;
+	u32 sr_errconfig_value;
+	struct clk *fclk;
+	struct clk *iclk;
+	void __iomem *srbase_addr;
+	void __iomem *vpbase_addr;
+	/* Lock for maintaining SR+VP programming sequence atomicity */
+	/* Voltage processor for the specific SR module */
+	struct omap_sr_vp vp;
+};
+
+/* Smart Reflex 1 structure */
+static struct omap_sr sr1 = {
+	/* *INDENT-OFF* */
+	.srid			= SR1,
+	.is_sr_reset		= 1,
+	.is_autocomp_active	= 0,
+	.srbase_addr		= OMAP2_IO_ADDRESS(OMAP34XX_SR1_BASE),
+	.vp = {
+		.prm_vpx_status_offset	= OMAP3_PRM_VP1_STATUS_OFFSET,
+		.prm_vpx_config_offset	= OMAP3_PRM_VP1_CONFIG_OFFSET,
+		.prm_vpx_stepmin_offset	= OMAP3_PRM_VP1_VSTEPMIN_OFFSET,
+		.prm_vpx_stepmax_offset	= OMAP3_PRM_VP1_VSTEPMAX_OFFSET,
+		.prm_vpx_limito_offset	= OMAP3_PRM_VP1_VLIMITTO_OFFSET,
+		.vpconfig_value		= PRM_VP1_CONFIG_ERROROFFSET |
+			PRM_VP1_CONFIG_TIMEOUTEN,
+		.vpstepmin_value	= PRM_VP1_VSTEPMIN_SMPSWAITTIMEMIN |
+			PRM_VP1_VSTEPMIN_VSTEPMIN,
+		.vpstepmax_value	= PRM_VP1_VSTEPMAX_SMPSWAITTIMEMAX |
+			PRM_VP1_VSTEPMAX_VSTEPMAX,
+		.vplimito_value		= PRM_VP1_VLIMITTO_VDDMAX |
+			PRM_VP1_VLIMITTO_VDDMIN,
+		.vpenable_mask		= PRM_VP1_CONFIG_VPENABLE,
+		.irqmask_trans_done	= VP1_IRQMASK_TRANSDONE,
+		.irqmask_smps_noack	= OMAP3430_VP1_NOSMPSACK_ST,
+	},
+	/* *INDENT-ON* */
+};
+
+/* Smart Reflex 2 structure */
+static struct omap_sr sr2 = {
+	/* *INDENT-OFF* */
+	.srid			= SR2,
+	.is_sr_reset		= 1,
+	.is_autocomp_active	= 0,
+	.srbase_addr		= OMAP2_IO_ADDRESS(OMAP34XX_SR2_BASE),
+	.vp = {
+		.prm_vpx_status_offset	= OMAP3_PRM_VP2_STATUS_OFFSET,
+		.prm_vpx_config_offset	= OMAP3_PRM_VP2_CONFIG_OFFSET,
+		.prm_vpx_stepmin_offset	= OMAP3_PRM_VP2_VSTEPMIN_OFFSET,
+		.prm_vpx_stepmax_offset	= OMAP3_PRM_VP2_VSTEPMAX_OFFSET,
+		.prm_vpx_limito_offset	= OMAP3_PRM_VP2_VLIMITTO_OFFSET,
+		.vpconfig_value		= PRM_VP2_CONFIG_ERROROFFSET |
+			PRM_VP2_CONFIG_TIMEOUTEN,
+		.vpstepmin_value	= PRM_VP2_VSTEPMIN_SMPSWAITTIMEMIN |
+			PRM_VP2_VSTEPMIN_VSTEPMIN,
+		.vpstepmax_value	= PRM_VP2_VSTEPMAX_SMPSWAITTIMEMAX |
+			PRM_VP2_VSTEPMAX_VSTEPMAX,
+		.vplimito_value		= PRM_VP2_VLIMITTO_VDDMAX |
+			PRM_VP2_VLIMITTO_VDDMIN,
+		.vpenable_mask		= PRM_VP2_CONFIG_VPENABLE,
+		.irqmask_trans_done	= VP2_IRQMASK_TRANSDONE,
+		.irqmask_smps_noack	= OMAP3430_VP1_NOSMPSACK_ST,
+	},
+	/* *INDENT-ON* */
+};
+
+/****************** PMIC WEAK FUNCTIONS FOR TWL4030 derivatives **********/
+
+/**
+ * @brief pmic_srinit - Power management IC initialization
+ * for smart reflex. The current code is written for TWL4030
+ * derivatives, replace in board file if PMIC requires
+ * a different sequence
+ *
+ * @return result of operation
+ */
+int __weak __init omap_pmic_srinit(void)
+{
+	int ret = -ENODEV;
+#ifdef CONFIG_TWL4030_CORE
+	u8 reg;
+	/* Enable SR on T2 */
+	ret = twl4030_i2c_read_u8(TWL4030_MODULE_PM_RECEIVER, &reg,
+				  R_DCDC_GLOBAL_CFG);
+
+	reg |= DCDC_GLOBAL_CFG_ENABLE_SRFLX;
+	ret |= twl4030_i2c_write_u8(TWL4030_MODULE_PM_RECEIVER, reg,
+				    R_DCDC_GLOBAL_CFG);
+#endif		/* End of CONFIG_TWL4030_CORE */
+	return ret;
+}
+
+/**
+ * @brief omap_pmic_voltage_ramp_delay - how much should this pmic ramp delay
+ * Various PMICs have different ramp up and down delays. choose to implement
+ * in required pmic file to override this function.
+ * On TWL4030 derivatives:
+ *  T2 SMPS slew rate (min) 4mV/uS, step size 12.5mV,
+ *  2us added as buffer.
+ *
+ * @param target_vsel - targetted voltage selction
+ * @param current_vsel - current voltage selection
+ *
+ * @return delay in uSeconds
+ */
+u32 __weak omap_pmic_voltage_ramp_delay(u8 target_vsel, u8 current_vsel)
+{
+	u32 t2_smps_steps = abs(target_vsel - current_vsel);
+	u32 t2_smps_delay = ((t2_smps_steps * 125) / 40) + 2;
+	return t2_smps_delay;
+}
+
+#ifdef CONFIG_OMAP_VC_BYPASS_UPDATE
+/**
+ * @brief omap_pmic_voltage_cmds - hook for pmic command sequence
+ * to be send out which are specific to pmic to set a specific voltage.
+ * this should inturn call vc_send_command with the required sequence
+ * The current implementation is for TWL4030 derivatives
+ *
+ * @param srid - which SR is this for?
+ * @param target_vsel - what voltage is desired to be set?
+ *
+ * @return specific value to set.
+ */
+int __weak omap_pmic_voltage_cmds(u8 srid, u8 target_vsel)
+{
+	u8 reg_addr = (srid == SR1) ? R_VDD1_SR_CONTROL : R_VDD2_SR_CONTROL;
+	return vc_send_command(R_SRI2C_SLAVE_ADDR, reg_addr, target_vsel,
+			COUNT_TIMEOUT_TWL4030_VCBYPASS);
+}
+#endif			/* ifdef CONFIG_OMAP_VC_BYPASS_UPDATE */
+
+/*********************** Voltage Controller functions *************************/
+
+/**
+ * @brief vc_send_command - The actual command transmission using
+ * Voltage controller on I2C4
+ *
+ * @param slave_addr - what is the PMIC slave address
+ * @param reg_addr  - what is the register address I should be using?
+ * @param data - what value do you want to write here?
+ * @param timeout_us timeout in uSeconds.
+ *
+ * @return 0 if all ok, else error value
+ */
+int vc_send_command(u8 slave_addr, u8 reg_addr, u8 data, u16 timeout_us)
+{
+	u32 value;
+	/* time to wait =
+	 * timeout_us/10 -> each udelay event
+	 * 1 udelay event every 50 iteration, assuming
+	 * each iteration is instaneous,
+	 * count = (timeout_us/10) * 50 or timeout_us * 5
+	 */
+	u32 count = timeout_us * 5;
+
+	value = (data << OMAP3430_DATA_SHIFT) |
+	    (reg_addr << OMAP3430_REGADDR_SHIFT) |
+	    (slave_addr << OMAP3430_SLAVEADDR_SHIFT);
+
+	prm_write_mod_reg(value, OMAP3430_GR_MOD,
+			  OMAP3_PRM_VC_BYPASS_VAL_OFFSET);
+
+	value = prm_set_mod_reg_bits(OMAP3430_VALID, OMAP3430_GR_MOD,
+				     OMAP3_PRM_VC_BYPASS_VAL_OFFSET);
+	/*
+	 * Do continous 50 checks then follow with a 10usec delay,
+	 * then check again
+	 */
+	do {
+		value = prm_read_mod_reg(OMAP3430_GR_MOD,
+					 OMAP3_PRM_VC_BYPASS_VAL_OFFSET)
+		    & OMAP3430_VALID;
+		/* should i wait? */
+		if (value && (count % 50))
+			udelay(10);
+		count--;
+	} while (value && count);
+	if (!count) {
+		pr_err("VC:Command Timedout! slave_addr=0x%02X,"
+		       "reg=0x%02X, value=0x%02X", slave_addr, reg_addr, data);
+		return -ETIMEDOUT;
+	}
+	return 0;
+}
+EXPORT_SYMBOL(vc_send_command);
+
+/**
+ * @brief sr_vc_bypass - setup voltage using VC Bypass technique
+ *
+ * @param target_opp - target opp to go to
+ * @param current_opp  - current opp
+ * @param target_vsel  - which voltage to go to?
+ * @param current_vsel  - current voltage
+ *
+ * @return -success or failure
+ */
+#ifdef CONFIG_OMAP_VC_BYPASS_UPDATE
+static int sr_vc_bypass(struct omap_sr *sr,
+			u32 target_opp_no, u8 target_vsel, u8 current_vsel)
+{
+	int ret = 0;
+	struct omap_sr_vp *vp = &sr->vp;
+	u32 vc_cmd_val_offs;
+	u32 vpconfig_value;
+
+	vc_cmd_val_offs =
+	    (sr->srid ==
+	     SR1) ? OMAP3_PRM_VC_CMD_VAL_0_OFFSET :
+	    OMAP3_PRM_VC_CMD_VAL_1_OFFSET;
+
+	vpconfig_value = vp->vpconfig_value;
+	vpconfig_value |= ((target_opp_no < 3) ? SR_ERRGAIN_LOWOP :
+			   SR_ERRGAIN_HIGHOPP) << OMAP3430_ERRORGAIN_SHIFT;
+	vpconfig_value |= target_vsel << OMAP3430_INITVOLTAGE_SHIFT;
+	prm_write_mod_reg(vpconfig_value, OMAP3430_GR_MOD,
+			  vp->prm_vpx_config_offset);
+
+	prm_rmw_mod_reg_bits(OMAP3430_VC_CMD_ON_MASK,
+			     (target_vsel << OMAP3430_VC_CMD_ON_SHIFT),
+			     OMAP3430_GR_MOD, vc_cmd_val_offs);
+
+	/*
+	 * Various PMIC might need a set of commands
+	 * provide hooks for specific PMICs to implement
+	 */
+	ret = omap_pmic_voltage_cmds(sr->srid, target_vsel);
+
+	/* delay based on pmic */
+	if (!ret)
+		udelay(omap_pmic_voltage_ramp_delay(target_vsel, current_vsel));
+
+	WARN_ON(ret);
+
+	return ret;
+}
+#endif			/* ifdef CONFIG_OMAP_VC_BYPASS_UPDATE */
+
+/********************* SR Private functions ***************************/
+
+/**
+ * @brief sr_write_reg - write to Smart Reflex Register
+ *
+ * @param sr  - pointer to SR structure
+ * @param offset - SR reg offset to write to
+ * @param value - value to write with
+ */
+static inline void sr_write_reg(struct omap_sr *sr, unsigned offset, u32 value)
+{
+	__raw_writel(value, SR_REGADDR(offset));
+}
+
+/**
+ * @brief sr_modify_reg - Modify a register and write a new value to a field
+ *
+ * @param sr -pointer to SR structure
+ * @param offset -register offset
+ * @param mask -mask to clear out
+ * @param value -value to write there
+ */
+static inline void sr_modify_reg(struct omap_sr *sr, unsigned offset, u32 mask,
+				 u32 value)
+{
+	u32 reg_val;
+
+	reg_val = __raw_readl(SR_REGADDR(offset));
+	reg_val &= ~mask;
+	reg_val |= value;
+
+	__raw_writel(reg_val, SR_REGADDR(offset));
+}
+
+/**
+ * @brief sr_read_reg - read a SR register
+ *
+ * @param sr - pointer to SR structure
+ * @param offset - register offset
+ *
+ * @return value in that register
+ */
+static inline u32 sr_read_reg(struct omap_sr *sr, unsigned offset)
+{
+	return __raw_readl(SR_REGADDR(offset));
+}
+
+/**
+ * @brief sr_vplimito_value -return the timeout value based on sysclk
+ *		and desired timeout uSec
+ *
+ * @param sys_clk_speed - internal sysclk freq in hz
+ * @param timeout_us - timeout in uSec
+ *
+ * @return timeout value to use in VPLIMITTO:TIMEOUT reg
+ */
+static inline u32 sr_vplimito_value(u32 sys_clk_speed, u16 timeout_us)
+{
+	u32 timeout_val;
+	/* prevent round off errors, we will divide by 10 later */
+	timeout_val = (sys_clk_speed / 100000);
+	timeout_val *= timeout_us;
+	timeout_val /= 10;
+	return timeout_val;
+}
+
+/**
+ * @brief sr_clk_enable - SR clock enable
+ *
+ * @param sr - Structure to SR structure
+ *
+ * @return - result
+ */
+static int sr_clk_enable(struct omap_sr *sr)
+{
+	if (clk_enable(sr->iclk) != 0) {
+		pr_crit("SR:Could not enable %s for [%d]\n",
+		       sr->iclk->name, sr->srid);
+		return -EINVAL;
+	}
+	if (clk_enable(sr->fclk) != 0) {
+		pr_crit("SR:Could not enable %s for [%d]\n",
+		       sr->fclk->name, sr->srid);
+		clk_disable(sr->iclk);
+		return -EINVAL;
+	}
+	sr_modify_reg(sr, ERRCONFIG,
+		      SR_CLKACTIVITY_MASK | ERRCONFIG_INTERRUPT_STATUS_MASK,
+		      SR_CLKACTIVITY_IOFF_FON);
+	sr->is_sr_reset = 0;
+
+	return 0;
+}
+
+/**
+ * @brief sr_clk_disable - SR func clock disable
+ *
+ * @param sr - pointer to SR structure
+ */
+static void sr_clk_disable(struct omap_sr *sr)
+{
+	/* set fclk, iclk- idle */
+	sr_modify_reg(sr, ERRCONFIG,
+		      SR_CLKACTIVITY_MASK | ERRCONFIG_INTERRUPT_STATUS_MASK,
+		      SR_CLKACTIVITY_IOFF_FOFF);
+
+	clk_disable(sr->fclk);
+	clk_disable(sr->iclk);
+	sr->is_sr_reset = 1;
+}
+
+/****************** Voltage processor functions ***************************/
+
+/**
+ * @brief sr_vp_clear_vptransdone - clear vptrans_done event
+ *
+ * @param sr - sr pointer
+ *
+ * @return 0 if cleared ok, else 1 if timedout!
+ */
+static int sr_vp_clear_vptransdone(struct omap_sr *sr)
+{
+	struct omap_sr_vp *vp = &sr->vp;
+	u32 irqstat;
+	u32 count = COUNT_TIMEOUT_TRANSDONE_CLR;
+	do {
+		prm_write_mod_reg(vp->irqmask_trans_done, OCP_MOD,
+				  OMAP3_PRM_IRQSTATUS_MPU_OFFSET);
+		irqstat = prm_read_mod_reg(OCP_MOD,
+					   OMAP3_PRM_IRQSTATUS_MPU_OFFSET) &
+		    vp->irqmask_trans_done;
+		if (irqstat)
+			udelay(1);
+		count--;
+	} while (count && irqstat);
+	if (!count) {
+		pr_crit("SR:VPTransdone[%d]:Timedout\n", sr->srid);
+		return -ETIMEDOUT;
+	}
+	return 0;
+}
+
+/**
+ * @brief sr_vp_forceupdate - do a forceupdate method
+ *		to update the voltage level
+ *
+ * @param sr - pointer to sr structure
+ * @param target_opp_no - targetted opp number
+ * @param target_vsel - targetted voltage level
+ * @param current_vsel - current voltage level
+ *
+ * @return 0 if all worked out, else 1
+ */
+#ifndef CONFIG_OMAP_VC_BYPASS_UPDATE
+static int sr_vp_forceupdate(struct omap_sr *sr, u32 target_opp_no,
+			     u8 target_vsel, u8 current_vsel)
+{
+	u32 count;
+	u32 irqstat;
+	u32 vpconfig_value;
+	u32 retry_counter = COUNT_RETRY_SMPSNOACK;
+
+	struct omap_sr_vp *vp = &sr->vp;
+
+retry_forceupdate:
+	/* First clear any pending events in the system */
+	if (sr_vp_clear_vptransdone(sr)) {
+		pr_crit("SR:forceupdate-transdone1[%d]:timedout\n", sr->srid);
+		return -ETIMEDOUT;
+	}
+
+	vpconfig_value = vp->vpconfig_value;
+	vpconfig_value |= ((target_opp_no < 3) ? SR_ERRGAIN_LOWOP :
+			   SR_ERRGAIN_HIGHOPP) << OMAP3430_ERRORGAIN_SHIFT;
+	vpconfig_value |= target_vsel << OMAP3430_INITVOLTAGE_SHIFT;
+
+	prm_write_mod_reg(vpconfig_value, OMAP3430_GR_MOD,
+			  vp->prm_vpx_config_offset);
+
+	/* Trigger initVDD value copy to voltage processor */
+	prm_set_mod_reg_bits(OMAP3430_INITVDD, OMAP3430_GR_MOD,
+			     vp->prm_vpx_config_offset);
+
+	/* Force update of voltage */
+	prm_set_mod_reg_bits(OMAP3430_FORCEUPDATE, OMAP3430_GR_MOD,
+			     vp->prm_vpx_config_offset);
+
+	/* Clear initVDD copy trigger bit */
+	prm_clear_mod_reg_bits(OMAP3430_INITVDD, OMAP3430_GR_MOD,
+			       vp->prm_vpx_config_offset);
+	/* Clear force bit */
+	prm_clear_mod_reg_bits(OMAP3430_FORCEUPDATE, OMAP3430_GR_MOD,
+			       vp->prm_vpx_config_offset);
+
+	/* Now wait for the i2c transactions to complete */
+	count = COUNT_TIMEOUT_TRANSDONE_SET;
+	irqstat = 0;
+	do {
+		irqstat = prm_read_mod_reg(OCP_MOD,
+					   OMAP3_PRM_IRQSTATUS_MPU_OFFSET) &
+		    vp->irqmask_trans_done;
+		if (!irqstat)
+			udelay(1);
+		count--;
+	} while (count && !irqstat);
+	if (!count) {
+		irqstat = prm_read_mod_reg(OCP_MOD,
+					   OMAP3_PRM_IRQSTATUS_MPU_OFFSET);
+		if (irqstat & vp->irqmask_smps_noack) {
+			WARN(irqstat, "SMPS NO ACK DETECTED[0x%08X]!!"
+					"ATTEMPTING RECOVERY [%d left]\n",
+					irqstat, retry_counter);
+			prm_write_mod_reg(irqstat, OCP_MOD,
+					   OMAP3_PRM_IRQSTATUS_MPU_OFFSET);
+			retry_counter--;
+			if (retry_counter)
+				goto retry_forceupdate;
+		}
+		pr_crit("SR:forceupdate-transdone[%d]:timedout-"
+		       "irqstat=0x%08X\n", sr->srid, irqstat);
+		BUG();
+		return -ETIMEDOUT;
+	}
+
+	/*
+	 * Now we wait for voltage to rise on PMIC
+	 */
+	udelay(omap_pmic_voltage_ramp_delay(target_vsel, current_vsel));
+
+	/* clear that event */
+	if (sr_vp_clear_vptransdone(sr)) {
+		pr_crit("SR:forceupdate-transdone2[%d]:timedout\n", sr->srid);
+		BUG();
+		return -ETIMEDOUT;
+	}
+	return 0;
+}
+#endif		/* ifndef CONFIG_OMAP_VC_BYPASS_UPDATE */
+
+/**
+ * @brief sr_vp_enable - enable VP enable code
+ *
+ * @param sr
+ */
+static int sr_vp_enable(struct omap_sr *sr, u32 target_opp_no)
+{
+	u32 vpconfig_value;
+	struct omap_sr_vp *vp = &sr->vp;
+
+	/* Disable VP */
+	prm_clear_mod_reg_bits(vp->vpenable_mask, OMAP3430_GR_MOD,
+			       vp->prm_vpx_config_offset);
+	/* Clear INITVDD */
+	prm_clear_mod_reg_bits(OMAP3430_INITVDD, OMAP3430_GR_MOD,
+			       vp->prm_vpx_config_offset);
+
+	vpconfig_value = vp->vpconfig_value;
+	vpconfig_value |= ((sr->srid == SR1) ? mpu_opps[target_opp_no].vsel :
+			   l3_opps[target_opp_no].vsel) <<
+	    OMAP3430_INITVOLTAGE_SHIFT;
+	vpconfig_value |=
+	    ((target_opp_no < 3) ? SR_ERRGAIN_LOWOP : SR_ERRGAIN_HIGHOPP) <<
+	    OMAP3430_ERRORGAIN_SHIFT;
+
+	prm_write_mod_reg(vpconfig_value, OMAP3430_GR_MOD,
+			  vp->prm_vpx_config_offset);
+
+	prm_write_mod_reg(vp->vpstepmin_value, OMAP3430_GR_MOD,
+			  vp->prm_vpx_stepmin_offset);
+	prm_write_mod_reg(vp->vpstepmax_value, OMAP3430_GR_MOD,
+			  vp->prm_vpx_stepmax_offset);
+	prm_write_mod_reg(vp->vplimito_value, OMAP3430_GR_MOD,
+			  vp->prm_vpx_limito_offset);
+
+	/* write1 to latch */
+	prm_set_mod_reg_bits(OMAP3430_INITVDD, OMAP3430_GR_MOD,
+			     vp->prm_vpx_config_offset);
+	/* write2 clear */
+	prm_clear_mod_reg_bits(OMAP3430_INITVDD, OMAP3430_GR_MOD,
+			       vp->prm_vpx_config_offset);
+	/* Enable VP */
+	prm_set_mod_reg_bits(vp->vpenable_mask, OMAP3430_GR_MOD,
+			     vp->prm_vpx_config_offset);
+	return 0;
+}
+
+/**
+ * @brief sr_vp_disable - disbale Voltage processor
+ *
+ * @param sr - sr structure
+ *
+ * @return 0 if all ok, else return -ETIMEDOUT
+ */
+static int sr_vp_disable(struct omap_sr *sr)
+{
+	int count;
+	u32 v;
+	struct omap_sr_vp *vp = &sr->vp;
+
+	v = prm_read_mod_reg(OMAP3430_GR_MOD,
+			     vp->prm_vpx_config_offset) & vp->vpenable_mask;
+	/* Am i already disabled? */
+	if (!v) {
+		pr_info("SR[%d] attempt to disable VP when already disabled!\n",
+			sr->srid);
+		return 0;
+	}
+
+	/* Disable VP */
+	prm_clear_mod_reg_bits(vp->vpenable_mask, OMAP3430_GR_MOD,
+			       vp->prm_vpx_config_offset);
+
+	/* Wait for vp to get idle - clear any events pending */
+	count = COUNT_TIMEOUT_MCUDISACK;
+	do {
+		v = prm_read_mod_reg(OMAP3430_GR_MOD,
+				     vp->prm_vpx_status_offset) &
+		    PRM_VP_STATUS_VPINIDLE;
+		if (!v)
+			udelay(1);
+		count--;
+	} while (count && !v);
+	if (unlikely(!count)) {
+		v = prm_read_mod_reg(OCP_MOD, OMAP3_PRM_IRQSTATUS_MPU_OFFSET);
+		pr_warning("SR:vpdisable-vpinidle[%d][opp=%d]:timedout-"
+				"irqstat=0x%08X\n", sr->srid,
+				sr->req_opp_no, v);
+		return -ETIMEDOUT;
+	}
+	return 0;
+}
+
+/**
+ * @brief sr_vp_configure - configure the basic SR structure
+ *
+ * @param sr - pointer to SR structure
+ */
+static void sr_vp_configure(struct omap_sr *sr)
+{
+	u32 target_opp_no;
+	u32 target_vsel;
+	u32 prm_vpx_voltage;
+
+	if (sr->srid == SR1) {
+		target_opp_no = mpu_opps[resource_get_level("vdd1_opp")].opp_id;
+		target_vsel = mpu_opps[resource_get_level("vdd1_opp")].vsel;
+		prm_vpx_voltage = prm_read_mod_reg(OMAP3430_GR_MOD,
+					   OMAP3_PRM_VP1_VOLTAGE_OFFSET);
+	} else {
+		target_opp_no = l3_opps[resource_get_level("vdd2_opp")].opp_id;
+		target_vsel = l3_opps[resource_get_level("vdd2_opp")].vsel;
+		prm_vpx_voltage = prm_read_mod_reg(OMAP3430_GR_MOD,
+					   OMAP3_PRM_VP2_VOLTAGE_OFFSET);
+	}
+
+	sr_vp_enable(sr, target_opp_no);
+	if (SR_CHOSEN_VOLTAGE_UPDATE_MECH
+	    (sr, target_opp_no, target_vsel, prm_vpx_voltage))
+		pr_crit("SR[%d] CONFIGURE VP failed!!\n", sr->srid);
+}
+
+/**
+ * @brief sr_vp_reset_voltage - reset the voltages back to DVFS values
+ *
+ * @param srid -SRID
+ *
+ * @return 0 if ok, else result
+ */
+static int sr_vp_reset_voltage(int srid)
+{
+	u32 target_opp_no;
+	u32 target_vsel;
+	u32 prm_vpx_voltage;
+	struct omap_sr *sr;
+	if (srid == SR1) {
+		sr = &sr1;
+		target_opp_no = sr1.req_opp_no;
+		target_vsel = mpu_opps[target_opp_no].vsel;
+		prm_vpx_voltage = prm_read_mod_reg(OMAP3430_GR_MOD,
+					   OMAP3_PRM_VP1_VOLTAGE_OFFSET);
+	} else {
+		sr = &sr2;
+		target_opp_no = sr2.req_opp_no;
+		target_vsel = l3_opps[target_opp_no].vsel;
+		prm_vpx_voltage = prm_read_mod_reg(OMAP3430_GR_MOD,
+					   OMAP3_PRM_VP2_VOLTAGE_OFFSET);
+	}
+	return SR_CHOSEN_VOLTAGE_UPDATE_MECH(sr, target_opp_no,
+					     target_vsel, prm_vpx_voltage);
+
+}
+
+/*********************** SR functions *************************/
+
+/**
+ * @brief sr_enable - enable smart reflex
+ *
+ * @param sr - smartreflex structure we are interest
+ * @param target_opp_no - target opp we want to switch to
+ *
+ * @return 0 if all went right, else return err val
+ */
+static int sr_enable(struct omap_sr *sr, u32 target_opp_no)
+{
+	u32 value;
+
+	if (!sr->is_sr_reset) {
+		pr_info("SR[%d]already enabled\n", sr->srid);
+		return -EINVAL;
+	}
+
+	sr->req_opp_no = target_opp_no;
+
+	value = sr->opp_nvalue[target_opp_no - 1];
+	if (value == 0) {
+		pr_info("SR[%d]:OPP%d doesn't support SmartReflex\n",
+		       sr->srid, target_opp_no);
+		return -EINVAL;
+	}
+
+	sr_clk_enable(sr);
+	/* Start with setting SREnable as 0 */
+	sr_modify_reg(sr, SRCONFIG, SRCONFIG_SRENABLE, 0);
+
+	sr_write_reg(sr, SRCONFIG, sr->sr_config_value);
+
+	sr_write_reg(sr, NVALUERECIPROCAL, value);
+
+	value = sr->sr_errconfig_value |
+	    ((target_opp_no < 3) ? SR_ERRMINLIMIT_LOWOPP :
+	     SR_ERRMINLIMIT_HIGHOPP);
+
+	sr_write_reg(sr, ERRCONFIG, value);
+
+	/* SRCONFIG - enable SR */
+	sr_modify_reg(sr, SRCONFIG, SRCONFIG_SRENABLE, SRCONFIG_SRENABLE);
+
+	return 0;
+}
+
+/**
+ * @brief sr_disable - disable Smart Reflex
+ *
+ * @param sr -  pointer to sr structure of interest
+ *
+ * @return 0 if all went right, else return INVAL/TIMEDOUT
+ */
+int sr_disable(struct omap_sr *sr)
+{
+	int count;
+	u32 stat;
+	u32 value;
+
+	if (sr->is_sr_reset) {
+		pr_info("SR[%d]-disable:already Disabled\n", sr->srid);
+		return -EINVAL;
+	}
+	value = sr_read_reg(sr, SRCONFIG) & SRCONFIG_SRENABLE;
+	if (!value) {
+		pr_info("SR[%d] attempt to disable SR when already disabled!\n",
+			sr->srid);
+		return 0;
+	}
+	value = sr->opp_nvalue[sr->req_opp_no - 1];
+	if (value == 0) {
+		pr_info("SR[%d]-disable:"
+		       "OPP%d doesn't support SmartReflex\n",
+		       sr->srid, sr->req_opp_no);
+		return -EINVAL;
+	}
+	/* Enable the MCUDISACKINST */
+	sr_modify_reg(sr, ERRCONFIG, ERRCONFIG_MCUDISACKINTEN |
+		      ERRCONFIG_INTERRUPT_STATUS_MASK,
+		      ERRCONFIG_MCUDISACKINTEN);
+
+	/* SRCONFIG - disable SR */
+	sr_modify_reg(sr, SRCONFIG, SRCONFIG_SRENABLE, 0);
+
+	/* Disable VPBOUND interrupt and clear any status
+	 * before actually waiting for disack
+	 * should be done after sr is disabled
+	 */
+	sr_modify_reg(sr, ERRCONFIG, ERRCONFIG_VPBOUNDINTEN |
+		      ERRCONFIG_INTERRUPT_STATUS_MASK, ERRCONFIG_VPBOUNDINTST);
+
+	/* Wait for MCUDISACKINTST to be set */
+	count = COUNT_TIMEOUT_MCUDISACK;
+	do {
+		stat = sr_read_reg(sr, ERRCONFIG) & ERRCONFIG_MCUDISACKINTST;
+		if (!stat)
+			udelay(1);
+		count--;
+	} while (count && !stat);
+	/* Clear the event and disable MCUDISACKINST */
+	sr_modify_reg(sr, ERRCONFIG, ERRCONFIG_MCUDISACKINTEN |
+		      ERRCONFIG_INTERRUPT_STATUS_MASK,
+		      ERRCONFIG_MCUDISACKINTST);
+
+	if (!count) {
+		pr_crit("SR[%d]-disable:MCUDIS timedout\n", sr->srid);
+		return -ETIMEDOUT;
+	}
+	sr_clk_disable(sr);
+	return 0;
+}
+
+/**************** Common enable/disable functionality *********************/
+
+/**
+ * @brief srvp_disable - disable SR and VP
+ * These functions are based on h/w timeouts and should ideally not fail.
+ *
+ * @param sr -sr struct
+ *
+ * @return  result
+ */
+static int srvp_disable(struct omap_sr *sr)
+{
+	int ret;
+	/* If we dont have an nvalue, dont bother.. */
+	if (!sr->opp_nvalue[sr->req_opp_no - 1]) {
+		pr_warning("SR[%d]: OPP%d does not support SR to disable\n",
+				sr->srid, sr->req_opp_no);
+		return -EINVAL;
+	}
+	ret = sr_vp_disable(sr);
+	if (unlikely(ret)) {
+		pr_err("SR[%d]: failed to disable vp:%d\n", sr->srid, ret);
+	} else {
+		ret = sr_disable(sr);
+		if (unlikely(ret))
+			pr_err("SR[%d]: failed to disable sr:%d\n",
+			       sr->srid, ret);
+	}
+	/*
+	 * Does not make much sense renabling SR as
+	 * system is going to be in an invalid state
+	 */
+	WARN_ON(ret);
+	return ret;
+}
+
+/**
+ * @brief srvp_enable - enable SR and VP
+ * These functions are based on h/w timeouts and should ideally not fail.
+ *
+ * @param sr -sr struct
+ * @param target_opp -opp to go to
+ *
+ * @return result
+ */
+static int srvp_enable(struct omap_sr *sr, u32 target_opp)
+{
+	int ret;
+	/* If we dont have an nvalue, dont bother.. */
+	if (!sr->opp_nvalue[target_opp - 1]) {
+		pr_warning("SR[%d]: OPP%d does not support SR to enable\n",
+				sr->srid, target_opp);
+		return -EINVAL;
+	}
+	ret = sr_vp_enable(sr, target_opp);
+	if (unlikely(ret)) {
+		pr_err("SR[%d]: failed to enable vp:%d\n", sr->srid, ret);
+	} else {
+		ret = sr_enable(sr, target_opp);
+		/* Attempt to recover */
+		if (unlikely(ret)) {
+			pr_err("SR[%d]: failed to enable sr:%d\n", sr->srid,
+			       ret);
+			/* nothing we can do if vp_disable fails */
+			(void)sr_vp_disable(sr);
+		}
+	}
+	/*
+	 * potentially system in an invalid state - warn..
+	 */
+	WARN_ON(ret);
+	return ret;
+}
+
+/*********************** DVFS Entry POINTS **********************************/
+
+/**
+ * @brief sr_vp_enable_both - enable both vp and sr
+ *
+ * @param target_opp - targetted op
+ * @param current_opp - current opp
+ *
+ * @return 0 if ok, 1 if not ok
+ */
+int sr_vp_enable_both(u32 target_opp, u32 current_opp)
+{
+	struct omap_sr *sr;
+	u32 vdd, target_opp_no;
+	int ret = 0;
+
+	vdd = get_vdd(target_opp);
+	target_opp_no = get_opp_no(target_opp);
+	sr = (vdd == PRCM_VDD1) ? &sr1 : &sr2;
+
+	if (sr->is_autocomp_active && sr->is_sr_reset) {
+		ret = srvp_enable(sr, target_opp_no);
+		if (ret) {
+			pr_err("SR[%d]:enableboth:"
+			       "failed enable SR\n", sr->srid);
+		}
+	}
+	return 0;
+}
+EXPORT_SYMBOL(sr_vp_enable_both);
+
+/**
+ * @brief sr_vp_disable_both - disable both vp and sr
+ *
+ * @param target_opp - targetted opp
+ * @param current_opp - current opp
+ *
+ * @return 0 if ok, 1 if not ok
+ */
+int sr_vp_disable_both(u32 target_opp, u32 current_opp)
+{
+	struct omap_sr *sr;
+	u32 vdd;
+	int ret = 0;
+
+	vdd = get_vdd(target_opp);
+	sr = (vdd == PRCM_VDD1) ? &sr1 : &sr2;
+
+	if (sr->is_autocomp_active && !sr->is_sr_reset) {
+		ret = srvp_disable(sr);
+		if (ret) {
+			pr_err("SR[%d]:disableboth:"
+			       "failed disable SR\n", sr->srid);
+		}
+	}
+
+	return 0;
+
+}
+EXPORT_SYMBOL(sr_vp_disable_both);
+
+/**
+ * @brief sr_voltage_set - setup a voltage requested
+ *
+ * @param target_opp - targetted opp
+ * @param current_opp  - current opp
+ * @param target_vsel - targeted voltage
+ * @param current_vsel - current voltage
+ *
+ * @return  - result of op -0 if ok, else value
+ */
+int sr_voltage_set(u32 target_opp, u32 current_opp,
+		   u8 target_vsel, u8 current_vsel)
+{
+	struct omap_sr *sr;
+	u32 vdd, target_opp_no;
+	int ret;
+
+	vdd = get_vdd(target_opp);
+	target_opp_no = get_opp_no(target_opp);
+	sr = (vdd == PRCM_VDD1) ? &sr1 : &sr2;
+
+	ret =
+	    SR_CHOSEN_VOLTAGE_UPDATE_MECH(sr, target_opp_no, target_vsel,
+					  current_vsel);
+
+	return ret;
+}
+EXPORT_SYMBOL(sr_voltage_set);
+
+/*********************** CPUIDLE ENTRY POINTS *********************************/
+
+/**
+ * @brief disable_smartreflex - disable SmartReflex before WFI
+ *
+ * @param srid SRID
+ */
+void disable_smartreflex(int srid)
+{
+	struct omap_sr *sr = NULL;
+	int ret;
+	u32 current_opp_no;
+
+	sr = (srid == SR1) ? &sr1 : &sr2;
+
+	current_opp_no = (sr->srid == SR1) ?
+			mpu_opps[resource_get_level("vdd1_opp")].opp_id :
+			l3_opps[resource_get_level("vdd2_opp")].opp_id;
+
+
+	if (sr->is_autocomp_active && !sr->is_sr_reset) {
+		sr->req_opp_no = current_opp_no;
+		ret = srvp_disable(sr);
+		if (ret)
+			pr_err("SR[%d]:disable_smartreflex:"
+			       "failed disable SR\n", sr->srid);
+	}
+
+	/* Reset the voltage for current OPP to nominal if SR was enabled */
+	if (sr->is_autocomp_active)
+		sr_vp_reset_voltage(srid);
+}
+EXPORT_SYMBOL(disable_smartreflex);
+
+/**
+ * @brief enable_smartreflex - enable smart reflex after WFI is hit
+ *
+ * @param srid -SR ID to hit
+ */
+void enable_smartreflex(int srid)
+{
+	struct omap_sr *sr;
+	int ret;
+	u32 current_opp_no;
+
+	sr = (srid == SR1) ? &sr1 : &sr2;
+
+	current_opp_no = (sr->srid == SR1) ?
+			mpu_opps[resource_get_level("vdd1_opp")].opp_id :
+			l3_opps[resource_get_level("vdd2_opp")].opp_id;
+	if (sr->is_autocomp_active && sr->is_sr_reset) {
+		ret = srvp_enable(sr, current_opp_no);
+		if (ret)
+			pr_err("SR[%d]:enable_smartreflex:"
+			       "failed enable SR\n", sr->srid);
+	}
+}
+EXPORT_SYMBOL(enable_smartreflex);
+
+/*********************** SYSFS ENTRY POINTS *********************************/
+/**
+ * @brief omap_sr_vdd_autocomp_show - Sysfs entry for showing SR status
+ *
+ */
+static ssize_t omap_sr_vdd_autocomp_show(struct kobject *kobj,
+					 struct kobj_attribute *attr, char *buf)
+{
+	int srid;
+	struct omap_sr *sr;
+	srid = (strcmp(attr->attr.name, "sr_vdd1_autocomp") == 0) ? SR1 : SR2;
+	sr = (srid == SR1) ? &sr1 : &sr2;
+	return sprintf(buf, "%d\n", sr->is_autocomp_active);
+}
+
+/**
+ * @brief omap_sr_vdd_autocomp_store - enable/disable SR
+ *
+ */
+static ssize_t omap_sr_vdd_autocomp_store(struct kobject *kobj,
+					  struct kobj_attribute *attr,
+					  const char *buf, size_t n)
+{
+	unsigned short value;
+	int srid;
+	struct omap_sr *sr;
+	int ret = 0;
+	u32 current_vddopp_no;
+	const char *name;
+
+	name = attr->attr.name;
+
+	srid = (strcmp(name, "sr_vdd1_autocomp") == 0) ? SR1 : SR2;
+	sr = (srid == SR1) ? &sr1 : &sr2;
+	current_vddopp_no = (sr->srid == SR1) ?
+			mpu_opps[resource_get_level("vdd1_opp")].opp_id :
+			l3_opps[resource_get_level("vdd2_opp")].opp_id;
+
+	if (sscanf(buf, "%hu", &value) != 1 || (value > 1)) {
+		pr_err("%s: Invalid value[%d]. Use 0 or 1\n", name, value);
+		return -EINVAL;
+	}
+	if (sr->is_autocomp_active == value) {
+		pr_info("%s: Already set to %d \n", name, value);
+		return n;
+	}
+	/*
+	 * Sanity check-might happen if SR and dvfs/idle paths collide
+	 * but unlikely though..
+	 */
+	if (unlikely(value ^ sr->is_sr_reset)) {
+		pr_warning("%s: Is already set %d Vs %d.\n", name, value,
+				sr->is_sr_reset);
+		return n;
+	}
+
+	if (value)
+		ret = srvp_enable(sr, current_vddopp_no);
+	else {
+		ret = srvp_disable(sr);
+		/* reset the voltage back to nominal */
+		sr_vp_configure(sr);
+	}
+	if (!ret) {
+		sr->is_autocomp_active = value;
+		ret = n;
+	}
+
+	return ret;
+}
+
+static struct kobj_attribute sr_vdd1_autocomp = {
+	.attr = {
+		 .name = __stringify(sr_vdd1_autocomp),
+		 .mode = 0644,
+		 },
+	.show = omap_sr_vdd_autocomp_show,
+	.store = omap_sr_vdd_autocomp_store,
+};
+
+static struct kobj_attribute sr_vdd2_autocomp = {
+	.attr = {
+		 .name = __stringify(sr_vdd2_autocomp),
+		 .mode = 0644,
+		 },
+	.show = omap_sr_vdd_autocomp_show,
+	.store = omap_sr_vdd_autocomp_store,
+};
+
+/*********************** INIT FUNCTIONS *************************************/
+
+/**
+ * @brief srvp_configure - configure smart reflex and VP params
+ *
+ * @param sr  - structure of sr of interest
+ */
+static void __init srvp_configure(struct omap_sr *sr)
+{
+	struct clk *sys_ck;
+	u32 sys_clk_speed;
+	u32 clk_len;
+	u32 senn_mod, senp_mod;
+
+	/* Grab the clock speed */
+	sys_ck = clk_get(NULL, "sys_ck");
+	sys_clk_speed = clk_get_rate(sys_ck);
+	clk_put(sys_ck);
+
+	switch (sys_clk_speed) {
+	case 12000000:
+		clk_len = SRCLKLENGTH_12MHZ_SYSCLK;
+		break;
+	case 13000000:
+		clk_len = SRCLKLENGTH_13MHZ_SYSCLK;
+		break;
+	case 19200000:
+		clk_len = SRCLKLENGTH_19MHZ_SYSCLK;
+		break;
+	case 26000000:
+		clk_len = SRCLKLENGTH_26MHZ_SYSCLK;
+		break;
+	case 38400000:
+		clk_len = SRCLKLENGTH_38MHZ_SYSCLK;
+		break;
+	default:
+		pr_err("SR[%d]:Invalid sysclk value: %d\n", sr->srid,
+		       sys_clk_speed);
+		BUG();
+		return;
+	}
+	/* Configure from the nvalues */
+	if (sr->srid == SR1) {
+#ifndef CONFIG_OMAP_SMARTREFLEX_TESTING_NVALUES
+		senn_mod = (omap_ctrl_readl(OMAP343X_CONTROL_FUSE_SR) &
+			    OMAP343X_SR1_SENNENABLE_MASK) >>
+		    OMAP343X_SR1_SENNENABLE_SHIFT;
+		senp_mod = (omap_ctrl_readl(OMAP343X_CONTROL_FUSE_SR) &
+			    OMAP343X_SR1_SENPENABLE_MASK) >>
+		    OMAP343X_SR1_SENPENABLE_SHIFT;
+
+		sr->opp_nvalue[4] =
+		    omap_ctrl_readl(OMAP343X_CONTROL_FUSE_OPP5_VDD1);
+		sr->opp_nvalue[3] =
+		    omap_ctrl_readl(OMAP343X_CONTROL_FUSE_OPP4_VDD1);
+		sr->opp_nvalue[2] =
+		    omap_ctrl_readl(OMAP343X_CONTROL_FUSE_OPP3_VDD1);
+		sr->opp_nvalue[1] =
+		    omap_ctrl_readl(OMAP343X_CONTROL_FUSE_OPP2_VDD1);
+		sr->opp_nvalue[0] =
+		    omap_ctrl_readl(OMAP343X_CONTROL_FUSE_OPP1_VDD1);
+#else
+		memcpy(&sr->opp_nvalue, &sr1_test_nvalues,
+		       sizeof(sr1_test_nvalues));
+		senn_mod = SR1_N_MOD;
+		senp_mod = SR1_P_MOD;
+#endif			/* ifndef CONFIG_OMAP_SMARTREFLEX_TESTING_NVALUES */
+		sr->sr_errconfig_value = SR1_ERRWEIGHT | SR1_ERRMAXLIMIT;
+		sr->vp.vplimito_value |= sr_vplimito_value(sys_clk_speed,
+				PRM_VP1_VLIMITTO_TIMEOUT_US) <<
+					PRM_VP1_VLIMITTO_TIMEOUT_SHIFT;
+
+	} else {
+#ifndef CONFIG_OMAP_SMARTREFLEX_TESTING_NVALUES
+		senn_mod = (omap_ctrl_readl(OMAP343X_CONTROL_FUSE_SR) &
+			    OMAP343X_SR2_SENNENABLE_MASK) >>
+		    OMAP343X_SR2_SENNENABLE_SHIFT;
+
+		senp_mod = (omap_ctrl_readl(OMAP343X_CONTROL_FUSE_SR) &
+			    OMAP343X_SR2_SENPENABLE_MASK) >>
+		    OMAP343X_SR2_SENPENABLE_SHIFT;
+
+		sr->opp_nvalue[2] =
+		    omap_ctrl_readl(OMAP343X_CONTROL_FUSE_OPP3_VDD2);
+		sr->opp_nvalue[1] =
+		    omap_ctrl_readl(OMAP343X_CONTROL_FUSE_OPP2_VDD2);
+		sr->opp_nvalue[0] =
+		    omap_ctrl_readl(OMAP343X_CONTROL_FUSE_OPP1_VDD2);
+		sr->sr_errconfig_value = SR2_ERRWEIGHT | SR2_ERRMAXLIMIT;
+#else
+		memcpy(&sr->opp_nvalue, &sr2_test_nvalues,
+		       sizeof(sr2_test_nvalues));
+		senn_mod = SR2_N_MOD;
+		senp_mod = SR2_P_MOD;
+#endif			/* ifndef CONFIG_OMAP_SMARTREFLEX_TESTING_NVALUES */
+		sr->vp.vplimito_value |= sr_vplimito_value(sys_clk_speed,
+				PRM_VP2_VLIMITTO_TIMEOUT_US) <<
+					PRM_VP2_VLIMITTO_TIMEOUT_SHIFT;
+	}
+
+	sr->sr_errconfig_value |=
+	    ERRCONFIG_VPBOUNDINTEN | ERRCONFIG_VPBOUNDINTST |
+	    SR_CLKACTIVITY_IOFF_FON;
+
+	sr->sr_config_value =
+	    (clk_len << SRCONFIG_SRCLKLENGTH_SHIFT) | SRCONFIG_ERRGEN_EN
+	    | SRCONFIG_SENENABLE | (senn_mod <<
+				    SRCONFIG_SENNENABLE_SHIFT) |
+	    (senp_mod << SRCONFIG_SENPENABLE_SHIFT) | SRCONFIG_DELAYCTRL;
+
+	/* Set up nominal voltage */
+	sr_vp_configure(sr);
+}
+
+/**
+ * @brief omap_sr_init - SR initialization
+ *
+ * @return  0
+ */
+static int __init omap_sr_init(void)
+{
+	int ret = 0;
+	ret = omap_pmic_srinit();
+	if (ret) {
+		pr_crit("PMIC init failed during SmartReflex initilization."
+				"connectivity issues?: %d\n", ret);
+		return ret;
+	}
+
+#ifdef CONFIG_OMAP_SMARTREFLEX_TESTING_NVALUES
+	pr_err("Warning: This build uses SmartReflex Testing NVALUES!!..\n");
+#endif
+	/* TODO: Extend this support for various PMICs */
+	if (cpu_is_omap34xx()) {
+		sr1.fclk = clk_get(NULL, "sr1_fck");
+		sr1.iclk = clk_get(NULL, "sr_l4_ick");
+		sr2.fclk = clk_get(NULL, "sr2_fck");
+		sr2.iclk = clk_get(NULL, "sr_l4_ick");
+
+		srvp_configure(&sr1);
+		srvp_configure(&sr2);
+
+	} else {
+		pr_warning("SmartReflex is not supported\n");
+		return -ENODEV;
+	}
+
+	pr_info("SmartReflex driver initialized\n");
+
+	ret = sysfs_create_file(power_kobj, &sr_vdd1_autocomp.attr);
+	if (ret)
+		pr_warning("sysfs_create_file failed: %d\n", ret);
+
+	ret = sysfs_create_file(power_kobj, &sr_vdd2_autocomp.attr);
+	if (ret)
+		pr_warning("sysfs_create_file failed: %d\n", ret);
+
+	return 0;
+}
+late_initcall(omap_sr_init);
diff --git a/arch/arm/mach-omap2/smartreflex.h b/arch/arm/mach-omap2/smartreflex.h
new file mode 100644
index 0000000..8efe2e2
--- /dev/null
+++ b/arch/arm/mach-omap2/smartreflex.h
@@ -0,0 +1,249 @@ 
+#ifndef __ARCH_ARM_MACH_OMAP3_SMARTREFLEX_H
+#define __ARCH_ARM_MACH_OMAP3_SMARTREFLEX_H
+/*
+ * linux/arch/arm/mach-omap2/smartreflex.h
+ *
+ * Copyright (C) 2008 Nokia Corporation
+ * Kalle Jokiniemi
+ *
+ * Copyright (C) 2007 Texas Instruments, Inc.
+ * Lesly A M <x0080970@ti.com>
+ *
+ * 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
+ * published by the Free Software Foundation.
+ */
+
+/* SMART REFLEX REG ADDRESS OFFSET */
+#define SRCONFIG		0x00
+#define SRSTATUS		0x04
+#define SENVAL			0x08
+#define SENMIN			0x0C
+#define SENMAX			0x10
+#define SENAVG			0x14
+#define AVGWEIGHT		0x18
+#define NVALUERECIPROCAL	0x1C
+#define SENERROR		0x20
+#define ERRCONFIG		0x24
+
+/* SR Modules */
+#define SR1			1
+#define SR2			2
+
+#define VP1_IRQMASK_TRANSDONE		(0x1 << 15)
+#define VP2_IRQMASK_TRANSDONE		(0x1 << 21)
+
+/* PRM_VP1_CONFIG */
+#define PRM_VP1_CONFIG_ERROROFFSET	(0x00 << 24)
+#define PRM_VP1_CONFIG_ERRORGAIN	(0x18 << 16)
+#define SR_ERRGAIN_LOWOP		(0x0C)
+#define SR_ERRGAIN_HIGHOPP		(0x18)
+#define SR_ERRMINLIMIT_LOWOPP           (0xF4 << 0)
+#define SR_ERRMINLIMIT_HIGHOPP          (0xF9 << 0)
+#define PRM_VP_STATUS_VPINIDLE		(0x1 << 0)
+
+#define PRM_VP1_CONFIG_INITVOLTAGE	(0x30 << 8) /* 1.2 volt */
+#define PRM_VP1_CONFIG_TIMEOUTEN	(0x1 << 3)
+#define PRM_VP1_CONFIG_INITVDD		(0x1 << 2)
+#define PRM_VP1_CONFIG_FORCEUPDATE	(0x1 << 1)
+#define PRM_VP1_CONFIG_VPENABLE		(0x1 << 0)
+
+/* PRM_VP1_VSTEPMIN */
+#define PRM_VP1_VSTEPMIN_SMPSWAITTIMEMIN	(0x03C << 8)
+#define PRM_VP1_VSTEPMIN_VSTEPMIN		(0x01 << 0)
+
+/* PRM_VP1_VSTEPMAX */
+#define PRM_VP1_VSTEPMAX_SMPSWAITTIMEMAX	(0x003C << 8)
+#define PRM_VP1_VSTEPMAX_VSTEPMAX		(0x08 << 0)
+
+/* PRM_VP1_VLIMITTO */
+#define PRM_VP1_VLIMITTO_VDDMAX		(0x44 << 24)
+#define PRM_VP1_VLIMITTO_VDDMIN		(0x14 << 16)
+#define PRM_VP1_VLIMITTO_TIMEOUT_US	(200)
+#define PRM_VP1_VLIMITTO_TIMEOUT_SHIFT	(0)
+
+/* PRM_VP2_CONFIG */
+#define PRM_VP2_CONFIG_ERROROFFSET	(0x00 << 24)
+#define PRM_VP2_CONFIG_ERRORGAIN	(0x18 << 16)
+
+#define PRM_VP2_CONFIG_INITVOLTAGE	(0x30 << 8) /* 1.2 volt */
+#define PRM_VP2_CONFIG_TIMEOUTEN	(0x1 << 3)
+#define PRM_VP2_CONFIG_INITVDD		(0x1 << 2)
+#define PRM_VP2_CONFIG_FORCEUPDATE	(0x1 << 1)
+#define PRM_VP2_CONFIG_VPENABLE		(0x1 << 0)
+
+/* PRM_VP2_VSTEPMIN */
+#define PRM_VP2_VSTEPMIN_SMPSWAITTIMEMIN	(0x03C << 8)
+#define PRM_VP2_VSTEPMIN_VSTEPMIN		(0x01 << 0)
+
+/* PRM_VP2_VSTEPMAX */
+#define PRM_VP2_VSTEPMAX_SMPSWAITTIMEMAX	(0x003C << 8)
+#define PRM_VP2_VSTEPMAX_VSTEPMAX		(0x08 << 0)
+
+/* PRM_VP2_VLIMITTO */
+#define PRM_VP2_VLIMITTO_VDDMAX		(0x42 << 24)
+#define PRM_VP2_VLIMITTO_VDDMIN		(0x18 << 16)
+#define PRM_VP2_VLIMITTO_TIMEOUT_US	(200)
+#define PRM_VP2_VLIMITTO_TIMEOUT_SHIFT	(0)
+
+/* SRCONFIG */
+#define SRCLKLENGTH_12MHZ_SYSCLK	0x3C
+#define SRCLKLENGTH_13MHZ_SYSCLK	0x41
+#define SRCLKLENGTH_19MHZ_SYSCLK	0x60
+#define SRCLKLENGTH_26MHZ_SYSCLK	0x82
+#define SRCLKLENGTH_38MHZ_SYSCLK	0xC0
+
+#define SRCONFIG_SRCLKLENGTH_SHIFT	12
+#define SRCONFIG_SENNENABLE_SHIFT	5
+#define SRCONFIG_SENPENABLE_SHIFT	3
+
+#define SRCONFIG_SRENABLE		(0x01 << 11)
+#define SRCONFIG_SENENABLE		(0x01 << 10)
+#define SRCONFIG_ERRGEN_EN		(0x01 << 9)
+#define SRCONFIG_MINMAXAVG_EN		(0x01 << 8)
+
+#define SRCONFIG_DELAYCTRL		(0x01 << 2)
+#define SRCONFIG_CLKCTRL		(0x00 << 0)
+
+/* NVALUERECIPROCAL */
+#define NVALUERECIPROCAL_SENPGAIN_SHIFT	20
+#define NVALUERECIPROCAL_SENNGAIN_SHIFT	16
+#define NVALUERECIPROCAL_RNSENP_SHIFT	8
+#define NVALUERECIPROCAL_RNSENN_SHIFT	0
+
+/* ERRCONFIG */
+#define SR_CLKACTIVITY_MASK		(0x03 << 20)
+#define SR_ERRWEIGHT_MASK		(0x07 << 16)
+#define SR_ERRMAXLIMIT_MASK		(0xFF << 8)
+#define SR_ERRMINLIMIT_MASK		(0xFF << 0)
+
+#define SR_CLKACTIVITY_IOFF_FOFF	(0x00 << 20)
+#define SR_CLKACTIVITY_IOFF_FON		(0x02 << 20)
+
+#define ERRCONFIG_VPBOUNDINTEN		(0x1 << 31)
+#define ERRCONFIG_MCUDISACKINTEN	(0x1 << 23)
+
+/* Status Bits */
+#define ERRCONFIG_VPBOUNDINTST		(0x1 << 30)
+#define ERRCONFIG_MCUACCUMINTST		(0x1 << 28)
+#define ERRCONFIG_MCUVALIDINTST		(0x1 << 26)
+#define ERRCONFIG_MCUBOUNDINTST		(0x1 << 24)
+#define ERRCONFIG_MCUDISACKINTST	(0x1 << 22)
+
+/* WARNING: Ensure all access to errconfig register skips
+ * clearing intst bits to ensure that we dont clear status
+ * bits unwantedly.. esp vpbound
+ */
+#define ERRCONFIG_INTERRUPT_STATUS_MASK  (ERRCONFIG_VPBOUNDINTST |\
+		ERRCONFIG_MCUACCUMINTST |\
+		ERRCONFIG_MCUVALIDINTST |\
+		ERRCONFIG_MCUBOUNDINTST |\
+		ERRCONFIG_MCUDISACKINTST | (0X1<<19))
+
+#define SR1_ERRWEIGHT			(0x04 << 16)
+#define SR1_ERRMAXLIMIT			(0x02 << 8)
+#define SR1_ERRMINLIMIT			(0xFA << 0)
+
+#define SR2_ERRWEIGHT			(0x04 << 16)
+#define SR2_ERRMAXLIMIT			(0x02 << 8)
+#define SR2_ERRMINLIMIT			(0xFA << 0)
+
+/* T2 SMART REFLEX */
+#define R_SRI2C_SLAVE_ADDR		0x12
+#define R_VDD1_SR_CONTROL		0x00
+#define R_VDD2_SR_CONTROL		0x01
+
+/* VDDs*/
+#define PRCM_VDD1	1
+#define PRCM_VDD2	2
+
+/*
+ * XXX: These should be removed/moved from here once we have a working DVFS
+ * implementation in place
+ */
+#define PHY_TO_OFF_PM_MASTER(p)		(p - 0x36)
+#define PHY_TO_OFF_PM_RECIEVER(p)	(p - 0x5b)
+#define PHY_TO_OFF_PM_INT(p)		(p - 0x2e)
+
+/* Vmode control */
+#define R_DCDC_GLOBAL_CFG		PHY_TO_OFF_PM_RECIEVER(0x61)
+/* R_DCDC_GLOBAL_CFG register, SMARTREFLEX_ENABLE values */
+#define DCDC_GLOBAL_CFG_ENABLE_SRFLX	0x08
+
+
+/* DEVICE ID/DPLL ID/CLOCK ID: bits 28-31 for OMAP type */
+#define OMAP_TYPE_SHIFT		28
+#define OMAP_TYPE_MASK		0xF
+/* OPP ID: bits: 0-4 for OPP number */
+#define OPP_NO_POS		0
+#define OPP_NO_MASK		0x1F
+/* OPP ID: bits: 5-6 for VDD */
+#define VDD_NO_POS		5
+#define VDD_NO_MASK		0x3
+/* Other IDs: bits 20-27 for ID type */
+/* These IDs have bits 25,26,27 as 1 */
+#define OTHER_ID_TYPE_SHIFT		20
+#define OTHER_ID_TYPE_MASK		0xFF
+
+#define OTHER_ID_TYPE(X) ((X & OTHER_ID_TYPE_MASK) << OTHER_ID_TYPE_SHIFT)
+#define ID_OPP_NO(X)	 ((X & OPP_NO_MASK) << OPP_NO_POS)
+#define ID_VDD(X)	 ((X & VDD_NO_MASK) << VDD_NO_POS)
+#define OMAP(X)		 ((X >> OMAP_TYPE_SHIFT) & OMAP_TYPE_MASK)
+#define get_opp_no(X)	 ((X >> OPP_NO_POS) & OPP_NO_MASK)
+#define get_vdd(X)	 ((X >> VDD_NO_POS) & VDD_NO_MASK)
+
+/* XXX: end remove/move */
+
+/* XXX: find more appropriate place for these once DVFS is in place */
+extern u32 current_vdd1_opp;
+extern u32 current_vdd2_opp;
+
+/*
+ * Smartreflex module enable/disable interface.
+ * NOTE: if smartreflex is not enabled from sysfs, these functions will not
+ * do anything.
+ */
+#ifdef CONFIG_OMAP_SMARTREFLEX
+void enable_smartreflex(int srid);
+void disable_smartreflex(int srid);
+int sr_voltage_set(u32 target_opp, u32 current_opp,
+		   u8 target_vsel, u8 current_vsel);
+int sr_vp_disable_both(u32 target_opp, u32 current_opp);
+int sr_vp_enable_both(u32 target_opp, u32 current_opp);
+int vc_send_command(u8 slave_addr, u8 reg_addr, u8 data, u16 timeout_us);
+int omap_pmic_srinit(void);
+u32 omap_pmic_voltage_ramp_delay(u8 target_vsel, u8 current_vsel);
+#ifdef CONFIG_OMAP_VC_BYPASS_UPDATE
+int omap_pmic_voltage_cmds(u8 srid, u8 target_vsel);
+#endif
+#else
+static inline void enable_smartreflex(int srid) {}
+static inline void disable_smartreflex(int srid) {}
+static inline int sr_voltage_set(u32 target_opp, u32 current_opp,
+				   u8 target_vsel, u8 current_vsel)
+{
+	return -EINVAL;
+}
+static inline int sr_vp_disable_both(u32 target_opp, u32 current_opp)
+{
+	return -EINVAL;
+}
+static inline int sr_vp_enable_both(u32 target_opp, u32 current_opp)
+{
+	return -EINVAL;
+}
+static inline int vc_send_command(u8 slave_addr, u8 reg_addr, u8 data,
+		u16 timeout_us)
+{
+	return -EINVAL;
+}
+#ifdef CONFIG_OMAP_VC_BYPASS_UPDATE
+static inline int omap_pmic_voltage_cmds(u8 srid, u8 target_vsel)
+{
+	return -EINVAL;
+}
+};
+#endif
+#endif
+
+#endif
diff --git a/arch/arm/plat-omap/Kconfig b/arch/arm/plat-omap/Kconfig
index 2143db5..30c70d3 100644
--- a/arch/arm/plat-omap/Kconfig
+++ b/arch/arm/plat-omap/Kconfig
@@ -81,9 +81,10 @@  config OMAP_SMARTREFLEX
 	  compensation for VDD1 and VDD2, user must write 1 to
 	  /sys/power/sr_vddX_autocomp, where X is 1 or 2.
 
-config OMAP_SMARTREFLEX_TESTING
-	bool "Smartreflex testing support"
+config OMAP_SMARTREFLEX_TESTING_NVALUES
+	bool "Use SmartReflex Test NVALUES"
 	depends on OMAP_SMARTREFLEX
+	depends on EXPERIMENTAL
 	default n
 	help
 	  Say Y if you want to enable SmartReflex testing with SW hardcoded
@@ -93,7 +94,18 @@  config OMAP_SMARTREFLEX_TESTING
 	  SmartReflex modules are included. Using these hardcoded values set
 	  in software, one can test the SmartReflex features without E-fuse.
 
-	  WARNING: Enabling this option may cause your device to hang!
+	  WARNING:
+	  * Enabling this option may cause your device to hang!
+	  * If you don't know what you are doing, leave this option as n
+
+config OMAP_VC_BYPASS_UPDATE
+	bool "Use VC Bypass method of updating voltage"
+	depends on OMAP_SMARTREFLEX
+	default n
+	help
+	  Say Y if you would like to use VC Bypass method of
+	  update. If this is disabled, the default
+	  VP forceupdate method is used.
 
 config OMAP_RESET_CLOCKS
 	bool "Reset unused clocks during boot"