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