diff options
author | Jonghwan Choi <jhbird.choi@samsung.com> | 2012-12-23 18:57:48 -0500 |
---|---|---|
committer | Kukjin Kim <kgene.kim@samsung.com> | 2012-12-23 18:57:48 -0500 |
commit | 0e0e425f58fc91b7559350e12060938f8fa7a1c2 (patch) | |
tree | 0ad8546486ad9abf9eb684f197eac1d5064f673b /drivers/cpufreq | |
parent | 9d0554fff9a21d846adcfbd14cfb02e82773162c (diff) |
cpufreq: exynos: Split exynos_target function into two functions
Split exynos_target function into exynos_target & exynos_cpufreq_scale.
The exynos_cpufreq_scale changes the voltage & frequency.
Signed-off-by: Jonghwan Choi <jhbird.choi@samsung.com>
Signed-off-by: Kukjin Kim <kgene.kim@samsung.com>
Diffstat (limited to 'drivers/cpufreq')
-rw-r--r-- | drivers/cpufreq/exynos-cpufreq.c | 151 |
1 files changed, 86 insertions, 65 deletions
diff --git a/drivers/cpufreq/exynos-cpufreq.c b/drivers/cpufreq/exynos-cpufreq.c index 0d40eb7b1dee..232208cf6c03 100644 --- a/drivers/cpufreq/exynos-cpufreq.c +++ b/drivers/cpufreq/exynos-cpufreq.c | |||
@@ -42,54 +42,55 @@ static unsigned int exynos_getspeed(unsigned int cpu) | |||
42 | return clk_get_rate(exynos_info->cpu_clk) / 1000; | 42 | return clk_get_rate(exynos_info->cpu_clk) / 1000; |
43 | } | 43 | } |
44 | 44 | ||
45 | static int exynos_target(struct cpufreq_policy *policy, | 45 | static int exynos_cpufreq_get_index(unsigned int freq) |
46 | unsigned int target_freq, | 46 | { |
47 | unsigned int relation) | 47 | struct cpufreq_frequency_table *freq_table = exynos_info->freq_table; |
48 | int index; | ||
49 | |||
50 | for (index = 0; | ||
51 | freq_table[index].frequency != CPUFREQ_TABLE_END; index++) | ||
52 | if (freq_table[index].frequency == freq) | ||
53 | break; | ||
54 | |||
55 | if (freq_table[index].frequency == CPUFREQ_TABLE_END) | ||
56 | return -EINVAL; | ||
57 | |||
58 | return index; | ||
59 | } | ||
60 | |||
61 | static int exynos_cpufreq_scale(unsigned int target_freq) | ||
48 | { | 62 | { |
49 | unsigned int index, old_index; | ||
50 | unsigned int arm_volt, safe_arm_volt = 0; | ||
51 | int ret = 0; | ||
52 | struct cpufreq_frequency_table *freq_table = exynos_info->freq_table; | 63 | struct cpufreq_frequency_table *freq_table = exynos_info->freq_table; |
53 | unsigned int *volt_table = exynos_info->volt_table; | 64 | unsigned int *volt_table = exynos_info->volt_table; |
65 | struct cpufreq_policy *policy = cpufreq_cpu_get(0); | ||
66 | unsigned int arm_volt, safe_arm_volt = 0; | ||
54 | unsigned int mpll_freq_khz = exynos_info->mpll_freq_khz; | 67 | unsigned int mpll_freq_khz = exynos_info->mpll_freq_khz; |
55 | 68 | unsigned int index, old_index; | |
56 | mutex_lock(&cpufreq_lock); | 69 | int ret = 0; |
57 | 70 | ||
58 | freqs.old = policy->cur; | 71 | freqs.old = policy->cur; |
72 | freqs.cpu = policy->cpu; | ||
59 | 73 | ||
60 | if (frequency_locked && target_freq != locking_frequency) { | 74 | if (target_freq == freqs.old) |
61 | ret = -EAGAIN; | ||
62 | goto out; | 75 | goto out; |
63 | } | ||
64 | 76 | ||
65 | /* | 77 | /* |
66 | * The policy max have been changed so that we cannot get proper | 78 | * The policy max have been changed so that we cannot get proper |
67 | * old_index with cpufreq_frequency_table_target(). Thus, ignore | 79 | * old_index with cpufreq_frequency_table_target(). Thus, ignore |
68 | * policy and get the index from the raw freqeuncy table. | 80 | * policy and get the index from the raw freqeuncy table. |
69 | */ | 81 | */ |
70 | for (old_index = 0; | 82 | old_index = exynos_cpufreq_get_index(freqs.old); |
71 | freq_table[old_index].frequency != CPUFREQ_TABLE_END; | 83 | if (old_index < 0) { |
72 | old_index++) | 84 | ret = old_index; |
73 | if (freq_table[old_index].frequency == freqs.old) | ||
74 | break; | ||
75 | |||
76 | if (freq_table[old_index].frequency == CPUFREQ_TABLE_END) { | ||
77 | ret = -EINVAL; | ||
78 | goto out; | 85 | goto out; |
79 | } | 86 | } |
80 | 87 | ||
81 | if (cpufreq_frequency_table_target(policy, freq_table, | 88 | index = exynos_cpufreq_get_index(target_freq); |
82 | target_freq, relation, &index)) { | 89 | if (index < 0) { |
83 | ret = -EINVAL; | 90 | ret = index; |
84 | goto out; | 91 | goto out; |
85 | } | 92 | } |
86 | 93 | ||
87 | freqs.new = freq_table[index].frequency; | ||
88 | freqs.cpu = policy->cpu; | ||
89 | |||
90 | if (freqs.new == freqs.old) | ||
91 | goto out; | ||
92 | |||
93 | /* | 94 | /* |
94 | * ARM clock source will be changed APLL to MPLL temporary | 95 | * ARM clock source will be changed APLL to MPLL temporary |
95 | * To support this level, need to control regulator for | 96 | * To support this level, need to control regulator for |
@@ -109,13 +110,23 @@ static int exynos_target(struct cpufreq_policy *policy, | |||
109 | /* When the new frequency is higher than current frequency */ | 110 | /* When the new frequency is higher than current frequency */ |
110 | if ((freqs.new > freqs.old) && !safe_arm_volt) { | 111 | if ((freqs.new > freqs.old) && !safe_arm_volt) { |
111 | /* Firstly, voltage up to increase frequency */ | 112 | /* Firstly, voltage up to increase frequency */ |
112 | regulator_set_voltage(arm_regulator, arm_volt, | 113 | ret = regulator_set_voltage(arm_regulator, arm_volt, arm_volt); |
113 | arm_volt); | 114 | if (ret) { |
115 | pr_err("%s: failed to set cpu voltage to %d\n", | ||
116 | __func__, arm_volt); | ||
117 | goto out; | ||
118 | } | ||
114 | } | 119 | } |
115 | 120 | ||
116 | if (safe_arm_volt) | 121 | if (safe_arm_volt) { |
117 | regulator_set_voltage(arm_regulator, safe_arm_volt, | 122 | ret = regulator_set_voltage(arm_regulator, safe_arm_volt, |
118 | safe_arm_volt); | 123 | safe_arm_volt); |
124 | if (ret) { | ||
125 | pr_err("%s: failed to set cpu voltage to %d\n", | ||
126 | __func__, safe_arm_volt); | ||
127 | goto out; | ||
128 | } | ||
129 | } | ||
119 | 130 | ||
120 | exynos_info->set_freq(old_index, index); | 131 | exynos_info->set_freq(old_index, index); |
121 | 132 | ||
@@ -128,8 +139,43 @@ static int exynos_target(struct cpufreq_policy *policy, | |||
128 | /* down the voltage after frequency change */ | 139 | /* down the voltage after frequency change */ |
129 | regulator_set_voltage(arm_regulator, arm_volt, | 140 | regulator_set_voltage(arm_regulator, arm_volt, |
130 | arm_volt); | 141 | arm_volt); |
142 | if (ret) { | ||
143 | pr_err("%s: failed to set cpu voltage to %d\n", | ||
144 | __func__, arm_volt); | ||
145 | goto out; | ||
146 | } | ||
147 | } | ||
148 | |||
149 | out: | ||
150 | |||
151 | cpufreq_cpu_put(policy); | ||
152 | |||
153 | return ret; | ||
154 | } | ||
155 | |||
156 | static int exynos_target(struct cpufreq_policy *policy, | ||
157 | unsigned int target_freq, | ||
158 | unsigned int relation) | ||
159 | { | ||
160 | struct cpufreq_frequency_table *freq_table = exynos_info->freq_table; | ||
161 | unsigned int index; | ||
162 | int ret; | ||
163 | |||
164 | mutex_lock(&cpufreq_lock); | ||
165 | |||
166 | if (frequency_locked) | ||
167 | goto out; | ||
168 | |||
169 | if (cpufreq_frequency_table_target(policy, freq_table, | ||
170 | target_freq, relation, &index)) { | ||
171 | ret = -EINVAL; | ||
172 | goto out; | ||
131 | } | 173 | } |
132 | 174 | ||
175 | freqs.new = freq_table[index].frequency; | ||
176 | |||
177 | ret = exynos_cpufreq_scale(freqs.new); | ||
178 | |||
133 | out: | 179 | out: |
134 | mutex_unlock(&cpufreq_lock); | 180 | mutex_unlock(&cpufreq_lock); |
135 | 181 | ||
@@ -166,51 +212,26 @@ static int exynos_cpufreq_resume(struct cpufreq_policy *policy) | |||
166 | static int exynos_cpufreq_pm_notifier(struct notifier_block *notifier, | 212 | static int exynos_cpufreq_pm_notifier(struct notifier_block *notifier, |
167 | unsigned long pm_event, void *v) | 213 | unsigned long pm_event, void *v) |
168 | { | 214 | { |
169 | struct cpufreq_policy *policy = cpufreq_cpu_get(0); /* boot CPU */ | 215 | int ret; |
170 | static unsigned int saved_frequency; | ||
171 | unsigned int temp; | ||
172 | 216 | ||
173 | mutex_lock(&cpufreq_lock); | ||
174 | switch (pm_event) { | 217 | switch (pm_event) { |
175 | case PM_SUSPEND_PREPARE: | 218 | case PM_SUSPEND_PREPARE: |
176 | if (frequency_locked) | 219 | mutex_lock(&cpufreq_lock); |
177 | goto out; | ||
178 | |||
179 | frequency_locked = true; | 220 | frequency_locked = true; |
221 | mutex_unlock(&cpufreq_lock); | ||
180 | 222 | ||
181 | if (locking_frequency) { | 223 | ret = exynos_cpufreq_scale(locking_frequency); |
182 | saved_frequency = exynos_getspeed(0); | 224 | if (ret < 0) |
225 | return NOTIFY_BAD; | ||
183 | 226 | ||
184 | mutex_unlock(&cpufreq_lock); | ||
185 | exynos_target(policy, locking_frequency, | ||
186 | CPUFREQ_RELATION_H); | ||
187 | mutex_lock(&cpufreq_lock); | ||
188 | } | ||
189 | break; | 227 | break; |
190 | 228 | ||
191 | case PM_POST_SUSPEND: | 229 | case PM_POST_SUSPEND: |
192 | if (saved_frequency) { | 230 | mutex_lock(&cpufreq_lock); |
193 | /* | ||
194 | * While frequency_locked, only locking_frequency | ||
195 | * is valid for target(). In order to use | ||
196 | * saved_frequency while keeping frequency_locked, | ||
197 | * we temporarly overwrite locking_frequency. | ||
198 | */ | ||
199 | temp = locking_frequency; | ||
200 | locking_frequency = saved_frequency; | ||
201 | |||
202 | mutex_unlock(&cpufreq_lock); | ||
203 | exynos_target(policy, locking_frequency, | ||
204 | CPUFREQ_RELATION_H); | ||
205 | mutex_lock(&cpufreq_lock); | ||
206 | |||
207 | locking_frequency = temp; | ||
208 | } | ||
209 | frequency_locked = false; | 231 | frequency_locked = false; |
232 | mutex_unlock(&cpufreq_lock); | ||
210 | break; | 233 | break; |
211 | } | 234 | } |
212 | out: | ||
213 | mutex_unlock(&cpufreq_lock); | ||
214 | 235 | ||
215 | return NOTIFY_OK; | 236 | return NOTIFY_OK; |
216 | } | 237 | } |