summaryrefslogtreecommitdiffstats
path: root/meta/recipes-kernel/linux/linux-omap2-git/omap3evm/0001-ARM-OMAP-SmartReflex-driver.patch
diff options
context:
space:
mode:
Diffstat (limited to 'meta/recipes-kernel/linux/linux-omap2-git/omap3evm/0001-ARM-OMAP-SmartReflex-driver.patch')
-rw-r--r--meta/recipes-kernel/linux/linux-omap2-git/omap3evm/0001-ARM-OMAP-SmartReflex-driver.patch1002
1 files changed, 1002 insertions, 0 deletions
diff --git a/meta/recipes-kernel/linux/linux-omap2-git/omap3evm/0001-ARM-OMAP-SmartReflex-driver.patch b/meta/recipes-kernel/linux/linux-omap2-git/omap3evm/0001-ARM-OMAP-SmartReflex-driver.patch
new file mode 100644
index 0000000000..550a4f58be
--- /dev/null
+++ b/meta/recipes-kernel/linux/linux-omap2-git/omap3evm/0001-ARM-OMAP-SmartReflex-driver.patch
@@ -0,0 +1,1002 @@
1From: Kalle Jokiniemi <ext-kalle.jokiniemi@nokia.com>
2To: linux-omap@vger.kernel.org
3Cc: Kalle Jokiniemi <ext-kalle.jokiniemi@nokia.com>
4Subject: [PATCH 1/3] ARM: OMAP: SmartReflex driver, reference source and header files
5Date: Mon, 2 Jun 2008 14:30:12 +0300
6
7The following patch set integrates TI's SmartReflex driver. SmartReflex is a
8module that adjusts OMAP3 VDD1 and VDD2 operating voltages around the nominal
9values of current operating point depending on silicon characteristics and
10operating conditions.
11
12The driver creates two sysfs entries into /sys/power/ named "sr_vdd1_autocomp"
13and "sr_vdd2_autocomp" which can be used to activate SmartReflex modules 1 and
142.
15
16Use the following commands to enable SmartReflex:
17
18echo -n 1 > /sys/power/sr_vdd1_autocomp
19echo -n 1 > /sys/power/sr_vdd2_autocomp
20
21To disable:
22
23echo -n 0 > /sys/power/sr_vdd1_autocomp
24echo -n 0 > /sys/power/sr_vdd2_autocomp
25
26This particular patch adds the TI reference source and header files for
27SmartReflex. Only modifications include minor styling to pass checkpatch.pl
28test.
29
30Signed-off-by: Kalle Jokiniemi <ext-kalle.jokiniemi@nokia.com>
31---
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
37
38diff --git a/arch/arm/mach-omap2/smartreflex.c b/arch/arm/mach-omap2/smartreflex.c
39new file mode 100644
40index 0000000..dae7460
41--- /dev/null
42+++ b/arch/arm/mach-omap2/smartreflex.c
43@@ -0,0 +1,815 @@
44+/*
45+ * linux/arch/arm/mach-omap3/smartreflex.c
46+ *
47+ * OMAP34XX SmartReflex Voltage Control
48+ *
49+ * Copyright (C) 2007 Texas Instruments, Inc.
50+ * Lesly A M <x0080970@ti.com>
51+ *
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.
55+ */
56+
57+
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>
66+
67+#include <asm/arch/prcm.h>
68+#include <asm/arch/power_companion.h>
69+#include <linux/io.h>
70+
71+#include "prcm-regs.h"
72+#include "smartreflex.h"
73+
74+
75+/* #define DEBUG_SR 1 */
76+#ifdef DEBUG_SR
77+# define DPRINTK(fmt, args...) printk(KERN_ERR "%s: " fmt, __func__ ,\
78+ ## args)
79+#else
80+# define DPRINTK(fmt, args...)
81+#endif
82+
83+struct omap_sr{
84+ int srid;
85+ int is_sr_reset;
86+ int is_autocomp_active;
87+ struct clk *fck;
88+ u32 req_opp_no;
89+ u32 opp1_nvalue, opp2_nvalue, opp3_nvalue, opp4_nvalue, opp5_nvalue;
90+ u32 senp_mod, senn_mod;
91+ u32 srbase_addr;
92+ u32 vpbase_addr;
93+};
94+
95+static struct omap_sr sr1 = {
96+ .srid = SR1,
97+ .is_sr_reset = 1,
98+ .is_autocomp_active = 0,
99+ .srbase_addr = OMAP34XX_SR1_BASE,
100+};
101+
102+static struct omap_sr sr2 = {
103+ .srid = SR2,
104+ .is_sr_reset = 1,
105+ .is_autocomp_active = 0,
106+ .srbase_addr = OMAP34XX_SR2_BASE,
107+};
108+
109+static inline void sr_write_reg(struct omap_sr *sr, int offset, u32 value)
110+{
111+ omap_writel(value, sr->srbase_addr + offset);
112+}
113+
114+static inline void sr_modify_reg(struct omap_sr *sr, int offset, u32 mask,
115+ u32 value)
116+{
117+ u32 reg_val;
118+
119+ reg_val = omap_readl(sr->srbase_addr + offset);
120+ reg_val &= ~mask;
121+ reg_val |= value;
122+
123+ omap_writel(reg_val, sr->srbase_addr + offset);
124+}
125+
126+static inline u32 sr_read_reg(struct omap_sr *sr, int offset)
127+{
128+ return omap_readl(sr->srbase_addr + offset);
129+}
130+
131+
132+#ifndef USE_EFUSE_VALUES
133+static void cal_reciprocal(u32 sensor, u32 *sengain, u32 *rnsen)
134+{
135+ u32 gn, rn, mul;
136+
137+ for (gn = 0; gn < GAIN_MAXLIMIT; gn++) {
138+ mul = 1 << (gn + 8);
139+ rn = mul / sensor;
140+ if (rn < R_MAXLIMIT) {
141+ *sengain = gn;
142+ *rnsen = rn;
143+ }
144+ }
145+}
146+#endif
147+
148+static int sr_clk_enable(struct omap_sr *sr)
149+{
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;
153+ }
154+
155+ /* set fclk- active , iclk- idle */
156+ sr_modify_reg(sr, ERRCONFIG, SR_CLKACTIVITY_MASK,
157+ SR_CLKACTIVITY_IOFF_FON);
158+
159+ return 0;
160+
161+clk_enable_err:
162+ return -1;
163+}
164+
165+static int sr_clk_disable(struct omap_sr *sr)
166+{
167+ /* set fclk, iclk- idle */
168+ sr_modify_reg(sr, ERRCONFIG, SR_CLKACTIVITY_MASK,
169+ SR_CLKACTIVITY_IOFF_FOFF);
170+
171+ clk_disable(sr->fck);
172+ sr->is_sr_reset = 1;
173+
174+ return 0;
175+}
176+
177+static void sr_set_nvalues(struct omap_sr *sr)
178+{
179+#ifdef USE_EFUSE_VALUES
180+ u32 n1, n2;
181+#else
182+ u32 senpval, sennval;
183+ u32 senpgain, senngain;
184+ u32 rnsenp, rnsenn;
185+#endif
186+
187+ if (sr->srid == SR1) {
188+#ifdef USE_EFUSE_VALUES
189+ /* Read values for VDD1 from EFUSE */
190+#else
191+ /* since E-Fuse Values are not available, calculating the
192+ * reciprocal of the SenN and SenP values for SR1
193+ */
194+ sr->senp_mod = 0x03; /* SenN-M5 enabled */
195+ sr->senn_mod = 0x03;
196+
197+ /* for OPP5 */
198+ senpval = 0x848 + 0x330;
199+ sennval = 0xacd + 0x330;
200+
201+ cal_reciprocal(senpval, &senpgain, &rnsenp);
202+ cal_reciprocal(sennval, &senngain, &rnsenn);
203+
204+ sr->opp5_nvalue =
205+ ((senpgain << NVALUERECIPROCAL_SENPGAIN_SHIFT) |
206+ (senngain << NVALUERECIPROCAL_SENNGAIN_SHIFT) |
207+ (rnsenp << NVALUERECIPROCAL_RNSENP_SHIFT) |
208+ (rnsenn << NVALUERECIPROCAL_RNSENN_SHIFT));
209+
210+ /* for OPP4 */
211+ senpval = 0x727 + 0x2a0;
212+ sennval = 0x964 + 0x2a0;
213+
214+ cal_reciprocal(senpval, &senpgain, &rnsenp);
215+ cal_reciprocal(sennval, &senngain, &rnsenn);
216+
217+ sr->opp4_nvalue =
218+ ((senpgain << NVALUERECIPROCAL_SENPGAIN_SHIFT) |
219+ (senngain << NVALUERECIPROCAL_SENNGAIN_SHIFT) |
220+ (rnsenp << NVALUERECIPROCAL_RNSENP_SHIFT) |
221+ (rnsenn << NVALUERECIPROCAL_RNSENN_SHIFT));
222+
223+ /* for OPP3 */
224+ senpval = 0x655 + 0x200;
225+ sennval = 0x85b + 0x200;
226+
227+ cal_reciprocal(senpval, &senpgain, &rnsenp);
228+ cal_reciprocal(sennval, &senngain, &rnsenn);
229+
230+ sr->opp3_nvalue =
231+ ((senpgain << NVALUERECIPROCAL_SENPGAIN_SHIFT) |
232+ (senngain << NVALUERECIPROCAL_SENNGAIN_SHIFT) |
233+ (rnsenp << NVALUERECIPROCAL_RNSENP_SHIFT) |
234+ (rnsenn << NVALUERECIPROCAL_RNSENN_SHIFT));
235+
236+ /* for OPP2 */
237+ senpval = 0x3be + 0x1a0;
238+ sennval = 0x506 + 0x1a0;
239+
240+ cal_reciprocal(senpval, &senpgain, &rnsenp);
241+ cal_reciprocal(sennval, &senngain, &rnsenn);
242+
243+ sr->opp2_nvalue =
244+ ((senpgain << NVALUERECIPROCAL_SENPGAIN_SHIFT) |
245+ (senngain << NVALUERECIPROCAL_SENNGAIN_SHIFT) |
246+ (rnsenp << NVALUERECIPROCAL_RNSENP_SHIFT) |
247+ (rnsenn << NVALUERECIPROCAL_RNSENN_SHIFT));
248+
249+ /* for OPP1 */
250+ senpval = 0x28c + 0x100;
251+ sennval = 0x373 + 0x100;
252+
253+ cal_reciprocal(senpval, &senpgain, &rnsenp);
254+ cal_reciprocal(sennval, &senngain, &rnsenn);
255+
256+ sr->opp1_nvalue =
257+ ((senpgain << NVALUERECIPROCAL_SENPGAIN_SHIFT) |
258+ (senngain << NVALUERECIPROCAL_SENNGAIN_SHIFT) |
259+ (rnsenp << NVALUERECIPROCAL_RNSENP_SHIFT) |
260+ (rnsenn << NVALUERECIPROCAL_RNSENN_SHIFT));
261+
262+ sr_clk_enable(sr);
263+ sr_write_reg(sr, NVALUERECIPROCAL, sr->opp3_nvalue);
264+ sr_clk_disable(sr);
265+
266+#endif
267+ } else if (sr->srid == SR2) {
268+#ifdef USE_EFUSE_VALUES
269+ /* Read values for VDD2 from EFUSE */
270+#else
271+ /* since E-Fuse Values are not available, calculating the
272+ * reciprocal of the SenN and SenP values for SR2
273+ */
274+ sr->senp_mod = 0x03;
275+ sr->senn_mod = 0x03;
276+
277+ /* for OPP3 */
278+ senpval = 0x579 + 0x200;
279+ sennval = 0x76f + 0x200;
280+
281+ cal_reciprocal(senpval, &senpgain, &rnsenp);
282+ cal_reciprocal(sennval, &senngain, &rnsenn);
283+
284+ sr->opp3_nvalue =
285+ ((senpgain << NVALUERECIPROCAL_SENPGAIN_SHIFT) |
286+ (senngain << NVALUERECIPROCAL_SENNGAIN_SHIFT) |
287+ (rnsenp << NVALUERECIPROCAL_RNSENP_SHIFT) |
288+ (rnsenn << NVALUERECIPROCAL_RNSENN_SHIFT));
289+
290+ /* for OPP2 */
291+ senpval = 0x390 + 0x1c0;
292+ sennval = 0x4f5 + 0x1c0;
293+
294+ cal_reciprocal(senpval, &senpgain, &rnsenp);
295+ cal_reciprocal(sennval, &senngain, &rnsenn);
296+
297+ sr->opp2_nvalue =
298+ ((senpgain << NVALUERECIPROCAL_SENPGAIN_SHIFT) |
299+ (senngain << NVALUERECIPROCAL_SENNGAIN_SHIFT) |
300+ (rnsenp << NVALUERECIPROCAL_RNSENP_SHIFT) |
301+ (rnsenn << NVALUERECIPROCAL_RNSENN_SHIFT));
302+
303+ /* for OPP1 */
304+ senpval = 0x25d;
305+ sennval = 0x359;
306+
307+ cal_reciprocal(senpval, &senpgain, &rnsenp);
308+ cal_reciprocal(sennval, &senngain, &rnsenn);
309+
310+ sr->opp1_nvalue =
311+ ((senpgain << NVALUERECIPROCAL_SENPGAIN_SHIFT) |
312+ (senngain << NVALUERECIPROCAL_SENNGAIN_SHIFT) |
313+ (rnsenp << NVALUERECIPROCAL_RNSENP_SHIFT) |
314+ (rnsenn << NVALUERECIPROCAL_RNSENN_SHIFT));
315+
316+#endif
317+ }
318+
319+}
320+
321+static void sr_configure_vp(int srid)
322+{
323+ u32 vpconfig;
324+
325+ if (srid == SR1) {
326+ vpconfig = PRM_VP1_CONFIG_ERROROFFSET | PRM_VP1_CONFIG_ERRORGAIN
327+ | PRM_VP1_CONFIG_INITVOLTAGE | PRM_VP1_CONFIG_TIMEOUTEN;
328+
329+ PRM_VP1_CONFIG = vpconfig;
330+ PRM_VP1_VSTEPMIN = PRM_VP1_VSTEPMIN_SMPSWAITTIMEMIN |
331+ PRM_VP1_VSTEPMIN_VSTEPMIN;
332+
333+ PRM_VP1_VSTEPMAX = PRM_VP1_VSTEPMAX_SMPSWAITTIMEMAX |
334+ PRM_VP1_VSTEPMAX_VSTEPMAX;
335+
336+ PRM_VP1_VLIMITTO = PRM_VP1_VLIMITTO_VDDMAX |
337+ PRM_VP1_VLIMITTO_VDDMIN | PRM_VP1_VLIMITTO_TIMEOUT;
338+
339+ PRM_VP1_CONFIG |= PRM_VP1_CONFIG_INITVDD;
340+ PRM_VP1_CONFIG &= ~PRM_VP1_CONFIG_INITVDD;
341+
342+ } else if (srid == SR2) {
343+ vpconfig = PRM_VP2_CONFIG_ERROROFFSET | PRM_VP2_CONFIG_ERRORGAIN
344+ | PRM_VP2_CONFIG_INITVOLTAGE | PRM_VP2_CONFIG_TIMEOUTEN;
345+
346+ PRM_VP2_CONFIG = vpconfig;
347+ PRM_VP2_VSTEPMIN = PRM_VP2_VSTEPMIN_SMPSWAITTIMEMIN |
348+ PRM_VP2_VSTEPMIN_VSTEPMIN;
349+
350+ PRM_VP2_VSTEPMAX = PRM_VP2_VSTEPMAX_SMPSWAITTIMEMAX |
351+ PRM_VP2_VSTEPMAX_VSTEPMAX;
352+
353+ PRM_VP2_VLIMITTO = PRM_VP2_VLIMITTO_VDDMAX |
354+ PRM_VP2_VLIMITTO_VDDMIN | PRM_VP2_VLIMITTO_TIMEOUT;
355+
356+ PRM_VP2_CONFIG |= PRM_VP2_CONFIG_INITVDD;
357+ PRM_VP2_CONFIG &= ~PRM_VP2_CONFIG_INITVDD;
358+
359+ }
360+}
361+
362+static void sr_configure_vc(void)
363+{
364+ PRM_VC_SMPS_SA =
365+ (R_SRI2C_SLAVE_ADDR << PRM_VC_SMPS_SA1_SHIFT) |
366+ (R_SRI2C_SLAVE_ADDR << PRM_VC_SMPS_SA0_SHIFT);
367+
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);
370+
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);
375+
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);
380+
381+ PRM_VC_CH_CONF = PRM_VC_CH_CONF_CMD1 | PRM_VC_CH_CONF_RAV1;
382+
383+ PRM_VC_I2C_CFG = PRM_VC_I2C_CFG_MCODE | PRM_VC_I2C_CFG_HSEN
384+ | PRM_VC_I2C_CFG_SREN;
385+
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;
394+#else
395+ PRM_VOLTCTRL |= PRM_VOLTCTRL_AUTO_RET;
396+#endif
397+
398+}
399+
400+
401+static void sr_configure(struct omap_sr *sr)
402+{
403+ u32 sys_clk, sr_clk_length = 0;
404+ u32 sr_config;
405+ u32 senp_en , senn_en;
406+
407+ senp_en = sr->senp_mod;
408+ senn_en = sr->senn_mod;
409+
410+ sys_clk = prcm_get_system_clock_speed();
411+
412+ switch (sys_clk) {
413+ case 12000:
414+ sr_clk_length = SRCLKLENGTH_12MHZ_SYSCLK;
415+ break;
416+ case 13000:
417+ sr_clk_length = SRCLKLENGTH_13MHZ_SYSCLK;
418+ break;
419+ case 19200:
420+ sr_clk_length = SRCLKLENGTH_19MHZ_SYSCLK;
421+ break;
422+ case 26000:
423+ sr_clk_length = SRCLKLENGTH_26MHZ_SYSCLK;
424+ break;
425+ case 38400:
426+ sr_clk_length = SRCLKLENGTH_38MHZ_SYSCLK;
427+ break;
428+ default :
429+ printk(KERN_ERR "Invalid sysclk value\n");
430+ break;
431+ }
432+
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;
442+
443+ sr_write_reg(sr, SRCONFIG, sr_config);
444+
445+ sr_write_reg(sr, AVGWEIGHT, SR1_AVGWEIGHT_SENPAVGWEIGHT |
446+ SR1_AVGWEIGHT_SENNAVGWEIGHT);
447+
448+ sr_modify_reg(sr, ERRCONFIG, (SR_ERRWEIGHT_MASK |
449+ SR_ERRMAXLIMIT_MASK | SR_ERRMINLIMIT_MASK),
450+ (SR1_ERRWEIGHT | SR1_ERRMAXLIMIT | SR1_ERRMINLIMIT));
451+
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;
460+
461+ sr_write_reg(sr, SRCONFIG, sr_config);
462+
463+ sr_write_reg(sr, AVGWEIGHT, SR2_AVGWEIGHT_SENPAVGWEIGHT |
464+ SR2_AVGWEIGHT_SENNAVGWEIGHT);
465+
466+ sr_modify_reg(sr, ERRCONFIG, (SR_ERRWEIGHT_MASK |
467+ SR_ERRMAXLIMIT_MASK | SR_ERRMINLIMIT_MASK),
468+ (SR2_ERRWEIGHT | SR2_ERRMAXLIMIT | SR2_ERRMINLIMIT));
469+
470+ }
471+ sr->is_sr_reset = 0;
472+}
473+
474+static void sr_enable(struct omap_sr *sr, u32 target_opp_no)
475+{
476+ u32 nvalue_reciprocal, current_nvalue;
477+
478+ sr->req_opp_no = target_opp_no;
479+
480+ if (sr->srid == SR1) {
481+ switch (target_opp_no) {
482+ case 5:
483+ nvalue_reciprocal = sr->opp5_nvalue;
484+ break;
485+ case 4:
486+ nvalue_reciprocal = sr->opp4_nvalue;
487+ break;
488+ case 3:
489+ nvalue_reciprocal = sr->opp3_nvalue;
490+ break;
491+ case 2:
492+ nvalue_reciprocal = sr->opp2_nvalue;
493+ break;
494+ case 1:
495+ nvalue_reciprocal = sr->opp1_nvalue;
496+ break;
497+ default:
498+ nvalue_reciprocal = sr->opp3_nvalue;
499+ break;
500+ }
501+ } else {
502+ switch (target_opp_no) {
503+ case 3:
504+ nvalue_reciprocal = sr->opp3_nvalue;
505+ break;
506+ case 2:
507+ nvalue_reciprocal = sr->opp2_nvalue;
508+ break;
509+ case 1:
510+ nvalue_reciprocal = sr->opp1_nvalue;
511+ break;
512+ default:
513+ nvalue_reciprocal = sr->opp3_nvalue;
514+ break;
515+ }
516+ }
517+
518+ current_nvalue = sr_read_reg(sr, NVALUERECIPROCAL);
519+
520+ if (current_nvalue == nvalue_reciprocal) {
521+ DPRINTK("System is already at the desired voltage level\n");
522+ return;
523+ }
524+
525+ sr_write_reg(sr, NVALUERECIPROCAL, nvalue_reciprocal);
526+
527+ /* Enable the interrupt */
528+ sr_modify_reg(sr, ERRCONFIG,
529+ (ERRCONFIG_VPBOUNDINTEN | ERRCONFIG_VPBOUNDINTST),
530+ (ERRCONFIG_VPBOUNDINTEN | ERRCONFIG_VPBOUNDINTST));
531+
532+ if (sr->srid == SR1) {
533+ /* Enable VP1 */
534+ PRM_VP1_CONFIG |= PRM_VP1_CONFIG_VPENABLE;
535+ } else if (sr->srid == SR2) {
536+ /* Enable VP2 */
537+ PRM_VP2_CONFIG |= PRM_VP2_CONFIG_VPENABLE;
538+ }
539+
540+ /* SRCONFIG - enable SR */
541+ sr_modify_reg(sr, SRCONFIG, SRCONFIG_SRENABLE, SRCONFIG_SRENABLE);
542+
543+}
544+
545+static void sr_disable(struct omap_sr *sr)
546+{
547+ sr->is_sr_reset = 1;
548+
549+ /* SRCONFIG - disable SR */
550+ sr_modify_reg(sr, SRCONFIG, SRCONFIG_SRENABLE, ~SRCONFIG_SRENABLE);
551+
552+ if (sr->srid == SR1) {
553+ /* Enable VP1 */
554+ PRM_VP1_CONFIG &= ~PRM_VP1_CONFIG_VPENABLE;
555+ } else if (sr->srid == SR2) {
556+ /* Enable VP2 */
557+ PRM_VP2_CONFIG &= ~PRM_VP2_CONFIG_VPENABLE;
558+ }
559+}
560+
561+
562+void sr_start_vddautocomap(int srid, u32 target_opp_no)
563+{
564+ struct omap_sr *sr = NULL;
565+
566+ if (srid == SR1)
567+ sr = &sr1;
568+ else if (srid == SR2)
569+ sr = &sr2;
570+
571+ if (sr->is_sr_reset == 1) {
572+ sr_clk_enable(sr);
573+ sr_configure(sr);
574+ }
575+
576+ if (sr->is_autocomp_active == 1)
577+ DPRINTK(KERN_WARNING "SR%d: VDD autocomp is already active\n",
578+ srid);
579+
580+ sr->is_autocomp_active = 1;
581+ sr_enable(sr, target_opp_no);
582+}
583+EXPORT_SYMBOL(sr_start_vddautocomap);
584+
585+int sr_stop_vddautocomap(int srid)
586+{
587+ struct omap_sr *sr = NULL;
588+
589+ if (srid == SR1)
590+ sr = &sr1;
591+ else if (srid == SR2)
592+ sr = &sr2;
593+
594+ if (sr->is_autocomp_active == 1) {
595+ sr_disable(sr);
596+ sr_clk_disable(sr);
597+ sr->is_autocomp_active = 0;
598+ return SR_TRUE;
599+ } else {
600+ DPRINTK(KERN_WARNING "SR%d: VDD autocomp is not active\n",
601+ srid);
602+ return SR_FALSE;
603+ }
604+
605+}
606+EXPORT_SYMBOL(sr_stop_vddautocomap);
607+
608+void enable_smartreflex(int srid)
609+{
610+ u32 target_opp_no = 0;
611+ struct omap_sr *sr = NULL;
612+
613+ if (srid == SR1)
614+ sr = &sr1;
615+ else if (srid == SR2)
616+ sr = &sr2;
617+
618+ if (sr->is_autocomp_active == 1) {
619+ if (sr->is_sr_reset == 1) {
620+ if (srid == SR1) {
621+ /* Enable SR clks */
622+ CM_FCLKEN_WKUP |= SR1_CLK_ENABLE;
623+ target_opp_no = get_opp_no(current_vdd1_opp);
624+
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);
629+ }
630+
631+ sr_configure(sr);
632+
633+ sr_enable(sr, target_opp_no);
634+ }
635+ }
636+}
637+
638+void disable_smartreflex(int srid)
639+{
640+ struct omap_sr *sr = NULL;
641+
642+ if (srid == SR1)
643+ sr = &sr1;
644+ else if (srid == SR2)
645+ sr = &sr2;
646+
647+ if (sr->is_autocomp_active == 1) {
648+ if (srid == SR1) {
649+ /* Enable SR clk */
650+ CM_FCLKEN_WKUP |= SR1_CLK_ENABLE;
651+
652+ } else if (srid == SR2) {
653+ /* Enable SR clk */
654+ CM_FCLKEN_WKUP |= SR2_CLK_ENABLE;
655+ }
656+
657+ if (sr->is_sr_reset == 0) {
658+
659+ sr->is_sr_reset = 1;
660+ /* SRCONFIG - disable SR */
661+ sr_modify_reg(sr, SRCONFIG, SRCONFIG_SRENABLE,
662+ ~SRCONFIG_SRENABLE);
663+
664+ if (sr->srid == SR1) {
665+ /* Disable SR clk */
666+ CM_FCLKEN_WKUP &= ~SR1_CLK_ENABLE;
667+ /* Enable VP1 */
668+ PRM_VP1_CONFIG &= ~PRM_VP1_CONFIG_VPENABLE;
669+
670+ } else if (sr->srid == SR2) {
671+ /* Disable SR clk */
672+ CM_FCLKEN_WKUP &= ~SR2_CLK_ENABLE;
673+ /* Enable VP2 */
674+ PRM_VP2_CONFIG &= ~PRM_VP2_CONFIG_VPENABLE;
675+ }
676+ }
677+ }
678+}
679+
680+
681+/* Voltage Scaling using SR VCBYPASS */
682+int sr_voltagescale_vcbypass(u32 target_opp, u8 vsel)
683+{
684+ int ret;
685+ int sr_status = 0;
686+ u32 vdd, target_opp_no;
687+ u32 vc_bypass_value;
688+ u32 reg_addr = 0;
689+ u32 loop_cnt = 0, retries_cnt = 0;
690+
691+ vdd = get_vdd(target_opp);
692+ target_opp_no = get_opp_no(target_opp);
693+
694+ if (vdd == PRCM_VDD1) {
695+ sr_status = sr_stop_vddautocomap(SR1);
696+
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;
700+
701+ } else if (vdd == PRCM_VDD2) {
702+ sr_status = sr_stop_vddautocomap(SR2);
703+
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;
707+ }
708+
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);
712+
713+ PRM_VC_BYPASS_VAL = vc_bypass_value;
714+
715+ PRM_VC_BYPASS_VAL |= PRM_VC_BYPASS_VALID;
716+
717+ DPRINTK("%s : PRM_VC_BYPASS_VAL %X\n", __func__, PRM_VC_BYPASS_VAL);
718+ DPRINTK("PRM_IRQST_MPU %X\n", PRM_IRQSTATUS_MPU);
719+
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"
724+ "write\n");
725+ return ret;
726+ }
727+ }
728+
729+ omap_udelay(T2_SMPS_UPDATE_DELAY);
730+
731+ if (sr_status) {
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);
736+ }
737+
738+ return SR_PASS;
739+}
740+
741+/* Sysfs interface to select SR VDD1 auto compensation */
742+static ssize_t omap_sr_vdd1_autocomp_show(struct kset *subsys, char *buf)
743+{
744+ return sprintf(buf, "%d\n", sr1.is_autocomp_active);
745+}
746+
747+static ssize_t omap_sr_vdd1_autocomp_store(struct kset *subsys,
748+ const char *buf, size_t n)
749+{
750+ u32 current_vdd1opp_no;
751+ unsigned short value;
752+
753+ if (sscanf(buf, "%hu", &value) != 1 || (value > 1)) {
754+ printk(KERN_ERR "sr_vdd1_autocomp: Invalid value\n");
755+ return -EINVAL;
756+ }
757+
758+ current_vdd1opp_no = get_opp_no(current_vdd1_opp);
759+
760+ if (value == 0)
761+ sr_stop_vddautocomap(SR1);
762+ else
763+ sr_start_vddautocomap(SR1, current_vdd1opp_no);
764+
765+ return n;
766+}
767+
768+static struct subsys_attribute sr_vdd1_autocomp = {
769+ .attr = {
770+ .name = __stringify(sr_vdd1_autocomp),
771+ .mode = 0644,
772+ },
773+ .show = omap_sr_vdd1_autocomp_show,
774+ .store = omap_sr_vdd1_autocomp_store,
775+};
776+
777+/* Sysfs interface to select SR VDD2 auto compensation */
778+static ssize_t omap_sr_vdd2_autocomp_show(struct kset *subsys, char *buf)
779+{
780+ return sprintf(buf, "%d\n", sr2.is_autocomp_active);
781+}
782+
783+static ssize_t omap_sr_vdd2_autocomp_store(struct kset *subsys,
784+ const char *buf, size_t n)
785+{
786+ u32 current_vdd2opp_no;
787+ unsigned short value;
788+
789+ if (sscanf(buf, "%hu", &value) != 1 || (value > 1)) {
790+ printk(KERN_ERR "sr_vdd2_autocomp: Invalid value\n");
791+ return -EINVAL;
792+ }
793+
794+ current_vdd2opp_no = get_opp_no(current_vdd2_opp);
795+
796+ if (value == 0)
797+ sr_stop_vddautocomap(SR2);
798+ else
799+ sr_start_vddautocomap(SR2, current_vdd2opp_no);
800+
801+ return n;
802+}
803+
804+static struct subsys_attribute sr_vdd2_autocomp = {
805+ .attr = {
806+ .name = __stringify(sr_vdd2_autocomp),
807+ .mode = 0644,
808+ },
809+ .show = omap_sr_vdd2_autocomp_show,
810+ .store = omap_sr_vdd2_autocomp_store,
811+};
812+
813+
814+
815+static int __init omap3_sr_init(void)
816+{
817+ int ret = 0;
818+ u8 RdReg;
819+
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");
824+
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 */
829+
830+ /* Call the VPConfig, VCConfig, set N Values. */
831+ sr_set_nvalues(&sr1);
832+ sr_configure_vp(SR1);
833+
834+ sr_set_nvalues(&sr2);
835+ sr_configure_vp(SR2);
836+
837+ sr_configure_vc();
838+
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);
843+
844+
845+ printk(KERN_INFO "SmartReflex driver initialized\n");
846+
847+ ret = subsys_create_file(&power_subsys, &sr_vdd1_autocomp);
848+ if (ret)
849+ printk(KERN_ERR "subsys_create_file failed: %d\n", ret);
850+
851+ ret = subsys_create_file(&power_subsys, &sr_vdd2_autocomp);
852+ if (ret)
853+ printk(KERN_ERR "subsys_create_file failed: %d\n", ret);
854+
855+ return 0;
856+}
857+
858+arch_initcall(omap3_sr_init);
859diff --git a/arch/arm/mach-omap2/smartreflex.h b/arch/arm/mach-omap2/smartreflex.h
860new file mode 100644
861index 0000000..62907ef
862--- /dev/null
863+++ b/arch/arm/mach-omap2/smartreflex.h
864@@ -0,0 +1,136 @@
865+/*
866+ * linux/arch/arm/mach-omap3/smartreflex.h
867+ *
868+ * Copyright (C) 2007 Texas Instruments, Inc.
869+ * Lesly A M <x0080970@ti.com>
870+ *
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.
874+ */
875+
876+
877+/* SR Modules */
878+#define SR1 1
879+#define SR2 2
880+
881+#define SR_FAIL 1
882+#define SR_PASS 0
883+
884+#define SR_TRUE 1
885+#define SR_FALSE 0
886+
887+#define GAIN_MAXLIMIT 16
888+#define R_MAXLIMIT 256
889+
890+#define SR1_CLK_ENABLE (0x1 << 6)
891+#define SR2_CLK_ENABLE (0x1 << 7)
892+
893+/* PRM_VP1_CONFIG */
894+#define PRM_VP1_CONFIG_ERROROFFSET (0x00 << 24)
895+#define PRM_VP1_CONFIG_ERRORGAIN (0x20 << 16)
896+
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)
902+
903+/* PRM_VP1_VSTEPMIN */
904+#define PRM_VP1_VSTEPMIN_SMPSWAITTIMEMIN (0x01F4 << 8)
905+#define PRM_VP1_VSTEPMIN_VSTEPMIN (0x01 << 0)
906+
907+/* PRM_VP1_VSTEPMAX */
908+#define PRM_VP1_VSTEPMAX_SMPSWAITTIMEMAX (0x01F4 << 8)
909+#define PRM_VP1_VSTEPMAX_VSTEPMAX (0x04 << 0)
910+
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)
915+
916+/* PRM_VP2_CONFIG */
917+#define PRM_VP2_CONFIG_ERROROFFSET (0x00 << 24)
918+#define PRM_VP2_CONFIG_ERRORGAIN (0x20 << 16)
919+
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)
925+
926+/* PRM_VP2_VSTEPMIN */
927+#define PRM_VP2_VSTEPMIN_SMPSWAITTIMEMIN (0x01F4 << 8)
928+#define PRM_VP2_VSTEPMIN_VSTEPMIN (0x01 << 0)
929+
930+/* PRM_VP2_VSTEPMAX */
931+#define PRM_VP2_VSTEPMAX_SMPSWAITTIMEMAX (0x01F4 << 8)
932+#define PRM_VP2_VSTEPMAX_VSTEPMAX (0x04 << 0)
933+
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)
938+
939+/* SRCONFIG */
940+#define SR1_SRCONFIG_ACCUMDATA (0x1F4 << 22)
941+#define SR2_SRCONFIG_ACCUMDATA (0x1F4 << 22)
942+
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
948+
949+#define SRCONFIG_SRCLKLENGTH_SHIFT 12
950+#define SRCONFIG_SENNENABLE_SHIFT 5
951+#define SRCONFIG_SENPENABLE_SHIFT 3
952+
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)
957+
958+#define SRCONFIG_DELAYCTRL (0x01 << 2)
959+#define SRCONFIG_CLKCTRL (0x00 << 0)
960+
961+/* AVGWEIGHT */
962+#define SR1_AVGWEIGHT_SENPAVGWEIGHT (0x03 << 2)
963+#define SR1_AVGWEIGHT_SENNAVGWEIGHT (0x03 << 0)
964+
965+#define SR2_AVGWEIGHT_SENPAVGWEIGHT (0x01 << 2)
966+#define SR2_AVGWEIGHT_SENNAVGWEIGHT (0x01 << 0)
967+
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
973+
974+/* ERRCONFIG */
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)
979+
980+#define SR_CLKACTIVITY_IOFF_FOFF (0x00 << 20)
981+#define SR_CLKACTIVITY_IOFF_FON (0x02 << 20)
982+
983+#define ERRCONFIG_VPBOUNDINTEN (0x1 << 31)
984+#define ERRCONFIG_VPBOUNDINTST (0x1 << 30)
985+
986+#define SR1_ERRWEIGHT (0x07 << 16)
987+#define SR1_ERRMAXLIMIT (0x02 << 8)
988+#define SR1_ERRMINLIMIT (0xFA << 0)
989+
990+#define SR2_ERRWEIGHT (0x07 << 16)
991+#define SR2_ERRMAXLIMIT (0x02 << 8)
992+#define SR2_ERRMINLIMIT (0xF9 << 0)
993+
994+extern u32 current_vdd1_opp;
995+extern u32 current_vdd2_opp;
996+extern struct kset power_subsys;
997+
998+extern inline int loop_wait(u32 *lcnt, u32 *rcnt, u32 delay);
999+extern void omap_udelay(u32 udelay);
1000+
1001--
10021.5.4.3