diff options
author | Glenn Elliott <gelliott@cs.unc.edu> | 2012-03-04 19:47:13 -0500 |
---|---|---|
committer | Glenn Elliott <gelliott@cs.unc.edu> | 2012-03-04 19:47:13 -0500 |
commit | c71c03bda1e86c9d5198c5d83f712e695c4f2a1e (patch) | |
tree | ecb166cb3e2b7e2adb3b5e292245fefd23381ac8 /arch/arm/mach-omap2/omap_twl.c | |
parent | ea53c912f8a86a8567697115b6a0d8152beee5c8 (diff) | |
parent | 6a00f206debf8a5c8899055726ad127dbeeed098 (diff) |
Merge branch 'mpi-master' into wip-k-fmlpwip-k-fmlp
Conflicts:
litmus/sched_cedf.c
Diffstat (limited to 'arch/arm/mach-omap2/omap_twl.c')
-rw-r--r-- | arch/arm/mach-omap2/omap_twl.c | 339 |
1 files changed, 339 insertions, 0 deletions
diff --git a/arch/arm/mach-omap2/omap_twl.c b/arch/arm/mach-omap2/omap_twl.c new file mode 100644 index 000000000000..07d6140baa9d --- /dev/null +++ b/arch/arm/mach-omap2/omap_twl.c | |||
@@ -0,0 +1,339 @@ | |||
1 | /** | ||
2 | * OMAP and TWL PMIC specific intializations. | ||
3 | * | ||
4 | * Copyright (C) 2010 Texas Instruments Incorporated. | ||
5 | * Thara Gopinath | ||
6 | * Copyright (C) 2009 Texas Instruments Incorporated. | ||
7 | * Nishanth Menon | ||
8 | * Copyright (C) 2009 Nokia Corporation | ||
9 | * Paul Walmsley | ||
10 | * | ||
11 | * This program is free software; you can redistribute it and/or modify | ||
12 | * it under the terms of the GNU General Public License version 2 as | ||
13 | * published by the Free Software Foundation. | ||
14 | */ | ||
15 | |||
16 | #include <linux/err.h> | ||
17 | #include <linux/io.h> | ||
18 | #include <linux/kernel.h> | ||
19 | #include <linux/i2c/twl.h> | ||
20 | |||
21 | #include "voltage.h" | ||
22 | |||
23 | #include "pm.h" | ||
24 | |||
25 | #define OMAP3_SRI2C_SLAVE_ADDR 0x12 | ||
26 | #define OMAP3_VDD_MPU_SR_CONTROL_REG 0x00 | ||
27 | #define OMAP3_VDD_CORE_SR_CONTROL_REG 0x01 | ||
28 | #define OMAP3_VP_CONFIG_ERROROFFSET 0x00 | ||
29 | #define OMAP3_VP_VSTEPMIN_VSTEPMIN 0x1 | ||
30 | #define OMAP3_VP_VSTEPMAX_VSTEPMAX 0x04 | ||
31 | #define OMAP3_VP_VLIMITTO_TIMEOUT_US 200 | ||
32 | |||
33 | #define OMAP3430_VP1_VLIMITTO_VDDMIN 0x14 | ||
34 | #define OMAP3430_VP1_VLIMITTO_VDDMAX 0x42 | ||
35 | #define OMAP3430_VP2_VLIMITTO_VDDMIN 0x18 | ||
36 | #define OMAP3430_VP2_VLIMITTO_VDDMAX 0x2c | ||
37 | |||
38 | #define OMAP3630_VP1_VLIMITTO_VDDMIN 0x18 | ||
39 | #define OMAP3630_VP1_VLIMITTO_VDDMAX 0x3c | ||
40 | #define OMAP3630_VP2_VLIMITTO_VDDMIN 0x18 | ||
41 | #define OMAP3630_VP2_VLIMITTO_VDDMAX 0x30 | ||
42 | |||
43 | #define OMAP4_SRI2C_SLAVE_ADDR 0x12 | ||
44 | #define OMAP4_VDD_MPU_SR_VOLT_REG 0x55 | ||
45 | #define OMAP4_VDD_IVA_SR_VOLT_REG 0x5B | ||
46 | #define OMAP4_VDD_CORE_SR_VOLT_REG 0x61 | ||
47 | |||
48 | #define OMAP4_VP_CONFIG_ERROROFFSET 0x00 | ||
49 | #define OMAP4_VP_VSTEPMIN_VSTEPMIN 0x01 | ||
50 | #define OMAP4_VP_VSTEPMAX_VSTEPMAX 0x04 | ||
51 | #define OMAP4_VP_VLIMITTO_TIMEOUT_US 200 | ||
52 | |||
53 | #define OMAP4_VP_MPU_VLIMITTO_VDDMIN 0xA | ||
54 | #define OMAP4_VP_MPU_VLIMITTO_VDDMAX 0x39 | ||
55 | #define OMAP4_VP_IVA_VLIMITTO_VDDMIN 0xA | ||
56 | #define OMAP4_VP_IVA_VLIMITTO_VDDMAX 0x2D | ||
57 | #define OMAP4_VP_CORE_VLIMITTO_VDDMIN 0xA | ||
58 | #define OMAP4_VP_CORE_VLIMITTO_VDDMAX 0x28 | ||
59 | |||
60 | static bool is_offset_valid; | ||
61 | static u8 smps_offset; | ||
62 | /* | ||
63 | * Flag to ensure Smartreflex bit in TWL | ||
64 | * being cleared in board file is not overwritten. | ||
65 | */ | ||
66 | static bool __initdata twl_sr_enable_autoinit; | ||
67 | |||
68 | #define TWL4030_DCDC_GLOBAL_CFG 0x06 | ||
69 | #define REG_SMPS_OFFSET 0xE0 | ||
70 | #define SMARTREFLEX_ENABLE BIT(3) | ||
71 | |||
72 | static unsigned long twl4030_vsel_to_uv(const u8 vsel) | ||
73 | { | ||
74 | return (((vsel * 125) + 6000)) * 100; | ||
75 | } | ||
76 | |||
77 | static u8 twl4030_uv_to_vsel(unsigned long uv) | ||
78 | { | ||
79 | return DIV_ROUND_UP(uv - 600000, 12500); | ||
80 | } | ||
81 | |||
82 | static unsigned long twl6030_vsel_to_uv(const u8 vsel) | ||
83 | { | ||
84 | /* | ||
85 | * In TWL6030 depending on the value of SMPS_OFFSET | ||
86 | * efuse register the voltage range supported in | ||
87 | * standard mode can be either between 0.6V - 1.3V or | ||
88 | * 0.7V - 1.4V. In TWL6030 ES1.0 SMPS_OFFSET efuse | ||
89 | * is programmed to all 0's where as starting from | ||
90 | * TWL6030 ES1.1 the efuse is programmed to 1 | ||
91 | */ | ||
92 | if (!is_offset_valid) { | ||
93 | twl_i2c_read_u8(TWL6030_MODULE_ID0, &smps_offset, | ||
94 | REG_SMPS_OFFSET); | ||
95 | is_offset_valid = true; | ||
96 | } | ||
97 | |||
98 | /* | ||
99 | * There is no specific formula for voltage to vsel | ||
100 | * conversion above 1.3V. There are special hardcoded | ||
101 | * values for voltages above 1.3V. Currently we are | ||
102 | * hardcoding only for 1.35 V which is used for 1GH OPP for | ||
103 | * OMAP4430. | ||
104 | */ | ||
105 | if (vsel == 0x3A) | ||
106 | return 1350000; | ||
107 | |||
108 | if (smps_offset & 0x8) | ||
109 | return ((((vsel - 1) * 125) + 7000)) * 100; | ||
110 | else | ||
111 | return ((((vsel - 1) * 125) + 6000)) * 100; | ||
112 | } | ||
113 | |||
114 | static u8 twl6030_uv_to_vsel(unsigned long uv) | ||
115 | { | ||
116 | /* | ||
117 | * In TWL6030 depending on the value of SMPS_OFFSET | ||
118 | * efuse register the voltage range supported in | ||
119 | * standard mode can be either between 0.6V - 1.3V or | ||
120 | * 0.7V - 1.4V. In TWL6030 ES1.0 SMPS_OFFSET efuse | ||
121 | * is programmed to all 0's where as starting from | ||
122 | * TWL6030 ES1.1 the efuse is programmed to 1 | ||
123 | */ | ||
124 | if (!is_offset_valid) { | ||
125 | twl_i2c_read_u8(TWL6030_MODULE_ID0, &smps_offset, | ||
126 | REG_SMPS_OFFSET); | ||
127 | is_offset_valid = true; | ||
128 | } | ||
129 | |||
130 | /* | ||
131 | * There is no specific formula for voltage to vsel | ||
132 | * conversion above 1.3V. There are special hardcoded | ||
133 | * values for voltages above 1.3V. Currently we are | ||
134 | * hardcoding only for 1.35 V which is used for 1GH OPP for | ||
135 | * OMAP4430. | ||
136 | */ | ||
137 | if (uv == 1350000) | ||
138 | return 0x3A; | ||
139 | |||
140 | if (smps_offset & 0x8) | ||
141 | return DIV_ROUND_UP(uv - 700000, 12500) + 1; | ||
142 | else | ||
143 | return DIV_ROUND_UP(uv - 600000, 12500) + 1; | ||
144 | } | ||
145 | |||
146 | static struct omap_volt_pmic_info omap3_mpu_volt_info = { | ||
147 | .slew_rate = 4000, | ||
148 | .step_size = 12500, | ||
149 | .on_volt = 1200000, | ||
150 | .onlp_volt = 1000000, | ||
151 | .ret_volt = 975000, | ||
152 | .off_volt = 600000, | ||
153 | .volt_setup_time = 0xfff, | ||
154 | .vp_erroroffset = OMAP3_VP_CONFIG_ERROROFFSET, | ||
155 | .vp_vstepmin = OMAP3_VP_VSTEPMIN_VSTEPMIN, | ||
156 | .vp_vstepmax = OMAP3_VP_VSTEPMAX_VSTEPMAX, | ||
157 | .vp_vddmin = OMAP3430_VP1_VLIMITTO_VDDMIN, | ||
158 | .vp_vddmax = OMAP3430_VP1_VLIMITTO_VDDMAX, | ||
159 | .vp_timeout_us = OMAP3_VP_VLIMITTO_TIMEOUT_US, | ||
160 | .i2c_slave_addr = OMAP3_SRI2C_SLAVE_ADDR, | ||
161 | .pmic_reg = OMAP3_VDD_MPU_SR_CONTROL_REG, | ||
162 | .vsel_to_uv = twl4030_vsel_to_uv, | ||
163 | .uv_to_vsel = twl4030_uv_to_vsel, | ||
164 | }; | ||
165 | |||
166 | static struct omap_volt_pmic_info omap3_core_volt_info = { | ||
167 | .slew_rate = 4000, | ||
168 | .step_size = 12500, | ||
169 | .on_volt = 1200000, | ||
170 | .onlp_volt = 1000000, | ||
171 | .ret_volt = 975000, | ||
172 | .off_volt = 600000, | ||
173 | .volt_setup_time = 0xfff, | ||
174 | .vp_erroroffset = OMAP3_VP_CONFIG_ERROROFFSET, | ||
175 | .vp_vstepmin = OMAP3_VP_VSTEPMIN_VSTEPMIN, | ||
176 | .vp_vstepmax = OMAP3_VP_VSTEPMAX_VSTEPMAX, | ||
177 | .vp_vddmin = OMAP3430_VP2_VLIMITTO_VDDMIN, | ||
178 | .vp_vddmax = OMAP3430_VP2_VLIMITTO_VDDMAX, | ||
179 | .vp_timeout_us = OMAP3_VP_VLIMITTO_TIMEOUT_US, | ||
180 | .i2c_slave_addr = OMAP3_SRI2C_SLAVE_ADDR, | ||
181 | .pmic_reg = OMAP3_VDD_CORE_SR_CONTROL_REG, | ||
182 | .vsel_to_uv = twl4030_vsel_to_uv, | ||
183 | .uv_to_vsel = twl4030_uv_to_vsel, | ||
184 | }; | ||
185 | |||
186 | static struct omap_volt_pmic_info omap4_mpu_volt_info = { | ||
187 | .slew_rate = 4000, | ||
188 | .step_size = 12500, | ||
189 | .on_volt = 1350000, | ||
190 | .onlp_volt = 1350000, | ||
191 | .ret_volt = 837500, | ||
192 | .off_volt = 600000, | ||
193 | .volt_setup_time = 0, | ||
194 | .vp_erroroffset = OMAP4_VP_CONFIG_ERROROFFSET, | ||
195 | .vp_vstepmin = OMAP4_VP_VSTEPMIN_VSTEPMIN, | ||
196 | .vp_vstepmax = OMAP4_VP_VSTEPMAX_VSTEPMAX, | ||
197 | .vp_vddmin = OMAP4_VP_MPU_VLIMITTO_VDDMIN, | ||
198 | .vp_vddmax = OMAP4_VP_MPU_VLIMITTO_VDDMAX, | ||
199 | .vp_timeout_us = OMAP4_VP_VLIMITTO_TIMEOUT_US, | ||
200 | .i2c_slave_addr = OMAP4_SRI2C_SLAVE_ADDR, | ||
201 | .pmic_reg = OMAP4_VDD_MPU_SR_VOLT_REG, | ||
202 | .vsel_to_uv = twl6030_vsel_to_uv, | ||
203 | .uv_to_vsel = twl6030_uv_to_vsel, | ||
204 | }; | ||
205 | |||
206 | static struct omap_volt_pmic_info omap4_iva_volt_info = { | ||
207 | .slew_rate = 4000, | ||
208 | .step_size = 12500, | ||
209 | .on_volt = 1100000, | ||
210 | .onlp_volt = 1100000, | ||
211 | .ret_volt = 837500, | ||
212 | .off_volt = 600000, | ||
213 | .volt_setup_time = 0, | ||
214 | .vp_erroroffset = OMAP4_VP_CONFIG_ERROROFFSET, | ||
215 | .vp_vstepmin = OMAP4_VP_VSTEPMIN_VSTEPMIN, | ||
216 | .vp_vstepmax = OMAP4_VP_VSTEPMAX_VSTEPMAX, | ||
217 | .vp_vddmin = OMAP4_VP_IVA_VLIMITTO_VDDMIN, | ||
218 | .vp_vddmax = OMAP4_VP_IVA_VLIMITTO_VDDMAX, | ||
219 | .vp_timeout_us = OMAP4_VP_VLIMITTO_TIMEOUT_US, | ||
220 | .i2c_slave_addr = OMAP4_SRI2C_SLAVE_ADDR, | ||
221 | .pmic_reg = OMAP4_VDD_IVA_SR_VOLT_REG, | ||
222 | .vsel_to_uv = twl6030_vsel_to_uv, | ||
223 | .uv_to_vsel = twl6030_uv_to_vsel, | ||
224 | }; | ||
225 | |||
226 | static struct omap_volt_pmic_info omap4_core_volt_info = { | ||
227 | .slew_rate = 4000, | ||
228 | .step_size = 12500, | ||
229 | .on_volt = 1100000, | ||
230 | .onlp_volt = 1100000, | ||
231 | .ret_volt = 837500, | ||
232 | .off_volt = 600000, | ||
233 | .volt_setup_time = 0, | ||
234 | .vp_erroroffset = OMAP4_VP_CONFIG_ERROROFFSET, | ||
235 | .vp_vstepmin = OMAP4_VP_VSTEPMIN_VSTEPMIN, | ||
236 | .vp_vstepmax = OMAP4_VP_VSTEPMAX_VSTEPMAX, | ||
237 | .vp_vddmin = OMAP4_VP_CORE_VLIMITTO_VDDMIN, | ||
238 | .vp_vddmax = OMAP4_VP_CORE_VLIMITTO_VDDMAX, | ||
239 | .vp_timeout_us = OMAP4_VP_VLIMITTO_TIMEOUT_US, | ||
240 | .i2c_slave_addr = OMAP4_SRI2C_SLAVE_ADDR, | ||
241 | .pmic_reg = OMAP4_VDD_CORE_SR_VOLT_REG, | ||
242 | .vsel_to_uv = twl6030_vsel_to_uv, | ||
243 | .uv_to_vsel = twl6030_uv_to_vsel, | ||
244 | }; | ||
245 | |||
246 | int __init omap4_twl_init(void) | ||
247 | { | ||
248 | struct voltagedomain *voltdm; | ||
249 | |||
250 | if (!cpu_is_omap44xx()) | ||
251 | return -ENODEV; | ||
252 | |||
253 | voltdm = omap_voltage_domain_lookup("mpu"); | ||
254 | omap_voltage_register_pmic(voltdm, &omap4_mpu_volt_info); | ||
255 | |||
256 | voltdm = omap_voltage_domain_lookup("iva"); | ||
257 | omap_voltage_register_pmic(voltdm, &omap4_iva_volt_info); | ||
258 | |||
259 | voltdm = omap_voltage_domain_lookup("core"); | ||
260 | omap_voltage_register_pmic(voltdm, &omap4_core_volt_info); | ||
261 | |||
262 | return 0; | ||
263 | } | ||
264 | |||
265 | int __init omap3_twl_init(void) | ||
266 | { | ||
267 | struct voltagedomain *voltdm; | ||
268 | |||
269 | if (!cpu_is_omap34xx()) | ||
270 | return -ENODEV; | ||
271 | |||
272 | if (cpu_is_omap3630()) { | ||
273 | omap3_mpu_volt_info.vp_vddmin = OMAP3630_VP1_VLIMITTO_VDDMIN; | ||
274 | omap3_mpu_volt_info.vp_vddmax = OMAP3630_VP1_VLIMITTO_VDDMAX; | ||
275 | omap3_core_volt_info.vp_vddmin = OMAP3630_VP2_VLIMITTO_VDDMIN; | ||
276 | omap3_core_volt_info.vp_vddmax = OMAP3630_VP2_VLIMITTO_VDDMAX; | ||
277 | } | ||
278 | |||
279 | /* | ||
280 | * The smartreflex bit on twl4030 specifies if the setting of voltage | ||
281 | * is done over the I2C_SR path. Since this setting is independent of | ||
282 | * the actual usage of smartreflex AVS module, we enable TWL SR bit | ||
283 | * by default irrespective of whether smartreflex AVS module is enabled | ||
284 | * on the OMAP side or not. This is because without this bit enabled, | ||
285 | * the voltage scaling through vp forceupdate/bypass mechanism of | ||
286 | * voltage scaling will not function on TWL over I2C_SR. | ||
287 | */ | ||
288 | if (!twl_sr_enable_autoinit) | ||
289 | omap3_twl_set_sr_bit(true); | ||
290 | |||
291 | voltdm = omap_voltage_domain_lookup("mpu"); | ||
292 | omap_voltage_register_pmic(voltdm, &omap3_mpu_volt_info); | ||
293 | |||
294 | voltdm = omap_voltage_domain_lookup("core"); | ||
295 | omap_voltage_register_pmic(voltdm, &omap3_core_volt_info); | ||
296 | |||
297 | return 0; | ||
298 | } | ||
299 | |||
300 | /** | ||
301 | * omap3_twl_set_sr_bit() - Set/Clear SR bit on TWL | ||
302 | * @enable: enable SR mode in twl or not | ||
303 | * | ||
304 | * If 'enable' is true, enables Smartreflex bit on TWL 4030 to make sure | ||
305 | * voltage scaling through OMAP SR works. Else, the smartreflex bit | ||
306 | * on twl4030 is cleared as there are platforms which use OMAP3 and T2 but | ||
307 | * use Synchronized Scaling Hardware Strategy (ENABLE_VMODE=1) and Direct | ||
308 | * Strategy Software Scaling Mode (ENABLE_VMODE=0), for setting the voltages, | ||
309 | * in those scenarios this bit is to be cleared (enable = false). | ||
310 | * | ||
311 | * Returns 0 on success, error is returned if I2C read/write fails. | ||
312 | */ | ||
313 | int __init omap3_twl_set_sr_bit(bool enable) | ||
314 | { | ||
315 | u8 temp; | ||
316 | int ret; | ||
317 | if (twl_sr_enable_autoinit) | ||
318 | pr_warning("%s: unexpected multiple calls\n", __func__); | ||
319 | |||
320 | ret = twl_i2c_read_u8(TWL4030_MODULE_PM_RECEIVER, &temp, | ||
321 | TWL4030_DCDC_GLOBAL_CFG); | ||
322 | if (ret) | ||
323 | goto err; | ||
324 | |||
325 | if (enable) | ||
326 | temp |= SMARTREFLEX_ENABLE; | ||
327 | else | ||
328 | temp &= ~SMARTREFLEX_ENABLE; | ||
329 | |||
330 | ret = twl_i2c_write_u8(TWL4030_MODULE_PM_RECEIVER, temp, | ||
331 | TWL4030_DCDC_GLOBAL_CFG); | ||
332 | if (!ret) { | ||
333 | twl_sr_enable_autoinit = true; | ||
334 | return 0; | ||
335 | } | ||
336 | err: | ||
337 | pr_err("%s: Error access to TWL4030 (%d)\n", __func__, ret); | ||
338 | return ret; | ||
339 | } | ||