Chinaunix首页 | 论坛 | 博客
  • 博客访问: 97274
  • 博文数量: 23
  • 博客积分: 516
  • 博客等级: 中士
  • 技术积分: 315
  • 用 户 组: 普通用户
  • 注册时间: 2011-10-29 16:45
文章分类
文章存档

2012年(11)

2011年(12)

分类: LINUX

2012-01-05 11:47:18

背景:使用esFileManager无法获取cpu频率信息
          利用systeminfo pro也只能查看到current frequency
修改方法:通过参考s3c64xx的cpufreq驱动,添加一个驱动到自己的平台,修改相关的配置文件以实现
说明:我们的产品不支持变频,故将获取的cpu主频赋给一个全局变量。

patch:
From afee80a0d7fe5af0c7bea09c2fcd9c8a0245cf1a Mon Sep 17 00:00:00 2001
From: wangxiaodong
Date: Thu, 5 Jan 2012 11:08:28 +0800
Subject: [PATCH] add emxx_cpufreq driver and display cpufreq info

---
 arch/arm/Kconfig                  |    4 +-
 arch/arm/configs/emev_defconfig   |   16 +++
 arch/arm/mach-emxx/Kconfig        |    3 +
 arch/arm/mach-emxx/Makefile       |    1 +
 arch/arm/mach-emxx/emxx_cpufreq.c |  220 +++++++++++++++++++++++++++++++++++++
 5 files changed, 242 insertions(+), 2 deletions(-)
 mode change 100644 => 100755 arch/arm/Kconfig
 create mode 100755 arch/arm/mach-emxx/emxx_cpufreq.c

diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
old mode 100644
new mode 100755
index ec5abe8..1547628
--- a/arch/arm/Kconfig
+++ b/arch/arm/Kconfig
@@ -1589,7 +1589,7 @@ endmenu
 
 menu "CPU Power Management"
 
-if ARCH_HAS_CPUFREQ
+#if ARCH_HAS_CPUFREQ
 
 source "drivers/cpufreq/Kconfig"
 
@@ -1666,7 +1666,7 @@ config CPU_FREQ_S3C24XX_DEBUGFS
     help
       Export status information via debugfs.
 
-endif
+#endif
 
 source "drivers/cpuidle/Kconfig"
 
diff --git a/arch/arm/configs/emev_defconfig b/arch/arm/configs/emev_defconfig
index 8d2789e..11397ff 100755
--- a/arch/arm/configs/emev_defconfig
+++ b/arch/arm/configs/emev_defconfig
@@ -263,6 +263,7 @@ CONFIG_EMXX_SPI=y
 CONFIG_EMXX_PWM=m
 # CONFIG_EMXX_DTV is not set
 # CONFIG_EMXX_DM2016 is not set
+CONFIG_EMXX_CPUFREQ=y
 CONFIG_EMXX_AXP192_PWC=y
 CONFIG_EMXX_AXP192_REGRW=y
 CONFIG_EMXX_EXTIO=y
@@ -385,6 +386,21 @@ CONFIG_CMDLINE=""
 #
 # CPU Power Management
 #
+CONFIG_CPU_FREQ=y
+CONFIG_CPU_FREQ_TABLE=y
+# CONFIG_CPU_FREQ_DEBUG is not set
+CONFIG_CPU_FREQ_STAT=y
+# CONFIG_CPU_FREQ_STAT_DETAILS is not set
+CONFIG_CPU_FREQ_DEFAULT_GOV_PERFORMANCE=y
+# CONFIG_CPU_FREQ_DEFAULT_GOV_POWERSAVE is not set
+# CONFIG_CPU_FREQ_DEFAULT_GOV_USERSPACE is not set
+# CONFIG_CPU_FREQ_DEFAULT_GOV_ONDEMAND is not set
+# CONFIG_CPU_FREQ_DEFAULT_GOV_CONSERVATIVE is not set
+CONFIG_CPU_FREQ_GOV_PERFORMANCE=y
+# CONFIG_CPU_FREQ_GOV_POWERSAVE is not set
+# CONFIG_CPU_FREQ_GOV_USERSPACE is not set
+# CONFIG_CPU_FREQ_GOV_ONDEMAND is not set
+# CONFIG_CPU_FREQ_GOV_CONSERVATIVE is not set
 # CONFIG_CPU_IDLE is not set
 
 #
diff --git a/arch/arm/mach-emxx/Kconfig b/arch/arm/mach-emxx/Kconfig
index fcecfdf..ff555d4 100755
--- a/arch/arm/mach-emxx/Kconfig
+++ b/arch/arm/mach-emxx/Kconfig
@@ -105,6 +105,9 @@ config EMXX_DM2016
     bool "EMEV DM2016 driver support"
     depends on I2C
     default n
+config EMXX_CPUFREQ
+    bool "EMEV cpufreq driver support"
+    default y
    
 config EMXX_AXP192_PWC
     bool "EMEV AXP 192 driver support"
diff --git a/arch/arm/mach-emxx/Makefile b/arch/arm/mach-emxx/Makefile
index e25f27e..e6bac1f 100755
--- a/arch/arm/mach-emxx/Makefile
+++ b/arch/arm/mach-emxx/Makefile
@@ -34,3 +34,4 @@ obj-$(CONFIG_PM)        += pm_pmu.o
 obj-$(CONFIG_SMP)        += platsmp.o headsmp.o
 obj-$(CONFIG_HOTPLUG_CPU)    += hotplug.o
 
+obj-$(CONFIG_EMXX_CPUFREQ)    += emxx_cpufreq.o   
diff --git a/arch/arm/mach-emxx/emxx_cpufreq.c b/arch/arm/mach-emxx/emxx_cpufreq.c
new file mode 100755
index 0000000..210433c
--- /dev/null
+++ b/arch/arm/mach-emxx/emxx_cpufreq.c
@@ -0,0 +1,220 @@
+/* linux/arch/arm/plat-s3c64xx/cpufreq.c
+ *
+ * Copyright 2009 Wolfson Microelectronics plc
+ *
+ * S3C64xx CPUfreq Support
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+#include
+
+static struct regulator *vddarm;
+
+static unsigned long regulator_latency;
+static unsigned long emxx_cpufreq;
+struct emxx_dvfs {
+    unsigned int vddarm_min;
+    unsigned int vddarm_max;
+};
+
+static struct emxx_dvfs emxx_dvfs_table[] = {
+    [0] = { 1000000, 1150000 },
+    [1] = { 1050000, 1150000 },
+    [2] = { 1100000, 1150000 },
+    [3] = { 1200000, 1350000 },
+};
+
+static struct cpufreq_frequency_table emxx_freq_table[] = {
+    { 0, 1062000 },
+    { 0, 1062000 },
+    { 1, 1062000 },
+    { 1, 1062000 },
+    { 2, 1062000 },
+    { 2, 1062000 },
+    { 2, 1062000 },
+    { 2, 1062000 },
+    { 3, 1062000 },
+    { 0, CPUFREQ_TABLE_END },
+};
+
+static int emxx_cpufreq_verify_speed(struct cpufreq_policy *policy)
+{
+    return cpufreq_frequency_table_verify(policy, emxx_freq_table);
+}
+
+static unsigned int emxx_cpufreq_get_speed(unsigned int cpu)
+{
+    return emxx_cpufreq;
+}
+
+static int emxx_cpufreq_set_target(struct cpufreq_policy *policy,
+                      unsigned int target_freq,
+                      unsigned int relation)
+{
+    int ret;
+    unsigned int i;
+    struct cpufreq_freqs freqs;
+    struct emxx_dvfs *dvfs;
+
+    ret = cpufreq_frequency_table_target(policy, emxx_freq_table,
+                         target_freq, relation, &i);
+    if (ret != 0)
+        return ret;
+
+    freqs.cpu = 0;
+    freqs.old = emxx_cpufreq;
+    freqs.new = emxx_freq_table[i].frequency;
+    freqs.flags = 0;
+    dvfs = &emxx_dvfs_table[emxx_freq_table[i].index];
+
+    if (freqs.old == freqs.new)
+        return 0;
+
+    pr_debug("cpufreq: Transition %d-%dkHz\n", freqs.old, freqs.new);
+
+    cpufreq_notify_transition(&freqs, CPUFREQ_PRECHANGE);
+
+#ifdef CONFIG_REGULATOR
+    if (vddarm && freqs.new < freqs.old) {
+        ret = regulator_set_voltage(vddarm,
+                        dvfs->vddarm_min,
+                        dvfs->vddarm_max);
+        if (ret != 0) {
+            pr_err("cpufreq: Failed to set VDDARM for %dkHz: %d\n",
+                   freqs.new, ret);
+            goto err_clk;
+        }
+    }
+#endif
+
+    cpufreq_notify_transition(&freqs, CPUFREQ_POSTCHANGE);
+
+    return 0;
+}
+
+#ifdef CONFIG_REGULATOR
+static void __init emxx_cpufreq_config_regulator(void)
+{
+    int count, v, i, found;
+    struct cpufreq_frequency_table *freq;
+    struct emxx_dvfs *dvfs;
+
+    count = regulator_count_voltages(vddarm);
+    if (count < 0) {
+        pr_err("cpufreq: Unable to check supported voltages\n");
+    }
+
+    freq = emxx_freq_table;
+    while (count > 0 && freq->frequency != CPUFREQ_TABLE_END) {
+        if (freq->frequency == CPUFREQ_ENTRY_INVALID)
+            continue;
+
+        dvfs = &emxx_dvfs_table[freq->index];
+        found = 0;
+
+        for (i = 0; i < count; i++) {
+            v = regulator_list_voltage(vddarm, i);
+            if (v >= dvfs->vddarm_min && v <= dvfs->vddarm_max)
+                found = 1;
+        }
+
+        if (!found) {
+            pr_debug("cpufreq: %dkHz unsupported by regulator\n",
+                 freq->frequency);
+            freq->frequency = CPUFREQ_ENTRY_INVALID;
+        }
+
+        freq++;
+    }
+
+    /* Guess based on having to do an I2C/SPI write; in future we
+     * will be able to query the regulator performance here. */
+    regulator_latency = 1 * 1000 * 1000;
+}
+#endif
+
+static int __init emxx_cpufreq_driver_init(struct cpufreq_policy *policy)
+{
+    int ret;
+    unsigned int i;
+    unsigned int bogomips = 0;
+    struct cpufreq_frequency_table *freq;
+   
+    if (emxx_freq_table == NULL) {
+        pr_err("cpufreq: No frequency information for this CPU\n");
+        return -ENODEV;
+    }
+
+#ifdef CONFIG_REGULATOR
+    vddarm = regulator_get(NULL, "vddarm");
+    if (IS_ERR(vddarm)) {
+        ret = PTR_ERR(vddarm);
+        pr_err("cpufreq: Failed to obtain VDDARM: %d\n", ret);
+        pr_err("cpufreq: Only frequency scaling available\n");
+        vddarm = NULL;
+    } else {
+        emxx_cpufreq_config_regulator();
+    }
+#endif
+   
+    for_each_online_cpu(i)   
+    {
+        bogomips = per_cpu(cpu_data, i).loops_per_jiffy / (500000UL/HZ);   
+    }   
+
+    emxx_cpufreq = (bogomips + 5)* 1000 / 2;
+
+    freq = emxx_freq_table;
+    while (freq->frequency != CPUFREQ_TABLE_END) {
+   
+        if (emxx_cpufreq != freq->frequency) {
+
+            freq->frequency = emxx_cpufreq;
+        }
+
+        freq++;
+    }
+   
+    policy->cur = emxx_cpufreq;
+
+    /* Datasheet says PLL stabalisation time (if we were to use
+     * the PLLs, which we don't currently) is ~300us worst case,
+     * but add some fudge.
+     */
+    policy->cpuinfo.transition_latency = (500 * 1000) + regulator_latency;
+
+    ret = cpufreq_frequency_table_cpuinfo(policy, emxx_freq_table);
+    if (ret != 0) {
+        pr_err("cpufreq: Failed to configure frequency table: %d\n",
+               ret);
+        regulator_put(vddarm);
+    }
+    return ret;
+}
+
+static struct cpufreq_driver emxx_cpufreq_driver = {
+    .owner        = THIS_MODULE,
+    .flags          = 0,
+    .verify        = emxx_cpufreq_verify_speed,
+    .target        = emxx_cpufreq_set_target,
+    .get        = emxx_cpufreq_get_speed,
+    .init        = emxx_cpufreq_driver_init,
+    .name        = "emev",
+};
+
+static int __init emxx_cpufreq_init(void)
+{
+    return cpufreq_register_driver(&emxx_cpufreq_driver);
+}
+module_init(emxx_cpufreq_init);
--
1.7.5.4


阅读(2846) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~