ARM: tegra: thermal: fixed some skin thermal bugs
[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-2012 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 #include <linux/suspend.h>
33
34 #include "clock.h"
35 #include "cpu-tegra.h"
36 #include "dvfs.h"
37
38 static struct tegra_thermal_data *therm;
39 static LIST_HEAD(tegra_therm_list);
40 static DEFINE_MUTEX(tegra_therm_mutex);
41
42 static struct balanced_throttle *throttle_list;
43 static int throttle_list_size;
44
45 #ifdef CONFIG_TEGRA_EDP_LIMITS
46 static long edp_thermal_zone_val;
47 #endif
48
49 #ifdef CONFIG_TEGRA_SKIN_THROTTLE
50 static int skin_devs_bitmap;
51 static struct therm_est_subdevice *skin_devs[THERMAL_DEVICE_MAX];
52 static int skin_devs_count;
53 #endif
54 static bool tegra_thermal_suspend;
55
56 #ifdef CONFIG_DEBUG_FS
57 static struct dentry *thermal_debugfs_root;
58 #endif
59
60 static inline long dev2tj(struct tegra_thermal_device *dev,
61                                 long dev_temp)
62 {
63         return dev_temp + dev->offset;
64 }
65
66 static inline long tj2dev(struct tegra_thermal_device *dev,
67                                 long tj_temp)
68 {
69         return tj_temp - dev->offset;
70 }
71
72 static int tegra_thermal_get_temp_unlocked(long *tj_temp, bool offsetted)
73 {
74         struct tegra_thermal_device *dev = NULL;
75         int ret = 0;
76
77 #if defined(CONFIG_TEGRA_EDP_LIMITS) || defined(CONFIG_TEGRA_THERMAL_THROTTLE)
78         list_for_each_entry(dev, &tegra_therm_list, node)
79                 if (dev->id == therm->throttle_edp_device_id)
80                         break;
81 #endif
82
83         if (dev) {
84                 dev->get_temp(dev->data, tj_temp);
85                 if (offsetted)
86                         *tj_temp = dev2tj(dev, *tj_temp);
87         } else {
88                 ret = -1;
89         }
90
91         return ret;
92 }
93
94 #ifdef CONFIG_TEGRA_THERMAL_THROTTLE
95
96 static int tegra_thermal_zone_bind(struct thermal_zone_device *thz,
97                                 struct thermal_cooling_device *cdevice) {
98
99         struct balanced_throttle *bthrot = cdevice->devdata;
100         struct tegra_thermal_device *device = thz->devdata;
101
102         if ((bthrot->id == BALANCED_THROTTLE_ID_TJ) &&
103                 (device->id == therm->throttle_edp_device_id))
104                 return thermal_zone_bind_cooling_device(thz, 0, cdevice);
105
106 #ifdef CONFIG_TEGRA_SKIN_THROTTLE
107         if ((bthrot->id == BALANCED_THROTTLE_ID_SKIN) &&
108                 (device->id == therm->skin_device_id))
109                 return thermal_zone_bind_cooling_device(thz, 0, cdevice);
110 #endif
111
112         return 0;
113 }
114
115 static int tegra_thermal_zone_unbind(struct thermal_zone_device *thz,
116                                 struct thermal_cooling_device *cdevice) {
117         struct balanced_throttle *bthrot = cdevice->devdata;
118         struct tegra_thermal_device *device = thz->devdata;
119
120         if ((bthrot->id == BALANCED_THROTTLE_ID_TJ) &&
121                 (device->id == therm->throttle_edp_device_id))
122                 return thermal_zone_unbind_cooling_device(thz, 0, cdevice);
123
124 #ifdef CONFIG_TEGRA_SKIN_THROTTLE
125         if ((bthrot->id == BALANCED_THROTTLE_ID_SKIN) &&
126                 (device->id == therm->skin_device_id))
127                 return thermal_zone_unbind_cooling_device(thz, 0, cdevice);
128 #endif
129
130         return 0;
131 }
132
133 static int tegra_thermal_zone_get_temp(struct thermal_zone_device *thz,
134                                         unsigned long *temp)
135 {
136         struct tegra_thermal_device *device = thz->devdata;
137
138         if (!tegra_thermal_suspend)
139                 device->get_temp(device->data, temp);
140
141         return 0;
142 }
143
144 static int tegra_thermal_zone_get_trip_type(
145                         struct thermal_zone_device *thermal,
146                         int trip,
147                         enum thermal_trip_type *type) {
148         if (trip != 0)
149                 return -EINVAL;
150
151         *type = THERMAL_TRIP_PASSIVE;
152
153         return 0;
154 }
155
156 static int tegra_thermal_zone_get_trip_temp(struct thermal_zone_device *thz,
157                                         int trip,
158                                         unsigned long *temp) {
159         struct tegra_thermal_device *device = thz->devdata;
160
161         if (trip != 0)
162                 return -EINVAL;
163
164         if (device->id == therm->throttle_edp_device_id)
165                 *temp = therm->temp_throttle;
166 #ifdef CONFIG_TEGRA_SKIN_THROTTLE
167         else if (device->id == therm->skin_device_id)
168                 *temp = therm->temp_throttle_skin;
169 #endif
170         else
171                 return -EINVAL;
172
173         return 0;
174 }
175
176 static struct thermal_zone_device_ops tegra_thermal_zone_ops = {
177         .bind = tegra_thermal_zone_bind,
178         .unbind = tegra_thermal_zone_unbind,
179         .get_temp = tegra_thermal_zone_get_temp,
180         .get_trip_type = tegra_thermal_zone_get_trip_type,
181         .get_trip_temp = tegra_thermal_zone_get_trip_temp,
182 };
183 #endif
184
185 static int tegra_thermal_pm_notify(struct notifier_block *nb,
186                                 unsigned long event, void *data)
187 {
188         switch (event) {
189         case PM_SUSPEND_PREPARE:
190                 tegra_thermal_suspend = true;
191                 break;
192         case PM_POST_SUSPEND:
193                 tegra_thermal_suspend = false;
194                 break;
195         }
196
197         return NOTIFY_OK;
198 };
199
200 static struct notifier_block tegra_thermal_nb = {
201         .notifier_call = tegra_thermal_pm_notify,
202 };
203
204 static void tegra_thermal_alert_unlocked(void *data)
205 {
206         struct tegra_thermal_device *device = data;
207         long temp_tj;
208         long lo_limit_throttle_tj, hi_limit_throttle_tj;
209         long lo_limit_edp_tj = 0, hi_limit_edp_tj = 0;
210         long temp_low_dev, temp_low_tj;
211         int lo_limit_tj = 0, hi_limit_tj = 0;
212 #ifdef CONFIG_TEGRA_EDP_LIMITS
213         const struct tegra_edp_limits *z;
214         int zones_sz;
215         int i;
216 #endif
217
218 #ifdef CONFIG_TEGRA_THERMAL_THROTTLE
219         if (device->thz) {
220                 if ((!device->thz->passive) && (!tegra_thermal_suspend))
221                         thermal_zone_device_update(device->thz);
222         }
223 #endif
224
225         /* Convert all temps to tj and then do all work/logic in terms of
226            tj in order to avoid confusion */
227         if (tegra_thermal_get_temp_unlocked(&temp_tj, true))
228                 return;
229         device->get_temp_low(device, &temp_low_dev);
230         temp_low_tj = dev2tj(device, temp_low_dev);
231
232         lo_limit_throttle_tj = temp_low_tj;
233         hi_limit_throttle_tj = dev2tj(device, therm->temp_shutdown);
234
235 #ifdef CONFIG_TEGRA_THERMAL_THROTTLE
236         hi_limit_throttle_tj = dev2tj(device, therm->temp_throttle);
237
238         if (temp_tj > dev2tj(device, therm->temp_throttle)) {
239                 lo_limit_throttle_tj = dev2tj(device, therm->temp_throttle);
240                 hi_limit_throttle_tj = dev2tj(device, therm->temp_shutdown);
241         }
242 #endif
243
244 #ifdef CONFIG_TEGRA_EDP_LIMITS
245         tegra_get_cpu_edp_limits(&z, &zones_sz);
246
247 /* edp table based off of tdiode measurements */
248 #define EDP_TEMP_TJ(_index) (z[_index].temperature * 1000 + therm->edp_offset)
249
250         if (temp_tj < EDP_TEMP_TJ(0)) {
251                 lo_limit_edp_tj = temp_low_tj;
252                 hi_limit_edp_tj = EDP_TEMP_TJ(0);
253         } else if (temp_tj >= EDP_TEMP_TJ(zones_sz-1)) {
254                 lo_limit_edp_tj = EDP_TEMP_TJ(zones_sz-1) -
255                                         therm->hysteresis_edp;
256                 hi_limit_edp_tj = dev2tj(device, therm->temp_shutdown);
257         } else {
258                 for (i = 0; (i + 1) < zones_sz; i++) {
259                         if ((temp_tj >= EDP_TEMP_TJ(i)) &&
260                                 (temp_tj < EDP_TEMP_TJ(i+1))) {
261                                 lo_limit_edp_tj = EDP_TEMP_TJ(i) -
262                                                         therm->hysteresis_edp;
263                                 hi_limit_edp_tj = EDP_TEMP_TJ(i+1);
264                                 break;
265                         }
266                 }
267         }
268 #undef EDP_TEMP_TJ
269 #else
270         lo_limit_edp_tj = temp_low_tj;
271         hi_limit_edp_tj = dev2tj(device, therm->temp_shutdown);
272 #endif
273
274         /* Get smallest window size */
275         lo_limit_tj = max(lo_limit_throttle_tj, lo_limit_edp_tj);
276         hi_limit_tj = min(hi_limit_throttle_tj, hi_limit_edp_tj);
277
278         device->set_limits(device->data,
279                                 tj2dev(device, lo_limit_tj),
280                                 tj2dev(device, hi_limit_tj));
281
282 #ifdef CONFIG_TEGRA_EDP_LIMITS
283         /* inform edp governor */
284         if (edp_thermal_zone_val != temp_tj) {
285                 long temp_edp = (dev2tj(device, temp_tj) - therm->edp_offset) / 1000;
286                 tegra_edp_update_thermal_zone(temp_edp);
287                 edp_thermal_zone_val = temp_edp;
288         }
289 #endif
290 }
291
292 #ifdef CONFIG_TEGRA_THERMAL_THROTTLE
293 /* Make sure this function remains stateless */
294 static void tegra_thermal_alert(void *data)
295 {
296         mutex_lock(&tegra_therm_mutex);
297         tegra_thermal_alert_unlocked(data);
298         mutex_unlock(&tegra_therm_mutex);
299 }
300 #endif
301
302 #ifdef CONFIG_TEGRA_SKIN_THROTTLE
303 static void tegra_skin_thermal_alert(void *data)
304 {
305         struct tegra_thermal_device *dev = data;
306
307         if (!dev->thz->passive)
308                 thermal_zone_device_update(dev->thz);
309 }
310
311 static int tegra_skin_device_register(struct tegra_thermal_device *device)
312 {
313         int i;
314         struct therm_est_subdevice *skin_dev =
315                 kzalloc(sizeof(struct therm_est_subdevice), GFP_KERNEL);
316
317         for (i = 0; i < therm->skin_devs_size; i++) {
318                 if (therm->skin_devs[i].id == device->id) {
319                         memcpy(skin_dev->coeffs,
320                                 therm->skin_devs[i].coeffs,
321                                 sizeof(skin_devs[i]->coeffs));
322                         break;
323                 }
324         }
325
326         skin_dev->dev_data = device->data;
327         skin_dev->get_temp = device->get_temp;
328
329         skin_devs[skin_devs_count++] = skin_dev;
330
331         /* Create skin thermal device */
332         if (skin_devs_count == therm->skin_devs_size) {
333                 struct tegra_thermal_device *thermal_skin_device;
334                 struct therm_estimator *skin_estimator;
335
336                 skin_estimator = therm_est_register(
337                                         skin_devs,
338                                         skin_devs_count,
339                                         therm->skin_temp_offset,
340                                         therm->skin_period);
341                 thermal_skin_device = kzalloc(sizeof(struct tegra_thermal_device),
342                                                         GFP_KERNEL);
343                 thermal_skin_device->name = "skin_pred";
344                 thermal_skin_device->id = THERMAL_DEVICE_ID_SKIN;
345                 thermal_skin_device->data = skin_estimator;
346                 thermal_skin_device->get_temp =
347                         (int (*)(void *, long *)) therm_est_get_temp;
348                 thermal_skin_device->set_limits =
349                         (int (*)(void *, long, long)) therm_est_set_limits;
350                 thermal_skin_device->set_alert =
351                         (int (*)(void *, void (*)(void *), void *))
352                                 therm_est_set_alert;
353
354                 tegra_thermal_device_register(thermal_skin_device);
355         }
356
357         return 0;
358 }
359 #endif
360
361 int tegra_thermal_device_register(struct tegra_thermal_device *device)
362 {
363         struct tegra_thermal_device *dev;
364 #ifdef CONFIG_TEGRA_THERMAL_THROTTLE
365         struct thermal_zone_device *thz;
366         int t1 = 0, t2 = 0, pdelay = 0;
367         bool create_thz = false;
368 #endif
369
370         mutex_lock(&tegra_therm_mutex);
371         list_for_each_entry(dev, &tegra_therm_list, node) {
372                 if (dev->id == device->id) {
373                         mutex_unlock(&tegra_therm_mutex);
374                         return -EINVAL;
375                 }
376         }
377
378 #ifdef CONFIG_TEGRA_THERMAL_THROTTLE
379         if (device->id == therm->throttle_edp_device_id) {
380                 t1 = therm->tc1;
381                 t2 = therm->tc2;
382                 pdelay = therm->passive_delay;
383                 create_thz = true;
384         }
385 #endif
386 #ifdef CONFIG_TEGRA_SKIN_THROTTLE
387         if (device->id == therm->skin_device_id) {
388                 t1 = 0;
389                 t2 = 1;
390                 pdelay = 5000;
391                 create_thz = true;
392         }
393 #endif
394
395 #ifdef CONFIG_TEGRA_THERMAL_THROTTLE
396         if (create_thz) {
397                 thz = thermal_zone_device_register(
398                                                 device->name,
399                                                 1, /* trips */
400                                                 device,
401                                                 &tegra_thermal_zone_ops,
402                                                 t1, /* dT/dt */
403                                                 t2, /* throttle */
404                                                 pdelay,
405                                                 0); /* polling delay */
406                 if (IS_ERR_OR_NULL(thz))
407                         return -ENODEV;
408
409                 device->thz = thz;
410         }
411 #endif
412
413         list_add(&device->node, &tegra_therm_list);
414         mutex_unlock(&tegra_therm_mutex);
415
416         if (device->id == therm->shutdown_device_id) {
417                 device->set_shutdown_temp(device->data, therm->temp_shutdown);
418         }
419
420 #ifdef CONFIG_TEGRA_SKIN_THROTTLE
421         if (device->id == therm->skin_device_id) {
422                 if (create_thz)
423                         device->set_alert(device->data,
424                                 tegra_skin_thermal_alert,
425                                 device);
426                 device->set_limits(device->data, 0, therm->temp_throttle_skin);
427         }
428 #endif
429
430 #ifdef CONFIG_TEGRA_THERMAL_THROTTLE
431         if (device->id == therm->throttle_edp_device_id) {
432                 device->set_alert(device->data, tegra_thermal_alert, device);
433
434                 /* initialize limits */
435                 tegra_thermal_alert(device);
436         }
437 #endif
438
439 #ifdef CONFIG_TEGRA_SKIN_THROTTLE
440         if ((therm->skin_device_id == THERMAL_DEVICE_ID_SKIN) &&
441                 device->id && skin_devs_bitmap)
442                 tegra_skin_device_register(device);
443 #endif
444
445         register_pm_notifier(&tegra_thermal_nb);
446         return 0;
447 }
448
449 /* This needs to be inialized later hand */
450 static int __init throttle_list_init(void)
451 {
452         int i;
453         for (i = 0; i < throttle_list_size; i++)
454                 if (balanced_throttle_register(&throttle_list[i]))
455                         return -ENODEV;
456
457         return 0;
458 }
459 late_initcall(throttle_list_init);
460
461 int __init tegra_thermal_init(struct tegra_thermal_data *data,
462                                 struct balanced_throttle *tlist,
463                                 int tlist_size)
464 {
465         therm = data;
466 #ifdef CONFIG_DEBUG_FS
467         thermal_debugfs_root = debugfs_create_dir("tegra_thermal", 0);
468 #endif
469
470 #ifdef CONFIG_TEGRA_SKIN_THROTTLE
471         {
472                 int i;
473                 for (i = 0; i < therm->skin_devs_size; i++)
474                         skin_devs_bitmap |= therm->skin_devs[i].id;
475         }
476 #endif
477
478         throttle_list = tlist;
479         throttle_list_size = tlist_size;
480
481         return 0;
482 }
483
484 int tegra_thermal_exit(void)
485 {
486 #ifdef CONFIG_TEGRA_THERMAL_THROTTLE
487         struct tegra_thermal_device *dev;
488         mutex_lock(&tegra_therm_mutex);
489         list_for_each_entry(dev, &tegra_therm_list, node) {
490                 thermal_zone_device_unregister(dev->thz);
491         }
492         mutex_unlock(&tegra_therm_mutex);
493 #endif
494
495         return 0;
496 }
497
498 #ifdef CONFIG_DEBUG_FS
499 static int tegra_thermal_temp_tj_get(void *data, u64 *val)
500 {
501         long temp_tj;
502
503         mutex_lock(&tegra_therm_mutex);
504         if (tegra_thermal_get_temp_unlocked(&temp_tj, false))
505                 temp_tj = -1;
506         mutex_unlock(&tegra_therm_mutex);
507
508         *val = (u64)temp_tj;
509
510         return 0;
511 }
512
513 DEFINE_SIMPLE_ATTRIBUTE(temp_tj_fops,
514                         tegra_thermal_temp_tj_get,
515                         NULL,
516                         "%llu\n");
517
518 static int __init temp_tj_debug_init(void)
519 {
520         debugfs_create_file("temp_tj", 0644, thermal_debugfs_root,
521                 NULL, &temp_tj_fops);
522         return 0;
523 }
524 late_initcall(temp_tj_debug_init);
525
526
527 #define TEGRA_THERM_DEBUGFS(_name, _device_id, throttle, shutdown) \
528         static int tegra_thermal_##_name##_set(void *data, u64 val) \
529         { \
530                 struct tegra_thermal_device *dev; \
531                 mutex_lock(&tegra_therm_mutex); \
532                 therm->_name = val; \
533                 list_for_each_entry(dev, &tegra_therm_list, node) \
534                         if (dev->id == therm->_device_id) \
535                                 break; \
536                 if (dev) { \
537                         if (throttle) \
538                                 tegra_thermal_alert_unlocked(dev); \
539                         if (shutdown) \
540                                 dev->set_shutdown_temp(dev->data, \
541                                                         therm->temp_shutdown); \
542                 } \
543                 mutex_unlock(&tegra_therm_mutex); \
544                 return 0; \
545         } \
546         static int tegra_thermal_##_name##_get(void *data, u64 *val) \
547         { \
548                 *val = (u64)therm->_name; \
549                 return 0; \
550         } \
551         DEFINE_SIMPLE_ATTRIBUTE(_name##_fops, \
552                                 tegra_thermal_##_name##_get, \
553                                 tegra_thermal_##_name##_set, \
554                                 "%llu\n"); \
555         static int __init _name##_debug_init(void) \
556         { \
557                 debugfs_create_file(#_name, 0644, thermal_debugfs_root, \
558                         NULL, &_name##_fops); \
559                 return 0; \
560         } \
561         late_initcall(_name##_debug_init);
562
563
564 TEGRA_THERM_DEBUGFS(temp_shutdown, shutdown_device_id, false, true);
565 #ifdef CONFIG_TEGRA_THERMAL_THROTTLE
566 TEGRA_THERM_DEBUGFS(temp_throttle, throttle_edp_device_id, true, false);
567 #endif
568 #ifdef CONFIG_TEGRA_SKIN_THROTTLE
569 TEGRA_THERM_DEBUGFS(temp_throttle_skin, skin_device_id, false, false);
570 #endif
571
572 #ifdef CONFIG_TEGRA_THERMAL_THROTTLE
573 #define THERM_DEBUGFS(_name) \
574         static int tegra_thermal_##_name##_set(void *data, u64 val) \
575         { \
576                 struct tegra_thermal_device *dev; \
577                 mutex_lock(&tegra_therm_mutex); \
578                 list_for_each_entry(dev, &tegra_therm_list, node) \
579                         if (dev->id == therm->throttle_edp_device_id) \
580                                 break; \
581                 if (dev) \
582                         dev->thz->_name = val; \
583                 mutex_unlock(&tegra_therm_mutex); \
584                 return 0; \
585         } \
586         static int tegra_thermal_##_name##_get(void *data, u64 *val) \
587         { \
588                 struct tegra_thermal_device *dev; \
589                 mutex_lock(&tegra_therm_mutex); \
590                 list_for_each_entry(dev, &tegra_therm_list, node) \
591                         if (dev->id == therm->throttle_edp_device_id) \
592                                 break; \
593                 if (dev) \
594                         *val = (u64)dev->thz->_name; \
595                 mutex_unlock(&tegra_therm_mutex); \
596                 return 0; \
597         } \
598         DEFINE_SIMPLE_ATTRIBUTE(_name##_fops, \
599                         tegra_thermal_##_name##_get, \
600                         tegra_thermal_##_name##_set, \
601                         "%llu\n"); \
602         static int __init _name##_debug_init(void) \
603         { \
604                 debugfs_create_file(#_name, 0644, thermal_debugfs_root, \
605                         NULL, &_name##_fops); \
606                 return 0; \
607         } \
608         late_initcall(_name##_debug_init);
609
610
611 THERM_DEBUGFS(tc1);
612 THERM_DEBUGFS(tc2);
613 THERM_DEBUGFS(passive_delay);
614 #endif
615 #endif