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>
This commit is contained in:
Zhang, Rui 2008-02-27 08:37:50 +08:00 committed by Len Brown
parent baadac8b10
commit 3152fb9f11
3 changed files with 155 additions and 37 deletions

View file

@ -143,10 +143,10 @@ type Strings which represent the thermal zone type.
This is given by thermal zone driver as part of registration. This is given by thermal zone driver as part of registration.
Eg: "ACPI thermal zone" indicates it's a ACPI thermal device Eg: "ACPI thermal zone" indicates it's a ACPI thermal device
RO RO
Optional Required
temp Current temperature as reported by thermal zone (sensor) temp Current temperature as reported by thermal zone (sensor)
Unit: degree Celsius Unit: millidegree Celsius
RO RO
Required Required
@ -163,7 +163,7 @@ mode One of the predefined values in [kernel, user]
charge of the thermal management. charge of the thermal management.
trip_point_[0-*]_temp The temperature above which trip point will be fired trip_point_[0-*]_temp The temperature above which trip point will be fired
Unit: degree Celsius Unit: millidegree Celsius
RO RO
Optional Optional
@ -193,7 +193,7 @@ type String which represents the type of device
eg. For memory controller device on intel_menlow platform: eg. For memory controller device on intel_menlow platform:
this should be "Memory controller" this should be "Memory controller"
RO RO
Optional Required
max_state The maximum permissible cooling state of this cooling device. max_state The maximum permissible cooling state of this cooling device.
RO RO
@ -219,16 +219,16 @@ the sys I/F structure will be built like this:
|thermal_zone1: |thermal_zone1:
|-----type: ACPI thermal zone |-----type: ACPI thermal zone
|-----temp: 37 |-----temp: 37000
|-----mode: kernel |-----mode: kernel
|-----trip_point_0_temp: 100 |-----trip_point_0_temp: 100000
|-----trip_point_0_type: critical |-----trip_point_0_type: critical
|-----trip_point_1_temp: 80 |-----trip_point_1_temp: 80000
|-----trip_point_1_type: passive |-----trip_point_1_type: passive
|-----trip_point_2_temp: 70 |-----trip_point_2_temp: 70000
|-----trip_point_2_type: active[0] |-----trip_point_2_type: active0
|-----trip_point_3_temp: 60 |-----trip_point_3_temp: 60000
|-----trip_point_3_type: active[1] |-----trip_point_3_type: active1
|-----cdev0: --->/sys/class/thermal/cooling_device0 |-----cdev0: --->/sys/class/thermal/cooling_device0
|-----cdev0_trip_point: 1 /* cdev0 can be used for passive */ |-----cdev0_trip_point: 1 /* cdev0 can be used for passive */
|-----cdev1: --->/sys/class/thermal/cooling_device3 |-----cdev1: --->/sys/class/thermal/cooling_device3

View file

@ -4,6 +4,7 @@
menuconfig THERMAL menuconfig THERMAL
bool "Generic Thermal sysfs driver" bool "Generic Thermal sysfs driver"
select HWMON
default y default y
help help
Generic Thermal Sysfs driver offers a generic mechanism for Generic Thermal Sysfs driver offers a generic mechanism for

View file

@ -30,8 +30,10 @@
#include <linux/idr.h> #include <linux/idr.h>
#include <linux/thermal.h> #include <linux/thermal.h>
#include <linux/spinlock.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_DESCRIPTION("Generic thermal management sysfs support");
MODULE_LICENSE("GPL"); MODULE_LICENSE("GPL");
@ -56,6 +58,9 @@ static LIST_HEAD(thermal_tz_list);
static LIST_HEAD(thermal_cdev_list); static LIST_HEAD(thermal_cdev_list);
static DEFINE_MUTEX(thermal_list_lock); 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) static int get_idr(struct idr *idr, struct mutex *lock, int *id)
{ {
int err; int err;
@ -87,7 +92,67 @@ static void release_idr(struct idr *idr, struct mutex *lock, int id)
mutex_unlock(lock); 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) \ #define to_thermal_zone(_dev) \
container_of(_dev, struct thermal_zone_device, device) container_of(_dev, struct thermal_zone_device, device)
@ -214,7 +279,7 @@ do { \
device_remove_file(_dev, &trip_point_attrs[_index * 2 + 1]); \ device_remove_file(_dev, &trip_point_attrs[_index * 2 + 1]); \
} while (0) } while (0)
/* sys I/F for cooling device */ /* cooling device sys I/F */
#define to_cooling_device(_dev) \ #define to_cooling_device(_dev) \
container_of(_dev, struct thermal_cooling_device, device) 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; struct thermal_zone_device *pos;
int result; int result;
if (!type)
return ERR_PTR(-EINVAL);
if (strlen(type) >= THERMAL_NAME_LENGTH) if (strlen(type) >= THERMAL_NAME_LENGTH)
return ERR_PTR(-EINVAL); return ERR_PTR(-EINVAL);
@ -477,11 +545,9 @@ struct thermal_cooling_device *thermal_cooling_device_register(char *type,
} }
/* sys I/F */ /* sys I/F */
if (type) { result = device_create_file(&cdev->device, &dev_attr_cdev_type);
result = device_create_file(&cdev->device, &dev_attr_cdev_type); if (result)
if (result) goto unregister;
goto unregister;
}
result = device_create_file(&cdev->device, &dev_attr_max_state); result = device_create_file(&cdev->device, &dev_attr_max_state);
if (result) if (result)
@ -547,8 +613,8 @@ void thermal_cooling_device_unregister(struct
tz->ops->unbind(tz, cdev); tz->ops->unbind(tz, cdev);
} }
mutex_unlock(&thermal_list_lock); 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_max_state);
device_remove_file(&cdev->device, &dev_attr_cur_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 result;
int count; int count;
if (!type)
return ERR_PTR(-EINVAL);
if (strlen(type) >= THERMAL_NAME_LENGTH) if (strlen(type) >= THERMAL_NAME_LENGTH)
return ERR_PTR(-EINVAL); return ERR_PTR(-EINVAL);
@ -601,6 +670,13 @@ struct thermal_zone_device *thermal_zone_device_register(char *type,
kfree(tz); kfree(tz);
return ERR_PTR(result); 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); strcpy(tz->type, type);
tz->ops = ops; tz->ops = ops;
@ -615,13 +691,28 @@ struct thermal_zone_device *thermal_zone_device_register(char *type,
return ERR_PTR(result); return ERR_PTR(result);
} }
/* sys I/F */ /* hwmon sys I/F */
if (type) { result = device_create_file(thermal_hwmon,
result = device_create_file(&tz->device, &dev_attr_type); &sensor_attrs[tz->id * 2].dev_attr);
if (result) if (result)
goto unregister; 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); result = device_create_file(&tz->device, &dev_attr_temp);
if (result) if (result)
goto unregister; goto unregister;
@ -687,8 +778,17 @@ void thermal_zone_device_unregister(struct thermal_zone_device *tz)
tz->ops->unbind(tz, cdev); tz->ops->unbind(tz, cdev);
mutex_unlock(&thermal_list_lock); mutex_unlock(&thermal_list_lock);
if (tz->type[0]) device_remove_file(thermal_hwmon,
device_remove_file(&tz->device, &dev_attr_type); &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); device_remove_file(&tz->device, &dev_attr_temp);
if (tz->ops->get_mode) if (tz->ops->get_mode)
device_remove_file(&tz->device, &dev_attr_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); 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) static int __init thermal_init(void)
{ {
int result = 0; int result = 0;
@ -716,16 +829,20 @@ static int __init thermal_init(void)
mutex_destroy(&thermal_idr_lock); mutex_destroy(&thermal_idr_lock);
mutex_destroy(&thermal_list_lock); mutex_destroy(&thermal_list_lock);
} }
return result;
}
static void __exit thermal_exit(void) thermal_hwmon = hwmon_device_register(NULL);
{ if (IS_ERR(thermal_hwmon)) {
class_unregister(&thermal_class); result = PTR_ERR(thermal_hwmon);
idr_destroy(&thermal_tz_idr); thermal_hwmon = NULL;
idr_destroy(&thermal_cdev_idr); printk(KERN_ERR PREFIX
mutex_destroy(&thermal_idr_lock); "unable to register hwmon device\n");
mutex_destroy(&thermal_list_lock); thermal_exit();
return result;
}
result = device_create_file(thermal_hwmon, &dev_attr_name);
return result;
} }
subsys_initcall(thermal_init); subsys_initcall(thermal_init);