diff options
Diffstat (limited to 'recipes/linux/linux-omap-2.6.26/omap3evm/0003-ARM-OMAP-SmartReflex-driver.patch')
-rw-r--r-- | recipes/linux/linux-omap-2.6.26/omap3evm/0003-ARM-OMAP-SmartReflex-driver.patch | 1001 |
1 files changed, 1001 insertions, 0 deletions
diff --git a/recipes/linux/linux-omap-2.6.26/omap3evm/0003-ARM-OMAP-SmartReflex-driver.patch b/recipes/linux/linux-omap-2.6.26/omap3evm/0003-ARM-OMAP-SmartReflex-driver.patch new file mode 100644 index 0000000000..40d5790367 --- /dev/null +++ b/recipes/linux/linux-omap-2.6.26/omap3evm/0003-ARM-OMAP-SmartReflex-driver.patch @@ -0,0 +1,1001 @@ +From: Kalle Jokiniemi <ext-kalle.jokiniemi@nokia.com> +To: linux-omap@vger.kernel.org +Cc: Kalle Jokiniemi <ext-kalle.jokiniemi@nokia.com> +Subject: [PATCH 3/3] ARM: OMAP: SmartReflex driver: integration to linux-omap +Date: Fri, 6 Jun 2008 12:49:49 +0300 +Message-Id: <1212745789-13926-3-git-send-email-ext-kalle.jokiniemi@nokia.com> + +- Changed register accesses to use prm_{read,write}_mod_reg and + prm_{set,clear,rmw}_mod_reg_bits() functions instread of + "REG_X = REG_Y" type accesses. + +- Changed direct register clock enables/disables to clockframework calls. + +- replaced cpu-related #ifdefs with if (cpu_is_xxxx()) calls. + +- Added E-fuse support: Use silicon characteristics parameters from E-fuse + +- added smartreflex_disable/enable calls to pm34xx.c suspend function. + +- Added "SmartReflex support" entry into Kconfig under "System type->TI OMAP + Implementations". It depends on ARCH_OMAP34XX and TWL4030_CORE. + +- Added "SmartReflex testing support" Kconfig option for using hard coded + software parameters instead of E-fuse parameters. + +Signed-off-by: Kalle Jokiniemi <ext-kalle.jokiniemi@nokia.com> +--- + arch/arm/mach-omap2/Makefile | 3 + + arch/arm/mach-omap2/pm34xx.c | 9 + + arch/arm/mach-omap2/smartreflex.c | 531 +++++++++++++++++++++++-------------- + arch/arm/mach-omap2/smartreflex.h | 9 +- + arch/arm/plat-omap/Kconfig | 31 +++ + 5 files changed, 385 insertions(+), 198 deletions(-) + +diff --git a/arch/arm/mach-omap2/Makefile b/arch/arm/mach-omap2/Makefile +index 50c6657..f645b6e 100644 +--- a/arch/arm/mach-omap2/Makefile ++++ b/arch/arm/mach-omap2/Makefile +@@ -25,6 +25,9 @@ obj-$(CONFIG_ARCH_OMAP3) += pm34xx.o sleep34xx.o + obj-$(CONFIG_PM_DEBUG) += pm-debug.o + endif + ++# SmartReflex driver ++obj-$(CONFIG_OMAP_SMARTREFLEX) += smartreflex.o ++ + # Clock framework + obj-$(CONFIG_ARCH_OMAP2) += clock24xx.o + obj-$(CONFIG_ARCH_OMAP3) += clock34xx.o +diff --git a/arch/arm/mach-omap2/pm34xx.c b/arch/arm/mach-omap2/pm34xx.c +index 7e775cc..3da4f47 100644 +--- a/arch/arm/mach-omap2/pm34xx.c ++++ b/arch/arm/mach-omap2/pm34xx.c +@@ -36,6 +36,7 @@ + + #include "prm.h" + #include "pm.h" ++#include "smartreflex.h" + + struct power_state { + struct powerdomain *pwrdm; +@@ -256,6 +257,10 @@ static int omap3_pm_suspend(void) + struct power_state *pwrst; + int state, ret = 0; + ++ /* XXX Disable smartreflex before entering suspend */ ++ disable_smartreflex(SR1); ++ disable_smartreflex(SR2); ++ + /* Read current next_pwrsts */ + list_for_each_entry(pwrst, &pwrst_list, node) + pwrst->saved_state = pwrdm_read_next_pwrst(pwrst->pwrdm); +@@ -287,6 +292,10 @@ restore: + printk(KERN_INFO "Successfully put all powerdomains " + "to target state\n"); + ++ /* XXX Enable smartreflex after suspend */ ++ enable_smartreflex(SR1); ++ enable_smartreflex(SR2); ++ + return ret; + } + +diff --git a/arch/arm/mach-omap2/smartreflex.c b/arch/arm/mach-omap2/smartreflex.c +index dae7460..0b10a5d 100644 +--- a/arch/arm/mach-omap2/smartreflex.c ++++ b/arch/arm/mach-omap2/smartreflex.c +@@ -3,6 +3,9 @@ + * + * OMAP34XX SmartReflex Voltage Control + * ++ * Copyright (C) 2008 Nokia Corporation ++ * Kalle Jokiniemi ++ * + * Copyright (C) 2007 Texas Instruments, Inc. + * Lesly A M <x0080970@ti.com> + * +@@ -20,13 +23,16 @@ + #include <linux/err.h> + #include <linux/clk.h> + #include <linux/sysfs.h> +- +-#include <asm/arch/prcm.h> +-#include <asm/arch/power_companion.h> ++#include <linux/kobject.h> ++#include <linux/i2c/twl4030.h> + #include <linux/io.h> + +-#include "prcm-regs.h" ++#include <asm/arch/omap34xx.h> ++#include <asm/arch/control.h> ++ ++#include "prm.h" + #include "smartreflex.h" ++#include "prm-regbits-34xx.h" + + + /* #define DEBUG_SR 1 */ +@@ -37,11 +43,16 @@ + # define DPRINTK(fmt, args...) + #endif + ++/* XXX: These should be relocated where-ever the OPP implementation will be */ ++u32 current_vdd1_opp; ++u32 current_vdd2_opp; ++ + struct omap_sr{ + int srid; + int is_sr_reset; + int is_autocomp_active; + struct clk *fck; ++ u32 clk_length; + u32 req_opp_no; + u32 opp1_nvalue, opp2_nvalue, opp3_nvalue, opp4_nvalue, opp5_nvalue; + u32 senp_mod, senn_mod; +@@ -53,6 +64,7 @@ static struct omap_sr sr1 = { + .srid = SR1, + .is_sr_reset = 1, + .is_autocomp_active = 0, ++ .clk_length = 0, + .srbase_addr = OMAP34XX_SR1_BASE, + }; + +@@ -60,6 +72,7 @@ static struct omap_sr sr2 = { + .srid = SR2, + .is_sr_reset = 1, + .is_autocomp_active = 0, ++ .clk_length = 0, + .srbase_addr = OMAP34XX_SR2_BASE, + }; + +@@ -85,8 +98,6 @@ static inline u32 sr_read_reg(struct omap_sr *sr, int offset) + return omap_readl(sr->srbase_addr + offset); + } + +- +-#ifndef USE_EFUSE_VALUES + static void cal_reciprocal(u32 sensor, u32 *sengain, u32 *rnsen) + { + u32 gn, rn, mul; +@@ -100,7 +111,21 @@ static void cal_reciprocal(u32 sensor, u32 *sengain, u32 *rnsen) + } + } + } +-#endif ++ ++static void sr_clk_get(struct omap_sr *sr) ++{ ++ if (sr->srid == SR1) { ++ sr->fck = clk_get(NULL, "sr1_fck"); ++ if (IS_ERR(sr->fck)) ++ printk(KERN_ERR "Could not get sr1_fck\n"); ++ ++ } else if (sr->srid == SR2) { ++ sr->fck = clk_get(NULL, "sr2_fck"); ++ if (IS_ERR(sr->fck)) ++ printk(KERN_ERR "Could not get sr2_fck\n"); ++ ++ } ++} + + static int sr_clk_enable(struct omap_sr *sr) + { +@@ -131,22 +156,86 @@ static int sr_clk_disable(struct omap_sr *sr) + return 0; + } + +-static void sr_set_nvalues(struct omap_sr *sr) ++static void sr_set_clk_length(struct omap_sr *sr) ++{ ++ struct clk *osc_sys_ck; ++ u32 sys_clk = 0; ++ ++ osc_sys_ck = clk_get(NULL, "osc_sys_ck"); ++ sys_clk = clk_get_rate(osc_sys_ck); ++ clk_put(osc_sys_ck); ++ ++ switch (sys_clk) { ++ case 12000000: ++ sr->clk_length = SRCLKLENGTH_12MHZ_SYSCLK; ++ break; ++ case 13000000: ++ sr->clk_length = SRCLKLENGTH_13MHZ_SYSCLK; ++ break; ++ case 19200000: ++ sr->clk_length = SRCLKLENGTH_19MHZ_SYSCLK; ++ break; ++ case 26000000: ++ sr->clk_length = SRCLKLENGTH_26MHZ_SYSCLK; ++ break; ++ case 38400000: ++ sr->clk_length = SRCLKLENGTH_38MHZ_SYSCLK; ++ break; ++ default : ++ printk(KERN_ERR "Invalid sysclk value: %d\n", sys_clk); ++ break; ++ } ++} ++ ++static void sr_set_efuse_nvalues(struct omap_sr *sr) ++{ ++ if (sr->srid == SR1) { ++ sr->senn_mod = (omap_ctrl_readl(OMAP343X_CONTROL_FUSE_SR) & ++ OMAP343X_SR1_SENNENABLE_MASK) >> ++ OMAP343X_SR1_SENNENABLE_SHIFT; ++ ++ sr->senp_mod = (omap_ctrl_readl(OMAP343X_CONTROL_FUSE_SR) & ++ OMAP343X_SR1_SENPENABLE_MASK) >> ++ OMAP343X_SR1_SENPENABLE_SHIFT; ++ ++ sr->opp5_nvalue = omap_ctrl_readl( ++ OMAP343X_CONTROL_FUSE_OPP5_VDD1); ++ sr->opp4_nvalue = omap_ctrl_readl( ++ OMAP343X_CONTROL_FUSE_OPP4_VDD1); ++ sr->opp3_nvalue = omap_ctrl_readl( ++ OMAP343X_CONTROL_FUSE_OPP3_VDD1); ++ sr->opp2_nvalue = omap_ctrl_readl( ++ OMAP343X_CONTROL_FUSE_OPP2_VDD1); ++ sr->opp1_nvalue = omap_ctrl_readl( ++ OMAP343X_CONTROL_FUSE_OPP1_VDD1); ++ } else if (sr->srid == SR2) { ++ sr->senn_mod = (omap_ctrl_readl(OMAP343X_CONTROL_FUSE_SR) & ++ OMAP343X_SR2_SENNENABLE_MASK) >> ++ OMAP343X_SR2_SENNENABLE_SHIFT; ++ ++ sr->senp_mod = (omap_ctrl_readl(OMAP343X_CONTROL_FUSE_SR) & ++ OMAP343X_SR2_SENPENABLE_MASK) >> ++ OMAP343X_SR2_SENPENABLE_SHIFT; ++ ++ sr->opp3_nvalue = omap_ctrl_readl( ++ OMAP343X_CONTROL_FUSE_OPP3_VDD2); ++ sr->opp2_nvalue = omap_ctrl_readl( ++ OMAP343X_CONTROL_FUSE_OPP2_VDD2); ++ sr->opp1_nvalue = omap_ctrl_readl( ++ OMAP343X_CONTROL_FUSE_OPP1_VDD2); ++ } ++} ++ ++/* Hard coded nvalues for testing purposes, may cause device to hang! */ ++static void sr_set_testing_nvalues(struct omap_sr *sr) + { +-#ifdef USE_EFUSE_VALUES +- u32 n1, n2; +-#else + u32 senpval, sennval; + u32 senpgain, senngain; + u32 rnsenp, rnsenn; +-#endif + + if (sr->srid == SR1) { +-#ifdef USE_EFUSE_VALUES +- /* Read values for VDD1 from EFUSE */ +-#else +- /* since E-Fuse Values are not available, calculating the +- * reciprocal of the SenN and SenP values for SR1 ++ /* Calculating the reciprocal of the SenN and SenP values ++ * for SR1 + */ + sr->senp_mod = 0x03; /* SenN-M5 enabled */ + sr->senn_mod = 0x03; +@@ -216,15 +305,16 @@ static void sr_set_nvalues(struct omap_sr *sr) + (rnsenp << NVALUERECIPROCAL_RNSENP_SHIFT) | + (rnsenn << NVALUERECIPROCAL_RNSENN_SHIFT)); + ++ /* XXX The clocks are enabled in the startup and NVALUE is ++ * set also there. Disabling this for now, but this could ++ * be related to dynamic sleep during boot */ ++#if 0 + sr_clk_enable(sr); + sr_write_reg(sr, NVALUERECIPROCAL, sr->opp3_nvalue); + sr_clk_disable(sr); +- + #endif ++ + } else if (sr->srid == SR2) { +-#ifdef USE_EFUSE_VALUES +- /* Read values for VDD2 from EFUSE */ +-#else + /* since E-Fuse Values are not available, calculating the + * reciprocal of the SenN and SenP values for SR2 + */ +@@ -269,134 +359,163 @@ static void sr_set_nvalues(struct omap_sr *sr) + (senngain << NVALUERECIPROCAL_SENNGAIN_SHIFT) | + (rnsenp << NVALUERECIPROCAL_RNSENP_SHIFT) | + (rnsenn << NVALUERECIPROCAL_RNSENN_SHIFT)); +- +-#endif + } + + } + ++static void sr_set_nvalues(struct omap_sr *sr) ++{ ++ if (SR_TESTING_NVALUES) ++ sr_set_testing_nvalues(sr); ++ else ++ sr_set_efuse_nvalues(sr); ++} ++ + static void sr_configure_vp(int srid) + { + u32 vpconfig; + + if (srid == SR1) { + vpconfig = PRM_VP1_CONFIG_ERROROFFSET | PRM_VP1_CONFIG_ERRORGAIN +- | PRM_VP1_CONFIG_INITVOLTAGE | PRM_VP1_CONFIG_TIMEOUTEN; +- +- PRM_VP1_CONFIG = vpconfig; +- PRM_VP1_VSTEPMIN = PRM_VP1_VSTEPMIN_SMPSWAITTIMEMIN | +- PRM_VP1_VSTEPMIN_VSTEPMIN; +- +- PRM_VP1_VSTEPMAX = PRM_VP1_VSTEPMAX_SMPSWAITTIMEMAX | +- PRM_VP1_VSTEPMAX_VSTEPMAX; +- +- PRM_VP1_VLIMITTO = PRM_VP1_VLIMITTO_VDDMAX | +- PRM_VP1_VLIMITTO_VDDMIN | PRM_VP1_VLIMITTO_TIMEOUT; +- +- PRM_VP1_CONFIG |= PRM_VP1_CONFIG_INITVDD; +- PRM_VP1_CONFIG &= ~PRM_VP1_CONFIG_INITVDD; ++ | PRM_VP1_CONFIG_INITVOLTAGE ++ | PRM_VP1_CONFIG_TIMEOUTEN; ++ ++ prm_write_mod_reg(vpconfig, OMAP3430_GR_MOD, ++ OMAP3_PRM_VP1_CONFIG_OFFSET); ++ prm_write_mod_reg(PRM_VP1_VSTEPMIN_SMPSWAITTIMEMIN | ++ PRM_VP1_VSTEPMIN_VSTEPMIN, ++ OMAP3430_GR_MOD, ++ OMAP3_PRM_VP1_VSTEPMIN_OFFSET); ++ ++ prm_write_mod_reg(PRM_VP1_VSTEPMAX_SMPSWAITTIMEMAX | ++ PRM_VP1_VSTEPMAX_VSTEPMAX, ++ OMAP3430_GR_MOD, ++ OMAP3_PRM_VP1_VSTEPMAX_OFFSET); ++ ++ prm_write_mod_reg(PRM_VP1_VLIMITTO_VDDMAX | ++ PRM_VP1_VLIMITTO_VDDMIN | ++ PRM_VP1_VLIMITTO_TIMEOUT, ++ OMAP3430_GR_MOD, ++ OMAP3_PRM_VP1_VLIMITTO_OFFSET); ++ ++ /* Trigger initVDD value copy to voltage processor */ ++ prm_set_mod_reg_bits(PRM_VP1_CONFIG_INITVDD, OMAP3430_GR_MOD, ++ OMAP3_PRM_VP1_CONFIG_OFFSET); ++ /* Clear initVDD copy trigger bit */ ++ prm_clear_mod_reg_bits(PRM_VP1_CONFIG_INITVDD, OMAP3430_GR_MOD, ++ OMAP3_PRM_VP1_CONFIG_OFFSET); + + } else if (srid == SR2) { + vpconfig = PRM_VP2_CONFIG_ERROROFFSET | PRM_VP2_CONFIG_ERRORGAIN +- | PRM_VP2_CONFIG_INITVOLTAGE | PRM_VP2_CONFIG_TIMEOUTEN; +- +- PRM_VP2_CONFIG = vpconfig; +- PRM_VP2_VSTEPMIN = PRM_VP2_VSTEPMIN_SMPSWAITTIMEMIN | +- PRM_VP2_VSTEPMIN_VSTEPMIN; +- +- PRM_VP2_VSTEPMAX = PRM_VP2_VSTEPMAX_SMPSWAITTIMEMAX | +- PRM_VP2_VSTEPMAX_VSTEPMAX; +- +- PRM_VP2_VLIMITTO = PRM_VP2_VLIMITTO_VDDMAX | +- PRM_VP2_VLIMITTO_VDDMIN | PRM_VP2_VLIMITTO_TIMEOUT; +- +- PRM_VP2_CONFIG |= PRM_VP2_CONFIG_INITVDD; +- PRM_VP2_CONFIG &= ~PRM_VP2_CONFIG_INITVDD; ++ | PRM_VP2_CONFIG_INITVOLTAGE ++ | PRM_VP2_CONFIG_TIMEOUTEN; ++ ++ prm_write_mod_reg(vpconfig, OMAP3430_GR_MOD, ++ OMAP3_PRM_VP2_CONFIG_OFFSET); ++ prm_write_mod_reg(PRM_VP2_VSTEPMIN_SMPSWAITTIMEMIN | ++ PRM_VP2_VSTEPMIN_VSTEPMIN, ++ OMAP3430_GR_MOD, ++ OMAP3_PRM_VP2_VSTEPMIN_OFFSET); ++ ++ prm_write_mod_reg(PRM_VP2_VSTEPMAX_SMPSWAITTIMEMAX | ++ PRM_VP2_VSTEPMAX_VSTEPMAX, ++ OMAP3430_GR_MOD, ++ OMAP3_PRM_VP2_VSTEPMAX_OFFSET); ++ ++ prm_write_mod_reg(PRM_VP2_VLIMITTO_VDDMAX | ++ PRM_VP2_VLIMITTO_VDDMIN | ++ PRM_VP2_VLIMITTO_TIMEOUT, ++ OMAP3430_GR_MOD, ++ OMAP3_PRM_VP2_VLIMITTO_OFFSET); ++ ++ /* Trigger initVDD value copy to voltage processor */ ++ prm_set_mod_reg_bits(PRM_VP2_CONFIG_INITVDD, OMAP3430_GR_MOD, ++ OMAP3_PRM_VP2_CONFIG_OFFSET); ++ /* Reset initVDD copy trigger bit */ ++ prm_clear_mod_reg_bits(PRM_VP2_CONFIG_INITVDD, OMAP3430_GR_MOD, ++ OMAP3_PRM_VP2_CONFIG_OFFSET); + + } + } + + static void sr_configure_vc(void) + { +- PRM_VC_SMPS_SA = +- (R_SRI2C_SLAVE_ADDR << PRM_VC_SMPS_SA1_SHIFT) | +- (R_SRI2C_SLAVE_ADDR << PRM_VC_SMPS_SA0_SHIFT); +- +- PRM_VC_SMPS_VOL_RA = (R_VDD2_SR_CONTROL << PRM_VC_SMPS_VOLRA1_SHIFT) | +- (R_VDD1_SR_CONTROL << PRM_VC_SMPS_VOLRA0_SHIFT); +- +- PRM_VC_CMD_VAL_0 = (PRM_VC_CMD_VAL0_ON << PRM_VC_CMD_ON_SHIFT) | +- (PRM_VC_CMD_VAL0_ONLP << PRM_VC_CMD_ONLP_SHIFT) | +- (PRM_VC_CMD_VAL0_RET << PRM_VC_CMD_RET_SHIFT) | +- (PRM_VC_CMD_VAL0_OFF << PRM_VC_CMD_OFF_SHIFT); +- +- PRM_VC_CMD_VAL_1 = (PRM_VC_CMD_VAL1_ON << PRM_VC_CMD_ON_SHIFT) | +- (PRM_VC_CMD_VAL1_ONLP << PRM_VC_CMD_ONLP_SHIFT) | +- (PRM_VC_CMD_VAL1_RET << PRM_VC_CMD_RET_SHIFT) | +- (PRM_VC_CMD_VAL1_OFF << PRM_VC_CMD_OFF_SHIFT); +- +- PRM_VC_CH_CONF = PRM_VC_CH_CONF_CMD1 | PRM_VC_CH_CONF_RAV1; +- +- PRM_VC_I2C_CFG = PRM_VC_I2C_CFG_MCODE | PRM_VC_I2C_CFG_HSEN +- | PRM_VC_I2C_CFG_SREN; ++ prm_write_mod_reg((R_SRI2C_SLAVE_ADDR << OMAP3430_SMPS_SA1_SHIFT) | ++ (R_SRI2C_SLAVE_ADDR << OMAP3430_SMPS_SA0_SHIFT), ++ OMAP3430_GR_MOD, OMAP3_PRM_VC_SMPS_SA_OFFSET); ++ ++ prm_write_mod_reg((R_VDD2_SR_CONTROL << OMAP3430_VOLRA1_SHIFT) | ++ (R_VDD1_SR_CONTROL << OMAP3430_VOLRA0_SHIFT), ++ OMAP3430_GR_MOD, OMAP3_PRM_VC_SMPS_VOL_RA_OFFSET); ++ ++ prm_write_mod_reg((OMAP3430_VC_CMD_VAL0_ON << ++ OMAP3430_VC_CMD_ON_SHIFT) | ++ (OMAP3430_VC_CMD_VAL0_ONLP << OMAP3430_VC_CMD_ONLP_SHIFT) | ++ (OMAP3430_VC_CMD_VAL0_RET << OMAP3430_VC_CMD_RET_SHIFT) | ++ (OMAP3430_VC_CMD_VAL0_OFF << OMAP3430_VC_CMD_OFF_SHIFT), ++ OMAP3430_GR_MOD, OMAP3_PRM_VC_CMD_VAL_0_OFFSET); ++ ++ prm_write_mod_reg((OMAP3430_VC_CMD_VAL1_ON << ++ OMAP3430_VC_CMD_ON_SHIFT) | ++ (OMAP3430_VC_CMD_VAL1_ONLP << OMAP3430_VC_CMD_ONLP_SHIFT) | ++ (OMAP3430_VC_CMD_VAL1_RET << OMAP3430_VC_CMD_RET_SHIFT) | ++ (OMAP3430_VC_CMD_VAL1_OFF << OMAP3430_VC_CMD_OFF_SHIFT), ++ OMAP3430_GR_MOD, OMAP3_PRM_VC_CMD_VAL_1_OFFSET); ++ ++ prm_write_mod_reg(OMAP3430_CMD1 | OMAP3430_RAV1, ++ OMAP3430_GR_MOD, ++ OMAP3_PRM_VC_CH_CONF_OFFSET); ++ ++ prm_write_mod_reg(OMAP3430_MCODE_SHIFT | OMAP3430_HSEN | OMAP3430_SREN, ++ OMAP3430_GR_MOD, ++ OMAP3_PRM_VC_I2C_CFG_OFFSET); + + /* Setup voltctrl and other setup times */ ++ /* XXX CONFIG_SYSOFFMODE has not been implemented yet */ + #ifdef CONFIG_SYSOFFMODE +- PRM_VOLTCTRL = PRM_VOLTCTRL_AUTO_OFF | PRM_VOLTCTRL_AUTO_RET; +- PRM_CLKSETUP = PRM_CLKSETUP_DURATION; +- PRM_VOLTSETUP1 = (PRM_VOLTSETUP_TIME2 << PRM_VOLTSETUP_TIME2_OFFSET) | +- (PRM_VOLTSETUP_TIME1 << PRM_VOLTSETUP_TIME1_OFFSET); +- PRM_VOLTOFFSET = PRM_VOLTOFFSET_DURATION; +- PRM_VOLTSETUP2 = PRM_VOLTSETUP2_DURATION; ++ prm_write_mod_reg(OMAP3430_AUTO_OFF | OMAP3430_AUTO_RET, ++ OMAP3430_GR_MOD, ++ OMAP3_PRM_VOLTCTRL_OFFSET); ++ ++ prm_write_mod_reg(OMAP3430_CLKSETUP_DURATION, OMAP3430_GR_MOD, ++ OMAP3_PRM_CLKSETUP_OFFSET); ++ prm_write_mod_reg((OMAP3430_VOLTSETUP_TIME2 << ++ OMAP3430_VOLTSETUP_TIME2_OFFSET) | ++ (OMAP3430_VOLTSETUP_TIME1 << ++ OMAP3430_VOLTSETUP_TIME1_OFFSET), ++ OMAP3430_GR_MOD, OMAP3_PRM_VOLTSETUP1_OFFSET); ++ ++ prm_write_mod_reg(OMAP3430_VOLTOFFSET_DURATION, OMAP3430_GR_MOD, ++ OMAP3_PRM_VOLTOFFSET_OFFSET); ++ prm_write_mod_reg(OMAP3430_VOLTSETUP2_DURATION, OMAP3430_GR_MOD, ++ OMAP3_PRM_VOLTSETUP2_OFFSET); + #else +- PRM_VOLTCTRL |= PRM_VOLTCTRL_AUTO_RET; ++ prm_set_mod_reg_bits(OMAP3430_AUTO_RET, OMAP3430_GR_MOD, ++ OMAP3_PRM_VOLTCTRL_OFFSET); + #endif + + } + +- + static void sr_configure(struct omap_sr *sr) + { +- u32 sys_clk, sr_clk_length = 0; + u32 sr_config; + u32 senp_en , senn_en; + ++ if (sr->clk_length == 0) ++ sr_set_clk_length(sr); ++ + senp_en = sr->senp_mod; + senn_en = sr->senn_mod; +- +- sys_clk = prcm_get_system_clock_speed(); +- +- switch (sys_clk) { +- case 12000: +- sr_clk_length = SRCLKLENGTH_12MHZ_SYSCLK; +- break; +- case 13000: +- sr_clk_length = SRCLKLENGTH_13MHZ_SYSCLK; +- break; +- case 19200: +- sr_clk_length = SRCLKLENGTH_19MHZ_SYSCLK; +- break; +- case 26000: +- sr_clk_length = SRCLKLENGTH_26MHZ_SYSCLK; +- break; +- case 38400: +- sr_clk_length = SRCLKLENGTH_38MHZ_SYSCLK; +- break; +- default : +- printk(KERN_ERR "Invalid sysclk value\n"); +- break; +- } +- +- DPRINTK(KERN_DEBUG "SR : sys clk %lu\n", sys_clk); + if (sr->srid == SR1) { + sr_config = SR1_SRCONFIG_ACCUMDATA | +- (sr_clk_length << SRCONFIG_SRCLKLENGTH_SHIFT) | ++ (sr->clk_length << SRCONFIG_SRCLKLENGTH_SHIFT) | + SRCONFIG_SENENABLE | SRCONFIG_ERRGEN_EN | + SRCONFIG_MINMAXAVG_EN | + (senn_en << SRCONFIG_SENNENABLE_SHIFT) | + (senp_en << SRCONFIG_SENPENABLE_SHIFT) | + SRCONFIG_DELAYCTRL; +- ++ DPRINTK(KERN_DEBUG "setting SRCONFIG1 to 0x%08lx\n", ++ (unsigned long int) sr_config); + sr_write_reg(sr, SRCONFIG, sr_config); + + sr_write_reg(sr, AVGWEIGHT, SR1_AVGWEIGHT_SENPAVGWEIGHT | +@@ -408,18 +527,18 @@ static void sr_configure(struct omap_sr *sr) + + } else if (sr->srid == SR2) { + sr_config = SR2_SRCONFIG_ACCUMDATA | +- (sr_clk_length << SRCONFIG_SRCLKLENGTH_SHIFT) | ++ (sr->clk_length << SRCONFIG_SRCLKLENGTH_SHIFT) | + SRCONFIG_SENENABLE | SRCONFIG_ERRGEN_EN | + SRCONFIG_MINMAXAVG_EN | + (senn_en << SRCONFIG_SENNENABLE_SHIFT) | + (senp_en << SRCONFIG_SENPENABLE_SHIFT) | + SRCONFIG_DELAYCTRL; + ++ DPRINTK(KERN_DEBUG "setting SRCONFIG2 to 0x%08lx\n", ++ (unsigned long int) sr_config); + sr_write_reg(sr, SRCONFIG, sr_config); +- + sr_write_reg(sr, AVGWEIGHT, SR2_AVGWEIGHT_SENPAVGWEIGHT | + SR2_AVGWEIGHT_SENNAVGWEIGHT); +- + sr_modify_reg(sr, ERRCONFIG, (SR_ERRWEIGHT_MASK | + SR_ERRMAXLIMIT_MASK | SR_ERRMINLIMIT_MASK), + (SR2_ERRWEIGHT | SR2_ERRMAXLIMIT | SR2_ERRMINLIMIT)); +@@ -428,9 +547,9 @@ static void sr_configure(struct omap_sr *sr) + sr->is_sr_reset = 0; + } + +-static void sr_enable(struct omap_sr *sr, u32 target_opp_no) ++static int sr_enable(struct omap_sr *sr, u32 target_opp_no) + { +- u32 nvalue_reciprocal, current_nvalue; ++ u32 nvalue_reciprocal; + + sr->req_opp_no = target_opp_no; + +@@ -472,11 +591,10 @@ static void sr_enable(struct omap_sr *sr, u32 target_opp_no) + } + } + +- current_nvalue = sr_read_reg(sr, NVALUERECIPROCAL); +- +- if (current_nvalue == nvalue_reciprocal) { +- DPRINTK("System is already at the desired voltage level\n"); +- return; ++ if (nvalue_reciprocal == 0) { ++ printk(KERN_NOTICE "OPP%d doesn't support SmartReflex\n", ++ target_opp_no); ++ return SR_FALSE; + } + + sr_write_reg(sr, NVALUERECIPROCAL, nvalue_reciprocal); +@@ -485,18 +603,19 @@ static void sr_enable(struct omap_sr *sr, u32 target_opp_no) + sr_modify_reg(sr, ERRCONFIG, + (ERRCONFIG_VPBOUNDINTEN | ERRCONFIG_VPBOUNDINTST), + (ERRCONFIG_VPBOUNDINTEN | ERRCONFIG_VPBOUNDINTST)); +- + if (sr->srid == SR1) { + /* Enable VP1 */ +- PRM_VP1_CONFIG |= PRM_VP1_CONFIG_VPENABLE; ++ prm_set_mod_reg_bits(PRM_VP1_CONFIG_VPENABLE, OMAP3430_GR_MOD, ++ OMAP3_PRM_VP1_CONFIG_OFFSET); + } else if (sr->srid == SR2) { + /* Enable VP2 */ +- PRM_VP2_CONFIG |= PRM_VP2_CONFIG_VPENABLE; ++ prm_set_mod_reg_bits(PRM_VP2_CONFIG_VPENABLE, OMAP3430_GR_MOD, ++ OMAP3_PRM_VP2_CONFIG_OFFSET); + } + + /* SRCONFIG - enable SR */ + sr_modify_reg(sr, SRCONFIG, SRCONFIG_SRENABLE, SRCONFIG_SRENABLE); +- ++ return SR_TRUE; + } + + static void sr_disable(struct omap_sr *sr) +@@ -507,11 +626,13 @@ static void sr_disable(struct omap_sr *sr) + sr_modify_reg(sr, SRCONFIG, SRCONFIG_SRENABLE, ~SRCONFIG_SRENABLE); + + if (sr->srid == SR1) { +- /* Enable VP1 */ +- PRM_VP1_CONFIG &= ~PRM_VP1_CONFIG_VPENABLE; ++ /* Disable VP1 */ ++ prm_clear_mod_reg_bits(PRM_VP1_CONFIG_VPENABLE, OMAP3430_GR_MOD, ++ OMAP3_PRM_VP1_CONFIG_OFFSET); + } else if (sr->srid == SR2) { +- /* Enable VP2 */ +- PRM_VP2_CONFIG &= ~PRM_VP2_CONFIG_VPENABLE; ++ /* Disable VP2 */ ++ prm_clear_mod_reg_bits(PRM_VP2_CONFIG_VPENABLE, OMAP3430_GR_MOD, ++ OMAP3_PRM_VP2_CONFIG_OFFSET); + } + } + +@@ -535,7 +656,12 @@ void sr_start_vddautocomap(int srid, u32 target_opp_no) + srid); + + sr->is_autocomp_active = 1; +- sr_enable(sr, target_opp_no); ++ if (!sr_enable(sr, target_opp_no)) { ++ printk(KERN_WARNING "SR%d: VDD autocomp not activated\n", srid); ++ sr->is_autocomp_active = 0; ++ if (sr->is_sr_reset == 1) ++ sr_clk_disable(sr); ++ } + } + EXPORT_SYMBOL(sr_start_vddautocomap); + +@@ -574,20 +700,18 @@ void enable_smartreflex(int srid) + + if (sr->is_autocomp_active == 1) { + if (sr->is_sr_reset == 1) { +- if (srid == SR1) { +- /* Enable SR clks */ +- CM_FCLKEN_WKUP |= SR1_CLK_ENABLE; +- target_opp_no = get_opp_no(current_vdd1_opp); ++ /* Enable SR clks */ ++ sr_clk_enable(sr); + +- } else if (srid == SR2) { +- /* Enable SR clks */ +- CM_FCLKEN_WKUP |= SR2_CLK_ENABLE; ++ if (srid == SR1) ++ target_opp_no = get_opp_no(current_vdd1_opp); ++ else if (srid == SR2) + target_opp_no = get_opp_no(current_vdd2_opp); +- } + + sr_configure(sr); + +- sr_enable(sr, target_opp_no); ++ if (!sr_enable(sr, target_opp_no)) ++ sr_clk_disable(sr); + } + } + } +@@ -602,15 +726,6 @@ void disable_smartreflex(int srid) + sr = &sr2; + + if (sr->is_autocomp_active == 1) { +- if (srid == SR1) { +- /* Enable SR clk */ +- CM_FCLKEN_WKUP |= SR1_CLK_ENABLE; +- +- } else if (srid == SR2) { +- /* Enable SR clk */ +- CM_FCLKEN_WKUP |= SR2_CLK_ENABLE; +- } +- + if (sr->is_sr_reset == 0) { + + sr->is_sr_reset = 1; +@@ -618,17 +733,18 @@ void disable_smartreflex(int srid) + sr_modify_reg(sr, SRCONFIG, SRCONFIG_SRENABLE, + ~SRCONFIG_SRENABLE); + ++ /* Disable SR clk */ ++ sr_clk_disable(sr); + if (sr->srid == SR1) { +- /* Disable SR clk */ +- CM_FCLKEN_WKUP &= ~SR1_CLK_ENABLE; +- /* Enable VP1 */ +- PRM_VP1_CONFIG &= ~PRM_VP1_CONFIG_VPENABLE; +- ++ /* Disable VP1 */ ++ prm_clear_mod_reg_bits(PRM_VP1_CONFIG_VPENABLE, ++ OMAP3430_GR_MOD, ++ OMAP3_PRM_VP1_CONFIG_OFFSET); + } else if (sr->srid == SR2) { +- /* Disable SR clk */ +- CM_FCLKEN_WKUP &= ~SR2_CLK_ENABLE; +- /* Enable VP2 */ +- PRM_VP2_CONFIG &= ~PRM_VP2_CONFIG_VPENABLE; ++ /* Disable VP2 */ ++ prm_clear_mod_reg_bits(PRM_VP2_CONFIG_VPENABLE, ++ OMAP3430_GR_MOD, ++ OMAP3_PRM_VP2_CONFIG_OFFSET); + } + } + } +@@ -638,7 +754,6 @@ void disable_smartreflex(int srid) + /* Voltage Scaling using SR VCBYPASS */ + int sr_voltagescale_vcbypass(u32 target_opp, u8 vsel) + { +- int ret; + int sr_status = 0; + u32 vdd, target_opp_no; + u32 vc_bypass_value; +@@ -651,39 +766,53 @@ int sr_voltagescale_vcbypass(u32 target_opp, u8 vsel) + if (vdd == PRCM_VDD1) { + sr_status = sr_stop_vddautocomap(SR1); + +- PRM_VC_CMD_VAL_0 = (PRM_VC_CMD_VAL_0 & ~PRM_VC_CMD_ON_MASK) | +- (vsel << PRM_VC_CMD_ON_SHIFT); ++ prm_rmw_mod_reg_bits(OMAP3430_VC_CMD_ON_MASK, ++ (vsel << OMAP3430_VC_CMD_ON_SHIFT), ++ OMAP3430_GR_MOD, ++ OMAP3_PRM_VC_CMD_VAL_0_OFFSET); + reg_addr = R_VDD1_SR_CONTROL; + + } else if (vdd == PRCM_VDD2) { + sr_status = sr_stop_vddautocomap(SR2); + +- PRM_VC_CMD_VAL_1 = (PRM_VC_CMD_VAL_1 & ~PRM_VC_CMD_ON_MASK) | +- (vsel << PRM_VC_CMD_ON_SHIFT); ++ prm_rmw_mod_reg_bits(OMAP3430_VC_CMD_ON_MASK, ++ (vsel << OMAP3430_VC_CMD_ON_SHIFT), ++ OMAP3430_GR_MOD, ++ OMAP3_PRM_VC_CMD_VAL_1_OFFSET); + reg_addr = R_VDD2_SR_CONTROL; + } + +- vc_bypass_value = (vsel << PRM_VC_BYPASS_DATA_SHIFT) | +- (reg_addr << PRM_VC_BYPASS_REGADDR_SHIFT) | +- (R_SRI2C_SLAVE_ADDR << PRM_VC_BYPASS_SLAVEADDR_SHIFT); ++ vc_bypass_value = (vsel << OMAP3430_DATA_SHIFT) | ++ (reg_addr << OMAP3430_REGADDR_SHIFT) | ++ (R_SRI2C_SLAVE_ADDR << OMAP3430_SLAVEADDR_SHIFT); + +- PRM_VC_BYPASS_VAL = vc_bypass_value; ++ prm_write_mod_reg(vc_bypass_value, OMAP3430_GR_MOD, ++ OMAP3_PRM_VC_BYPASS_VAL_OFFSET); + +- PRM_VC_BYPASS_VAL |= PRM_VC_BYPASS_VALID; ++ vc_bypass_value = prm_set_mod_reg_bits(OMAP3430_VALID, OMAP3430_GR_MOD, ++ OMAP3_PRM_VC_BYPASS_VAL_OFFSET); + +- DPRINTK("%s : PRM_VC_BYPASS_VAL %X\n", __func__, PRM_VC_BYPASS_VAL); +- DPRINTK("PRM_IRQST_MPU %X\n", PRM_IRQSTATUS_MPU); ++ DPRINTK("%s : PRM_VC_BYPASS_VAL %X\n", __func__, vc_bypass_value); ++ DPRINTK("PRM_IRQST_MPU %X\n", prm_read_mod_reg(OCP_MOD, ++ OMAP3_PRM_IRQSTATUS_MPU_OFFSET)); + +- while ((PRM_VC_BYPASS_VAL & PRM_VC_BYPASS_VALID) != 0x0) { +- ret = loop_wait(&loop_cnt, &retries_cnt, 10); +- if (ret != PRCM_PASS) { ++ while ((vc_bypass_value & OMAP3430_VALID) != 0x0) { ++ loop_cnt++; ++ if (retries_cnt > 10) { + printk(KERN_INFO "Loop count exceeded in check SR I2C" + "write\n"); +- return ret; ++ return SR_FAIL; ++ } ++ if (loop_cnt > 50) { ++ retries_cnt++; ++ loop_cnt = 0; ++ udelay(10); + } ++ vc_bypass_value = prm_read_mod_reg(OMAP3430_GR_MOD, ++ OMAP3_PRM_VC_BYPASS_VAL_OFFSET); + } + +- omap_udelay(T2_SMPS_UPDATE_DELAY); ++ udelay(T2_SMPS_UPDATE_DELAY); + + if (sr_status) { + if (vdd == PRCM_VDD1) +@@ -696,13 +825,15 @@ int sr_voltagescale_vcbypass(u32 target_opp, u8 vsel) + } + + /* Sysfs interface to select SR VDD1 auto compensation */ +-static ssize_t omap_sr_vdd1_autocomp_show(struct kset *subsys, char *buf) ++static ssize_t omap_sr_vdd1_autocomp_show(struct kobject *kobj, ++ struct kobj_attribute *attr, char *buf) + { + return sprintf(buf, "%d\n", sr1.is_autocomp_active); + } + +-static ssize_t omap_sr_vdd1_autocomp_store(struct kset *subsys, +- const char *buf, size_t n) ++static ssize_t omap_sr_vdd1_autocomp_store(struct kobject *kobj, ++ struct kobj_attribute *attr, ++ const char *buf, size_t n) + { + u32 current_vdd1opp_no; + unsigned short value; +@@ -722,7 +853,7 @@ static ssize_t omap_sr_vdd1_autocomp_store(struct kset *subsys, + return n; + } + +-static struct subsys_attribute sr_vdd1_autocomp = { ++static struct kobj_attribute sr_vdd1_autocomp = { + .attr = { + .name = __stringify(sr_vdd1_autocomp), + .mode = 0644, +@@ -732,13 +863,15 @@ static struct subsys_attribute sr_vdd1_autocomp = { + }; + + /* Sysfs interface to select SR VDD2 auto compensation */ +-static ssize_t omap_sr_vdd2_autocomp_show(struct kset *subsys, char *buf) ++static ssize_t omap_sr_vdd2_autocomp_show(struct kobject *kobj, ++ struct kobj_attribute *attr, char *buf) + { + return sprintf(buf, "%d\n", sr2.is_autocomp_active); + } + +-static ssize_t omap_sr_vdd2_autocomp_store(struct kset *subsys, +- const char *buf, size_t n) ++static ssize_t omap_sr_vdd2_autocomp_store(struct kobject *kobj, ++ struct kobj_attribute *attr, ++ const char *buf, size_t n) + { + u32 current_vdd2opp_no; + unsigned short value; +@@ -758,7 +891,7 @@ static ssize_t omap_sr_vdd2_autocomp_store(struct kset *subsys, + return n; + } + +-static struct subsys_attribute sr_vdd2_autocomp = { ++static struct kobj_attribute sr_vdd2_autocomp = { + .attr = { + .name = __stringify(sr_vdd2_autocomp), + .mode = 0644, +@@ -774,15 +907,19 @@ static int __init omap3_sr_init(void) + int ret = 0; + u8 RdReg; + +-#ifdef CONFIG_ARCH_OMAP34XX +- sr1.fck = clk_get(NULL, "sr1_fck"); +- if (IS_ERR(sr1.fck)) +- printk(KERN_ERR "Could not get sr1_fck\n"); +- +- sr2.fck = clk_get(NULL, "sr2_fck"); +- if (IS_ERR(sr2.fck)) +- printk(KERN_ERR "Could not get sr2_fck\n"); +-#endif /* #ifdef CONFIG_ARCH_OMAP34XX */ ++ if (is_sil_rev_greater_than(OMAP3430_REV_ES1_0)) { ++ current_vdd1_opp = PRCM_VDD1_OPP3; ++ current_vdd2_opp = PRCM_VDD2_OPP3; ++ } else { ++ current_vdd1_opp = PRCM_VDD1_OPP1; ++ current_vdd2_opp = PRCM_VDD1_OPP1; ++ } ++ if (cpu_is_omap34xx()) { ++ sr_clk_get(&sr1); ++ sr_clk_get(&sr2); ++ } ++ sr_set_clk_length(&sr1); ++ sr_set_clk_length(&sr2); + + /* Call the VPConfig, VCConfig, set N Values. */ + sr_set_nvalues(&sr1); +@@ -794,22 +931,24 @@ static int __init omap3_sr_init(void) + sr_configure_vc(); + + /* Enable SR on T2 */ +- ret = t2_in(PM_RECEIVER, &RdReg, R_DCDC_GLOBAL_CFG); +- RdReg |= DCDC_GLOBAL_CFG_ENABLE_SRFLX; +- ret |= t2_out(PM_RECEIVER, RdReg, R_DCDC_GLOBAL_CFG); ++ ret = twl4030_i2c_read_u8(TWL4030_MODULE_PM_RECEIVER, &RdReg, ++ R_DCDC_GLOBAL_CFG); + ++ RdReg |= DCDC_GLOBAL_CFG_ENABLE_SRFLX; ++ ret |= twl4030_i2c_write_u8(TWL4030_MODULE_PM_RECEIVER, RdReg, ++ R_DCDC_GLOBAL_CFG); + + printk(KERN_INFO "SmartReflex driver initialized\n"); + +- ret = subsys_create_file(&power_subsys, &sr_vdd1_autocomp); ++ ret = sysfs_create_file(power_kobj, &sr_vdd1_autocomp.attr); + if (ret) +- printk(KERN_ERR "subsys_create_file failed: %d\n", ret); ++ printk(KERN_ERR "sysfs_create_file failed: %d\n", ret); + +- ret = subsys_create_file(&power_subsys, &sr_vdd2_autocomp); ++ ret = sysfs_create_file(power_kobj, &sr_vdd2_autocomp.attr); + if (ret) +- printk(KERN_ERR "subsys_create_file failed: %d\n", ret); ++ printk(KERN_ERR "sysfs_create_file failed: %d\n", ret); + + return 0; + } + +-arch_initcall(omap3_sr_init); ++late_initcall(omap3_sr_init); +diff --git a/arch/arm/mach-omap2/smartreflex.h b/arch/arm/mach-omap2/smartreflex.h +index 2091a15..194429e 100644 +--- a/arch/arm/mach-omap2/smartreflex.h ++++ b/arch/arm/mach-omap2/smartreflex.h +@@ -233,12 +233,18 @@ + extern u32 current_vdd1_opp; + extern u32 current_vdd2_opp; + ++#ifdef CONFIG_OMAP_SMARTREFLEX_TESTING ++#define SR_TESTING_NVALUES 1 ++#else ++#define SR_TESTING_NVALUES 0 ++#endif ++ + /* + * Smartreflex module enable/disable interface. + * NOTE: if smartreflex is not enabled from sysfs, these functions will not + * do anything. + */ +-#if defined(CONFIG_ARCH_OMAP34XX) && defined(CONFIG_TWL4030_CORE) ++#ifdef CONFIG_OMAP_SMARTREFLEX + void enable_smartreflex(int srid); + void disable_smartreflex(int srid); + #else +@@ -246,7 +252,6 @@ static inline void enable_smartreflex(int srid) {} + static inline void disable_smartreflex(int srid) {} + #endif + +- + #endif + + +diff --git a/arch/arm/plat-omap/Kconfig b/arch/arm/plat-omap/Kconfig +index b085b07..960c13f 100644 +--- a/arch/arm/plat-omap/Kconfig ++++ b/arch/arm/plat-omap/Kconfig +@@ -56,6 +56,37 @@ config OMAP_DEBUG_CLOCKDOMAIN + for every clockdomain register write. However, the + extra detail costs some memory. + ++config OMAP_SMARTREFLEX ++ bool "SmartReflex support" ++ depends on ARCH_OMAP34XX && TWL4030_CORE ++ help ++ Say Y if you want to enable SmartReflex. ++ ++ SmartReflex can perform continuous dynamic voltage ++ scaling around the nominal operating point voltage ++ according to silicon characteristics and operating ++ conditions. Enabling SmartReflex reduces power ++ consumption. ++ ++ Please note, that by default SmartReflex is only ++ initialized. To enable the automatic voltage ++ 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" ++ depends on OMAP_SMARTREFLEX ++ default n ++ help ++ Say Y if you want to enable SmartReflex testing with SW hardcoded ++ NVALUES intead of E-fuse NVALUES set in factory silicon testing. ++ ++ In some devices the E-fuse values have not been set, even though ++ 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! ++ + config OMAP_RESET_CLOCKS + bool "Reset unused clocks during boot" + depends on ARCH_OMAP +-- +1.5.4.3 |