aboutsummaryrefslogtreecommitdiffstats
path: root/arch
diff options
context:
space:
mode:
authorThara Gopinath <thara@ti.com>2010-05-29 12:32:21 -0400
committerKevin Hilman <khilman@deeprootsystems.com>2010-12-22 17:31:02 -0500
commit2f34ce81b8c05c900e45bd88595cc154f7bb5957 (patch)
tree9bd5793ea11fef37439cd9a369d22d38ce30b268 /arch
parentf17f9726c27c3921e00a5750e85070e6dd7e1ff7 (diff)
OMAP3: PM: Adding voltage driver support.
This patch adds voltage driver support for OMAP3. The driver allows configuring the voltage controller and voltage processors during init and exports APIs to enable/disable voltage processors, scale voltage and reset voltage. The driver maintains the global voltage table on a per VDD basis which contains the various voltages supported by the VDD along with per voltage dependent data like smartreflex efuse offset, errminlimit and voltage processor errorgain. The driver also allows the voltage parameters dependent on the PMIC to be passed from the PMIC file through an API. The driver allows scaling of VDD voltages either through "vc bypass method" or through "vp forceupdate method" the choice being configurable through the board file. This patch contains code originally in linux omap pm branch smartreflex driver. Major contributors to this driver are Lesly A M, Rajendra Nayak, Kalle Jokiniemi, Paul Walmsley, Nishant Menon, Kevin Hilman. The separation of PMIC parameters into a separate structure which can be populated from the PMIC file is based on the work of Lun Chang from Motorola in an internal tree. Signed-off-by: Thara Gopinath <thara@ti.com> [khilman: fixed link error for OMAP2-only defconfig] Signed-off-by: Kevin Hilman <khilman@deeprootsystems.com>
Diffstat (limited to 'arch')
-rw-r--r--arch/arm/mach-omap2/Makefile5
-rw-r--r--arch/arm/mach-omap2/control.h17
-rw-r--r--arch/arm/mach-omap2/pm.c8
-rw-r--r--arch/arm/mach-omap2/voltage.c1226
-rw-r--r--arch/arm/plat-omap/include/plat/voltage.h134
5 files changed, 1388 insertions, 2 deletions
diff --git a/arch/arm/mach-omap2/Makefile b/arch/arm/mach-omap2/Makefile
index 1fce382a90a9..da7d53690d91 100644
--- a/arch/arm/mach-omap2/Makefile
+++ b/arch/arm/mach-omap2/Makefile
@@ -57,8 +57,9 @@ endif
57# Power Management 57# Power Management
58ifeq ($(CONFIG_PM),y) 58ifeq ($(CONFIG_PM),y)
59obj-$(CONFIG_ARCH_OMAP2) += pm24xx.o 59obj-$(CONFIG_ARCH_OMAP2) += pm24xx.o
60obj-$(CONFIG_ARCH_OMAP2) += sleep24xx.o pm_bus.o 60obj-$(CONFIG_ARCH_OMAP2) += sleep24xx.o pm_bus.o voltage.o
61obj-$(CONFIG_ARCH_OMAP3) += pm34xx.o sleep34xx.o cpuidle34xx.o pm_bus.o 61obj-$(CONFIG_ARCH_OMAP3) += pm34xx.o sleep34xx.o voltage.o \
62 cpuidle34xx.o pm_bus.o
62obj-$(CONFIG_ARCH_OMAP4) += pm44xx.o pm_bus.o 63obj-$(CONFIG_ARCH_OMAP4) += pm44xx.o pm_bus.o
63obj-$(CONFIG_PM_DEBUG) += pm-debug.o 64obj-$(CONFIG_PM_DEBUG) += pm-debug.o
64 65
diff --git a/arch/arm/mach-omap2/control.h b/arch/arm/mach-omap2/control.h
index 1ddc83bc2f84..b3df5c3300a9 100644
--- a/arch/arm/mach-omap2/control.h
+++ b/arch/arm/mach-omap2/control.h
@@ -148,6 +148,15 @@
148#define OMAP343X_CONTROL_TEST_KEY_11 (OMAP2_CONTROL_GENERAL + 0x00f4) 148#define OMAP343X_CONTROL_TEST_KEY_11 (OMAP2_CONTROL_GENERAL + 0x00f4)
149#define OMAP343X_CONTROL_TEST_KEY_12 (OMAP2_CONTROL_GENERAL + 0x00f8) 149#define OMAP343X_CONTROL_TEST_KEY_12 (OMAP2_CONTROL_GENERAL + 0x00f8)
150#define OMAP343X_CONTROL_TEST_KEY_13 (OMAP2_CONTROL_GENERAL + 0x00fc) 150#define OMAP343X_CONTROL_TEST_KEY_13 (OMAP2_CONTROL_GENERAL + 0x00fc)
151#define OMAP343X_CONTROL_FUSE_OPP1_VDD1 (OMAP2_CONTROL_GENERAL + 0x0110)
152#define OMAP343X_CONTROL_FUSE_OPP2_VDD1 (OMAP2_CONTROL_GENERAL + 0x0114)
153#define OMAP343X_CONTROL_FUSE_OPP3_VDD1 (OMAP2_CONTROL_GENERAL + 0x0118)
154#define OMAP343X_CONTROL_FUSE_OPP4_VDD1 (OMAP2_CONTROL_GENERAL + 0x011c)
155#define OMAP343X_CONTROL_FUSE_OPP5_VDD1 (OMAP2_CONTROL_GENERAL + 0x0120)
156#define OMAP343X_CONTROL_FUSE_OPP1_VDD2 (OMAP2_CONTROL_GENERAL + 0x0124)
157#define OMAP343X_CONTROL_FUSE_OPP2_VDD2 (OMAP2_CONTROL_GENERAL + 0x0128)
158#define OMAP343X_CONTROL_FUSE_OPP3_VDD2 (OMAP2_CONTROL_GENERAL + 0x012c)
159#define OMAP343X_CONTROL_FUSE_SR (OMAP2_CONTROL_GENERAL + 0x0130)
151#define OMAP343X_CONTROL_IVA2_BOOTADDR (OMAP2_CONTROL_GENERAL + 0x0190) 160#define OMAP343X_CONTROL_IVA2_BOOTADDR (OMAP2_CONTROL_GENERAL + 0x0190)
152#define OMAP343X_CONTROL_IVA2_BOOTMOD (OMAP2_CONTROL_GENERAL + 0x0194) 161#define OMAP343X_CONTROL_IVA2_BOOTMOD (OMAP2_CONTROL_GENERAL + 0x0194)
153#define OMAP343X_CONTROL_DEBOBS(i) (OMAP2_CONTROL_GENERAL + 0x01B0 \ 162#define OMAP343X_CONTROL_DEBOBS(i) (OMAP2_CONTROL_GENERAL + 0x01B0 \
@@ -164,6 +173,14 @@
164#define OMAP343X_CONTROL_SRAMLDO5 (OMAP2_CONTROL_GENERAL + 0x02C0) 173#define OMAP343X_CONTROL_SRAMLDO5 (OMAP2_CONTROL_GENERAL + 0x02C0)
165#define OMAP343X_CONTROL_CSI (OMAP2_CONTROL_GENERAL + 0x02C4) 174#define OMAP343X_CONTROL_CSI (OMAP2_CONTROL_GENERAL + 0x02C4)
166 175
176/* OMAP3630 only CONTROL_GENERAL register offsets */
177#define OMAP3630_CONTROL_FUSE_OPP1G_VDD1 (OMAP2_CONTROL_GENERAL + 0x0110)
178#define OMAP3630_CONTROL_FUSE_OPP50_VDD1 (OMAP2_CONTROL_GENERAL + 0x0114)
179#define OMAP3630_CONTROL_FUSE_OPP100_VDD1 (OMAP2_CONTROL_GENERAL + 0x0118)
180#define OMAP3630_CONTROL_FUSE_OPP120_VDD1 (OMAP2_CONTROL_GENERAL + 0x0120)
181#define OMAP3630_CONTROL_FUSE_OPP50_VDD2 (OMAP2_CONTROL_GENERAL + 0x0128)
182#define OMAP3630_CONTROL_FUSE_OPP100_VDD2 (OMAP2_CONTROL_GENERAL + 0x012C)
183
167/* AM35XX only CONTROL_GENERAL register offsets */ 184/* AM35XX only CONTROL_GENERAL register offsets */
168#define AM35XX_CONTROL_MSUSPENDMUX_6 (OMAP2_CONTROL_GENERAL + 0x0038) 185#define AM35XX_CONTROL_MSUSPENDMUX_6 (OMAP2_CONTROL_GENERAL + 0x0038)
169#define AM35XX_CONTROL_DEVCONF2 (OMAP2_CONTROL_GENERAL + 0x0310) 186#define AM35XX_CONTROL_DEVCONF2 (OMAP2_CONTROL_GENERAL + 0x0310)
diff --git a/arch/arm/mach-omap2/pm.c b/arch/arm/mach-omap2/pm.c
index 9b1db592759f..e828616fa8b9 100644
--- a/arch/arm/mach-omap2/pm.c
+++ b/arch/arm/mach-omap2/pm.c
@@ -17,6 +17,7 @@
17#include <plat/omap-pm.h> 17#include <plat/omap-pm.h>
18#include <plat/omap_device.h> 18#include <plat/omap_device.h>
19#include <plat/common.h> 19#include <plat/common.h>
20#include <plat/voltage.h>
20 21
21#include "powerdomain.h" 22#include "powerdomain.h"
22#include "clockdomain.h" 23#include "clockdomain.h"
@@ -163,3 +164,10 @@ static int __init omap2_common_pm_init(void)
163} 164}
164postcore_initcall(omap2_common_pm_init); 165postcore_initcall(omap2_common_pm_init);
165 166
167static int __init omap2_common_pm_late_init(void)
168{
169 omap_voltage_late_init();
170
171 return 0;
172}
173late_initcall(omap2_common_pm_late_init);
diff --git a/arch/arm/mach-omap2/voltage.c b/arch/arm/mach-omap2/voltage.c
new file mode 100644
index 000000000000..875667f130e3
--- /dev/null
+++ b/arch/arm/mach-omap2/voltage.c
@@ -0,0 +1,1226 @@
1/*
2 * OMAP3/OMAP4 Voltage Management Routines
3 *
4 * Author: Thara Gopinath <thara@ti.com>
5 *
6 * Copyright (C) 2007 Texas Instruments, Inc.
7 * Rajendra Nayak <rnayak@ti.com>
8 * Lesly A M <x0080970@ti.com>
9 *
10 * Copyright (C) 2008 Nokia Corporation
11 * Kalle Jokiniemi
12 *
13 * Copyright (C) 2010 Texas Instruments, Inc.
14 * Thara Gopinath <thara@ti.com>
15 *
16 * This program is free software; you can redistribute it and/or modify
17 * it under the terms of the GNU General Public License version 2 as
18 * published by the Free Software Foundation.
19 */
20
21#include <linux/delay.h>
22#include <linux/io.h>
23#include <linux/clk.h>
24#include <linux/err.h>
25#include <linux/debugfs.h>
26#include <linux/slab.h>
27
28#include <plat/common.h>
29#include <plat/voltage.h>
30
31#include "prm-regbits-34xx.h"
32#include "control.h"
33
34#define VP_IDLE_TIMEOUT 200
35#define VP_TRANXDONE_TIMEOUT 300
36#define VOLTAGE_DIR_SIZE 16
37
38/* Voltage processor register offsets */
39struct vp_reg_offs {
40 u8 vpconfig;
41 u8 vstepmin;
42 u8 vstepmax;
43 u8 vlimitto;
44 u8 vstatus;
45 u8 voltage;
46};
47
48/* Voltage Processor bit field values, shifts and masks */
49struct vp_reg_val {
50 /* PRM module */
51 u16 prm_mod;
52 /* VPx_VPCONFIG */
53 u32 vpconfig_erroroffset;
54 u16 vpconfig_errorgain;
55 u32 vpconfig_errorgain_mask;
56 u8 vpconfig_errorgain_shift;
57 u32 vpconfig_initvoltage_mask;
58 u8 vpconfig_initvoltage_shift;
59 u32 vpconfig_timeouten;
60 u32 vpconfig_initvdd;
61 u32 vpconfig_forceupdate;
62 u32 vpconfig_vpenable;
63 /* VPx_VSTEPMIN */
64 u8 vstepmin_stepmin;
65 u16 vstepmin_smpswaittimemin;
66 u8 vstepmin_stepmin_shift;
67 u8 vstepmin_smpswaittimemin_shift;
68 /* VPx_VSTEPMAX */
69 u8 vstepmax_stepmax;
70 u16 vstepmax_smpswaittimemax;
71 u8 vstepmax_stepmax_shift;
72 u8 vstepmax_smpswaittimemax_shift;
73 /* VPx_VLIMITTO */
74 u8 vlimitto_vddmin;
75 u8 vlimitto_vddmax;
76 u16 vlimitto_timeout;
77 u8 vlimitto_vddmin_shift;
78 u8 vlimitto_vddmax_shift;
79 u8 vlimitto_timeout_shift;
80 /* PRM_IRQSTATUS*/
81 u32 tranxdone_status;
82};
83
84/* Voltage controller registers and offsets */
85struct vc_reg_info {
86 /* PRM module */
87 u16 prm_mod;
88 /* VC register offsets */
89 u8 smps_sa_reg;
90 u8 smps_volra_reg;
91 u8 bypass_val_reg;
92 u8 cmdval_reg;
93 u8 voltsetup_reg;
94 /*VC_SMPS_SA*/
95 u8 smps_sa_shift;
96 u32 smps_sa_mask;
97 /* VC_SMPS_VOL_RA */
98 u8 smps_volra_shift;
99 u32 smps_volra_mask;
100 /* VC_BYPASS_VAL */
101 u8 data_shift;
102 u8 slaveaddr_shift;
103 u8 regaddr_shift;
104 u32 valid;
105 /* VC_CMD_VAL */
106 u8 cmd_on_shift;
107 u8 cmd_onlp_shift;
108 u8 cmd_ret_shift;
109 u8 cmd_off_shift;
110 u32 cmd_on_mask;
111 /* PRM_VOLTSETUP */
112 u8 voltsetup_shift;
113 u32 voltsetup_mask;
114};
115
116/**
117 * omap_vdd_info - Per Voltage Domain info
118 *
119 * @volt_data : voltage table having the distinct voltages supported
120 * by the domain and other associated per voltage data.
121 * @pmic_info : pmic specific parameters which should be populted by
122 * the pmic drivers.
123 * @vp_offs : structure containing the offsets for various
124 * vp registers
125 * @vp_reg : the register values, shifts, masks for various
126 * vp registers
127 * @vc_reg : structure containing various various vc registers,
128 * shifts, masks etc.
129 * @voltdm : pointer to the voltage domain structure
130 * @debug_dir : debug directory for this voltage domain.
131 * @curr_volt : current voltage for this vdd.
132 * @ocp_mod : The prm module for accessing the prm irqstatus reg.
133 * @prm_irqst_reg : prm irqstatus register.
134 * @vp_enabled : flag to keep track of whether vp is enabled or not
135 * @volt_scale : API to scale the voltage of the vdd.
136 */
137struct omap_vdd_info {
138 struct omap_volt_data *volt_data;
139 struct omap_volt_pmic_info *pmic_info;
140 struct vp_reg_offs vp_offs;
141 struct vp_reg_val vp_reg;
142 struct vc_reg_info vc_reg;
143 struct voltagedomain voltdm;
144 struct dentry *debug_dir;
145 u32 curr_volt;
146 u16 ocp_mod;
147 u8 prm_irqst_reg;
148 bool vp_enabled;
149 u32 (*read_reg) (u16 mod, u8 offset);
150 void (*write_reg) (u32 val, u16 mod, u8 offset);
151 int (*volt_scale) (struct omap_vdd_info *vdd,
152 unsigned long target_volt);
153};
154
155static struct omap_vdd_info *vdd_info;
156/*
157 * Number of scalable voltage domains.
158 */
159static int nr_scalable_vdd;
160
161/* OMAP3 VDD sturctures */
162static struct omap_vdd_info omap3_vdd_info[] = {
163 {
164 .vp_offs = {
165 .vpconfig = OMAP3_PRM_VP1_CONFIG_OFFSET,
166 .vstepmin = OMAP3_PRM_VP1_VSTEPMIN_OFFSET,
167 .vstepmax = OMAP3_PRM_VP1_VSTEPMAX_OFFSET,
168 .vlimitto = OMAP3_PRM_VP1_VLIMITTO_OFFSET,
169 .vstatus = OMAP3_PRM_VP1_STATUS_OFFSET,
170 .voltage = OMAP3_PRM_VP1_VOLTAGE_OFFSET,
171 },
172 .voltdm = {
173 .name = "mpu",
174 },
175 },
176 {
177 .vp_offs = {
178 .vpconfig = OMAP3_PRM_VP2_CONFIG_OFFSET,
179 .vstepmin = OMAP3_PRM_VP2_VSTEPMIN_OFFSET,
180 .vstepmax = OMAP3_PRM_VP2_VSTEPMAX_OFFSET,
181 .vlimitto = OMAP3_PRM_VP2_VLIMITTO_OFFSET,
182 .vstatus = OMAP3_PRM_VP2_STATUS_OFFSET,
183 .voltage = OMAP3_PRM_VP2_VOLTAGE_OFFSET,
184 },
185 .voltdm = {
186 .name = "core",
187 },
188 },
189};
190
191#define OMAP3_NR_SCALABLE_VDD ARRAY_SIZE(omap3_vdd_info)
192
193/*
194 * Structures containing OMAP3430/OMAP3630 voltage supported and various
195 * voltage dependent data for each VDD.
196 */
197#define VOLT_DATA_DEFINE(_v_nom, _efuse_offs, _errminlimit, _errgain) \
198{ \
199 .volt_nominal = _v_nom, \
200 .sr_efuse_offs = _efuse_offs, \
201 .sr_errminlimit = _errminlimit, \
202 .vp_errgain = _errgain \
203}
204
205/* VDD1 */
206static struct omap_volt_data omap34xx_vddmpu_volt_data[] = {
207 VOLT_DATA_DEFINE(OMAP3430_VDD_MPU_OPP1_UV, OMAP343X_CONTROL_FUSE_OPP1_VDD1, 0xf4, 0x0c),
208 VOLT_DATA_DEFINE(OMAP3430_VDD_MPU_OPP2_UV, OMAP343X_CONTROL_FUSE_OPP2_VDD1, 0xf4, 0x0c),
209 VOLT_DATA_DEFINE(OMAP3430_VDD_MPU_OPP3_UV, OMAP343X_CONTROL_FUSE_OPP3_VDD1, 0xf9, 0x18),
210 VOLT_DATA_DEFINE(OMAP3430_VDD_MPU_OPP4_UV, OMAP343X_CONTROL_FUSE_OPP4_VDD1, 0xf9, 0x18),
211 VOLT_DATA_DEFINE(OMAP3430_VDD_MPU_OPP5_UV, OMAP343X_CONTROL_FUSE_OPP5_VDD1, 0xf9, 0x18),
212 VOLT_DATA_DEFINE(0, 0, 0, 0),
213};
214
215static struct omap_volt_data omap36xx_vddmpu_volt_data[] = {
216 VOLT_DATA_DEFINE(OMAP3630_VDD_MPU_OPP50_UV, OMAP3630_CONTROL_FUSE_OPP50_VDD1, 0xf4, 0x0c),
217 VOLT_DATA_DEFINE(OMAP3630_VDD_MPU_OPP100_UV, OMAP3630_CONTROL_FUSE_OPP100_VDD1, 0xf9, 0x16),
218 VOLT_DATA_DEFINE(OMAP3630_VDD_MPU_OPP120_UV, OMAP3630_CONTROL_FUSE_OPP120_VDD1, 0xfa, 0x23),
219 VOLT_DATA_DEFINE(OMAP3630_VDD_MPU_OPP1G_UV, OMAP3630_CONTROL_FUSE_OPP1G_VDD1, 0xfa, 0x27),
220 VOLT_DATA_DEFINE(0, 0, 0, 0),
221};
222
223/* VDD2 */
224static struct omap_volt_data omap34xx_vddcore_volt_data[] = {
225 VOLT_DATA_DEFINE(OMAP3430_VDD_CORE_OPP1_UV, OMAP343X_CONTROL_FUSE_OPP1_VDD2, 0xf4, 0x0c),
226 VOLT_DATA_DEFINE(OMAP3430_VDD_CORE_OPP2_UV, OMAP343X_CONTROL_FUSE_OPP2_VDD2, 0xf4, 0x0c),
227 VOLT_DATA_DEFINE(OMAP3430_VDD_CORE_OPP3_UV, OMAP343X_CONTROL_FUSE_OPP3_VDD2, 0xf9, 0x18),
228 VOLT_DATA_DEFINE(0, 0, 0, 0),
229};
230
231static struct omap_volt_data omap36xx_vddcore_volt_data[] = {
232 VOLT_DATA_DEFINE(OMAP3630_VDD_CORE_OPP50_UV, OMAP3630_CONTROL_FUSE_OPP50_VDD2, 0xf4, 0x0c),
233 VOLT_DATA_DEFINE(OMAP3630_VDD_CORE_OPP100_UV, OMAP3630_CONTROL_FUSE_OPP100_VDD2, 0xf9, 0x16),
234 VOLT_DATA_DEFINE(0, 0, 0, 0),
235};
236
237static struct dentry *voltage_dir;
238
239/* Init function pointers */
240static void (*vc_init) (struct omap_vdd_info *vdd);
241static int (*vdd_data_configure) (struct omap_vdd_info *vdd);
242
243static u32 omap3_voltage_read_reg(u16 mod, u8 offset)
244{
245 return omap2_prm_read_mod_reg(mod, offset);
246}
247
248static void omap3_voltage_write_reg(u32 val, u16 mod, u8 offset)
249{
250 omap2_prm_write_mod_reg(val, mod, offset);
251}
252
253static void vp_latch_vsel(struct omap_vdd_info *vdd)
254{
255 u32 vpconfig;
256 u16 mod;
257 unsigned long uvdc;
258 char vsel;
259
260 uvdc = omap_voltage_get_nom_volt(&vdd->voltdm);
261 if (!uvdc) {
262 pr_warning("%s: unable to find current voltage for vdd_%s\n",
263 __func__, vdd->voltdm.name);
264 return;
265 }
266
267 if (!vdd->pmic_info || !vdd->pmic_info->uv_to_vsel) {
268 pr_warning("%s: PMIC function to convert voltage in uV to"
269 " vsel not registered\n", __func__);
270 return;
271 }
272
273 mod = vdd->vp_reg.prm_mod;
274
275 vsel = vdd->pmic_info->uv_to_vsel(uvdc);
276
277 vpconfig = vdd->read_reg(mod, vdd->vp_offs.vpconfig);
278 vpconfig &= ~(vdd->vp_reg.vpconfig_initvoltage_mask |
279 vdd->vp_reg.vpconfig_initvdd);
280 vpconfig |= vsel << vdd->vp_reg.vpconfig_initvoltage_shift;
281
282 vdd->write_reg(vpconfig, mod, vdd->vp_offs.vpconfig);
283
284 /* Trigger initVDD value copy to voltage processor */
285 vdd->write_reg((vpconfig | vdd->vp_reg.vpconfig_initvdd), mod,
286 vdd->vp_offs.vpconfig);
287
288 /* Clear initVDD copy trigger bit */
289 vdd->write_reg(vpconfig, mod, vdd->vp_offs.vpconfig);
290}
291
292/* Generic voltage init functions */
293static void __init vp_init(struct omap_vdd_info *vdd)
294{
295 u32 vp_val;
296 u16 mod;
297
298 if (!vdd->read_reg || !vdd->write_reg) {
299 pr_err("%s: No read/write API for accessing vdd_%s regs\n",
300 __func__, vdd->voltdm.name);
301 return;
302 }
303
304 mod = vdd->vp_reg.prm_mod;
305
306 vp_val = vdd->vp_reg.vpconfig_erroroffset |
307 (vdd->vp_reg.vpconfig_errorgain <<
308 vdd->vp_reg.vpconfig_errorgain_shift) |
309 vdd->vp_reg.vpconfig_timeouten;
310 vdd->write_reg(vp_val, mod, vdd->vp_offs.vpconfig);
311
312 vp_val = ((vdd->vp_reg.vstepmin_smpswaittimemin <<
313 vdd->vp_reg.vstepmin_smpswaittimemin_shift) |
314 (vdd->vp_reg.vstepmin_stepmin <<
315 vdd->vp_reg.vstepmin_stepmin_shift));
316 vdd->write_reg(vp_val, mod, vdd->vp_offs.vstepmin);
317
318 vp_val = ((vdd->vp_reg.vstepmax_smpswaittimemax <<
319 vdd->vp_reg.vstepmax_smpswaittimemax_shift) |
320 (vdd->vp_reg.vstepmax_stepmax <<
321 vdd->vp_reg.vstepmax_stepmax_shift));
322 vdd->write_reg(vp_val, mod, vdd->vp_offs.vstepmax);
323
324 vp_val = ((vdd->vp_reg.vlimitto_vddmax <<
325 vdd->vp_reg.vlimitto_vddmax_shift) |
326 (vdd->vp_reg.vlimitto_vddmin <<
327 vdd->vp_reg.vlimitto_vddmin_shift) |
328 (vdd->vp_reg.vlimitto_timeout <<
329 vdd->vp_reg.vlimitto_timeout_shift));
330 vdd->write_reg(vp_val, mod, vdd->vp_offs.vlimitto);
331}
332
333static void __init vdd_debugfs_init(struct omap_vdd_info *vdd)
334{
335 char *name;
336
337 name = kzalloc(VOLTAGE_DIR_SIZE, GFP_KERNEL);
338 if (!name) {
339 pr_warning("%s: Unable to allocate memory for debugfs"
340 " directory name for vdd_%s",
341 __func__, vdd->voltdm.name);
342 return;
343 }
344 strcpy(name, "vdd_");
345 strcat(name, vdd->voltdm.name);
346
347 vdd->debug_dir = debugfs_create_dir(name, voltage_dir);
348 if (IS_ERR(vdd->debug_dir)) {
349 pr_warning("%s: Unable to create debugfs directory for"
350 " vdd_%s\n", __func__, vdd->voltdm.name);
351 vdd->debug_dir = NULL;
352 }
353}
354
355/* Voltage scale and accessory APIs */
356static int _pre_volt_scale(struct omap_vdd_info *vdd,
357 unsigned long target_volt, u8 *target_vsel, u8 *current_vsel)
358{
359 struct omap_volt_data *volt_data;
360 u32 vc_cmdval, vp_errgain_val;
361 u16 vp_mod, vc_mod;
362
363 /* Check if suffiecient pmic info is available for this vdd */
364 if (!vdd->pmic_info) {
365 pr_err("%s: Insufficient pmic info to scale the vdd_%s\n",
366 __func__, vdd->voltdm.name);
367 return -EINVAL;
368 }
369
370 if (!vdd->pmic_info->uv_to_vsel) {
371 pr_err("%s: PMIC function to convert voltage in uV to"
372 "vsel not registered. Hence unable to scale voltage"
373 "for vdd_%s\n", __func__, vdd->voltdm.name);
374 return -ENODATA;
375 }
376
377 if (!vdd->read_reg || !vdd->write_reg) {
378 pr_err("%s: No read/write API for accessing vdd_%s regs\n",
379 __func__, vdd->voltdm.name);
380 return -EINVAL;
381 }
382
383 vp_mod = vdd->vp_reg.prm_mod;
384 vc_mod = vdd->vc_reg.prm_mod;
385
386 /* Get volt_data corresponding to target_volt */
387 volt_data = omap_voltage_get_voltdata(&vdd->voltdm, target_volt);
388 if (IS_ERR(volt_data))
389 volt_data = NULL;
390
391 *target_vsel = vdd->pmic_info->uv_to_vsel(target_volt);
392 *current_vsel = vdd->read_reg(vp_mod, vdd->vp_offs.voltage);
393
394 /* Setting the ON voltage to the new target voltage */
395 vc_cmdval = vdd->read_reg(vc_mod, vdd->vc_reg.cmdval_reg);
396 vc_cmdval &= ~vdd->vc_reg.cmd_on_mask;
397 vc_cmdval |= (*target_vsel << vdd->vc_reg.cmd_on_shift);
398 vdd->write_reg(vc_cmdval, vc_mod, vdd->vc_reg.cmdval_reg);
399
400 /* Setting vp errorgain based on the voltage */
401 if (volt_data) {
402 vp_errgain_val = vdd->read_reg(vp_mod,
403 vdd->vp_offs.vpconfig);
404 vdd->vp_reg.vpconfig_errorgain = volt_data->vp_errgain;
405 vp_errgain_val &= ~vdd->vp_reg.vpconfig_errorgain_mask;
406 vp_errgain_val |= vdd->vp_reg.vpconfig_errorgain <<
407 vdd->vp_reg.vpconfig_errorgain_shift;
408 vdd->write_reg(vp_errgain_val, vp_mod,
409 vdd->vp_offs.vpconfig);
410 }
411
412 return 0;
413}
414
415static void _post_volt_scale(struct omap_vdd_info *vdd,
416 unsigned long target_volt, u8 target_vsel, u8 current_vsel)
417{
418 u32 smps_steps = 0, smps_delay = 0;
419
420 smps_steps = abs(target_vsel - current_vsel);
421 /* SMPS slew rate / step size. 2us added as buffer. */
422 smps_delay = ((smps_steps * vdd->pmic_info->step_size) /
423 vdd->pmic_info->slew_rate) + 2;
424 udelay(smps_delay);
425
426 vdd->curr_volt = target_volt;
427}
428
429/* vc_bypass_scale_voltage - VC bypass method of voltage scaling */
430static int vc_bypass_scale_voltage(struct omap_vdd_info *vdd,
431 unsigned long target_volt)
432{
433 u32 loop_cnt = 0, retries_cnt = 0;
434 u32 vc_valid, vc_bypass_val_reg, vc_bypass_value;
435 u16 mod;
436 u8 target_vsel, current_vsel;
437 int ret;
438
439 ret = _pre_volt_scale(vdd, target_volt, &target_vsel, &current_vsel);
440 if (ret)
441 return ret;
442
443 mod = vdd->vc_reg.prm_mod;
444
445 vc_valid = vdd->vc_reg.valid;
446 vc_bypass_val_reg = vdd->vc_reg.bypass_val_reg;
447 vc_bypass_value = (target_vsel << vdd->vc_reg.data_shift) |
448 (vdd->pmic_info->pmic_reg <<
449 vdd->vc_reg.regaddr_shift) |
450 (vdd->pmic_info->i2c_slave_addr <<
451 vdd->vc_reg.slaveaddr_shift);
452
453 vdd->write_reg(vc_bypass_value, mod, vc_bypass_val_reg);
454 vdd->write_reg(vc_bypass_value | vc_valid, mod, vc_bypass_val_reg);
455
456 vc_bypass_value = vdd->read_reg(mod, vc_bypass_val_reg);
457 /*
458 * Loop till the bypass command is acknowledged from the SMPS.
459 * NOTE: This is legacy code. The loop count and retry count needs
460 * to be revisited.
461 */
462 while (!(vc_bypass_value & vc_valid)) {
463 loop_cnt++;
464
465 if (retries_cnt > 10) {
466 pr_warning("%s: Retry count exceeded\n", __func__);
467 return -ETIMEDOUT;
468 }
469
470 if (loop_cnt > 50) {
471 retries_cnt++;
472 loop_cnt = 0;
473 udelay(10);
474 }
475 vc_bypass_value = vdd->read_reg(mod, vc_bypass_val_reg);
476 }
477
478 _post_volt_scale(vdd, target_volt, target_vsel, current_vsel);
479 return 0;
480}
481
482/* VP force update method of voltage scaling */
483static int vp_forceupdate_scale_voltage(struct omap_vdd_info *vdd,
484 unsigned long target_volt)
485{
486 u32 vpconfig;
487 u16 mod, ocp_mod;
488 u8 target_vsel, current_vsel, prm_irqst_reg;
489 int ret, timeout = 0;
490
491 ret = _pre_volt_scale(vdd, target_volt, &target_vsel, &current_vsel);
492 if (ret)
493 return ret;
494
495 mod = vdd->vp_reg.prm_mod;
496 ocp_mod = vdd->ocp_mod;
497 prm_irqst_reg = vdd->prm_irqst_reg;
498
499 /*
500 * Clear all pending TransactionDone interrupt/status. Typical latency
501 * is <3us
502 */
503 while (timeout++ < VP_TRANXDONE_TIMEOUT) {
504 vdd->write_reg(vdd->vp_reg.tranxdone_status,
505 ocp_mod, prm_irqst_reg);
506 if (!(vdd->read_reg(ocp_mod, prm_irqst_reg) &
507 vdd->vp_reg.tranxdone_status))
508 break;
509 udelay(1);
510 }
511 if (timeout >= VP_TRANXDONE_TIMEOUT) {
512 pr_warning("%s: vdd_%s TRANXDONE timeout exceeded."
513 "Voltage change aborted", __func__, vdd->voltdm.name);
514 return -ETIMEDOUT;
515 }
516
517 /* Configure for VP-Force Update */
518 vpconfig = vdd->read_reg(mod, vdd->vp_offs.vpconfig);
519 vpconfig &= ~(vdd->vp_reg.vpconfig_initvdd |
520 vdd->vp_reg.vpconfig_forceupdate |
521 vdd->vp_reg.vpconfig_initvoltage_mask);
522 vpconfig |= ((target_vsel <<
523 vdd->vp_reg.vpconfig_initvoltage_shift));
524 vdd->write_reg(vpconfig, mod, vdd->vp_offs.vpconfig);
525
526 /* Trigger initVDD value copy to voltage processor */
527 vpconfig |= vdd->vp_reg.vpconfig_initvdd;
528 vdd->write_reg(vpconfig, mod, vdd->vp_offs.vpconfig);
529
530 /* Force update of voltage */
531 vpconfig |= vdd->vp_reg.vpconfig_forceupdate;
532 vdd->write_reg(vpconfig, mod, vdd->vp_offs.vpconfig);
533
534 /*
535 * Wait for TransactionDone. Typical latency is <200us.
536 * Depends on SMPSWAITTIMEMIN/MAX and voltage change
537 */
538 timeout = 0;
539 omap_test_timeout((vdd->read_reg(ocp_mod, prm_irqst_reg) &
540 vdd->vp_reg.tranxdone_status),
541 VP_TRANXDONE_TIMEOUT, timeout);
542 if (timeout >= VP_TRANXDONE_TIMEOUT)
543 pr_err("%s: vdd_%s TRANXDONE timeout exceeded."
544 "TRANXDONE never got set after the voltage update\n",
545 __func__, vdd->voltdm.name);
546
547 _post_volt_scale(vdd, target_volt, target_vsel, current_vsel);
548
549 /*
550 * Disable TransactionDone interrupt , clear all status, clear
551 * control registers
552 */
553 timeout = 0;
554 while (timeout++ < VP_TRANXDONE_TIMEOUT) {
555 vdd->write_reg(vdd->vp_reg.tranxdone_status,
556 ocp_mod, prm_irqst_reg);
557 if (!(vdd->read_reg(ocp_mod, prm_irqst_reg) &
558 vdd->vp_reg.tranxdone_status))
559 break;
560 udelay(1);
561 }
562
563 if (timeout >= VP_TRANXDONE_TIMEOUT)
564 pr_warning("%s: vdd_%s TRANXDONE timeout exceeded while trying"
565 "to clear the TRANXDONE status\n",
566 __func__, vdd->voltdm.name);
567
568 vpconfig = vdd->read_reg(mod, vdd->vp_offs.vpconfig);
569 /* Clear initVDD copy trigger bit */
570 vpconfig &= ~vdd->vp_reg.vpconfig_initvdd;;
571 vdd->write_reg(vpconfig, mod, vdd->vp_offs.vpconfig);
572 /* Clear force bit */
573 vpconfig &= ~vdd->vp_reg.vpconfig_forceupdate;
574 vdd->write_reg(vpconfig, mod, vdd->vp_offs.vpconfig);
575
576 return 0;
577}
578
579/* OMAP3 specific voltage init functions */
580
581/*
582 * Intializes the voltage controller registers with the PMIC and board
583 * specific parameters and voltage setup times for OMAP3.
584 */
585static void __init omap3_vc_init(struct omap_vdd_info *vdd)
586{
587 u32 vc_val;
588 u16 mod;
589 u8 on_vsel, onlp_vsel, ret_vsel, off_vsel;
590 static bool is_initialized;
591
592 if (!vdd->pmic_info || !vdd->pmic_info->uv_to_vsel) {
593 pr_err("%s: PMIC info requried to configure vc for"
594 "vdd_%s not populated.Hence cannot initialize vc\n",
595 __func__, vdd->voltdm.name);
596 return;
597 }
598
599 if (!vdd->read_reg || !vdd->write_reg) {
600 pr_err("%s: No read/write API for accessing vdd_%s regs\n",
601 __func__, vdd->voltdm.name);
602 return;
603 }
604
605 mod = vdd->vc_reg.prm_mod;
606
607 /* Set up the SMPS_SA(i2c slave address in VC */
608 vc_val = vdd->read_reg(mod, vdd->vc_reg.smps_sa_reg);
609 vc_val &= ~vdd->vc_reg.smps_sa_mask;
610 vc_val |= vdd->pmic_info->i2c_slave_addr << vdd->vc_reg.smps_sa_shift;
611 vdd->write_reg(vc_val, mod, vdd->vc_reg.smps_sa_reg);
612
613 /* Setup the VOLRA(pmic reg addr) in VC */
614 vc_val = vdd->read_reg(mod, vdd->vc_reg.smps_volra_reg);
615 vc_val &= ~vdd->vc_reg.smps_volra_mask;
616 vc_val |= vdd->pmic_info->pmic_reg << vdd->vc_reg.smps_volra_shift;
617 vdd->write_reg(vc_val, mod, vdd->vc_reg.smps_volra_reg);
618
619 /*Configure the setup times */
620 vc_val = vdd->read_reg(mod, vdd->vc_reg.voltsetup_reg);
621 vc_val &= ~vdd->vc_reg.voltsetup_mask;
622 vc_val |= vdd->pmic_info->volt_setup_time <<
623 vdd->vc_reg.voltsetup_shift;
624 vdd->write_reg(vc_val, mod, vdd->vc_reg.voltsetup_reg);
625
626 /* Set up the on, inactive, retention and off voltage */
627 on_vsel = vdd->pmic_info->uv_to_vsel(vdd->pmic_info->on_volt);
628 onlp_vsel = vdd->pmic_info->uv_to_vsel(vdd->pmic_info->onlp_volt);
629 ret_vsel = vdd->pmic_info->uv_to_vsel(vdd->pmic_info->ret_volt);
630 off_vsel = vdd->pmic_info->uv_to_vsel(vdd->pmic_info->off_volt);
631 vc_val = ((on_vsel << vdd->vc_reg.cmd_on_shift) |
632 (onlp_vsel << vdd->vc_reg.cmd_onlp_shift) |
633 (ret_vsel << vdd->vc_reg.cmd_ret_shift) |
634 (off_vsel << vdd->vc_reg.cmd_off_shift));
635 vdd->write_reg(vc_val, mod, vdd->vc_reg.cmdval_reg);
636
637 if (is_initialized)
638 return;
639
640 /* Generic VC parameters init */
641 vdd->write_reg(OMAP3430_CMD1_MASK | OMAP3430_RAV1_MASK, mod,
642 OMAP3_PRM_VC_CH_CONF_OFFSET);
643 vdd->write_reg(OMAP3430_MCODE_SHIFT | OMAP3430_HSEN_MASK, mod,
644 OMAP3_PRM_VC_I2C_CFG_OFFSET);
645 vdd->write_reg(OMAP3_CLKSETUP, mod, OMAP3_PRM_CLKSETUP_OFFSET);
646 vdd->write_reg(OMAP3_VOLTOFFSET, mod, OMAP3_PRM_VOLTOFFSET_OFFSET);
647 vdd->write_reg(OMAP3_VOLTSETUP2, mod, OMAP3_PRM_VOLTSETUP2_OFFSET);
648 is_initialized = true;
649}
650
651/* Sets up all the VDD related info for OMAP3 */
652static int __init omap3_vdd_data_configure(struct omap_vdd_info *vdd)
653{
654 struct clk *sys_ck;
655 u32 sys_clk_speed, timeout_val, waittime;
656
657 if (!vdd->pmic_info) {
658 pr_err("%s: PMIC info requried to configure vdd_%s not"
659 "populated.Hence cannot initialize vdd_%s\n",
660 __func__, vdd->voltdm.name, vdd->voltdm.name);
661 return -EINVAL;
662 }
663
664 if (!strcmp(vdd->voltdm.name, "mpu")) {
665 if (cpu_is_omap3630())
666 vdd->volt_data = omap36xx_vddmpu_volt_data;
667 else
668 vdd->volt_data = omap34xx_vddmpu_volt_data;
669
670 vdd->vp_reg.tranxdone_status = OMAP3430_VP1_TRANXDONE_ST_MASK;
671 vdd->vc_reg.cmdval_reg = OMAP3_PRM_VC_CMD_VAL_0_OFFSET;
672 vdd->vc_reg.smps_sa_shift = OMAP3430_PRM_VC_SMPS_SA_SA0_SHIFT;
673 vdd->vc_reg.smps_sa_mask = OMAP3430_PRM_VC_SMPS_SA_SA0_MASK;
674 vdd->vc_reg.smps_volra_shift = OMAP3430_VOLRA0_SHIFT;
675 vdd->vc_reg.smps_volra_mask = OMAP3430_VOLRA0_MASK;
676 vdd->vc_reg.voltsetup_shift = OMAP3430_SETUP_TIME1_SHIFT;
677 vdd->vc_reg.voltsetup_mask = OMAP3430_SETUP_TIME1_MASK;
678 } else if (!strcmp(vdd->voltdm.name, "core")) {
679 if (cpu_is_omap3630())
680 vdd->volt_data = omap36xx_vddcore_volt_data;
681 else
682 vdd->volt_data = omap34xx_vddcore_volt_data;
683
684 vdd->vp_reg.tranxdone_status = OMAP3430_VP2_TRANXDONE_ST_MASK;
685 vdd->vc_reg.cmdval_reg = OMAP3_PRM_VC_CMD_VAL_1_OFFSET;
686 vdd->vc_reg.smps_sa_shift = OMAP3430_PRM_VC_SMPS_SA_SA1_SHIFT;
687 vdd->vc_reg.smps_sa_mask = OMAP3430_PRM_VC_SMPS_SA_SA1_MASK;
688 vdd->vc_reg.smps_volra_shift = OMAP3430_VOLRA1_SHIFT;
689 vdd->vc_reg.smps_volra_mask = OMAP3430_VOLRA1_MASK;
690 vdd->vc_reg.voltsetup_shift = OMAP3430_SETUP_TIME2_SHIFT;
691 vdd->vc_reg.voltsetup_mask = OMAP3430_SETUP_TIME2_MASK;
692 } else {
693 pr_warning("%s: vdd_%s does not exisit in OMAP3\n",
694 __func__, vdd->voltdm.name);
695 return -EINVAL;
696 }
697
698 /*
699 * Sys clk rate is require to calculate vp timeout value and
700 * smpswaittimemin and smpswaittimemax.
701 */
702 sys_ck = clk_get(NULL, "sys_ck");
703 if (IS_ERR(sys_ck)) {
704 pr_warning("%s: Could not get the sys clk to calculate"
705 "various vdd_%s params\n", __func__, vdd->voltdm.name);
706 return -EINVAL;
707 }
708 sys_clk_speed = clk_get_rate(sys_ck);
709 clk_put(sys_ck);
710 /* Divide to avoid overflow */
711 sys_clk_speed /= 1000;
712
713 /* Generic voltage parameters */
714 vdd->curr_volt = 1200000;
715 vdd->ocp_mod = OCP_MOD;
716 vdd->prm_irqst_reg = OMAP3_PRM_IRQSTATUS_MPU_OFFSET;
717 vdd->read_reg = omap3_voltage_read_reg;
718 vdd->write_reg = omap3_voltage_write_reg;
719 vdd->volt_scale = vp_forceupdate_scale_voltage;
720 vdd->vp_enabled = false;
721
722 /* VC parameters */
723 vdd->vc_reg.prm_mod = OMAP3430_GR_MOD;
724 vdd->vc_reg.smps_sa_reg = OMAP3_PRM_VC_SMPS_SA_OFFSET;
725 vdd->vc_reg.smps_volra_reg = OMAP3_PRM_VC_SMPS_VOL_RA_OFFSET;
726 vdd->vc_reg.bypass_val_reg = OMAP3_PRM_VC_BYPASS_VAL_OFFSET;
727 vdd->vc_reg.voltsetup_reg = OMAP3_PRM_VOLTSETUP1_OFFSET;
728 vdd->vc_reg.data_shift = OMAP3430_DATA_SHIFT;
729 vdd->vc_reg.slaveaddr_shift = OMAP3430_SLAVEADDR_SHIFT;
730 vdd->vc_reg.regaddr_shift = OMAP3430_REGADDR_SHIFT;
731 vdd->vc_reg.valid = OMAP3430_VALID_MASK;
732 vdd->vc_reg.cmd_on_shift = OMAP3430_VC_CMD_ON_SHIFT;
733 vdd->vc_reg.cmd_on_mask = OMAP3430_VC_CMD_ON_MASK;
734 vdd->vc_reg.cmd_onlp_shift = OMAP3430_VC_CMD_ONLP_SHIFT;
735 vdd->vc_reg.cmd_ret_shift = OMAP3430_VC_CMD_RET_SHIFT;
736 vdd->vc_reg.cmd_off_shift = OMAP3430_VC_CMD_OFF_SHIFT;
737
738 vdd->vp_reg.prm_mod = OMAP3430_GR_MOD;
739
740 /* VPCONFIG bit fields */
741 vdd->vp_reg.vpconfig_erroroffset = (vdd->pmic_info->vp_erroroffset <<
742 OMAP3430_ERROROFFSET_SHIFT);
743 vdd->vp_reg.vpconfig_errorgain_mask = OMAP3430_ERRORGAIN_MASK;
744 vdd->vp_reg.vpconfig_errorgain_shift = OMAP3430_ERRORGAIN_SHIFT;
745 vdd->vp_reg.vpconfig_initvoltage_shift = OMAP3430_INITVOLTAGE_SHIFT;
746 vdd->vp_reg.vpconfig_initvoltage_mask = OMAP3430_INITVOLTAGE_MASK;
747 vdd->vp_reg.vpconfig_timeouten = OMAP3430_TIMEOUTEN_MASK;
748 vdd->vp_reg.vpconfig_initvdd = OMAP3430_INITVDD_MASK;
749 vdd->vp_reg.vpconfig_forceupdate = OMAP3430_FORCEUPDATE_MASK;
750 vdd->vp_reg.vpconfig_vpenable = OMAP3430_VPENABLE_MASK;
751
752 /* VSTEPMIN VSTEPMAX bit fields */
753 waittime = ((vdd->pmic_info->step_size / vdd->pmic_info->slew_rate) *
754 sys_clk_speed) / 1000;
755 vdd->vp_reg.vstepmin_smpswaittimemin = waittime;
756 vdd->vp_reg.vstepmax_smpswaittimemax = waittime;
757 vdd->vp_reg.vstepmin_stepmin = vdd->pmic_info->vp_vstepmin;
758 vdd->vp_reg.vstepmax_stepmax = vdd->pmic_info->vp_vstepmax;
759 vdd->vp_reg.vstepmin_smpswaittimemin_shift =
760 OMAP3430_SMPSWAITTIMEMIN_SHIFT;
761 vdd->vp_reg.vstepmax_smpswaittimemax_shift =
762 OMAP3430_SMPSWAITTIMEMAX_SHIFT;
763 vdd->vp_reg.vstepmin_stepmin_shift = OMAP3430_VSTEPMIN_SHIFT;
764 vdd->vp_reg.vstepmax_stepmax_shift = OMAP3430_VSTEPMAX_SHIFT;
765
766 /* VLIMITTO bit fields */
767 timeout_val = (sys_clk_speed * vdd->pmic_info->vp_timeout_us) / 1000;
768 vdd->vp_reg.vlimitto_timeout = timeout_val;
769 vdd->vp_reg.vlimitto_vddmin = vdd->pmic_info->vp_vddmin;
770 vdd->vp_reg.vlimitto_vddmax = vdd->pmic_info->vp_vddmax;
771 vdd->vp_reg.vlimitto_vddmin_shift = OMAP3430_VDDMIN_SHIFT;
772 vdd->vp_reg.vlimitto_vddmax_shift = OMAP3430_VDDMAX_SHIFT;
773 vdd->vp_reg.vlimitto_timeout_shift = OMAP3430_TIMEOUT_SHIFT;
774
775 return 0;
776}
777
778/* Public functions */
779/**
780 * omap_voltage_get_nom_volt() - Gets the current non-auto-compensated voltage
781 * @voltdm: pointer to the VDD for which current voltage info is needed
782 *
783 * API to get the current non-auto-compensated voltage for a VDD.
784 * Returns 0 in case of error else returns the current voltage for the VDD.
785 */
786unsigned long omap_voltage_get_nom_volt(struct voltagedomain *voltdm)
787{
788 struct omap_vdd_info *vdd;
789
790 if (!voltdm || IS_ERR(voltdm)) {
791 pr_warning("%s: VDD specified does not exist!\n", __func__);
792 return 0;
793 }
794
795 vdd = container_of(voltdm, struct omap_vdd_info, voltdm);
796
797 return vdd->curr_volt;
798}
799
800/**
801 * omap_vp_get_curr_volt() - API to get the current vp voltage.
802 * @voltdm: pointer to the VDD.
803 *
804 * This API returns the current voltage for the specified voltage processor
805 */
806unsigned long omap_vp_get_curr_volt(struct voltagedomain *voltdm)
807{
808 struct omap_vdd_info *vdd;
809 u8 curr_vsel;
810
811 if (!voltdm || IS_ERR(voltdm)) {
812 pr_warning("%s: VDD specified does not exist!\n", __func__);
813 return 0;
814 }
815
816 vdd = container_of(voltdm, struct omap_vdd_info, voltdm);
817 if (!vdd->read_reg) {
818 pr_err("%s: No read API for reading vdd_%s regs\n",
819 __func__, voltdm->name);
820 return 0;
821 }
822
823 curr_vsel = vdd->read_reg(vdd->vp_reg.prm_mod,
824 vdd->vp_offs.voltage);
825
826 if (!vdd->pmic_info || !vdd->pmic_info->vsel_to_uv) {
827 pr_warning("%s: PMIC function to convert vsel to voltage"
828 "in uV not registerd\n", __func__);
829 return 0;
830 }
831
832 return vdd->pmic_info->vsel_to_uv(curr_vsel);
833}
834
835/**
836 * omap_vp_enable() - API to enable a particular VP
837 * @voltdm: pointer to the VDD whose VP is to be enabled.
838 *
839 * This API enables a particular voltage processor. Needed by the smartreflex
840 * class drivers.
841 */
842void omap_vp_enable(struct voltagedomain *voltdm)
843{
844 struct omap_vdd_info *vdd;
845 u32 vpconfig;
846 u16 mod;
847
848 if (!voltdm || IS_ERR(voltdm)) {
849 pr_warning("%s: VDD specified does not exist!\n", __func__);
850 return;
851 }
852
853 vdd = container_of(voltdm, struct omap_vdd_info, voltdm);
854 if (!vdd->read_reg || !vdd->write_reg) {
855 pr_err("%s: No read/write API for accessing vdd_%s regs\n",
856 __func__, voltdm->name);
857 return;
858 }
859
860 mod = vdd->vp_reg.prm_mod;
861
862 /* If VP is already enabled, do nothing. Return */
863 if (vdd->vp_enabled)
864 return;
865
866 vp_latch_vsel(vdd);
867
868 /* Enable VP */
869 vpconfig = vdd->read_reg(mod, vdd->vp_offs.vpconfig);
870 vpconfig |= vdd->vp_reg.vpconfig_vpenable;
871 vdd->write_reg(vpconfig, mod, vdd->vp_offs.vpconfig);
872 vdd->vp_enabled = true;
873}
874
875/**
876 * omap_vp_disable() - API to disable a particular VP
877 * @voltdm: pointer to the VDD whose VP is to be disabled.
878 *
879 * This API disables a particular voltage processor. Needed by the smartreflex
880 * class drivers.
881 */
882void omap_vp_disable(struct voltagedomain *voltdm)
883{
884 struct omap_vdd_info *vdd;
885 u32 vpconfig;
886 u16 mod;
887 int timeout;
888
889 if (!voltdm || IS_ERR(voltdm)) {
890 pr_warning("%s: VDD specified does not exist!\n", __func__);
891 return;
892 }
893
894 vdd = container_of(voltdm, struct omap_vdd_info, voltdm);
895 if (!vdd->read_reg || !vdd->write_reg) {
896 pr_err("%s: No read/write API for accessing vdd_%s regs\n",
897 __func__, voltdm->name);
898 return;
899 }
900
901 mod = vdd->vp_reg.prm_mod;
902
903 /* If VP is already disabled, do nothing. Return */
904 if (!vdd->vp_enabled) {
905 pr_warning("%s: Trying to disable VP for vdd_%s when"
906 "it is already disabled\n", __func__, voltdm->name);
907 return;
908 }
909
910 /* Disable VP */
911 vpconfig = vdd->read_reg(mod, vdd->vp_offs.vpconfig);
912 vpconfig &= ~vdd->vp_reg.vpconfig_vpenable;
913 vdd->write_reg(vpconfig, mod, vdd->vp_offs.vpconfig);
914
915 /*
916 * Wait for VP idle Typical latency is <2us. Maximum latency is ~100us
917 */
918 omap_test_timeout((vdd->read_reg(mod, vdd->vp_offs.vstatus)),
919 VP_IDLE_TIMEOUT, timeout);
920
921 if (timeout >= VP_IDLE_TIMEOUT)
922 pr_warning("%s: vdd_%s idle timedout\n",
923 __func__, voltdm->name);
924
925 vdd->vp_enabled = false;
926
927 return;
928}
929
930/**
931 * omap_voltage_scale_vdd() - API to scale voltage of a particular
932 * voltage domain.
933 * @voltdm: pointer to the VDD which is to be scaled.
934 * @target_volt: The target voltage of the voltage domain
935 *
936 * This API should be called by the kernel to do the voltage scaling
937 * for a particular voltage domain during dvfs or any other situation.
938 */
939int omap_voltage_scale_vdd(struct voltagedomain *voltdm,
940 unsigned long target_volt)
941{
942 struct omap_vdd_info *vdd;
943
944 if (!voltdm || IS_ERR(voltdm)) {
945 pr_warning("%s: VDD specified does not exist!\n", __func__);
946 return -EINVAL;
947 }
948
949 vdd = container_of(voltdm, struct omap_vdd_info, voltdm);
950
951 if (!vdd->volt_scale) {
952 pr_err("%s: No voltage scale API registered for vdd_%s\n",
953 __func__, voltdm->name);
954 return -ENODATA;
955 }
956
957 return vdd->volt_scale(vdd, target_volt);
958}
959
960/**
961 * omap_voltage_reset() - Resets the voltage of a particular voltage domain
962 * to that of the current OPP.
963 * @voltdm: pointer to the VDD whose voltage is to be reset.
964 *
965 * This API finds out the correct voltage the voltage domain is supposed
966 * to be at and resets the voltage to that level. Should be used expecially
967 * while disabling any voltage compensation modules.
968 */
969void omap_voltage_reset(struct voltagedomain *voltdm)
970{
971 unsigned long target_uvdc;
972
973 if (!voltdm || IS_ERR(voltdm)) {
974 pr_warning("%s: VDD specified does not exist!\n", __func__);
975 return;
976 }
977
978 target_uvdc = omap_voltage_get_nom_volt(voltdm);
979 if (!target_uvdc) {
980 pr_err("%s: unable to find current voltage for vdd_%s\n",
981 __func__, voltdm->name);
982 return;
983 }
984
985 omap_voltage_scale_vdd(voltdm, target_uvdc);
986}
987
988/**
989 * omap_voltage_get_volttable() - API to get the voltage table associated with a
990 * particular voltage domain.
991 * @voltdm: pointer to the VDD for which the voltage table is required
992 * @volt_data: the voltage table for the particular vdd which is to be
993 * populated by this API
994 *
995 * This API populates the voltage table associated with a VDD into the
996 * passed parameter pointer. Returns the count of distinct voltages
997 * supported by this vdd.
998 *
999 */
1000void omap_voltage_get_volttable(struct voltagedomain *voltdm,
1001 struct omap_volt_data **volt_data)
1002{
1003 struct omap_vdd_info *vdd;
1004
1005 if (!voltdm || IS_ERR(voltdm)) {
1006 pr_warning("%s: VDD specified does not exist!\n", __func__);
1007 return;
1008 }
1009
1010 vdd = container_of(voltdm, struct omap_vdd_info, voltdm);
1011
1012 *volt_data = vdd->volt_data;
1013}
1014
1015/**
1016 * omap_voltage_get_voltdata() - API to get the voltage table entry for a
1017 * particular voltage
1018 * @voltdm: pointer to the VDD whose voltage table has to be searched
1019 * @volt: the voltage to be searched in the voltage table
1020 *
1021 * This API searches through the voltage table for the required voltage
1022 * domain and tries to find a matching entry for the passed voltage volt.
1023 * If a matching entry is found volt_data is populated with that entry.
1024 * This API searches only through the non-compensated voltages int the
1025 * voltage table.
1026 * Returns pointer to the voltage table entry corresponding to volt on
1027 * sucess. Returns -ENODATA if no voltage table exisits for the passed voltage
1028 * domain or if there is no matching entry.
1029 */
1030struct omap_volt_data *omap_voltage_get_voltdata(struct voltagedomain *voltdm,
1031 unsigned long volt)
1032{
1033 struct omap_vdd_info *vdd;
1034 int i;
1035
1036 if (!voltdm || IS_ERR(voltdm)) {
1037 pr_warning("%s: VDD specified does not exist!\n", __func__);
1038 return ERR_PTR(-EINVAL);
1039 }
1040
1041 vdd = container_of(voltdm, struct omap_vdd_info, voltdm);
1042
1043 if (!vdd->volt_data) {
1044 pr_warning("%s: voltage table does not exist for vdd_%s\n",
1045 __func__, voltdm->name);
1046 return ERR_PTR(-ENODATA);
1047 }
1048
1049 for (i = 0; vdd->volt_data[i].volt_nominal != 0; i++) {
1050 if (vdd->volt_data[i].volt_nominal == volt)
1051 return &vdd->volt_data[i];
1052 }
1053
1054 pr_notice("%s: Unable to match the current voltage with the voltage"
1055 "table for vdd_%s\n", __func__, voltdm->name);
1056
1057 return ERR_PTR(-ENODATA);
1058}
1059
1060/**
1061 * omap_voltage_register_pmic() - API to register PMIC specific data
1062 * @voltdm: pointer to the VDD for which the PMIC specific data is
1063 * to be registered
1064 * @pmic_info: the structure containing pmic info
1065 *
1066 * This API is to be called by the SOC/PMIC file to specify the
1067 * pmic specific info as present in omap_volt_pmic_info structure.
1068 */
1069int omap_voltage_register_pmic(struct voltagedomain *voltdm,
1070 struct omap_volt_pmic_info *pmic_info)
1071{
1072 struct omap_vdd_info *vdd;
1073
1074 if (!voltdm || IS_ERR(voltdm)) {
1075 pr_warning("%s: VDD specified does not exist!\n", __func__);
1076 return -EINVAL;
1077 }
1078
1079 vdd = container_of(voltdm, struct omap_vdd_info, voltdm);
1080
1081 vdd->pmic_info = pmic_info;
1082
1083 return 0;
1084}
1085
1086/**
1087 * omap_voltage_get_dbgdir() - API to get pointer to the debugfs directory
1088 * corresponding to a voltage domain.
1089 *
1090 * @voltdm: pointer to the VDD whose debug directory is required.
1091 *
1092 * This API returns pointer to the debugfs directory corresponding
1093 * to the voltage domain. Should be used by drivers requiring to
1094 * add any debug entry for a particular voltage domain. Returns NULL
1095 * in case of error.
1096 */
1097struct dentry *omap_voltage_get_dbgdir(struct voltagedomain *voltdm)
1098{
1099 struct omap_vdd_info *vdd;
1100
1101 if (!voltdm || IS_ERR(voltdm)) {
1102 pr_warning("%s: VDD specified does not exist!\n", __func__);
1103 return NULL;
1104 }
1105
1106 vdd = container_of(voltdm, struct omap_vdd_info, voltdm);
1107
1108 return vdd->debug_dir;
1109}
1110
1111/**
1112 * omap_change_voltscale_method() - API to change the voltage scaling method.
1113 * @voltdm: pointer to the VDD whose voltage scaling method
1114 * has to be changed.
1115 * @voltscale_method: the method to be used for voltage scaling.
1116 *
1117 * This API can be used by the board files to change the method of voltage
1118 * scaling between vpforceupdate and vcbypass. The parameter values are
1119 * defined in voltage.h
1120 */
1121void omap_change_voltscale_method(struct voltagedomain *voltdm,
1122 int voltscale_method)
1123{
1124 struct omap_vdd_info *vdd;
1125
1126 if (!voltdm || IS_ERR(voltdm)) {
1127 pr_warning("%s: VDD specified does not exist!\n", __func__);
1128 return;
1129 }
1130
1131 vdd = container_of(voltdm, struct omap_vdd_info, voltdm);
1132
1133 switch (voltscale_method) {
1134 case VOLTSCALE_VPFORCEUPDATE:
1135 vdd->volt_scale = vp_forceupdate_scale_voltage;
1136 return;
1137 case VOLTSCALE_VCBYPASS:
1138 vdd->volt_scale = vc_bypass_scale_voltage;
1139 return;
1140 default:
1141 pr_warning("%s: Trying to change the method of voltage scaling"
1142 "to an unsupported one!\n", __func__);
1143 }
1144}
1145
1146/**
1147 * omap_voltage_domain_lookup() - API to get the voltage domain pointer
1148 * @name: Name of the voltage domain
1149 *
1150 * This API looks up in the global vdd_info struct for the
1151 * existence of voltage domain <name>. If it exists, the API returns
1152 * a pointer to the voltage domain structure corresponding to the
1153 * VDD<name>. Else retuns error pointer.
1154 */
1155struct voltagedomain *omap_voltage_domain_lookup(char *name)
1156{
1157 int i;
1158
1159 if (!vdd_info) {
1160 pr_err("%s: Voltage driver init not yet happened.Faulting!\n",
1161 __func__);
1162 return ERR_PTR(-EINVAL);
1163 }
1164
1165 if (!name) {
1166 pr_err("%s: No name to get the votage domain!\n", __func__);
1167 return ERR_PTR(-EINVAL);
1168 }
1169
1170 for (i = 0; i < nr_scalable_vdd; i++) {
1171 if (!(strcmp(name, vdd_info[i].voltdm.name)))
1172 return &vdd_info[i].voltdm;
1173 }
1174
1175 return ERR_PTR(-EINVAL);
1176}
1177
1178/**
1179 * omap_voltage_late_init() - Init the various voltage parameters
1180 *
1181 * This API is to be called in the later stages of the
1182 * system boot to init the voltage controller and
1183 * voltage processors.
1184 */
1185int __init omap_voltage_late_init(void)
1186{
1187 int i;
1188
1189 if (!vdd_info) {
1190 pr_err("%s: Voltage driver support not added\n",
1191 __func__);
1192 return -EINVAL;
1193 }
1194
1195 voltage_dir = debugfs_create_dir("voltage", NULL);
1196 if (IS_ERR(voltage_dir))
1197 pr_err("%s: Unable to create voltage debugfs main dir\n",
1198 __func__);
1199 for (i = 0; i < nr_scalable_vdd; i++) {
1200 if (vdd_data_configure(&vdd_info[i]))
1201 continue;
1202 vc_init(&vdd_info[i]);
1203 vp_init(&vdd_info[i]);
1204 vdd_debugfs_init(&vdd_info[i]);
1205 }
1206
1207 return 0;
1208}
1209
1210/**
1211 * omap_voltage_early_init()- Volatage driver early init
1212 */
1213static int __init omap_voltage_early_init(void)
1214{
1215 if (cpu_is_omap34xx()) {
1216 vdd_info = omap3_vdd_info;
1217 nr_scalable_vdd = OMAP3_NR_SCALABLE_VDD;
1218 vc_init = omap3_vc_init;
1219 vdd_data_configure = omap3_vdd_data_configure;
1220 } else {
1221 pr_warning("%s: voltage driver support not added\n", __func__);
1222 }
1223
1224 return 0;
1225}
1226core_initcall(omap_voltage_early_init);
diff --git a/arch/arm/plat-omap/include/plat/voltage.h b/arch/arm/plat-omap/include/plat/voltage.h
new file mode 100644
index 000000000000..2f4f59abd19f
--- /dev/null
+++ b/arch/arm/plat-omap/include/plat/voltage.h
@@ -0,0 +1,134 @@
1/*
2 * OMAP Voltage Management Routines
3 *
4 * Author: Thara Gopinath <thara@ti.com>
5 *
6 * Copyright (C) 2009 Texas Instruments, Inc.
7 * Thara Gopinath <thara@ti.com>
8 *
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License version 2 as
11 * published by the Free Software Foundation.
12 */
13
14#ifndef __ARCH_ARM_MACH_OMAP2_VOLTAGE_H
15#define __ARCH_ARM_MACH_OMAP2_VOLTAGE_H
16
17#define VOLTSCALE_VPFORCEUPDATE 1
18#define VOLTSCALE_VCBYPASS 2
19
20/*
21 * OMAP3 GENERIC setup times. Revisit to see if these needs to be
22 * passed from board or PMIC file
23 */
24#define OMAP3_CLKSETUP 0xff
25#define OMAP3_VOLTOFFSET 0xff
26#define OMAP3_VOLTSETUP2 0xff
27
28/* Voltage value defines */
29#define OMAP3430_VDD_MPU_OPP1_UV 975000
30#define OMAP3430_VDD_MPU_OPP2_UV 1075000
31#define OMAP3430_VDD_MPU_OPP3_UV 1200000
32#define OMAP3430_VDD_MPU_OPP4_UV 1270000
33#define OMAP3430_VDD_MPU_OPP5_UV 1350000
34
35#define OMAP3430_VDD_CORE_OPP1_UV 975000
36#define OMAP3430_VDD_CORE_OPP2_UV 1050000
37#define OMAP3430_VDD_CORE_OPP3_UV 1150000
38
39#define OMAP3630_VDD_MPU_OPP50_UV 1012500
40#define OMAP3630_VDD_MPU_OPP100_UV 1200000
41#define OMAP3630_VDD_MPU_OPP120_UV 1325000
42#define OMAP3630_VDD_MPU_OPP1G_UV 1375000
43
44#define OMAP3630_VDD_CORE_OPP50_UV 1000000
45#define OMAP3630_VDD_CORE_OPP100_UV 1200000
46
47/**
48 * struct voltagedomain - omap voltage domain global structure.
49 * @name: Name of the voltage domain which can be used as a unique
50 * identifier.
51 */
52struct voltagedomain {
53 char *name;
54};
55
56/* API to get the voltagedomain pointer */
57struct voltagedomain *omap_voltage_domain_lookup(char *name);
58
59/**
60 * struct omap_volt_data - Omap voltage specific data.
61 * @voltage_nominal: The possible voltage value in uV
62 * @sr_efuse_offs: The offset of the efuse register(from system
63 * control module base address) from where to read
64 * the n-target value for the smartreflex module.
65 * @sr_errminlimit: Error min limit value for smartreflex. This value
66 * differs at differnet opp and thus is linked
67 * with voltage.
68 * @vp_errorgain: Error gain value for the voltage processor. This
69 * field also differs according to the voltage/opp.
70 */
71struct omap_volt_data {
72 u32 volt_nominal;
73 u32 sr_efuse_offs;
74 u8 sr_errminlimit;
75 u8 vp_errgain;
76};
77
78/**
79 * struct omap_volt_pmic_info - PMIC specific data required by voltage driver.
80 * @slew_rate: PMIC slew rate (in uv/us)
81 * @step_size: PMIC voltage step size (in uv)
82 * @vsel_to_uv: PMIC API to convert vsel value to actual voltage in uV.
83 * @uv_to_vsel: PMIC API to convert voltage in uV to vsel value.
84 */
85struct omap_volt_pmic_info {
86 int slew_rate;
87 int step_size;
88 u32 on_volt;
89 u32 onlp_volt;
90 u32 ret_volt;
91 u32 off_volt;
92 u16 volt_setup_time;
93 u8 vp_erroroffset;
94 u8 vp_vstepmin;
95 u8 vp_vstepmax;
96 u8 vp_vddmin;
97 u8 vp_vddmax;
98 u8 vp_timeout_us;
99 u8 i2c_slave_addr;
100 u8 pmic_reg;
101 unsigned long (*vsel_to_uv) (const u8 vsel);
102 u8 (*uv_to_vsel) (unsigned long uV);
103};
104
105unsigned long omap_vp_get_curr_volt(struct voltagedomain *voltdm);
106void omap_vp_enable(struct voltagedomain *voltdm);
107void omap_vp_disable(struct voltagedomain *voltdm);
108int omap_voltage_scale_vdd(struct voltagedomain *voltdm,
109 unsigned long target_volt);
110void omap_voltage_reset(struct voltagedomain *voltdm);
111void omap_voltage_get_volttable(struct voltagedomain *voltdm,
112 struct omap_volt_data **volt_data);
113struct omap_volt_data *omap_voltage_get_voltdata(struct voltagedomain *voltdm,
114 unsigned long volt);
115unsigned long omap_voltage_get_nom_volt(struct voltagedomain *voltdm);
116struct dentry *omap_voltage_get_dbgdir(struct voltagedomain *voltdm);
117#ifdef CONFIG_PM
118int omap_voltage_register_pmic(struct voltagedomain *voltdm,
119 struct omap_volt_pmic_info *pmic_info);
120void omap_change_voltscale_method(struct voltagedomain *voltdm,
121 int voltscale_method);
122int omap_voltage_late_init(void);
123#else
124static inline int omap_voltage_register_pmic(struct voltagedomain *voltdm,
125 struct omap_volt_pmic_info *pmic_info) {}
126static inline void omap_change_voltscale_method(struct voltagedomain *voltdm,
127 int voltscale_method) {}
128static inline int omap_voltage_late_init(void)
129{
130 return -EINVAL;
131}
132#endif
133
134#endif