aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/acpi/thermal.c
diff options
context:
space:
mode:
authorZhang Rui <rui.zhang@intel.com>2008-01-17 02:51:11 -0500
committerLen Brown <len.brown@intel.com>2008-02-01 23:12:19 -0500
commit3f655ef8c439e0775ffb7d1ead5d1d4f060e1f8b (patch)
tree9ac375f1f4c54a698e3f2736497193c0f00d638c /drivers/acpi/thermal.c
parent203d3d4aa482339b4816f131f713e1b8ee37f6dd (diff)
ACPI: register ACPI thermal zone as generic thermal zone devices
Register ACPI thermal zone as thermal zone device. the new sys I/F for ACPI thermal zone will be like this: /sys/class/thermal: |thermal_zone1: |-----type: "ACPI thermal zone". RO |-----temp: the current temperature. RO |-----mode: the current working mode. RW. the default value is "kernel" which means thermal management is done by ACPI thermal driver. "echo user > mode" prevents all the ACPI thermal driver actions upon any trip points. |-----trip_point_0_temp: the threshold of trip point 0. RO. |-----trip_point_0_type: "critical". RO. the type of trip point 0 This may be one of critical/hot/passive/active[x] for an ACPI thermal zone. ... |-----trip_point_3_temp: |-----trip_point_3_type: "active[1]" Signed-off-by: Zhang Rui <rui.zhang@intel.com> Signed-off-by: Thomas Sujith <sujith.thomas@intel.com> Signed-off-by: Len Brown <len.brown@intel.com>
Diffstat (limited to 'drivers/acpi/thermal.c')
-rw-r--r--drivers/acpi/thermal.c301
1 files changed, 291 insertions, 10 deletions
diff --git a/drivers/acpi/thermal.c b/drivers/acpi/thermal.c
index 5f79b4451212..c6cfce4c0122 100644
--- a/drivers/acpi/thermal.c
+++ b/drivers/acpi/thermal.c
@@ -43,7 +43,7 @@
43#include <linux/seq_file.h> 43#include <linux/seq_file.h>
44#include <linux/reboot.h> 44#include <linux/reboot.h>
45#include <asm/uaccess.h> 45#include <asm/uaccess.h>
46 46#include <linux/thermal.h>
47#include <acpi/acpi_bus.h> 47#include <acpi/acpi_bus.h>
48#include <acpi/acpi_drivers.h> 48#include <acpi/acpi_drivers.h>
49 49
@@ -195,6 +195,8 @@ struct acpi_thermal {
195 struct acpi_thermal_trips trips; 195 struct acpi_thermal_trips trips;
196 struct acpi_handle_list devices; 196 struct acpi_handle_list devices;
197 struct timer_list timer; 197 struct timer_list timer;
198 struct thermal_zone_device *thermal_zone;
199 int tz_enabled;
198 struct mutex lock; 200 struct mutex lock;
199}; 201};
200 202
@@ -732,6 +734,9 @@ static void acpi_thermal_check(void *data)
732 if (result) 734 if (result)
733 goto unlock; 735 goto unlock;
734 736
737 if (!tz->tz_enabled)
738 goto unlock;
739
735 memset(&tz->state, 0, sizeof(tz->state)); 740 memset(&tz->state, 0, sizeof(tz->state));
736 741
737 /* 742 /*
@@ -825,6 +830,273 @@ static void acpi_thermal_check(void *data)
825 mutex_unlock(&tz->lock); 830 mutex_unlock(&tz->lock);
826} 831}
827 832
833/* sys I/F for generic thermal sysfs support */
834static int thermal_get_temp(struct thermal_zone_device *thermal, char *buf)
835{
836 struct acpi_thermal *tz = thermal->devdata;
837
838 if (!tz)
839 return -EINVAL;
840
841 return sprintf(buf, "%ld\n", KELVIN_TO_CELSIUS(tz->temperature));
842}
843
844static const char enabled[] = "kernel";
845static const char disabled[] = "user";
846static int thermal_get_mode(struct thermal_zone_device *thermal,
847 char *buf)
848{
849 struct acpi_thermal *tz = thermal->devdata;
850
851 if (!tz)
852 return -EINVAL;
853
854 return sprintf(buf, "%s\n", tz->tz_enabled ?
855 enabled : disabled);
856}
857
858static int thermal_set_mode(struct thermal_zone_device *thermal,
859 const char *buf)
860{
861 struct acpi_thermal *tz = thermal->devdata;
862 int enable;
863
864 if (!tz)
865 return -EINVAL;
866
867 /*
868 * enable/disable thermal management from ACPI thermal driver
869 */
870 if (!strncmp(buf, enabled, sizeof enabled - 1))
871 enable = 1;
872 else if (!strncmp(buf, disabled, sizeof disabled - 1))
873 enable = 0;
874 else
875 return -EINVAL;
876
877 if (enable != tz->tz_enabled) {
878 tz->tz_enabled = enable;
879 ACPI_DEBUG_PRINT((ACPI_DB_INFO,
880 "%s ACPI thermal control\n",
881 tz->tz_enabled ? enabled : disabled));
882 acpi_thermal_check(tz);
883 }
884 return 0;
885}
886
887static int thermal_get_trip_type(struct thermal_zone_device *thermal,
888 int trip, char *buf)
889{
890 struct acpi_thermal *tz = thermal->devdata;
891 int i;
892
893 if (!tz || trip < 0)
894 return -EINVAL;
895
896 if (tz->trips.critical.flags.valid) {
897 if (!trip)
898 return sprintf(buf, "critical\n");
899 trip--;
900 }
901
902 if (tz->trips.hot.flags.valid) {
903 if (!trip)
904 return sprintf(buf, "hot\n");
905 trip--;
906 }
907
908 if (tz->trips.passive.flags.valid) {
909 if (!trip)
910 return sprintf(buf, "passive\n");
911 trip--;
912 }
913
914 for (i = 0; i < ACPI_THERMAL_MAX_ACTIVE &&
915 tz->trips.active[i].flags.valid; i++) {
916 if (!trip)
917 return sprintf(buf, "active%d\n", i);
918 trip--;
919 }
920
921 return -EINVAL;
922}
923
924static int thermal_get_trip_temp(struct thermal_zone_device *thermal,
925 int trip, char *buf)
926{
927 struct acpi_thermal *tz = thermal->devdata;
928 int i;
929
930 if (!tz || trip < 0)
931 return -EINVAL;
932
933 if (tz->trips.critical.flags.valid) {
934 if (!trip)
935 return sprintf(buf, "%ld\n", KELVIN_TO_CELSIUS(
936 tz->trips.critical.temperature));
937 trip--;
938 }
939
940 if (tz->trips.hot.flags.valid) {
941 if (!trip)
942 return sprintf(buf, "%ld\n", KELVIN_TO_CELSIUS(
943 tz->trips.hot.temperature));
944 trip--;
945 }
946
947 if (tz->trips.passive.flags.valid) {
948 if (!trip)
949 return sprintf(buf, "%ld\n", KELVIN_TO_CELSIUS(
950 tz->trips.passive.temperature));
951 trip--;
952 }
953
954 for (i = 0; i < ACPI_THERMAL_MAX_ACTIVE &&
955 tz->trips.active[i].flags.valid; i++) {
956 if (!trip)
957 return sprintf(buf, "%ld\n", KELVIN_TO_CELSIUS(
958 tz->trips.active[i].temperature));
959 trip--;
960 }
961
962 return -EINVAL;
963}
964
965typedef int (*cb)(struct thermal_zone_device *, int,
966 struct thermal_cooling_device *);
967static int acpi_thermal_cooling_device_cb(struct thermal_zone_device *thermal,
968 struct thermal_cooling_device *cdev,
969 cb action)
970{
971 struct acpi_device *device = cdev->devdata;
972 struct acpi_thermal *tz = thermal->devdata;
973 acpi_handle handle = device->handle;
974 int i;
975 int j;
976 int trip = -1;
977 int result = 0;
978
979 if (tz->trips.critical.flags.valid)
980 trip++;
981
982 if (tz->trips.hot.flags.valid)
983 trip++;
984
985 if (tz->trips.passive.flags.valid) {
986 trip++;
987 for (i = 0; i < tz->trips.passive.devices.count;
988 i++) {
989 if (tz->trips.passive.devices.handles[i] !=
990 handle)
991 continue;
992 result = action(thermal, trip, cdev);
993 if (result)
994 goto failed;
995 }
996 }
997
998 for (i = 0; i < ACPI_THERMAL_MAX_ACTIVE; i++) {
999 if (!tz->trips.active[i].flags.valid)
1000 break;
1001 trip++;
1002 for (j = 0;
1003 j < tz->trips.active[i].devices.count;
1004 j++) {
1005 if (tz->trips.active[i].devices.
1006 handles[j] != handle)
1007 continue;
1008 result = action(thermal, trip, cdev);
1009 if (result)
1010 goto failed;
1011 }
1012 }
1013
1014 for (i = 0; i < tz->devices.count; i++) {
1015 if (tz->devices.handles[i] != handle)
1016 continue;
1017 result = action(thermal, -1, cdev);
1018 if (result)
1019 goto failed;
1020 }
1021
1022failed:
1023 return result;
1024}
1025
1026static int
1027acpi_thermal_bind_cooling_device(struct thermal_zone_device *thermal,
1028 struct thermal_cooling_device *cdev)
1029{
1030 return acpi_thermal_cooling_device_cb(thermal, cdev,
1031 thermal_zone_bind_cooling_device);
1032}
1033
1034static int
1035acpi_thermal_unbind_cooling_device(struct thermal_zone_device *thermal,
1036 struct thermal_cooling_device *cdev)
1037{
1038 return acpi_thermal_cooling_device_cb(thermal, cdev,
1039 thermal_zone_unbind_cooling_device);
1040}
1041
1042static struct thermal_zone_device_ops acpi_thermal_zone_ops = {
1043 .bind = acpi_thermal_bind_cooling_device,
1044 .unbind = acpi_thermal_unbind_cooling_device,
1045 .get_temp = thermal_get_temp,
1046 .get_mode = thermal_get_mode,
1047 .set_mode = thermal_set_mode,
1048 .get_trip_type = thermal_get_trip_type,
1049 .get_trip_temp = thermal_get_trip_temp,
1050};
1051
1052static int acpi_thermal_register_thermal_zone(struct acpi_thermal *tz)
1053{
1054 int trips = 0;
1055 int result;
1056 int i;
1057
1058 if (tz->trips.critical.flags.valid)
1059 trips++;
1060
1061 if (tz->trips.hot.flags.valid)
1062 trips++;
1063
1064 if (tz->trips.passive.flags.valid)
1065 trips++;
1066
1067 for (i = 0; i < ACPI_THERMAL_MAX_ACTIVE &&
1068 tz->trips.active[i].flags.valid; i++, trips++);
1069 tz->thermal_zone = thermal_zone_device_register("ACPI thermal zone",
1070 trips, tz, &acpi_thermal_zone_ops);
1071 if (!tz->thermal_zone)
1072 return -ENODEV;
1073
1074 result = sysfs_create_link(&tz->device->dev.kobj,
1075 &tz->thermal_zone->device.kobj, "thermal_zone");
1076 if (result)
1077 return result;
1078
1079 result = sysfs_create_link(&tz->thermal_zone->device.kobj,
1080 &tz->device->dev.kobj, "device");
1081 if (result)
1082 return result;
1083
1084 tz->tz_enabled = 1;
1085
1086 printk(KERN_INFO PREFIX "%s is registered as thermal_zone%d\n",
1087 tz->device->dev.bus_id, tz->thermal_zone->id);
1088 return 0;
1089}
1090
1091static void acpi_thermal_unregister_thermal_zone(struct acpi_thermal *tz)
1092{
1093 sysfs_remove_link(&tz->device->dev.kobj, "thermal_zone");
1094 sysfs_remove_link(&tz->thermal_zone->device.kobj, "device");
1095 thermal_zone_device_unregister(tz->thermal_zone);
1096 tz->thermal_zone = NULL;
1097}
1098
1099
828/* -------------------------------------------------------------------------- 1100/* --------------------------------------------------------------------------
829 FS Interface (/proc) 1101 FS Interface (/proc)
830 -------------------------------------------------------------------------- */ 1102 -------------------------------------------------------------------------- */
@@ -1260,13 +1532,19 @@ static int acpi_thermal_add(struct acpi_device *device)
1260 strcpy(acpi_device_class(device), ACPI_THERMAL_CLASS); 1532 strcpy(acpi_device_class(device), ACPI_THERMAL_CLASS);
1261 acpi_driver_data(device) = tz; 1533 acpi_driver_data(device) = tz;
1262 mutex_init(&tz->lock); 1534 mutex_init(&tz->lock);
1535
1536
1263 result = acpi_thermal_get_info(tz); 1537 result = acpi_thermal_get_info(tz);
1264 if (result) 1538 if (result)
1265 goto end; 1539 goto free_memory;
1540
1541 result = acpi_thermal_register_thermal_zone(tz);
1542 if (result)
1543 goto free_memory;
1266 1544
1267 result = acpi_thermal_add_fs(device); 1545 result = acpi_thermal_add_fs(device);
1268 if (result) 1546 if (result)
1269 goto end; 1547 goto unregister_thermal_zone;
1270 1548
1271 init_timer(&tz->timer); 1549 init_timer(&tz->timer);
1272 1550
@@ -1277,19 +1555,21 @@ static int acpi_thermal_add(struct acpi_device *device)
1277 acpi_thermal_notify, tz); 1555 acpi_thermal_notify, tz);
1278 if (ACPI_FAILURE(status)) { 1556 if (ACPI_FAILURE(status)) {
1279 result = -ENODEV; 1557 result = -ENODEV;
1280 goto end; 1558 goto remove_fs;
1281 } 1559 }
1282 1560
1283 printk(KERN_INFO PREFIX "%s [%s] (%ld C)\n", 1561 printk(KERN_INFO PREFIX "%s [%s] (%ld C)\n",
1284 acpi_device_name(device), acpi_device_bid(device), 1562 acpi_device_name(device), acpi_device_bid(device),
1285 KELVIN_TO_CELSIUS(tz->temperature)); 1563 KELVIN_TO_CELSIUS(tz->temperature));
1564 goto end;
1286 1565
1287 end: 1566remove_fs:
1288 if (result) { 1567 acpi_thermal_remove_fs(device);
1289 acpi_thermal_remove_fs(device); 1568unregister_thermal_zone:
1290 kfree(tz); 1569 thermal_zone_device_unregister(tz->thermal_zone);
1291 } 1570free_memory:
1292 1571 kfree(tz);
1572end:
1293 return result; 1573 return result;
1294} 1574}
1295 1575
@@ -1329,6 +1609,7 @@ static int acpi_thermal_remove(struct acpi_device *device, int type)
1329 } 1609 }
1330 1610
1331 acpi_thermal_remove_fs(device); 1611 acpi_thermal_remove_fs(device);
1612 acpi_thermal_unregister_thermal_zone(tz);
1332 mutex_destroy(&tz->lock); 1613 mutex_destroy(&tz->lock);
1333 kfree(tz); 1614 kfree(tz);
1334 return 0; 1615 return 0;