mirror of
https://github.com/adulau/aha.git
synced 2024-12-28 11:46:19 +00:00
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:
parent
baadac8b10
commit
3152fb9f11
3 changed files with 155 additions and 37 deletions
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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);
|
||||||
|
|
Loading…
Reference in a new issue