diff options
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/int340x_thermal/Makefile | 1 | ||||
-rw-r--r-- | drivers/thermal/int340x_thermal/acpi_thermal_rel.c | 8 | ||||
-rw-r--r-- | drivers/thermal/int340x_thermal/int3400_thermal.c | 1 | ||||
-rw-r--r-- | drivers/thermal/int340x_thermal/int3402_thermal.c | 1 | ||||
-rw-r--r-- | drivers/thermal/int340x_thermal/int3403_thermal.c | 4 | ||||
-rw-r--r-- | drivers/thermal/int340x_thermal/processor_thermal_device.c | 309 | ||||
-rw-r--r-- | drivers/thermal/intel_powerclamp.c | 1 | ||||
-rw-r--r-- | drivers/thermal/rockchip_thermal.c | 1 | ||||
-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 |
16 files changed, 491 insertions, 271 deletions
diff --git a/drivers/thermal/cpu_cooling.c b/drivers/thermal/cpu_cooling.c index 588185abeab0..f65f0d109fc8 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,26 +54,27 @@ | |||
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 | * @node: list_head to link all cpufreq_cooling_device together. | 60 | * @node: list_head to link all cpufreq_cooling_device together. |
43 | * | 61 | * |
44 | * This structure is required for keeping information of each | 62 | * This structure is required for keeping information of each registered |
45 | * cpufreq_cooling_device registered. In order to prevent corruption of this a | 63 | * cpufreq_cooling_device. |
46 | * mutex lock cooling_cpufreq_lock is used. | ||
47 | */ | 64 | */ |
48 | struct cpufreq_cooling_device { | 65 | struct cpufreq_cooling_device { |
49 | int id; | 66 | int id; |
50 | struct thermal_cooling_device *cool_dev; | 67 | struct thermal_cooling_device *cool_dev; |
51 | unsigned int cpufreq_state; | 68 | unsigned int cpufreq_state; |
52 | unsigned int cpufreq_val; | 69 | unsigned int cpufreq_val; |
70 | unsigned int max_level; | ||
71 | unsigned int *freq_table; /* In descending order */ | ||
53 | struct cpumask allowed_cpus; | 72 | struct cpumask allowed_cpus; |
54 | struct list_head node; | 73 | struct list_head node; |
55 | }; | 74 | }; |
56 | static DEFINE_IDR(cpufreq_idr); | 75 | static DEFINE_IDR(cpufreq_idr); |
57 | static DEFINE_MUTEX(cooling_cpufreq_lock); | 76 | static DEFINE_MUTEX(cooling_cpufreq_lock); |
58 | 77 | ||
59 | static unsigned int cpufreq_dev_count; | ||
60 | |||
61 | static LIST_HEAD(cpufreq_dev_list); | 78 | static LIST_HEAD(cpufreq_dev_list); |
62 | 79 | ||
63 | /** | 80 | /** |
@@ -99,120 +116,30 @@ static void release_idr(struct idr *idr, int id) | |||
99 | /* Below code defines functions to be used for cpufreq as cooling device */ | 116 | /* Below code defines functions to be used for cpufreq as cooling device */ |
100 | 117 | ||
101 | /** | 118 | /** |
102 | * is_cpufreq_valid - function to check frequency transitioning capability. | 119 | * get_level: Find the level for a particular frequency |
103 | * @cpu: cpu for which check is needed. | 120 | * @cpufreq_dev: cpufreq_dev for which the property is required |
121 | * @freq: Frequency | ||
104 | * | 122 | * |
105 | * This function will check the current state of the system if | 123 | * Return: level on success, THERMAL_CSTATE_INVALID on error. |
106 | * it is capable of changing the frequency for a given @cpu. | ||
107 | * | ||
108 | * Return: 0 if the system is not currently capable of changing | ||
109 | * the frequency of given cpu. !0 in case the frequency is changeable. | ||
110 | */ | 124 | */ |
111 | static int is_cpufreq_valid(int cpu) | 125 | static unsigned long get_level(struct cpufreq_cooling_device *cpufreq_dev, |
126 | unsigned int freq) | ||
112 | { | 127 | { |
113 | struct cpufreq_policy policy; | 128 | unsigned long level; |
114 | |||
115 | return !cpufreq_get_policy(&policy, cpu); | ||
116 | } | ||
117 | |||
118 | enum cpufreq_cooling_property { | ||
119 | GET_LEVEL, | ||
120 | GET_FREQ, | ||
121 | GET_MAXL, | ||
122 | }; | ||
123 | |||
124 | /** | ||
125 | * get_property - fetch a property of interest for a give cpu. | ||
126 | * @cpu: cpu for which the property is required | ||
127 | * @input: query parameter | ||
128 | * @output: query return | ||
129 | * @property: type of query (frequency, level, max level) | ||
130 | * | ||
131 | * This is the common function to | ||
132 | * 1. get maximum cpu cooling states | ||
133 | * 2. translate frequency to cooling state | ||
134 | * 3. translate cooling state to frequency | ||
135 | * Note that the code may be not in good shape | ||
136 | * but it is written in this way in order to: | ||
137 | * a) reduce duplicate code as most of the code can be shared. | ||
138 | * b) make sure the logic is consistent when translating between | ||
139 | * cooling states and frequencies. | ||
140 | * | ||
141 | * Return: 0 on success, -EINVAL when invalid parameters are passed. | ||
142 | */ | ||
143 | static int get_property(unsigned int cpu, unsigned long input, | ||
144 | unsigned int *output, | ||
145 | enum cpufreq_cooling_property property) | ||
146 | { | ||
147 | int i; | ||
148 | unsigned long max_level = 0, level = 0; | ||
149 | unsigned int freq = CPUFREQ_ENTRY_INVALID; | ||
150 | int descend = -1; | ||
151 | struct cpufreq_frequency_table *pos, *table = | ||
152 | cpufreq_frequency_get_table(cpu); | ||
153 | |||
154 | if (!output) | ||
155 | return -EINVAL; | ||
156 | |||
157 | if (!table) | ||
158 | return -EINVAL; | ||
159 | |||
160 | cpufreq_for_each_valid_entry(pos, table) { | ||
161 | /* ignore duplicate entry */ | ||
162 | if (freq == pos->frequency) | ||
163 | continue; | ||
164 | |||
165 | /* get the frequency order */ | ||
166 | if (freq != CPUFREQ_ENTRY_INVALID && descend == -1) | ||
167 | descend = freq > pos->frequency; | ||
168 | |||
169 | freq = pos->frequency; | ||
170 | max_level++; | ||
171 | } | ||
172 | |||
173 | /* No valid cpu frequency entry */ | ||
174 | if (max_level == 0) | ||
175 | return -EINVAL; | ||
176 | 129 | ||
177 | /* max_level is an index, not a counter */ | 130 | for (level = 0; level <= cpufreq_dev->max_level; level++) { |
178 | max_level--; | 131 | if (freq == cpufreq_dev->freq_table[level]) |
132 | return level; | ||
179 | 133 | ||
180 | /* get max level */ | 134 | if (freq > cpufreq_dev->freq_table[level]) |
181 | if (property == GET_MAXL) { | 135 | break; |
182 | *output = (unsigned int)max_level; | ||
183 | return 0; | ||
184 | } | 136 | } |
185 | 137 | ||
186 | if (property == GET_FREQ) | 138 | return THERMAL_CSTATE_INVALID; |
187 | level = descend ? input : (max_level - input); | ||
188 | |||
189 | i = 0; | ||
190 | cpufreq_for_each_valid_entry(pos, table) { | ||
191 | /* ignore duplicate entry */ | ||
192 | if (freq == pos->frequency) | ||
193 | continue; | ||
194 | |||
195 | /* now we have a valid frequency entry */ | ||
196 | freq = pos->frequency; | ||
197 | |||
198 | if (property == GET_LEVEL && (unsigned int)input == freq) { | ||
199 | /* get level by frequency */ | ||
200 | *output = descend ? i : (max_level - i); | ||
201 | return 0; | ||
202 | } | ||
203 | if (property == GET_FREQ && level == i) { | ||
204 | /* get frequency by level */ | ||
205 | *output = freq; | ||
206 | return 0; | ||
207 | } | ||
208 | i++; | ||
209 | } | ||
210 | |||
211 | return -EINVAL; | ||
212 | } | 139 | } |
213 | 140 | ||
214 | /** | 141 | /** |
215 | * cpufreq_cooling_get_level - for a give cpu, return the cooling level. | 142 | * cpufreq_cooling_get_level - for a given cpu, return the cooling level. |
216 | * @cpu: cpu for which the level is required | 143 | * @cpu: cpu for which the level is required |
217 | * @freq: the frequency of interest | 144 | * @freq: the frequency of interest |
218 | * | 145 | * |
@@ -224,77 +151,21 @@ static int get_property(unsigned int cpu, unsigned long input, | |||
224 | */ | 151 | */ |
225 | unsigned long cpufreq_cooling_get_level(unsigned int cpu, unsigned int freq) | 152 | unsigned long cpufreq_cooling_get_level(unsigned int cpu, unsigned int freq) |
226 | { | 153 | { |
227 | unsigned int val; | 154 | struct cpufreq_cooling_device *cpufreq_dev; |
228 | |||
229 | if (get_property(cpu, (unsigned long)freq, &val, GET_LEVEL)) | ||
230 | return THERMAL_CSTATE_INVALID; | ||
231 | |||
232 | return (unsigned long)val; | ||
233 | } | ||
234 | EXPORT_SYMBOL_GPL(cpufreq_cooling_get_level); | ||
235 | |||
236 | /** | ||
237 | * get_cpu_frequency - get the absolute value of frequency from level. | ||
238 | * @cpu: cpu for which frequency is fetched. | ||
239 | * @level: cooling level | ||
240 | * | ||
241 | * This function matches cooling level with frequency. Based on a cooling level | ||
242 | * of frequency, equals cooling state of cpu cooling device, it will return | ||
243 | * the corresponding frequency. | ||
244 | * e.g level=0 --> 1st MAX FREQ, level=1 ---> 2nd MAX FREQ, .... etc | ||
245 | * | ||
246 | * Return: 0 on error, the corresponding frequency otherwise. | ||
247 | */ | ||
248 | static unsigned int get_cpu_frequency(unsigned int cpu, unsigned long level) | ||
249 | { | ||
250 | int ret = 0; | ||
251 | unsigned int freq; | ||
252 | |||
253 | ret = get_property(cpu, level, &freq, GET_FREQ); | ||
254 | if (ret) | ||
255 | return 0; | ||
256 | |||
257 | return freq; | ||
258 | } | ||
259 | |||
260 | /** | ||
261 | * cpufreq_apply_cooling - function to apply frequency clipping. | ||
262 | * @cpufreq_device: cpufreq_cooling_device pointer containing frequency | ||
263 | * clipping data. | ||
264 | * @cooling_state: value of the cooling state. | ||
265 | * | ||
266 | * Function used to make sure the cpufreq layer is aware of current thermal | ||
267 | * limits. The limits are applied by updating the cpufreq policy. | ||
268 | * | ||
269 | * Return: 0 on success, an error code otherwise (-EINVAL in case wrong | ||
270 | * cooling state). | ||
271 | */ | ||
272 | static int cpufreq_apply_cooling(struct cpufreq_cooling_device *cpufreq_device, | ||
273 | unsigned long cooling_state) | ||
274 | { | ||
275 | unsigned int cpuid, clip_freq; | ||
276 | struct cpumask *mask = &cpufreq_device->allowed_cpus; | ||
277 | unsigned int cpu = cpumask_any(mask); | ||
278 | |||
279 | |||
280 | /* Check if the old cooling action is same as new cooling action */ | ||
281 | if (cpufreq_device->cpufreq_state == cooling_state) | ||
282 | return 0; | ||
283 | |||
284 | clip_freq = get_cpu_frequency(cpu, cooling_state); | ||
285 | if (!clip_freq) | ||
286 | return -EINVAL; | ||
287 | |||
288 | cpufreq_device->cpufreq_state = cooling_state; | ||
289 | cpufreq_device->cpufreq_val = clip_freq; | ||
290 | 155 | ||
291 | for_each_cpu(cpuid, mask) { | 156 | mutex_lock(&cooling_cpufreq_lock); |
292 | if (is_cpufreq_valid(cpuid)) | 157 | list_for_each_entry(cpufreq_dev, &cpufreq_dev_list, node) { |
293 | cpufreq_update_policy(cpuid); | 158 | if (cpumask_test_cpu(cpu, &cpufreq_dev->allowed_cpus)) { |
159 | mutex_unlock(&cooling_cpufreq_lock); | ||
160 | return get_level(cpufreq_dev, freq); | ||
161 | } | ||
294 | } | 162 | } |
163 | mutex_unlock(&cooling_cpufreq_lock); | ||
295 | 164 | ||
296 | return 0; | 165 | pr_err("%s: cpu:%d not part of any cooling device\n", __func__, cpu); |
166 | return THERMAL_CSTATE_INVALID; | ||
297 | } | 167 | } |
168 | EXPORT_SYMBOL_GPL(cpufreq_cooling_get_level); | ||
298 | 169 | ||
299 | /** | 170 | /** |
300 | * cpufreq_thermal_notifier - notifier callback for cpufreq policy change. | 171 | * cpufreq_thermal_notifier - notifier callback for cpufreq policy change. |
@@ -324,11 +195,6 @@ static int cpufreq_thermal_notifier(struct notifier_block *nb, | |||
324 | &cpufreq_dev->allowed_cpus)) | 195 | &cpufreq_dev->allowed_cpus)) |
325 | continue; | 196 | continue; |
326 | 197 | ||
327 | if (!cpufreq_dev->cpufreq_val) | ||
328 | cpufreq_dev->cpufreq_val = get_cpu_frequency( | ||
329 | cpumask_any(&cpufreq_dev->allowed_cpus), | ||
330 | cpufreq_dev->cpufreq_state); | ||
331 | |||
332 | max_freq = cpufreq_dev->cpufreq_val; | 198 | max_freq = cpufreq_dev->cpufreq_val; |
333 | 199 | ||
334 | if (policy->max != max_freq) | 200 | if (policy->max != max_freq) |
@@ -355,19 +221,9 @@ static int cpufreq_get_max_state(struct thermal_cooling_device *cdev, | |||
355 | unsigned long *state) | 221 | unsigned long *state) |
356 | { | 222 | { |
357 | struct cpufreq_cooling_device *cpufreq_device = cdev->devdata; | 223 | struct cpufreq_cooling_device *cpufreq_device = cdev->devdata; |
358 | struct cpumask *mask = &cpufreq_device->allowed_cpus; | ||
359 | unsigned int cpu; | ||
360 | unsigned int count = 0; | ||
361 | int ret; | ||
362 | |||
363 | cpu = cpumask_any(mask); | ||
364 | |||
365 | ret = get_property(cpu, 0, &count, GET_MAXL); | ||
366 | 224 | ||
367 | if (count > 0) | 225 | *state = cpufreq_device->max_level; |
368 | *state = count; | 226 | return 0; |
369 | |||
370 | return ret; | ||
371 | } | 227 | } |
372 | 228 | ||
373 | /** | 229 | /** |
@@ -404,8 +260,24 @@ static int cpufreq_set_cur_state(struct thermal_cooling_device *cdev, | |||
404 | unsigned long state) | 260 | unsigned long state) |
405 | { | 261 | { |
406 | struct cpufreq_cooling_device *cpufreq_device = cdev->devdata; | 262 | struct cpufreq_cooling_device *cpufreq_device = cdev->devdata; |
263 | unsigned int cpu = cpumask_any(&cpufreq_device->allowed_cpus); | ||
264 | unsigned int clip_freq; | ||
265 | |||
266 | /* Request state should be less than max_level */ | ||
267 | if (WARN_ON(state > cpufreq_device->max_level)) | ||
268 | return -EINVAL; | ||
269 | |||
270 | /* Check if the old cooling action is same as new cooling action */ | ||
271 | if (cpufreq_device->cpufreq_state == state) | ||
272 | return 0; | ||
407 | 273 | ||
408 | return cpufreq_apply_cooling(cpufreq_device, state); | 274 | clip_freq = cpufreq_device->freq_table[state]; |
275 | cpufreq_device->cpufreq_state = state; | ||
276 | cpufreq_device->cpufreq_val = clip_freq; | ||
277 | |||
278 | cpufreq_update_policy(cpu); | ||
279 | |||
280 | return 0; | ||
409 | } | 281 | } |
410 | 282 | ||
411 | /* Bind cpufreq callbacks to thermal cooling device ops */ | 283 | /* Bind cpufreq callbacks to thermal cooling device ops */ |
@@ -420,10 +292,25 @@ static struct notifier_block thermal_cpufreq_notifier_block = { | |||
420 | .notifier_call = cpufreq_thermal_notifier, | 292 | .notifier_call = cpufreq_thermal_notifier, |
421 | }; | 293 | }; |
422 | 294 | ||
295 | static unsigned int find_next_max(struct cpufreq_frequency_table *table, | ||
296 | unsigned int prev_max) | ||
297 | { | ||
298 | struct cpufreq_frequency_table *pos; | ||
299 | unsigned int max = 0; | ||
300 | |||
301 | cpufreq_for_each_valid_entry(pos, table) { | ||
302 | if (pos->frequency > max && pos->frequency < prev_max) | ||
303 | max = pos->frequency; | ||
304 | } | ||
305 | |||
306 | return max; | ||
307 | } | ||
308 | |||
423 | /** | 309 | /** |
424 | * __cpufreq_cooling_register - helper function to create cpufreq cooling device | 310 | * __cpufreq_cooling_register - helper function to create cpufreq cooling device |
425 | * @np: a valid struct device_node to the cooling device device tree node | 311 | * @np: a valid struct device_node to the cooling device device tree node |
426 | * @clip_cpus: cpumask of cpus where the frequency constraints will happen. | 312 | * @clip_cpus: cpumask of cpus where the frequency constraints will happen. |
313 | * Normally this should be same as cpufreq policy->related_cpus. | ||
427 | * | 314 | * |
428 | * This interface function registers the cpufreq cooling device with the name | 315 | * This interface function registers the cpufreq cooling device with the name |
429 | * "thermal-cpufreq-%x". This api can support multiple instances of cpufreq | 316 | * "thermal-cpufreq-%x". This api can support multiple instances of cpufreq |
@@ -438,37 +325,42 @@ __cpufreq_cooling_register(struct device_node *np, | |||
438 | const struct cpumask *clip_cpus) | 325 | const struct cpumask *clip_cpus) |
439 | { | 326 | { |
440 | struct thermal_cooling_device *cool_dev; | 327 | struct thermal_cooling_device *cool_dev; |
441 | struct cpufreq_cooling_device *cpufreq_dev = NULL; | 328 | struct cpufreq_cooling_device *cpufreq_dev; |
442 | unsigned int min = 0, max = 0; | ||
443 | char dev_name[THERMAL_NAME_LENGTH]; | 329 | char dev_name[THERMAL_NAME_LENGTH]; |
444 | int ret = 0, i; | 330 | struct cpufreq_frequency_table *pos, *table; |
445 | struct cpufreq_policy policy; | 331 | unsigned int freq, i; |
332 | int ret; | ||
446 | 333 | ||
447 | /* Verify that all the clip cpus have same freq_min, freq_max limit */ | 334 | table = cpufreq_frequency_get_table(cpumask_first(clip_cpus)); |
448 | for_each_cpu(i, clip_cpus) { | 335 | if (!table) { |
449 | /* continue if cpufreq policy not found and not return error */ | 336 | pr_debug("%s: CPUFreq table not found\n", __func__); |
450 | if (!cpufreq_get_policy(&policy, i)) | 337 | return ERR_PTR(-EPROBE_DEFER); |
451 | continue; | ||
452 | if (min == 0 && max == 0) { | ||
453 | min = policy.cpuinfo.min_freq; | ||
454 | max = policy.cpuinfo.max_freq; | ||
455 | } else { | ||
456 | if (min != policy.cpuinfo.min_freq || | ||
457 | max != policy.cpuinfo.max_freq) | ||
458 | return ERR_PTR(-EINVAL); | ||
459 | } | ||
460 | } | 338 | } |
461 | cpufreq_dev = kzalloc(sizeof(struct cpufreq_cooling_device), | 339 | |
462 | GFP_KERNEL); | 340 | cpufreq_dev = kzalloc(sizeof(*cpufreq_dev), GFP_KERNEL); |
463 | if (!cpufreq_dev) | 341 | if (!cpufreq_dev) |
464 | return ERR_PTR(-ENOMEM); | 342 | return ERR_PTR(-ENOMEM); |
465 | 343 | ||
344 | /* Find max levels */ | ||
345 | cpufreq_for_each_valid_entry(pos, table) | ||
346 | cpufreq_dev->max_level++; | ||
347 | |||
348 | cpufreq_dev->freq_table = kmalloc(sizeof(*cpufreq_dev->freq_table) * | ||
349 | cpufreq_dev->max_level, GFP_KERNEL); | ||
350 | if (!cpufreq_dev->freq_table) { | ||
351 | cool_dev = ERR_PTR(-ENOMEM); | ||
352 | goto free_cdev; | ||
353 | } | ||
354 | |||
355 | /* max_level is an index, not a counter */ | ||
356 | cpufreq_dev->max_level--; | ||
357 | |||
466 | cpumask_copy(&cpufreq_dev->allowed_cpus, clip_cpus); | 358 | cpumask_copy(&cpufreq_dev->allowed_cpus, clip_cpus); |
467 | 359 | ||
468 | ret = get_idr(&cpufreq_idr, &cpufreq_dev->id); | 360 | ret = get_idr(&cpufreq_idr, &cpufreq_dev->id); |
469 | if (ret) { | 361 | if (ret) { |
470 | kfree(cpufreq_dev); | 362 | cool_dev = ERR_PTR(ret); |
471 | return ERR_PTR(-EINVAL); | 363 | goto free_table; |
472 | } | 364 | } |
473 | 365 | ||
474 | snprintf(dev_name, sizeof(dev_name), "thermal-cpufreq-%d", | 366 | snprintf(dev_name, sizeof(dev_name), "thermal-cpufreq-%d", |
@@ -476,25 +368,44 @@ __cpufreq_cooling_register(struct device_node *np, | |||
476 | 368 | ||
477 | cool_dev = thermal_of_cooling_device_register(np, dev_name, cpufreq_dev, | 369 | cool_dev = thermal_of_cooling_device_register(np, dev_name, cpufreq_dev, |
478 | &cpufreq_cooling_ops); | 370 | &cpufreq_cooling_ops); |
479 | if (IS_ERR(cool_dev)) { | 371 | if (IS_ERR(cool_dev)) |
480 | release_idr(&cpufreq_idr, cpufreq_dev->id); | 372 | goto remove_idr; |
481 | kfree(cpufreq_dev); | 373 | |
482 | return cool_dev; | 374 | /* Fill freq-table in descending order of frequencies */ |
375 | for (i = 0, freq = -1; i <= cpufreq_dev->max_level; i++) { | ||
376 | freq = find_next_max(table, freq); | ||
377 | cpufreq_dev->freq_table[i] = freq; | ||
378 | |||
379 | /* Warn for duplicate entries */ | ||
380 | if (!freq) | ||
381 | pr_warn("%s: table has duplicate entries\n", __func__); | ||
382 | else | ||
383 | pr_debug("%s: freq:%u KHz\n", __func__, freq); | ||
483 | } | 384 | } |
385 | |||
386 | cpufreq_dev->cpufreq_val = cpufreq_dev->freq_table[0]; | ||
484 | cpufreq_dev->cool_dev = cool_dev; | 387 | cpufreq_dev->cool_dev = cool_dev; |
485 | cpufreq_dev->cpufreq_state = 0; | 388 | |
486 | mutex_lock(&cooling_cpufreq_lock); | 389 | mutex_lock(&cooling_cpufreq_lock); |
487 | 390 | ||
488 | /* Register the notifier for first cpufreq cooling device */ | 391 | /* Register the notifier for first cpufreq cooling device */ |
489 | if (cpufreq_dev_count == 0) | 392 | if (list_empty(&cpufreq_dev_list)) |
490 | cpufreq_register_notifier(&thermal_cpufreq_notifier_block, | 393 | cpufreq_register_notifier(&thermal_cpufreq_notifier_block, |
491 | CPUFREQ_POLICY_NOTIFIER); | 394 | CPUFREQ_POLICY_NOTIFIER); |
492 | cpufreq_dev_count++; | ||
493 | list_add(&cpufreq_dev->node, &cpufreq_dev_list); | 395 | list_add(&cpufreq_dev->node, &cpufreq_dev_list); |
494 | 396 | ||
495 | mutex_unlock(&cooling_cpufreq_lock); | 397 | mutex_unlock(&cooling_cpufreq_lock); |
496 | 398 | ||
497 | return cool_dev; | 399 | return cool_dev; |
400 | |||
401 | remove_idr: | ||
402 | release_idr(&cpufreq_idr, cpufreq_dev->id); | ||
403 | free_table: | ||
404 | kfree(cpufreq_dev->freq_table); | ||
405 | free_cdev: | ||
406 | kfree(cpufreq_dev); | ||
407 | |||
408 | return cool_dev; | ||
498 | } | 409 | } |
499 | 410 | ||
500 | /** | 411 | /** |
@@ -555,16 +466,16 @@ void cpufreq_cooling_unregister(struct thermal_cooling_device *cdev) | |||
555 | cpufreq_dev = cdev->devdata; | 466 | cpufreq_dev = cdev->devdata; |
556 | mutex_lock(&cooling_cpufreq_lock); | 467 | mutex_lock(&cooling_cpufreq_lock); |
557 | list_del(&cpufreq_dev->node); | 468 | list_del(&cpufreq_dev->node); |
558 | cpufreq_dev_count--; | ||
559 | 469 | ||
560 | /* Unregister the notifier for the last cpufreq cooling device */ | 470 | /* Unregister the notifier for the last cpufreq cooling device */ |
561 | if (cpufreq_dev_count == 0) | 471 | if (list_empty(&cpufreq_dev_list)) |
562 | cpufreq_unregister_notifier(&thermal_cpufreq_notifier_block, | 472 | cpufreq_unregister_notifier(&thermal_cpufreq_notifier_block, |
563 | CPUFREQ_POLICY_NOTIFIER); | 473 | CPUFREQ_POLICY_NOTIFIER); |
564 | mutex_unlock(&cooling_cpufreq_lock); | 474 | mutex_unlock(&cooling_cpufreq_lock); |
565 | 475 | ||
566 | thermal_cooling_device_unregister(cpufreq_dev->cool_dev); | 476 | thermal_cooling_device_unregister(cpufreq_dev->cool_dev); |
567 | release_idr(&cpufreq_idr, cpufreq_dev->id); | 477 | release_idr(&cpufreq_idr, cpufreq_dev->id); |
478 | kfree(cpufreq_dev->freq_table); | ||
568 | kfree(cpufreq_dev); | 479 | kfree(cpufreq_dev); |
569 | } | 480 | } |
570 | EXPORT_SYMBOL_GPL(cpufreq_cooling_unregister); | 481 | 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/int340x_thermal/Makefile b/drivers/thermal/int340x_thermal/Makefile index ffe40bffaf1a..d4413698a85f 100644 --- a/drivers/thermal/int340x_thermal/Makefile +++ b/drivers/thermal/int340x_thermal/Makefile | |||
@@ -1,4 +1,5 @@ | |||
1 | obj-$(CONFIG_INT340X_THERMAL) += int3400_thermal.o | 1 | obj-$(CONFIG_INT340X_THERMAL) += int3400_thermal.o |
2 | obj-$(CONFIG_INT340X_THERMAL) += int3402_thermal.o | 2 | obj-$(CONFIG_INT340X_THERMAL) += int3402_thermal.o |
3 | obj-$(CONFIG_INT340X_THERMAL) += int3403_thermal.o | 3 | obj-$(CONFIG_INT340X_THERMAL) += int3403_thermal.o |
4 | obj-$(CONFIG_INT340X_THERMAL) += processor_thermal_device.o | ||
4 | obj-$(CONFIG_ACPI_THERMAL_REL) += acpi_thermal_rel.o | 5 | obj-$(CONFIG_ACPI_THERMAL_REL) += acpi_thermal_rel.o |
diff --git a/drivers/thermal/int340x_thermal/acpi_thermal_rel.c b/drivers/thermal/int340x_thermal/acpi_thermal_rel.c index e4e61b3fb11e..231cabc16e16 100644 --- a/drivers/thermal/int340x_thermal/acpi_thermal_rel.c +++ b/drivers/thermal/int340x_thermal/acpi_thermal_rel.c | |||
@@ -82,7 +82,7 @@ int acpi_parse_trt(acpi_handle handle, int *trt_count, struct trt **trtp, | |||
82 | struct acpi_buffer trt_format = { sizeof("RRNNNNNN"), "RRNNNNNN" }; | 82 | struct acpi_buffer trt_format = { sizeof("RRNNNNNN"), "RRNNNNNN" }; |
83 | 83 | ||
84 | if (!acpi_has_method(handle, "_TRT")) | 84 | if (!acpi_has_method(handle, "_TRT")) |
85 | return 0; | 85 | return -ENODEV; |
86 | 86 | ||
87 | status = acpi_evaluate_object(handle, "_TRT", NULL, &buffer); | 87 | status = acpi_evaluate_object(handle, "_TRT", NULL, &buffer); |
88 | if (ACPI_FAILURE(status)) | 88 | if (ACPI_FAILURE(status)) |
@@ -167,7 +167,7 @@ int acpi_parse_art(acpi_handle handle, int *art_count, struct art **artp, | |||
167 | sizeof("RRNNNNNNNNNNN"), "RRNNNNNNNNNNN" }; | 167 | sizeof("RRNNNNNNNNNNN"), "RRNNNNNNNNNNN" }; |
168 | 168 | ||
169 | if (!acpi_has_method(handle, "_ART")) | 169 | if (!acpi_has_method(handle, "_ART")) |
170 | return 0; | 170 | return -ENODEV; |
171 | 171 | ||
172 | status = acpi_evaluate_object(handle, "_ART", NULL, &buffer); | 172 | status = acpi_evaluate_object(handle, "_ART", NULL, &buffer); |
173 | if (ACPI_FAILURE(status)) | 173 | if (ACPI_FAILURE(status)) |
@@ -321,8 +321,8 @@ static long acpi_thermal_rel_ioctl(struct file *f, unsigned int cmd, | |||
321 | unsigned long length = 0; | 321 | unsigned long length = 0; |
322 | int count = 0; | 322 | int count = 0; |
323 | char __user *arg = (void __user *)__arg; | 323 | char __user *arg = (void __user *)__arg; |
324 | struct trt *trts; | 324 | struct trt *trts = NULL; |
325 | struct art *arts; | 325 | struct art *arts = NULL; |
326 | 326 | ||
327 | switch (cmd) { | 327 | switch (cmd) { |
328 | case ACPI_THERMAL_GET_TRT_COUNT: | 328 | case ACPI_THERMAL_GET_TRT_COUNT: |
diff --git a/drivers/thermal/int340x_thermal/int3400_thermal.c b/drivers/thermal/int340x_thermal/int3400_thermal.c index dcb306ea14a4..65a98a97df07 100644 --- a/drivers/thermal/int340x_thermal/int3400_thermal.c +++ b/drivers/thermal/int340x_thermal/int3400_thermal.c | |||
@@ -335,7 +335,6 @@ static struct platform_driver int3400_thermal_driver = { | |||
335 | .remove = int3400_thermal_remove, | 335 | .remove = int3400_thermal_remove, |
336 | .driver = { | 336 | .driver = { |
337 | .name = "int3400 thermal", | 337 | .name = "int3400 thermal", |
338 | .owner = THIS_MODULE, | ||
339 | .acpi_match_table = ACPI_PTR(int3400_thermal_match), | 338 | .acpi_match_table = ACPI_PTR(int3400_thermal_match), |
340 | }, | 339 | }, |
341 | }; | 340 | }; |
diff --git a/drivers/thermal/int340x_thermal/int3402_thermal.c b/drivers/thermal/int340x_thermal/int3402_thermal.c index a5d08c14ba24..c5cbc3af3a05 100644 --- a/drivers/thermal/int340x_thermal/int3402_thermal.c +++ b/drivers/thermal/int340x_thermal/int3402_thermal.c | |||
@@ -231,7 +231,6 @@ static struct platform_driver int3402_thermal_driver = { | |||
231 | .remove = int3402_thermal_remove, | 231 | .remove = int3402_thermal_remove, |
232 | .driver = { | 232 | .driver = { |
233 | .name = "int3402 thermal", | 233 | .name = "int3402 thermal", |
234 | .owner = THIS_MODULE, | ||
235 | .acpi_match_table = int3402_thermal_match, | 234 | .acpi_match_table = int3402_thermal_match, |
236 | }, | 235 | }, |
237 | }; | 236 | }; |
diff --git a/drivers/thermal/int340x_thermal/int3403_thermal.c b/drivers/thermal/int340x_thermal/int3403_thermal.c index 1bfa6a69e77a..0faf500d8a77 100644 --- a/drivers/thermal/int340x_thermal/int3403_thermal.c +++ b/drivers/thermal/int340x_thermal/int3403_thermal.c | |||
@@ -301,6 +301,8 @@ static int int3403_sensor_remove(struct int3403_priv *priv) | |||
301 | { | 301 | { |
302 | struct int3403_sensor *obj = priv->priv; | 302 | struct int3403_sensor *obj = priv->priv; |
303 | 303 | ||
304 | acpi_remove_notify_handler(priv->adev->handle, | ||
305 | ACPI_DEVICE_NOTIFY, int3403_notify); | ||
304 | thermal_zone_device_unregister(obj->tzone); | 306 | thermal_zone_device_unregister(obj->tzone); |
305 | return 0; | 307 | return 0; |
306 | } | 308 | } |
@@ -369,6 +371,7 @@ static int int3403_cdev_add(struct int3403_priv *priv) | |||
369 | p = buf.pointer; | 371 | p = buf.pointer; |
370 | if (!p || (p->type != ACPI_TYPE_PACKAGE)) { | 372 | if (!p || (p->type != ACPI_TYPE_PACKAGE)) { |
371 | printk(KERN_WARNING "Invalid PPSS data\n"); | 373 | printk(KERN_WARNING "Invalid PPSS data\n"); |
374 | kfree(buf.pointer); | ||
372 | return -EFAULT; | 375 | return -EFAULT; |
373 | } | 376 | } |
374 | 377 | ||
@@ -381,6 +384,7 @@ static int int3403_cdev_add(struct int3403_priv *priv) | |||
381 | 384 | ||
382 | priv->priv = obj; | 385 | priv->priv = obj; |
383 | 386 | ||
387 | kfree(buf.pointer); | ||
384 | /* TODO: add ACPI notification support */ | 388 | /* TODO: add ACPI notification support */ |
385 | 389 | ||
386 | return result; | 390 | return result; |
diff --git a/drivers/thermal/int340x_thermal/processor_thermal_device.c b/drivers/thermal/int340x_thermal/processor_thermal_device.c new file mode 100644 index 000000000000..31bb553aac26 --- /dev/null +++ b/drivers/thermal/int340x_thermal/processor_thermal_device.c | |||
@@ -0,0 +1,309 @@ | |||
1 | /* | ||
2 | * processor_thermal_device.c | ||
3 | * Copyright (c) 2014, Intel Corporation. | ||
4 | * | ||
5 | * This program is free software; you can redistribute it and/or modify it | ||
6 | * under the terms and conditions of the GNU General Public License, | ||
7 | * version 2, as published by the Free Software Foundation. | ||
8 | * | ||
9 | * This program is distributed in the hope it will be useful, but WITHOUT | ||
10 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | ||
11 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | ||
12 | * more details. | ||
13 | * | ||
14 | */ | ||
15 | #include <linux/kernel.h> | ||
16 | #include <linux/module.h> | ||
17 | #include <linux/init.h> | ||
18 | #include <linux/pci.h> | ||
19 | #include <linux/platform_device.h> | ||
20 | #include <linux/acpi.h> | ||
21 | |||
22 | /* Broadwell-U/HSB thermal reporting device */ | ||
23 | #define PCI_DEVICE_ID_PROC_BDW_THERMAL 0x1603 | ||
24 | #define PCI_DEVICE_ID_PROC_HSB_THERMAL 0x0A03 | ||
25 | |||
26 | /* Braswell thermal reporting device */ | ||
27 | #define PCI_DEVICE_ID_PROC_BSW_THERMAL 0x22DC | ||
28 | |||
29 | struct power_config { | ||
30 | u32 index; | ||
31 | u32 min_uw; | ||
32 | u32 max_uw; | ||
33 | u32 tmin_us; | ||
34 | u32 tmax_us; | ||
35 | u32 step_uw; | ||
36 | }; | ||
37 | |||
38 | struct proc_thermal_device { | ||
39 | struct device *dev; | ||
40 | struct acpi_device *adev; | ||
41 | struct power_config power_limits[2]; | ||
42 | }; | ||
43 | |||
44 | enum proc_thermal_emum_mode_type { | ||
45 | PROC_THERMAL_NONE, | ||
46 | PROC_THERMAL_PCI, | ||
47 | PROC_THERMAL_PLATFORM_DEV | ||
48 | }; | ||
49 | |||
50 | /* | ||
51 | * We can have only one type of enumeration, PCI or Platform, | ||
52 | * not both. So we don't need instance specific data. | ||
53 | */ | ||
54 | static enum proc_thermal_emum_mode_type proc_thermal_emum_mode = | ||
55 | PROC_THERMAL_NONE; | ||
56 | |||
57 | #define POWER_LIMIT_SHOW(index, suffix) \ | ||
58 | static ssize_t power_limit_##index##_##suffix##_show(struct device *dev, \ | ||
59 | struct device_attribute *attr, \ | ||
60 | char *buf) \ | ||
61 | { \ | ||
62 | struct pci_dev *pci_dev; \ | ||
63 | struct platform_device *pdev; \ | ||
64 | struct proc_thermal_device *proc_dev; \ | ||
65 | \ | ||
66 | if (proc_thermal_emum_mode == PROC_THERMAL_PLATFORM_DEV) { \ | ||
67 | pdev = to_platform_device(dev); \ | ||
68 | proc_dev = platform_get_drvdata(pdev); \ | ||
69 | } else { \ | ||
70 | pci_dev = to_pci_dev(dev); \ | ||
71 | proc_dev = pci_get_drvdata(pci_dev); \ | ||
72 | } \ | ||
73 | return sprintf(buf, "%lu\n",\ | ||
74 | (unsigned long)proc_dev->power_limits[index].suffix * 1000); \ | ||
75 | } | ||
76 | |||
77 | POWER_LIMIT_SHOW(0, min_uw) | ||
78 | POWER_LIMIT_SHOW(0, max_uw) | ||
79 | POWER_LIMIT_SHOW(0, step_uw) | ||
80 | POWER_LIMIT_SHOW(0, tmin_us) | ||
81 | POWER_LIMIT_SHOW(0, tmax_us) | ||
82 | |||
83 | POWER_LIMIT_SHOW(1, min_uw) | ||
84 | POWER_LIMIT_SHOW(1, max_uw) | ||
85 | POWER_LIMIT_SHOW(1, step_uw) | ||
86 | POWER_LIMIT_SHOW(1, tmin_us) | ||
87 | POWER_LIMIT_SHOW(1, tmax_us) | ||
88 | |||
89 | static DEVICE_ATTR_RO(power_limit_0_min_uw); | ||
90 | static DEVICE_ATTR_RO(power_limit_0_max_uw); | ||
91 | static DEVICE_ATTR_RO(power_limit_0_step_uw); | ||
92 | static DEVICE_ATTR_RO(power_limit_0_tmin_us); | ||
93 | static DEVICE_ATTR_RO(power_limit_0_tmax_us); | ||
94 | |||
95 | static DEVICE_ATTR_RO(power_limit_1_min_uw); | ||
96 | static DEVICE_ATTR_RO(power_limit_1_max_uw); | ||
97 | static DEVICE_ATTR_RO(power_limit_1_step_uw); | ||
98 | static DEVICE_ATTR_RO(power_limit_1_tmin_us); | ||
99 | static DEVICE_ATTR_RO(power_limit_1_tmax_us); | ||
100 | |||
101 | static struct attribute *power_limit_attrs[] = { | ||
102 | &dev_attr_power_limit_0_min_uw.attr, | ||
103 | &dev_attr_power_limit_1_min_uw.attr, | ||
104 | &dev_attr_power_limit_0_max_uw.attr, | ||
105 | &dev_attr_power_limit_1_max_uw.attr, | ||
106 | &dev_attr_power_limit_0_step_uw.attr, | ||
107 | &dev_attr_power_limit_1_step_uw.attr, | ||
108 | &dev_attr_power_limit_0_tmin_us.attr, | ||
109 | &dev_attr_power_limit_1_tmin_us.attr, | ||
110 | &dev_attr_power_limit_0_tmax_us.attr, | ||
111 | &dev_attr_power_limit_1_tmax_us.attr, | ||
112 | NULL | ||
113 | }; | ||
114 | |||
115 | static struct attribute_group power_limit_attribute_group = { | ||
116 | .attrs = power_limit_attrs, | ||
117 | .name = "power_limits" | ||
118 | }; | ||
119 | |||
120 | static int proc_thermal_add(struct device *dev, | ||
121 | struct proc_thermal_device **priv) | ||
122 | { | ||
123 | struct proc_thermal_device *proc_priv; | ||
124 | struct acpi_device *adev; | ||
125 | acpi_status status; | ||
126 | struct acpi_buffer buf = { ACPI_ALLOCATE_BUFFER, NULL }; | ||
127 | union acpi_object *elements, *ppcc; | ||
128 | union acpi_object *p; | ||
129 | int i; | ||
130 | int ret; | ||
131 | |||
132 | adev = ACPI_COMPANION(dev); | ||
133 | |||
134 | status = acpi_evaluate_object(adev->handle, "PPCC", NULL, &buf); | ||
135 | if (ACPI_FAILURE(status)) | ||
136 | return -ENODEV; | ||
137 | |||
138 | p = buf.pointer; | ||
139 | if (!p || (p->type != ACPI_TYPE_PACKAGE)) { | ||
140 | dev_err(dev, "Invalid PPCC data\n"); | ||
141 | ret = -EFAULT; | ||
142 | goto free_buffer; | ||
143 | } | ||
144 | if (!p->package.count) { | ||
145 | dev_err(dev, "Invalid PPCC package size\n"); | ||
146 | ret = -EFAULT; | ||
147 | goto free_buffer; | ||
148 | } | ||
149 | |||
150 | proc_priv = devm_kzalloc(dev, sizeof(*proc_priv), GFP_KERNEL); | ||
151 | if (!proc_priv) { | ||
152 | ret = -ENOMEM; | ||
153 | goto free_buffer; | ||
154 | } | ||
155 | |||
156 | proc_priv->dev = dev; | ||
157 | proc_priv->adev = adev; | ||
158 | |||
159 | for (i = 0; i < min((int)p->package.count - 1, 2); ++i) { | ||
160 | elements = &(p->package.elements[i+1]); | ||
161 | if (elements->type != ACPI_TYPE_PACKAGE || | ||
162 | elements->package.count != 6) { | ||
163 | ret = -EFAULT; | ||
164 | goto free_buffer; | ||
165 | } | ||
166 | ppcc = elements->package.elements; | ||
167 | proc_priv->power_limits[i].index = ppcc[0].integer.value; | ||
168 | proc_priv->power_limits[i].min_uw = ppcc[1].integer.value; | ||
169 | proc_priv->power_limits[i].max_uw = ppcc[2].integer.value; | ||
170 | proc_priv->power_limits[i].tmin_us = ppcc[3].integer.value; | ||
171 | proc_priv->power_limits[i].tmax_us = ppcc[4].integer.value; | ||
172 | proc_priv->power_limits[i].step_uw = ppcc[5].integer.value; | ||
173 | } | ||
174 | |||
175 | *priv = proc_priv; | ||
176 | |||
177 | ret = sysfs_create_group(&dev->kobj, | ||
178 | &power_limit_attribute_group); | ||
179 | |||
180 | free_buffer: | ||
181 | kfree(buf.pointer); | ||
182 | |||
183 | return ret; | ||
184 | } | ||
185 | |||
186 | void proc_thermal_remove(struct proc_thermal_device *proc_priv) | ||
187 | { | ||
188 | sysfs_remove_group(&proc_priv->dev->kobj, | ||
189 | &power_limit_attribute_group); | ||
190 | } | ||
191 | |||
192 | static int int3401_add(struct platform_device *pdev) | ||
193 | { | ||
194 | struct proc_thermal_device *proc_priv; | ||
195 | int ret; | ||
196 | |||
197 | if (proc_thermal_emum_mode == PROC_THERMAL_PCI) { | ||
198 | dev_err(&pdev->dev, "error: enumerated as PCI dev\n"); | ||
199 | return -ENODEV; | ||
200 | } | ||
201 | |||
202 | ret = proc_thermal_add(&pdev->dev, &proc_priv); | ||
203 | if (ret) | ||
204 | return ret; | ||
205 | |||
206 | platform_set_drvdata(pdev, proc_priv); | ||
207 | proc_thermal_emum_mode = PROC_THERMAL_PLATFORM_DEV; | ||
208 | |||
209 | return 0; | ||
210 | } | ||
211 | |||
212 | static int int3401_remove(struct platform_device *pdev) | ||
213 | { | ||
214 | proc_thermal_remove(platform_get_drvdata(pdev)); | ||
215 | |||
216 | return 0; | ||
217 | } | ||
218 | |||
219 | static int proc_thermal_pci_probe(struct pci_dev *pdev, | ||
220 | const struct pci_device_id *unused) | ||
221 | { | ||
222 | struct proc_thermal_device *proc_priv; | ||
223 | int ret; | ||
224 | |||
225 | if (proc_thermal_emum_mode == PROC_THERMAL_PLATFORM_DEV) { | ||
226 | dev_err(&pdev->dev, "error: enumerated as platform dev\n"); | ||
227 | return -ENODEV; | ||
228 | } | ||
229 | |||
230 | ret = pci_enable_device(pdev); | ||
231 | if (ret < 0) { | ||
232 | dev_err(&pdev->dev, "error: could not enable device\n"); | ||
233 | return ret; | ||
234 | } | ||
235 | |||
236 | ret = proc_thermal_add(&pdev->dev, &proc_priv); | ||
237 | if (ret) { | ||
238 | pci_disable_device(pdev); | ||
239 | return ret; | ||
240 | } | ||
241 | |||
242 | pci_set_drvdata(pdev, proc_priv); | ||
243 | proc_thermal_emum_mode = PROC_THERMAL_PCI; | ||
244 | |||
245 | return 0; | ||
246 | } | ||
247 | |||
248 | static void proc_thermal_pci_remove(struct pci_dev *pdev) | ||
249 | { | ||
250 | proc_thermal_remove(pci_get_drvdata(pdev)); | ||
251 | pci_disable_device(pdev); | ||
252 | } | ||
253 | |||
254 | static const struct pci_device_id proc_thermal_pci_ids[] = { | ||
255 | { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_PROC_BDW_THERMAL)}, | ||
256 | { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_PROC_HSB_THERMAL)}, | ||
257 | { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_PROC_BSW_THERMAL)}, | ||
258 | { 0, }, | ||
259 | }; | ||
260 | |||
261 | MODULE_DEVICE_TABLE(pci, proc_thermal_pci_ids); | ||
262 | |||
263 | static struct pci_driver proc_thermal_pci_driver = { | ||
264 | .name = "proc_thermal", | ||
265 | .probe = proc_thermal_pci_probe, | ||
266 | .remove = proc_thermal_pci_remove, | ||
267 | .id_table = proc_thermal_pci_ids, | ||
268 | }; | ||
269 | |||
270 | static const struct acpi_device_id int3401_device_ids[] = { | ||
271 | {"INT3401", 0}, | ||
272 | {"", 0}, | ||
273 | }; | ||
274 | MODULE_DEVICE_TABLE(acpi, int3401_device_ids); | ||
275 | |||
276 | static struct platform_driver int3401_driver = { | ||
277 | .probe = int3401_add, | ||
278 | .remove = int3401_remove, | ||
279 | .driver = { | ||
280 | .name = "int3401 thermal", | ||
281 | .acpi_match_table = int3401_device_ids, | ||
282 | }, | ||
283 | }; | ||
284 | |||
285 | static int __init proc_thermal_init(void) | ||
286 | { | ||
287 | int ret; | ||
288 | |||
289 | ret = platform_driver_register(&int3401_driver); | ||
290 | if (ret) | ||
291 | return ret; | ||
292 | |||
293 | ret = pci_register_driver(&proc_thermal_pci_driver); | ||
294 | |||
295 | return ret; | ||
296 | } | ||
297 | |||
298 | static void __exit proc_thermal_exit(void) | ||
299 | { | ||
300 | platform_driver_unregister(&int3401_driver); | ||
301 | pci_unregister_driver(&proc_thermal_pci_driver); | ||
302 | } | ||
303 | |||
304 | module_init(proc_thermal_init); | ||
305 | module_exit(proc_thermal_exit); | ||
306 | |||
307 | MODULE_AUTHOR("Srinivas Pandruvada <srinivas.pandruvada@linux.intel.com>"); | ||
308 | MODULE_DESCRIPTION("Processor Thermal Reporting Device Driver"); | ||
309 | MODULE_LICENSE("GPL v2"); | ||
diff --git a/drivers/thermal/intel_powerclamp.c b/drivers/thermal/intel_powerclamp.c index e98b4249187c..6ceebd659dd4 100644 --- a/drivers/thermal/intel_powerclamp.c +++ b/drivers/thermal/intel_powerclamp.c | |||
@@ -688,6 +688,7 @@ static const struct x86_cpu_id intel_powerclamp_ids[] = { | |||
688 | { X86_VENDOR_INTEL, 6, 0x45}, | 688 | { X86_VENDOR_INTEL, 6, 0x45}, |
689 | { X86_VENDOR_INTEL, 6, 0x46}, | 689 | { X86_VENDOR_INTEL, 6, 0x46}, |
690 | { X86_VENDOR_INTEL, 6, 0x4c}, | 690 | { X86_VENDOR_INTEL, 6, 0x4c}, |
691 | { X86_VENDOR_INTEL, 6, 0x56}, | ||
691 | {} | 692 | {} |
692 | }; | 693 | }; |
693 | MODULE_DEVICE_TABLE(x86cpu, intel_powerclamp_ids); | 694 | MODULE_DEVICE_TABLE(x86cpu, intel_powerclamp_ids); |
diff --git a/drivers/thermal/rockchip_thermal.c b/drivers/thermal/rockchip_thermal.c index 1bcddfc60e91..9c6ce548e363 100644 --- a/drivers/thermal/rockchip_thermal.c +++ b/drivers/thermal/rockchip_thermal.c | |||
@@ -677,7 +677,6 @@ static SIMPLE_DEV_PM_OPS(rockchip_thermal_pm_ops, | |||
677 | static struct platform_driver rockchip_thermal_driver = { | 677 | static struct platform_driver rockchip_thermal_driver = { |
678 | .driver = { | 678 | .driver = { |
679 | .name = "rockchip-thermal", | 679 | .name = "rockchip-thermal", |
680 | .owner = THIS_MODULE, | ||
681 | .pm = &rockchip_thermal_pm_ops, | 680 | .pm = &rockchip_thermal_pm_ops, |
682 | .of_match_table = of_rockchip_thermal_match, | 681 | .of_match_table = of_rockchip_thermal_match, |
683 | }, | 682 | }, |
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 | ||