• Home
  • History
  • Annotate
  • Line#
  • Navigate
  • Raw
  • Download
  • only in /netgear-R7000-V1.0.7.12_1.2.5/components/opensource/linux/linux-2.6.36/arch/arm/plat-omap/
1/*
2 *  linux/arch/arm/plat-omap/cpu-omap.c
3 *
4 *  CPU frequency scaling for OMAP
5 *
6 *  Copyright (C) 2005 Nokia Corporation
7 *  Written by Tony Lindgren <tony@atomide.com>
8 *
9 *  Based on cpu-sa1110.c, Copyright (C) 2001 Russell King
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#include <linux/types.h>
16#include <linux/kernel.h>
17#include <linux/sched.h>
18#include <linux/cpufreq.h>
19#include <linux/delay.h>
20#include <linux/init.h>
21#include <linux/err.h>
22#include <linux/clk.h>
23#include <linux/io.h>
24
25#include <mach/hardware.h>
26#include <plat/clock.h>
27#include <asm/system.h>
28
29#define VERY_HI_RATE	900000000
30
31static struct cpufreq_frequency_table *freq_table;
32
33#ifdef CONFIG_ARCH_OMAP1
34#define MPU_CLK		"mpu"
35#else
36#define MPU_CLK		"virt_prcm_set"
37#endif
38
39static struct clk *mpu_clk;
40
41/* TODO: Add support for SDRAM timing changes */
42
43int omap_verify_speed(struct cpufreq_policy *policy)
44{
45	if (freq_table)
46		return cpufreq_frequency_table_verify(policy, freq_table);
47
48	if (policy->cpu)
49		return -EINVAL;
50
51	cpufreq_verify_within_limits(policy, policy->cpuinfo.min_freq,
52				     policy->cpuinfo.max_freq);
53
54	policy->min = clk_round_rate(mpu_clk, policy->min * 1000) / 1000;
55	policy->max = clk_round_rate(mpu_clk, policy->max * 1000) / 1000;
56	cpufreq_verify_within_limits(policy, policy->cpuinfo.min_freq,
57				     policy->cpuinfo.max_freq);
58	return 0;
59}
60
61unsigned int omap_getspeed(unsigned int cpu)
62{
63	unsigned long rate;
64
65	if (cpu)
66		return 0;
67
68	rate = clk_get_rate(mpu_clk) / 1000;
69	return rate;
70}
71
72static int omap_target(struct cpufreq_policy *policy,
73		       unsigned int target_freq,
74		       unsigned int relation)
75{
76	struct cpufreq_freqs freqs;
77	int ret = 0;
78
79	/* Ensure desired rate is within allowed range.  Some govenors
80	 * (ondemand) will just pass target_freq=0 to get the minimum. */
81	if (target_freq < policy->min)
82		target_freq = policy->min;
83	if (target_freq > policy->max)
84		target_freq = policy->max;
85
86	freqs.old = omap_getspeed(0);
87	freqs.new = clk_round_rate(mpu_clk, target_freq * 1000) / 1000;
88	freqs.cpu = 0;
89
90	if (freqs.old == freqs.new)
91		return ret;
92
93	cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE);
94#ifdef CONFIG_CPU_FREQ_DEBUG
95	printk(KERN_DEBUG "cpufreq-omap: transition: %u --> %u\n",
96	       freqs.old, freqs.new);
97#endif
98	ret = clk_set_rate(mpu_clk, freqs.new * 1000);
99	cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE);
100
101	return ret;
102}
103
104static int __init omap_cpu_init(struct cpufreq_policy *policy)
105{
106	int result = 0;
107
108	mpu_clk = clk_get(NULL, MPU_CLK);
109	if (IS_ERR(mpu_clk))
110		return PTR_ERR(mpu_clk);
111
112	if (policy->cpu != 0)
113		return -EINVAL;
114
115	policy->cur = policy->min = policy->max = omap_getspeed(0);
116
117	clk_init_cpufreq_table(&freq_table);
118	if (freq_table) {
119		result = cpufreq_frequency_table_cpuinfo(policy, freq_table);
120		if (!result)
121			cpufreq_frequency_table_get_attr(freq_table,
122							policy->cpu);
123	} else {
124		policy->cpuinfo.min_freq = clk_round_rate(mpu_clk, 0) / 1000;
125		policy->cpuinfo.max_freq = clk_round_rate(mpu_clk,
126							VERY_HI_RATE) / 1000;
127	}
128
129	policy->cpuinfo.transition_latency = 300 * 1000;
130
131	return 0;
132}
133
134static int omap_cpu_exit(struct cpufreq_policy *policy)
135{
136	clk_exit_cpufreq_table(&freq_table);
137	clk_put(mpu_clk);
138	return 0;
139}
140
141static struct freq_attr *omap_cpufreq_attr[] = {
142	&cpufreq_freq_attr_scaling_available_freqs,
143	NULL,
144};
145
146static struct cpufreq_driver omap_driver = {
147	.flags		= CPUFREQ_STICKY,
148	.verify		= omap_verify_speed,
149	.target		= omap_target,
150	.get		= omap_getspeed,
151	.init		= omap_cpu_init,
152	.exit		= omap_cpu_exit,
153	.name		= "omap",
154	.attr		= omap_cpufreq_attr,
155};
156
157static int __init omap_cpufreq_init(void)
158{
159	return cpufreq_register_driver(&omap_driver);
160}
161
162arch_initcall(omap_cpufreq_init);
163
164/*
165 * if ever we want to remove this, upon cleanup call:
166 *
167 * cpufreq_unregister_driver()
168 * cpufreq_frequency_table_put_attr()
169 */
170