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