From 5f945012c9705a23a3eb9a2827807e3c3ed263a1 Mon Sep 17 00:00:00 2001 From: "Franklin S. Cooper Jr" Date: Thu, 27 Jun 2013 10:57:32 -0500 Subject: linux-am335x-psp: Add patch to enable SR on PG 2.x boards. * Add patch that enables Smart Reflex on new PG 2.x boards. Signed-off-by: Franklin S. Cooper Jr Signed-off-by: Denys Dmytriyenko --- ...lex-support-for-ES-2.x-and-suspend-resume.patch | 1928 ++++++++++++++++++++ recipes-kernel/linux/linux-am335x-psp_3.2.bb | 3 +- 2 files changed, 1930 insertions(+), 1 deletion(-) create mode 100644 recipes-kernel/linux/linux-am335x-psp-3.2/0001-Smartreflex-support-for-ES-2.x-and-suspend-resume.patch diff --git a/recipes-kernel/linux/linux-am335x-psp-3.2/0001-Smartreflex-support-for-ES-2.x-and-suspend-resume.patch b/recipes-kernel/linux/linux-am335x-psp-3.2/0001-Smartreflex-support-for-ES-2.x-and-suspend-resume.patch new file mode 100644 index 00000000..bc2b5c7a --- /dev/null +++ b/recipes-kernel/linux/linux-am335x-psp-3.2/0001-Smartreflex-support-for-ES-2.x-and-suspend-resume.patch @@ -0,0 +1,1928 @@ +From 4866616f13b397a07c06a45a34d050c1b4539e10 Mon Sep 17 00:00:00 2001 +From: Greg Guyotte +Date: Tue, 28 May 2013 20:45:07 -0500 +Subject: [PATCH] Smartreflex support for ES 2.x and suspend resume + +This change adds support for ES 2.x to the SmartReflex driver. +It also adds suspend/resume handlers which resolves an identified +problem. The voltage calculation has been improved in order +to settle more quickly and accurately to the target voltage. + +Signed-off-by: Greg Guyotte +--- + arch/arm/mach-omap2/am33xx-smartreflex-class2.c | 852 +++++++++++++---------- + arch/arm/mach-omap2/devices.c | 483 +++++++------ + arch/arm/plat-omap/include/plat/smartreflex.h | 72 +- + 3 files changed, 812 insertions(+), 595 deletions(-) + +diff --git a/arch/arm/mach-omap2/am33xx-smartreflex-class2.c b/arch/arm/mach-omap2/am33xx-smartreflex-class2.c +index 6a66e68..4d750d4 100644 +--- a/arch/arm/mach-omap2/am33xx-smartreflex-class2.c ++++ b/arch/arm/mach-omap2/am33xx-smartreflex-class2.c +@@ -28,6 +28,7 @@ + #include + #include + #include ++#include + + #include + #include +@@ -37,6 +38,9 @@ + + #define CLK_NAME_LEN 40 + ++/* Global reference used for suspend/resume only */ ++static struct am33xx_sr *global_sr_info; ++ + static inline void sr_write_reg(struct am33xx_sr *sr, int offset, u32 value, + u32 srid) + { +@@ -60,63 +64,68 @@ static inline u32 sr_read_reg(struct am33xx_sr *sr, int offset, u32 srid) + return readl(sr->sen[srid].base + offset); + } + +-static void cal_reciprocal(u32 sensor, u32 *sengain, u32 *rnsen) { +- u32 gn, rn, mul; +- +- for (gn = 0; gn < GAIN_MAXLIMIT; gn++) { +- mul = 1 << (gn + 8); +- rn = mul / sensor; +- if (rn < R_MAXLIMIT) { +- *sengain = gn; +- *rnsen = rn; +- } +- } ++static void cal_reciprocal(u32 sensor, u32 *sengain, u32 *rnsen) ++{ ++ u32 gn, rn, mul; ++ ++ for (gn = 0; gn < GAIN_MAXLIMIT; gn++) { ++ mul = 1 << (gn + 8); ++ rn = mul / sensor; ++ if (rn < R_MAXLIMIT) { ++ *sengain = gn; ++ *rnsen = rn; ++ } ++ } + } + +-static u32 cal_test_nvalue(u32 sennval, u32 senpval) { +- u32 senpgain=0, senngain=0; +- u32 rnsenp=0, rnsenn=0; ++static u32 cal_test_nvalue(u32 sennval, u32 senpval) ++{ ++ u32 senpgain = 0, senngain = 0; ++ u32 rnsenp = 0, rnsenn = 0; + +- /* Calculating the gain and reciprocal of the SenN and SenP values */ +- cal_reciprocal(senpval, &senpgain, &rnsenp); +- cal_reciprocal(sennval, &senngain, &rnsenn); ++ /* Calculating the gain and reciprocal of the SenN and SenP values */ ++ cal_reciprocal(senpval, &senpgain, &rnsenp); ++ cal_reciprocal(sennval, &senngain, &rnsenn); + +- return (senpgain << NVALUERECIPROCAL_SENPGAIN_SHIFT) | +- (senngain << NVALUERECIPROCAL_SENNGAIN_SHIFT) | +- (rnsenp << NVALUERECIPROCAL_RNSENP_SHIFT) | +- (rnsenn << NVALUERECIPROCAL_RNSENN_SHIFT); ++ return (senpgain << NVALUERECIPROCAL_SENPGAIN_SHIFT) | ++ (senngain << NVALUERECIPROCAL_SENNGAIN_SHIFT) | ++ (rnsenp << NVALUERECIPROCAL_RNSENP_SHIFT) | ++ (rnsenn << NVALUERECIPROCAL_RNSENN_SHIFT); + } + ++/* margin is defined similar to the SenVal register. ++ SenP margin is 31:16 bits ++ SenN margin is 15:00 bits ++*/ + static unsigned int sr_adjust_efuse_nvalue(unsigned int opp_no, +- unsigned int orig_opp_nvalue, +- unsigned int mv_delta) { +- unsigned int new_opp_nvalue; +- unsigned int senp_gain, senn_gain, rnsenp, rnsenn, pnt_delta, nnt_delta; +- unsigned int new_senn, new_senp, senn, senp; ++ unsigned int orig_opp_nvalue, ++ unsigned int margin) { ++ unsigned int new_opp_nvalue, senp_gain, senn_gain, rnsenp, rnsenn; ++ unsigned int pnt_delta, nnt_delta, new_senn, new_senp, senn, senp; + +- /* calculate SenN and SenP from the efuse value */ +- senp_gain = ((orig_opp_nvalue >> 20) & 0xf); +- senn_gain = ((orig_opp_nvalue >> 16) & 0xf); +- rnsenp = ((orig_opp_nvalue >> 8) & 0xff); +- rnsenn = (orig_opp_nvalue & 0xff); ++ /* calculate SenN and SenP from the efuse value */ ++ senp_gain = ((orig_opp_nvalue >> 20) & 0xf); ++ senn_gain = ((orig_opp_nvalue >> 16) & 0xf); ++ rnsenp = ((orig_opp_nvalue >> 8) & 0xff); ++ rnsenn = (orig_opp_nvalue & 0xff); + +- senp = ((1<<(senp_gain+8))/(rnsenp)); +- senn = ((1<<(senn_gain+8))/(rnsenn)); ++ senp = ((1<<(senp_gain+8))/(rnsenp)); ++ senn = ((1<<(senn_gain+8))/(rnsenn)); + +- /* calculate the voltage delta */ +- pnt_delta = (26 * mv_delta)/10; +- nnt_delta = (3 * mv_delta); ++ /* calculate the voltage delta */ ++ pnt_delta = (margin >> 16) & 0xffff; ++ nnt_delta = margin & 0xffff; + +- /* now lets add the voltage delta to the sensor values */ +- new_senn = senn + nnt_delta; +- new_senp = senp + pnt_delta; ++ /* now lets add the voltage delta to the sensor values */ ++ new_senn = senn + nnt_delta; ++ new_senp = senp + pnt_delta; + +- new_opp_nvalue = cal_test_nvalue(new_senn, new_senp); ++ new_opp_nvalue = cal_test_nvalue(new_senn, new_senp); + +- printk("Compensating OPP%d for %dmV Orig nvalue:0x%x New nvalue:0x%x \n", +- opp_no, mv_delta, orig_opp_nvalue, new_opp_nvalue); ++ printk(KERN_DEBUG "Compensating OPP%d: Orig nvalue:0x%x New nvalue:0x%x\n", ++ opp_no, orig_opp_nvalue, new_opp_nvalue); + +- return new_opp_nvalue; ++ return new_opp_nvalue; + } + + /* irq_sr_reenable - Re-enable SR interrupts (triggered by delayed work queue) +@@ -128,55 +137,104 @@ static unsigned int sr_adjust_efuse_nvalue(unsigned int opp_no, + */ + static void irq_sr_reenable(struct work_struct *work) + { +- u32 srid; ++ u32 srid; + struct am33xx_sr_sensor *sens; +- struct am33xx_sr *sr; ++ struct am33xx_sr *sr; + +- sens = container_of((void *)work, struct am33xx_sr_sensor, +- work_reenable); ++ sens = container_of((void *)work, struct am33xx_sr_sensor, ++ work_reenable); + +- srid = sens->sr_id; ++ srid = sens->sr_id; + +- sr = container_of((void *)sens, struct am33xx_sr, sen[srid]); ++ sr = container_of((void *)sens, struct am33xx_sr, sen[srid]); + +- dev_dbg(&sr->pdev->dev, "%s: SR %d\n", __func__, srid); ++ dev_dbg(&sr->pdev->dev, "%s: SR %d\n", __func__, srid); + +- /* Must clear IRQ status */ +- sens->irq_status = 0; ++ /* Must clear IRQ status */ ++ sens->irq_status = 0; + +- /* Re-enable the interrupt */ ++ /* moved from initial irq handler to solve problem of extra ++ interrupts (Clear bounds interrupt) */ ++ sr_modify_reg(sr, IRQSTATUS, IRQSTATUS_MCBOUNDSINT, ++ IRQSTATUS_MCBOUNDSINT, srid); ++ ++ /* Re-enable the interrupt */ + sr_modify_reg(sr, IRQENABLE_SET, IRQENABLE_MCUBOUNDSINT, + IRQENABLE_MCUBOUNDSINT, srid); +- +- /* Restart the module after voltage set */ +- sr_modify_reg(sr, SRCONFIG, SRCONFIG_SRENABLE, +- SRCONFIG_SRENABLE, srid); + } + + /* get_errvolt - get error voltage from SR error register + * @sr: contains SR driver data + * @srid: contains the srid, indicates which SR moduel lswe are using ++ * @curr_volt: current voltage for domain (in microvolts) ++ * @reset: set to 1 to reset the internal state machine + * +- * Read the error from SENSOR error register and then convert ++ * Reads the error from SENSOR error register and then convert + * to voltage delta, return value is the voltage delta in micro + * volt. + */ +-static int get_errvolt(struct am33xx_sr *sr, s32 srid) ++static int get_errvolt(struct am33xx_sr *sr, int srid, int curr_volt, ++ int reset) + { +- struct am33xx_sr_sensor *sens; +- int senerror_reg; +- s32 uvoltage; +- s8 terror; ++ struct am33xx_sr_sensor *sens; ++ int senerror_reg, gain; ++ s32 uvoltage = 0; ++ s8 avg_error; + +- sens = &sr->sen[srid]; ++ sens = &sr->sen[srid]; + ++ /* used when OPP changes to reset the state machine */ ++ if (reset > 0) { ++ sens->state = 0; ++ return 0; ++ } ++ ++ /* Read the AvgError */ + senerror_reg = sr_read_reg(sr, SENERROR_V2, srid); + senerror_reg = (senerror_reg & 0x0000FF00); +- terror = (s8)(senerror_reg >> 8); ++ avg_error = (s8)(senerror_reg >> 8); ++ ++ switch (sens->state) { ++ case 0: /* save the current voltage and AvgError for state 1 */ ++ sens->saved_volt = curr_volt; ++ sens->avg_error_nom = avg_error; ++ ++ /* calculate -5% voltage (spec vmin) */ ++ uvoltage = -(curr_volt * 5) / 100; ++ ++ sens->state = 1; ++ break; ++ case 1: /* guard against divide by zero (should not happen) */ ++ if (sens->avg_error_nom == avg_error) { ++ dev_err(&sr->pdev->dev, ++ "%s: SR %d: Same AvgError for 2 different voltages\n", ++ __func__, srid); ++ sens->state = 0; ++ break; ++ } + +- /* math defined in SR functional spec */ +- uvoltage = ((terror) * sr->uvoltage_step_size) >> 7; +- uvoltage = uvoltage * sens->opp_data[sens->curr_opp].e2v_gain; ++ /* calculate what the gain should be based on slope */ ++ gain = abs(sens->saved_volt - curr_volt) / ++ abs(sens->avg_error_nom - avg_error); ++ uvoltage = gain * avg_error; ++ ++ dev_dbg(&sr->pdev->dev, ++ "SR %d: State 1 calculated %duV gain, vmin = %d\n", ++ srid, gain, curr_volt + uvoltage); ++ ++ /* store computed gain for state 2 */ ++ sens->opp_data[sens->curr_opp].e2v_gain = (gain / 100); ++ sens->state = 2; ++ break; ++ case 2: /* remain in this state to converge to final voltage */ ++ uvoltage = (avg_error * sr->uvoltage_step_size) >> 7; ++ uvoltage = uvoltage * sens->opp_data[sens->curr_opp].e2v_gain; ++ break; ++ default: ++ dev_err(&sr->pdev->dev, ++ "%s: SR %d: Invalid state for get_errvolt\n", ++ __func__, srid); ++ } + + return uvoltage; + } +@@ -204,48 +262,46 @@ static void set_voltage(struct work_struct *work) + + sr = container_of((void *)work, struct am33xx_sr, work); + +- for (i = 0; i < sr->no_of_sens; i++) { +- if (sr->sen[i].irq_status != 1) +- continue; ++ for (i = 0; i < sr->no_of_sens; i++) { ++ if (sr->sen[i].irq_status != 1) ++ continue; + +- /* Get the current voltage from PMIC */ +- prev_volt = regulator_get_voltage(sr->sen[i].reg); ++ /* Get the current voltage from PMIC */ ++ prev_volt = regulator_get_voltage(sr->sen[i].reg); + +- if (prev_volt < 0) { +- dev_err(&sr->pdev->dev, +- "%s: SR %d: regulator_get_voltage error %d\n", +- __func__, i, prev_volt); ++ if (prev_volt < 0) { ++ dev_err(&sr->pdev->dev, ++ "%s: SR %d: regulator_get_voltage error %d\n", ++ __func__, i, prev_volt); + +- goto reenable; +- } ++ goto reenable; ++ } + +- delta_v = get_errvolt(sr, i); +- new_volt = prev_volt + delta_v; ++ delta_v = get_errvolt(sr, i, prev_volt, 0); ++ new_volt = prev_volt + delta_v; + +- /* this is the primary output for debugging SR activity */ +- dev_dbg(&sr->pdev->dev, +- "%s: SR %d: prev volt=%d, delta_v=%d, req_volt=%d\n", +- __func__, i, prev_volt, delta_v, new_volt); ++ if (delta_v != 0) { ++ ret = regulator_set_voltage(sr->sen[i].reg, new_volt, ++ new_volt + sr->uvoltage_step_size); + +- /* Clear the counter, SR module disable */ +- sr_modify_reg(sr, SRCONFIG, SRCONFIG_SRENABLE, +- ~SRCONFIG_SRENABLE, i); ++ if (ret < 0) ++ dev_err(&sr->pdev->dev, ++ "%s: regulator_set_voltage failed! (err %d)\n", ++ __func__, ret); ++ } + +- if (delta_v != 0) { +- ret = regulator_set_voltage(sr->sen[i].reg, new_volt, +- new_volt + sr->uvoltage_step_size); ++ /* this is the primary output for debugging SR activity */ ++ printk(KERN_DEBUG "SR %d: curr=%d, delta_v=%d, calc=%d, act=%d, gain=%02x\n", ++ i, prev_volt, delta_v, new_volt, ++ regulator_get_voltage(sr->sen[i].reg), ++ sr->sen[i].opp_data[sr->sen[i].curr_opp].e2v_gain); + +- if (ret < 0) +- dev_err(&sr->pdev->dev, +- "%s: regulator_set_voltage failed! (err %d)\n", +- __func__, ret); +- } + reenable: +- /* allow time for voltage to settle before re-enabling SR +- module and interrupt */ +- schedule_delayed_work(&sr->sen[i].work_reenable, +- msecs_to_jiffies(sr->irq_delay)); +- } ++ /* allow time for voltage to settle before re-enabling SR ++ module and interrupt */ ++ schedule_delayed_work(&sr->sen[i].work_reenable, ++ msecs_to_jiffies(sr->irq_delay)); ++ } + } + + /* sr_class2_irq - sr irq handling +@@ -267,32 +323,28 @@ reenable: + static irqreturn_t sr_class2_irq(int irq, void *data) + { + u32 srid; +- struct am33xx_sr *sr; +- struct am33xx_sr_sensor *sr_sensor = (struct am33xx_sr_sensor *)data; ++ struct am33xx_sr *sr; ++ struct am33xx_sr_sensor *sr_sensor = (struct am33xx_sr_sensor *)data; + +- srid = sr_sensor->sr_id; ++ srid = sr_sensor->sr_id; + +- sr = container_of(data, struct am33xx_sr, sen[srid]); ++ sr = container_of(data, struct am33xx_sr, sen[srid]); + + sr->sen[srid].irq_status = 1; + +- /* Clear MCUBounds Interrupt */ +- sr_modify_reg(sr, IRQSTATUS, IRQSTATUS_MCBOUNDSINT, +- IRQSTATUS_MCBOUNDSINT, srid); +- + /* Disable the interrupt and re-enable in set_voltage() */ + sr_modify_reg(sr, IRQENABLE_CLR, IRQENABLE_MCUBOUNDSINT, + IRQENABLE_MCUBOUNDSINT, srid); + +- /* Causes set_voltage() to get called at a later time. Set_voltage() +- will check the irq_status flags to determine which SR needs to +- be serviced. This was previously done with schedule_work, but +- I observed a crash in set_voltage() when changing OPPs on weak +- silicon, which may have been related to insufficient voltage +- settling time for OPP change. This additional delay avoids the +- crash. */ +- schedule_delayed_work(&sr->work, +- msecs_to_jiffies(250)); ++ /* Causes set_voltage() to get called at a later time. Set_voltage() ++ will check the irq_status flags to determine which SR needs to ++ be serviced. This was previously done with schedule_work, but ++ I observed a crash in set_voltage() when changing OPPs on weak ++ silicon, which may have been related to insufficient voltage ++ settling time for OPP change. This additional delay avoids the ++ crash. */ ++ schedule_delayed_work(&sr->work, ++ msecs_to_jiffies(250)); + + return IRQ_HANDLED; + } +@@ -317,31 +369,31 @@ static int sr_clk_disable(struct am33xx_sr *sr, u32 srid) + + static inline int sr_set_nvalues(struct am33xx_sr *sr, u32 srid) + { +- int i; +- struct am33xx_sr_sensor *sens = &sr->sen[srid]; ++ int i; ++ struct am33xx_sr_sensor *sens = &sr->sen[srid]; + +- for (i = 0; i < sens->no_of_opps; i++) { +- /* Read nTarget value form EFUSE register*/ +- sens->opp_data[i].nvalue = readl(AM33XX_CTRL_REGADDR ++ for (i = 0; i < sens->no_of_opps; i++) { ++ /* Read nTarget value form EFUSE register*/ ++ sens->opp_data[i].nvalue = readl(AM33XX_CTRL_REGADDR + (sens->opp_data[i].efuse_offs)) & 0xFFFFFF; + +- /* validate nTarget value */ +- if (sens->opp_data[i].nvalue == 0) +- return -EINVAL; ++ /* validate nTarget value */ ++ if (sens->opp_data[i].nvalue == 0) ++ return -EINVAL; + +- /* adjust nTarget based on margin in mv */ +- sens->opp_data[i].adj_nvalue = sr_adjust_efuse_nvalue(i, +- sens->opp_data[i].nvalue, +- sens->opp_data[i].margin); ++ /* adjust nTarget based on margin in mv */ ++ sens->opp_data[i].adj_nvalue = sr_adjust_efuse_nvalue(i, ++ sens->opp_data[i].nvalue, ++ sens->opp_data[i].margin); + +- dev_dbg(&sr->pdev->dev, +- "NValueReciprocal value (from efuse) = %08x\n", +- sens->opp_data[i].nvalue); ++ dev_dbg(&sr->pdev->dev, ++ "NValueReciprocal value (from efuse) = %08x\n", ++ sens->opp_data[i].nvalue); + +- dev_dbg(&sr->pdev->dev, +- "Adjusted NValueReciprocal value = %08x\n", +- sens->opp_data[i].adj_nvalue); +- } ++ dev_dbg(&sr->pdev->dev, ++ "Adjusted NValueReciprocal value = %08x\n", ++ sens->opp_data[i].adj_nvalue); ++ } + return 0; + } + +@@ -354,7 +406,7 @@ static inline int sr_set_nvalues(struct am33xx_sr *sr, u32 srid) + */ + static void sr_configure(struct am33xx_sr *sr, u32 srid) + { +- struct am33xx_sr_sensor *sens = &sr->sen[srid]; ++ struct am33xx_sr_sensor *sens = &sr->sen[srid]; + + /* Configuring the SR module with clock length, enabling the + * error generator, enable SR module, enable individual N and P +@@ -370,11 +422,11 @@ static void sr_configure(struct am33xx_sr *sr, u32 srid) + sr_modify_reg(sr, ERRCONFIG_V2, (SR_ERRWEIGHT_MASK | + SR_ERRMAXLIMIT_MASK | SR_ERRMINLIMIT_MASK), + ((sens->opp_data[sens->curr_opp].err_weight << +- ERRCONFIG_ERRWEIGHT_SHIFT) | ++ ERRCONFIG_ERRWEIGHT_SHIFT) | + (sens->opp_data[sens->curr_opp].err_maxlimit << +- ERRCONFIG_ERRMAXLIMIT_SHIFT) | ++ ERRCONFIG_ERRMAXLIMIT_SHIFT) | + (sens->opp_data[sens->curr_opp].err_minlimit << +- ERRCONFIG_ERRMINLIMIT_SHIFT)), ++ ERRCONFIG_ERRMINLIMIT_SHIFT)), + srid); + } + +@@ -387,9 +439,14 @@ static void sr_configure(struct am33xx_sr *sr, u32 srid) + */ + static void sr_enable(struct am33xx_sr *sr, u32 srid) + { +- struct am33xx_sr_sensor *sens; ++ struct am33xx_sr_sensor *sens; ++ ++ if (sr->is_suspended) { ++ dev_dbg(&sr->pdev->dev, "%s: in suspended state\n", __func__); ++ return; ++ } + +- sens = &sr->sen[srid]; ++ sens = &sr->sen[srid]; + + /* Check if SR is already enabled. If yes do nothing */ + if (sr_read_reg(sr, SRCONFIG, srid) & SRCONFIG_SRENABLE) +@@ -397,11 +454,11 @@ static void sr_enable(struct am33xx_sr *sr, u32 srid) + + if (sens->opp_data[sens->curr_opp].nvalue == 0) + dev_err(&sr->pdev->dev, +- "%s: OPP doesn't support SmartReflex\n", __func__); ++ "%s: OPP doesn't support SmartReflex\n", __func__); + + /* Writing the nReciprocal value to the register */ + sr_write_reg(sr, NVALUERECIPROCAL, +- sens->opp_data[sens->curr_opp].adj_nvalue, srid); ++ sens->opp_data[sens->curr_opp].adj_nvalue, srid); + + /* Enable the interrupt */ + sr_modify_reg(sr, IRQENABLE_SET, IRQENABLE_MCUBOUNDSINT, +@@ -420,6 +477,11 @@ static void sr_enable(struct am33xx_sr *sr, u32 srid) + */ + static void sr_disable(struct am33xx_sr *sr, u32 srid) + { ++ if (sr->is_suspended) { ++ dev_dbg(&sr->pdev->dev, "%s: in suspended state\n", __func__); ++ return; ++ } ++ + /* Disable the interrupt */ + sr_modify_reg(sr, IRQENABLE_CLR, IRQENABLE_MCUBOUNDSINT, + IRQENABLE_MCUBOUNDSINT, srid); +@@ -440,31 +502,31 @@ static void sr_start_vddautocomp(struct am33xx_sr *sr) + int i; + + if ((sr->sen[SR_CORE].opp_data[0].nvalue == 0) || +- (sr->sen[SR_MPU].opp_data[0].nvalue == 0)) { ++ (sr->sen[SR_MPU].opp_data[0].nvalue == 0)) { + dev_err(&sr->pdev->dev, "SR module not enabled, nTarget" + " values are not found\n"); + return; + } + +- if (sr->autocomp_active == 1) { ++ if (sr->autocomp_active) { + dev_warn(&sr->pdev->dev, "SR VDD autocomp already active\n"); + return; + } + + for (i = 0; i < sr->no_of_sens; i++) { +- /* Read current regulator value and voltage */ +- sr->sen[i].init_volt_mv = regulator_get_voltage(sr->sen[i].reg); ++ /* Read current regulator value and voltage */ ++ sr->sen[i].init_volt_mv = regulator_get_voltage(sr->sen[i].reg); + +- dev_dbg(&sr->pdev->dev, "%s: regulator %d, init_volt = %d\n", +- __func__, i, sr->sen[i].init_volt_mv); ++ dev_dbg(&sr->pdev->dev, "%s: regulator %d, init_volt = %d\n", ++ __func__, i, sr->sen[i].init_volt_mv); + + if (sr_clk_enable(sr, i)) +- return; ++ return; + sr_configure(sr, i); + sr_enable(sr, i); + } + +- sr->autocomp_active = 1; ++ sr->autocomp_active = true; + } + + /* sr_stop_vddautocomp - Stop VDD auto compensation +@@ -477,22 +539,22 @@ static void sr_stop_vddautocomp(struct am33xx_sr *sr) + { + int i; + +- if (sr->autocomp_active == 0) { ++ if (!sr->autocomp_active) { + dev_warn(&sr->pdev->dev, "SR VDD autocomp is not active\n"); + return; + } + +- /* cancel bottom half interrupt handlers that haven't run yet */ ++ /* cancel bottom half interrupt handlers that haven't run yet */ + cancel_delayed_work_sync(&sr->work); + + for (i = 0; i < sr->no_of_sens; i++) { +- /* cancel any outstanding SR IRQ re-enables on work queue */ +- cancel_delayed_work_sync(&sr->sen[i].work_reenable); ++ /* cancel any outstanding SR IRQ re-enables on work queue */ ++ cancel_delayed_work_sync(&sr->sen[i].work_reenable); + sr_disable(sr, i); + sr_clk_disable(sr, i); + } + +- sr->autocomp_active = 0; ++ sr->autocomp_active = false; + } + + /* am33xx_sr_autocomp_show - Store user input value and stop SR +@@ -513,7 +575,8 @@ static int am33xx_sr_autocomp_show(void *data, u64 *val) + + static int am33xx_sr_margin_show(void *data, u64 *val) + { +- struct am33xx_sr_opp_data *sr_opp_data = (struct am33xx_sr_opp_data *)data; ++ struct am33xx_sr_opp_data *sr_opp_data = ++ (struct am33xx_sr_opp_data *)data; + + *val = (u64) sr_opp_data->margin; + +@@ -522,35 +585,35 @@ static int am33xx_sr_margin_show(void *data, u64 *val) + + static int am33xx_sr_margin_update(void *data, u64 val) + { +- struct am33xx_sr_opp_data *sr_opp_data = +- (struct am33xx_sr_opp_data *)data; +- struct am33xx_sr_sensor *sr_sensor; +- struct am33xx_sr *sr_info; ++ struct am33xx_sr_opp_data *sr_opp_data = ++ (struct am33xx_sr_opp_data *)data; ++ struct am33xx_sr_sensor *sr_sensor; ++ struct am33xx_sr *sr_info; + +- /* work back to the sr_info pointer */ +- sr_sensor = container_of((void *)sr_opp_data, struct am33xx_sr_sensor, +- opp_data[sr_opp_data->opp_id]); ++ /* work back to the sr_info pointer */ ++ sr_sensor = container_of((void *)sr_opp_data, struct am33xx_sr_sensor, ++ opp_data[sr_opp_data->opp_id]); + +- sr_info = container_of((void *)sr_sensor, struct am33xx_sr, +- sen[sr_sensor->sr_id]); ++ sr_info = container_of((void *)sr_sensor, struct am33xx_sr, ++ sen[sr_sensor->sr_id]); + +- /* store the value of margin */ +- sr_opp_data->margin = (s32)val; ++ /* store the value of margin */ ++ sr_opp_data->margin = (s32)val; + +- dev_warn(&sr_info->pdev->dev, "%s: new margin=%d, srid=%d, opp=%d\n", +- __func__, sr_opp_data->margin, sr_sensor->sr_id, +- sr_opp_data->opp_id); ++ dev_warn(&sr_info->pdev->dev, "%s: new margin=%d, srid=%d, opp=%d\n", ++ __func__, sr_opp_data->margin, sr_sensor->sr_id, ++ sr_opp_data->opp_id); + +- /* updata ntarget values based upon new margin */ +- if (sr_set_nvalues(sr_info, sr_sensor->sr_id) == -EINVAL) +- dev_err(&sr_info->pdev->dev, +- "%s: Zero NValue read from EFUSE\n", __func__); ++ /* updata ntarget values based upon new margin */ ++ if (sr_set_nvalues(sr_info, sr_sensor->sr_id) == -EINVAL) ++ dev_err(&sr_info->pdev->dev, ++ "%s: Zero NValue read from EFUSE\n", __func__); + +- /* restart SmartReflex to adapt to new values */ +- sr_stop_vddautocomp(sr_info); +- sr_start_vddautocomp(sr_info); ++ /* restart SmartReflex to adapt to new values */ ++ sr_stop_vddautocomp(sr_info); ++ sr_start_vddautocomp(sr_info); + +- return 0; ++ return 0; + } + + /* am33xx_sr_autocomp_store - Store user input and start SR +@@ -564,21 +627,25 @@ static int am33xx_sr_autocomp_store(void *data, u64 val) + { + struct am33xx_sr *sr_info = (struct am33xx_sr *) data; + ++ if (sr_info->is_suspended) { ++ pr_warning("%s: in suspended state\n", __func__); ++ return -EBUSY; ++ } ++ + /* Sanity check */ + if (val && (val != 1)) { + dev_warn(&sr_info->pdev->dev, "%s: Invalid argument %llu\n", +- __func__, val); ++ __func__, val); + return -EINVAL; + } + + if (!val) { +- sr_info->disabled_by_user = 1; ++ sr_info->disabled_by_user = true; + sr_stop_vddautocomp(sr_info); +- } +- else { +- sr_info->disabled_by_user = 0; ++ } else { ++ sr_info->disabled_by_user = false; + sr_start_vddautocomp(sr_info); +- } ++ } + + return 0; + } +@@ -618,7 +685,7 @@ DEFINE_SIMPLE_ATTRIBUTE(margin_fops, am33xx_sr_margin_show, + */ + static int sr_debugfs_entries(struct am33xx_sr *sr_info) + { +- struct am33xx_sr_sensor *sens; ++ struct am33xx_sr_sensor *sens; + struct dentry *dbg_dir, *sen_dir, *opp_dir; + int i, j; + +@@ -629,13 +696,13 @@ static int sr_debugfs_entries(struct am33xx_sr *sr_info) + return PTR_ERR(dbg_dir); + } + +- (void) debugfs_create_file("autocomp", S_IRUGO | S_IWUGO, dbg_dir, ++ (void) debugfs_create_file("autocomp", S_IRUGO | S_IWUSR, dbg_dir, + (void *)sr_info, &sr_fops); +- (void) debugfs_create_u32("interrupt_delay", S_IRUGO | S_IWUGO, ++ (void) debugfs_create_u32("interrupt_delay", S_IRUGO | S_IWUSR, + dbg_dir, &sr_info->irq_delay); + + for (i = 0; i < sr_info->no_of_sens; i++) { +- sens = &sr_info->sen[i]; ++ sens = &sr_info->sen[i]; + sen_dir = debugfs_create_dir(sens->name, dbg_dir); + if (IS_ERR(sen_dir)) { + dev_err(&sr_info->pdev->dev, "%s: Unable to create" +@@ -643,37 +710,37 @@ static int sr_debugfs_entries(struct am33xx_sr *sr_info) + return PTR_ERR(sen_dir); + } + +- (void)debugfs_create_u32("initial_voltage", S_IRUGO, sen_dir, ++ (void)debugfs_create_u32("initial_voltage", S_IRUGO, sen_dir, + &sens->init_volt_mv); +- (void)debugfs_create_file("current_voltage", S_IRUGO, sen_dir, ++ (void)debugfs_create_file("current_voltage", S_IRUGO, sen_dir, + (void *)sens, &curr_volt_fops); + +- for (j = 0; j < sr_info->sen[i].no_of_opps; j++) { +- char tmp[20]; +- +- sprintf(&tmp[0], "opp%d", j); +- opp_dir = debugfs_create_dir(tmp, sen_dir); +- if (IS_ERR(opp_dir)) { +- dev_err(&sr_info->pdev->dev, +- "%s: Unable to create debugfs directory\n", +- __func__); +- return PTR_ERR(opp_dir); +- } +- +- (void)debugfs_create_file("margin", S_IRUGO | S_IWUGO, +- opp_dir, (void *)&sens->opp_data[j], +- &margin_fops); +- (void)debugfs_create_x32("err2voltgain", +- S_IRUGO | S_IWUGO, +- opp_dir, +- &sens->opp_data[j].e2v_gain); +- (void)debugfs_create_x32("nvalue", S_IRUGO, +- opp_dir, +- &sens->opp_data[j].nvalue); +- (void)debugfs_create_x32("adj_nvalue", S_IRUGO, +- opp_dir, +- &sens->opp_data[j].adj_nvalue); +- } ++ for (j = 0; j < sr_info->sen[i].no_of_opps; j++) { ++ char tmp[20]; ++ ++ sprintf(&tmp[0], "opp%d", j); ++ opp_dir = debugfs_create_dir(tmp, sen_dir); ++ if (IS_ERR(opp_dir)) { ++ dev_err(&sr_info->pdev->dev, ++ "%s: Unable to create debugfs directory\n", ++ __func__); ++ return PTR_ERR(opp_dir); ++ } ++ ++ (void)debugfs_create_file("margin", S_IRUGO | S_IWUSR, ++ opp_dir, (void *)&sens->opp_data[j], ++ &margin_fops); ++ (void)debugfs_create_x32("err2voltgain", ++ S_IRUGO | S_IWUSR, ++ opp_dir, ++ &sens->opp_data[j].e2v_gain); ++ (void)debugfs_create_x32("nvalue", S_IRUGO, ++ opp_dir, ++ &sens->opp_data[j].nvalue); ++ (void)debugfs_create_x32("adj_nvalue", S_IRUGO, ++ opp_dir, ++ &sens->opp_data[j].adj_nvalue); ++ } + } + return 0; + } +@@ -688,51 +755,64 @@ static int sr_debugfs_entries(struct am33xx_sr *sr_info) + + /* Find and return current OPP. This should change to use system APIs, + but voltdm is not currently populated, and opp APIs are also not working. */ +-static int get_current_opp(struct am33xx_sr *sr, u32 srid, u32 freq) { +- int i; ++static int get_current_opp(struct am33xx_sr *sr, u32 srid, u32 freq) ++{ ++ int i; + +- for (i = 0; i < sr->sen[srid].no_of_opps; i++) { +- if (sr->sen[srid].opp_data[i].frequency == freq) +- return i; +- } ++ for (i = 0; i < sr->sen[srid].no_of_opps; i++) { ++ if (sr->sen[srid].opp_data[i].frequency == freq) ++ return i; ++ } + +- return -EINVAL; ++ return -EINVAL; + } + + static int am33xx_sr_cpufreq_transition(struct notifier_block *nb, + unsigned long val, void *data) + { +- struct am33xx_sr *sr; +- struct cpufreq_freqs *cpu; ++ struct am33xx_sr *sr; ++ struct cpufreq_freqs *cpu; + + sr = container_of(nb, struct am33xx_sr, freq_transition); + +- /* We are required to disable SR while OPP change is occurring */ ++ /* We are required to disable SR while OPP change is occurring */ + if (val == CPUFREQ_PRECHANGE) { +- dev_dbg(&sr->pdev->dev, "%s: prechange\n", __func__); +- sr_stop_vddautocomp(sr); ++ dev_dbg(&sr->pdev->dev, "%s: prechange\n", __func__); ++ ++ printk(KERN_DEBUG "%s: prechange\n", __func__); ++ ++ sr_stop_vddautocomp(sr); ++ + } else if (val == CPUFREQ_POSTCHANGE) { +- cpu = (struct cpufreq_freqs *)data; +- dev_dbg(&sr->pdev->dev, +- "%s: postchange, cpu=%d, old=%d, new=%d\n", +- __func__, cpu->cpu, cpu->old, cpu->new); +- +- /* update current OPP */ +- sr->sen[SR_MPU].curr_opp = get_current_opp(sr, SR_MPU, +- cpu->new*1000); +- if (sr->sen[SR_MPU].curr_opp == -EINVAL) { +- dev_err(&sr->pdev->dev, "%s: cannot determine opp\n", +- __func__); +- return -EINVAL; +- } +- +- dev_dbg(&sr->pdev->dev, "%s: postchange, new opp=%d\n", +- __func__, sr->sen[SR_MPU].curr_opp); +- +- /* this handles the case when the user has disabled SR via +- debugfs, therefore we do not want to enable SR */ +- if (sr->disabled_by_user == 0) +- sr_start_vddautocomp(sr); ++ cpu = (struct cpufreq_freqs *)data; ++ dev_dbg(&sr->pdev->dev, ++ "%s: postchange, cpu=%d, old=%d, new=%d\n", ++ __func__, cpu->cpu, cpu->old, cpu->new); ++ ++ printk(KERN_DEBUG "%s: postchange\n", __func__); ++ ++ /* update current OPP */ ++ sr->sen[SR_MPU].curr_opp = get_current_opp(sr, SR_MPU, ++ cpu->new*1000); ++ if (sr->sen[SR_MPU].curr_opp == -EINVAL) { ++ dev_err(&sr->pdev->dev, "%s: cannot determine opp\n", ++ __func__); ++ return -EINVAL; ++ } ++ ++ dev_dbg(&sr->pdev->dev, "%s: postchange, new opp=%d\n", ++ __func__, sr->sen[SR_MPU].curr_opp); ++ ++ /* reset the voltage calculation algorithm for MPU */ ++ get_errvolt(sr, SR_MPU, 0, 1); ++ ++ /* this handles the case when the user has disabled SR via ++ debugfs, therefore we do not want to enable SR */ ++ if (sr->disabled_by_user == false) { ++ printk(KERN_DEBUG "%s: postchange, new opp=%d\n", ++ __func__, sr->sen[SR_MPU].curr_opp); ++ sr_start_vddautocomp(sr); ++ } + } + + return 0; +@@ -740,7 +820,7 @@ static int am33xx_sr_cpufreq_transition(struct notifier_block *nb, + + static inline int am33xx_sr_cpufreq_register(struct am33xx_sr *sr) + { +- sr->freq_transition.notifier_call = am33xx_sr_cpufreq_transition; ++ sr->freq_transition.notifier_call = am33xx_sr_cpufreq_transition; + + return cpufreq_register_notifier(&sr->freq_transition, + CPUFREQ_TRANSITION_NOTIFIER); +@@ -754,6 +834,67 @@ static inline void am33xx_sr_cpufreq_deregister(struct am33xx_sr *sr) + + #endif + ++static void print_die_id(void) ++{ ++ writel(0xF47765F2, AM33XX_CTRL_REGADDR(0x1828)); ++ writel(0x703E6C3D, AM33XX_CTRL_REGADDR(0x1844)); ++ writel(0x3724C7D6, AM33XX_CTRL_REGADDR(0x182C)); ++ writel(0x7A733E49, AM33XX_CTRL_REGADDR(0x184C)); ++ ++ printk(KERN_DEBUG "DIEID: %08x %08x %08x %08x\n", ++ readl(AM33XX_CTRL_REGADDR(0x183C)), ++ readl(AM33XX_CTRL_REGADDR(0x1848)), ++ readl(AM33XX_CTRL_REGADDR(0x1824)), ++ readl(AM33XX_CTRL_REGADDR(0x1850))); ++ ++ printk(KERN_DEBUG "EFUSE SMA register val = %08x\n", ++ readl(AM33XX_CTRL_REGADDR(0x7fc))); ++} ++ ++static int am33xx_sr_suspend(struct device *dev) ++{ ++ if (global_sr_info == NULL) ++ return -EINVAL; ++ ++ /* if we are already disabled or suspended, do nothing */ ++ if (global_sr_info->disabled_by_user) ++ return 0; ++ ++ if (global_sr_info->is_suspended) ++ return 0; ++ ++#ifdef CONFIG_CPU_FREQ ++ am33xx_sr_cpufreq_deregister(global_sr_info); ++#endif ++ sr_stop_vddautocomp(global_sr_info); ++ global_sr_info->is_suspended = true; ++ ++ return 0; ++} ++ ++static int am33xx_sr_resume(struct device *dev) ++{ ++ if (global_sr_info == NULL) ++ return -EINVAL; ++ ++ /* ensure we don't enable SR if it was disabled before suspend */ ++ if (global_sr_info->disabled_by_user) ++ return 0; ++ ++ if (!global_sr_info->is_suspended) ++ return 0; ++ ++ global_sr_info->is_suspended = false; ++ sr_start_vddautocomp(global_sr_info); ++ ++#ifdef CONFIG_CPU_FREQ ++ if (am33xx_sr_cpufreq_register(global_sr_info)) { ++ printk(KERN_ERR "failed to register cpufreq\n"); ++ } ++#endif ++ return 0; ++} ++ + static int __init am33xx_sr_probe(struct platform_device *pdev) + { + struct am33xx_sr *sr_info; +@@ -761,13 +902,9 @@ static int __init am33xx_sr_probe(struct platform_device *pdev) + struct resource *res[MAX_SENSORS]; + int irq; + int ret; +- int i,j; ++ int i, j; + +- if (omap_rev() != AM335X_REV_ES1_0) { +- dev_err(&pdev->dev, "%s: Smartreflex requires ES 1.0\n", +- __func__); +- return -EINVAL; +- } ++ print_die_id(); + + sr_info = kzalloc(sizeof(struct am33xx_sr), GFP_KERNEL); + if (!sr_info) { +@@ -776,6 +913,8 @@ static int __init am33xx_sr_probe(struct platform_device *pdev) + return -ENOMEM; + } + ++ global_sr_info = sr_info; ++ + pdata = pdev->dev.platform_data; + if (!pdata) { + dev_err(&pdev->dev, "%s: platform data missing\n", __func__); +@@ -787,77 +926,77 @@ static int __init am33xx_sr_probe(struct platform_device *pdev) + sr_info->sen[SR_CORE].name = "smartreflex0"; + sr_info->sen[SR_MPU].name = "smartreflex1"; + sr_info->ip_type = pdata->ip_type; +- sr_info->irq_delay = pdata->irq_delay; +- sr_info->no_of_sens = pdata->no_of_sens; +- sr_info->no_of_vds = pdata->no_of_vds; ++ sr_info->irq_delay = pdata->irq_delay; ++ sr_info->no_of_sens = pdata->no_of_sens; ++ sr_info->no_of_vds = pdata->no_of_vds; + sr_info->uvoltage_step_size = pdata->vstep_size_uv; + sr_info->autocomp_active = false; +- sr_info->disabled_by_user = false; ++ sr_info->disabled_by_user = false; + + for (i = 0; i < sr_info->no_of_sens; i++) { +- u32 curr_freq=0; +- +- sr_info->sen[i].reg_name = pdata->vd_name[i]; +- +- /* this should be determined from voltdm or opp layer, but +- those approaches are not working */ +- sr_info->sen[i].no_of_opps = pdata->sr_sdata[i].no_of_opps; +- sr_info->sen[i].sr_id = i; +- +- /* Reading per OPP Values */ +- for (j = 0; j < sr_info->sen[i].no_of_opps; j++) { +- sr_info->sen[i].opp_data[j].efuse_offs = +- pdata->sr_sdata[i].sr_opp_data[j].efuse_offs; +- sr_info->sen[i].opp_data[j].e2v_gain = +- pdata->sr_sdata[i].sr_opp_data[j].e2v_gain; +- sr_info->sen[i].opp_data[j].err_weight = +- pdata->sr_sdata[i].sr_opp_data[j].err_weight; +- sr_info->sen[i].opp_data[j].err_minlimit = +- pdata->sr_sdata[i].sr_opp_data[j].err_minlimit; +- sr_info->sen[i].opp_data[j].err_maxlimit = +- pdata->sr_sdata[i].sr_opp_data[j].err_maxlimit; +- sr_info->sen[i].opp_data[j].margin = +- pdata->sr_sdata[i].sr_opp_data[j].margin; +- sr_info->sen[i].opp_data[j].nominal_volt = +- pdata->sr_sdata[i].sr_opp_data[j].nominal_volt; +- sr_info->sen[i].opp_data[j].frequency = +- pdata->sr_sdata[i].sr_opp_data[j].frequency; +- sr_info->sen[i].opp_data[j].opp_id = j; +- } +- +- if (i == SR_MPU) { +- /* hardcoded CPU NR */ +- curr_freq = cpufreq_get(0); +- +- /* update current OPP */ +- sr_info->sen[i].curr_opp = get_current_opp(sr_info, i, +- curr_freq*1000); +- if (sr_info->sen[i].curr_opp == -EINVAL) { +- dev_err(&sr_info->pdev->dev, +- "%s: cannot determine opp\n",__func__); +- ret = -EINVAL; +- goto err_free_sr_info; +- } +- } else { +- sr_info->sen[i].curr_opp = +- pdata->sr_sdata[i].default_opp; +- } +- +- dev_dbg(&pdev->dev, +- "%s: SR%d, curr_opp=%d, no_of_opps=%d, step_size=%d\n", +- __func__, i, sr_info->sen[i].curr_opp, +- sr_info->sen[i].no_of_opps, +- sr_info->uvoltage_step_size); +- +- ret = sr_set_nvalues(sr_info, i); +- if (ret == -EINVAL) { +- dev_err(&sr_info->pdev->dev, +- "%s: Zero NValue read from EFUSE\n", __func__); +- goto err_free_sr_info; +- } +- +- INIT_DELAYED_WORK(&sr_info->sen[i].work_reenable, +- irq_sr_reenable); ++ u32 curr_freq = 0; ++ ++ sr_info->sen[i].reg_name = pdata->vd_name[i]; ++ ++ /* this should be determined from voltdm or opp layer, but ++ those approaches are not working */ ++ sr_info->sen[i].no_of_opps = pdata->sr_sdata[i].no_of_opps; ++ sr_info->sen[i].sr_id = i; ++ ++ /* Reading per OPP Values */ ++ for (j = 0; j < sr_info->sen[i].no_of_opps; j++) { ++ sr_info->sen[i].opp_data[j].efuse_offs = ++ pdata->sr_sdata[i].sr_opp_data[j].efuse_offs; ++ sr_info->sen[i].opp_data[j].e2v_gain = ++ pdata->sr_sdata[i].sr_opp_data[j].e2v_gain; ++ sr_info->sen[i].opp_data[j].err_weight = ++ pdata->sr_sdata[i].sr_opp_data[j].err_weight; ++ sr_info->sen[i].opp_data[j].err_minlimit = ++ pdata->sr_sdata[i].sr_opp_data[j].err_minlimit; ++ sr_info->sen[i].opp_data[j].err_maxlimit = ++ pdata->sr_sdata[i].sr_opp_data[j].err_maxlimit; ++ sr_info->sen[i].opp_data[j].margin = ++ pdata->sr_sdata[i].sr_opp_data[j].margin; ++ sr_info->sen[i].opp_data[j].nominal_volt = ++ pdata->sr_sdata[i].sr_opp_data[j].nominal_volt; ++ sr_info->sen[i].opp_data[j].frequency = ++ pdata->sr_sdata[i].sr_opp_data[j].frequency; ++ sr_info->sen[i].opp_data[j].opp_id = j; ++ } ++ ++ if (i == SR_MPU) { ++ /* hardcoded CPU NR */ ++ curr_freq = cpufreq_get(0); ++ ++ /* update current OPP */ ++ sr_info->sen[i].curr_opp = get_current_opp(sr_info, i, ++ curr_freq*1000); ++ if (sr_info->sen[i].curr_opp == -EINVAL) { ++ dev_err(&sr_info->pdev->dev, ++ "%s: cannot determine opp\n", __func__); ++ ret = -EINVAL; ++ goto err_free_sr_info; ++ } ++ } else { ++ sr_info->sen[i].curr_opp = ++ pdata->sr_sdata[i].default_opp; ++ } ++ ++ dev_dbg(&pdev->dev, ++ "%s: SR%d, curr_opp=%d, no_of_opps=%d, step_size=%d\n", ++ __func__, i, sr_info->sen[i].curr_opp, ++ sr_info->sen[i].no_of_opps, ++ sr_info->uvoltage_step_size); ++ ++ ret = sr_set_nvalues(sr_info, i); ++ if (ret == -EINVAL) { ++ dev_err(&sr_info->pdev->dev, ++ "%s: Zero NValue read from EFUSE\n", __func__); ++ goto err_free_sr_info; ++ } ++ ++ INIT_DELAYED_WORK(&sr_info->sen[i].work_reenable, ++ irq_sr_reenable); + + sr_info->res_name[i] = kzalloc(CLK_NAME_LEN + 1, GFP_KERNEL); + +@@ -907,7 +1046,7 @@ static int __init am33xx_sr_probe(struct platform_device *pdev) + + ret = request_irq(sr_info->sen[i].irq, sr_class2_irq, + IRQF_DISABLED, sr_info->sen[i].name, +- (void *)&sr_info->sen[i]); ++ (void *)&sr_info->sen[i]); + if (ret) { + dev_err(&pdev->dev, "%s: Could not install SR ISR\n", + __func__); +@@ -917,22 +1056,22 @@ static int __init am33xx_sr_probe(struct platform_device *pdev) + sr_info->sen[i].senn_en = pdata->sr_sdata[i].senn_mod; + sr_info->sen[i].senp_en = pdata->sr_sdata[i].senp_mod; + +- sr_info->sen[i].reg = +- regulator_get(NULL, sr_info->sen[i].reg_name); +- if (IS_ERR(sr_info->sen[i].reg)) { +- ret = -EINVAL; +- goto err_free_irq; +- } ++ sr_info->sen[i].reg = ++ regulator_get(NULL, sr_info->sen[i].reg_name); ++ if (IS_ERR(sr_info->sen[i].reg)) { ++ ret = -EINVAL; ++ goto err_free_irq; ++ } + +- /* Read current regulator value and voltage */ +- sr_info->sen[i].init_volt_mv = +- regulator_get_voltage(sr_info->sen[i].reg); ++ /* Read current regulator value and voltage */ ++ sr_info->sen[i].init_volt_mv = ++ regulator_get_voltage(sr_info->sen[i].reg); + +- dev_dbg(&pdev->dev, "%s: regulator %d, init_volt = %d\n", +- __func__, i, sr_info->sen[i].init_volt_mv); ++ dev_dbg(&pdev->dev, "%s: regulator %d, init_volt = %d\n", ++ __func__, i, sr_info->sen[i].init_volt_mv); + } /* for() */ + +- /* set_voltage() will be used as the bottom half IRQ handler */ ++ /* set_voltage() will be used as the bottom half IRQ handler */ + INIT_DELAYED_WORK(&sr_info->work, set_voltage); + + #ifdef CONFIG_CPU_FREQ +@@ -943,22 +1082,24 @@ static int __init am33xx_sr_probe(struct platform_device *pdev) + } + #endif + ++#ifdef CONFIG_DEBUG_FS + /* debugfs entries */ + ret = sr_debugfs_entries(sr_info); + if (ret) + dev_warn(&pdev->dev, "%s: Debugfs entries are not created\n", + __func__); ++#endif + + platform_set_drvdata(pdev, sr_info); + + dev_info(&pdev->dev, "%s: Driver initialized\n", __func__); + +- /* disabled_by_user used to ensure SR doesn't come on via CPUFREQ +- scaling if user has disabled SR via debugfs on enable_on_init */ ++ /* disabled_by_user used to ensure SR doesn't come on via CPUFREQ ++ scaling if user has disabled SR via debugfs on enable_on_init */ + if (pdata->enable_on_init) + sr_start_vddautocomp(sr_info); +- else +- sr_info->disabled_by_user = 1; ++ else ++ sr_info->disabled_by_user = true; + + return ret; + +@@ -967,8 +1108,8 @@ static int __init am33xx_sr_probe(struct platform_device *pdev) + #endif + + err_reg_put: +- i--; /* back up i by one to walk back through the for loop */ +- regulator_put(sr_info->sen[i].reg); ++ i--; /* back up i by one to walk back through the for loop */ ++ regulator_put(sr_info->sen[i].reg); + err_free_irq: + free_irq(sr_info->sen[i].irq, (void *)sr_info); + err_put_clock: +@@ -978,11 +1119,10 @@ err_unmap: + err_release_mem: + release_mem_region(res[i]->start, resource_size(res[i])); + err_free_mem: +- kfree(sr_info->res_name[i]); +- /* unwind back through the for loop */ +- if (i != 0) { +- goto err_reg_put; +- } ++ kfree(sr_info->res_name[i]); ++ /* unwind back through the for loop */ ++ if (i != 0) ++ goto err_reg_put; + + err_free_sr_info: + kfree(sr_info); +@@ -1010,27 +1150,31 @@ static int __devexit am33xx_sr_remove(struct platform_device *pdev) + #endif + + for (i = 0; i < sr_info->no_of_sens; i++) { +- regulator_put(sr_info->sen[i].reg); +- irq = platform_get_irq_byname(pdev, sr_info->sen[i].name); ++ regulator_put(sr_info->sen[i].reg); ++ irq = platform_get_irq_byname(pdev, sr_info->sen[i].name); + free_irq(irq, (void *)sr_info); + clk_put(sr_info->sen[i].fck); + iounmap(sr_info->sen[i].base); + res[i] = platform_get_resource_byname(pdev, + IORESOURCE_MEM, sr_info->sen[i].name); + release_mem_region(res[i]->start, resource_size(res[i])); +- kfree(sr_info->res_name[i]); ++ kfree(sr_info->res_name[i]); + } + + kfree(sr_info); + +- dev_info(&pdev->dev, "%s: SR has been removed\n", __func__); ++ dev_info(&pdev->dev, "%s: SR has been removed\n", __func__); + return 0; + } + ++static SIMPLE_DEV_PM_OPS(am33xx_sr_dev_pm_ops, am33xx_sr_suspend, ++ am33xx_sr_resume); ++ + static struct platform_driver smartreflex_driver = { + .driver = { + .name = "smartreflex", + .owner = THIS_MODULE, ++ .pm = &am33xx_sr_dev_pm_ops, + }, + .remove = am33xx_sr_remove, + }; +diff --git a/arch/arm/mach-omap2/devices.c b/arch/arm/mach-omap2/devices.c +index b524b47..8081818 100644 +--- a/arch/arm/mach-omap2/devices.c ++++ b/arch/arm/mach-omap2/devices.c +@@ -1231,244 +1231,313 @@ static struct platform_device am335x_sgx = { + /* The values below are based upon silicon characterization data. + * Each OPP and sensor combination potentially has different values. + * The values of ERR2VOLT_GAIN and ERR_MIN_LIMIT also change based on +- * the PMIC step size. Values have been given to cover the AM335 EVM ++ * the PMIC step size. Values have been given to cover the AM335 EVM + * (12.5mV step) and the Beaglebone (25mV step). If the step + * size changes, you should update these values, and don't forget to + * change the step size in the platform data structure, am33xx_sr_pdata. + */ + +-#define AM33XX_SR0_OPP50_CNTRL_OFFSET 0x07B8 +-#define AM33XX_SR0_OPP50_EVM_ERR2VOLT_GAIN 0xC +-#define AM33XX_SR0_OPP50_EVM_ERR_MIN_LIMIT 0xF5 +-#define AM33XX_SR0_OPP50_BB_ERR2VOLT_GAIN 0x6 +-#define AM33XX_SR0_OPP50_BB_ERR_MIN_LIMIT 0xEA +-#define AM33XX_SR0_OPP50_ERR_MAX_LIMIT 0x2 +-#define AM33XX_SR0_OPP50_ERR_WEIGHT 0x4 +-#define AM33XX_SR0_OPP50_MARGIN 0 +- +-#define AM33XX_SR0_OPP100_CNTRL_OFFSET 0x07BC +-#define AM33XX_SR0_OPP100_EVM_ERR2VOLT_GAIN 0x12 +-#define AM33XX_SR0_OPP100_EVM_ERR_MIN_LIMIT 0xF8 +-#define AM33XX_SR0_OPP100_BB_ERR2VOLT_GAIN 0x9 +-#define AM33XX_SR0_OPP100_BB_ERR_MIN_LIMIT 0xF1 +-#define AM33XX_SR0_OPP100_ERR_MAX_LIMIT 0x2 +-#define AM33XX_SR0_OPP100_ERR_WEIGHT 0x4 +-#define AM33XX_SR0_OPP100_MARGIN 0 +- +-#define AM33XX_SR1_OPP50_CNTRL_OFFSET 0x0770 +-#define AM33XX_SR1_OPP50_EVM_ERR2VOLT_GAIN 0x5 +-#define AM33XX_SR1_OPP50_EVM_ERR_MIN_LIMIT 0xE6 +-#define AM33XX_SR1_OPP50_BB_ERR2VOLT_GAIN 0x2 +-#define AM33XX_SR1_OPP50_BB_ERR_MIN_LIMIT 0xC0 +-#define AM33XX_SR1_OPP50_ERR_MAX_LIMIT 0x2 +-#define AM33XX_SR1_OPP50_ERR_WEIGHT 0x4 +-#define AM33XX_SR1_OPP50_MARGIN 0 +- +-#define AM33XX_SR1_OPP100_CNTRL_OFFSET 0x0774 +-#define AM33XX_SR1_OPP100_EVM_ERR2VOLT_GAIN 0x8 +-#define AM33XX_SR1_OPP100_EVM_ERR_MIN_LIMIT 0xF0 +-#define AM33XX_SR1_OPP100_BB_ERR2VOLT_GAIN 0x4 +-#define AM33XX_SR1_OPP100_BB_ERR_MIN_LIMIT 0xDF +-#define AM33XX_SR1_OPP100_ERR_MAX_LIMIT 0x2 +-#define AM33XX_SR1_OPP100_ERR_WEIGHT 0x4 +-#define AM33XX_SR1_OPP100_MARGIN 0 +- +-#define AM33XX_SR1_OPP120_CNTRL_OFFSET 0x0778 +-#define AM33XX_SR1_OPP120_EVM_ERR2VOLT_GAIN 0xB +-#define AM33XX_SR1_OPP120_EVM_ERR_MIN_LIMIT 0xF4 +-#define AM33XX_SR1_OPP120_BB_ERR2VOLT_GAIN 0x5 +-#define AM33XX_SR1_OPP120_BB_ERR_MIN_LIMIT 0xE6 +-#define AM33XX_SR1_OPP120_ERR_MAX_LIMIT 0x2 +-#define AM33XX_SR1_OPP120_ERR_WEIGHT 0x4 +-#define AM33XX_SR1_OPP120_MARGIN 0 +- +-#define AM33XX_SR1_OPPTURBO_CNTRL_OFFSET 0x077C +-#define AM33XX_SR1_OPPTURBO_EVM_ERR2VOLT_GAIN 0xC +-#define AM33XX_SR1_OPPTURBO_EVM_ERR_MIN_LIMIT 0xF5 +-#define AM33XX_SR1_OPPTURBO_BB_ERR2VOLT_GAIN 0x6 +-#define AM33XX_SR1_OPPTURBO_BB_ERR_MIN_LIMIT 0xEA +-#define AM33XX_SR1_OPPTURBO_ERR_MAX_LIMIT 0x2 +-#define AM33XX_SR1_OPPTURBO_ERR_WEIGHT 0x4 +-#define AM33XX_SR1_OPPTURBO_MARGIN 0 ++#define AM33XX_SR0_OPP50_CNTRL_OFFSET 0x07B8 ++#define AM33XX_SR0_OPP50_EVM_ERR_MIN_LIMIT 0xF0 ++#define AM33XX_SR0_OPP50_BB_ERR_MIN_LIMIT 0xEA ++#define AM33XX_SR0_OPP50_ERR_MAX_LIMIT 0x2 ++#define AM33XX_SR0_OPP50_ERR_WEIGHT 0x4 ++#define AM33XX_SR0_OPP50_MARGIN 0 ++ ++#define AM33XX_SR0_OPP100_CNTRL_OFFSET 0x07BC ++#define AM33XX_SR0_OPP100_EVM_ERR_MIN_LIMIT 0xF0 ++#define AM33XX_SR0_OPP100_BB_ERR_MIN_LIMIT 0xF1 ++#define AM33XX_SR0_OPP100_ERR_MAX_LIMIT 0x2 ++#define AM33XX_SR0_OPP100_ERR_WEIGHT 0x4 ++#define AM33XX_SR0_OPP100_MARGIN 0 ++ ++#define AM33XX_SR1_OPP50_CNTRL_OFFSET 0x0770 ++#define AM33XX_SR1_OPP50_EVM_ERR_MIN_LIMIT 0xFA ++#define AM33XX_SR1_OPP50_BB_ERR_MIN_LIMIT 0xC0 ++#define AM33XX_SR1_OPP50_ERR_MAX_LIMIT 0x2 ++#define AM33XX_SR1_OPP50_ERR_WEIGHT 0x4 ++#define AM33XX_SR1_OPP50_MARGIN 0 ++ ++#define AM33XX_SR1_OPP100_CNTRL_OFFSET 0x0774 ++#define AM33XX_SR1_OPP100_EVM_ERR_MIN_LIMIT 0xFB ++#define AM33XX_SR1_OPP100_BB_ERR_MIN_LIMIT 0xDF ++#define AM33XX_SR1_OPP100_ERR_MAX_LIMIT 0x2 ++#define AM33XX_SR1_OPP100_ERR_WEIGHT 0x4 ++#define AM33XX_SR1_OPP100_MARGIN 0 ++ ++#define AM33XX_SR1_OPP120_CNTRL_OFFSET 0x0778 ++#define AM33XX_SR1_OPP120_EVM_ERR_MIN_LIMIT 0xFC ++#define AM33XX_SR1_OPP120_BB_ERR_MIN_LIMIT 0xE6 ++#define AM33XX_SR1_OPP120_ERR_MAX_LIMIT 0x2 ++#define AM33XX_SR1_OPP120_ERR_WEIGHT 0x7 ++#define AM33XX_SR1_OPP120_MARGIN 0 ++ ++#define AM33XX_SR1_OPPTURBO_CNTRL_OFFSET 0x077C ++#define AM33XX_SR1_OPPTURBO_EVM_ERR_MIN_LIMIT 0xFD ++#define AM33XX_SR1_OPPTURBO_BB_ERR_MIN_LIMIT 0xEA ++#define AM33XX_SR1_OPPTURBO_ERR_MAX_LIMIT 0x2 ++#define AM33XX_SR1_OPPTURBO_ERR_WEIGHT 0x7 ++#define AM33XX_SR1_OPPTURBO_MARGIN 0 ++ ++/* bits 31:16 = SenP margin; bit 15:0 = SenN margin */ ++ ++#define AM33XX_SR1_OPPNITRO_MARGIN 0x018B019A + + /* the voltages and frequencies should probably be defined in opp3xxx_data.c. + Once SR is integrated to the mainline driver, and voltdm is working + correctly in AM335x, these can be removed. */ +-#define AM33XX_VDD_MPU_OPP50_UV 950000 +-#define AM33XX_VDD_MPU_OPP100_UV 1100000 +-#define AM33XX_VDD_MPU_OPP120_UV 1200000 +-#define AM33XX_VDD_MPU_OPPTURBO_UV 1260000 +-#define AM33XX_VDD_CORE_OPP50_UV 950000 +-#define AM33XX_VDD_CORE_OPP100_UV 1100000 +- +-#define AM33XX_VDD_MPU_OPP50_FREQ 275000000 +-#define AM33XX_VDD_MPU_OPP100_FREQ 500000000 +-#define AM33XX_VDD_MPU_OPP120_FREQ 600000000 +-#define AM33XX_VDD_MPU_OPPTURBO_FREQ 720000000 ++#define AM33XX_VDD_MPU_OPP50_UV 950000 ++#define AM33XX_VDD_MPU_OPP100_UV 1100000 ++#define AM33XX_VDD_MPU_OPP120_UV 1200000 ++#define AM33XX_VDD_MPU_OPPTURBO_UV 1260000 ++#define AM33XX_VDD_CORE_OPP50_UV 950000 ++#define AM33XX_VDD_CORE_OPP100_UV 1100000 ++ ++#define AM33XX_VDD_MPU_OPP50_FREQ 275000000 ++#define AM33XX_VDD_MPU_OPP100_FREQ 500000000 ++#define AM33XX_VDD_MPU_OPP120_FREQ 600000000 ++#define AM33XX_VDD_MPU_OPPTURBO_FREQ 720000000 ++ ++#define AM33XX_ES2_0_VDD_MPU_OPP50_UV 950000 ++#define AM33XX_ES2_0_VDD_MPU_OPP100_UV 1100000 ++#define AM33XX_ES2_0_VDD_MPU_OPP120_UV 1200000 ++#define AM33XX_ES2_0_VDD_MPU_OPPTURBO_UV 1260000 ++#define AM33XX_ES2_0_VDD_MPU_OPPNITRO_UV 1320000 ++ ++#define AM33XX_ES2_0_VDD_MPU_OPP50_FREQ 300000000 ++#define AM33XX_ES2_0_VDD_MPU_OPP100_FREQ 600000000 ++#define AM33XX_ES2_0_VDD_MPU_OPP120_FREQ 720000000 ++#define AM33XX_ES2_0_VDD_MPU_OPPTURBO_FREQ 800000000 ++#define AM33XX_ES2_0_VDD_MPU_OPPNITRO_FREQ 1000000000 ++ ++static struct am33xx_sr_opp_data sr1_opp_data_2_0[] = { ++ { ++ .efuse_offs = AM33XX_SR1_OPP50_CNTRL_OFFSET, ++ .e2v_gain = 0, ++ .err_minlimit = AM33XX_SR1_OPP50_EVM_ERR_MIN_LIMIT, ++ .err_maxlimit = AM33XX_SR1_OPP50_ERR_MAX_LIMIT, ++ .err_weight = AM33XX_SR1_OPP50_ERR_WEIGHT, ++ .margin = AM33XX_SR1_OPP50_MARGIN, ++ .nominal_volt = AM33XX_ES2_0_VDD_MPU_OPP50_UV, ++ .frequency = AM33XX_ES2_0_VDD_MPU_OPP50_FREQ, ++ }, ++ { ++ .efuse_offs = AM33XX_SR1_OPP100_CNTRL_OFFSET, ++ .e2v_gain = 0, ++ .err_minlimit = AM33XX_SR1_OPP100_EVM_ERR_MIN_LIMIT, ++ .err_maxlimit = AM33XX_SR1_OPP100_ERR_MAX_LIMIT, ++ .err_weight = AM33XX_SR1_OPP100_ERR_WEIGHT, ++ .margin = AM33XX_SR1_OPP100_MARGIN, ++ .nominal_volt = AM33XX_ES2_0_VDD_MPU_OPP100_UV, ++ .frequency = AM33XX_ES2_0_VDD_MPU_OPP100_FREQ, ++ }, ++ { ++ .efuse_offs = AM33XX_SR1_OPP120_CNTRL_OFFSET, ++ .e2v_gain = 0, ++ .err_minlimit = AM33XX_SR1_OPP120_EVM_ERR_MIN_LIMIT, ++ .err_maxlimit = AM33XX_SR1_OPP120_ERR_MAX_LIMIT, ++ .err_weight = AM33XX_SR1_OPP120_ERR_WEIGHT, ++ .margin = AM33XX_SR1_OPP120_MARGIN, ++ .nominal_volt = AM33XX_ES2_0_VDD_MPU_OPP120_UV, ++ .frequency = AM33XX_ES2_0_VDD_MPU_OPP120_FREQ, ++ }, ++ { ++ .efuse_offs = AM33XX_SR1_OPPTURBO_CNTRL_OFFSET, ++ .e2v_gain = 0, ++ .err_minlimit = AM33XX_SR1_OPPTURBO_EVM_ERR_MIN_LIMIT, ++ .err_maxlimit = AM33XX_SR1_OPPTURBO_ERR_MAX_LIMIT, ++ .err_weight = AM33XX_SR1_OPPTURBO_ERR_WEIGHT, ++ .margin = AM33XX_SR1_OPPTURBO_MARGIN, ++ .nominal_volt = AM33XX_ES2_0_VDD_MPU_OPPTURBO_UV, ++ .frequency = AM33XX_ES2_0_VDD_MPU_OPPTURBO_FREQ, ++ }, ++ { ++ /* NITRO can use the TURBO data, except for margin */ ++ .efuse_offs = AM33XX_SR1_OPPTURBO_CNTRL_OFFSET, ++ .e2v_gain = 0, ++ .err_minlimit = AM33XX_SR1_OPPTURBO_EVM_ERR_MIN_LIMIT, ++ .err_maxlimit = AM33XX_SR1_OPPTURBO_ERR_MAX_LIMIT, ++ .err_weight = AM33XX_SR1_OPPTURBO_ERR_WEIGHT, ++ .margin = AM33XX_SR1_OPPNITRO_MARGIN, ++ .nominal_volt = AM33XX_ES2_0_VDD_MPU_OPPNITRO_UV, ++ .frequency = AM33XX_ES2_0_VDD_MPU_OPPNITRO_FREQ, ++ }, ++}; + + static struct am33xx_sr_opp_data sr1_opp_data[] = { +- { +- .efuse_offs = AM33XX_SR1_OPP50_CNTRL_OFFSET, +- .e2v_gain = AM33XX_SR1_OPP50_EVM_ERR2VOLT_GAIN, +- .err_minlimit = AM33XX_SR1_OPP50_EVM_ERR_MIN_LIMIT, +- .err_maxlimit = AM33XX_SR1_OPP50_ERR_MAX_LIMIT, +- .err_weight = AM33XX_SR1_OPP50_ERR_WEIGHT, +- .margin = AM33XX_SR1_OPP50_MARGIN, +- .nominal_volt = AM33XX_VDD_MPU_OPP50_UV, +- .frequency = AM33XX_VDD_MPU_OPP50_FREQ, +- }, +- { +- .efuse_offs = AM33XX_SR1_OPP100_CNTRL_OFFSET, +- .e2v_gain = AM33XX_SR1_OPP100_EVM_ERR2VOLT_GAIN, +- .err_minlimit = AM33XX_SR1_OPP100_EVM_ERR_MIN_LIMIT, +- .err_maxlimit = AM33XX_SR1_OPP100_ERR_MAX_LIMIT, +- .err_weight = AM33XX_SR1_OPP100_ERR_WEIGHT, +- .margin = AM33XX_SR1_OPP100_MARGIN, +- .nominal_volt = AM33XX_VDD_MPU_OPP100_UV, +- .frequency = AM33XX_VDD_MPU_OPP100_FREQ, +- }, +- { +- .efuse_offs = AM33XX_SR1_OPP120_CNTRL_OFFSET, +- .e2v_gain = AM33XX_SR1_OPP120_EVM_ERR2VOLT_GAIN, +- .err_minlimit = AM33XX_SR1_OPP120_EVM_ERR_MIN_LIMIT, +- .err_maxlimit = AM33XX_SR1_OPP120_ERR_MAX_LIMIT, +- .err_weight = AM33XX_SR1_OPP120_ERR_WEIGHT, +- .margin = AM33XX_SR1_OPP120_MARGIN, +- .nominal_volt = AM33XX_VDD_MPU_OPP120_UV, +- .frequency = AM33XX_VDD_MPU_OPP120_FREQ, +- }, +- { +- .efuse_offs = AM33XX_SR1_OPPTURBO_CNTRL_OFFSET, +- .e2v_gain = AM33XX_SR1_OPPTURBO_EVM_ERR2VOLT_GAIN, +- .err_minlimit = AM33XX_SR1_OPPTURBO_EVM_ERR_MIN_LIMIT, +- .err_maxlimit = AM33XX_SR1_OPPTURBO_ERR_MAX_LIMIT, +- .err_weight = AM33XX_SR1_OPPTURBO_ERR_WEIGHT, +- .margin = AM33XX_SR1_OPPTURBO_MARGIN, +- .nominal_volt = AM33XX_VDD_MPU_OPPTURBO_UV, +- .frequency = AM33XX_VDD_MPU_OPPTURBO_FREQ, +- }, ++ { ++ .efuse_offs = AM33XX_SR1_OPP50_CNTRL_OFFSET, ++ .e2v_gain = 0, ++ .err_minlimit = AM33XX_SR1_OPP50_EVM_ERR_MIN_LIMIT, ++ .err_maxlimit = AM33XX_SR1_OPP50_ERR_MAX_LIMIT, ++ .err_weight = AM33XX_SR1_OPP50_ERR_WEIGHT, ++ .margin = AM33XX_SR1_OPP50_MARGIN, ++ .nominal_volt = AM33XX_VDD_MPU_OPP50_UV, ++ .frequency = AM33XX_VDD_MPU_OPP50_FREQ, ++ }, ++ { ++ .efuse_offs = AM33XX_SR1_OPP100_CNTRL_OFFSET, ++ .e2v_gain = 0, ++ .err_minlimit = AM33XX_SR1_OPP100_EVM_ERR_MIN_LIMIT, ++ .err_maxlimit = AM33XX_SR1_OPP100_ERR_MAX_LIMIT, ++ .err_weight = AM33XX_SR1_OPP100_ERR_WEIGHT, ++ .margin = AM33XX_SR1_OPP100_MARGIN, ++ .nominal_volt = AM33XX_VDD_MPU_OPP100_UV, ++ .frequency = AM33XX_VDD_MPU_OPP100_FREQ, ++ }, ++ { ++ .efuse_offs = AM33XX_SR1_OPP120_CNTRL_OFFSET, ++ .e2v_gain = 0, ++ .err_minlimit = AM33XX_SR1_OPP120_EVM_ERR_MIN_LIMIT, ++ .err_maxlimit = AM33XX_SR1_OPP120_ERR_MAX_LIMIT, ++ .err_weight = AM33XX_SR1_OPP120_ERR_WEIGHT, ++ .margin = AM33XX_SR1_OPP120_MARGIN, ++ .nominal_volt = AM33XX_VDD_MPU_OPP120_UV, ++ .frequency = AM33XX_VDD_MPU_OPP120_FREQ, ++ }, ++ { ++ .efuse_offs = AM33XX_SR1_OPPTURBO_CNTRL_OFFSET, ++ .e2v_gain = 0, ++ .err_minlimit = AM33XX_SR1_OPPTURBO_EVM_ERR_MIN_LIMIT, ++ .err_maxlimit = AM33XX_SR1_OPPTURBO_ERR_MAX_LIMIT, ++ .err_weight = AM33XX_SR1_OPPTURBO_ERR_WEIGHT, ++ .margin = AM33XX_SR1_OPPTURBO_MARGIN, ++ .nominal_volt = AM33XX_VDD_MPU_OPPTURBO_UV, ++ .frequency = AM33XX_VDD_MPU_OPPTURBO_FREQ, ++ }, + }; + + static struct am33xx_sr_opp_data sr0_opp_data[] = { +- { +- .efuse_offs = AM33XX_SR0_OPP50_CNTRL_OFFSET, +- .e2v_gain = AM33XX_SR0_OPP50_EVM_ERR2VOLT_GAIN, +- .err_minlimit = AM33XX_SR0_OPP50_EVM_ERR_MIN_LIMIT, +- .err_maxlimit = AM33XX_SR0_OPP50_ERR_MAX_LIMIT, +- .err_weight = AM33XX_SR0_OPP50_ERR_WEIGHT, +- .margin = AM33XX_SR0_OPP50_MARGIN, +- .nominal_volt = AM33XX_VDD_CORE_OPP50_UV, +- }, +- { +- .efuse_offs = AM33XX_SR0_OPP100_CNTRL_OFFSET, +- .e2v_gain = AM33XX_SR0_OPP100_EVM_ERR2VOLT_GAIN, +- .err_minlimit = AM33XX_SR0_OPP100_EVM_ERR_MIN_LIMIT, +- .err_maxlimit = AM33XX_SR0_OPP100_ERR_MAX_LIMIT, +- .err_weight = AM33XX_SR0_OPP100_ERR_WEIGHT, +- .margin = AM33XX_SR0_OPP100_MARGIN, +- .nominal_volt = AM33XX_VDD_CORE_OPP100_UV, +- }, ++ { ++ .efuse_offs = AM33XX_SR0_OPP50_CNTRL_OFFSET, ++ .e2v_gain = 0, ++ .err_minlimit = AM33XX_SR0_OPP50_EVM_ERR_MIN_LIMIT, ++ .err_maxlimit = AM33XX_SR0_OPP50_ERR_MAX_LIMIT, ++ .err_weight = AM33XX_SR0_OPP50_ERR_WEIGHT, ++ .margin = AM33XX_SR0_OPP50_MARGIN, ++ .nominal_volt = AM33XX_VDD_CORE_OPP50_UV, ++ }, ++ { ++ .efuse_offs = AM33XX_SR0_OPP100_CNTRL_OFFSET, ++ .e2v_gain = 0, ++ .err_minlimit = AM33XX_SR0_OPP100_EVM_ERR_MIN_LIMIT, ++ .err_maxlimit = AM33XX_SR0_OPP100_ERR_MAX_LIMIT, ++ .err_weight = AM33XX_SR0_OPP100_ERR_WEIGHT, ++ .margin = AM33XX_SR0_OPP100_MARGIN, ++ .nominal_volt = AM33XX_VDD_CORE_OPP100_UV, ++ }, ++}; ++ ++static struct am33xx_sr_sdata sr_sensor_data_2_0[] = { ++ { ++ .sr_opp_data = sr0_opp_data, ++ /* note that OPP50 is NOT used in Linux kernel for AM335x */ ++ .no_of_opps = 0x2, ++ .default_opp = 0x1, ++ .senn_mod = 0x1, ++ .senp_mod = 0x1, ++ }, ++ { ++ .sr_opp_data = sr1_opp_data_2_0, ++ /* the opp data below should be determined ++ dynamically during SR probe */ ++ .no_of_opps = 0x5, ++ .default_opp = 0x3, ++ .senn_mod = 0x1, ++ .senp_mod = 0x1, ++ }, + }; + + static struct am33xx_sr_sdata sr_sensor_data[] = { +- { +- .sr_opp_data = sr0_opp_data, +- /* note that OPP50 is NOT used in Linux kernel for AM335x */ +- .no_of_opps = 0x2, +- .default_opp = 0x1, +- .senn_mod = 0x1, +- .senp_mod = 0x1, +- }, +- { +- .sr_opp_data = sr1_opp_data, +- /* the opp data below should be determined +- dynamically during SR probe */ +- .no_of_opps = 0x4, +- .default_opp = 0x3, +- .senn_mod = 0x1, +- .senp_mod = 0x1, +- }, ++ { ++ .sr_opp_data = sr0_opp_data, ++ /* note that OPP50 is NOT used in Linux kernel for AM335x */ ++ .no_of_opps = 0x2, ++ .default_opp = 0x1, ++ .senn_mod = 0x1, ++ .senp_mod = 0x1, ++ }, ++ { ++ .sr_opp_data = sr1_opp_data, ++ /* the opp data below should be determined ++ dynamically during SR probe */ ++ .no_of_opps = 0x4, ++ .default_opp = 0x3, ++ .senn_mod = 0x1, ++ .senp_mod = 0x1, ++ }, + }; + + static struct am33xx_sr_platform_data am33xx_sr_pdata = { +- .vd_name[0] = "vdd_core", +- .vd_name[1] = "vdd_mpu", +- .ip_type = 2, +- .irq_delay = 1000, +- .no_of_vds = 2, +- .no_of_sens = ARRAY_SIZE(sr_sensor_data), +- .vstep_size_uv = 12500, +- .enable_on_init = true, +- .sr_sdata = sr_sensor_data, ++ .vd_name[0] = "vdd_core", ++ .vd_name[1] = "vdd_mpu", ++ .ip_type = 2, ++ .irq_delay = 1000, ++ .no_of_vds = 2, ++ .no_of_sens = ARRAY_SIZE(sr_sensor_data), ++ .vstep_size_uv = 12500, ++ .enable_on_init = true, ++ .sr_sdata = sr_sensor_data, + }; + + static struct resource am33xx_sr_resources[] = { +- { +- .name = "smartreflex0", +- .start = AM33XX_SR0_BASE, +- .end = AM33XX_SR0_BASE + SZ_4K - 1, +- .flags = IORESOURCE_MEM, +- }, +- { +- .name = "smartreflex0", +- .start = AM33XX_IRQ_SMARTREFLEX0, +- .end = AM33XX_IRQ_SMARTREFLEX0, +- .flags = IORESOURCE_IRQ, +- }, +- { +- .name = "smartreflex1", +- .start = AM33XX_SR1_BASE, +- .end = AM33XX_SR1_BASE + SZ_4K - 1, +- .flags = IORESOURCE_MEM, +- }, +- { +- .name = "smartreflex1", +- .start = AM33XX_IRQ_SMARTREFLEX1, +- .end = AM33XX_IRQ_SMARTREFLEX1, +- .flags = IORESOURCE_IRQ, +- }, ++ { ++ .name = "smartreflex0", ++ .start = AM33XX_SR0_BASE, ++ .end = AM33XX_SR0_BASE + SZ_4K - 1, ++ .flags = IORESOURCE_MEM, ++ }, ++ { ++ .name = "smartreflex0", ++ .start = AM33XX_IRQ_SMARTREFLEX0, ++ .end = AM33XX_IRQ_SMARTREFLEX0, ++ .flags = IORESOURCE_IRQ, ++ }, ++ { ++ .name = "smartreflex1", ++ .start = AM33XX_SR1_BASE, ++ .end = AM33XX_SR1_BASE + SZ_4K - 1, ++ .flags = IORESOURCE_MEM, ++ }, ++ { ++ .name = "smartreflex1", ++ .start = AM33XX_IRQ_SMARTREFLEX1, ++ .end = AM33XX_IRQ_SMARTREFLEX1, ++ .flags = IORESOURCE_IRQ, ++ }, + }; + + /* VCORE for SR regulator init */ + static struct platform_device am33xx_sr_device = { +- .name = "smartreflex", +- .id = -1, +- .num_resources = ARRAY_SIZE(am33xx_sr_resources), +- .resource = am33xx_sr_resources, +- .dev = { +- .platform_data = &am33xx_sr_pdata, +- }, ++ .name = "smartreflex", ++ .id = -1, ++ .num_resources = ARRAY_SIZE(am33xx_sr_resources), ++ .resource = am33xx_sr_resources, ++ .dev = { ++ .platform_data = &am33xx_sr_pdata, ++ }, + }; + + void __init am33xx_sr_init(void) + { +- /* For beaglebone, update voltage step size and related parameters +- appropriately. All other AM33XX platforms are good with the +- structure defaults as initialized above. */ +- if ((am33xx_evmid == BEAGLE_BONE_OLD) || +- (am33xx_evmid == BEAGLE_BONE_A3)) { +- printk(KERN_ERR "address of pdata = %08x\n", (u32)&am33xx_sr_pdata); +- am33xx_sr_pdata.vstep_size_uv = 25000; +- /* CORE */ +- sr0_opp_data[0].e2v_gain = AM33XX_SR0_OPP50_BB_ERR2VOLT_GAIN; +- sr0_opp_data[0].err_minlimit = AM33XX_SR0_OPP50_BB_ERR_MIN_LIMIT; +- sr0_opp_data[1].e2v_gain = AM33XX_SR0_OPP100_BB_ERR2VOLT_GAIN; +- sr0_opp_data[1].err_minlimit = AM33XX_SR0_OPP100_BB_ERR_MIN_LIMIT; +- /* MPU */ +- sr1_opp_data[0].e2v_gain = AM33XX_SR1_OPP50_BB_ERR2VOLT_GAIN; +- sr1_opp_data[0].err_minlimit = AM33XX_SR1_OPP50_BB_ERR_MIN_LIMIT; +- sr1_opp_data[1].e2v_gain = AM33XX_SR1_OPP100_BB_ERR2VOLT_GAIN; +- sr1_opp_data[1].err_minlimit = AM33XX_SR1_OPP100_BB_ERR_MIN_LIMIT; +- sr1_opp_data[2].e2v_gain = AM33XX_SR1_OPP120_BB_ERR2VOLT_GAIN; +- sr1_opp_data[2].err_minlimit = AM33XX_SR1_OPP120_BB_ERR_MIN_LIMIT; +- sr1_opp_data[3].e2v_gain = AM33XX_SR1_OPPTURBO_BB_ERR2VOLT_GAIN; +- sr1_opp_data[3].err_minlimit = AM33XX_SR1_OPPTURBO_BB_ERR_MIN_LIMIT; +- } +- +- if (platform_device_register(&am33xx_sr_device)) +- printk(KERN_ERR "failed to register am33xx_sr device\n"); +- else +- printk(KERN_INFO "registered am33xx_sr device\n"); ++ if (omap_rev() != AM335X_REV_ES1_0) ++ am33xx_sr_pdata.sr_sdata = sr_sensor_data_2_0; ++ ++ /* For beaglebone, update voltage step size and related parameters ++ appropriately. All other AM33XX platforms are good with the ++ structure defaults as initialized above. */ ++ if ((am33xx_evmid == BEAGLE_BONE_OLD) || ++ (am33xx_evmid == BEAGLE_BONE_A3)) { ++ printk(KERN_ERR "address of pdata = %08x\n", ++ (u32)&am33xx_sr_pdata); ++ ++ am33xx_sr_pdata.vstep_size_uv = 25000; ++ } ++ ++ if (platform_device_register(&am33xx_sr_device)) ++ printk(KERN_ERR "failed to register am33xx_sr device\n"); ++ else ++ printk(KERN_INFO "registered am33xx_sr device\n"); + } + #else + inline void am33xx_sr_init(void) {} +diff --git a/arch/arm/plat-omap/include/plat/smartreflex.h b/arch/arm/plat-omap/include/plat/smartreflex.h +index 76c1ff7..d837755 100644 +--- a/arch/arm/plat-omap/include/plat/smartreflex.h ++++ b/arch/arm/plat-omap/include/plat/smartreflex.h +@@ -238,14 +238,14 @@ int sr_register_class(struct omap_sr_class_data *class_data); + + #ifdef CONFIG_AM33XX_SMARTREFLEX + +-#define SR_CORE (0) +-#define SR_MPU (1) ++#define SR_CORE (0) ++#define SR_MPU (1) + #define SRCLKLENGTH_125MHZ_SYSCLK (0x78 << 12) +-#define GAIN_MAXLIMIT (16) +-#define R_MAXLIMIT (256) +-#define MAX_SENSORS 2 ++#define GAIN_MAXLIMIT (16) ++#define R_MAXLIMIT (256) ++#define MAX_SENSORS (2) + /* GG: eventually this should be determined at runtime */ +-#define AM33XX_OPP_COUNT 4 ++#define AM33XX_OPP_COUNT (5) + + /** + * struct am33xx_sr_opp_data - Smartreflex data per OPP +@@ -264,17 +264,17 @@ int sr_register_class(struct omap_sr_class_data *class_data); + */ + struct am33xx_sr_opp_data { + u32 efuse_offs; +- u32 nvalue; +- u32 adj_nvalue; ++ u32 nvalue; ++ u32 adj_nvalue; + s32 e2v_gain; + u32 err_weight; + u32 err_minlimit; + u32 err_maxlimit; +- s32 margin; +- u32 nominal_volt; /* nominal_volt and frequency may be removed +- once am33xx voltdm layer works */ +- u32 frequency; +- u32 opp_id; ++ s32 margin; ++ u32 nominal_volt; /* nominal_volt and frequency may be removed ++ once am33xx voltdm layer works */ ++ u32 frequency; ++ u32 opp_id; + }; + + /** +@@ -290,50 +290,54 @@ struct am33xx_sr_opp_data { + */ + struct am33xx_sr_sdata { + struct am33xx_sr_opp_data *sr_opp_data; +- u32 no_of_opps; +- u32 default_opp; ++ u32 no_of_opps; ++ u32 default_opp; + u32 senn_mod; + u32 senp_mod; + }; + + struct am33xx_sr_sensor { +- u32 sr_id; ++ u32 sr_id; + u32 irq; + u32 irq_status; + u32 senn_en; + u32 senp_en; + char *name; +- char *reg_name; ++ char *reg_name; + void __iomem *base; +- int init_volt_mv; +- int curr_opp; +- u32 no_of_opps; +- struct delayed_work work_reenable; +- struct regulator *reg; +- struct am33xx_sr_opp_data opp_data[AM33XX_OPP_COUNT]; ++ int init_volt_mv; ++ int curr_opp; ++ u32 no_of_opps; ++ int state; ++ s8 avg_error_nom; ++ int saved_volt; ++ struct delayed_work work_reenable; ++ struct regulator *reg; ++ struct am33xx_sr_opp_data opp_data[AM33XX_OPP_COUNT]; + struct clk *fck; +- struct voltagedomain *voltdm; +- struct omap_volt_data *volt_data; ++ struct voltagedomain *voltdm; ++ struct omap_volt_data *volt_data; + }; + + struct am33xx_sr { +- u32 autocomp_active; ++ bool autocomp_active; ++ bool is_suspended; + u32 sens_per_vd; +- u32 no_of_sens; +- u32 no_of_vds; ++ u32 no_of_sens; ++ u32 no_of_vds; + u32 ip_type; +- u32 irq_delay; +- u32 disabled_by_user; ++ u32 irq_delay; ++ bool disabled_by_user; + int uvoltage_step_size; +- char *res_name[MAX_SENSORS]; ++ char *res_name[MAX_SENSORS]; + #ifdef CONFIG_CPU_FREQ + struct notifier_block freq_transition; + #endif +- /*struct work_struct work;*/ +- struct delayed_work work; ++ struct delayed_work work; + struct sr_platform_data *sr_data; + struct am33xx_sr_sensor sen[MAX_SENSORS]; + struct platform_device *pdev; ++ struct list_head node; + }; + + /** +@@ -354,7 +358,7 @@ struct am33xx_sr_platform_data { + struct am33xx_sr_sdata *sr_sdata; + char *vd_name[2]; + u32 ip_type; +- u32 irq_delay; ++ u32 irq_delay; + u32 no_of_vds; + u32 no_of_sens; + u32 vstep_size_uv; +-- +1.7.9.5 + diff --git a/recipes-kernel/linux/linux-am335x-psp_3.2.bb b/recipes-kernel/linux/linux-am335x-psp_3.2.bb index 7fd69353..958bba5a 100644 --- a/recipes-kernel/linux/linux-am335x-psp_3.2.bb +++ b/recipes-kernel/linux/linux-am335x-psp_3.2.bb @@ -15,7 +15,7 @@ DEPENDS += "am33x-cm3" KERNEL_IMAGETYPE = "uImage" # The main PR is now using MACHINE_KERNEL_PR, for ti33x see conf/machine/include/ti33x.inc -MACHINE_KERNEL_PR_append = "e+gitr${SRCPV}" +MACHINE_KERNEL_PR_append = "f+gitr${SRCPV}" BRANCH = "v3.2-staging" @@ -68,6 +68,7 @@ PATCHES += "file://0001-am33x-Add-memory-addresses-for-crypto-modules.patch \ PATCHES += "file://0001-am33xx-Add-SmartReflex-support.patch \ file://0002-am33xx-Enable-CONFIG_AM33XX_SMARTREFLEX.patch \ file://0002-Smartreflex-limited-to-ES-1.0.patch \ + file://0001-Smartreflex-support-for-ES-2.x-and-suspend-resume.patch \ " # Add a patch to the omap-serial driver to allow suspend/resume during -- cgit v1.2.3-54-g00ecf