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