2 * acpi_thermal.c - ACPI Thermal Zone Driver ($Revision: 41 $)
4 * Copyright (C) 2001, 2002 Andy Grover <andrew.grover@intel.com>
5 * Copyright (C) 2001, 2002 Paul Diefenbaugh <paul.s.diefenbaugh@intel.com>
7 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or (at
12 * your option) any later version.
14 * This program is distributed in the hope that it will be useful, but
15 * WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * General Public License for more details.
19 * You should have received a copy of the GNU General Public License along
20 * with this program; if not, write to the Free Software Foundation, Inc.,
21 * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
23 * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
25 * This driver fully implements the ACPI thermal policy as described in the
26 * ACPI 2.0 Specification.
28 * TBD: 1. Implement passive cooling hysteresis.
29 * 2. Enhance passive cooling (CPU) states/limit interface to support
30 * concepts of 'multiple limiters', upper/lower limits, etc.
34 #include <linux/kernel.h>
35 #include <linux/module.h>
36 #include <linux/dmi.h>
37 #include <linux/init.h>
38 #include <linux/types.h>
39 #include <linux/proc_fs.h>
40 #include <linux/jiffies.h>
41 #include <linux/kmod.h>
42 #include <linux/seq_file.h>
43 #include <linux/reboot.h>
44 #include <linux/device.h>
45 #include <asm/uaccess.h>
46 #include <linux/thermal.h>
47 #include <acpi/acpi_bus.h>
48 #include <acpi/acpi_drivers.h>
50 #define ACPI_THERMAL_CLASS "thermal_zone"
51 #define ACPI_THERMAL_DEVICE_NAME "Thermal Zone"
52 #define ACPI_THERMAL_FILE_STATE "state"
53 #define ACPI_THERMAL_FILE_TEMPERATURE "temperature"
54 #define ACPI_THERMAL_FILE_TRIP_POINTS "trip_points"
55 #define ACPI_THERMAL_FILE_COOLING_MODE "cooling_mode"
56 #define ACPI_THERMAL_FILE_POLLING_FREQ "polling_frequency"
57 #define ACPI_THERMAL_NOTIFY_TEMPERATURE 0x80
58 #define ACPI_THERMAL_NOTIFY_THRESHOLDS 0x81
59 #define ACPI_THERMAL_NOTIFY_DEVICES 0x82
60 #define ACPI_THERMAL_NOTIFY_CRITICAL 0xF0
61 #define ACPI_THERMAL_NOTIFY_HOT 0xF1
62 #define ACPI_THERMAL_MODE_ACTIVE 0x00
64 #define ACPI_THERMAL_MAX_ACTIVE 10
65 #define ACPI_THERMAL_MAX_LIMIT_STR_LEN 65
67 #define _COMPONENT ACPI_THERMAL_COMPONENT
68 ACPI_MODULE_NAME("thermal");
70 MODULE_AUTHOR("Paul Diefenbaugh");
71 MODULE_DESCRIPTION("ACPI Thermal Zone Driver");
72 MODULE_LICENSE("GPL");
75 module_param(act
, int, 0644);
76 MODULE_PARM_DESC(act
, "Disable or override all lowest active trip points.");
79 module_param(crt
, int, 0644);
80 MODULE_PARM_DESC(crt
, "Disable or lower all critical trip points.");
83 module_param(tzp
, int, 0444);
84 MODULE_PARM_DESC(tzp
, "Thermal zone polling frequency, in 1/10 seconds.");
87 module_param(nocrt
, int, 0);
88 MODULE_PARM_DESC(nocrt
, "Set to take no action upon ACPI thermal zone critical trips points.");
91 module_param(off
, int, 0);
92 MODULE_PARM_DESC(off
, "Set to disable ACPI thermal support.");
95 module_param(psv
, int, 0644);
96 MODULE_PARM_DESC(psv
, "Disable or override all passive trip points.");
98 static int acpi_thermal_add(struct acpi_device
*device
);
99 static int acpi_thermal_remove(struct acpi_device
*device
, int type
);
100 static int acpi_thermal_resume(struct acpi_device
*device
);
101 static int acpi_thermal_state_open_fs(struct inode
*inode
, struct file
*file
);
102 static int acpi_thermal_temp_open_fs(struct inode
*inode
, struct file
*file
);
103 static int acpi_thermal_trip_open_fs(struct inode
*inode
, struct file
*file
);
104 static int acpi_thermal_cooling_open_fs(struct inode
*inode
, struct file
*file
);
105 static ssize_t
acpi_thermal_write_cooling_mode(struct file
*,
106 const char __user
*, size_t,
108 static int acpi_thermal_polling_open_fs(struct inode
*inode
, struct file
*file
);
109 static ssize_t
acpi_thermal_write_polling(struct file
*, const char __user
*,
112 static const struct acpi_device_id thermal_device_ids
[] = {
113 {ACPI_THERMAL_HID
, 0},
116 MODULE_DEVICE_TABLE(acpi
, thermal_device_ids
);
118 static struct acpi_driver acpi_thermal_driver
= {
120 .class = ACPI_THERMAL_CLASS
,
121 .ids
= thermal_device_ids
,
123 .add
= acpi_thermal_add
,
124 .remove
= acpi_thermal_remove
,
125 .resume
= acpi_thermal_resume
,
129 struct acpi_thermal_state
{
138 struct acpi_thermal_state_flags
{
144 struct acpi_thermal_critical
{
145 struct acpi_thermal_state_flags flags
;
146 unsigned long temperature
;
149 struct acpi_thermal_hot
{
150 struct acpi_thermal_state_flags flags
;
151 unsigned long temperature
;
154 struct acpi_thermal_passive
{
155 struct acpi_thermal_state_flags flags
;
156 unsigned long temperature
;
160 struct acpi_handle_list devices
;
163 struct acpi_thermal_active
{
164 struct acpi_thermal_state_flags flags
;
165 unsigned long temperature
;
166 struct acpi_handle_list devices
;
169 struct acpi_thermal_trips
{
170 struct acpi_thermal_critical critical
;
171 struct acpi_thermal_hot hot
;
172 struct acpi_thermal_passive passive
;
173 struct acpi_thermal_active active
[ACPI_THERMAL_MAX_ACTIVE
];
176 struct acpi_thermal_flags
{
177 u8 cooling_mode
:1; /* _SCP */
178 u8 devices
:1; /* _TZD */
182 struct acpi_thermal
{
183 struct acpi_device
* device
;
185 unsigned long temperature
;
186 unsigned long last_temperature
;
187 unsigned long polling_frequency
;
189 struct acpi_thermal_flags flags
;
190 struct acpi_thermal_state state
;
191 struct acpi_thermal_trips trips
;
192 struct acpi_handle_list devices
;
193 struct thermal_zone_device
*thermal_zone
;
199 static const struct file_operations acpi_thermal_state_fops
= {
200 .owner
= THIS_MODULE
,
201 .open
= acpi_thermal_state_open_fs
,
204 .release
= single_release
,
207 static const struct file_operations acpi_thermal_temp_fops
= {
208 .owner
= THIS_MODULE
,
209 .open
= acpi_thermal_temp_open_fs
,
212 .release
= single_release
,
215 static const struct file_operations acpi_thermal_trip_fops
= {
216 .owner
= THIS_MODULE
,
217 .open
= acpi_thermal_trip_open_fs
,
220 .release
= single_release
,
223 static const struct file_operations acpi_thermal_cooling_fops
= {
224 .owner
= THIS_MODULE
,
225 .open
= acpi_thermal_cooling_open_fs
,
227 .write
= acpi_thermal_write_cooling_mode
,
229 .release
= single_release
,
232 static const struct file_operations acpi_thermal_polling_fops
= {
233 .owner
= THIS_MODULE
,
234 .open
= acpi_thermal_polling_open_fs
,
236 .write
= acpi_thermal_write_polling
,
238 .release
= single_release
,
241 /* --------------------------------------------------------------------------
242 Thermal Zone Management
243 -------------------------------------------------------------------------- */
245 static int acpi_thermal_get_temperature(struct acpi_thermal
*tz
)
247 acpi_status status
= AE_OK
;
248 unsigned long long tmp
;
253 tz
->last_temperature
= tz
->temperature
;
255 status
= acpi_evaluate_integer(tz
->device
->handle
, "_TMP", NULL
, &tmp
);
256 if (ACPI_FAILURE(status
))
259 tz
->temperature
= tmp
;
260 ACPI_DEBUG_PRINT((ACPI_DB_INFO
, "Temperature is %lu dK\n",
266 static int acpi_thermal_get_polling_frequency(struct acpi_thermal
*tz
)
268 acpi_status status
= AE_OK
;
269 unsigned long long tmp
;
274 status
= acpi_evaluate_integer(tz
->device
->handle
, "_TZP", NULL
, &tmp
);
275 if (ACPI_FAILURE(status
))
278 tz
->polling_frequency
= tmp
;
279 ACPI_DEBUG_PRINT((ACPI_DB_INFO
, "Polling frequency is %lu dS\n",
280 tz
->polling_frequency
));
285 static int acpi_thermal_set_polling(struct acpi_thermal
*tz
, int seconds
)
291 tz
->polling_frequency
= seconds
* 10; /* Convert value to deci-seconds */
293 tz
->thermal_zone
->polling_delay
= seconds
* 1000;
296 thermal_zone_device_update(tz
->thermal_zone
);
298 ACPI_DEBUG_PRINT((ACPI_DB_INFO
,
299 "Polling frequency set to %lu seconds\n",
300 tz
->polling_frequency
/10));
305 static int acpi_thermal_set_cooling_mode(struct acpi_thermal
*tz
, int mode
)
307 acpi_status status
= AE_OK
;
308 union acpi_object arg0
= { ACPI_TYPE_INTEGER
};
309 struct acpi_object_list arg_list
= { 1, &arg0
};
310 acpi_handle handle
= NULL
;
316 status
= acpi_get_handle(tz
->device
->handle
, "_SCP", &handle
);
317 if (ACPI_FAILURE(status
)) {
318 ACPI_DEBUG_PRINT((ACPI_DB_INFO
, "_SCP not present\n"));
322 arg0
.integer
.value
= mode
;
324 status
= acpi_evaluate_object(handle
, NULL
, &arg_list
, NULL
);
325 if (ACPI_FAILURE(status
))
331 #define ACPI_TRIPS_CRITICAL 0x01
332 #define ACPI_TRIPS_HOT 0x02
333 #define ACPI_TRIPS_PASSIVE 0x04
334 #define ACPI_TRIPS_ACTIVE 0x08
335 #define ACPI_TRIPS_DEVICES 0x10
337 #define ACPI_TRIPS_REFRESH_THRESHOLDS (ACPI_TRIPS_PASSIVE | ACPI_TRIPS_ACTIVE)
338 #define ACPI_TRIPS_REFRESH_DEVICES ACPI_TRIPS_DEVICES
340 #define ACPI_TRIPS_INIT (ACPI_TRIPS_CRITICAL | ACPI_TRIPS_HOT | \
341 ACPI_TRIPS_PASSIVE | ACPI_TRIPS_ACTIVE | \
345 * This exception is thrown out in two cases:
346 * 1.An invalid trip point becomes invalid or a valid trip point becomes invalid
347 * when re-evaluating the AML code.
348 * 2.TODO: Devices listed in _PSL, _ALx, _TZD may change.
349 * We need to re-bind the cooling devices of a thermal zone when this occurs.
351 #define ACPI_THERMAL_TRIPS_EXCEPTION(flags, str) \
353 if (flags != ACPI_TRIPS_INIT) \
354 ACPI_EXCEPTION((AE_INFO, AE_ERROR, \
355 "ACPI thermal trip point %s changed\n" \
356 "Please send acpidump to linux-acpi@vger.kernel.org\n", str)); \
359 static int acpi_thermal_trips_update(struct acpi_thermal
*tz
, int flag
)
361 acpi_status status
= AE_OK
;
362 unsigned long long tmp
;
363 struct acpi_handle_list devices
;
367 /* Critical Shutdown (required) */
368 if (flag
& ACPI_TRIPS_CRITICAL
) {
369 status
= acpi_evaluate_integer(tz
->device
->handle
,
371 tz
->trips
.critical
.temperature
= tmp
;
373 * Treat freezing temperatures as invalid as well; some
374 * BIOSes return really low values and cause reboots at startup.
375 * Below zero (Celsius) values clearly aren't right for sure..
376 * ... so lets discard those as invalid.
378 if (ACPI_FAILURE(status
) ||
379 tz
->trips
.critical
.temperature
<= 2732) {
380 tz
->trips
.critical
.flags
.valid
= 0;
381 ACPI_EXCEPTION((AE_INFO
, status
,
382 "No or invalid critical threshold"));
385 tz
->trips
.critical
.flags
.valid
= 1;
386 ACPI_DEBUG_PRINT((ACPI_DB_INFO
,
387 "Found critical threshold [%lu]\n",
388 tz
->trips
.critical
.temperature
));
390 if (tz
->trips
.critical
.flags
.valid
== 1) {
392 tz
->trips
.critical
.flags
.valid
= 0;
393 } else if (crt
> 0) {
394 unsigned long crt_k
= CELSIUS_TO_KELVIN(crt
);
396 * Allow override critical threshold
398 if (crt_k
> tz
->trips
.critical
.temperature
)
399 printk(KERN_WARNING PREFIX
400 "Critical threshold %d C\n", crt
);
401 tz
->trips
.critical
.temperature
= crt_k
;
406 /* Critical Sleep (optional) */
407 if (flag
& ACPI_TRIPS_HOT
) {
408 status
= acpi_evaluate_integer(tz
->device
->handle
,
410 if (ACPI_FAILURE(status
)) {
411 tz
->trips
.hot
.flags
.valid
= 0;
412 ACPI_DEBUG_PRINT((ACPI_DB_INFO
,
413 "No hot threshold\n"));
415 tz
->trips
.hot
.temperature
= tmp
;
416 tz
->trips
.hot
.flags
.valid
= 1;
417 ACPI_DEBUG_PRINT((ACPI_DB_INFO
,
418 "Found hot threshold [%lu]\n",
419 tz
->trips
.critical
.temperature
));
423 /* Passive (optional) */
424 if (((flag
& ACPI_TRIPS_PASSIVE
) && tz
->trips
.passive
.flags
.valid
) ||
425 (flag
== ACPI_TRIPS_INIT
)) {
426 valid
= tz
->trips
.passive
.flags
.valid
;
429 } else if (psv
> 0) {
430 tmp
= CELSIUS_TO_KELVIN(psv
);
433 status
= acpi_evaluate_integer(tz
->device
->handle
,
437 if (ACPI_FAILURE(status
))
438 tz
->trips
.passive
.flags
.valid
= 0;
440 tz
->trips
.passive
.temperature
= tmp
;
441 tz
->trips
.passive
.flags
.valid
= 1;
442 if (flag
== ACPI_TRIPS_INIT
) {
443 status
= acpi_evaluate_integer(
444 tz
->device
->handle
, "_TC1",
446 if (ACPI_FAILURE(status
))
447 tz
->trips
.passive
.flags
.valid
= 0;
449 tz
->trips
.passive
.tc1
= tmp
;
450 status
= acpi_evaluate_integer(
451 tz
->device
->handle
, "_TC2",
453 if (ACPI_FAILURE(status
))
454 tz
->trips
.passive
.flags
.valid
= 0;
456 tz
->trips
.passive
.tc2
= tmp
;
457 status
= acpi_evaluate_integer(
458 tz
->device
->handle
, "_TSP",
460 if (ACPI_FAILURE(status
))
461 tz
->trips
.passive
.flags
.valid
= 0;
463 tz
->trips
.passive
.tsp
= tmp
;
467 if ((flag
& ACPI_TRIPS_DEVICES
) && tz
->trips
.passive
.flags
.valid
) {
468 memset(&devices
, 0, sizeof(struct acpi_handle_list
));
469 status
= acpi_evaluate_reference(tz
->device
->handle
, "_PSL",
471 if (ACPI_FAILURE(status
)) {
472 printk(KERN_WARNING PREFIX
473 "Invalid passive threshold\n");
474 tz
->trips
.passive
.flags
.valid
= 0;
477 tz
->trips
.passive
.flags
.valid
= 1;
479 if (memcmp(&tz
->trips
.passive
.devices
, &devices
,
480 sizeof(struct acpi_handle_list
))) {
481 memcpy(&tz
->trips
.passive
.devices
, &devices
,
482 sizeof(struct acpi_handle_list
));
483 ACPI_THERMAL_TRIPS_EXCEPTION(flag
, "device");
486 if ((flag
& ACPI_TRIPS_PASSIVE
) || (flag
& ACPI_TRIPS_DEVICES
)) {
487 if (valid
!= tz
->trips
.passive
.flags
.valid
)
488 ACPI_THERMAL_TRIPS_EXCEPTION(flag
, "state");
491 /* Active (optional) */
492 for (i
= 0; i
< ACPI_THERMAL_MAX_ACTIVE
; i
++) {
493 char name
[5] = { '_', 'A', 'C', ('0' + i
), '\0' };
494 valid
= tz
->trips
.active
[i
].flags
.valid
;
497 break; /* disable all active trip points */
499 if ((flag
== ACPI_TRIPS_INIT
) || ((flag
& ACPI_TRIPS_ACTIVE
) &&
500 tz
->trips
.active
[i
].flags
.valid
)) {
501 status
= acpi_evaluate_integer(tz
->device
->handle
,
503 if (ACPI_FAILURE(status
)) {
504 tz
->trips
.active
[i
].flags
.valid
= 0;
510 tz
->trips
.active
[0].temperature
=
511 CELSIUS_TO_KELVIN(act
);
514 * Don't allow override higher than
515 * the next higher trip point
517 tz
->trips
.active
[i
- 1].temperature
=
518 (tz
->trips
.active
[i
- 2].temperature
<
519 CELSIUS_TO_KELVIN(act
) ?
520 tz
->trips
.active
[i
- 2].temperature
:
521 CELSIUS_TO_KELVIN(act
));
524 tz
->trips
.active
[i
].temperature
= tmp
;
525 tz
->trips
.active
[i
].flags
.valid
= 1;
530 if ((flag
& ACPI_TRIPS_DEVICES
) && tz
->trips
.active
[i
].flags
.valid
) {
531 memset(&devices
, 0, sizeof(struct acpi_handle_list
));
532 status
= acpi_evaluate_reference(tz
->device
->handle
,
533 name
, NULL
, &devices
);
534 if (ACPI_FAILURE(status
)) {
535 printk(KERN_WARNING PREFIX
536 "Invalid active%d threshold\n", i
);
537 tz
->trips
.active
[i
].flags
.valid
= 0;
540 tz
->trips
.active
[i
].flags
.valid
= 1;
542 if (memcmp(&tz
->trips
.active
[i
].devices
, &devices
,
543 sizeof(struct acpi_handle_list
))) {
544 memcpy(&tz
->trips
.active
[i
].devices
, &devices
,
545 sizeof(struct acpi_handle_list
));
546 ACPI_THERMAL_TRIPS_EXCEPTION(flag
, "device");
549 if ((flag
& ACPI_TRIPS_ACTIVE
) || (flag
& ACPI_TRIPS_DEVICES
))
550 if (valid
!= tz
->trips
.active
[i
].flags
.valid
)
551 ACPI_THERMAL_TRIPS_EXCEPTION(flag
, "state");
553 if (!tz
->trips
.active
[i
].flags
.valid
)
557 if (flag
& ACPI_TRIPS_DEVICES
) {
558 memset(&devices
, 0, sizeof(struct acpi_handle_list
));
559 status
= acpi_evaluate_reference(tz
->device
->handle
, "_TZD",
561 if (memcmp(&tz
->devices
, &devices
,
562 sizeof(struct acpi_handle_list
))) {
563 memcpy(&tz
->devices
, &devices
,
564 sizeof(struct acpi_handle_list
));
565 ACPI_THERMAL_TRIPS_EXCEPTION(flag
, "device");
572 static int acpi_thermal_get_trip_points(struct acpi_thermal
*tz
)
574 return acpi_thermal_trips_update(tz
, ACPI_TRIPS_INIT
);
577 static void acpi_thermal_check(void *data
)
579 struct acpi_thermal
*tz
= data
;
581 thermal_zone_device_update(tz
->thermal_zone
);
584 /* sys I/F for generic thermal sysfs support */
585 #define KELVIN_TO_MILLICELSIUS(t, off) (((t) - (off)) * 100)
587 static int thermal_get_temp(struct thermal_zone_device
*thermal
,
590 struct acpi_thermal
*tz
= thermal
->devdata
;
596 result
= acpi_thermal_get_temperature(tz
);
600 *temp
= KELVIN_TO_MILLICELSIUS(tz
->temperature
, tz
->kelvin_offset
);
604 static const char enabled
[] = "kernel";
605 static const char disabled
[] = "user";
606 static int thermal_get_mode(struct thermal_zone_device
*thermal
,
607 enum thermal_device_mode
*mode
)
609 struct acpi_thermal
*tz
= thermal
->devdata
;
614 *mode
= tz
->tz_enabled
? THERMAL_DEVICE_ENABLED
:
615 THERMAL_DEVICE_DISABLED
;
620 static int thermal_set_mode(struct thermal_zone_device
*thermal
,
621 enum thermal_device_mode mode
)
623 struct acpi_thermal
*tz
= thermal
->devdata
;
630 * enable/disable thermal management from ACPI thermal driver
632 if (mode
== THERMAL_DEVICE_ENABLED
)
634 else if (mode
== THERMAL_DEVICE_DISABLED
)
639 if (enable
!= tz
->tz_enabled
) {
640 tz
->tz_enabled
= enable
;
641 ACPI_DEBUG_PRINT((ACPI_DB_INFO
,
642 "%s ACPI thermal control\n",
643 tz
->tz_enabled
? enabled
: disabled
));
644 acpi_thermal_check(tz
);
649 static int thermal_get_trip_type(struct thermal_zone_device
*thermal
,
650 int trip
, enum thermal_trip_type
*type
)
652 struct acpi_thermal
*tz
= thermal
->devdata
;
658 if (tz
->trips
.critical
.flags
.valid
) {
660 *type
= THERMAL_TRIP_CRITICAL
;
666 if (tz
->trips
.hot
.flags
.valid
) {
668 *type
= THERMAL_TRIP_HOT
;
674 if (tz
->trips
.passive
.flags
.valid
) {
676 *type
= THERMAL_TRIP_PASSIVE
;
682 for (i
= 0; i
< ACPI_THERMAL_MAX_ACTIVE
&&
683 tz
->trips
.active
[i
].flags
.valid
; i
++) {
685 *type
= THERMAL_TRIP_ACTIVE
;
694 static int thermal_get_trip_temp(struct thermal_zone_device
*thermal
,
695 int trip
, unsigned long *temp
)
697 struct acpi_thermal
*tz
= thermal
->devdata
;
703 if (tz
->trips
.critical
.flags
.valid
) {
705 *temp
= KELVIN_TO_MILLICELSIUS(
706 tz
->trips
.critical
.temperature
,
713 if (tz
->trips
.hot
.flags
.valid
) {
715 *temp
= KELVIN_TO_MILLICELSIUS(
716 tz
->trips
.hot
.temperature
,
723 if (tz
->trips
.passive
.flags
.valid
) {
725 *temp
= KELVIN_TO_MILLICELSIUS(
726 tz
->trips
.passive
.temperature
,
733 for (i
= 0; i
< ACPI_THERMAL_MAX_ACTIVE
&&
734 tz
->trips
.active
[i
].flags
.valid
; i
++) {
736 *temp
= KELVIN_TO_MILLICELSIUS(
737 tz
->trips
.active
[i
].temperature
,
747 static int thermal_get_crit_temp(struct thermal_zone_device
*thermal
,
748 unsigned long *temperature
) {
749 struct acpi_thermal
*tz
= thermal
->devdata
;
751 if (tz
->trips
.critical
.flags
.valid
) {
752 *temperature
= KELVIN_TO_MILLICELSIUS(
753 tz
->trips
.critical
.temperature
,
760 static int thermal_notify(struct thermal_zone_device
*thermal
, int trip
,
761 enum thermal_trip_type trip_type
)
764 struct acpi_thermal
*tz
= thermal
->devdata
;
766 if (trip_type
== THERMAL_TRIP_CRITICAL
)
767 type
= ACPI_THERMAL_NOTIFY_CRITICAL
;
768 else if (trip_type
== THERMAL_TRIP_HOT
)
769 type
= ACPI_THERMAL_NOTIFY_HOT
;
773 acpi_bus_generate_proc_event(tz
->device
, type
, 1);
774 acpi_bus_generate_netlink_event(tz
->device
->pnp
.device_class
,
775 dev_name(&tz
->device
->dev
), type
, 1);
777 if (trip_type
== THERMAL_TRIP_CRITICAL
&& nocrt
)
783 typedef int (*cb
)(struct thermal_zone_device
*, int,
784 struct thermal_cooling_device
*);
785 static int acpi_thermal_cooling_device_cb(struct thermal_zone_device
*thermal
,
786 struct thermal_cooling_device
*cdev
,
789 struct acpi_device
*device
= cdev
->devdata
;
790 struct acpi_thermal
*tz
= thermal
->devdata
;
791 struct acpi_device
*dev
;
799 if (tz
->trips
.critical
.flags
.valid
)
802 if (tz
->trips
.hot
.flags
.valid
)
805 if (tz
->trips
.passive
.flags
.valid
) {
807 for (i
= 0; i
< tz
->trips
.passive
.devices
.count
;
809 handle
= tz
->trips
.passive
.devices
.handles
[i
];
810 status
= acpi_bus_get_device(handle
, &dev
);
811 if (ACPI_SUCCESS(status
) && (dev
== device
)) {
812 result
= action(thermal
, trip
, cdev
);
819 for (i
= 0; i
< ACPI_THERMAL_MAX_ACTIVE
; i
++) {
820 if (!tz
->trips
.active
[i
].flags
.valid
)
824 j
< tz
->trips
.active
[i
].devices
.count
;
826 handle
= tz
->trips
.active
[i
].devices
.handles
[j
];
827 status
= acpi_bus_get_device(handle
, &dev
);
828 if (ACPI_SUCCESS(status
) && (dev
== device
)) {
829 result
= action(thermal
, trip
, cdev
);
836 for (i
= 0; i
< tz
->devices
.count
; i
++) {
837 handle
= tz
->devices
.handles
[i
];
838 status
= acpi_bus_get_device(handle
, &dev
);
839 if (ACPI_SUCCESS(status
) && (dev
== device
)) {
840 result
= action(thermal
, -1, cdev
);
851 acpi_thermal_bind_cooling_device(struct thermal_zone_device
*thermal
,
852 struct thermal_cooling_device
*cdev
)
854 return acpi_thermal_cooling_device_cb(thermal
, cdev
,
855 thermal_zone_bind_cooling_device
);
859 acpi_thermal_unbind_cooling_device(struct thermal_zone_device
*thermal
,
860 struct thermal_cooling_device
*cdev
)
862 return acpi_thermal_cooling_device_cb(thermal
, cdev
,
863 thermal_zone_unbind_cooling_device
);
866 static struct thermal_zone_device_ops acpi_thermal_zone_ops
= {
867 .bind
= acpi_thermal_bind_cooling_device
,
868 .unbind
= acpi_thermal_unbind_cooling_device
,
869 .get_temp
= thermal_get_temp
,
870 .get_mode
= thermal_get_mode
,
871 .set_mode
= thermal_set_mode
,
872 .get_trip_type
= thermal_get_trip_type
,
873 .get_trip_temp
= thermal_get_trip_temp
,
874 .get_crit_temp
= thermal_get_crit_temp
,
875 .notify
= thermal_notify
,
878 static int acpi_thermal_register_thermal_zone(struct acpi_thermal
*tz
)
885 if (tz
->trips
.critical
.flags
.valid
)
888 if (tz
->trips
.hot
.flags
.valid
)
891 if (tz
->trips
.passive
.flags
.valid
)
894 for (i
= 0; i
< ACPI_THERMAL_MAX_ACTIVE
&&
895 tz
->trips
.active
[i
].flags
.valid
; i
++, trips
++);
897 if (tz
->trips
.passive
.flags
.valid
)
899 thermal_zone_device_register("acpitz", trips
, tz
,
900 &acpi_thermal_zone_ops
,
901 tz
->trips
.passive
.tc1
,
902 tz
->trips
.passive
.tc2
,
903 tz
->trips
.passive
.tsp
*100,
904 tz
->polling_frequency
*100);
907 thermal_zone_device_register("acpitz", trips
, tz
,
908 &acpi_thermal_zone_ops
,
910 tz
->polling_frequency
);
911 if (IS_ERR(tz
->thermal_zone
))
914 result
= sysfs_create_link(&tz
->device
->dev
.kobj
,
915 &tz
->thermal_zone
->device
.kobj
, "thermal_zone");
919 result
= sysfs_create_link(&tz
->thermal_zone
->device
.kobj
,
920 &tz
->device
->dev
.kobj
, "device");
924 status
= acpi_attach_data(tz
->device
->handle
,
925 acpi_bus_private_data_handler
,
927 if (ACPI_FAILURE(status
)) {
928 printk(KERN_ERR PREFIX
929 "Error attaching device data\n");
935 dev_info(&tz
->device
->dev
, "registered as thermal_zone%d\n",
936 tz
->thermal_zone
->id
);
940 static void acpi_thermal_unregister_thermal_zone(struct acpi_thermal
*tz
)
942 sysfs_remove_link(&tz
->device
->dev
.kobj
, "thermal_zone");
943 sysfs_remove_link(&tz
->thermal_zone
->device
.kobj
, "device");
944 thermal_zone_device_unregister(tz
->thermal_zone
);
945 tz
->thermal_zone
= NULL
;
946 acpi_detach_data(tz
->device
->handle
, acpi_bus_private_data_handler
);
950 /* --------------------------------------------------------------------------
952 -------------------------------------------------------------------------- */
954 static struct proc_dir_entry
*acpi_thermal_dir
;
956 static int acpi_thermal_state_seq_show(struct seq_file
*seq
, void *offset
)
958 struct acpi_thermal
*tz
= seq
->private;
964 seq_puts(seq
, "state: ");
966 if (!tz
->state
.critical
&& !tz
->state
.hot
&& !tz
->state
.passive
967 && !tz
->state
.active
)
968 seq_puts(seq
, "ok\n");
970 if (tz
->state
.critical
)
971 seq_puts(seq
, "critical ");
973 seq_puts(seq
, "hot ");
974 if (tz
->state
.passive
)
975 seq_puts(seq
, "passive ");
976 if (tz
->state
.active
)
977 seq_printf(seq
, "active[%d]", tz
->state
.active_index
);
985 static int acpi_thermal_state_open_fs(struct inode
*inode
, struct file
*file
)
987 return single_open(file
, acpi_thermal_state_seq_show
, PDE(inode
)->data
);
990 static int acpi_thermal_temp_seq_show(struct seq_file
*seq
, void *offset
)
993 struct acpi_thermal
*tz
= seq
->private;
999 result
= acpi_thermal_get_temperature(tz
);
1003 seq_printf(seq
, "temperature: %ld C\n",
1004 KELVIN_TO_CELSIUS(tz
->temperature
));
1010 static int acpi_thermal_temp_open_fs(struct inode
*inode
, struct file
*file
)
1012 return single_open(file
, acpi_thermal_temp_seq_show
, PDE(inode
)->data
);
1015 static int acpi_thermal_trip_seq_show(struct seq_file
*seq
, void *offset
)
1017 struct acpi_thermal
*tz
= seq
->private;
1018 struct acpi_device
*device
;
1028 if (tz
->trips
.critical
.flags
.valid
)
1029 seq_printf(seq
, "critical (S5): %ld C%s",
1030 KELVIN_TO_CELSIUS(tz
->trips
.critical
.temperature
),
1031 nocrt
? " <disabled>\n" : "\n");
1033 if (tz
->trips
.hot
.flags
.valid
)
1034 seq_printf(seq
, "hot (S4): %ld C%s",
1035 KELVIN_TO_CELSIUS(tz
->trips
.hot
.temperature
),
1036 nocrt
? " <disabled>\n" : "\n");
1038 if (tz
->trips
.passive
.flags
.valid
) {
1040 "passive: %ld C: tc1=%lu tc2=%lu tsp=%lu devices=",
1041 KELVIN_TO_CELSIUS(tz
->trips
.passive
.temperature
),
1042 tz
->trips
.passive
.tc1
, tz
->trips
.passive
.tc2
,
1043 tz
->trips
.passive
.tsp
);
1044 for (j
= 0; j
< tz
->trips
.passive
.devices
.count
; j
++) {
1045 status
= acpi_bus_get_device(tz
->trips
.passive
.devices
.
1046 handles
[j
], &device
);
1047 seq_printf(seq
, "%4.4s ", status
? "" :
1048 acpi_device_bid(device
));
1050 seq_puts(seq
, "\n");
1053 for (i
= 0; i
< ACPI_THERMAL_MAX_ACTIVE
; i
++) {
1054 if (!(tz
->trips
.active
[i
].flags
.valid
))
1056 seq_printf(seq
, "active[%d]: %ld C: devices=",
1058 KELVIN_TO_CELSIUS(tz
->trips
.active
[i
].temperature
));
1059 for (j
= 0; j
< tz
->trips
.active
[i
].devices
.count
; j
++){
1060 status
= acpi_bus_get_device(tz
->trips
.active
[i
].
1063 seq_printf(seq
, "%4.4s ", status
? "" :
1064 acpi_device_bid(device
));
1066 seq_puts(seq
, "\n");
1073 static int acpi_thermal_trip_open_fs(struct inode
*inode
, struct file
*file
)
1075 return single_open(file
, acpi_thermal_trip_seq_show
, PDE(inode
)->data
);
1078 static int acpi_thermal_cooling_seq_show(struct seq_file
*seq
, void *offset
)
1080 struct acpi_thermal
*tz
= seq
->private;
1086 if (!tz
->flags
.cooling_mode
)
1087 seq_puts(seq
, "<setting not supported>\n");
1089 seq_puts(seq
, "0 - Active; 1 - Passive\n");
1095 static int acpi_thermal_cooling_open_fs(struct inode
*inode
, struct file
*file
)
1097 return single_open(file
, acpi_thermal_cooling_seq_show
,
1102 acpi_thermal_write_cooling_mode(struct file
*file
,
1103 const char __user
* buffer
,
1104 size_t count
, loff_t
* ppos
)
1106 struct seq_file
*m
= file
->private_data
;
1107 struct acpi_thermal
*tz
= m
->private;
1109 char mode_string
[12] = { '\0' };
1112 if (!tz
|| (count
> sizeof(mode_string
) - 1))
1115 if (!tz
->flags
.cooling_mode
)
1118 if (copy_from_user(mode_string
, buffer
, count
))
1121 mode_string
[count
] = '\0';
1123 result
= acpi_thermal_set_cooling_mode(tz
,
1124 simple_strtoul(mode_string
, NULL
,
1129 acpi_thermal_check(tz
);
1134 static int acpi_thermal_polling_seq_show(struct seq_file
*seq
, void *offset
)
1136 struct acpi_thermal
*tz
= seq
->private;
1142 if (!tz
->thermal_zone
->polling_delay
) {
1143 seq_puts(seq
, "<polling disabled>\n");
1147 seq_printf(seq
, "polling frequency: %d seconds\n",
1148 (tz
->thermal_zone
->polling_delay
/ 1000));
1154 static int acpi_thermal_polling_open_fs(struct inode
*inode
, struct file
*file
)
1156 return single_open(file
, acpi_thermal_polling_seq_show
,
1161 acpi_thermal_write_polling(struct file
*file
,
1162 const char __user
* buffer
,
1163 size_t count
, loff_t
* ppos
)
1165 struct seq_file
*m
= file
->private_data
;
1166 struct acpi_thermal
*tz
= m
->private;
1168 char polling_string
[12] = { '\0' };
1172 if (!tz
|| (count
> sizeof(polling_string
) - 1))
1175 if (copy_from_user(polling_string
, buffer
, count
))
1178 polling_string
[count
] = '\0';
1180 seconds
= simple_strtoul(polling_string
, NULL
, 0);
1182 result
= acpi_thermal_set_polling(tz
, seconds
);
1186 acpi_thermal_check(tz
);
1191 static int acpi_thermal_add_fs(struct acpi_device
*device
)
1193 struct proc_dir_entry
*entry
= NULL
;
1196 if (!acpi_device_dir(device
)) {
1197 acpi_device_dir(device
) = proc_mkdir(acpi_device_bid(device
),
1199 if (!acpi_device_dir(device
))
1204 entry
= proc_create_data(ACPI_THERMAL_FILE_STATE
,
1205 S_IRUGO
, acpi_device_dir(device
),
1206 &acpi_thermal_state_fops
,
1207 acpi_driver_data(device
));
1211 /* 'temperature' [R] */
1212 entry
= proc_create_data(ACPI_THERMAL_FILE_TEMPERATURE
,
1213 S_IRUGO
, acpi_device_dir(device
),
1214 &acpi_thermal_temp_fops
,
1215 acpi_driver_data(device
));
1219 /* 'trip_points' [R] */
1220 entry
= proc_create_data(ACPI_THERMAL_FILE_TRIP_POINTS
,
1222 acpi_device_dir(device
),
1223 &acpi_thermal_trip_fops
,
1224 acpi_driver_data(device
));
1228 /* 'cooling_mode' [R/W] */
1229 entry
= proc_create_data(ACPI_THERMAL_FILE_COOLING_MODE
,
1230 S_IFREG
| S_IRUGO
| S_IWUSR
,
1231 acpi_device_dir(device
),
1232 &acpi_thermal_cooling_fops
,
1233 acpi_driver_data(device
));
1237 /* 'polling_frequency' [R/W] */
1238 entry
= proc_create_data(ACPI_THERMAL_FILE_POLLING_FREQ
,
1239 S_IFREG
| S_IRUGO
| S_IWUSR
,
1240 acpi_device_dir(device
),
1241 &acpi_thermal_polling_fops
,
1242 acpi_driver_data(device
));
1248 static int acpi_thermal_remove_fs(struct acpi_device
*device
)
1251 if (acpi_device_dir(device
)) {
1252 remove_proc_entry(ACPI_THERMAL_FILE_POLLING_FREQ
,
1253 acpi_device_dir(device
));
1254 remove_proc_entry(ACPI_THERMAL_FILE_COOLING_MODE
,
1255 acpi_device_dir(device
));
1256 remove_proc_entry(ACPI_THERMAL_FILE_TRIP_POINTS
,
1257 acpi_device_dir(device
));
1258 remove_proc_entry(ACPI_THERMAL_FILE_TEMPERATURE
,
1259 acpi_device_dir(device
));
1260 remove_proc_entry(ACPI_THERMAL_FILE_STATE
,
1261 acpi_device_dir(device
));
1262 remove_proc_entry(acpi_device_bid(device
), acpi_thermal_dir
);
1263 acpi_device_dir(device
) = NULL
;
1269 /* --------------------------------------------------------------------------
1271 -------------------------------------------------------------------------- */
1273 static void acpi_thermal_notify(acpi_handle handle
, u32 event
, void *data
)
1275 struct acpi_thermal
*tz
= data
;
1276 struct acpi_device
*device
= NULL
;
1282 device
= tz
->device
;
1285 case ACPI_THERMAL_NOTIFY_TEMPERATURE
:
1286 acpi_thermal_check(tz
);
1288 case ACPI_THERMAL_NOTIFY_THRESHOLDS
:
1289 acpi_thermal_trips_update(tz
, ACPI_TRIPS_REFRESH_THRESHOLDS
);
1290 acpi_thermal_check(tz
);
1291 acpi_bus_generate_proc_event(device
, event
, 0);
1292 acpi_bus_generate_netlink_event(device
->pnp
.device_class
,
1293 dev_name(&device
->dev
), event
, 0);
1295 case ACPI_THERMAL_NOTIFY_DEVICES
:
1296 acpi_thermal_trips_update(tz
, ACPI_TRIPS_REFRESH_DEVICES
);
1297 acpi_thermal_check(tz
);
1298 acpi_bus_generate_proc_event(device
, event
, 0);
1299 acpi_bus_generate_netlink_event(device
->pnp
.device_class
,
1300 dev_name(&device
->dev
), event
, 0);
1303 ACPI_DEBUG_PRINT((ACPI_DB_INFO
,
1304 "Unsupported event [0x%x]\n", event
));
1311 static int acpi_thermal_get_info(struct acpi_thermal
*tz
)
1319 /* Get temperature [_TMP] (required) */
1320 result
= acpi_thermal_get_temperature(tz
);
1324 /* Get trip points [_CRT, _PSV, etc.] (required) */
1325 result
= acpi_thermal_get_trip_points(tz
);
1329 /* Set the cooling mode [_SCP] to active cooling (default) */
1330 result
= acpi_thermal_set_cooling_mode(tz
, ACPI_THERMAL_MODE_ACTIVE
);
1332 tz
->flags
.cooling_mode
= 1;
1334 /* Get default polling frequency [_TZP] (optional) */
1336 tz
->polling_frequency
= tzp
;
1338 acpi_thermal_get_polling_frequency(tz
);
1344 * The exact offset between Kelvin and degree Celsius is 273.15. However ACPI
1345 * handles temperature values with a single decimal place. As a consequence,
1346 * some implementations use an offset of 273.1 and others use an offset of
1347 * 273.2. Try to find out which one is being used, to present the most
1348 * accurate and visually appealing number.
1350 * The heuristic below should work for all ACPI thermal zones which have a
1351 * critical trip point with a value being a multiple of 0.5 degree Celsius.
1353 static void acpi_thermal_guess_offset(struct acpi_thermal
*tz
)
1355 if (tz
->trips
.critical
.flags
.valid
&&
1356 (tz
->trips
.critical
.temperature
% 5) == 1)
1357 tz
->kelvin_offset
= 2731;
1359 tz
->kelvin_offset
= 2732;
1362 static int acpi_thermal_add(struct acpi_device
*device
)
1365 acpi_status status
= AE_OK
;
1366 struct acpi_thermal
*tz
= NULL
;
1372 tz
= kzalloc(sizeof(struct acpi_thermal
), GFP_KERNEL
);
1376 tz
->device
= device
;
1377 strcpy(tz
->name
, device
->pnp
.bus_id
);
1378 strcpy(acpi_device_name(device
), ACPI_THERMAL_DEVICE_NAME
);
1379 strcpy(acpi_device_class(device
), ACPI_THERMAL_CLASS
);
1380 device
->driver_data
= tz
;
1381 mutex_init(&tz
->lock
);
1384 result
= acpi_thermal_get_info(tz
);
1388 acpi_thermal_guess_offset(tz
);
1390 result
= acpi_thermal_register_thermal_zone(tz
);
1394 result
= acpi_thermal_add_fs(device
);
1396 goto unregister_thermal_zone
;
1398 status
= acpi_install_notify_handler(device
->handle
,
1400 acpi_thermal_notify
, tz
);
1401 if (ACPI_FAILURE(status
)) {
1406 printk(KERN_INFO PREFIX
"%s [%s] (%ld C)\n",
1407 acpi_device_name(device
), acpi_device_bid(device
),
1408 KELVIN_TO_CELSIUS(tz
->temperature
));
1412 acpi_thermal_remove_fs(device
);
1413 unregister_thermal_zone
:
1414 thermal_zone_device_unregister(tz
->thermal_zone
);
1421 static int acpi_thermal_remove(struct acpi_device
*device
, int type
)
1423 acpi_status status
= AE_OK
;
1424 struct acpi_thermal
*tz
= NULL
;
1426 if (!device
|| !acpi_driver_data(device
))
1429 tz
= acpi_driver_data(device
);
1431 status
= acpi_remove_notify_handler(device
->handle
,
1433 acpi_thermal_notify
);
1435 acpi_thermal_remove_fs(device
);
1436 acpi_thermal_unregister_thermal_zone(tz
);
1437 mutex_destroy(&tz
->lock
);
1442 static int acpi_thermal_resume(struct acpi_device
*device
)
1444 struct acpi_thermal
*tz
= NULL
;
1445 int i
, j
, power_state
, result
;
1448 if (!device
|| !acpi_driver_data(device
))
1451 tz
= acpi_driver_data(device
);
1453 for (i
= 0; i
< ACPI_THERMAL_MAX_ACTIVE
; i
++) {
1454 if (!(&tz
->trips
.active
[i
]))
1456 if (!tz
->trips
.active
[i
].flags
.valid
)
1458 tz
->trips
.active
[i
].flags
.enabled
= 1;
1459 for (j
= 0; j
< tz
->trips
.active
[i
].devices
.count
; j
++) {
1460 result
= acpi_bus_get_power(tz
->trips
.active
[i
].devices
.
1461 handles
[j
], &power_state
);
1462 if (result
|| (power_state
!= ACPI_STATE_D0
)) {
1463 tz
->trips
.active
[i
].flags
.enabled
= 0;
1467 tz
->state
.active
|= tz
->trips
.active
[i
].flags
.enabled
;
1470 acpi_thermal_check(tz
);
1475 static int thermal_act(const struct dmi_system_id
*d
) {
1478 printk(KERN_NOTICE
"ACPI: %s detected: "
1479 "disabling all active thermal trip points\n", d
->ident
);
1484 static int thermal_nocrt(const struct dmi_system_id
*d
) {
1486 printk(KERN_NOTICE
"ACPI: %s detected: "
1487 "disabling all critical thermal trip point actions.\n", d
->ident
);
1491 static int thermal_tzp(const struct dmi_system_id
*d
) {
1494 printk(KERN_NOTICE
"ACPI: %s detected: "
1495 "enabling thermal zone polling\n", d
->ident
);
1496 tzp
= 300; /* 300 dS = 30 Seconds */
1500 static int thermal_psv(const struct dmi_system_id
*d
) {
1503 printk(KERN_NOTICE
"ACPI: %s detected: "
1504 "disabling all passive thermal trip points\n", d
->ident
);
1510 static struct dmi_system_id thermal_dmi_table
[] __initdata
= {
1512 * Award BIOS on this AOpen makes thermal control almost worthless.
1513 * http://bugzilla.kernel.org/show_bug.cgi?id=8842
1516 .callback
= thermal_act
,
1517 .ident
= "AOpen i915GMm-HFS",
1519 DMI_MATCH(DMI_BOARD_VENDOR
, "AOpen"),
1520 DMI_MATCH(DMI_BOARD_NAME
, "i915GMm-HFS"),
1524 .callback
= thermal_psv
,
1525 .ident
= "AOpen i915GMm-HFS",
1527 DMI_MATCH(DMI_BOARD_VENDOR
, "AOpen"),
1528 DMI_MATCH(DMI_BOARD_NAME
, "i915GMm-HFS"),
1532 .callback
= thermal_tzp
,
1533 .ident
= "AOpen i915GMm-HFS",
1535 DMI_MATCH(DMI_BOARD_VENDOR
, "AOpen"),
1536 DMI_MATCH(DMI_BOARD_NAME
, "i915GMm-HFS"),
1540 .callback
= thermal_nocrt
,
1541 .ident
= "Gigabyte GA-7ZX",
1543 DMI_MATCH(DMI_BOARD_VENDOR
, "Gigabyte Technology Co., Ltd."),
1544 DMI_MATCH(DMI_BOARD_NAME
, "7ZX"),
1550 static int __init
acpi_thermal_init(void)
1554 dmi_check_system(thermal_dmi_table
);
1557 printk(KERN_NOTICE
"ACPI: thermal control disabled\n");
1560 acpi_thermal_dir
= proc_mkdir(ACPI_THERMAL_CLASS
, acpi_root_dir
);
1561 if (!acpi_thermal_dir
)
1564 result
= acpi_bus_register_driver(&acpi_thermal_driver
);
1566 remove_proc_entry(ACPI_THERMAL_CLASS
, acpi_root_dir
);
1573 static void __exit
acpi_thermal_exit(void)
1576 acpi_bus_unregister_driver(&acpi_thermal_driver
);
1578 remove_proc_entry(ACPI_THERMAL_CLASS
, acpi_root_dir
);
1583 module_init(acpi_thermal_init
);
1584 module_exit(acpi_thermal_exit
);