diff options
Diffstat (limited to 'drivers/thermal')
-rw-r--r-- | drivers/thermal/Kconfig | 1 | ||||
-rw-r--r-- | drivers/thermal/thermal.c | 169 |
2 files changed, 144 insertions, 26 deletions
diff --git a/drivers/thermal/Kconfig b/drivers/thermal/Kconfig index 69f19f22487..3ab313ed441 100644 --- a/drivers/thermal/Kconfig +++ b/drivers/thermal/Kconfig @@ -4,6 +4,7 @@ menuconfig THERMAL bool "Generic Thermal sysfs driver" + select HWMON default y help Generic Thermal Sysfs driver offers a generic mechanism for diff --git a/drivers/thermal/thermal.c b/drivers/thermal/thermal.c index 8b86e53ccf7..41bd4c805ac 100644 --- a/drivers/thermal/thermal.c +++ b/drivers/thermal/thermal.c @@ -30,8 +30,10 @@ #include <linux/idr.h> #include <linux/thermal.h> #include <linux/spinlock.h> +#include <linux/hwmon.h> +#include <linux/hwmon-sysfs.h> -MODULE_AUTHOR("Zhang Rui") +MODULE_AUTHOR("Zhang Rui"); MODULE_DESCRIPTION("Generic thermal management sysfs support"); MODULE_LICENSE("GPL"); @@ -56,6 +58,9 @@ static LIST_HEAD(thermal_tz_list); static LIST_HEAD(thermal_cdev_list); static DEFINE_MUTEX(thermal_list_lock); +static struct device *thermal_hwmon; +#define MAX_THERMAL_ZONES 10 + static int get_idr(struct idr *idr, struct mutex *lock, int *id) { int err; @@ -87,7 +92,67 @@ static void release_idr(struct idr *idr, struct mutex *lock, int id) mutex_unlock(lock); } -/* sys I/F for thermal zone */ +/* hwmon sys I/F*/ +static ssize_t +name_show(struct device *dev, struct device_attribute *attr, char *buf) +{ + return sprintf(buf, "thermal_sys_class\n"); +} + +static ssize_t +temp_input_show(struct device *dev, struct device_attribute *attr, char *buf) +{ + struct thermal_zone_device *tz; + struct sensor_device_attribute *sensor_attr + = to_sensor_dev_attr(attr); + + list_for_each_entry(tz, &thermal_tz_list, node) + if (tz->id == sensor_attr->index) + return tz->ops->get_temp(tz, buf); + + return -ENODEV; +} + +static ssize_t +temp_crit_show(struct device *dev, struct device_attribute *attr, + char *buf) +{ + struct thermal_zone_device *tz; + struct sensor_device_attribute *sensor_attr + = to_sensor_dev_attr(attr); + + list_for_each_entry(tz, &thermal_tz_list, node) + if (tz->id == sensor_attr->index) + return tz->ops->get_trip_temp(tz, 0, buf); + + return -ENODEV; +} + +static DEVICE_ATTR(name, 0444, name_show, NULL); +static struct sensor_device_attribute sensor_attrs[] = { + SENSOR_ATTR(temp1_input, 0444, temp_input_show, NULL, 0), + SENSOR_ATTR(temp1_crit, 0444, temp_crit_show, NULL, 0), + SENSOR_ATTR(temp2_input, 0444, temp_input_show, NULL, 1), + SENSOR_ATTR(temp2_crit, 0444, temp_crit_show, NULL, 1), + SENSOR_ATTR(temp3_input, 0444, temp_input_show, NULL, 2), + SENSOR_ATTR(temp3_crit, 0444, temp_crit_show, NULL, 2), + SENSOR_ATTR(temp4_input, 0444, temp_input_show, NULL, 3), + SENSOR_ATTR(temp4_crit, 0444, temp_crit_show, NULL, 3), + SENSOR_ATTR(temp5_input, 0444, temp_input_show, NULL, 4), + SENSOR_ATTR(temp5_crit, 0444, temp_crit_show, NULL, 4), + SENSOR_ATTR(temp6_input, 0444, temp_input_show, NULL, 5), + SENSOR_ATTR(temp6_crit, 0444, temp_crit_show, NULL, 5), + SENSOR_ATTR(temp7_input, 0444, temp_input_show, NULL, 6), + SENSOR_ATTR(temp7_crit, 0444, temp_crit_show, NULL, 6), + SENSOR_ATTR(temp8_input, 0444, temp_input_show, NULL, 7), + SENSOR_ATTR(temp8_crit, 0444, temp_crit_show, NULL, 7), + SENSOR_ATTR(temp9_input, 0444, temp_input_show, NULL, 8), + SENSOR_ATTR(temp9_crit, 0444, temp_crit_show, NULL, 8), + SENSOR_ATTR(temp10_input, 0444, temp_input_show, NULL, 9), + SENSOR_ATTR(temp10_crit, 0444, temp_crit_show, NULL, 9), +}; + +/* thermal zone sys I/F */ #define to_thermal_zone(_dev) \ container_of(_dev, struct thermal_zone_device, device) @@ -214,7 +279,7 @@ do { \ device_remove_file(_dev, &trip_point_attrs[_index * 2 + 1]); \ } while (0) -/* sys I/F for cooling device */ +/* cooling device sys I/F */ #define to_cooling_device(_dev) \ container_of(_dev, struct thermal_cooling_device, device) @@ -447,6 +512,9 @@ struct thermal_cooling_device *thermal_cooling_device_register(char *type, struct thermal_zone_device *pos; int result; + if (!type) + return ERR_PTR(-EINVAL); + if (strlen(type) >= THERMAL_NAME_LENGTH) return ERR_PTR(-EINVAL); @@ -477,11 +545,9 @@ struct thermal_cooling_device *thermal_cooling_device_register(char *type, } /* sys I/F */ - if (type) { - result = device_create_file(&cdev->device, &dev_attr_cdev_type); - if (result) - goto unregister; - } + result = device_create_file(&cdev->device, &dev_attr_cdev_type); + if (result) + goto unregister; result = device_create_file(&cdev->device, &dev_attr_max_state); if (result) @@ -547,8 +613,8 @@ void thermal_cooling_device_unregister(struct tz->ops->unbind(tz, cdev); } mutex_unlock(&thermal_list_lock); - if (cdev->type[0]) - device_remove_file(&cdev->device, &dev_attr_cdev_type); + + device_remove_file(&cdev->device, &dev_attr_cdev_type); device_remove_file(&cdev->device, &dev_attr_max_state); device_remove_file(&cdev->device, &dev_attr_cur_state); @@ -580,6 +646,9 @@ struct thermal_zone_device *thermal_zone_device_register(char *type, int result; int count; + if (!type) + return ERR_PTR(-EINVAL); + if (strlen(type) >= THERMAL_NAME_LENGTH) return ERR_PTR(-EINVAL); @@ -601,6 +670,13 @@ struct thermal_zone_device *thermal_zone_device_register(char *type, kfree(tz); return ERR_PTR(result); } + if (tz->id >= MAX_THERMAL_ZONES) { + printk(KERN_ERR PREFIX + "Too many thermal zones\n"); + release_idr(&thermal_tz_idr, &thermal_idr_lock, tz->id); + kfree(tz); + return ERR_PTR(-EINVAL); + } strcpy(tz->type, type); tz->ops = ops; @@ -615,13 +691,28 @@ struct thermal_zone_device *thermal_zone_device_register(char *type, return ERR_PTR(result); } - /* sys I/F */ - if (type) { - result = device_create_file(&tz->device, &dev_attr_type); - if (result) - goto unregister; + /* hwmon sys I/F */ + result = device_create_file(thermal_hwmon, + &sensor_attrs[tz->id * 2].dev_attr); + if (result) + goto unregister; + + if (trips > 0) { + char buf[40]; + result = tz->ops->get_trip_type(tz, 0, buf); + if (result > 0 && !strcmp(buf, "critical\n")) { + result = device_create_file(thermal_hwmon, + &sensor_attrs[tz->id * 2 + 1].dev_attr); + if (result) + goto unregister; + } } + /* sys I/F */ + result = device_create_file(&tz->device, &dev_attr_type); + if (result) + goto unregister; + result = device_create_file(&tz->device, &dev_attr_temp); if (result) goto unregister; @@ -687,8 +778,17 @@ void thermal_zone_device_unregister(struct thermal_zone_device *tz) tz->ops->unbind(tz, cdev); mutex_unlock(&thermal_list_lock); - if (tz->type[0]) - device_remove_file(&tz->device, &dev_attr_type); + device_remove_file(thermal_hwmon, + &sensor_attrs[tz->id * 2].dev_attr); + if (tz->trips > 0) { + char buf[40]; + if (tz->ops->get_trip_type(tz, 0, buf) > 0) + if (!strcmp(buf, "critical\n")) + device_remove_file(thermal_hwmon, + &sensor_attrs[tz->id * 2 + 1].dev_attr); + } + + device_remove_file(&tz->device, &dev_attr_type); device_remove_file(&tz->device, &dev_attr_temp); if (tz->ops->get_mode) device_remove_file(&tz->device, &dev_attr_mode); @@ -705,6 +805,19 @@ void thermal_zone_device_unregister(struct thermal_zone_device *tz) EXPORT_SYMBOL(thermal_zone_device_unregister); +static void thermal_exit(void) +{ + if (thermal_hwmon) { + device_remove_file(thermal_hwmon, &dev_attr_name); + hwmon_device_unregister(thermal_hwmon); + } + class_unregister(&thermal_class); + idr_destroy(&thermal_tz_idr); + idr_destroy(&thermal_cdev_idr); + mutex_destroy(&thermal_idr_lock); + mutex_destroy(&thermal_list_lock); +} + static int __init thermal_init(void) { int result = 0; @@ -716,16 +829,20 @@ static int __init thermal_init(void) mutex_destroy(&thermal_idr_lock); mutex_destroy(&thermal_list_lock); } - return result; -} -static void __exit thermal_exit(void) -{ - class_unregister(&thermal_class); - idr_destroy(&thermal_tz_idr); - idr_destroy(&thermal_cdev_idr); - mutex_destroy(&thermal_idr_lock); - mutex_destroy(&thermal_list_lock); + thermal_hwmon = hwmon_device_register(NULL); + if (IS_ERR(thermal_hwmon)) { + result = PTR_ERR(thermal_hwmon); + thermal_hwmon = NULL; + printk(KERN_ERR PREFIX + "unable to register hwmon device\n"); + thermal_exit(); + return result; + } + + result = device_create_file(thermal_hwmon, &dev_attr_name); + + return result; } subsys_initcall(thermal_init); |