diff options
author | Zhang, Rui <rui.zhang@intel.com> | 2008-02-26 19:37:50 -0500 |
---|---|---|
committer | Len Brown <len.brown@intel.com> | 2008-03-13 01:49:01 -0400 |
commit | 3152fb9f11cdd2fd8688c2c5cb805e5c09b53dd9 (patch) | |
tree | cc3433220de915d59320a512f62996a873d0b765 | |
parent | baadac8b10c5ac15ce3d26b68fa266c8889b163f (diff) |
thermal: fix generic thermal I/F for hwmon
Signed-off-by: Zhang Rui <rui.zhang@intel.com>
Signed-off-by: Len Brown <len.brown@intel.com>
-rw-r--r-- | Documentation/thermal/sysfs-api.txt | 22 | ||||
-rw-r--r-- | drivers/thermal/Kconfig | 1 | ||||
-rw-r--r-- | drivers/thermal/thermal.c | 169 |
3 files changed, 155 insertions, 37 deletions
diff --git a/Documentation/thermal/sysfs-api.txt b/Documentation/thermal/sysfs-api.txt index ba9c2da5a8c2..d9f28be75403 100644 --- a/Documentation/thermal/sysfs-api.txt +++ b/Documentation/thermal/sysfs-api.txt | |||
@@ -143,10 +143,10 @@ type Strings which represent the thermal zone type. | |||
143 | This is given by thermal zone driver as part of registration. | 143 | This is given by thermal zone driver as part of registration. |
144 | Eg: "ACPI thermal zone" indicates it's a ACPI thermal device | 144 | Eg: "ACPI thermal zone" indicates it's a ACPI thermal device |
145 | RO | 145 | RO |
146 | Optional | 146 | Required |
147 | 147 | ||
148 | temp Current temperature as reported by thermal zone (sensor) | 148 | temp Current temperature as reported by thermal zone (sensor) |
149 | Unit: degree Celsius | 149 | Unit: millidegree Celsius |
150 | RO | 150 | RO |
151 | Required | 151 | Required |
152 | 152 | ||
@@ -163,7 +163,7 @@ mode One of the predefined values in [kernel, user] | |||
163 | charge of the thermal management. | 163 | charge of the thermal management. |
164 | 164 | ||
165 | trip_point_[0-*]_temp The temperature above which trip point will be fired | 165 | trip_point_[0-*]_temp The temperature above which trip point will be fired |
166 | Unit: degree Celsius | 166 | Unit: millidegree Celsius |
167 | RO | 167 | RO |
168 | Optional | 168 | Optional |
169 | 169 | ||
@@ -193,7 +193,7 @@ type String which represents the type of device | |||
193 | eg. For memory controller device on intel_menlow platform: | 193 | eg. For memory controller device on intel_menlow platform: |
194 | this should be "Memory controller" | 194 | this should be "Memory controller" |
195 | RO | 195 | RO |
196 | Optional | 196 | Required |
197 | 197 | ||
198 | max_state The maximum permissible cooling state of this cooling device. | 198 | max_state The maximum permissible cooling state of this cooling device. |
199 | RO | 199 | RO |
@@ -219,16 +219,16 @@ the sys I/F structure will be built like this: | |||
219 | 219 | ||
220 | |thermal_zone1: | 220 | |thermal_zone1: |
221 | |-----type: ACPI thermal zone | 221 | |-----type: ACPI thermal zone |
222 | |-----temp: 37 | 222 | |-----temp: 37000 |
223 | |-----mode: kernel | 223 | |-----mode: kernel |
224 | |-----trip_point_0_temp: 100 | 224 | |-----trip_point_0_temp: 100000 |
225 | |-----trip_point_0_type: critical | 225 | |-----trip_point_0_type: critical |
226 | |-----trip_point_1_temp: 80 | 226 | |-----trip_point_1_temp: 80000 |
227 | |-----trip_point_1_type: passive | 227 | |-----trip_point_1_type: passive |
228 | |-----trip_point_2_temp: 70 | 228 | |-----trip_point_2_temp: 70000 |
229 | |-----trip_point_2_type: active[0] | 229 | |-----trip_point_2_type: active0 |
230 | |-----trip_point_3_temp: 60 | 230 | |-----trip_point_3_temp: 60000 |
231 | |-----trip_point_3_type: active[1] | 231 | |-----trip_point_3_type: active1 |
232 | |-----cdev0: --->/sys/class/thermal/cooling_device0 | 232 | |-----cdev0: --->/sys/class/thermal/cooling_device0 |
233 | |-----cdev0_trip_point: 1 /* cdev0 can be used for passive */ | 233 | |-----cdev0_trip_point: 1 /* cdev0 can be used for passive */ |
234 | |-----cdev1: --->/sys/class/thermal/cooling_device3 | 234 | |-----cdev1: --->/sys/class/thermal/cooling_device3 |
diff --git a/drivers/thermal/Kconfig b/drivers/thermal/Kconfig index 69f19f224875..3ab313ed441c 100644 --- a/drivers/thermal/Kconfig +++ b/drivers/thermal/Kconfig | |||
@@ -4,6 +4,7 @@ | |||
4 | 4 | ||
5 | menuconfig THERMAL | 5 | menuconfig THERMAL |
6 | bool "Generic Thermal sysfs driver" | 6 | bool "Generic Thermal sysfs driver" |
7 | select HWMON | ||
7 | default y | 8 | default y |
8 | help | 9 | help |
9 | Generic Thermal Sysfs driver offers a generic mechanism for | 10 | Generic Thermal Sysfs driver offers a generic mechanism for |
diff --git a/drivers/thermal/thermal.c b/drivers/thermal/thermal.c index 8b86e53ccf7a..41bd4c805ace 100644 --- a/drivers/thermal/thermal.c +++ b/drivers/thermal/thermal.c | |||
@@ -30,8 +30,10 @@ | |||
30 | #include <linux/idr.h> | 30 | #include <linux/idr.h> |
31 | #include <linux/thermal.h> | 31 | #include <linux/thermal.h> |
32 | #include <linux/spinlock.h> | 32 | #include <linux/spinlock.h> |
33 | #include <linux/hwmon.h> | ||
34 | #include <linux/hwmon-sysfs.h> | ||
33 | 35 | ||
34 | MODULE_AUTHOR("Zhang Rui") | 36 | MODULE_AUTHOR("Zhang Rui"); |
35 | MODULE_DESCRIPTION("Generic thermal management sysfs support"); | 37 | MODULE_DESCRIPTION("Generic thermal management sysfs support"); |
36 | MODULE_LICENSE("GPL"); | 38 | MODULE_LICENSE("GPL"); |
37 | 39 | ||
@@ -56,6 +58,9 @@ static LIST_HEAD(thermal_tz_list); | |||
56 | static LIST_HEAD(thermal_cdev_list); | 58 | static LIST_HEAD(thermal_cdev_list); |
57 | static DEFINE_MUTEX(thermal_list_lock); | 59 | static DEFINE_MUTEX(thermal_list_lock); |
58 | 60 | ||
61 | static struct device *thermal_hwmon; | ||
62 | #define MAX_THERMAL_ZONES 10 | ||
63 | |||
59 | static int get_idr(struct idr *idr, struct mutex *lock, int *id) | 64 | static int get_idr(struct idr *idr, struct mutex *lock, int *id) |
60 | { | 65 | { |
61 | int err; | 66 | int err; |
@@ -87,7 +92,67 @@ static void release_idr(struct idr *idr, struct mutex *lock, int id) | |||
87 | mutex_unlock(lock); | 92 | mutex_unlock(lock); |
88 | } | 93 | } |
89 | 94 | ||
90 | /* sys I/F for thermal zone */ | 95 | /* hwmon sys I/F*/ |
96 | static ssize_t | ||
97 | name_show(struct device *dev, struct device_attribute *attr, char *buf) | ||
98 | { | ||
99 | return sprintf(buf, "thermal_sys_class\n"); | ||
100 | } | ||
101 | |||
102 | static ssize_t | ||
103 | temp_input_show(struct device *dev, struct device_attribute *attr, char *buf) | ||
104 | { | ||
105 | struct thermal_zone_device *tz; | ||
106 | struct sensor_device_attribute *sensor_attr | ||
107 | = to_sensor_dev_attr(attr); | ||
108 | |||
109 | list_for_each_entry(tz, &thermal_tz_list, node) | ||
110 | if (tz->id == sensor_attr->index) | ||
111 | return tz->ops->get_temp(tz, buf); | ||
112 | |||
113 | return -ENODEV; | ||
114 | } | ||
115 | |||
116 | static ssize_t | ||
117 | temp_crit_show(struct device *dev, struct device_attribute *attr, | ||
118 | char *buf) | ||
119 | { | ||
120 | struct thermal_zone_device *tz; | ||
121 | struct sensor_device_attribute *sensor_attr | ||
122 | = to_sensor_dev_attr(attr); | ||
123 | |||
124 | list_for_each_entry(tz, &thermal_tz_list, node) | ||
125 | if (tz->id == sensor_attr->index) | ||
126 | return tz->ops->get_trip_temp(tz, 0, buf); | ||
127 | |||
128 | return -ENODEV; | ||
129 | } | ||
130 | |||
131 | static DEVICE_ATTR(name, 0444, name_show, NULL); | ||
132 | static struct sensor_device_attribute sensor_attrs[] = { | ||
133 | SENSOR_ATTR(temp1_input, 0444, temp_input_show, NULL, 0), | ||
134 | SENSOR_ATTR(temp1_crit, 0444, temp_crit_show, NULL, 0), | ||
135 | SENSOR_ATTR(temp2_input, 0444, temp_input_show, NULL, 1), | ||
136 | SENSOR_ATTR(temp2_crit, 0444, temp_crit_show, NULL, 1), | ||
137 | SENSOR_ATTR(temp3_input, 0444, temp_input_show, NULL, 2), | ||
138 | SENSOR_ATTR(temp3_crit, 0444, temp_crit_show, NULL, 2), | ||
139 | SENSOR_ATTR(temp4_input, 0444, temp_input_show, NULL, 3), | ||
140 | SENSOR_ATTR(temp4_crit, 0444, temp_crit_show, NULL, 3), | ||
141 | SENSOR_ATTR(temp5_input, 0444, temp_input_show, NULL, 4), | ||
142 | SENSOR_ATTR(temp5_crit, 0444, temp_crit_show, NULL, 4), | ||
143 | SENSOR_ATTR(temp6_input, 0444, temp_input_show, NULL, 5), | ||
144 | SENSOR_ATTR(temp6_crit, 0444, temp_crit_show, NULL, 5), | ||
145 | SENSOR_ATTR(temp7_input, 0444, temp_input_show, NULL, 6), | ||
146 | SENSOR_ATTR(temp7_crit, 0444, temp_crit_show, NULL, 6), | ||
147 | SENSOR_ATTR(temp8_input, 0444, temp_input_show, NULL, 7), | ||
148 | SENSOR_ATTR(temp8_crit, 0444, temp_crit_show, NULL, 7), | ||
149 | SENSOR_ATTR(temp9_input, 0444, temp_input_show, NULL, 8), | ||
150 | SENSOR_ATTR(temp9_crit, 0444, temp_crit_show, NULL, 8), | ||
151 | SENSOR_ATTR(temp10_input, 0444, temp_input_show, NULL, 9), | ||
152 | SENSOR_ATTR(temp10_crit, 0444, temp_crit_show, NULL, 9), | ||
153 | }; | ||
154 | |||
155 | /* thermal zone sys I/F */ | ||
91 | 156 | ||
92 | #define to_thermal_zone(_dev) \ | 157 | #define to_thermal_zone(_dev) \ |
93 | container_of(_dev, struct thermal_zone_device, device) | 158 | container_of(_dev, struct thermal_zone_device, device) |
@@ -214,7 +279,7 @@ do { \ | |||
214 | device_remove_file(_dev, &trip_point_attrs[_index * 2 + 1]); \ | 279 | device_remove_file(_dev, &trip_point_attrs[_index * 2 + 1]); \ |
215 | } while (0) | 280 | } while (0) |
216 | 281 | ||
217 | /* sys I/F for cooling device */ | 282 | /* cooling device sys I/F */ |
218 | #define to_cooling_device(_dev) \ | 283 | #define to_cooling_device(_dev) \ |
219 | container_of(_dev, struct thermal_cooling_device, device) | 284 | container_of(_dev, struct thermal_cooling_device, device) |
220 | 285 | ||
@@ -447,6 +512,9 @@ struct thermal_cooling_device *thermal_cooling_device_register(char *type, | |||
447 | struct thermal_zone_device *pos; | 512 | struct thermal_zone_device *pos; |
448 | int result; | 513 | int result; |
449 | 514 | ||
515 | if (!type) | ||
516 | return ERR_PTR(-EINVAL); | ||
517 | |||
450 | if (strlen(type) >= THERMAL_NAME_LENGTH) | 518 | if (strlen(type) >= THERMAL_NAME_LENGTH) |
451 | return ERR_PTR(-EINVAL); | 519 | return ERR_PTR(-EINVAL); |
452 | 520 | ||
@@ -477,11 +545,9 @@ struct thermal_cooling_device *thermal_cooling_device_register(char *type, | |||
477 | } | 545 | } |
478 | 546 | ||
479 | /* sys I/F */ | 547 | /* sys I/F */ |
480 | if (type) { | 548 | result = device_create_file(&cdev->device, &dev_attr_cdev_type); |
481 | result = device_create_file(&cdev->device, &dev_attr_cdev_type); | 549 | if (result) |
482 | if (result) | 550 | goto unregister; |
483 | goto unregister; | ||
484 | } | ||
485 | 551 | ||
486 | result = device_create_file(&cdev->device, &dev_attr_max_state); | 552 | result = device_create_file(&cdev->device, &dev_attr_max_state); |
487 | if (result) | 553 | if (result) |
@@ -547,8 +613,8 @@ void thermal_cooling_device_unregister(struct | |||
547 | tz->ops->unbind(tz, cdev); | 613 | tz->ops->unbind(tz, cdev); |
548 | } | 614 | } |
549 | mutex_unlock(&thermal_list_lock); | 615 | mutex_unlock(&thermal_list_lock); |
550 | if (cdev->type[0]) | 616 | |
551 | device_remove_file(&cdev->device, &dev_attr_cdev_type); | 617 | device_remove_file(&cdev->device, &dev_attr_cdev_type); |
552 | device_remove_file(&cdev->device, &dev_attr_max_state); | 618 | device_remove_file(&cdev->device, &dev_attr_max_state); |
553 | device_remove_file(&cdev->device, &dev_attr_cur_state); | 619 | device_remove_file(&cdev->device, &dev_attr_cur_state); |
554 | 620 | ||
@@ -580,6 +646,9 @@ struct thermal_zone_device *thermal_zone_device_register(char *type, | |||
580 | int result; | 646 | int result; |
581 | int count; | 647 | int count; |
582 | 648 | ||
649 | if (!type) | ||
650 | return ERR_PTR(-EINVAL); | ||
651 | |||
583 | if (strlen(type) >= THERMAL_NAME_LENGTH) | 652 | if (strlen(type) >= THERMAL_NAME_LENGTH) |
584 | return ERR_PTR(-EINVAL); | 653 | return ERR_PTR(-EINVAL); |
585 | 654 | ||
@@ -601,6 +670,13 @@ struct thermal_zone_device *thermal_zone_device_register(char *type, | |||
601 | kfree(tz); | 670 | kfree(tz); |
602 | return ERR_PTR(result); | 671 | return ERR_PTR(result); |
603 | } | 672 | } |
673 | if (tz->id >= MAX_THERMAL_ZONES) { | ||
674 | printk(KERN_ERR PREFIX | ||
675 | "Too many thermal zones\n"); | ||
676 | release_idr(&thermal_tz_idr, &thermal_idr_lock, tz->id); | ||
677 | kfree(tz); | ||
678 | return ERR_PTR(-EINVAL); | ||
679 | } | ||
604 | 680 | ||
605 | strcpy(tz->type, type); | 681 | strcpy(tz->type, type); |
606 | tz->ops = ops; | 682 | tz->ops = ops; |
@@ -615,13 +691,28 @@ struct thermal_zone_device *thermal_zone_device_register(char *type, | |||
615 | return ERR_PTR(result); | 691 | return ERR_PTR(result); |
616 | } | 692 | } |
617 | 693 | ||
618 | /* sys I/F */ | 694 | /* hwmon sys I/F */ |
619 | if (type) { | 695 | result = device_create_file(thermal_hwmon, |
620 | result = device_create_file(&tz->device, &dev_attr_type); | 696 | &sensor_attrs[tz->id * 2].dev_attr); |
621 | if (result) | 697 | if (result) |
622 | goto unregister; | 698 | goto unregister; |
699 | |||
700 | if (trips > 0) { | ||
701 | char buf[40]; | ||
702 | result = tz->ops->get_trip_type(tz, 0, buf); | ||
703 | if (result > 0 && !strcmp(buf, "critical\n")) { | ||
704 | result = device_create_file(thermal_hwmon, | ||
705 | &sensor_attrs[tz->id * 2 + 1].dev_attr); | ||
706 | if (result) | ||
707 | goto unregister; | ||
708 | } | ||
623 | } | 709 | } |
624 | 710 | ||
711 | /* sys I/F */ | ||
712 | result = device_create_file(&tz->device, &dev_attr_type); | ||
713 | if (result) | ||
714 | goto unregister; | ||
715 | |||
625 | result = device_create_file(&tz->device, &dev_attr_temp); | 716 | result = device_create_file(&tz->device, &dev_attr_temp); |
626 | if (result) | 717 | if (result) |
627 | goto unregister; | 718 | goto unregister; |
@@ -687,8 +778,17 @@ void thermal_zone_device_unregister(struct thermal_zone_device *tz) | |||
687 | tz->ops->unbind(tz, cdev); | 778 | tz->ops->unbind(tz, cdev); |
688 | mutex_unlock(&thermal_list_lock); | 779 | mutex_unlock(&thermal_list_lock); |
689 | 780 | ||
690 | if (tz->type[0]) | 781 | device_remove_file(thermal_hwmon, |
691 | device_remove_file(&tz->device, &dev_attr_type); | 782 | &sensor_attrs[tz->id * 2].dev_attr); |
783 | if (tz->trips > 0) { | ||
784 | char buf[40]; | ||
785 | if (tz->ops->get_trip_type(tz, 0, buf) > 0) | ||
786 | if (!strcmp(buf, "critical\n")) | ||
787 | device_remove_file(thermal_hwmon, | ||
788 | &sensor_attrs[tz->id * 2 + 1].dev_attr); | ||
789 | } | ||
790 | |||
791 | device_remove_file(&tz->device, &dev_attr_type); | ||
692 | device_remove_file(&tz->device, &dev_attr_temp); | 792 | device_remove_file(&tz->device, &dev_attr_temp); |
693 | if (tz->ops->get_mode) | 793 | if (tz->ops->get_mode) |
694 | device_remove_file(&tz->device, &dev_attr_mode); | 794 | device_remove_file(&tz->device, &dev_attr_mode); |
@@ -705,6 +805,19 @@ void thermal_zone_device_unregister(struct thermal_zone_device *tz) | |||
705 | 805 | ||
706 | EXPORT_SYMBOL(thermal_zone_device_unregister); | 806 | EXPORT_SYMBOL(thermal_zone_device_unregister); |
707 | 807 | ||
808 | static void thermal_exit(void) | ||
809 | { | ||
810 | if (thermal_hwmon) { | ||
811 | device_remove_file(thermal_hwmon, &dev_attr_name); | ||
812 | hwmon_device_unregister(thermal_hwmon); | ||
813 | } | ||
814 | class_unregister(&thermal_class); | ||
815 | idr_destroy(&thermal_tz_idr); | ||
816 | idr_destroy(&thermal_cdev_idr); | ||
817 | mutex_destroy(&thermal_idr_lock); | ||
818 | mutex_destroy(&thermal_list_lock); | ||
819 | } | ||
820 | |||
708 | static int __init thermal_init(void) | 821 | static int __init thermal_init(void) |
709 | { | 822 | { |
710 | int result = 0; | 823 | int result = 0; |
@@ -716,16 +829,20 @@ static int __init thermal_init(void) | |||
716 | mutex_destroy(&thermal_idr_lock); | 829 | mutex_destroy(&thermal_idr_lock); |
717 | mutex_destroy(&thermal_list_lock); | 830 | mutex_destroy(&thermal_list_lock); |
718 | } | 831 | } |
719 | return result; | ||
720 | } | ||
721 | 832 | ||
722 | static void __exit thermal_exit(void) | 833 | thermal_hwmon = hwmon_device_register(NULL); |
723 | { | 834 | if (IS_ERR(thermal_hwmon)) { |
724 | class_unregister(&thermal_class); | 835 | result = PTR_ERR(thermal_hwmon); |
725 | idr_destroy(&thermal_tz_idr); | 836 | thermal_hwmon = NULL; |
726 | idr_destroy(&thermal_cdev_idr); | 837 | printk(KERN_ERR PREFIX |
727 | mutex_destroy(&thermal_idr_lock); | 838 | "unable to register hwmon device\n"); |
728 | mutex_destroy(&thermal_list_lock); | 839 | thermal_exit(); |
840 | return result; | ||
841 | } | ||
842 | |||
843 | result = device_create_file(thermal_hwmon, &dev_attr_name); | ||
844 | |||
845 | return result; | ||
729 | } | 846 | } |
730 | 847 | ||
731 | subsys_initcall(thermal_init); | 848 | subsys_initcall(thermal_init); |