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/mach-integrator/cpu.c
  3  *
  4  *  Copyright (C) 2001-2002 Deep Blue Solutions Ltd.
  5  *
  6  * This program is free software; you can redistribute it and/or modify
  7  * it under the terms of the GNU General Public License version 2 as
  8  * published by the Free Software Foundation.
  9  *
 10  * CPU support functions
 11  */
 12 #include <linux/module.h>
 13 #include <linux/types.h>
 14 #include <linux/kernel.h>
 15 #include <linux/cpufreq.h>
 16 #include <linux/slab.h>
 17 #include <linux/sched.h>
 18 #include <linux/smp.h>
 19 #include <linux/init.h>
 20 #include <linux/io.h>
 21 
 22 #include <mach/hardware.h>
 23 #include <asm/mach-types.h>
 24 #include <asm/hardware/icst525.h>
 25 
 26 static struct cpufreq_driver integrator_driver;
 27 
 28 #define CM_ID   (IO_ADDRESS(INTEGRATOR_HDR_BASE)+INTEGRATOR_HDR_ID_OFFSET)
 29 #define CM_OSC  (IO_ADDRESS(INTEGRATOR_HDR_BASE)+INTEGRATOR_HDR_OSC_OFFSET)
 30 #define CM_STAT (IO_ADDRESS(INTEGRATOR_HDR_BASE)+INTEGRATOR_HDR_STAT_OFFSET)
 31 #define CM_LOCK (IO_ADDRESS(INTEGRATOR_HDR_BASE)+INTEGRATOR_HDR_LOCK_OFFSET)
 32 
 33 static const struct icst525_params lclk_params = {
 34         .ref            = 24000,
 35         .vco_max        = 320000,
 36         .vd_min         = 8,
 37         .vd_max         = 132,
 38         .rd_min         = 24,
 39         .rd_max         = 24,
 40 };
 41 
 42 static const struct icst525_params cclk_params = {
 43         .ref            = 24000,
 44         .vco_max        = 320000,
 45         .vd_min         = 12,
 46         .vd_max         = 160,
 47         .rd_min         = 24,
 48         .rd_max         = 24,
 49 };
 50 
 51 /*
 52  * Validate the speed policy.
 53  */
 54 static int integrator_verify_policy(struct cpufreq_policy *policy)
 55 {
 56         struct icst525_vco vco;
 57 
 58         cpufreq_verify_within_limits(policy, 
 59                                      policy->cpuinfo.min_freq, 
 60                                      policy->cpuinfo.max_freq);
 61 
 62         vco = icst525_khz_to_vco(&cclk_params, policy->max);
 63         policy->max = icst525_khz(&cclk_params, vco);
 64 
 65         vco = icst525_khz_to_vco(&cclk_params, policy->min);
 66         policy->min = icst525_khz(&cclk_params, vco);
 67 
 68         cpufreq_verify_within_limits(policy, 
 69                                      policy->cpuinfo.min_freq, 
 70                                      policy->cpuinfo.max_freq);
 71 
 72         return 0;
 73 }
 74 
 75 
 76 static int integrator_set_target(struct cpufreq_policy *policy,
 77                                  unsigned int target_freq,
 78                                  unsigned int relation)
 79 {
 80         cpumask_t cpus_allowed;
 81         int cpu = policy->cpu;
 82         struct icst525_vco vco;
 83         struct cpufreq_freqs freqs;
 84         u_int cm_osc;
 85 
 86         /*
 87          * Save this threads cpus_allowed mask.
 88          */
 89         cpus_allowed = current->cpus_allowed;
 90 
 91         /*
 92          * Bind to the specified CPU.  When this call returns,
 93          * we should be running on the right CPU.
 94          */
 95         set_cpus_allowed(current, cpumask_of_cpu(cpu));
 96         BUG_ON(cpu != smp_processor_id());
 97 
 98         /* get current setting */
 99         cm_osc = __raw_readl(CM_OSC);
100 
101         if (machine_is_integrator()) {
102                 vco.s = (cm_osc >> 8) & 7;
103         } else if (machine_is_cintegrator()) {
104                 vco.s = 1;
105         }
106         vco.v = cm_osc & 255;
107         vco.r = 22;
108         freqs.old = icst525_khz(&cclk_params, vco);
109 
110         /* icst525_khz_to_vco rounds down -- so we need the next
111          * larger freq in case of CPUFREQ_RELATION_L.
112          */
113         if (relation == CPUFREQ_RELATION_L)
114                 target_freq += 999;
115         if (target_freq > policy->max)
116                 target_freq = policy->max;
117         vco = icst525_khz_to_vco(&cclk_params, target_freq);
118         freqs.new = icst525_khz(&cclk_params, vco);
119 
120         freqs.cpu = policy->cpu;
121 
122         if (freqs.old == freqs.new) {
123                 set_cpus_allowed(current, cpus_allowed);
124                 return 0;
125         }
126 
127         cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE);
128 
129         cm_osc = __raw_readl(CM_OSC);
130 
131         if (machine_is_integrator()) {
132                 cm_osc &= 0xfffff800;
133                 cm_osc |= vco.s << 8;
134         } else if (machine_is_cintegrator()) {
135                 cm_osc &= 0xffffff00;
136         }
137         cm_osc |= vco.v;
138 
139         __raw_writel(0xa05f, CM_LOCK);
140         __raw_writel(cm_osc, CM_OSC);
141         __raw_writel(0, CM_LOCK);
142 
143         /*
144          * Restore the CPUs allowed mask.
145          */
146         set_cpus_allowed(current, cpus_allowed);
147 
148         cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE);
149 
150         return 0;
151 }
152 
153 static unsigned int integrator_get(unsigned int cpu)
154 {
155         cpumask_t cpus_allowed;
156         unsigned int current_freq;
157         u_int cm_osc;
158         struct icst525_vco vco;
159 
160         cpus_allowed = current->cpus_allowed;
161 
162         set_cpus_allowed(current, cpumask_of_cpu(cpu));
163         BUG_ON(cpu != smp_processor_id());
164 
165         /* detect memory etc. */
166         cm_osc = __raw_readl(CM_OSC);
167 
168         if (machine_is_integrator()) {
169                 vco.s = (cm_osc >> 8) & 7;
170         } else if (machine_is_cintegrator()) {
171                 vco.s = 1;
172         }
173         vco.v = cm_osc & 255;
174         vco.r = 22;
175 
176         current_freq = icst525_khz(&cclk_params, vco); /* current freq */
177 
178         set_cpus_allowed(current, cpus_allowed);
179 
180         return current_freq;
181 }
182 
183 static int integrator_cpufreq_init(struct cpufreq_policy *policy)
184 {
185 
186         /* set default policy and cpuinfo */
187         policy->cpuinfo.max_freq = 160000;
188         policy->cpuinfo.min_freq = 12000;
189         policy->cpuinfo.transition_latency = 1000000; /* 1 ms, assumed */
190         policy->cur = policy->min = policy->max = integrator_get(policy->cpu);
191 
192         return 0;
193 }
194 
195 static struct cpufreq_driver integrator_driver = {
196         .verify         = integrator_verify_policy,
197         .target         = integrator_set_target,
198         .get            = integrator_get,
199         .init           = integrator_cpufreq_init,
200         .name           = "integrator",
201 };
202 
203 static int __init integrator_cpu_init(void)
204 {
205         return cpufreq_register_driver(&integrator_driver);
206 }
207 
208 static void __exit integrator_cpu_exit(void)
209 {
210         cpufreq_unregister_driver(&integrator_driver);
211 }
212 
213 MODULE_AUTHOR ("Russell M. King");
214 MODULE_DESCRIPTION ("cpufreq driver for ARM Integrator CPUs");
215 MODULE_LICENSE ("GPL");
216 
217 module_init(integrator_cpu_init);
218 module_exit(integrator_cpu_exit);
219 
  This page was automatically generated by the LXR engine.