Merge branch 'master' of git://git.kernel.org/pub/scm/fs/xfs/xfs
[pandora-kernel.git] / arch / arm / plat-omap / cpu-omap.c
index b269024..843e8af 100644 (file)
 #include <linux/io.h>
 
 #include <mach/hardware.h>
+#include <mach/clock.h>
 #include <asm/system.h>
 
 #define VERY_HI_RATE   900000000
 
+static struct cpufreq_frequency_table *freq_table;
+
 #ifdef CONFIG_ARCH_OMAP1
 #define MPU_CLK                "mpu"
 #else
@@ -39,6 +42,9 @@ static struct clk *mpu_clk;
 
 int omap_verify_speed(struct cpufreq_policy *policy)
 {
+       if (freq_table)
+               return cpufreq_frequency_table_verify(policy, freq_table);
+
        if (policy->cpu)
                return -EINVAL;
 
@@ -70,12 +76,26 @@ static int omap_target(struct cpufreq_policy *policy,
        struct cpufreq_freqs freqs;
        int ret = 0;
 
+       /* Ensure desired rate is within allowed range.  Some govenors
+        * (ondemand) will just pass target_freq=0 to get the minimum. */
+       if (target_freq < policy->cpuinfo.min_freq)
+               target_freq = policy->cpuinfo.min_freq;
+       if (target_freq > policy->cpuinfo.max_freq)
+               target_freq = policy->cpuinfo.max_freq;
+
        freqs.old = omap_getspeed(0);
        freqs.new = clk_round_rate(mpu_clk, target_freq * 1000) / 1000;
        freqs.cpu = 0;
 
+       if (freqs.old == freqs.new)
+               return ret;
+
        cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE);
-       ret = clk_set_rate(mpu_clk, target_freq * 1000);
+#ifdef CONFIG_CPU_FREQ_DEBUG
+       printk(KERN_DEBUG "cpufreq-omap: transition: %u --> %u\n",
+              freqs.old, freqs.new);
+#endif
+       ret = clk_set_rate(mpu_clk, freqs.new * 1000);
        cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE);
 
        return ret;
@@ -83,16 +103,31 @@ static int omap_target(struct cpufreq_policy *policy,
 
 static int __init omap_cpu_init(struct cpufreq_policy *policy)
 {
+       int result = 0;
+
        mpu_clk = clk_get(NULL, MPU_CLK);
        if (IS_ERR(mpu_clk))
                return PTR_ERR(mpu_clk);
 
        if (policy->cpu != 0)
                return -EINVAL;
+
        policy->cur = policy->min = policy->max = omap_getspeed(0);
-       policy->cpuinfo.min_freq = clk_round_rate(mpu_clk, 0) / 1000;
-       policy->cpuinfo.max_freq = clk_round_rate(mpu_clk, VERY_HI_RATE) / 1000;
-       policy->cpuinfo.transition_latency = CPUFREQ_ETERNAL;
+
+       clk_init_cpufreq_table(&freq_table);
+       if (freq_table) {
+               result = cpufreq_frequency_table_cpuinfo(policy, freq_table);
+               if (!result)
+                       cpufreq_frequency_table_get_attr(freq_table,
+                                                       policy->cpu);
+       } else {
+               policy->cpuinfo.min_freq = clk_round_rate(mpu_clk, 0) / 1000;
+               policy->cpuinfo.max_freq = clk_round_rate(mpu_clk,
+                                                       VERY_HI_RATE) / 1000;
+       }
+
+       /* FIXME: what's the actual transition time? */
+       policy->cpuinfo.transition_latency = 10 * 1000 * 1000;
 
        return 0;
 }
@@ -103,6 +138,11 @@ static int omap_cpu_exit(struct cpufreq_policy *policy)
        return 0;
 }
 
+static struct freq_attr *omap_cpufreq_attr[] = {
+       &cpufreq_freq_attr_scaling_available_freqs,
+       NULL,
+};
+
 static struct cpufreq_driver omap_driver = {
        .flags          = CPUFREQ_STICKY,
        .verify         = omap_verify_speed,
@@ -111,6 +151,7 @@ static struct cpufreq_driver omap_driver = {
        .init           = omap_cpu_init,
        .exit           = omap_cpu_exit,
        .name           = "omap",
+       .attr           = omap_cpufreq_attr,
 };
 
 static int __init omap_cpufreq_init(void)
@@ -119,3 +160,11 @@ static int __init omap_cpufreq_init(void)
 }
 
 arch_initcall(omap_cpufreq_init);
+
+/*
+ * if ever we want to remove this, upon cleanup call:
+ *
+ * cpufreq_unregister_driver()
+ * cpufreq_frequency_table_put_attr()
+ */
+