Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

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

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
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -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
+291 −10
Original line number Diff line number Diff line
@@ -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) {
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;