0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
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
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
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");