Back to home page

OSCL-LXR

 
 

    


0001 /*
0002  * cpufreq driver for the SuperH processors.
0003  *
0004  * Copyright (C) 2002 - 2012 Paul Mundt
0005  * Copyright (C) 2002 M. R. Brown
0006  *
0007  * Clock framework bits from arch/avr32/mach-at32ap/cpufreq.c
0008  *
0009  *   Copyright (C) 2004-2007 Atmel Corporation
0010  *
0011  * This file is subject to the terms and conditions of the GNU General Public
0012  * License.  See the file "COPYING" in the main directory of this archive
0013  * for more details.
0014  */
0015 #define pr_fmt(fmt) "cpufreq: " fmt
0016 
0017 #include <linux/types.h>
0018 #include <linux/cpufreq.h>
0019 #include <linux/kernel.h>
0020 #include <linux/module.h>
0021 #include <linux/init.h>
0022 #include <linux/err.h>
0023 #include <linux/cpumask.h>
0024 #include <linux/cpu.h>
0025 #include <linux/smp.h>
0026 #include <linux/clk.h>
0027 #include <linux/percpu.h>
0028 #include <linux/sh_clk.h>
0029 
0030 static DEFINE_PER_CPU(struct clk, sh_cpuclk);
0031 
0032 struct cpufreq_target {
0033     struct cpufreq_policy   *policy;
0034     unsigned int        freq;
0035 };
0036 
0037 static unsigned int sh_cpufreq_get(unsigned int cpu)
0038 {
0039     return (clk_get_rate(&per_cpu(sh_cpuclk, cpu)) + 500) / 1000;
0040 }
0041 
0042 static long __sh_cpufreq_target(void *arg)
0043 {
0044     struct cpufreq_target *target = arg;
0045     struct cpufreq_policy *policy = target->policy;
0046     int cpu = policy->cpu;
0047     struct clk *cpuclk = &per_cpu(sh_cpuclk, cpu);
0048     struct cpufreq_freqs freqs;
0049     struct device *dev;
0050     long freq;
0051 
0052     if (smp_processor_id() != cpu)
0053         return -ENODEV;
0054 
0055     dev = get_cpu_device(cpu);
0056 
0057     /* Convert target_freq from kHz to Hz */
0058     freq = clk_round_rate(cpuclk, target->freq * 1000);
0059 
0060     if (freq < (policy->min * 1000) || freq > (policy->max * 1000))
0061         return -EINVAL;
0062 
0063     dev_dbg(dev, "requested frequency %u Hz\n", target->freq * 1000);
0064 
0065     freqs.old   = sh_cpufreq_get(cpu);
0066     freqs.new   = (freq + 500) / 1000;
0067     freqs.flags = 0;
0068 
0069     cpufreq_freq_transition_begin(target->policy, &freqs);
0070     clk_set_rate(cpuclk, freq);
0071     cpufreq_freq_transition_end(target->policy, &freqs, 0);
0072 
0073     dev_dbg(dev, "set frequency %lu Hz\n", freq);
0074     return 0;
0075 }
0076 
0077 /*
0078  * Here we notify other drivers of the proposed change and the final change.
0079  */
0080 static int sh_cpufreq_target(struct cpufreq_policy *policy,
0081                  unsigned int target_freq,
0082                  unsigned int relation)
0083 {
0084     struct cpufreq_target data = { .policy = policy, .freq = target_freq };
0085 
0086     return work_on_cpu(policy->cpu, __sh_cpufreq_target, &data);
0087 }
0088 
0089 static int sh_cpufreq_verify(struct cpufreq_policy_data *policy)
0090 {
0091     struct clk *cpuclk = &per_cpu(sh_cpuclk, policy->cpu);
0092     struct cpufreq_frequency_table *freq_table;
0093 
0094     freq_table = cpuclk->nr_freqs ? cpuclk->freq_table : NULL;
0095     if (freq_table)
0096         return cpufreq_frequency_table_verify(policy, freq_table);
0097 
0098     cpufreq_verify_within_cpu_limits(policy);
0099 
0100     policy->min = (clk_round_rate(cpuclk, 1) + 500) / 1000;
0101     policy->max = (clk_round_rate(cpuclk, ~0UL) + 500) / 1000;
0102 
0103     cpufreq_verify_within_cpu_limits(policy);
0104     return 0;
0105 }
0106 
0107 static int sh_cpufreq_cpu_init(struct cpufreq_policy *policy)
0108 {
0109     unsigned int cpu = policy->cpu;
0110     struct clk *cpuclk = &per_cpu(sh_cpuclk, cpu);
0111     struct cpufreq_frequency_table *freq_table;
0112     struct device *dev;
0113 
0114     dev = get_cpu_device(cpu);
0115 
0116     cpuclk = clk_get(dev, "cpu_clk");
0117     if (IS_ERR(cpuclk)) {
0118         dev_err(dev, "couldn't get CPU clk\n");
0119         return PTR_ERR(cpuclk);
0120     }
0121 
0122     freq_table = cpuclk->nr_freqs ? cpuclk->freq_table : NULL;
0123     if (freq_table) {
0124         policy->freq_table = freq_table;
0125     } else {
0126         dev_notice(dev, "no frequency table found, falling back "
0127                "to rate rounding.\n");
0128 
0129         policy->min = policy->cpuinfo.min_freq =
0130             (clk_round_rate(cpuclk, 1) + 500) / 1000;
0131         policy->max = policy->cpuinfo.max_freq =
0132             (clk_round_rate(cpuclk, ~0UL) + 500) / 1000;
0133     }
0134 
0135     return 0;
0136 }
0137 
0138 static int sh_cpufreq_cpu_exit(struct cpufreq_policy *policy)
0139 {
0140     unsigned int cpu = policy->cpu;
0141     struct clk *cpuclk = &per_cpu(sh_cpuclk, cpu);
0142 
0143     clk_put(cpuclk);
0144 
0145     return 0;
0146 }
0147 
0148 static struct cpufreq_driver sh_cpufreq_driver = {
0149     .name       = "sh",
0150     .flags      = CPUFREQ_NO_AUTO_DYNAMIC_SWITCHING,
0151     .get        = sh_cpufreq_get,
0152     .target     = sh_cpufreq_target,
0153     .verify     = sh_cpufreq_verify,
0154     .init       = sh_cpufreq_cpu_init,
0155     .exit       = sh_cpufreq_cpu_exit,
0156     .attr       = cpufreq_generic_attr,
0157 };
0158 
0159 static int __init sh_cpufreq_module_init(void)
0160 {
0161     pr_notice("SuperH CPU frequency driver.\n");
0162     return cpufreq_register_driver(&sh_cpufreq_driver);
0163 }
0164 
0165 static void __exit sh_cpufreq_module_exit(void)
0166 {
0167     cpufreq_unregister_driver(&sh_cpufreq_driver);
0168 }
0169 
0170 module_init(sh_cpufreq_module_init);
0171 module_exit(sh_cpufreq_module_exit);
0172 
0173 MODULE_AUTHOR("Paul Mundt <lethal@linux-sh.org>");
0174 MODULE_DESCRIPTION("cpufreq driver for SuperH");
0175 MODULE_LICENSE("GPL");