1 From: Kalle Jokiniemi <ext-kalle.jokiniemi@nokia.com>
2 To: linux-omap@vger.kernel.org
3 Cc: Kalle Jokiniemi <ext-kalle.jokiniemi@nokia.com>
4 Subject: [PATCH 1/3] ARM: OMAP: SmartReflex driver, reference source and header files
5 Date: Mon, 2 Jun 2008 14:30:12 +0300
7 The following patch set integrates TI's SmartReflex driver. SmartReflex is a
8 module that adjusts OMAP3 VDD1 and VDD2 operating voltages around the nominal
9 values of current operating point depending on silicon characteristics and
12 The driver creates two sysfs entries into /sys/power/ named "sr_vdd1_autocomp"
13 and "sr_vdd2_autocomp" which can be used to activate SmartReflex modules 1 and
16 Use the following commands to enable SmartReflex:
18 echo -n 1 > /sys/power/sr_vdd1_autocomp
19 echo -n 1 > /sys/power/sr_vdd2_autocomp
23 echo -n 0 > /sys/power/sr_vdd1_autocomp
24 echo -n 0 > /sys/power/sr_vdd2_autocomp
26 This particular patch adds the TI reference source and header files for
27 SmartReflex. Only modifications include minor styling to pass checkpatch.pl
30 Signed-off-by: Kalle Jokiniemi <ext-kalle.jokiniemi@nokia.com>
32 arch/arm/mach-omap2/smartreflex.c | 815 +++++++++++++++++++++++++++++++++++++
33 arch/arm/mach-omap2/smartreflex.h | 136 ++++++
34 2 files changed, 951 insertions(+), 0 deletions(-)
35 create mode 100644 arch/arm/mach-omap2/smartreflex.c
36 create mode 100644 arch/arm/mach-omap2/smartreflex.h
38 diff --git a/arch/arm/mach-omap2/smartreflex.c b/arch/arm/mach-omap2/smartreflex.c
40 index 0000000..dae7460
42 +++ b/arch/arm/mach-omap2/smartreflex.c
45 + * linux/arch/arm/mach-omap3/smartreflex.c
47 + * OMAP34XX SmartReflex Voltage Control
49 + * Copyright (C) 2007 Texas Instruments, Inc.
50 + * Lesly A M <x0080970@ti.com>
52 + * This program is free software; you can redistribute it and/or modify
53 + * it under the terms of the GNU General Public License version 2 as
54 + * published by the Free Software Foundation.
58 +#include <linux/kernel.h>
59 +#include <linux/init.h>
60 +#include <linux/interrupt.h>
61 +#include <linux/module.h>
62 +#include <linux/delay.h>
63 +#include <linux/err.h>
64 +#include <linux/clk.h>
65 +#include <linux/sysfs.h>
67 +#include <asm/arch/prcm.h>
68 +#include <asm/arch/power_companion.h>
69 +#include <linux/io.h>
71 +#include "prcm-regs.h"
72 +#include "smartreflex.h"
75 +/* #define DEBUG_SR 1 */
77 +# define DPRINTK(fmt, args...) printk(KERN_ERR "%s: " fmt, __func__ ,\
80 +# define DPRINTK(fmt, args...)
86 + int is_autocomp_active;
89 + u32 opp1_nvalue, opp2_nvalue, opp3_nvalue, opp4_nvalue, opp5_nvalue;
90 + u32 senp_mod, senn_mod;
95 +static struct omap_sr sr1 = {
98 + .is_autocomp_active = 0,
99 + .srbase_addr = OMAP34XX_SR1_BASE,
102 +static struct omap_sr sr2 = {
105 + .is_autocomp_active = 0,
106 + .srbase_addr = OMAP34XX_SR2_BASE,
109 +static inline void sr_write_reg(struct omap_sr *sr, int offset, u32 value)
111 + omap_writel(value, sr->srbase_addr + offset);
114 +static inline void sr_modify_reg(struct omap_sr *sr, int offset, u32 mask,
119 + reg_val = omap_readl(sr->srbase_addr + offset);
123 + omap_writel(reg_val, sr->srbase_addr + offset);
126 +static inline u32 sr_read_reg(struct omap_sr *sr, int offset)
128 + return omap_readl(sr->srbase_addr + offset);
132 +#ifndef USE_EFUSE_VALUES
133 +static void cal_reciprocal(u32 sensor, u32 *sengain, u32 *rnsen)
137 + for (gn = 0; gn < GAIN_MAXLIMIT; gn++) {
138 + mul = 1 << (gn + 8);
140 + if (rn < R_MAXLIMIT) {
148 +static int sr_clk_enable(struct omap_sr *sr)
150 + if (clk_enable(sr->fck) != 0) {
151 + printk(KERN_ERR "Could not enable sr%d_fck\n", sr->srid);
152 + goto clk_enable_err;
155 + /* set fclk- active , iclk- idle */
156 + sr_modify_reg(sr, ERRCONFIG, SR_CLKACTIVITY_MASK,
157 + SR_CLKACTIVITY_IOFF_FON);
165 +static int sr_clk_disable(struct omap_sr *sr)
167 + /* set fclk, iclk- idle */
168 + sr_modify_reg(sr, ERRCONFIG, SR_CLKACTIVITY_MASK,
169 + SR_CLKACTIVITY_IOFF_FOFF);
171 + clk_disable(sr->fck);
172 + sr->is_sr_reset = 1;
177 +static void sr_set_nvalues(struct omap_sr *sr)
179 +#ifdef USE_EFUSE_VALUES
182 + u32 senpval, sennval;
183 + u32 senpgain, senngain;
184 + u32 rnsenp, rnsenn;
187 + if (sr->srid == SR1) {
188 +#ifdef USE_EFUSE_VALUES
189 + /* Read values for VDD1 from EFUSE */
191 + /* since E-Fuse Values are not available, calculating the
192 + * reciprocal of the SenN and SenP values for SR1
194 + sr->senp_mod = 0x03; /* SenN-M5 enabled */
195 + sr->senn_mod = 0x03;
198 + senpval = 0x848 + 0x330;
199 + sennval = 0xacd + 0x330;
201 + cal_reciprocal(senpval, &senpgain, &rnsenp);
202 + cal_reciprocal(sennval, &senngain, &rnsenn);
205 + ((senpgain << NVALUERECIPROCAL_SENPGAIN_SHIFT) |
206 + (senngain << NVALUERECIPROCAL_SENNGAIN_SHIFT) |
207 + (rnsenp << NVALUERECIPROCAL_RNSENP_SHIFT) |
208 + (rnsenn << NVALUERECIPROCAL_RNSENN_SHIFT));
211 + senpval = 0x727 + 0x2a0;
212 + sennval = 0x964 + 0x2a0;
214 + cal_reciprocal(senpval, &senpgain, &rnsenp);
215 + cal_reciprocal(sennval, &senngain, &rnsenn);
218 + ((senpgain << NVALUERECIPROCAL_SENPGAIN_SHIFT) |
219 + (senngain << NVALUERECIPROCAL_SENNGAIN_SHIFT) |
220 + (rnsenp << NVALUERECIPROCAL_RNSENP_SHIFT) |
221 + (rnsenn << NVALUERECIPROCAL_RNSENN_SHIFT));
224 + senpval = 0x655 + 0x200;
225 + sennval = 0x85b + 0x200;
227 + cal_reciprocal(senpval, &senpgain, &rnsenp);
228 + cal_reciprocal(sennval, &senngain, &rnsenn);
231 + ((senpgain << NVALUERECIPROCAL_SENPGAIN_SHIFT) |
232 + (senngain << NVALUERECIPROCAL_SENNGAIN_SHIFT) |
233 + (rnsenp << NVALUERECIPROCAL_RNSENP_SHIFT) |
234 + (rnsenn << NVALUERECIPROCAL_RNSENN_SHIFT));
237 + senpval = 0x3be + 0x1a0;
238 + sennval = 0x506 + 0x1a0;
240 + cal_reciprocal(senpval, &senpgain, &rnsenp);
241 + cal_reciprocal(sennval, &senngain, &rnsenn);
244 + ((senpgain << NVALUERECIPROCAL_SENPGAIN_SHIFT) |
245 + (senngain << NVALUERECIPROCAL_SENNGAIN_SHIFT) |
246 + (rnsenp << NVALUERECIPROCAL_RNSENP_SHIFT) |
247 + (rnsenn << NVALUERECIPROCAL_RNSENN_SHIFT));
250 + senpval = 0x28c + 0x100;
251 + sennval = 0x373 + 0x100;
253 + cal_reciprocal(senpval, &senpgain, &rnsenp);
254 + cal_reciprocal(sennval, &senngain, &rnsenn);
257 + ((senpgain << NVALUERECIPROCAL_SENPGAIN_SHIFT) |
258 + (senngain << NVALUERECIPROCAL_SENNGAIN_SHIFT) |
259 + (rnsenp << NVALUERECIPROCAL_RNSENP_SHIFT) |
260 + (rnsenn << NVALUERECIPROCAL_RNSENN_SHIFT));
263 + sr_write_reg(sr, NVALUERECIPROCAL, sr->opp3_nvalue);
264 + sr_clk_disable(sr);
267 + } else if (sr->srid == SR2) {
268 +#ifdef USE_EFUSE_VALUES
269 + /* Read values for VDD2 from EFUSE */
271 + /* since E-Fuse Values are not available, calculating the
272 + * reciprocal of the SenN and SenP values for SR2
274 + sr->senp_mod = 0x03;
275 + sr->senn_mod = 0x03;
278 + senpval = 0x579 + 0x200;
279 + sennval = 0x76f + 0x200;
281 + cal_reciprocal(senpval, &senpgain, &rnsenp);
282 + cal_reciprocal(sennval, &senngain, &rnsenn);
285 + ((senpgain << NVALUERECIPROCAL_SENPGAIN_SHIFT) |
286 + (senngain << NVALUERECIPROCAL_SENNGAIN_SHIFT) |
287 + (rnsenp << NVALUERECIPROCAL_RNSENP_SHIFT) |
288 + (rnsenn << NVALUERECIPROCAL_RNSENN_SHIFT));
291 + senpval = 0x390 + 0x1c0;
292 + sennval = 0x4f5 + 0x1c0;
294 + cal_reciprocal(senpval, &senpgain, &rnsenp);
295 + cal_reciprocal(sennval, &senngain, &rnsenn);
298 + ((senpgain << NVALUERECIPROCAL_SENPGAIN_SHIFT) |
299 + (senngain << NVALUERECIPROCAL_SENNGAIN_SHIFT) |
300 + (rnsenp << NVALUERECIPROCAL_RNSENP_SHIFT) |
301 + (rnsenn << NVALUERECIPROCAL_RNSENN_SHIFT));
307 + cal_reciprocal(senpval, &senpgain, &rnsenp);
308 + cal_reciprocal(sennval, &senngain, &rnsenn);
311 + ((senpgain << NVALUERECIPROCAL_SENPGAIN_SHIFT) |
312 + (senngain << NVALUERECIPROCAL_SENNGAIN_SHIFT) |
313 + (rnsenp << NVALUERECIPROCAL_RNSENP_SHIFT) |
314 + (rnsenn << NVALUERECIPROCAL_RNSENN_SHIFT));
321 +static void sr_configure_vp(int srid)
326 + vpconfig = PRM_VP1_CONFIG_ERROROFFSET | PRM_VP1_CONFIG_ERRORGAIN
327 + | PRM_VP1_CONFIG_INITVOLTAGE | PRM_VP1_CONFIG_TIMEOUTEN;
329 + PRM_VP1_CONFIG = vpconfig;
330 + PRM_VP1_VSTEPMIN = PRM_VP1_VSTEPMIN_SMPSWAITTIMEMIN |
331 + PRM_VP1_VSTEPMIN_VSTEPMIN;
333 + PRM_VP1_VSTEPMAX = PRM_VP1_VSTEPMAX_SMPSWAITTIMEMAX |
334 + PRM_VP1_VSTEPMAX_VSTEPMAX;
336 + PRM_VP1_VLIMITTO = PRM_VP1_VLIMITTO_VDDMAX |
337 + PRM_VP1_VLIMITTO_VDDMIN | PRM_VP1_VLIMITTO_TIMEOUT;
339 + PRM_VP1_CONFIG |= PRM_VP1_CONFIG_INITVDD;
340 + PRM_VP1_CONFIG &= ~PRM_VP1_CONFIG_INITVDD;
342 + } else if (srid == SR2) {
343 + vpconfig = PRM_VP2_CONFIG_ERROROFFSET | PRM_VP2_CONFIG_ERRORGAIN
344 + | PRM_VP2_CONFIG_INITVOLTAGE | PRM_VP2_CONFIG_TIMEOUTEN;
346 + PRM_VP2_CONFIG = vpconfig;
347 + PRM_VP2_VSTEPMIN = PRM_VP2_VSTEPMIN_SMPSWAITTIMEMIN |
348 + PRM_VP2_VSTEPMIN_VSTEPMIN;
350 + PRM_VP2_VSTEPMAX = PRM_VP2_VSTEPMAX_SMPSWAITTIMEMAX |
351 + PRM_VP2_VSTEPMAX_VSTEPMAX;
353 + PRM_VP2_VLIMITTO = PRM_VP2_VLIMITTO_VDDMAX |
354 + PRM_VP2_VLIMITTO_VDDMIN | PRM_VP2_VLIMITTO_TIMEOUT;
356 + PRM_VP2_CONFIG |= PRM_VP2_CONFIG_INITVDD;
357 + PRM_VP2_CONFIG &= ~PRM_VP2_CONFIG_INITVDD;
362 +static void sr_configure_vc(void)
365 + (R_SRI2C_SLAVE_ADDR << PRM_VC_SMPS_SA1_SHIFT) |
366 + (R_SRI2C_SLAVE_ADDR << PRM_VC_SMPS_SA0_SHIFT);
368 + PRM_VC_SMPS_VOL_RA = (R_VDD2_SR_CONTROL << PRM_VC_SMPS_VOLRA1_SHIFT) |
369 + (R_VDD1_SR_CONTROL << PRM_VC_SMPS_VOLRA0_SHIFT);
371 + PRM_VC_CMD_VAL_0 = (PRM_VC_CMD_VAL0_ON << PRM_VC_CMD_ON_SHIFT) |
372 + (PRM_VC_CMD_VAL0_ONLP << PRM_VC_CMD_ONLP_SHIFT) |
373 + (PRM_VC_CMD_VAL0_RET << PRM_VC_CMD_RET_SHIFT) |
374 + (PRM_VC_CMD_VAL0_OFF << PRM_VC_CMD_OFF_SHIFT);
376 + PRM_VC_CMD_VAL_1 = (PRM_VC_CMD_VAL1_ON << PRM_VC_CMD_ON_SHIFT) |
377 + (PRM_VC_CMD_VAL1_ONLP << PRM_VC_CMD_ONLP_SHIFT) |
378 + (PRM_VC_CMD_VAL1_RET << PRM_VC_CMD_RET_SHIFT) |
379 + (PRM_VC_CMD_VAL1_OFF << PRM_VC_CMD_OFF_SHIFT);
381 + PRM_VC_CH_CONF = PRM_VC_CH_CONF_CMD1 | PRM_VC_CH_CONF_RAV1;
383 + PRM_VC_I2C_CFG = PRM_VC_I2C_CFG_MCODE | PRM_VC_I2C_CFG_HSEN
384 + | PRM_VC_I2C_CFG_SREN;
386 + /* Setup voltctrl and other setup times */
387 +#ifdef CONFIG_SYSOFFMODE
388 + PRM_VOLTCTRL = PRM_VOLTCTRL_AUTO_OFF | PRM_VOLTCTRL_AUTO_RET;
389 + PRM_CLKSETUP = PRM_CLKSETUP_DURATION;
390 + PRM_VOLTSETUP1 = (PRM_VOLTSETUP_TIME2 << PRM_VOLTSETUP_TIME2_OFFSET) |
391 + (PRM_VOLTSETUP_TIME1 << PRM_VOLTSETUP_TIME1_OFFSET);
392 + PRM_VOLTOFFSET = PRM_VOLTOFFSET_DURATION;
393 + PRM_VOLTSETUP2 = PRM_VOLTSETUP2_DURATION;
395 + PRM_VOLTCTRL |= PRM_VOLTCTRL_AUTO_RET;
401 +static void sr_configure(struct omap_sr *sr)
403 + u32 sys_clk, sr_clk_length = 0;
405 + u32 senp_en , senn_en;
407 + senp_en = sr->senp_mod;
408 + senn_en = sr->senn_mod;
410 + sys_clk = prcm_get_system_clock_speed();
414 + sr_clk_length = SRCLKLENGTH_12MHZ_SYSCLK;
417 + sr_clk_length = SRCLKLENGTH_13MHZ_SYSCLK;
420 + sr_clk_length = SRCLKLENGTH_19MHZ_SYSCLK;
423 + sr_clk_length = SRCLKLENGTH_26MHZ_SYSCLK;
426 + sr_clk_length = SRCLKLENGTH_38MHZ_SYSCLK;
429 + printk(KERN_ERR "Invalid sysclk value\n");
433 + DPRINTK(KERN_DEBUG "SR : sys clk %lu\n", sys_clk);
434 + if (sr->srid == SR1) {
435 + sr_config = SR1_SRCONFIG_ACCUMDATA |
436 + (sr_clk_length << SRCONFIG_SRCLKLENGTH_SHIFT) |
437 + SRCONFIG_SENENABLE | SRCONFIG_ERRGEN_EN |
438 + SRCONFIG_MINMAXAVG_EN |
439 + (senn_en << SRCONFIG_SENNENABLE_SHIFT) |
440 + (senp_en << SRCONFIG_SENPENABLE_SHIFT) |
441 + SRCONFIG_DELAYCTRL;
443 + sr_write_reg(sr, SRCONFIG, sr_config);
445 + sr_write_reg(sr, AVGWEIGHT, SR1_AVGWEIGHT_SENPAVGWEIGHT |
446 + SR1_AVGWEIGHT_SENNAVGWEIGHT);
448 + sr_modify_reg(sr, ERRCONFIG, (SR_ERRWEIGHT_MASK |
449 + SR_ERRMAXLIMIT_MASK | SR_ERRMINLIMIT_MASK),
450 + (SR1_ERRWEIGHT | SR1_ERRMAXLIMIT | SR1_ERRMINLIMIT));
452 + } else if (sr->srid == SR2) {
453 + sr_config = SR2_SRCONFIG_ACCUMDATA |
454 + (sr_clk_length << SRCONFIG_SRCLKLENGTH_SHIFT) |
455 + SRCONFIG_SENENABLE | SRCONFIG_ERRGEN_EN |
456 + SRCONFIG_MINMAXAVG_EN |
457 + (senn_en << SRCONFIG_SENNENABLE_SHIFT) |
458 + (senp_en << SRCONFIG_SENPENABLE_SHIFT) |
459 + SRCONFIG_DELAYCTRL;
461 + sr_write_reg(sr, SRCONFIG, sr_config);
463 + sr_write_reg(sr, AVGWEIGHT, SR2_AVGWEIGHT_SENPAVGWEIGHT |
464 + SR2_AVGWEIGHT_SENNAVGWEIGHT);
466 + sr_modify_reg(sr, ERRCONFIG, (SR_ERRWEIGHT_MASK |
467 + SR_ERRMAXLIMIT_MASK | SR_ERRMINLIMIT_MASK),
468 + (SR2_ERRWEIGHT | SR2_ERRMAXLIMIT | SR2_ERRMINLIMIT));
471 + sr->is_sr_reset = 0;
474 +static void sr_enable(struct omap_sr *sr, u32 target_opp_no)
476 + u32 nvalue_reciprocal, current_nvalue;
478 + sr->req_opp_no = target_opp_no;
480 + if (sr->srid == SR1) {
481 + switch (target_opp_no) {
483 + nvalue_reciprocal = sr->opp5_nvalue;
486 + nvalue_reciprocal = sr->opp4_nvalue;
489 + nvalue_reciprocal = sr->opp3_nvalue;
492 + nvalue_reciprocal = sr->opp2_nvalue;
495 + nvalue_reciprocal = sr->opp1_nvalue;
498 + nvalue_reciprocal = sr->opp3_nvalue;
502 + switch (target_opp_no) {
504 + nvalue_reciprocal = sr->opp3_nvalue;
507 + nvalue_reciprocal = sr->opp2_nvalue;
510 + nvalue_reciprocal = sr->opp1_nvalue;
513 + nvalue_reciprocal = sr->opp3_nvalue;
518 + current_nvalue = sr_read_reg(sr, NVALUERECIPROCAL);
520 + if (current_nvalue == nvalue_reciprocal) {
521 + DPRINTK("System is already at the desired voltage level\n");
525 + sr_write_reg(sr, NVALUERECIPROCAL, nvalue_reciprocal);
527 + /* Enable the interrupt */
528 + sr_modify_reg(sr, ERRCONFIG,
529 + (ERRCONFIG_VPBOUNDINTEN | ERRCONFIG_VPBOUNDINTST),
530 + (ERRCONFIG_VPBOUNDINTEN | ERRCONFIG_VPBOUNDINTST));
532 + if (sr->srid == SR1) {
534 + PRM_VP1_CONFIG |= PRM_VP1_CONFIG_VPENABLE;
535 + } else if (sr->srid == SR2) {
537 + PRM_VP2_CONFIG |= PRM_VP2_CONFIG_VPENABLE;
540 + /* SRCONFIG - enable SR */
541 + sr_modify_reg(sr, SRCONFIG, SRCONFIG_SRENABLE, SRCONFIG_SRENABLE);
545 +static void sr_disable(struct omap_sr *sr)
547 + sr->is_sr_reset = 1;
549 + /* SRCONFIG - disable SR */
550 + sr_modify_reg(sr, SRCONFIG, SRCONFIG_SRENABLE, ~SRCONFIG_SRENABLE);
552 + if (sr->srid == SR1) {
554 + PRM_VP1_CONFIG &= ~PRM_VP1_CONFIG_VPENABLE;
555 + } else if (sr->srid == SR2) {
557 + PRM_VP2_CONFIG &= ~PRM_VP2_CONFIG_VPENABLE;
562 +void sr_start_vddautocomap(int srid, u32 target_opp_no)
564 + struct omap_sr *sr = NULL;
568 + else if (srid == SR2)
571 + if (sr->is_sr_reset == 1) {
576 + if (sr->is_autocomp_active == 1)
577 + DPRINTK(KERN_WARNING "SR%d: VDD autocomp is already active\n",
580 + sr->is_autocomp_active = 1;
581 + sr_enable(sr, target_opp_no);
583 +EXPORT_SYMBOL(sr_start_vddautocomap);
585 +int sr_stop_vddautocomap(int srid)
587 + struct omap_sr *sr = NULL;
591 + else if (srid == SR2)
594 + if (sr->is_autocomp_active == 1) {
596 + sr_clk_disable(sr);
597 + sr->is_autocomp_active = 0;
600 + DPRINTK(KERN_WARNING "SR%d: VDD autocomp is not active\n",
606 +EXPORT_SYMBOL(sr_stop_vddautocomap);
608 +void enable_smartreflex(int srid)
610 + u32 target_opp_no = 0;
611 + struct omap_sr *sr = NULL;
615 + else if (srid == SR2)
618 + if (sr->is_autocomp_active == 1) {
619 + if (sr->is_sr_reset == 1) {
621 + /* Enable SR clks */
622 + CM_FCLKEN_WKUP |= SR1_CLK_ENABLE;
623 + target_opp_no = get_opp_no(current_vdd1_opp);
625 + } else if (srid == SR2) {
626 + /* Enable SR clks */
627 + CM_FCLKEN_WKUP |= SR2_CLK_ENABLE;
628 + target_opp_no = get_opp_no(current_vdd2_opp);
633 + sr_enable(sr, target_opp_no);
638 +void disable_smartreflex(int srid)
640 + struct omap_sr *sr = NULL;
644 + else if (srid == SR2)
647 + if (sr->is_autocomp_active == 1) {
649 + /* Enable SR clk */
650 + CM_FCLKEN_WKUP |= SR1_CLK_ENABLE;
652 + } else if (srid == SR2) {
653 + /* Enable SR clk */
654 + CM_FCLKEN_WKUP |= SR2_CLK_ENABLE;
657 + if (sr->is_sr_reset == 0) {
659 + sr->is_sr_reset = 1;
660 + /* SRCONFIG - disable SR */
661 + sr_modify_reg(sr, SRCONFIG, SRCONFIG_SRENABLE,
662 + ~SRCONFIG_SRENABLE);
664 + if (sr->srid == SR1) {
665 + /* Disable SR clk */
666 + CM_FCLKEN_WKUP &= ~SR1_CLK_ENABLE;
668 + PRM_VP1_CONFIG &= ~PRM_VP1_CONFIG_VPENABLE;
670 + } else if (sr->srid == SR2) {
671 + /* Disable SR clk */
672 + CM_FCLKEN_WKUP &= ~SR2_CLK_ENABLE;
674 + PRM_VP2_CONFIG &= ~PRM_VP2_CONFIG_VPENABLE;
681 +/* Voltage Scaling using SR VCBYPASS */
682 +int sr_voltagescale_vcbypass(u32 target_opp, u8 vsel)
686 + u32 vdd, target_opp_no;
687 + u32 vc_bypass_value;
689 + u32 loop_cnt = 0, retries_cnt = 0;
691 + vdd = get_vdd(target_opp);
692 + target_opp_no = get_opp_no(target_opp);
694 + if (vdd == PRCM_VDD1) {
695 + sr_status = sr_stop_vddautocomap(SR1);
697 + PRM_VC_CMD_VAL_0 = (PRM_VC_CMD_VAL_0 & ~PRM_VC_CMD_ON_MASK) |
698 + (vsel << PRM_VC_CMD_ON_SHIFT);
699 + reg_addr = R_VDD1_SR_CONTROL;
701 + } else if (vdd == PRCM_VDD2) {
702 + sr_status = sr_stop_vddautocomap(SR2);
704 + PRM_VC_CMD_VAL_1 = (PRM_VC_CMD_VAL_1 & ~PRM_VC_CMD_ON_MASK) |
705 + (vsel << PRM_VC_CMD_ON_SHIFT);
706 + reg_addr = R_VDD2_SR_CONTROL;
709 + vc_bypass_value = (vsel << PRM_VC_BYPASS_DATA_SHIFT) |
710 + (reg_addr << PRM_VC_BYPASS_REGADDR_SHIFT) |
711 + (R_SRI2C_SLAVE_ADDR << PRM_VC_BYPASS_SLAVEADDR_SHIFT);
713 + PRM_VC_BYPASS_VAL = vc_bypass_value;
715 + PRM_VC_BYPASS_VAL |= PRM_VC_BYPASS_VALID;
717 + DPRINTK("%s : PRM_VC_BYPASS_VAL %X\n", __func__, PRM_VC_BYPASS_VAL);
718 + DPRINTK("PRM_IRQST_MPU %X\n", PRM_IRQSTATUS_MPU);
720 + while ((PRM_VC_BYPASS_VAL & PRM_VC_BYPASS_VALID) != 0x0) {
721 + ret = loop_wait(&loop_cnt, &retries_cnt, 10);
722 + if (ret != PRCM_PASS) {
723 + printk(KERN_INFO "Loop count exceeded in check SR I2C"
729 + omap_udelay(T2_SMPS_UPDATE_DELAY);
732 + if (vdd == PRCM_VDD1)
733 + sr_start_vddautocomap(SR1, target_opp_no);
734 + else if (vdd == PRCM_VDD2)
735 + sr_start_vddautocomap(SR2, target_opp_no);
741 +/* Sysfs interface to select SR VDD1 auto compensation */
742 +static ssize_t omap_sr_vdd1_autocomp_show(struct kset *subsys, char *buf)
744 + return sprintf(buf, "%d\n", sr1.is_autocomp_active);
747 +static ssize_t omap_sr_vdd1_autocomp_store(struct kset *subsys,
748 + const char *buf, size_t n)
750 + u32 current_vdd1opp_no;
751 + unsigned short value;
753 + if (sscanf(buf, "%hu", &value) != 1 || (value > 1)) {
754 + printk(KERN_ERR "sr_vdd1_autocomp: Invalid value\n");
758 + current_vdd1opp_no = get_opp_no(current_vdd1_opp);
761 + sr_stop_vddautocomap(SR1);
763 + sr_start_vddautocomap(SR1, current_vdd1opp_no);
768 +static struct subsys_attribute sr_vdd1_autocomp = {
770 + .name = __stringify(sr_vdd1_autocomp),
773 + .show = omap_sr_vdd1_autocomp_show,
774 + .store = omap_sr_vdd1_autocomp_store,
777 +/* Sysfs interface to select SR VDD2 auto compensation */
778 +static ssize_t omap_sr_vdd2_autocomp_show(struct kset *subsys, char *buf)
780 + return sprintf(buf, "%d\n", sr2.is_autocomp_active);
783 +static ssize_t omap_sr_vdd2_autocomp_store(struct kset *subsys,
784 + const char *buf, size_t n)
786 + u32 current_vdd2opp_no;
787 + unsigned short value;
789 + if (sscanf(buf, "%hu", &value) != 1 || (value > 1)) {
790 + printk(KERN_ERR "sr_vdd2_autocomp: Invalid value\n");
794 + current_vdd2opp_no = get_opp_no(current_vdd2_opp);
797 + sr_stop_vddautocomap(SR2);
799 + sr_start_vddautocomap(SR2, current_vdd2opp_no);
804 +static struct subsys_attribute sr_vdd2_autocomp = {
806 + .name = __stringify(sr_vdd2_autocomp),
809 + .show = omap_sr_vdd2_autocomp_show,
810 + .store = omap_sr_vdd2_autocomp_store,
815 +static int __init omap3_sr_init(void)
820 +#ifdef CONFIG_ARCH_OMAP34XX
821 + sr1.fck = clk_get(NULL, "sr1_fck");
822 + if (IS_ERR(sr1.fck))
823 + printk(KERN_ERR "Could not get sr1_fck\n");
825 + sr2.fck = clk_get(NULL, "sr2_fck");
826 + if (IS_ERR(sr2.fck))
827 + printk(KERN_ERR "Could not get sr2_fck\n");
828 +#endif /* #ifdef CONFIG_ARCH_OMAP34XX */
830 + /* Call the VPConfig, VCConfig, set N Values. */
831 + sr_set_nvalues(&sr1);
832 + sr_configure_vp(SR1);
834 + sr_set_nvalues(&sr2);
835 + sr_configure_vp(SR2);
839 + /* Enable SR on T2 */
840 + ret = t2_in(PM_RECEIVER, &RdReg, R_DCDC_GLOBAL_CFG);
841 + RdReg |= DCDC_GLOBAL_CFG_ENABLE_SRFLX;
842 + ret |= t2_out(PM_RECEIVER, RdReg, R_DCDC_GLOBAL_CFG);
845 + printk(KERN_INFO "SmartReflex driver initialized\n");
847 + ret = subsys_create_file(&power_subsys, &sr_vdd1_autocomp);
849 + printk(KERN_ERR "subsys_create_file failed: %d\n", ret);
851 + ret = subsys_create_file(&power_subsys, &sr_vdd2_autocomp);
853 + printk(KERN_ERR "subsys_create_file failed: %d\n", ret);
858 +arch_initcall(omap3_sr_init);
859 diff --git a/arch/arm/mach-omap2/smartreflex.h b/arch/arm/mach-omap2/smartreflex.h
861 index 0000000..62907ef
863 +++ b/arch/arm/mach-omap2/smartreflex.h
866 + * linux/arch/arm/mach-omap3/smartreflex.h
868 + * Copyright (C) 2007 Texas Instruments, Inc.
869 + * Lesly A M <x0080970@ti.com>
871 + * This program is free software; you can redistribute it and/or modify
872 + * it under the terms of the GNU General Public License version 2 as
873 + * published by the Free Software Foundation.
887 +#define GAIN_MAXLIMIT 16
888 +#define R_MAXLIMIT 256
890 +#define SR1_CLK_ENABLE (0x1 << 6)
891 +#define SR2_CLK_ENABLE (0x1 << 7)
893 +/* PRM_VP1_CONFIG */
894 +#define PRM_VP1_CONFIG_ERROROFFSET (0x00 << 24)
895 +#define PRM_VP1_CONFIG_ERRORGAIN (0x20 << 16)
897 +#define PRM_VP1_CONFIG_INITVOLTAGE (0x30 << 8) /* 1.2 volt */
898 +#define PRM_VP1_CONFIG_TIMEOUTEN (0x1 << 3)
899 +#define PRM_VP1_CONFIG_INITVDD (0x1 << 2)
900 +#define PRM_VP1_CONFIG_FORCEUPDATE (0x1 << 1)
901 +#define PRM_VP1_CONFIG_VPENABLE (0x1 << 0)
903 +/* PRM_VP1_VSTEPMIN */
904 +#define PRM_VP1_VSTEPMIN_SMPSWAITTIMEMIN (0x01F4 << 8)
905 +#define PRM_VP1_VSTEPMIN_VSTEPMIN (0x01 << 0)
907 +/* PRM_VP1_VSTEPMAX */
908 +#define PRM_VP1_VSTEPMAX_SMPSWAITTIMEMAX (0x01F4 << 8)
909 +#define PRM_VP1_VSTEPMAX_VSTEPMAX (0x04 << 0)
911 +/* PRM_VP1_VLIMITTO */
912 +#define PRM_VP1_VLIMITTO_VDDMAX (0x3C << 24)
913 +#define PRM_VP1_VLIMITTO_VDDMIN (0x0 << 16)
914 +#define PRM_VP1_VLIMITTO_TIMEOUT (0xFFFF << 0)
916 +/* PRM_VP2_CONFIG */
917 +#define PRM_VP2_CONFIG_ERROROFFSET (0x00 << 24)
918 +#define PRM_VP2_CONFIG_ERRORGAIN (0x20 << 16)
920 +#define PRM_VP2_CONFIG_INITVOLTAGE (0x30 << 8) /* 1.2 volt */
921 +#define PRM_VP2_CONFIG_TIMEOUTEN (0x1 << 3)
922 +#define PRM_VP2_CONFIG_INITVDD (0x1 << 2)
923 +#define PRM_VP2_CONFIG_FORCEUPDATE (0x1 << 1)
924 +#define PRM_VP2_CONFIG_VPENABLE (0x1 << 0)
926 +/* PRM_VP2_VSTEPMIN */
927 +#define PRM_VP2_VSTEPMIN_SMPSWAITTIMEMIN (0x01F4 << 8)
928 +#define PRM_VP2_VSTEPMIN_VSTEPMIN (0x01 << 0)
930 +/* PRM_VP2_VSTEPMAX */
931 +#define PRM_VP2_VSTEPMAX_SMPSWAITTIMEMAX (0x01F4 << 8)
932 +#define PRM_VP2_VSTEPMAX_VSTEPMAX (0x04 << 0)
934 +/* PRM_VP2_VLIMITTO */
935 +#define PRM_VP2_VLIMITTO_VDDMAX (0x2C << 24)
936 +#define PRM_VP2_VLIMITTO_VDDMIN (0x0 << 16)
937 +#define PRM_VP2_VLIMITTO_TIMEOUT (0xFFFF << 0)
940 +#define SR1_SRCONFIG_ACCUMDATA (0x1F4 << 22)
941 +#define SR2_SRCONFIG_ACCUMDATA (0x1F4 << 22)
943 +#define SRCLKLENGTH_12MHZ_SYSCLK 0x3C
944 +#define SRCLKLENGTH_13MHZ_SYSCLK 0x41
945 +#define SRCLKLENGTH_19MHZ_SYSCLK 0x60
946 +#define SRCLKLENGTH_26MHZ_SYSCLK 0x82
947 +#define SRCLKLENGTH_38MHZ_SYSCLK 0xC0
949 +#define SRCONFIG_SRCLKLENGTH_SHIFT 12
950 +#define SRCONFIG_SENNENABLE_SHIFT 5
951 +#define SRCONFIG_SENPENABLE_SHIFT 3
953 +#define SRCONFIG_SRENABLE (0x01 << 11)
954 +#define SRCONFIG_SENENABLE (0x01 << 10)
955 +#define SRCONFIG_ERRGEN_EN (0x01 << 9)
956 +#define SRCONFIG_MINMAXAVG_EN (0x01 << 8)
958 +#define SRCONFIG_DELAYCTRL (0x01 << 2)
959 +#define SRCONFIG_CLKCTRL (0x00 << 0)
962 +#define SR1_AVGWEIGHT_SENPAVGWEIGHT (0x03 << 2)
963 +#define SR1_AVGWEIGHT_SENNAVGWEIGHT (0x03 << 0)
965 +#define SR2_AVGWEIGHT_SENPAVGWEIGHT (0x01 << 2)
966 +#define SR2_AVGWEIGHT_SENNAVGWEIGHT (0x01 << 0)
968 +/* NVALUERECIPROCAL */
969 +#define NVALUERECIPROCAL_SENPGAIN_SHIFT 20
970 +#define NVALUERECIPROCAL_SENNGAIN_SHIFT 16
971 +#define NVALUERECIPROCAL_RNSENP_SHIFT 8
972 +#define NVALUERECIPROCAL_RNSENN_SHIFT 0
975 +#define SR_CLKACTIVITY_MASK (0x03 << 20)
976 +#define SR_ERRWEIGHT_MASK (0x07 << 16)
977 +#define SR_ERRMAXLIMIT_MASK (0xFF << 8)
978 +#define SR_ERRMINLIMIT_MASK (0xFF << 0)
980 +#define SR_CLKACTIVITY_IOFF_FOFF (0x00 << 20)
981 +#define SR_CLKACTIVITY_IOFF_FON (0x02 << 20)
983 +#define ERRCONFIG_VPBOUNDINTEN (0x1 << 31)
984 +#define ERRCONFIG_VPBOUNDINTST (0x1 << 30)
986 +#define SR1_ERRWEIGHT (0x07 << 16)
987 +#define SR1_ERRMAXLIMIT (0x02 << 8)
988 +#define SR1_ERRMINLIMIT (0xFA << 0)
990 +#define SR2_ERRWEIGHT (0x07 << 16)
991 +#define SR2_ERRMAXLIMIT (0x02 << 8)
992 +#define SR2_ERRMINLIMIT (0xF9 << 0)
994 +extern u32 current_vdd1_opp;
995 +extern u32 current_vdd2_opp;
996 +extern struct kset power_subsys;
998 +extern inline int loop_wait(u32 *lcnt, u32 *rcnt, u32 delay);
999 +extern void omap_udelay(u32 udelay);