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