+#include <linux/kernel.h>
+static struct cpu_op mx51_cpu_op[] = {
{
.cpu_rate = 160000000,},
{
.cpu_rate = 800000000,},
+};
Why did you remove the values between 800MHz and 160MHz? 400MHz and 200Mhz should work also, no?
It proved that those operating points don't work well.
+struct cpu_op *mx51_get_cpu_op(int *op) +{
*op = ARRAY_SIZE(mx51_cpu_op);
return mx51_cpu_op;
+} diff --git a/arch/arm/mach-mx5/cpu_op-mx51.h
b/arch/arm/mach-mx5/cpu_op-mx51.h
new file mode 100644 index 0000000..97477fe --- /dev/null +++ b/arch/arm/mach-mx5/cpu_op-mx51.h @@ -0,0 +1,14 @@ +/*
- Copyright (C) 2010 Freescale Semiconductor, Inc. All Rights Reserved.
- */
+/*
- The code contained herein is licensed under the GNU General Public
- License. You may obtain a copy of the GNU General Public License
- Version 2 or later at the following locations:
- */
+extern struct cpu_op *mx51_get_cpu_op(int *op); diff --git a/arch/arm/plat-mxc/Makefile b/arch/arm/plat-mxc/Makefile index 78d405e..a833d38 100644 --- a/arch/arm/plat-mxc/Makefile +++ b/arch/arm/plat-mxc/Makefile @@ -16,6 +16,7 @@ obj-$(CONFIG_MXC_ULPI) += ulpi.o obj-$(CONFIG_ARCH_MXC_AUDMUX_V1) += audmux-v1.o obj-$(CONFIG_ARCH_MXC_AUDMUX_V2) += audmux-v2.o obj-$(CONFIG_MXC_DEBUG_BOARD) += 3ds_debugboard.o +obj-$(CONFIG_CPU_FREQ_IMX) += cpufreq.o ifdef CONFIG_SND_IMX_SOC obj-y += ssi-fiq.o obj-y += ssi-fiq-ksym.o diff --git a/arch/arm/plat-mxc/cpufreq.c b/arch/arm/plat-mxc/cpufreq.c new file mode 100644 index 0000000..9cabeb9 --- /dev/null +++ b/arch/arm/plat-mxc/cpufreq.c @@ -0,0 +1,202 @@ +/*
- Copyright (C) 2010 Freescale Semiconductor, Inc. All Rights Reserved.
- */
+/*
- The code contained herein is licensed under the GNU General Public
- License. You may obtain a copy of the GNU General Public License
- Version 2 or later at the following locations:
- */
+/*
- A driver for the Freescale Semiconductor i.MXC CPUfreq module.
- The CPUFREQ driver is for controling CPU frequency. It allows you to
change
- the CPU clock speed on the fly.
- */
+#include <linux/cpufreq.h> +#include <linux/clk.h> +#include <linux/err.h> +#include <linux/slab.h> +#include <mach/hardware.h> +#include <mach/clock.h>
+#define CLK32_FREQ 32768 +#define NANOSECOND (1000 * 1000 * 1000)
+static int cpu_freq_khz_min; +static int cpu_freq_khz_max; +static int arm_normal_clk;
+static struct clk *cpu_clk; +static struct cpufreq_frequency_table *imx_freq_table;
+static int cpu_op_nr; +static struct cpu_op *cpu_op_tbl;
+static int set_cpu_freq(int freq) +{
int ret = 0;
int org_cpu_rate;
org_cpu_rate = clk_get_rate(cpu_clk);
if (org_cpu_rate == freq)
return ret;
You already checked this in mxc_set_target. Once is enough.
Well, this fucntion is not only used in mxc_set_target, so it is safer to still keep checking here.
ret = clk_set_rate(cpu_clk, freq);
if (ret != 0) {
printk(KERN_DEBUG "cannot set CPU clock rate\n");
return ret;
}
return ret;
+}
+static int mxc_verify_speed(struct cpufreq_policy *policy) +{
if (policy->cpu != 0)
return -EINVAL;
return cpufreq_frequency_table_verify(policy, imx_freq_table);
+}
+static unsigned int mxc_get_speed(unsigned int cpu) +{
if (cpu)
return 0;
return clk_get_rate(cpu_clk) / 1000;
+}
+static int mxc_set_target(struct cpufreq_policy *policy,
unsigned int target_freq, unsigned int relation)
+{
struct cpufreq_freqs freqs;
int freq_Hz;
int ret = 0;
unsigned int index;
cpufreq_frequency_table_target(policy, imx_freq_table,
target_freq, relation, &index);
freq_Hz = imx_freq_table[index].frequency * 1000;
freqs.old = clk_get_rate(cpu_clk) / 1000;
freqs.new = freq_Hz / 1000;
freqs.cpu = 0;
freqs.flags = 0;
cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE);
if (freqs.old != freqs.new)
ret = set_cpu_freq(freq_Hz);
cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE);
return ret;
+}
+static int __init mxc_cpufreq_init(struct cpufreq_policy *policy) +{
int ret;
int i;
printk(KERN_INFO "i.MXC CPU frequency driver\n");
if (policy->cpu != 0)
return -EINVAL;
cpu_clk = clk_get(NULL, "cpu_clk");
if (IS_ERR(cpu_clk)) {
printk(KERN_ERR "%s: failed to get cpu clock\n", __func__);
return PTR_ERR(cpu_clk);
}
cpu_op_tbl = get_cpu_op(&cpu_op_nr);
This will crash every board except the babbage board which happens to set this function pointer.
Add a checking here should avoid that.