arm: thermal: Removed nonTEGRA_THERMAL_SYSFS logic
[linux-3.10.git] / arch / arm / mach-tegra / tegra3_thermal.c
1 /*
2  * arch/arm/mach-tegra/tegra3_thermal.c
3  *
4  * Copyright (C) 2010-2011 NVIDIA Corporation.
5  *
6  * This software is licensed under the terms of the GNU General Public
7  * License version 2, as published by the Free Software Foundation, and
8  * may be copied, distributed, and modified under those terms.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
14  *
15  */
16
17 #include <linux/kernel.h>
18 #include <linux/cpufreq.h>
19 #include <linux/delay.h>
20 #include <linux/mutex.h>
21 #include <linux/init.h>
22 #include <linux/err.h>
23 #include <linux/clk.h>
24 #include <linux/debugfs.h>
25 #include <linux/seq_file.h>
26 #include <linux/uaccess.h>
27 #include <linux/thermal.h>
28 #include <mach/thermal.h>
29 #include <mach/edp.h>
30 #include <linux/slab.h>
31
32 #include "clock.h"
33 #include "cpu-tegra.h"
34 #include "dvfs.h"
35
36 #define MAX_ZONES (16)
37
38 struct tegra_thermal {
39         struct tegra_thermal_device *device;
40         long temp_shutdown_tj;
41 #ifdef CONFIG_TEGRA_THERMAL_THROTTLE
42         long temp_throttle_tj;
43         struct thermal_zone_device *thz;
44         int tc1;
45         int tc2;
46         long passive_delay;
47 #endif
48 #ifdef CONFIG_TEGRA_EDP_LIMITS
49         int edp_thermal_zone_val;
50         long edp_offset;
51         long hysteresis_edp;
52 #endif
53         struct mutex mutex;
54 };
55
56 static struct tegra_thermal thermal_state = {
57         .device = NULL,
58 #ifdef CONFIG_TEGRA_EDP_LIMITS
59         .edp_thermal_zone_val = -1,
60 #endif
61 };
62
63 #ifdef CONFIG_TEGRA_EDP_LIMITS
64 static inline long edp2tj(struct tegra_thermal *thermal,
65                                 long edp_temp)
66 {
67         return edp_temp + thermal->edp_offset;
68 }
69
70 static inline long tj2edp(struct tegra_thermal *thermal,
71                                 long temp_tj)
72 {
73         return temp_tj - thermal->edp_offset;
74 }
75 #endif
76
77 static inline long dev2tj(struct tegra_thermal_device *dev,
78                                 long dev_temp)
79 {
80         return dev_temp + dev->offset;
81 }
82
83 static inline long tj2dev(struct tegra_thermal_device *dev,
84                                 long tj_temp)
85 {
86         return tj_temp - dev->offset;
87 }
88
89 #ifdef CONFIG_TEGRA_THERMAL_THROTTLE
90
91 static int tegra_thermal_zone_bind(struct thermal_zone_device *thermal,
92                                 struct thermal_cooling_device *cdevice) {
93         /* Support only Thermal Throttling (1 trip) for now */
94         return thermal_zone_bind_cooling_device(thermal, 0, cdevice);
95 }
96
97 static int tegra_thermal_zone_unbind(struct thermal_zone_device *thermal,
98                                 struct thermal_cooling_device *cdevice) {
99         /* Support only Thermal Throttling (1 trip) for now */
100         return thermal_zone_unbind_cooling_device(thermal, 0, cdevice);
101 }
102
103 static int tegra_thermal_zone_get_temp(struct thermal_zone_device *thz,
104                                                 long *temp)
105 {
106         struct tegra_thermal *thermal = thz->devdata;
107         thermal->device->get_temp(thermal->device->data, temp);
108
109         return 0;
110 }
111
112 static int tegra_thermal_zone_get_trip_type(
113                         struct thermal_zone_device *thermal,
114                         int trip,
115                         enum thermal_trip_type *type) {
116
117         /* Support only Thermal Throttling (1 trip) for now */
118         if (trip != 0)
119                 return -EINVAL;
120
121         *type = THERMAL_TRIP_PASSIVE;
122
123         return 0;
124 }
125
126 static int tegra_thermal_zone_get_trip_temp(struct thermal_zone_device *thz,
127                                                 int trip,
128                                                 long *temp) {
129         struct tegra_thermal *thermal = thz->devdata;
130
131         /* Support only Thermal Throttling (1 trip) for now */
132         if (trip != 0)
133                 return -EINVAL;
134
135         *temp = tj2dev(thermal->device, thermal->temp_throttle_tj);
136
137         return 0;
138 }
139
140 static struct thermal_zone_device_ops tegra_thermal_zone_ops = {
141         .bind = tegra_thermal_zone_bind,
142         .unbind = tegra_thermal_zone_unbind,
143         .get_temp = tegra_thermal_zone_get_temp,
144         .get_trip_type = tegra_thermal_zone_get_trip_type,
145         .get_trip_temp = tegra_thermal_zone_get_trip_temp,
146 };
147 #endif
148
149 /* Make sure this function remains stateless */
150 void tegra_thermal_alert(void *data)
151 {
152         struct tegra_thermal *thermal = data;
153         int err;
154         long temp_dev, temp_tj;
155         long lo_limit_throttle_tj, hi_limit_throttle_tj;
156         long lo_limit_edp_tj = 0, hi_limit_edp_tj = 0;
157         long temp_low_dev, temp_low_tj;
158         int lo_limit_tj = 0, hi_limit_tj = 0;
159 #ifdef CONFIG_TEGRA_EDP_LIMITS
160         const struct tegra_edp_limits *z;
161         int zones_sz;
162         int i;
163 #endif
164
165         if (thermal != &thermal_state)
166                 BUG();
167
168         mutex_lock(&thermal_state.mutex);
169
170 #ifdef CONFIG_TEGRA_THERMAL_THROTTLE
171         if (thermal->thz) {
172                 if (!thermal->thz->passive)
173                         thermal_zone_device_update(thermal->thz);
174         }
175 #endif
176
177         err = thermal->device->get_temp(thermal->device->data, &temp_dev);
178         if (err) {
179                 pr_err("%s: get temp fail(%d)", __func__, err);
180                 goto done;
181         }
182
183         /* Convert all temps to tj and then do all work/logic in terms of
184            tj in order to avoid confusion */
185         temp_tj = dev2tj(thermal->device, temp_dev);
186         thermal->device->get_temp_low(thermal->device, &temp_low_dev);
187         temp_low_tj = dev2tj(thermal->device, temp_low_dev);
188
189         lo_limit_throttle_tj = temp_low_tj;
190         hi_limit_throttle_tj = thermal->temp_shutdown_tj;
191
192 #ifdef CONFIG_TEGRA_THERMAL_THROTTLE
193         hi_limit_throttle_tj = thermal->temp_throttle_tj;
194
195         if (temp_tj > thermal->temp_throttle_tj) {
196                 lo_limit_throttle_tj = thermal->temp_throttle_tj;
197                 hi_limit_throttle_tj = thermal->temp_shutdown_tj;
198         }
199 #endif
200
201 #ifdef CONFIG_TEGRA_EDP_LIMITS
202         tegra_get_cpu_edp_limits(&z, &zones_sz);
203
204 /* edp table based off of tdiode measurements */
205 #define EDP_TEMP_TJ(_index)     edp2tj(thermal, z[_index].temperature * 1000)
206
207         if (temp_tj < EDP_TEMP_TJ(0)) {
208                 lo_limit_edp_tj = temp_low_tj;
209                 hi_limit_edp_tj = EDP_TEMP_TJ(0);
210         } else if (temp_tj >= EDP_TEMP_TJ(zones_sz-1)) {
211                 lo_limit_edp_tj = EDP_TEMP_TJ(zones_sz-1) -
212                                         thermal->hysteresis_edp;
213                 hi_limit_edp_tj = thermal->temp_shutdown_tj;
214         } else {
215                 for (i = 0; (i + 1) < zones_sz; i++) {
216                         if ((temp_tj >= EDP_TEMP_TJ(i)) &&
217                                 (temp_tj < EDP_TEMP_TJ(i+1))) {
218                                 lo_limit_edp_tj = EDP_TEMP_TJ(i) -
219                                                         thermal->hysteresis_edp;
220                                 hi_limit_edp_tj = EDP_TEMP_TJ(i+1);
221                                 break;
222                         }
223                 }
224         }
225 #undef EDP_TEMP_TJ
226 #else
227         lo_limit_edp_tj = temp_low_tj;
228         hi_limit_edp_tj = thermal->temp_shutdown_tj;
229 #endif
230
231         /* Get smallest window size */
232         lo_limit_tj = max(lo_limit_throttle_tj, lo_limit_edp_tj);
233         hi_limit_tj = min(hi_limit_throttle_tj, hi_limit_edp_tj);
234
235         thermal->device->set_limits(thermal->device->data,
236                                         tj2dev(thermal->device, lo_limit_tj),
237                                         tj2dev(thermal->device, hi_limit_tj));
238
239 #ifdef CONFIG_TEGRA_EDP_LIMITS
240         /* inform edp governor */
241         if (thermal->edp_thermal_zone_val != temp_tj)
242                 tegra_edp_update_thermal_zone(tj2edp(thermal, temp_tj)/1000);
243
244         thermal->edp_thermal_zone_val = temp_tj;
245 #endif
246
247 done:
248         mutex_unlock(&thermal_state.mutex);
249 }
250
251 int tegra_thermal_set_device(struct tegra_thermal_device *device)
252 {
253 #ifdef CONFIG_TEGRA_THERMAL_THROTTLE
254         struct thermal_zone_device *thz;
255 #endif
256
257         /* only support one device */
258         if (thermal_state.device)
259                 return -EINVAL;
260
261         thermal_state.device = device;
262
263 #ifdef CONFIG_TEGRA_THERMAL_THROTTLE
264         thz = thermal_zone_device_register(thermal_state.device->name,
265                                         1, /* trips */
266                                         &thermal_state,
267                                         &tegra_thermal_zone_ops,
268                                         thermal_state.tc1, /* dT/dt */
269                                         thermal_state.tc2, /* throttle */
270                                         thermal_state.passive_delay,
271                                         0); /* polling delay */
272
273         if (IS_ERR(thz)) {
274                 thz = NULL;
275                 return -ENODEV;
276         }
277
278         thermal_state.thz = thz;
279 #endif
280         thermal_state.device->set_alert(thermal_state.device->data,
281                                         tegra_thermal_alert,
282                                         &thermal_state);
283
284         thermal_state.device->set_shutdown_temp(thermal_state.device->data,
285                                 tj2dev(device, thermal_state.temp_shutdown_tj));
286
287         /* initialize limits */
288         tegra_thermal_alert(&thermal_state);
289
290         return 0;
291 }
292
293 int __init tegra_thermal_init(struct tegra_thermal_data *data)
294 {
295 #ifdef CONFIG_TEGRA_THERMAL_THROTTLE
296         thermal_state.tc1 = data->tc1;
297         thermal_state.tc2 = data->tc2;
298         thermal_state.passive_delay = data->passive_delay;
299         thermal_state.temp_throttle_tj = data->temp_throttle +
300                                                 data->temp_offset;
301 #endif
302         mutex_init(&thermal_state.mutex);
303 #ifdef CONFIG_TEGRA_EDP_LIMITS
304         thermal_state.edp_offset = data->edp_offset;
305         thermal_state.hysteresis_edp = data->hysteresis_edp;
306 #endif
307         thermal_state.temp_shutdown_tj = data->temp_shutdown +
308                                                 data->temp_offset;
309
310         return 0;
311 }
312
313 int tegra_thermal_exit(void)
314 {
315 #ifdef CONFIG_TEGRA_THERMAL_THROTTLE
316         if (thermal_state.thz)
317                 thermal_zone_device_unregister(thermal_state.thz);
318 #endif
319
320         return 0;
321 }
322
323 #ifdef CONFIG_DEBUG_FS
324
325 #ifdef CONFIG_TEGRA_THERMAL_THROTTLE
326 static int tegra_thermal_throttle_temp_tj_set(void *data, u64 val)
327 {
328         mutex_lock(&thermal_state.mutex);
329         thermal_state.temp_throttle_tj = val;
330         mutex_unlock(&thermal_state.mutex);
331
332         tegra_thermal_alert(&thermal_state);
333
334         return 0;
335 }
336
337 static int tegra_thermal_throttle_temp_tj_get(void *data, u64 *val)
338 {
339         *val = (u64)thermal_state.temp_throttle_tj;
340         return 0;
341 }
342
343 DEFINE_SIMPLE_ATTRIBUTE(throttle_temp_tj_fops,
344                         tegra_thermal_throttle_temp_tj_get,
345                         tegra_thermal_throttle_temp_tj_set,
346                         "%llu\n");
347 #endif
348
349 static int tegra_thermal_shutdown_temp_tj_set(void *data, u64 val)
350 {
351         thermal_state.temp_shutdown_tj = val;
352
353         if (thermal_state.device)
354                 thermal_state.device->set_shutdown_temp(
355                                 thermal_state.device->data,
356                                 tj2dev(thermal_state.device,
357                                         thermal_state.temp_shutdown_tj));
358
359         tegra_thermal_alert(&thermal_state);
360
361         return 0;
362 }
363
364 static int tegra_thermal_shutdown_temp_tj_get(void *data, u64 *val)
365 {
366         *val = (u64)thermal_state.temp_shutdown_tj;
367         return 0;
368 }
369
370 DEFINE_SIMPLE_ATTRIBUTE(shutdown_temp_tj_fops,
371                         tegra_thermal_shutdown_temp_tj_get,
372                         tegra_thermal_shutdown_temp_tj_set,
373                         "%llu\n");
374
375
376 static int tegra_thermal_temp_tj_get(void *data, u64 *val)
377 {
378         long temp_tj, temp_dev;
379
380         if (thermal_state.device) {
381                 thermal_state.device->get_temp(thermal_state.device->data,
382                                                 &temp_dev);
383
384                 /* Convert all temps to tj and then do all work/logic in
385                    terms of tj in order to avoid confusion */
386                 temp_tj = dev2tj(thermal_state.device, temp_dev);
387         } else {
388                 temp_tj = -1;
389         }
390
391         *val = (u64)temp_tj;
392
393         return 0;
394 }
395
396 DEFINE_SIMPLE_ATTRIBUTE(temp_tj_fops,
397                         tegra_thermal_temp_tj_get,
398                         NULL,
399                         "%llu\n");
400
401 #ifdef CONFIG_TEGRA_THERMAL_THROTTLE
402 static int tegra_thermal_tc1_set(void *data, u64 val)
403 {
404         thermal_state.thz->tc1 = val;
405         return 0;
406 }
407
408 static int tegra_thermal_tc1_get(void *data, u64 *val)
409 {
410         *val = (u64)thermal_state.thz->tc1;
411         return 0;
412 }
413
414 DEFINE_SIMPLE_ATTRIBUTE(tc1_fops,
415                         tegra_thermal_tc1_get,
416                         tegra_thermal_tc1_set,
417                         "%llu\n");
418
419 static int tegra_thermal_tc2_set(void *data, u64 val)
420 {
421         thermal_state.thz->tc2 = val;
422         return 0;
423 }
424
425 static int tegra_thermal_tc2_get(void *data, u64 *val)
426 {
427         *val = (u64)thermal_state.thz->tc2;
428         return 0;
429 }
430
431 DEFINE_SIMPLE_ATTRIBUTE(tc2_fops,
432                         tegra_thermal_tc2_get,
433                         tegra_thermal_tc2_set,
434                         "%llu\n");
435
436 static int tegra_thermal_passive_delay_set(void *data, u64 val)
437 {
438         thermal_state.thz->passive_delay = val;
439         return 0;
440 }
441
442 static int tegra_thermal_passive_delay_get(void *data, u64 *val)
443 {
444         *val = (u64)thermal_state.thz->passive_delay;
445         return 0;
446 }
447
448 DEFINE_SIMPLE_ATTRIBUTE(passive_delay_fops,
449                         tegra_thermal_passive_delay_get,
450                         tegra_thermal_passive_delay_set,
451                         "%llu\n");
452 #endif
453
454
455 static struct dentry *thermal_debugfs_root;
456
457 static int __init tegra_thermal_debug_init(void)
458 {
459         thermal_debugfs_root = debugfs_create_dir("tegra_thermal", 0);
460
461         if (!debugfs_create_file("shutdown_temp_tj", 0644, thermal_debugfs_root,
462                                  NULL, &shutdown_temp_tj_fops))
463                 goto err_out;
464
465         if (!debugfs_create_file("temp_tj", 0644, thermal_debugfs_root,
466                                  NULL, &temp_tj_fops))
467                 goto err_out;
468
469 #ifdef CONFIG_TEGRA_THERMAL_THROTTLE
470         if (!debugfs_create_file("throttle_temp_tj", 0644, thermal_debugfs_root,
471                                  NULL, &throttle_temp_tj_fops))
472                 goto err_out;
473
474         if (!debugfs_create_file("tc1", 0644, thermal_debugfs_root,
475                                  NULL, &tc1_fops))
476                 goto err_out;
477
478         if (!debugfs_create_file("tc2", 0644, thermal_debugfs_root,
479                                  NULL, &tc2_fops))
480                 goto err_out;
481
482         if (!debugfs_create_file("passive_delay", 0644, thermal_debugfs_root,
483                                  NULL, &passive_delay_fops))
484                 goto err_out;
485 #endif
486
487         return 0;
488
489 err_out:
490         debugfs_remove_recursive(thermal_debugfs_root);
491         return -ENOMEM;
492 }
493
494 late_initcall(tegra_thermal_debug_init);
495 #endif