diff options
author | Zhang Rui <rui.zhang@intel.com> | 2014-12-21 09:49:12 -0500 |
---|---|---|
committer | Zhang Rui <rui.zhang@intel.com> | 2014-12-21 09:49:12 -0500 |
commit | 32c9edc4e356063e0218362d452a269cfa6798ee (patch) | |
tree | 43982a1f642c7fedef1cc5f8c247b646582cbe03 /drivers/thermal | |
parent | 59c56eb6db0c14fe569b1c9625cb850e52d29d88 (diff) | |
parent | 503ccc3fec4a56cdcfedc507cd1ea0d85e1fbfa2 (diff) |
Merge branch 'fixes' of git://git.kernel.org/pub/scm/linux/kernel/git/evalenti/linux-soc-thermal into thermal-soc
Diffstat (limited to 'drivers/thermal')
-rw-r--r-- | drivers/thermal/cpu_cooling.c | 359 | ||||
-rw-r--r-- | drivers/thermal/db8500_cpufreq_cooling.c | 20 | ||||
-rw-r--r-- | drivers/thermal/imx_thermal.c | 15 | ||||
-rw-r--r-- | drivers/thermal/samsung/Kconfig | 2 | ||||
-rw-r--r-- | drivers/thermal/samsung/exynos_thermal_common.c | 12 | ||||
-rw-r--r-- | drivers/thermal/samsung/exynos_tmu.c | 5 | ||||
-rw-r--r-- | drivers/thermal/thermal_core.c | 6 | ||||
-rw-r--r-- | drivers/thermal/ti-soc-thermal/ti-thermal-common.c | 17 |
8 files changed, 172 insertions, 264 deletions
diff --git a/drivers/thermal/cpu_cooling.c b/drivers/thermal/cpu_cooling.c index ad09e51ffae4..9b45f6426f44 100644 --- a/drivers/thermal/cpu_cooling.c +++ b/drivers/thermal/cpu_cooling.c | |||
@@ -4,6 +4,8 @@ | |||
4 | * Copyright (C) 2012 Samsung Electronics Co., Ltd(http://www.samsung.com) | 4 | * Copyright (C) 2012 Samsung Electronics Co., Ltd(http://www.samsung.com) |
5 | * Copyright (C) 2012 Amit Daniel <amit.kachhap@linaro.org> | 5 | * Copyright (C) 2012 Amit Daniel <amit.kachhap@linaro.org> |
6 | * | 6 | * |
7 | * Copyright (C) 2014 Viresh Kumar <viresh.kumar@linaro.org> | ||
8 | * | ||
7 | * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ | 9 | * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
8 | * This program is free software; you can redistribute it and/or modify | 10 | * This program is free software; you can redistribute it and/or modify |
9 | * it under the terms of the GNU General Public License as published by | 11 | * it under the terms of the GNU General Public License as published by |
@@ -28,6 +30,20 @@ | |||
28 | #include <linux/cpu.h> | 30 | #include <linux/cpu.h> |
29 | #include <linux/cpu_cooling.h> | 31 | #include <linux/cpu_cooling.h> |
30 | 32 | ||
33 | /* | ||
34 | * Cooling state <-> CPUFreq frequency | ||
35 | * | ||
36 | * Cooling states are translated to frequencies throughout this driver and this | ||
37 | * is the relation between them. | ||
38 | * | ||
39 | * Highest cooling state corresponds to lowest possible frequency. | ||
40 | * | ||
41 | * i.e. | ||
42 | * level 0 --> 1st Max Freq | ||
43 | * level 1 --> 2nd Max Freq | ||
44 | * ... | ||
45 | */ | ||
46 | |||
31 | /** | 47 | /** |
32 | * struct cpufreq_cooling_device - data for cooling device with cpufreq | 48 | * struct cpufreq_cooling_device - data for cooling device with cpufreq |
33 | * @id: unique integer value corresponding to each cpufreq_cooling_device | 49 | * @id: unique integer value corresponding to each cpufreq_cooling_device |
@@ -38,25 +54,26 @@ | |||
38 | * cooling devices. | 54 | * cooling devices. |
39 | * @cpufreq_val: integer value representing the absolute value of the clipped | 55 | * @cpufreq_val: integer value representing the absolute value of the clipped |
40 | * frequency. | 56 | * frequency. |
57 | * @max_level: maximum cooling level. One less than total number of valid | ||
58 | * cpufreq frequencies. | ||
41 | * @allowed_cpus: all the cpus involved for this cpufreq_cooling_device. | 59 | * @allowed_cpus: all the cpus involved for this cpufreq_cooling_device. |
42 | * | 60 | * |
43 | * This structure is required for keeping information of each | 61 | * This structure is required for keeping information of each registered |
44 | * cpufreq_cooling_device registered. In order to prevent corruption of this a | 62 | * cpufreq_cooling_device. |
45 | * mutex lock cooling_cpufreq_lock is used. | ||
46 | */ | 63 | */ |
47 | struct cpufreq_cooling_device { | 64 | struct cpufreq_cooling_device { |
48 | int id; | 65 | int id; |
49 | struct thermal_cooling_device *cool_dev; | 66 | struct thermal_cooling_device *cool_dev; |
50 | unsigned int cpufreq_state; | 67 | unsigned int cpufreq_state; |
51 | unsigned int cpufreq_val; | 68 | unsigned int cpufreq_val; |
69 | unsigned int max_level; | ||
70 | unsigned int *freq_table; /* In descending order */ | ||
52 | struct cpumask allowed_cpus; | 71 | struct cpumask allowed_cpus; |
53 | struct list_head node; | 72 | struct list_head node; |
54 | }; | 73 | }; |
55 | static DEFINE_IDR(cpufreq_idr); | 74 | static DEFINE_IDR(cpufreq_idr); |
56 | static DEFINE_MUTEX(cooling_cpufreq_lock); | 75 | static DEFINE_MUTEX(cooling_cpufreq_lock); |
57 | 76 | ||
58 | static unsigned int cpufreq_dev_count; | ||
59 | |||
60 | static LIST_HEAD(cpufreq_dev_list); | 77 | static LIST_HEAD(cpufreq_dev_list); |
61 | 78 | ||
62 | /** | 79 | /** |
@@ -98,120 +115,30 @@ static void release_idr(struct idr *idr, int id) | |||
98 | /* Below code defines functions to be used for cpufreq as cooling device */ | 115 | /* Below code defines functions to be used for cpufreq as cooling device */ |
99 | 116 | ||
100 | /** | 117 | /** |
101 | * is_cpufreq_valid - function to check frequency transitioning capability. | 118 | * get_level: Find the level for a particular frequency |
102 | * @cpu: cpu for which check is needed. | 119 | * @cpufreq_dev: cpufreq_dev for which the property is required |
120 | * @freq: Frequency | ||
103 | * | 121 | * |
104 | * This function will check the current state of the system if | 122 | * Return: level on success, THERMAL_CSTATE_INVALID on error. |
105 | * it is capable of changing the frequency for a given @cpu. | ||
106 | * | ||
107 | * Return: 0 if the system is not currently capable of changing | ||
108 | * the frequency of given cpu. !0 in case the frequency is changeable. | ||
109 | */ | 123 | */ |
110 | static int is_cpufreq_valid(int cpu) | 124 | static unsigned long get_level(struct cpufreq_cooling_device *cpufreq_dev, |
125 | unsigned int freq) | ||
111 | { | 126 | { |
112 | struct cpufreq_policy policy; | 127 | unsigned long level; |
113 | |||
114 | return !cpufreq_get_policy(&policy, cpu); | ||
115 | } | ||
116 | |||
117 | enum cpufreq_cooling_property { | ||
118 | GET_LEVEL, | ||
119 | GET_FREQ, | ||
120 | GET_MAXL, | ||
121 | }; | ||
122 | |||
123 | /** | ||
124 | * get_property - fetch a property of interest for a give cpu. | ||
125 | * @cpu: cpu for which the property is required | ||
126 | * @input: query parameter | ||
127 | * @output: query return | ||
128 | * @property: type of query (frequency, level, max level) | ||
129 | * | ||
130 | * This is the common function to | ||
131 | * 1. get maximum cpu cooling states | ||
132 | * 2. translate frequency to cooling state | ||
133 | * 3. translate cooling state to frequency | ||
134 | * Note that the code may be not in good shape | ||
135 | * but it is written in this way in order to: | ||
136 | * a) reduce duplicate code as most of the code can be shared. | ||
137 | * b) make sure the logic is consistent when translating between | ||
138 | * cooling states and frequencies. | ||
139 | * | ||
140 | * Return: 0 on success, -EINVAL when invalid parameters are passed. | ||
141 | */ | ||
142 | static int get_property(unsigned int cpu, unsigned long input, | ||
143 | unsigned int *output, | ||
144 | enum cpufreq_cooling_property property) | ||
145 | { | ||
146 | int i; | ||
147 | unsigned long max_level = 0, level = 0; | ||
148 | unsigned int freq = CPUFREQ_ENTRY_INVALID; | ||
149 | int descend = -1; | ||
150 | struct cpufreq_frequency_table *pos, *table = | ||
151 | cpufreq_frequency_get_table(cpu); | ||
152 | |||
153 | if (!output) | ||
154 | return -EINVAL; | ||
155 | |||
156 | if (!table) | ||
157 | return -EINVAL; | ||
158 | |||
159 | cpufreq_for_each_valid_entry(pos, table) { | ||
160 | /* ignore duplicate entry */ | ||
161 | if (freq == pos->frequency) | ||
162 | continue; | ||
163 | |||
164 | /* get the frequency order */ | ||
165 | if (freq != CPUFREQ_ENTRY_INVALID && descend == -1) | ||
166 | descend = freq > pos->frequency; | ||
167 | |||
168 | freq = pos->frequency; | ||
169 | max_level++; | ||
170 | } | ||
171 | |||
172 | /* No valid cpu frequency entry */ | ||
173 | if (max_level == 0) | ||
174 | return -EINVAL; | ||
175 | 128 | ||
176 | /* max_level is an index, not a counter */ | 129 | for (level = 0; level <= cpufreq_dev->max_level; level++) { |
177 | max_level--; | 130 | if (freq == cpufreq_dev->freq_table[level]) |
131 | return level; | ||
178 | 132 | ||
179 | /* get max level */ | 133 | if (freq > cpufreq_dev->freq_table[level]) |
180 | if (property == GET_MAXL) { | 134 | break; |
181 | *output = (unsigned int)max_level; | ||
182 | return 0; | ||
183 | } | 135 | } |
184 | 136 | ||
185 | if (property == GET_FREQ) | 137 | return THERMAL_CSTATE_INVALID; |
186 | level = descend ? input : (max_level - input); | ||
187 | |||
188 | i = 0; | ||
189 | cpufreq_for_each_valid_entry(pos, table) { | ||
190 | /* ignore duplicate entry */ | ||
191 | if (freq == pos->frequency) | ||
192 | continue; | ||
193 | |||
194 | /* now we have a valid frequency entry */ | ||
195 | freq = pos->frequency; | ||
196 | |||
197 | if (property == GET_LEVEL && (unsigned int)input == freq) { | ||
198 | /* get level by frequency */ | ||
199 | *output = descend ? i : (max_level - i); | ||
200 | return 0; | ||
201 | } | ||
202 | if (property == GET_FREQ && level == i) { | ||
203 | /* get frequency by level */ | ||
204 | *output = freq; | ||
205 | return 0; | ||
206 | } | ||
207 | i++; | ||
208 | } | ||
209 | |||
210 | return -EINVAL; | ||
211 | } | 138 | } |
212 | 139 | ||
213 | /** | 140 | /** |
214 | * cpufreq_cooling_get_level - for a give cpu, return the cooling level. | 141 | * cpufreq_cooling_get_level - for a given cpu, return the cooling level. |
215 | * @cpu: cpu for which the level is required | 142 | * @cpu: cpu for which the level is required |
216 | * @freq: the frequency of interest | 143 | * @freq: the frequency of interest |
217 | * | 144 | * |
@@ -223,77 +150,21 @@ static int get_property(unsigned int cpu, unsigned long input, | |||
223 | */ | 150 | */ |
224 | unsigned long cpufreq_cooling_get_level(unsigned int cpu, unsigned int freq) | 151 | unsigned long cpufreq_cooling_get_level(unsigned int cpu, unsigned int freq) |
225 | { | 152 | { |
226 | unsigned int val; | 153 | struct cpufreq_cooling_device *cpufreq_dev; |
227 | |||
228 | if (get_property(cpu, (unsigned long)freq, &val, GET_LEVEL)) | ||
229 | return THERMAL_CSTATE_INVALID; | ||
230 | |||
231 | return (unsigned long)val; | ||
232 | } | ||
233 | EXPORT_SYMBOL_GPL(cpufreq_cooling_get_level); | ||
234 | |||
235 | /** | ||
236 | * get_cpu_frequency - get the absolute value of frequency from level. | ||
237 | * @cpu: cpu for which frequency is fetched. | ||
238 | * @level: cooling level | ||
239 | * | ||
240 | * This function matches cooling level with frequency. Based on a cooling level | ||
241 | * of frequency, equals cooling state of cpu cooling device, it will return | ||
242 | * the corresponding frequency. | ||
243 | * e.g level=0 --> 1st MAX FREQ, level=1 ---> 2nd MAX FREQ, .... etc | ||
244 | * | ||
245 | * Return: 0 on error, the corresponding frequency otherwise. | ||
246 | */ | ||
247 | static unsigned int get_cpu_frequency(unsigned int cpu, unsigned long level) | ||
248 | { | ||
249 | int ret = 0; | ||
250 | unsigned int freq; | ||
251 | |||
252 | ret = get_property(cpu, level, &freq, GET_FREQ); | ||
253 | if (ret) | ||
254 | return 0; | ||
255 | |||
256 | return freq; | ||
257 | } | ||
258 | |||
259 | /** | ||
260 | * cpufreq_apply_cooling - function to apply frequency clipping. | ||
261 | * @cpufreq_device: cpufreq_cooling_device pointer containing frequency | ||
262 | * clipping data. | ||
263 | * @cooling_state: value of the cooling state. | ||
264 | * | ||
265 | * Function used to make sure the cpufreq layer is aware of current thermal | ||
266 | * limits. The limits are applied by updating the cpufreq policy. | ||
267 | * | ||
268 | * Return: 0 on success, an error code otherwise (-EINVAL in case wrong | ||
269 | * cooling state). | ||
270 | */ | ||
271 | static int cpufreq_apply_cooling(struct cpufreq_cooling_device *cpufreq_device, | ||
272 | unsigned long cooling_state) | ||
273 | { | ||
274 | unsigned int cpuid, clip_freq; | ||
275 | struct cpumask *mask = &cpufreq_device->allowed_cpus; | ||
276 | unsigned int cpu = cpumask_any(mask); | ||
277 | |||
278 | |||
279 | /* Check if the old cooling action is same as new cooling action */ | ||
280 | if (cpufreq_device->cpufreq_state == cooling_state) | ||
281 | return 0; | ||
282 | |||
283 | clip_freq = get_cpu_frequency(cpu, cooling_state); | ||
284 | if (!clip_freq) | ||
285 | return -EINVAL; | ||
286 | |||
287 | cpufreq_device->cpufreq_state = cooling_state; | ||
288 | cpufreq_device->cpufreq_val = clip_freq; | ||
289 | 154 | ||
290 | for_each_cpu(cpuid, mask) { | 155 | mutex_lock(&cooling_cpufreq_lock); |
291 | if (is_cpufreq_valid(cpuid)) | 156 | list_for_each_entry(cpufreq_dev, &cpufreq_dev_list, node) { |
292 | cpufreq_update_policy(cpuid); | 157 | if (cpumask_test_cpu(cpu, &cpufreq_dev->allowed_cpus)) { |
158 | mutex_unlock(&cooling_cpufreq_lock); | ||
159 | return get_level(cpufreq_dev, freq); | ||
160 | } | ||
293 | } | 161 | } |
162 | mutex_unlock(&cooling_cpufreq_lock); | ||
294 | 163 | ||
295 | return 0; | 164 | pr_err("%s: cpu:%d not part of any cooling device\n", __func__, cpu); |
165 | return THERMAL_CSTATE_INVALID; | ||
296 | } | 166 | } |
167 | EXPORT_SYMBOL_GPL(cpufreq_cooling_get_level); | ||
297 | 168 | ||
298 | /** | 169 | /** |
299 | * cpufreq_thermal_notifier - notifier callback for cpufreq policy change. | 170 | * cpufreq_thermal_notifier - notifier callback for cpufreq policy change. |
@@ -323,11 +194,6 @@ static int cpufreq_thermal_notifier(struct notifier_block *nb, | |||
323 | &cpufreq_dev->allowed_cpus)) | 194 | &cpufreq_dev->allowed_cpus)) |
324 | continue; | 195 | continue; |
325 | 196 | ||
326 | if (!cpufreq_dev->cpufreq_val) | ||
327 | cpufreq_dev->cpufreq_val = get_cpu_frequency( | ||
328 | cpumask_any(&cpufreq_dev->allowed_cpus), | ||
329 | cpufreq_dev->cpufreq_state); | ||
330 | |||
331 | max_freq = cpufreq_dev->cpufreq_val; | 197 | max_freq = cpufreq_dev->cpufreq_val; |
332 | 198 | ||
333 | if (policy->max != max_freq) | 199 | if (policy->max != max_freq) |
@@ -354,19 +220,9 @@ static int cpufreq_get_max_state(struct thermal_cooling_device *cdev, | |||
354 | unsigned long *state) | 220 | unsigned long *state) |
355 | { | 221 | { |
356 | struct cpufreq_cooling_device *cpufreq_device = cdev->devdata; | 222 | struct cpufreq_cooling_device *cpufreq_device = cdev->devdata; |
357 | struct cpumask *mask = &cpufreq_device->allowed_cpus; | ||
358 | unsigned int cpu; | ||
359 | unsigned int count = 0; | ||
360 | int ret; | ||
361 | |||
362 | cpu = cpumask_any(mask); | ||
363 | |||
364 | ret = get_property(cpu, 0, &count, GET_MAXL); | ||
365 | 223 | ||
366 | if (count > 0) | 224 | *state = cpufreq_device->max_level; |
367 | *state = count; | 225 | return 0; |
368 | |||
369 | return ret; | ||
370 | } | 226 | } |
371 | 227 | ||
372 | /** | 228 | /** |
@@ -403,8 +259,24 @@ static int cpufreq_set_cur_state(struct thermal_cooling_device *cdev, | |||
403 | unsigned long state) | 259 | unsigned long state) |
404 | { | 260 | { |
405 | struct cpufreq_cooling_device *cpufreq_device = cdev->devdata; | 261 | struct cpufreq_cooling_device *cpufreq_device = cdev->devdata; |
262 | unsigned int cpu = cpumask_any(&cpufreq_device->allowed_cpus); | ||
263 | unsigned int clip_freq; | ||
264 | |||
265 | /* Request state should be less than max_level */ | ||
266 | if (WARN_ON(state > cpufreq_device->max_level)) | ||
267 | return -EINVAL; | ||
268 | |||
269 | /* Check if the old cooling action is same as new cooling action */ | ||
270 | if (cpufreq_device->cpufreq_state == state) | ||
271 | return 0; | ||
406 | 272 | ||
407 | return cpufreq_apply_cooling(cpufreq_device, state); | 273 | clip_freq = cpufreq_device->freq_table[state]; |
274 | cpufreq_device->cpufreq_state = state; | ||
275 | cpufreq_device->cpufreq_val = clip_freq; | ||
276 | |||
277 | cpufreq_update_policy(cpu); | ||
278 | |||
279 | return 0; | ||
408 | } | 280 | } |
409 | 281 | ||
410 | /* Bind cpufreq callbacks to thermal cooling device ops */ | 282 | /* Bind cpufreq callbacks to thermal cooling device ops */ |
@@ -419,10 +291,25 @@ static struct notifier_block thermal_cpufreq_notifier_block = { | |||
419 | .notifier_call = cpufreq_thermal_notifier, | 291 | .notifier_call = cpufreq_thermal_notifier, |
420 | }; | 292 | }; |
421 | 293 | ||
294 | static unsigned int find_next_max(struct cpufreq_frequency_table *table, | ||
295 | unsigned int prev_max) | ||
296 | { | ||
297 | struct cpufreq_frequency_table *pos; | ||
298 | unsigned int max = 0; | ||
299 | |||
300 | cpufreq_for_each_valid_entry(pos, table) { | ||
301 | if (pos->frequency > max && pos->frequency < prev_max) | ||
302 | max = pos->frequency; | ||
303 | } | ||
304 | |||
305 | return max; | ||
306 | } | ||
307 | |||
422 | /** | 308 | /** |
423 | * __cpufreq_cooling_register - helper function to create cpufreq cooling device | 309 | * __cpufreq_cooling_register - helper function to create cpufreq cooling device |
424 | * @np: a valid struct device_node to the cooling device device tree node | 310 | * @np: a valid struct device_node to the cooling device device tree node |
425 | * @clip_cpus: cpumask of cpus where the frequency constraints will happen. | 311 | * @clip_cpus: cpumask of cpus where the frequency constraints will happen. |
312 | * Normally this should be same as cpufreq policy->related_cpus. | ||
426 | * | 313 | * |
427 | * This interface function registers the cpufreq cooling device with the name | 314 | * This interface function registers the cpufreq cooling device with the name |
428 | * "thermal-cpufreq-%x". This api can support multiple instances of cpufreq | 315 | * "thermal-cpufreq-%x". This api can support multiple instances of cpufreq |
@@ -437,37 +324,42 @@ __cpufreq_cooling_register(struct device_node *np, | |||
437 | const struct cpumask *clip_cpus) | 324 | const struct cpumask *clip_cpus) |
438 | { | 325 | { |
439 | struct thermal_cooling_device *cool_dev; | 326 | struct thermal_cooling_device *cool_dev; |
440 | struct cpufreq_cooling_device *cpufreq_dev = NULL; | 327 | struct cpufreq_cooling_device *cpufreq_dev; |
441 | unsigned int min = 0, max = 0; | ||
442 | char dev_name[THERMAL_NAME_LENGTH]; | 328 | char dev_name[THERMAL_NAME_LENGTH]; |
443 | int ret = 0, i; | 329 | struct cpufreq_frequency_table *pos, *table; |
444 | struct cpufreq_policy policy; | 330 | unsigned int freq, i; |
331 | int ret; | ||
445 | 332 | ||
446 | /* Verify that all the clip cpus have same freq_min, freq_max limit */ | 333 | table = cpufreq_frequency_get_table(cpumask_first(clip_cpus)); |
447 | for_each_cpu(i, clip_cpus) { | 334 | if (!table) { |
448 | /* continue if cpufreq policy not found and not return error */ | 335 | pr_debug("%s: CPUFreq table not found\n", __func__); |
449 | if (!cpufreq_get_policy(&policy, i)) | 336 | return ERR_PTR(-EPROBE_DEFER); |
450 | continue; | ||
451 | if (min == 0 && max == 0) { | ||
452 | min = policy.cpuinfo.min_freq; | ||
453 | max = policy.cpuinfo.max_freq; | ||
454 | } else { | ||
455 | if (min != policy.cpuinfo.min_freq || | ||
456 | max != policy.cpuinfo.max_freq) | ||
457 | return ERR_PTR(-EINVAL); | ||
458 | } | ||
459 | } | 337 | } |
460 | cpufreq_dev = kzalloc(sizeof(struct cpufreq_cooling_device), | 338 | |
461 | GFP_KERNEL); | 339 | cpufreq_dev = kzalloc(sizeof(*cpufreq_dev), GFP_KERNEL); |
462 | if (!cpufreq_dev) | 340 | if (!cpufreq_dev) |
463 | return ERR_PTR(-ENOMEM); | 341 | return ERR_PTR(-ENOMEM); |
464 | 342 | ||
343 | /* Find max levels */ | ||
344 | cpufreq_for_each_valid_entry(pos, table) | ||
345 | cpufreq_dev->max_level++; | ||
346 | |||
347 | cpufreq_dev->freq_table = kmalloc(sizeof(*cpufreq_dev->freq_table) * | ||
348 | cpufreq_dev->max_level, GFP_KERNEL); | ||
349 | if (!cpufreq_dev->freq_table) { | ||
350 | cool_dev = ERR_PTR(-ENOMEM); | ||
351 | goto free_cdev; | ||
352 | } | ||
353 | |||
354 | /* max_level is an index, not a counter */ | ||
355 | cpufreq_dev->max_level--; | ||
356 | |||
465 | cpumask_copy(&cpufreq_dev->allowed_cpus, clip_cpus); | 357 | cpumask_copy(&cpufreq_dev->allowed_cpus, clip_cpus); |
466 | 358 | ||
467 | ret = get_idr(&cpufreq_idr, &cpufreq_dev->id); | 359 | ret = get_idr(&cpufreq_idr, &cpufreq_dev->id); |
468 | if (ret) { | 360 | if (ret) { |
469 | kfree(cpufreq_dev); | 361 | cool_dev = ERR_PTR(ret); |
470 | return ERR_PTR(-EINVAL); | 362 | goto free_table; |
471 | } | 363 | } |
472 | 364 | ||
473 | snprintf(dev_name, sizeof(dev_name), "thermal-cpufreq-%d", | 365 | snprintf(dev_name, sizeof(dev_name), "thermal-cpufreq-%d", |
@@ -475,25 +367,44 @@ __cpufreq_cooling_register(struct device_node *np, | |||
475 | 367 | ||
476 | cool_dev = thermal_of_cooling_device_register(np, dev_name, cpufreq_dev, | 368 | cool_dev = thermal_of_cooling_device_register(np, dev_name, cpufreq_dev, |
477 | &cpufreq_cooling_ops); | 369 | &cpufreq_cooling_ops); |
478 | if (IS_ERR(cool_dev)) { | 370 | if (IS_ERR(cool_dev)) |
479 | release_idr(&cpufreq_idr, cpufreq_dev->id); | 371 | goto remove_idr; |
480 | kfree(cpufreq_dev); | 372 | |
481 | return cool_dev; | 373 | /* Fill freq-table in descending order of frequencies */ |
374 | for (i = 0, freq = -1; i <= cpufreq_dev->max_level; i++) { | ||
375 | freq = find_next_max(table, freq); | ||
376 | cpufreq_dev->freq_table[i] = freq; | ||
377 | |||
378 | /* Warn for duplicate entries */ | ||
379 | if (!freq) | ||
380 | pr_warn("%s: table has duplicate entries\n", __func__); | ||
381 | else | ||
382 | pr_debug("%s: freq:%u KHz\n", __func__, freq); | ||
482 | } | 383 | } |
384 | |||
385 | cpufreq_dev->cpufreq_val = cpufreq_dev->freq_table[0]; | ||
483 | cpufreq_dev->cool_dev = cool_dev; | 386 | cpufreq_dev->cool_dev = cool_dev; |
484 | cpufreq_dev->cpufreq_state = 0; | 387 | |
485 | mutex_lock(&cooling_cpufreq_lock); | 388 | mutex_lock(&cooling_cpufreq_lock); |
486 | 389 | ||
487 | /* Register the notifier for first cpufreq cooling device */ | 390 | /* Register the notifier for first cpufreq cooling device */ |
488 | if (cpufreq_dev_count == 0) | 391 | if (list_empty(&cpufreq_dev_list)) |
489 | cpufreq_register_notifier(&thermal_cpufreq_notifier_block, | 392 | cpufreq_register_notifier(&thermal_cpufreq_notifier_block, |
490 | CPUFREQ_POLICY_NOTIFIER); | 393 | CPUFREQ_POLICY_NOTIFIER); |
491 | cpufreq_dev_count++; | ||
492 | list_add(&cpufreq_dev->node, &cpufreq_dev_list); | 394 | list_add(&cpufreq_dev->node, &cpufreq_dev_list); |
493 | 395 | ||
494 | mutex_unlock(&cooling_cpufreq_lock); | 396 | mutex_unlock(&cooling_cpufreq_lock); |
495 | 397 | ||
496 | return cool_dev; | 398 | return cool_dev; |
399 | |||
400 | remove_idr: | ||
401 | release_idr(&cpufreq_idr, cpufreq_dev->id); | ||
402 | free_table: | ||
403 | kfree(cpufreq_dev->freq_table); | ||
404 | free_cdev: | ||
405 | kfree(cpufreq_dev); | ||
406 | |||
407 | return cool_dev; | ||
497 | } | 408 | } |
498 | 409 | ||
499 | /** | 410 | /** |
@@ -554,16 +465,16 @@ void cpufreq_cooling_unregister(struct thermal_cooling_device *cdev) | |||
554 | cpufreq_dev = cdev->devdata; | 465 | cpufreq_dev = cdev->devdata; |
555 | mutex_lock(&cooling_cpufreq_lock); | 466 | mutex_lock(&cooling_cpufreq_lock); |
556 | list_del(&cpufreq_dev->node); | 467 | list_del(&cpufreq_dev->node); |
557 | cpufreq_dev_count--; | ||
558 | 468 | ||
559 | /* Unregister the notifier for the last cpufreq cooling device */ | 469 | /* Unregister the notifier for the last cpufreq cooling device */ |
560 | if (cpufreq_dev_count == 0) | 470 | if (list_empty(&cpufreq_dev_list)) |
561 | cpufreq_unregister_notifier(&thermal_cpufreq_notifier_block, | 471 | cpufreq_unregister_notifier(&thermal_cpufreq_notifier_block, |
562 | CPUFREQ_POLICY_NOTIFIER); | 472 | CPUFREQ_POLICY_NOTIFIER); |
563 | mutex_unlock(&cooling_cpufreq_lock); | 473 | mutex_unlock(&cooling_cpufreq_lock); |
564 | 474 | ||
565 | thermal_cooling_device_unregister(cpufreq_dev->cool_dev); | 475 | thermal_cooling_device_unregister(cpufreq_dev->cool_dev); |
566 | release_idr(&cpufreq_idr, cpufreq_dev->id); | 476 | release_idr(&cpufreq_idr, cpufreq_dev->id); |
477 | kfree(cpufreq_dev->freq_table); | ||
567 | kfree(cpufreq_dev); | 478 | kfree(cpufreq_dev); |
568 | } | 479 | } |
569 | EXPORT_SYMBOL_GPL(cpufreq_cooling_unregister); | 480 | EXPORT_SYMBOL_GPL(cpufreq_cooling_unregister); |
diff --git a/drivers/thermal/db8500_cpufreq_cooling.c b/drivers/thermal/db8500_cpufreq_cooling.c index 000d53e934a0..607b62c7e611 100644 --- a/drivers/thermal/db8500_cpufreq_cooling.c +++ b/drivers/thermal/db8500_cpufreq_cooling.c | |||
@@ -18,7 +18,6 @@ | |||
18 | */ | 18 | */ |
19 | 19 | ||
20 | #include <linux/cpu_cooling.h> | 20 | #include <linux/cpu_cooling.h> |
21 | #include <linux/cpufreq.h> | ||
22 | #include <linux/err.h> | 21 | #include <linux/err.h> |
23 | #include <linux/module.h> | 22 | #include <linux/module.h> |
24 | #include <linux/of.h> | 23 | #include <linux/of.h> |
@@ -28,18 +27,17 @@ | |||
28 | static int db8500_cpufreq_cooling_probe(struct platform_device *pdev) | 27 | static int db8500_cpufreq_cooling_probe(struct platform_device *pdev) |
29 | { | 28 | { |
30 | struct thermal_cooling_device *cdev; | 29 | struct thermal_cooling_device *cdev; |
31 | struct cpumask mask_val; | ||
32 | |||
33 | /* make sure cpufreq driver has been initialized */ | ||
34 | if (!cpufreq_frequency_get_table(0)) | ||
35 | return -EPROBE_DEFER; | ||
36 | |||
37 | cpumask_set_cpu(0, &mask_val); | ||
38 | cdev = cpufreq_cooling_register(&mask_val); | ||
39 | 30 | ||
31 | cdev = cpufreq_cooling_register(cpu_present_mask); | ||
40 | if (IS_ERR(cdev)) { | 32 | if (IS_ERR(cdev)) { |
41 | dev_err(&pdev->dev, "Failed to register cooling device\n"); | 33 | int ret = PTR_ERR(cdev); |
42 | return PTR_ERR(cdev); | 34 | |
35 | if (ret != -EPROBE_DEFER) | ||
36 | dev_err(&pdev->dev, | ||
37 | "Failed to register cooling device %d\n", | ||
38 | ret); | ||
39 | |||
40 | return ret; | ||
43 | } | 41 | } |
44 | 42 | ||
45 | platform_set_drvdata(pdev, cdev); | 43 | platform_set_drvdata(pdev, cdev); |
diff --git a/drivers/thermal/imx_thermal.c b/drivers/thermal/imx_thermal.c index 88b32f942dcf..c1188ac053c9 100644 --- a/drivers/thermal/imx_thermal.c +++ b/drivers/thermal/imx_thermal.c | |||
@@ -9,7 +9,6 @@ | |||
9 | 9 | ||
10 | #include <linux/clk.h> | 10 | #include <linux/clk.h> |
11 | #include <linux/cpu_cooling.h> | 11 | #include <linux/cpu_cooling.h> |
12 | #include <linux/cpufreq.h> | ||
13 | #include <linux/delay.h> | 12 | #include <linux/delay.h> |
14 | #include <linux/device.h> | 13 | #include <linux/device.h> |
15 | #include <linux/init.h> | 14 | #include <linux/init.h> |
@@ -454,15 +453,10 @@ static int imx_thermal_probe(struct platform_device *pdev) | |||
454 | const struct of_device_id *of_id = | 453 | const struct of_device_id *of_id = |
455 | of_match_device(of_imx_thermal_match, &pdev->dev); | 454 | of_match_device(of_imx_thermal_match, &pdev->dev); |
456 | struct imx_thermal_data *data; | 455 | struct imx_thermal_data *data; |
457 | struct cpumask clip_cpus; | ||
458 | struct regmap *map; | 456 | struct regmap *map; |
459 | int measure_freq; | 457 | int measure_freq; |
460 | int ret; | 458 | int ret; |
461 | 459 | ||
462 | if (!cpufreq_get_current_driver()) { | ||
463 | dev_dbg(&pdev->dev, "no cpufreq driver!"); | ||
464 | return -EPROBE_DEFER; | ||
465 | } | ||
466 | data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL); | 460 | data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL); |
467 | if (!data) | 461 | if (!data) |
468 | return -ENOMEM; | 462 | return -ENOMEM; |
@@ -516,12 +510,13 @@ static int imx_thermal_probe(struct platform_device *pdev) | |||
516 | regmap_write(map, MISC0 + REG_SET, MISC0_REFTOP_SELBIASOFF); | 510 | regmap_write(map, MISC0 + REG_SET, MISC0_REFTOP_SELBIASOFF); |
517 | regmap_write(map, TEMPSENSE0 + REG_SET, TEMPSENSE0_POWER_DOWN); | 511 | regmap_write(map, TEMPSENSE0 + REG_SET, TEMPSENSE0_POWER_DOWN); |
518 | 512 | ||
519 | cpumask_set_cpu(0, &clip_cpus); | 513 | data->cdev = cpufreq_cooling_register(cpu_present_mask); |
520 | data->cdev = cpufreq_cooling_register(&clip_cpus); | ||
521 | if (IS_ERR(data->cdev)) { | 514 | if (IS_ERR(data->cdev)) { |
522 | ret = PTR_ERR(data->cdev); | 515 | ret = PTR_ERR(data->cdev); |
523 | dev_err(&pdev->dev, | 516 | if (ret != -EPROBE_DEFER) |
524 | "failed to register cpufreq cooling device: %d\n", ret); | 517 | dev_err(&pdev->dev, |
518 | "failed to register cpufreq cooling device: %d\n", | ||
519 | ret); | ||
525 | return ret; | 520 | return ret; |
526 | } | 521 | } |
527 | 522 | ||
diff --git a/drivers/thermal/samsung/Kconfig b/drivers/thermal/samsung/Kconfig index f760389a204c..c43306ecc0ab 100644 --- a/drivers/thermal/samsung/Kconfig +++ b/drivers/thermal/samsung/Kconfig | |||
@@ -1,6 +1,6 @@ | |||
1 | config EXYNOS_THERMAL | 1 | config EXYNOS_THERMAL |
2 | tristate "Exynos thermal management unit driver" | 2 | tristate "Exynos thermal management unit driver" |
3 | depends on ARCH_HAS_BANDGAP && OF | 3 | depends on OF |
4 | help | 4 | help |
5 | If you say yes here you get support for the TMU (Thermal Management | 5 | If you say yes here you get support for the TMU (Thermal Management |
6 | Unit) driver for SAMSUNG EXYNOS series of SoCs. This driver initialises | 6 | Unit) driver for SAMSUNG EXYNOS series of SoCs. This driver initialises |
diff --git a/drivers/thermal/samsung/exynos_thermal_common.c b/drivers/thermal/samsung/exynos_thermal_common.c index b6be572704a4..6dc3815cc73f 100644 --- a/drivers/thermal/samsung/exynos_thermal_common.c +++ b/drivers/thermal/samsung/exynos_thermal_common.c | |||
@@ -347,7 +347,6 @@ void exynos_report_trigger(struct thermal_sensor_conf *conf) | |||
347 | int exynos_register_thermal(struct thermal_sensor_conf *sensor_conf) | 347 | int exynos_register_thermal(struct thermal_sensor_conf *sensor_conf) |
348 | { | 348 | { |
349 | int ret; | 349 | int ret; |
350 | struct cpumask mask_val; | ||
351 | struct exynos_thermal_zone *th_zone; | 350 | struct exynos_thermal_zone *th_zone; |
352 | 351 | ||
353 | if (!sensor_conf || !sensor_conf->read_temperature) { | 352 | if (!sensor_conf || !sensor_conf->read_temperature) { |
@@ -367,13 +366,14 @@ int exynos_register_thermal(struct thermal_sensor_conf *sensor_conf) | |||
367 | * sensor | 366 | * sensor |
368 | */ | 367 | */ |
369 | if (sensor_conf->cooling_data.freq_clip_count > 0) { | 368 | if (sensor_conf->cooling_data.freq_clip_count > 0) { |
370 | cpumask_set_cpu(0, &mask_val); | ||
371 | th_zone->cool_dev[th_zone->cool_dev_size] = | 369 | th_zone->cool_dev[th_zone->cool_dev_size] = |
372 | cpufreq_cooling_register(&mask_val); | 370 | cpufreq_cooling_register(cpu_present_mask); |
373 | if (IS_ERR(th_zone->cool_dev[th_zone->cool_dev_size])) { | 371 | if (IS_ERR(th_zone->cool_dev[th_zone->cool_dev_size])) { |
374 | dev_err(sensor_conf->dev, | 372 | ret = PTR_ERR(th_zone->cool_dev[th_zone->cool_dev_size]); |
375 | "Failed to register cpufreq cooling device\n"); | 373 | if (ret != -EPROBE_DEFER) |
376 | ret = -EINVAL; | 374 | dev_err(sensor_conf->dev, |
375 | "Failed to register cpufreq cooling device: %d\n", | ||
376 | ret); | ||
377 | goto err_unregister; | 377 | goto err_unregister; |
378 | } | 378 | } |
379 | th_zone->cool_dev_size++; | 379 | th_zone->cool_dev_size++; |
diff --git a/drivers/thermal/samsung/exynos_tmu.c b/drivers/thermal/samsung/exynos_tmu.c index d44d91d681d4..d2f1e62a4232 100644 --- a/drivers/thermal/samsung/exynos_tmu.c +++ b/drivers/thermal/samsung/exynos_tmu.c | |||
@@ -927,7 +927,10 @@ static int exynos_tmu_probe(struct platform_device *pdev) | |||
927 | /* Register the sensor with thermal management interface */ | 927 | /* Register the sensor with thermal management interface */ |
928 | ret = exynos_register_thermal(sensor_conf); | 928 | ret = exynos_register_thermal(sensor_conf); |
929 | if (ret) { | 929 | if (ret) { |
930 | dev_err(&pdev->dev, "Failed to register thermal interface\n"); | 930 | if (ret != -EPROBE_DEFER) |
931 | dev_err(&pdev->dev, | ||
932 | "Failed to register thermal interface: %d\n", | ||
933 | ret); | ||
931 | goto err_clk; | 934 | goto err_clk; |
932 | } | 935 | } |
933 | data->reg_conf = sensor_conf; | 936 | data->reg_conf = sensor_conf; |
diff --git a/drivers/thermal/thermal_core.c b/drivers/thermal/thermal_core.c index 84fdf0792e27..87e0b0782023 100644 --- a/drivers/thermal/thermal_core.c +++ b/drivers/thermal/thermal_core.c | |||
@@ -930,7 +930,7 @@ int thermal_zone_bind_cooling_device(struct thermal_zone_device *tz, | |||
930 | struct thermal_zone_device *pos1; | 930 | struct thermal_zone_device *pos1; |
931 | struct thermal_cooling_device *pos2; | 931 | struct thermal_cooling_device *pos2; |
932 | unsigned long max_state; | 932 | unsigned long max_state; |
933 | int result; | 933 | int result, ret; |
934 | 934 | ||
935 | if (trip >= tz->trips || (trip < 0 && trip != THERMAL_TRIPS_NONE)) | 935 | if (trip >= tz->trips || (trip < 0 && trip != THERMAL_TRIPS_NONE)) |
936 | return -EINVAL; | 936 | return -EINVAL; |
@@ -947,7 +947,9 @@ int thermal_zone_bind_cooling_device(struct thermal_zone_device *tz, | |||
947 | if (tz != pos1 || cdev != pos2) | 947 | if (tz != pos1 || cdev != pos2) |
948 | return -EINVAL; | 948 | return -EINVAL; |
949 | 949 | ||
950 | cdev->ops->get_max_state(cdev, &max_state); | 950 | ret = cdev->ops->get_max_state(cdev, &max_state); |
951 | if (ret) | ||
952 | return ret; | ||
951 | 953 | ||
952 | /* lower default 0, upper default max_state */ | 954 | /* lower default 0, upper default max_state */ |
953 | lower = lower == THERMAL_NO_LIMIT ? 0 : lower; | 955 | lower = lower == THERMAL_NO_LIMIT ? 0 : lower; |
diff --git a/drivers/thermal/ti-soc-thermal/ti-thermal-common.c b/drivers/thermal/ti-soc-thermal/ti-thermal-common.c index 5fd03865e396..3fb054a10f6a 100644 --- a/drivers/thermal/ti-soc-thermal/ti-thermal-common.c +++ b/drivers/thermal/ti-soc-thermal/ti-thermal-common.c | |||
@@ -28,7 +28,6 @@ | |||
28 | #include <linux/kernel.h> | 28 | #include <linux/kernel.h> |
29 | #include <linux/workqueue.h> | 29 | #include <linux/workqueue.h> |
30 | #include <linux/thermal.h> | 30 | #include <linux/thermal.h> |
31 | #include <linux/cpufreq.h> | ||
32 | #include <linux/cpumask.h> | 31 | #include <linux/cpumask.h> |
33 | #include <linux/cpu_cooling.h> | 32 | #include <linux/cpu_cooling.h> |
34 | #include <linux/of.h> | 33 | #include <linux/of.h> |
@@ -407,17 +406,17 @@ int ti_thermal_register_cpu_cooling(struct ti_bandgap *bgp, int id) | |||
407 | if (!data) | 406 | if (!data) |
408 | return -EINVAL; | 407 | return -EINVAL; |
409 | 408 | ||
410 | if (!cpufreq_get_current_driver()) { | ||
411 | dev_dbg(bgp->dev, "no cpufreq driver yet\n"); | ||
412 | return -EPROBE_DEFER; | ||
413 | } | ||
414 | |||
415 | /* Register cooling device */ | 409 | /* Register cooling device */ |
416 | data->cool_dev = cpufreq_cooling_register(cpu_present_mask); | 410 | data->cool_dev = cpufreq_cooling_register(cpu_present_mask); |
417 | if (IS_ERR(data->cool_dev)) { | 411 | if (IS_ERR(data->cool_dev)) { |
418 | dev_err(bgp->dev, | 412 | int ret = PTR_ERR(data->cool_dev); |
419 | "Failed to register cpufreq cooling device\n"); | 413 | |
420 | return PTR_ERR(data->cool_dev); | 414 | if (ret != -EPROBE_DEFER) |
415 | dev_err(bgp->dev, | ||
416 | "Failed to register cpu cooling device %d\n", | ||
417 | ret); | ||
418 | |||
419 | return ret; | ||
421 | } | 420 | } |
422 | ti_bandgap_set_sensor_data(bgp, id, data); | 421 | ti_bandgap_set_sensor_data(bgp, id, data); |
423 | 422 | ||