aboutsummaryrefslogtreecommitdiffstats
path: root/arch/arm
diff options
context:
space:
mode:
authorDaniel Walker <dwalker@codeaurora.org>2010-03-03 11:54:11 -0500
committerDaniel Walker <dwalker@codeaurora.org>2010-05-12 12:14:20 -0400
commit43b39f9f040fd49a094222f70857e3690ce653a3 (patch)
tree33ad6a143fb86df54f0cada4acf19d95b5234343 /arch/arm
parent9f68fcdb8f9b0f55830f58b02cecc5c26b0ba17b (diff)
arm: msm: add cpu frequency controls
This adds acpuclock-arm11.c from Google. This provides control over the cpu frequency for arm11 cpu's. This has shared authorship between Google, and Qualcomm. Most of it was written by Mike Chan at Google. Signed-off-by: Daniel Walker <dwalker@codeaurora.org>
Diffstat (limited to 'arch/arm')
-rw-r--r--arch/arm/mach-msm/Makefile1
-rw-r--r--arch/arm/mach-msm/acpuclock-arm11.c523
-rw-r--r--arch/arm/mach-msm/acpuclock.h32
-rw-r--r--arch/arm/mach-msm/include/mach/board.h11
4 files changed, 567 insertions, 0 deletions
diff --git a/arch/arm/mach-msm/Makefile b/arch/arm/mach-msm/Makefile
index 91e6f5c95dc1..0cb523fe3b3e 100644
--- a/arch/arm/mach-msm/Makefile
+++ b/arch/arm/mach-msm/Makefile
@@ -2,6 +2,7 @@ obj-y += io.o idle.o irq.o timer.o dma.o
2obj-y += devices.o 2obj-y += devices.o
3obj-y += proc_comm.o 3obj-y += proc_comm.o
4obj-y += vreg.o 4obj-y += vreg.o
5obj-y += acpuclock-arm11.o
5obj-y += clock.o clock-7x01a.o 6obj-y += clock.o clock-7x01a.o
6 7
7obj-$(CONFIG_MACH_HALIBUT) += board-halibut.o 8obj-$(CONFIG_MACH_HALIBUT) += board-halibut.o
diff --git a/arch/arm/mach-msm/acpuclock-arm11.c b/arch/arm/mach-msm/acpuclock-arm11.c
new file mode 100644
index 000000000000..f9c9035bd9bb
--- /dev/null
+++ b/arch/arm/mach-msm/acpuclock-arm11.c
@@ -0,0 +1,523 @@
1/* arch/arm/mach-msm/acpuclock.c
2 *
3 * MSM architecture clock driver
4 *
5 * Copyright (C) 2007 Google, Inc.
6 * Copyright (c) 2007 QUALCOMM Incorporated
7 * Author: San Mehat <san@android.com>
8 *
9 * This software is licensed under the terms of the GNU General Public
10 * License version 2, as published by the Free Software Foundation, and
11 * may be copied, distributed, and modified under those terms.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 */
19
20#include <linux/version.h>
21#include <linux/kernel.h>
22#include <linux/init.h>
23#include <linux/list.h>
24#include <linux/errno.h>
25#include <linux/string.h>
26#include <linux/delay.h>
27#include <linux/clk.h>
28#include <linux/cpufreq.h>
29#include <linux/mutex.h>
30#include <linux/io.h>
31#include <mach/board.h>
32#include <mach/msm_iomap.h>
33
34#include "proc_comm.h"
35#include "acpuclock.h"
36
37
38#define A11S_CLK_CNTL_ADDR (MSM_CSR_BASE + 0x100)
39#define A11S_CLK_SEL_ADDR (MSM_CSR_BASE + 0x104)
40#define A11S_VDD_SVS_PLEVEL_ADDR (MSM_CSR_BASE + 0x124)
41
42/*
43 * ARM11 clock configuration for specific ACPU speeds
44 */
45
46#define ACPU_PLL_TCXO -1
47#define ACPU_PLL_0 0
48#define ACPU_PLL_1 1
49#define ACPU_PLL_2 2
50#define ACPU_PLL_3 3
51
52#define PERF_SWITCH_DEBUG 0
53#define PERF_SWITCH_STEP_DEBUG 0
54
55struct clock_state
56{
57 struct clkctl_acpu_speed *current_speed;
58 struct mutex lock;
59 uint32_t acpu_switch_time_us;
60 uint32_t max_speed_delta_khz;
61 uint32_t vdd_switch_time_us;
62 unsigned long power_collapse_khz;
63 unsigned long wait_for_irq_khz;
64};
65
66static struct clk *ebi1_clk;
67static struct clock_state drv_state = { 0 };
68
69static void __init acpuclk_init(void);
70
71/* MSM7201A Levels 3-6 all correspond to 1.2V, level 7 corresponds to 1.325V. */
72enum {
73 VDD_0 = 0,
74 VDD_1 = 1,
75 VDD_2 = 2,
76 VDD_3 = 3,
77 VDD_4 = 3,
78 VDD_5 = 3,
79 VDD_6 = 3,
80 VDD_7 = 7,
81 VDD_END
82};
83
84struct clkctl_acpu_speed {
85 unsigned int a11clk_khz;
86 int pll;
87 unsigned int a11clk_src_sel;
88 unsigned int a11clk_src_div;
89 unsigned int ahbclk_khz;
90 unsigned int ahbclk_div;
91 int vdd;
92 unsigned int axiclk_khz;
93 unsigned long lpj; /* loops_per_jiffy */
94/* Index in acpu_freq_tbl[] for steppings. */
95 short down;
96 short up;
97};
98
99/*
100 * ACPU speed table. Complete table is shown but certain speeds are commented
101 * out to optimized speed switching. Initalize loops_per_jiffy to 0.
102 *
103 * Table stepping up/down is optimized for 256mhz jumps while staying on the
104 * same PLL.
105 */
106#if (0)
107static struct clkctl_acpu_speed acpu_freq_tbl[] = {
108 { 19200, ACPU_PLL_TCXO, 0, 0, 19200, 0, VDD_0, 30720, 0, 0, 8 },
109 { 61440, ACPU_PLL_0, 4, 3, 61440, 0, VDD_0, 30720, 0, 0, 8 },
110 { 81920, ACPU_PLL_0, 4, 2, 40960, 1, VDD_0, 61440, 0, 0, 8 },
111 { 96000, ACPU_PLL_1, 1, 7, 48000, 1, VDD_0, 61440, 0, 0, 9 },
112 { 122880, ACPU_PLL_0, 4, 1, 61440, 1, VDD_3, 61440, 0, 0, 8 },
113 { 128000, ACPU_PLL_1, 1, 5, 64000, 1, VDD_3, 61440, 0, 0, 12 },
114 { 176000, ACPU_PLL_2, 2, 5, 88000, 1, VDD_3, 61440, 0, 0, 11 },
115 { 192000, ACPU_PLL_1, 1, 3, 64000, 2, VDD_3, 61440, 0, 0, 12 },
116 { 245760, ACPU_PLL_0, 4, 0, 81920, 2, VDD_4, 61440, 0, 0, 12 },
117 { 256000, ACPU_PLL_1, 1, 2, 128000, 2, VDD_5, 128000, 0, 0, 12 },
118 { 264000, ACPU_PLL_2, 2, 3, 88000, 2, VDD_5, 128000, 0, 6, 13 },
119 { 352000, ACPU_PLL_2, 2, 2, 88000, 3, VDD_5, 128000, 0, 6, 13 },
120 { 384000, ACPU_PLL_1, 1, 1, 128000, 2, VDD_6, 128000, 0, 5, -1 },
121 { 528000, ACPU_PLL_2, 2, 1, 132000, 3, VDD_7, 128000, 0, 11, -1 },
122 { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
123};
124#else /* Table of freq we currently use. */
125static struct clkctl_acpu_speed acpu_freq_tbl[] = {
126 { 19200, ACPU_PLL_TCXO, 0, 0, 19200, 0, VDD_0, 30720, 0, 0, 4 },
127 { 122880, ACPU_PLL_0, 4, 1, 61440, 1, VDD_3, 61440, 0, 0, 4 },
128 { 128000, ACPU_PLL_1, 1, 5, 64000, 1, VDD_3, 61440, 0, 0, 6 },
129 { 176000, ACPU_PLL_2, 2, 5, 88000, 1, VDD_3, 61440, 0, 0, 5 },
130 { 245760, ACPU_PLL_0, 4, 0, 81920, 2, VDD_4, 61440, 0, 0, 5 },
131 { 352000, ACPU_PLL_2, 2, 2, 88000, 3, VDD_5, 128000, 0, 3, 7 },
132 { 384000, ACPU_PLL_1, 1, 1, 128000, 2, VDD_6, 128000, 0, 2, -1 },
133 { 528000, ACPU_PLL_2, 2, 1, 132000, 3, VDD_7, 128000, 0, 5, -1 },
134 { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
135};
136#endif
137
138static struct cpufreq_frequency_table freq_table[] = {
139 { 0, 122880 },
140 { 1, 128000 },
141 { 2, 245760 },
142 { 3, 384000 },
143 { 4, 528000 },
144 { 5, CPUFREQ_TABLE_END },
145};
146
147static int pc_pll_request(unsigned id, unsigned on)
148{
149 int res;
150 on = !!on;
151
152#if PERF_SWITCH_DEBUG
153 if (on)
154 printk(KERN_DEBUG "Enabling PLL %d\n", id);
155 else
156 printk(KERN_DEBUG "Disabling PLL %d\n", id);
157#endif
158
159 res = msm_proc_comm(PCOM_CLKCTL_RPC_PLL_REQUEST, &id, &on);
160 if (res < 0)
161 return res;
162
163#if PERF_SWITCH_DEBUG
164 if (on)
165 printk(KERN_DEBUG "PLL %d enabled\n", id);
166 else
167 printk(KERN_DEBUG "PLL %d disabled\n", id);
168#endif
169 return res;
170}
171
172
173/*----------------------------------------------------------------------------
174 * ARM11 'owned' clock control
175 *---------------------------------------------------------------------------*/
176
177unsigned long acpuclk_power_collapse(void) {
178 int ret = acpuclk_get_rate();
179 ret *= 1000;
180 if (ret > drv_state.power_collapse_khz)
181 acpuclk_set_rate(drv_state.power_collapse_khz, 1);
182 return ret;
183}
184
185unsigned long acpuclk_get_wfi_rate(void)
186{
187 return drv_state.wait_for_irq_khz;
188}
189
190unsigned long acpuclk_wait_for_irq(void) {
191 int ret = acpuclk_get_rate();
192 ret *= 1000;
193 if (ret > drv_state.wait_for_irq_khz)
194 acpuclk_set_rate(drv_state.wait_for_irq_khz, 1);
195 return ret;
196}
197
198static int acpuclk_set_vdd_level(int vdd)
199{
200 uint32_t current_vdd;
201
202 current_vdd = readl(A11S_VDD_SVS_PLEVEL_ADDR) & 0x07;
203
204#if PERF_SWITCH_DEBUG
205 printk(KERN_DEBUG "acpuclock: Switching VDD from %u -> %d\n",
206 current_vdd, vdd);
207#endif
208 writel((1 << 7) | (vdd << 3), A11S_VDD_SVS_PLEVEL_ADDR);
209 udelay(drv_state.vdd_switch_time_us);
210 if ((readl(A11S_VDD_SVS_PLEVEL_ADDR) & 0x7) != vdd) {
211#if PERF_SWITCH_DEBUG
212 printk(KERN_ERR "acpuclock: VDD set failed\n");
213#endif
214 return -EIO;
215 }
216
217#if PERF_SWITCH_DEBUG
218 printk(KERN_DEBUG "acpuclock: VDD switched\n");
219#endif
220 return 0;
221}
222
223/* Set proper dividers for the given clock speed. */
224static void acpuclk_set_div(const struct clkctl_acpu_speed *hunt_s) {
225 uint32_t reg_clkctl, reg_clksel, clk_div;
226
227 /* AHB_CLK_DIV */
228 clk_div = (readl(A11S_CLK_SEL_ADDR) >> 1) & 0x03;
229 /*
230 * If the new clock divider is higher than the previous, then
231 * program the divider before switching the clock
232 */
233 if (hunt_s->ahbclk_div > clk_div) {
234 reg_clksel = readl(A11S_CLK_SEL_ADDR);
235 reg_clksel &= ~(0x3 << 1);
236 reg_clksel |= (hunt_s->ahbclk_div << 1);
237 writel(reg_clksel, A11S_CLK_SEL_ADDR);
238 }
239 if ((readl(A11S_CLK_SEL_ADDR) & 0x01) == 0) {
240 /* SRC0 */
241
242 /* Program clock source */
243 reg_clkctl = readl(A11S_CLK_CNTL_ADDR);
244 reg_clkctl &= ~(0x07 << 4);
245 reg_clkctl |= (hunt_s->a11clk_src_sel << 4);
246 writel(reg_clkctl, A11S_CLK_CNTL_ADDR);
247
248 /* Program clock divider */
249 reg_clkctl = readl(A11S_CLK_CNTL_ADDR);
250 reg_clkctl &= ~0xf;
251 reg_clkctl |= hunt_s->a11clk_src_div;
252 writel(reg_clkctl, A11S_CLK_CNTL_ADDR);
253
254 /* Program clock source selection */
255 reg_clksel = readl(A11S_CLK_SEL_ADDR);
256 reg_clksel |= 1; /* CLK_SEL_SRC1NO == SRC1 */
257 writel(reg_clksel, A11S_CLK_SEL_ADDR);
258 } else {
259 /* SRC1 */
260
261 /* Program clock source */
262 reg_clkctl = readl(A11S_CLK_CNTL_ADDR);
263 reg_clkctl &= ~(0x07 << 12);
264 reg_clkctl |= (hunt_s->a11clk_src_sel << 12);
265 writel(reg_clkctl, A11S_CLK_CNTL_ADDR);
266
267 /* Program clock divider */
268 reg_clkctl = readl(A11S_CLK_CNTL_ADDR);
269 reg_clkctl &= ~(0xf << 8);
270 reg_clkctl |= (hunt_s->a11clk_src_div << 8);
271 writel(reg_clkctl, A11S_CLK_CNTL_ADDR);
272
273 /* Program clock source selection */
274 reg_clksel = readl(A11S_CLK_SEL_ADDR);
275 reg_clksel &= ~1; /* CLK_SEL_SRC1NO == SRC0 */
276 writel(reg_clksel, A11S_CLK_SEL_ADDR);
277 }
278
279 /*
280 * If the new clock divider is lower than the previous, then
281 * program the divider after switching the clock
282 */
283 if (hunt_s->ahbclk_div < clk_div) {
284 reg_clksel = readl(A11S_CLK_SEL_ADDR);
285 reg_clksel &= ~(0x3 << 1);
286 reg_clksel |= (hunt_s->ahbclk_div << 1);
287 writel(reg_clksel, A11S_CLK_SEL_ADDR);
288 }
289}
290
291int acpuclk_set_rate(unsigned long rate, int for_power_collapse)
292{
293 uint32_t reg_clkctl;
294 struct clkctl_acpu_speed *cur_s, *tgt_s, *strt_s;
295 int rc = 0;
296 unsigned int plls_enabled = 0, pll;
297
298 strt_s = cur_s = drv_state.current_speed;
299
300 WARN_ONCE(cur_s == NULL, "acpuclk_set_rate: not initialized\n");
301 if (cur_s == NULL)
302 return -ENOENT;
303
304 if (rate == (cur_s->a11clk_khz * 1000))
305 return 0;
306
307 for (tgt_s = acpu_freq_tbl; tgt_s->a11clk_khz != 0; tgt_s++) {
308 if (tgt_s->a11clk_khz == (rate / 1000))
309 break;
310 }
311
312 if (tgt_s->a11clk_khz == 0)
313 return -EINVAL;
314
315 /* Choose the highest speed speed at or below 'rate' with same PLL. */
316 if (for_power_collapse && tgt_s->a11clk_khz < cur_s->a11clk_khz) {
317 while (tgt_s->pll != ACPU_PLL_TCXO && tgt_s->pll != cur_s->pll)
318 tgt_s--;
319 }
320
321 if (strt_s->pll != ACPU_PLL_TCXO)
322 plls_enabled |= 1 << strt_s->pll;
323
324 if (!for_power_collapse) {
325 mutex_lock(&drv_state.lock);
326 if (strt_s->pll != tgt_s->pll && tgt_s->pll != ACPU_PLL_TCXO) {
327 rc = pc_pll_request(tgt_s->pll, 1);
328 if (rc < 0) {
329 pr_err("PLL%d enable failed (%d)\n",
330 tgt_s->pll, rc);
331 goto out;
332 }
333 plls_enabled |= 1 << tgt_s->pll;
334 }
335 /* Increase VDD if needed. */
336 if (tgt_s->vdd > cur_s->vdd) {
337 if ((rc = acpuclk_set_vdd_level(tgt_s->vdd)) < 0) {
338 printk(KERN_ERR "Unable to switch ACPU vdd\n");
339 goto out;
340 }
341 }
342 }
343
344 /* Set wait states for CPU inbetween frequency changes */
345 reg_clkctl = readl(A11S_CLK_CNTL_ADDR);
346 reg_clkctl |= (100 << 16); /* set WT_ST_CNT */
347 writel(reg_clkctl, A11S_CLK_CNTL_ADDR);
348
349#if PERF_SWITCH_DEBUG
350 printk(KERN_INFO "acpuclock: Switching from ACPU rate %u -> %u\n",
351 strt_s->a11clk_khz * 1000, tgt_s->a11clk_khz * 1000);
352#endif
353
354 while (cur_s != tgt_s) {
355 /*
356 * Always jump to target freq if within 256mhz, regulardless of
357 * PLL. If differnece is greater, use the predefinied
358 * steppings in the table.
359 */
360 int d = abs((int)(cur_s->a11clk_khz - tgt_s->a11clk_khz));
361 if (d > drv_state.max_speed_delta_khz) {
362 /* Step up or down depending on target vs current. */
363 int clk_index = tgt_s->a11clk_khz > cur_s->a11clk_khz ?
364 cur_s->up : cur_s->down;
365 if (clk_index < 0) { /* This should not happen. */
366 printk(KERN_ERR "cur:%u target: %u\n",
367 cur_s->a11clk_khz, tgt_s->a11clk_khz);
368 rc = -EINVAL;
369 goto out;
370 }
371 cur_s = &acpu_freq_tbl[clk_index];
372 } else {
373 cur_s = tgt_s;
374 }
375#if PERF_SWITCH_STEP_DEBUG
376 printk(KERN_DEBUG "%s: STEP khz = %u, pll = %d\n",
377 __FUNCTION__, cur_s->a11clk_khz, cur_s->pll);
378#endif
379 if (!for_power_collapse&& cur_s->pll != ACPU_PLL_TCXO
380 && !(plls_enabled & (1 << cur_s->pll))) {
381 rc = pc_pll_request(cur_s->pll, 1);
382 if (rc < 0) {
383 pr_err("PLL%d enable failed (%d)\n",
384 cur_s->pll, rc);
385 goto out;
386 }
387 plls_enabled |= 1 << cur_s->pll;
388 }
389
390 acpuclk_set_div(cur_s);
391 drv_state.current_speed = cur_s;
392 /* Re-adjust lpj for the new clock speed. */
393 loops_per_jiffy = cur_s->lpj;
394 udelay(drv_state.acpu_switch_time_us);
395 }
396
397 /* Nothing else to do for power collapse. */
398 if (for_power_collapse)
399 return 0;
400
401 /* Disable PLLs we are not using anymore. */
402 plls_enabled &= ~(1 << tgt_s->pll);
403 for (pll = ACPU_PLL_0; pll <= ACPU_PLL_2; pll++)
404 if (plls_enabled & (1 << pll)) {
405 rc = pc_pll_request(pll, 0);
406 if (rc < 0) {
407 pr_err("PLL%d disable failed (%d)\n", pll, rc);
408 goto out;
409 }
410 }
411
412 /* Change the AXI bus frequency if we can. */
413 if (strt_s->axiclk_khz != tgt_s->axiclk_khz) {
414 rc = clk_set_rate(ebi1_clk, tgt_s->axiclk_khz * 1000);
415 if (rc < 0)
416 pr_err("Setting AXI min rate failed!\n");
417 }
418
419 /* Drop VDD level if we can. */
420 if (tgt_s->vdd < strt_s->vdd) {
421 if (acpuclk_set_vdd_level(tgt_s->vdd) < 0)
422 printk(KERN_ERR "acpuclock: Unable to drop ACPU vdd\n");
423 }
424
425#if PERF_SWITCH_DEBUG
426 printk(KERN_DEBUG "%s: ACPU speed change complete\n", __FUNCTION__);
427#endif
428out:
429 if (!for_power_collapse)
430 mutex_unlock(&drv_state.lock);
431 return rc;
432}
433
434static void __init acpuclk_init(void)
435{
436 struct clkctl_acpu_speed *speed;
437 uint32_t div, sel;
438 int rc;
439
440 /*
441 * Determine the rate of ACPU clock
442 */
443
444 if (!(readl(A11S_CLK_SEL_ADDR) & 0x01)) { /* CLK_SEL_SRC1N0 */
445 /* CLK_SRC0_SEL */
446 sel = (readl(A11S_CLK_CNTL_ADDR) >> 12) & 0x7;
447 /* CLK_SRC0_DIV */
448 div = (readl(A11S_CLK_CNTL_ADDR) >> 8) & 0x0f;
449 } else {
450 /* CLK_SRC1_SEL */
451 sel = (readl(A11S_CLK_CNTL_ADDR) >> 4) & 0x07;
452 /* CLK_SRC1_DIV */
453 div = readl(A11S_CLK_CNTL_ADDR) & 0x0f;
454 }
455
456 for (speed = acpu_freq_tbl; speed->a11clk_khz != 0; speed++) {
457 if (speed->a11clk_src_sel == sel
458 && (speed->a11clk_src_div == div))
459 break;
460 }
461 if (speed->a11clk_khz == 0) {
462 printk(KERN_WARNING "Warning - ACPU clock reports invalid speed\n");
463 return;
464 }
465
466 drv_state.current_speed = speed;
467
468 rc = clk_set_rate(ebi1_clk, speed->axiclk_khz * 1000);
469 if (rc < 0)
470 pr_err("Setting AXI min rate failed!\n");
471
472 printk(KERN_INFO "ACPU running at %d KHz\n", speed->a11clk_khz);
473}
474
475unsigned long acpuclk_get_rate(void)
476{
477 WARN_ONCE(drv_state.current_speed == NULL,
478 "acpuclk_get_rate: not initialized\n");
479 if (drv_state.current_speed)
480 return drv_state.current_speed->a11clk_khz;
481 else
482 return 0;
483}
484
485uint32_t acpuclk_get_switch_time(void)
486{
487 return drv_state.acpu_switch_time_us;
488}
489
490/*----------------------------------------------------------------------------
491 * Clock driver initialization
492 *---------------------------------------------------------------------------*/
493
494/* Initalize the lpj field in the acpu_freq_tbl. */
495static void __init lpj_init(void)
496{
497 int i;
498 const struct clkctl_acpu_speed *base_clk = drv_state.current_speed;
499 for (i = 0; acpu_freq_tbl[i].a11clk_khz; i++) {
500 acpu_freq_tbl[i].lpj = cpufreq_scale(loops_per_jiffy,
501 base_clk->a11clk_khz,
502 acpu_freq_tbl[i].a11clk_khz);
503 }
504}
505
506void __init msm_acpu_clock_init(struct msm_acpu_clock_platform_data *clkdata)
507{
508 pr_info("acpu_clock_init()\n");
509
510 ebi1_clk = clk_get(NULL, "ebi1_clk");
511
512 mutex_init(&drv_state.lock);
513 drv_state.acpu_switch_time_us = clkdata->acpu_switch_time_us;
514 drv_state.max_speed_delta_khz = clkdata->max_speed_delta_khz;
515 drv_state.vdd_switch_time_us = clkdata->vdd_switch_time_us;
516 drv_state.power_collapse_khz = clkdata->power_collapse_khz;
517 drv_state.wait_for_irq_khz = clkdata->wait_for_irq_khz;
518 acpuclk_init();
519 lpj_init();
520#ifdef CONFIG_CPU_FREQ_TABLE
521 cpufreq_frequency_table_get_attr(freq_table, smp_processor_id());
522#endif
523}
diff --git a/arch/arm/mach-msm/acpuclock.h b/arch/arm/mach-msm/acpuclock.h
new file mode 100644
index 000000000000..415de2eb9a5e
--- /dev/null
+++ b/arch/arm/mach-msm/acpuclock.h
@@ -0,0 +1,32 @@
1/* arch/arm/mach-msm/acpuclock.h
2 *
3 * MSM architecture clock driver header
4 *
5 * Copyright (C) 2007 Google, Inc.
6 * Copyright (c) 2007 QUALCOMM Incorporated
7 * Author: San Mehat <san@android.com>
8 *
9 * This software is licensed under the terms of the GNU General Public
10 * License version 2, as published by the Free Software Foundation, and
11 * may be copied, distributed, and modified under those terms.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 */
19
20#ifndef __ARCH_ARM_MACH_MSM_ACPUCLOCK_H
21#define __ARCH_ARM_MACH_MSM_ACPUCLOCK_H
22
23int acpuclk_set_rate(unsigned long rate, int for_power_collapse);
24unsigned long acpuclk_get_rate(void);
25uint32_t acpuclk_get_switch_time(void);
26unsigned long acpuclk_wait_for_irq(void);
27unsigned long acpuclk_power_collapse(void);
28unsigned long acpuclk_get_wfi_rate(void);
29
30
31#endif
32
diff --git a/arch/arm/mach-msm/include/mach/board.h b/arch/arm/mach-msm/include/mach/board.h
index 264d62e519f3..fb12fd87bb81 100644
--- a/arch/arm/mach-msm/include/mach/board.h
+++ b/arch/arm/mach-msm/include/mach/board.h
@@ -27,6 +27,16 @@ struct msm_mddi_platform_data
27 unsigned has_vsync_irq:1; 27 unsigned has_vsync_irq:1;
28}; 28};
29 29
30struct msm_acpu_clock_platform_data
31{
32 uint32_t acpu_switch_time_us;
33 uint32_t max_speed_delta_khz;
34 uint32_t vdd_switch_time_us;
35 unsigned long power_collapse_khz;
36 unsigned long wait_for_irq_khz;
37};
38
39
30/* common init routines for use by arch/arm/mach-msm/board-*.c */ 40/* common init routines for use by arch/arm/mach-msm/board-*.c */
31 41
32void __init msm_add_devices(void); 42void __init msm_add_devices(void);
@@ -34,5 +44,6 @@ void __init msm_map_common_io(void);
34void __init msm_init_irq(void); 44void __init msm_init_irq(void);
35void __init msm_init_gpio(void); 45void __init msm_init_gpio(void);
36void __init msm_clock_init(void); 46void __init msm_clock_init(void);
47void __init msm_acpu_clock_init(struct msm_acpu_clock_platform_data *);
37 48
38#endif 49#endif