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