arm: tegra: thermal: Added thermal debugfs nodes
[linux-2.6.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_throttle_tj;
41         long temp_shutdown_tj;
42 #ifdef CONFIG_TEGRA_THERMAL_SYSFS
43         struct thermal_zone_device *thz;
44         int tc1;
45         int tc2;
46         long passive_delay;
47 #else
48         long temp_throttle_low_tj;
49 #endif
50 #ifdef CONFIG_TEGRA_EDP_LIMITS
51         int edp_thermal_zone_val;
52         long edp_offset;
53         long hysteresis_edp;
54 #endif
55         struct mutex mutex;
56 };
57
58 static struct tegra_thermal thermal_state = {
59         .device = NULL,
60 #ifdef CONFIG_TEGRA_EDP_LIMITS
61         .edp_thermal_zone_val = -1,
62 #endif
63 };
64
65 #ifndef CONFIG_TEGRA_THERMAL_SYSFS
66 static bool throttle_enb;
67 #endif
68
69 #ifdef CONFIG_TEGRA_EDP_LIMITS
70 static inline long edp2tj(struct tegra_thermal *thermal,
71                                 long edp_temp)
72 {
73         return edp_temp + thermal->edp_offset;
74 }
75
76 static inline long tj2edp(struct tegra_thermal *thermal,
77                                 long temp_tj)
78 {
79         return temp_tj - thermal->edp_offset;
80 }
81 #endif
82
83 static inline long dev2tj(struct tegra_thermal_device *dev,
84                                 long dev_temp)
85 {
86         return dev_temp + dev->offset;
87 }
88
89 static inline long tj2dev(struct tegra_thermal_device *dev,
90                                 long tj_temp)
91 {
92         return tj_temp - dev->offset;
93 }
94
95 #ifdef CONFIG_TEGRA_THERMAL_SYSFS
96
97 static int tegra_thermal_zone_bind(struct thermal_zone_device *thermal,
98                                 struct thermal_cooling_device *cdevice) {
99         /* Support only Thermal Throttling (1 trip) for now */
100         return thermal_zone_bind_cooling_device(thermal, 0, cdevice);
101 }
102
103 static int tegra_thermal_zone_unbind(struct thermal_zone_device *thermal,
104                                 struct thermal_cooling_device *cdevice) {
105         /* Support only Thermal Throttling (1 trip) for now */
106         return thermal_zone_unbind_cooling_device(thermal, 0, cdevice);
107 }
108
109 static int tegra_thermal_zone_get_temp(struct thermal_zone_device *thz,
110                                                 long *temp)
111 {
112         struct tegra_thermal *thermal = thz->devdata;
113         thermal->device->get_temp(thermal->device->data, temp);
114
115         return 0;
116 }
117
118 static int tegra_thermal_zone_get_trip_type(
119                         struct thermal_zone_device *thermal,
120                         int trip,
121                         enum thermal_trip_type *type) {
122
123         /* Support only Thermal Throttling (1 trip) for now */
124         if (trip != 0)
125                 return -EINVAL;
126
127         *type = THERMAL_TRIP_PASSIVE;
128
129         return 0;
130 }
131
132 static int tegra_thermal_zone_get_trip_temp(struct thermal_zone_device *thz,
133                                                 int trip,
134                                                 long *temp) {
135         struct tegra_thermal *thermal = thz->devdata;
136
137         /* Support only Thermal Throttling (1 trip) for now */
138         if (trip != 0)
139                 return -EINVAL;
140
141         *temp = tj2dev(thermal->device, thermal->temp_throttle_tj);
142
143         return 0;
144 }
145
146 static struct thermal_zone_device_ops tegra_thermal_zone_ops = {
147         .bind = tegra_thermal_zone_bind,
148         .unbind = tegra_thermal_zone_unbind,
149         .get_temp = tegra_thermal_zone_get_temp,
150         .get_trip_type = tegra_thermal_zone_get_trip_type,
151         .get_trip_temp = tegra_thermal_zone_get_trip_temp,
152 };
153 #endif
154
155 /* The thermal sysfs handles notifying the throttling
156  * cooling device */
157 #ifndef CONFIG_TEGRA_THERMAL_SYSFS
158 static void tegra_therm_throttle(bool enable)
159 {
160         if (throttle_enb != enable) {
161                 mutex_lock(&thermal_state.mutex);
162                 tegra_throttling_enable(enable);
163                 throttle_enb = enable;
164                 mutex_unlock(&thermal_state.mutex);
165         }
166 }
167 #endif
168
169 /* Make sure this function remains stateless */
170 void tegra_thermal_alert(void *data)
171 {
172         struct tegra_thermal *thermal = data;
173         int err;
174         long temp_dev, temp_tj;
175         long lo_limit_throttle_tj, hi_limit_throttle_tj;
176         long lo_limit_edp_tj = 0, hi_limit_edp_tj = 0;
177         int lo_limit_tj = 0, hi_limit_tj = 0;
178 #ifdef CONFIG_TEGRA_EDP_LIMITS
179         const struct tegra_edp_limits *z;
180         int zones_sz;
181         int i;
182 #endif
183
184         if (thermal != &thermal_state)
185                 BUG();
186
187         mutex_lock(&thermal_state.mutex);
188
189 #ifdef CONFIG_TEGRA_THERMAL_SYSFS
190         if (thermal->thz) {
191                 if (!thermal->thz->passive)
192                         thermal_zone_device_update(thermal->thz);
193         }
194 #endif
195
196         err = thermal->device->get_temp(thermal->device->data, &temp_dev);
197         if (err) {
198                 pr_err("%s: get temp fail(%d)", __func__, err);
199                 goto done;
200         }
201
202         /* Convert all temps to tj and then do all work/logic in terms of
203            tj in order to avoid confusion */
204         temp_tj = dev2tj(thermal->device, temp_dev);
205
206         lo_limit_throttle_tj = dev2tj(thermal->device, 0);
207         hi_limit_throttle_tj = thermal->temp_throttle_tj;
208
209 #ifndef CONFIG_TEGRA_THERMAL_SYSFS
210         /* Check to see if we are currently throttling */
211         if ((tegra_is_throttling() &&
212                 (temp_tj > thermal->temp_throttle_low_tj))
213                 || (temp_tj >= thermal->temp_throttle_tj)) {
214                 lo_limit_throttle_tj = thermal->temp_throttle_low_tj;
215                 hi_limit_throttle_tj = thermal->temp_shutdown_tj;
216         }
217 #else
218         if (temp_tj > thermal->temp_throttle_tj) {
219                 lo_limit_throttle_tj = thermal->temp_throttle_tj;
220                 hi_limit_throttle_tj = thermal->temp_shutdown_tj;
221         }
222 #endif
223
224 #ifdef CONFIG_TEGRA_EDP_LIMITS
225         tegra_get_cpu_edp_limits(&z, &zones_sz);
226
227 /* edp table based off of tdiode measurements */
228 #define EDP_TEMP_TJ(_index)     edp2tj(thermal, z[_index].temperature * 1000)
229
230         if (temp_tj < EDP_TEMP_TJ(0)) {
231                 lo_limit_edp_tj = dev2tj(thermal->device, 0);
232                 hi_limit_edp_tj = EDP_TEMP_TJ(0);
233         } else if (temp_tj >= EDP_TEMP_TJ(zones_sz-1)) {
234                 lo_limit_edp_tj = EDP_TEMP_TJ(zones_sz-1) -
235                                         thermal->hysteresis_edp;
236                 hi_limit_edp_tj = thermal->temp_shutdown_tj;
237         } else {
238                 for (i = 0; (i + 1) < zones_sz; i++) {
239                         if ((temp_tj >= EDP_TEMP_TJ(i)) &&
240                                 (temp_tj < EDP_TEMP_TJ(i+1))) {
241                                 lo_limit_edp_tj = EDP_TEMP_TJ(i) -
242                                                         thermal->hysteresis_edp;
243                                 hi_limit_edp_tj = EDP_TEMP_TJ(i+1);
244                                 break;
245                         }
246                 }
247         }
248 #undef EDP_TEMP_TJ
249 #else
250         lo_limit_edp_tj = 0;
251         hi_limit_edp_tj = thermal->temp_shutdown_tj;
252 #endif
253
254         /* Get smallest window size */
255         lo_limit_tj = max(lo_limit_throttle_tj, lo_limit_edp_tj);
256         hi_limit_tj = min(hi_limit_throttle_tj, hi_limit_edp_tj);
257
258         thermal->device->set_limits(thermal->device->data,
259                                         tj2dev(thermal->device, lo_limit_tj),
260                                         tj2dev(thermal->device, hi_limit_tj));
261
262 #ifndef CONFIG_TEGRA_THERMAL_SYSFS
263         if (temp_tj >= thermal->temp_throttle_tj) {
264                 /* start throttling */
265                 if (!tegra_is_throttling())
266                         tegra_therm_throttle(true);
267         } else if (temp_tj <= thermal->temp_throttle_low_tj) {
268                 /* switch off throttling */
269                 if (tegra_is_throttling())
270                         tegra_therm_throttle(false);
271         }
272 #endif
273
274 #ifdef CONFIG_TEGRA_EDP_LIMITS
275         /* inform edp governor */
276         if (thermal->edp_thermal_zone_val != temp_tj)
277                 tegra_edp_update_thermal_zone(tj2edp(thermal, temp_tj)/1000);
278
279         thermal->edp_thermal_zone_val = temp_tj;
280 #endif
281
282 done:
283         mutex_unlock(&thermal_state.mutex);
284 }
285
286 int tegra_thermal_set_device(struct tegra_thermal_device *device)
287 {
288 #ifdef CONFIG_TEGRA_THERMAL_SYSFS
289         struct thermal_zone_device *thz;
290 #endif
291
292         /* only support one device */
293         if (thermal_state.device)
294                 return -EINVAL;
295
296         thermal_state.device = device;
297
298 #ifdef CONFIG_TEGRA_THERMAL_SYSFS
299         thz = thermal_zone_device_register(thermal_state.device->name,
300                                         1, /* trips */
301                                         &thermal_state,
302                                         &tegra_thermal_zone_ops,
303                                         thermal_state.tc1, /* dT/dt */
304                                         thermal_state.tc2, /* throttle */
305                                         thermal_state.passive_delay,
306                                         0); /* polling delay */
307
308         if (IS_ERR(thz)) {
309                 thz = NULL;
310                 return -ENODEV;
311         }
312
313         thermal_state.thz = thz;
314 #endif
315         thermal_state.device->set_alert(thermal_state.device->data,
316                                         tegra_thermal_alert,
317                                         &thermal_state);
318
319         thermal_state.device->set_shutdown_temp(thermal_state.device->data,
320                                 tj2dev(device, thermal_state.temp_shutdown_tj));
321
322         /* initialize limits */
323         tegra_thermal_alert(&thermal_state);
324
325         return 0;
326 }
327
328 int __init tegra_thermal_init(struct tegra_thermal_data *data)
329 {
330 #ifdef CONFIG_TEGRA_THERMAL_SYSFS
331         thermal_state.tc1 = data->tc1;
332         thermal_state.tc2 = data->tc2;
333         thermal_state.passive_delay = data->passive_delay;
334 #else
335         thermal_state.temp_throttle_low_tj = data->temp_throttle +
336                                                 data->temp_offset -
337                                                 data->hysteresis_throttle;
338 #endif
339         mutex_init(&thermal_state.mutex);
340 #ifdef CONFIG_TEGRA_EDP_LIMITS
341         thermal_state.edp_offset = data->edp_offset;
342         thermal_state.hysteresis_edp = data->hysteresis_edp;
343 #endif
344         thermal_state.temp_throttle_tj = data->temp_throttle +
345                                                 data->temp_offset;
346         thermal_state.temp_shutdown_tj = data->temp_shutdown +
347                                                 data->temp_offset;
348
349         return 0;
350 }
351
352 int tegra_thermal_exit(void)
353 {
354 #ifdef CONFIG_TEGRA_THERMAL_SYSFS
355         if (thermal_state.thz)
356                 thermal_zone_device_unregister(thermal_state.thz);
357 #endif
358
359         return 0;
360 }
361
362 #ifdef CONFIG_DEBUG_FS
363
364 static int tegra_thermal_throttle_temp_tj_set(void *data, u64 val)
365 {
366 #ifndef CONFIG_TEGRA_THERMAL_SYSFS
367         long throttle_hysteresis = thermal_state.temp_throttle_tj -
368                                         thermal_state.temp_throttle_low_tj;
369 #endif
370
371         mutex_lock(&thermal_state.mutex);
372         thermal_state.temp_throttle_tj = val;
373 #ifndef CONFIG_TEGRA_THERMAL_SYSFS
374         thermal_state.temp_throttle_low_tj = thermal_state.temp_throttle_tj -
375                                                 throttle_hysteresis;
376 #endif
377         mutex_unlock(&thermal_state.mutex);
378
379         tegra_thermal_alert(&thermal_state);
380
381         return 0;
382 }
383
384 static int tegra_thermal_throttle_temp_tj_get(void *data, u64 *val)
385 {
386         *val = (u64)thermal_state.temp_throttle_tj;
387         return 0;
388 }
389
390 DEFINE_SIMPLE_ATTRIBUTE(throttle_temp_tj_fops,
391                         tegra_thermal_throttle_temp_tj_get,
392                         tegra_thermal_throttle_temp_tj_set,
393                         "%llu\n");
394
395 static int tegra_thermal_shutdown_temp_tj_set(void *data, u64 val)
396 {
397         thermal_state.temp_shutdown_tj = val;
398
399         if (thermal_state.device)
400                 thermal_state.device->set_shutdown_temp(
401                                 thermal_state.device->data,
402                                 tj2dev(thermal_state.device,
403                                         thermal_state.temp_shutdown_tj));
404
405         tegra_thermal_alert(&thermal_state);
406
407         return 0;
408 }
409
410 static int tegra_thermal_shutdown_temp_tj_get(void *data, u64 *val)
411 {
412         *val = (u64)thermal_state.temp_shutdown_tj;
413         return 0;
414 }
415
416 DEFINE_SIMPLE_ATTRIBUTE(shutdown_temp_tj_fops,
417                         tegra_thermal_shutdown_temp_tj_get,
418                         tegra_thermal_shutdown_temp_tj_set,
419                         "%llu\n");
420
421
422 static int tegra_thermal_temp_tj_get(void *data, u64 *val)
423 {
424         long temp_tj, temp_dev;
425
426         if (thermal_state.device) {
427                 thermal_state.device->get_temp(thermal_state.device->data,
428                                                 &temp_dev);
429
430                 /* Convert all temps to tj and then do all work/logic in
431                    terms of tj in order to avoid confusion */
432                 temp_tj = dev2tj(thermal_state.device, temp_dev);
433         } else {
434                 temp_tj = -1;
435         }
436
437         *val = (u64)temp_tj;
438
439         return 0;
440 }
441
442 DEFINE_SIMPLE_ATTRIBUTE(temp_tj_fops,
443                         tegra_thermal_temp_tj_get,
444                         NULL,
445                         "%llu\n");
446
447 #ifdef CONFIG_TEGRA_THERMAL_SYSFS
448 static int tegra_thermal_tc1_set(void *data, u64 val)
449 {
450         thermal_state.thz->tc1 = val;
451         return 0;
452 }
453
454 static int tegra_thermal_tc1_get(void *data, u64 *val)
455 {
456         *val = (u64)thermal_state.thz->tc1;
457         return 0;
458 }
459
460 DEFINE_SIMPLE_ATTRIBUTE(tc1_fops,
461                         tegra_thermal_tc1_get,
462                         tegra_thermal_tc1_set,
463                         "%llu\n");
464
465 static int tegra_thermal_tc2_set(void *data, u64 val)
466 {
467         thermal_state.thz->tc2 = val;
468         return 0;
469 }
470
471 static int tegra_thermal_tc2_get(void *data, u64 *val)
472 {
473         *val = (u64)thermal_state.thz->tc2;
474         return 0;
475 }
476
477 DEFINE_SIMPLE_ATTRIBUTE(tc2_fops,
478                         tegra_thermal_tc2_get,
479                         tegra_thermal_tc2_set,
480                         "%llu\n");
481
482 static int tegra_thermal_passive_delay_set(void *data, u64 val)
483 {
484         thermal_state.thz->passive_delay = val;
485         return 0;
486 }
487
488 static int tegra_thermal_passive_delay_get(void *data, u64 *val)
489 {
490         *val = (u64)thermal_state.thz->passive_delay;
491         return 0;
492 }
493
494 DEFINE_SIMPLE_ATTRIBUTE(passive_delay_fops,
495                         tegra_thermal_passive_delay_get,
496                         tegra_thermal_passive_delay_set,
497                         "%llu\n");
498 #endif
499
500
501 static struct dentry *thermal_debugfs_root;
502
503 static int __init tegra_thermal_debug_init(void)
504 {
505         thermal_debugfs_root = debugfs_create_dir("tegra_thermal", 0);
506
507         if (!debugfs_create_file("throttle_temp_tj", 0644, thermal_debugfs_root,
508                                  NULL, &throttle_temp_tj_fops))
509                 goto err_out;
510
511         if (!debugfs_create_file("shutdown_temp_tj", 0644, thermal_debugfs_root,
512                                  NULL, &shutdown_temp_tj_fops))
513                 goto err_out;
514
515         if (!debugfs_create_file("temp_tj", 0644, thermal_debugfs_root,
516                                  NULL, &temp_tj_fops))
517                 goto err_out;
518
519 #ifdef CONFIG_TEGRA_THERMAL_SYSFS
520         if (!debugfs_create_file("tc1", 0644, thermal_debugfs_root,
521                                  NULL, &tc1_fops))
522                 goto err_out;
523
524         if (!debugfs_create_file("tc2", 0644, thermal_debugfs_root,
525                                  NULL, &tc2_fops))
526                 goto err_out;
527
528         if (!debugfs_create_file("passive_delay", 0644, thermal_debugfs_root,
529                                  NULL, &passive_delay_fops))
530                 goto err_out;
531 #endif
532
533         return 0;
534
535 err_out:
536         debugfs_remove_recursive(thermal_debugfs_root);
537         return -ENOMEM;
538 }
539
540 late_initcall(tegra_thermal_debug_init);
541 #endif