Linux Audio

Check our new training course

Loading...
Note: File does not exist in v6.2.
  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
 43static int 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
 61static unsigned 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 __cpuinit 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	/* FIXME: what's the actual transition time? */
130	policy->cpuinfo.transition_latency = 300 * 1000;
131
132	return 0;
133}
134
135static int omap_cpu_exit(struct cpufreq_policy *policy)
136{
137	clk_exit_cpufreq_table(&freq_table);
138	clk_put(mpu_clk);
139	return 0;
140}
141
142static struct freq_attr *omap_cpufreq_attr[] = {
143	&cpufreq_freq_attr_scaling_available_freqs,
144	NULL,
145};
146
147static struct cpufreq_driver omap_driver = {
148	.flags		= CPUFREQ_STICKY,
149	.verify		= omap_verify_speed,
150	.target		= omap_target,
151	.get		= omap_getspeed,
152	.init		= omap_cpu_init,
153	.exit		= omap_cpu_exit,
154	.name		= "omap",
155	.attr		= omap_cpufreq_attr,
156};
157
158static int __init omap_cpufreq_init(void)
159{
160	return cpufreq_register_driver(&omap_driver);
161}
162
163arch_initcall(omap_cpufreq_init);
164
165/*
166 * if ever we want to remove this, upon cleanup call:
167 *
168 * cpufreq_unregister_driver()
169 * cpufreq_frequency_table_put_attr()
170 */
171