On Wed, Nov 2, 2011 at 9:43 PM, Kukjin Kim kgene@samsung.com wrote:
From: Jongpill Lee boyko@samsung.com
This patch adds DVS lock feature for other driver and pm/
reboot notifier to enhance stability.
Signed-off-by: Jongpill Lee boyko@samsung.com
Signed-off-by: SangWook Ju sw...@samsung.com
Signed-off-by: Jonghwan Choi jhbird.c...@samsung.com
Signed-off-by: Jaecheol Lee jc@samsung.com
---
arch/arm/mach-exynos4/include/mach/cpufreq.h | 39 ++
drivers/cpufreq/exynos4210-cpufreq.c | 174
+-
2 files changed, 207 insertions(+), 6 deletions(-)
create mode 100644 arch/arm/mach-exynos4/include/mach/cpufreq.h
diff --git a/arch/arm/mach-exynos4/include/mach/cpufreq.h
b/arch/arm/mach-exynos4/include/mach/cpufreq.h
new file mode 100644
index 000..7e00931
--- /dev/null
+++ b/arch/arm/mach-exynos4/include/mach/cpufreq.h
@@ -0,0 +1,39 @@
+/* linux/arch/arm/mach-exynos4/include/mach/cpufreq.h
+ *
+ * Copyright (c) 2011 Samsung Electronics Co., Ltd.
+ * http://www.samsung.com
+ *
+ * EXYNOS4 - 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.
+ */
+
+/*
+ * CPU frequency level index for using cpufreq lock API
+ * This should be same with cpufreq_frequency_table
+ */
+enum cpufreq_level_request {
+ CPU_L0, /* 1200MHz */
+ CPU_L1, /* 1000MHz */
+ CPU_L2, /* 800MHz */
+ CPU_L3, /* 500MHz */
+ CPU_L4, /* 200MHz */
+ CPU_LEVEL_END,
+};
+
+enum cpufreq_lock_ID {
+ DVFS_LOCK_ID_G2D, /* G2D */
+ DVFS_LOCK_ID_TV, /* TV */
+ DVFS_LOCK_ID_MFC, /* MFC */
+ DVFS_LOCK_ID_USB, /* USB */
+ DVFS_LOCK_ID_CAM, /* CAM */
+ DVFS_LOCK_ID_PM, /* PM */
+ DVFS_LOCK_ID_USER, /* USER */
+ DVFS_LOCK_ID_END,
+};
+
+int exynos4_cpufreq_lock(unsigned int nId,
+ enum cpufreq_level_request cpufreq_level);
+void exynos4_cpufreq_lock_free(unsigned int nId);
diff --git a/drivers/cpufreq/exynos4210-cpufreq.c
b/drivers/cpufreq/exynos4210-cpufreq.c
index 246f9e2..30e1949 100644
--- a/drivers/cpufreq/exynos4210-cpufreq.c
+++ b/drivers/cpufreq/exynos4210-cpufreq.c
@@ -17,14 +17,21 @@
#include linux/slab.h
#include linux/regulator/consumer.h
#include linux/cpufreq.h
+#include linux/suspend.h
+#include linux/reboot.h
#include mach/map.h
#include mach/regs-clock.h
#include mach/regs-mem.h
+#include mach/cpufreq.h
#include plat/clock.h
#include plat/pm.h
+static bool exynos4_cpufreq_init_done;
+static DEFINE_MUTEX(set_freq_lock);
+static DEFINE_MUTEX(set_cpu_freq_lock);
+
static struct clk *cpu_clk;
static struct clk *moutcore;
static struct clk *mout_mpll;
@@ -53,6 +60,12 @@ static struct cpufreq_frequency_table
exynos4_freq_table[] = {
{0, CPUFREQ_TABLE_END},
};
+/* This defines are for cpufreq lock */
+#define CPUFREQ_MIN_LEVEL (CPUFREQ_LEVEL_END - 1)
+unsigned int cpufreq_lock_id;
+unsigned int cpufreq_lock_val[DVFS_LOCK_ID_END];
+unsigned int cpufreq_lock_level = CPUFREQ_MIN_LEVEL;
+
static unsigned int clkdiv_cpu0[CPUFREQ_LEVEL_END][7] = {
/*
* Clock divider value for following
@@ -272,22 +285,31 @@ static int exynos4_target(struct cpufreq_policy
*policy,
{
unsigned int index, old_index;
unsigned int arm_volt;
+ int ret = 0;
+
+ mutex_lock(set_freq_lock);
freqs.old = exynos4_getspeed(policy-cpu);
if (cpufreq_frequency_table_target(policy, exynos4_freq_table,
- freqs.old, relation, old_index))
- return -EINVAL;
+ freqs.old, relation, old_index))
{
+ ret = -EINVAL;
+ goto out;
+ }
if (cpufreq_frequency_table_target(policy, exynos4_freq_table,
- target_freq, relation, index))
- return -EINVAL;
+ target_freq, relation, index)) {
+ ret = -EINVAL;
+ goto out;
+ }
freqs.new = exynos4_freq_table[index].frequency;
freqs.cpu = policy-cpu;
- if (freqs.new == freqs.old)
- return 0;
+ if (freqs.new == freqs.old) {
+ ret = -EINVAL;
+ goto out;
+ }
/* get the voltage value */
arm_volt = exynos4_volt_table[index].arm_volt;
@@ -311,8 +333,98 @@ static int exynos4_target(struct cpufreq_policy
*policy,
regulator_set_voltage(arm_regulator, arm_volt, arm_volt);
}
+out:
+ mutex_unlock(set_freq_lock);
+
+ return ret;
+}
+
+atomic_t