forked from Minki/linux
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: Zhang Rui <rui.zhang@intel.com> Signed-off-by: Thomas Sujith <sujith.thomas@intel.com> Signed-off-by: Len Brown <len.brown@intel.com>
This commit is contained in:
parent
203d3d4aa4
commit
3f655ef8c4
@ -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;
|
||||
|
Loading…
Reference in New Issue
Block a user