Commit 3f655ef8 authored by Zhang Rui's avatar Zhang Rui Committed by Len Brown

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: default avatarZhang Rui <rui.zhang@intel.com>
Signed-off-by: default avatarThomas Sujith <sujith.thomas@intel.com>
Signed-off-by: default avatarLen Brown <len.brown@intel.com>
parent 203d3d4a
......@@ -186,6 +186,7 @@ config ACPI_HOTPLUG_CPU
config ACPI_THERMAL
tristate "Thermal Zone"
depends on ACPI_PROCESSOR
select THERMAL
default y
help
This driver adds support for ACPI thermal zones. Most mobile and
......
......@@ -43,7 +43,7 @@
#include <linux/seq_file.h>
#include <linux/reboot.h>
#include <asm/uaccess.h>
#include <linux/thermal.h>
#include <acpi/acpi_bus.h>
#include <acpi/acpi_drivers.h>
......@@ -195,6 +195,8 @@ struct acpi_thermal {
struct acpi_thermal_trips trips;
struct acpi_handle_list devices;
struct timer_list timer;
struct thermal_zone_device *thermal_zone;
int tz_enabled;
struct mutex lock;
};
......@@ -732,6 +734,9 @@ static void acpi_thermal_check(void *data)
if (result)
goto unlock;
if (!tz->tz_enabled)
goto unlock;
memset(&tz->state, 0, sizeof(tz->state));
/*
......@@ -825,6 +830,273 @@ static void acpi_thermal_check(void *data)
mutex_unlock(&tz->lock);
}
/* sys I/F for generic thermal sysfs support */
static int thermal_get_temp(struct thermal_zone_device *thermal, char *buf)
{
struct acpi_thermal *tz = thermal->devdata;
if (!tz)
return -EINVAL;
return sprintf(buf, "%ld\n", KELVIN_TO_CELSIUS(tz->temperature));
}
static const char enabled[] = "kernel";
static const char disabled[] = "user";
static int thermal_get_mode(struct thermal_zone_device *thermal,
char *buf)
{
struct acpi_thermal *tz = thermal->devdata;
if (!tz)
return -EINVAL;
return sprintf(buf, "%s\n", tz->tz_enabled ?
enabled : disabled);
}
static int thermal_set_mode(struct thermal_zone_device *thermal,
const char *buf)
{
struct acpi_thermal *tz = thermal->devdata;
int enable;
if (!tz)
return -EINVAL;
/*
* enable/disable thermal management from ACPI thermal driver
*/
if (!strncmp(buf, enabled, sizeof enabled - 1))
enable = 1;
else if (!strncmp(buf, disabled, sizeof disabled - 1))
enable = 0;
else
return -EINVAL;
if (enable != tz->tz_enabled) {
tz->tz_enabled = enable;
ACPI_DEBUG_PRINT((ACPI_DB_INFO,
"%s ACPI thermal control\n",
tz->tz_enabled ? enabled : disabled));
acpi_thermal_check(tz);
}
return 0;
}
static int thermal_get_trip_type(struct thermal_zone_device *thermal,
int trip, char *buf)
{
struct acpi_thermal *tz = thermal->devdata;
int i;
if (!tz || trip < 0)
return -EINVAL;
if (tz->trips.critical.flags.valid) {
if (!trip)
return sprintf(buf, "critical\n");
trip--;
}
if (tz->trips.hot.flags.valid) {
if (!trip)
return sprintf(buf, "hot\n");
trip--;
}
if (tz->trips.passive.flags.valid) {
if (!trip)
return sprintf(buf, "passive\n");
trip--;
}
for (i = 0; i < ACPI_THERMAL_MAX_ACTIVE &&
tz->trips.active[i].flags.valid; i++) {
if (!trip)
return sprintf(buf, "active%d\n", i);
trip--;
}
return -EINVAL;
}
static int thermal_get_trip_temp(struct thermal_zone_device *thermal,
int trip, char *buf)
{
struct acpi_thermal *tz = thermal->devdata;
int i;
if (!tz || trip < 0)
return -EINVAL;
if (tz->trips.critical.flags.valid) {
if (!trip)
return sprintf(buf, "%ld\n", KELVIN_TO_CELSIUS(
tz->trips.critical.temperature));
trip--;
}
if (tz->trips.hot.flags.valid) {
if (!trip)
return sprintf(buf, "%ld\n", KELVIN_TO_CELSIUS(
tz->trips.hot.temperature));
trip--;
}
if (tz->trips.passive.flags.valid) {
if (!trip)
return sprintf(buf, "%ld\n", KELVIN_TO_CELSIUS(
tz->trips.passive.temperature));
trip--;
}
for (i = 0; i < ACPI_THERMAL_MAX_ACTIVE &&
tz->trips.active[i].flags.valid; i++) {
if (!trip)
return sprintf(buf, "%ld\n", KELVIN_TO_CELSIUS(
tz->trips.active[i].temperature));
trip--;
}
return -EINVAL;
}
typedef int (*cb)(struct thermal_zone_device *, int,
struct thermal_cooling_device *);
static int acpi_thermal_cooling_device_cb(struct thermal_zone_device *thermal,
struct thermal_cooling_device *cdev,
cb action)
{
struct acpi_device *device = cdev->devdata;
struct acpi_thermal *tz = thermal->devdata;
acpi_handle handle = device->handle;
int i;
int j;
int trip = -1;
int result = 0;
if (tz->trips.critical.flags.valid)
trip++;
if (tz->trips.hot.flags.valid)
trip++;
if (tz->trips.passive.flags.valid) {
trip++;
for (i = 0; i < tz->trips.passive.devices.count;
i++) {
if (tz->trips.passive.devices.handles[i] !=
handle)
continue;
result = action(thermal, trip, cdev);
if (result)
goto failed;
}
}
for (i = 0; i < ACPI_THERMAL_MAX_ACTIVE; i++) {
if (!tz->trips.active[i].flags.valid)
break;
trip++;
for (j = 0;
j < tz->trips.active[i].devices.count;
j++) {
if (tz->trips.active[i].devices.
handles[j] != handle)
continue;
result = action(thermal, trip, cdev);
if (result)
goto failed;
}
}
for (i = 0; i < tz->devices.count; i++) {
if (tz->devices.handles[i] != handle)
continue;
result = action(thermal, -1, cdev);
if (result)
goto failed;
}
failed:
return result;
}
static int
acpi_thermal_bind_cooling_device(struct thermal_zone_device *thermal,
struct thermal_cooling_device *cdev)
{
return acpi_thermal_cooling_device_cb(thermal, cdev,
thermal_zone_bind_cooling_device);
}
static int
acpi_thermal_unbind_cooling_device(struct thermal_zone_device *thermal,
struct thermal_cooling_device *cdev)
{
return acpi_thermal_cooling_device_cb(thermal, cdev,
thermal_zone_unbind_cooling_device);
}
static struct thermal_zone_device_ops acpi_thermal_zone_ops = {
.bind = acpi_thermal_bind_cooling_device,
.unbind = acpi_thermal_unbind_cooling_device,
.get_temp = thermal_get_temp,
.get_mode = thermal_get_mode,
.set_mode = thermal_set_mode,
.get_trip_type = thermal_get_trip_type,
.get_trip_temp = thermal_get_trip_temp,
};
static int acpi_thermal_register_thermal_zone(struct acpi_thermal *tz)
{
int trips = 0;
int result;
int i;
if (tz->trips.critical.flags.valid)
trips++;
if (tz->trips.hot.flags.valid)
trips++;
if (tz->trips.passive.flags.valid)
trips++;
for (i = 0; i < ACPI_THERMAL_MAX_ACTIVE &&
tz->trips.active[i].flags.valid; i++, trips++);
tz->thermal_zone = thermal_zone_device_register("ACPI thermal zone",
trips, tz, &acpi_thermal_zone_ops);
if (!tz->thermal_zone)
return -ENODEV;
result = sysfs_create_link(&tz->device->dev.kobj,
&tz->thermal_zone->device.kobj, "thermal_zone");
if (result)
return result;
result = sysfs_create_link(&tz->thermal_zone->device.kobj,
&tz->device->dev.kobj, "device");
if (result)
return result;
tz->tz_enabled = 1;
printk(KERN_INFO PREFIX "%s is registered as thermal_zone%d\n",
tz->device->dev.bus_id, tz->thermal_zone->id);
return 0;
}
static void acpi_thermal_unregister_thermal_zone(struct acpi_thermal *tz)
{
sysfs_remove_link(&tz->device->dev.kobj, "thermal_zone");
sysfs_remove_link(&tz->thermal_zone->device.kobj, "device");
thermal_zone_device_unregister(tz->thermal_zone);
tz->thermal_zone = NULL;
}
/* --------------------------------------------------------------------------
FS Interface (/proc)
-------------------------------------------------------------------------- */
......@@ -1260,13 +1532,19 @@ static int acpi_thermal_add(struct acpi_device *device)
strcpy(acpi_device_class(device), ACPI_THERMAL_CLASS);
acpi_driver_data(device) = tz;
mutex_init(&tz->lock);
result = acpi_thermal_get_info(tz);
if (result)
goto end;
goto free_memory;
result = acpi_thermal_register_thermal_zone(tz);
if (result)
goto free_memory;
result = acpi_thermal_add_fs(device);
if (result)
goto end;
goto unregister_thermal_zone;
init_timer(&tz->timer);
......@@ -1277,19 +1555,21 @@ static int acpi_thermal_add(struct acpi_device *device)
acpi_thermal_notify, tz);
if (ACPI_FAILURE(status)) {
result = -ENODEV;
goto end;
goto remove_fs;
}
printk(KERN_INFO PREFIX "%s [%s] (%ld C)\n",
acpi_device_name(device), acpi_device_bid(device),
KELVIN_TO_CELSIUS(tz->temperature));
goto end;
end:
if (result) {
acpi_thermal_remove_fs(device);
kfree(tz);
}
remove_fs:
acpi_thermal_remove_fs(device);
unregister_thermal_zone:
thermal_zone_device_unregister(tz->thermal_zone);
free_memory:
kfree(tz);
end:
return result;
}
......@@ -1329,6 +1609,7 @@ static int acpi_thermal_remove(struct acpi_device *device, int type)
}
acpi_thermal_remove_fs(device);
acpi_thermal_unregister_thermal_zone(tz);
mutex_destroy(&tz->lock);
kfree(tz);
return 0;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment