ARM: tegra: thermal framework notifier
[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->throttle_edp_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 /* Make sure this function remains stateless */
293 void tegra_thermal_alert(void *data)
294 {
295         mutex_lock(&tegra_therm_mutex);
296         tegra_thermal_alert_unlocked(data);
297         mutex_unlock(&tegra_therm_mutex);
298 }
299
300 #ifdef CONFIG_TEGRA_SKIN_THROTTLE
301 static int tegra_skin_device_register(struct tegra_thermal_device *device)
302 {
303         int i;
304         struct therm_est_subdevice *skin_dev =
305                 kzalloc(sizeof(struct therm_est_subdevice), GFP_KERNEL);
306
307         for (i = 0; i < therm->skin_devs_size; i++) {
308                 if (therm->skin_devs[i].id == device->id) {
309                         memcpy(skin_dev->coeffs,
310                                 therm->skin_devs[i].coeffs,
311                                 sizeof(skin_devs[i]->coeffs));
312                         break;
313                 }
314         }
315
316         skin_dev->dev_data = device->data;
317         skin_dev->get_temp = device->get_temp;
318
319         skin_devs[skin_devs_count++] = skin_dev;
320
321         /* Create skin thermal device */
322         if (skin_devs_count == therm->skin_devs_size) {
323                 struct tegra_thermal_device *thermal_skin_device;
324                 struct therm_estimator *skin_estimator;
325
326                 skin_estimator = therm_est_register(
327                                         skin_devs,
328                                         skin_devs_count,
329                                         therm->skin_temp_offset,
330                                         therm->skin_period);
331                 thermal_skin_device = kzalloc(sizeof(struct tegra_thermal_device),
332                                                         GFP_KERNEL);
333                 thermal_skin_device->name = "skin_pred";
334                 thermal_skin_device->id = THERMAL_DEVICE_ID_SKIN;
335                 thermal_skin_device->data = skin_estimator;
336                 thermal_skin_device->get_temp =
337                         (int (*)(void *, long *)) therm_est_get_temp;
338                 thermal_skin_device->set_limits =
339                         (int (*)(void *, long, long)) therm_est_set_limits;
340                 thermal_skin_device->set_alert =
341                         (int (*)(void *, void (*)(void *), void *))
342                                 therm_est_set_alert;
343
344                 tegra_thermal_device_register(thermal_skin_device);
345         }
346
347         return 0;
348 }
349 #endif
350
351 int tegra_thermal_device_register(struct tegra_thermal_device *device)
352 {
353         struct tegra_thermal_device *dev;
354 #ifdef CONFIG_TEGRA_THERMAL_THROTTLE
355         struct thermal_zone_device *thz;
356         int t1 = 0, t2 = 0, pdelay = 0;
357         bool create_thz = false;
358 #endif
359
360         mutex_lock(&tegra_therm_mutex);
361         list_for_each_entry(dev, &tegra_therm_list, node) {
362                 if (dev->id == device->id) {
363                         mutex_unlock(&tegra_therm_mutex);
364                         return -EINVAL;
365                 }
366         }
367
368 #ifdef CONFIG_TEGRA_THERMAL_THROTTLE
369         if (device->id == therm->throttle_edp_device_id) {
370                 t1 = therm->tc1;
371                 t2 = therm->tc2;
372                 pdelay = therm->passive_delay;
373                 create_thz = true;
374         }
375 #endif
376 #ifdef CONFIG_TEGRA_SKIN_THROTTLE
377         if (device->id == therm->skin_device_id) {
378                 t1 = 0;
379                 t2 = 1;
380                 pdelay = 5000;
381                 create_thz = true;
382         }
383 #endif
384
385 #ifdef CONFIG_TEGRA_THERMAL_THROTTLE
386         if (create_thz) {
387                 thz = thermal_zone_device_register(
388                                                 device->name,
389                                                 1, /* trips */
390                                                 device,
391                                                 &tegra_thermal_zone_ops,
392                                                 t1, /* dT/dt */
393                                                 t2, /* throttle */
394                                                 pdelay,
395                                                 0); /* polling delay */
396                 if (IS_ERR_OR_NULL(thz))
397                         return -ENODEV;
398
399                 device->thz = thz;
400         }
401 #endif
402
403         list_add(&device->node, &tegra_therm_list);
404         mutex_unlock(&tegra_therm_mutex);
405
406         if (device->id == therm->shutdown_device_id) {
407                 device->set_shutdown_temp(device->data, therm->temp_shutdown);
408         }
409
410 #ifdef CONFIG_TEGRA_SKIN_THROTTLE
411         if (device->id == therm->skin_device_id) {
412                 if (create_thz)
413                         device->set_alert(device->data,
414                                 (void (*)(void *))thermal_zone_device_update,
415                                 thz);
416                 device->set_limits(device->data, 0, therm->temp_throttle_skin);
417         }
418 #endif
419
420 #ifdef CONFIG_TEGRA_THERMAL_THROTTLE
421         if (device->id == therm->throttle_edp_device_id) {
422                 device->set_alert(device->data, tegra_thermal_alert, device);
423
424                 /* initialize limits */
425                 tegra_thermal_alert(device);
426         }
427 #endif
428
429 #ifdef CONFIG_TEGRA_SKIN_THROTTLE
430         if ((therm->skin_device_id == THERMAL_DEVICE_ID_SKIN) &&
431                 device->id && skin_devs_bitmap)
432                 tegra_skin_device_register(device);
433 #endif
434
435         register_pm_notifier(&tegra_thermal_nb);
436         return 0;
437 }
438
439 /* This needs to be inialized later hand */
440 static int __init throttle_list_init(void)
441 {
442         int i;
443         for (i = 0; i < throttle_list_size; i++)
444                 if (balanced_throttle_register(&throttle_list[i]))
445                         return -ENODEV;
446
447         return 0;
448 }
449 late_initcall(throttle_list_init);
450
451 int __init tegra_thermal_init(struct tegra_thermal_data *data,
452                                 struct balanced_throttle *tlist,
453                                 int tlist_size)
454 {
455         therm = data;
456 #ifdef CONFIG_DEBUG_FS
457         thermal_debugfs_root = debugfs_create_dir("tegra_thermal", 0);
458 #endif
459
460 #ifdef CONFIG_TEGRA_SKIN_THROTTLE
461         {
462                 int i;
463                 for (i = 0; i < therm->skin_devs_size; i++)
464                         skin_devs_bitmap |= therm->skin_devs[i].id;
465         }
466 #endif
467
468         throttle_list = tlist;
469         throttle_list_size = tlist_size;
470
471         return 0;
472 }
473
474 int tegra_thermal_exit(void)
475 {
476 #ifdef CONFIG_TEGRA_THERMAL_THROTTLE
477         struct tegra_thermal_device *dev;
478         mutex_lock(&tegra_therm_mutex);
479         list_for_each_entry(dev, &tegra_therm_list, node) {
480                 thermal_zone_device_unregister(dev->thz);
481         }
482         mutex_unlock(&tegra_therm_mutex);
483 #endif
484
485         return 0;
486 }
487
488 #ifdef CONFIG_DEBUG_FS
489 static int tegra_thermal_temp_tj_get(void *data, u64 *val)
490 {
491         long temp_tj;
492
493         mutex_lock(&tegra_therm_mutex);
494         if (tegra_thermal_get_temp_unlocked(&temp_tj, false))
495                 temp_tj = -1;
496         mutex_unlock(&tegra_therm_mutex);
497
498         *val = (u64)temp_tj;
499
500         return 0;
501 }
502
503 DEFINE_SIMPLE_ATTRIBUTE(temp_tj_fops,
504                         tegra_thermal_temp_tj_get,
505                         NULL,
506                         "%llu\n");
507
508 static int __init temp_tj_debug_init(void)
509 {
510         debugfs_create_file("temp_tj", 0644, thermal_debugfs_root,
511                 NULL, &temp_tj_fops);
512         return 0;
513 }
514 late_initcall(temp_tj_debug_init);
515
516
517 #define TEGRA_THERM_DEBUGFS(_name, _device_id, throttle, shutdown) \
518         static int tegra_thermal_##_name##_set(void *data, u64 val) \
519         { \
520                 struct tegra_thermal_device *dev; \
521                 mutex_lock(&tegra_therm_mutex); \
522                 therm->_name = val; \
523                 list_for_each_entry(dev, &tegra_therm_list, node) \
524                         if (dev->id == therm->_device_id) \
525                                 break; \
526                 if (dev) { \
527                         if (throttle) \
528                                 tegra_thermal_alert_unlocked(dev); \
529                         if (shutdown) \
530                                 dev->set_shutdown_temp(dev->data, \
531                                                         therm->temp_shutdown); \
532                 } \
533                 mutex_unlock(&tegra_therm_mutex); \
534                 return 0; \
535         } \
536         static int tegra_thermal_##_name##_get(void *data, u64 *val) \
537         { \
538                 *val = (u64)therm->_name; \
539                 return 0; \
540         } \
541         DEFINE_SIMPLE_ATTRIBUTE(_name##_fops, \
542                                 tegra_thermal_##_name##_get, \
543                                 tegra_thermal_##_name##_set, \
544                                 "%llu\n"); \
545         static int __init _name##_debug_init(void) \
546         { \
547                 debugfs_create_file(#_name, 0644, thermal_debugfs_root, \
548                         NULL, &_name##_fops); \
549                 return 0; \
550         } \
551         late_initcall(_name##_debug_init);
552
553
554 TEGRA_THERM_DEBUGFS(temp_shutdown, shutdown_device_id, false, true);
555 #ifdef CONFIG_TEGRA_THERMAL_THROTTLE
556 TEGRA_THERM_DEBUGFS(temp_throttle, throttle_edp_device_id, true, false);
557 #endif
558 #ifdef CONFIG_TEGRA_SKIN_THROTTLE
559 TEGRA_THERM_DEBUGFS(temp_throttle_skin, skin_device_id, false, false);
560 #endif
561
562 #ifdef CONFIG_TEGRA_THERMAL_THROTTLE
563 #define THERM_DEBUGFS(_name) \
564         static int tegra_thermal_##_name##_set(void *data, u64 val) \
565         { \
566                 struct tegra_thermal_device *dev; \
567                 mutex_lock(&tegra_therm_mutex); \
568                 list_for_each_entry(dev, &tegra_therm_list, node) \
569                         if (dev->id == therm->throttle_edp_device_id) \
570                                 break; \
571                 if (dev) \
572                         dev->thz->_name = val; \
573                 mutex_unlock(&tegra_therm_mutex); \
574                 return 0; \
575         } \
576         static int tegra_thermal_##_name##_get(void *data, u64 *val) \
577         { \
578                 struct tegra_thermal_device *dev; \
579                 mutex_lock(&tegra_therm_mutex); \
580                 list_for_each_entry(dev, &tegra_therm_list, node) \
581                         if (dev->id == therm->throttle_edp_device_id) \
582                                 break; \
583                 if (dev) \
584                         *val = (u64)dev->thz->_name; \
585                 mutex_unlock(&tegra_therm_mutex); \
586                 return 0; \
587         } \
588         DEFINE_SIMPLE_ATTRIBUTE(_name##_fops, \
589                         tegra_thermal_##_name##_get, \
590                         tegra_thermal_##_name##_set, \
591                         "%llu\n"); \
592         static int __init _name##_debug_init(void) \
593         { \
594                 debugfs_create_file(#_name, 0644, thermal_debugfs_root, \
595                         NULL, &_name##_fops); \
596                 return 0; \
597         } \
598         late_initcall(_name##_debug_init);
599
600
601 THERM_DEBUGFS(tc1);
602 THERM_DEBUGFS(tc2);
603 THERM_DEBUGFS(passive_delay);
604 #endif
605 #endif