Linux kernel & device driver programming

Cross-Referenced Linux and Device Driver Code

[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ]
Version: [ 2.6.11.8 ] [ 2.6.25 ] [ 2.6.25.8 ] [ 2.6.31.13 ] Architecture: [ i386 ]
  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 <mach/clock.h>
 27 #include <asm/system.h>
 28 
 29 #define VERY_HI_RATE    900000000
 30 
 31 static 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 
 39 static struct clk *mpu_clk;
 40 
 41 /* TODO: Add support for SDRAM timing changes */
 42 
 43 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 
 61 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 
 72 static 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 
104 static 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         /* FIXME: what's the actual transition time? */
130         policy->cpuinfo.transition_latency = 10 * 1000 * 1000;
131 
132         return 0;
133 }
134 
135 static int omap_cpu_exit(struct cpufreq_policy *policy)
136 {
137         clk_put(mpu_clk);
138         return 0;
139 }
140 
141 static struct freq_attr *omap_cpufreq_attr[] = {
142         &cpufreq_freq_attr_scaling_available_freqs,
143         NULL,
144 };
145 
146 static 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 
157 static int __init omap_cpufreq_init(void)
158 {
159         return cpufreq_register_driver(&omap_driver);
160 }
161 
162 arch_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 
171 
  This page was automatically generated by the LXR engine.