Thermal: int3400 thermal: register to thermal framework

Signed-off-by: Zhang Rui <rui.zhang@intel.com>
This commit is contained in:
Zhang Rui 2014-03-23 23:37:32 +08:00
parent c5738dddc0
commit 0ab15365ff
2 changed files with 104 additions and 0 deletions

View File

@ -237,6 +237,7 @@ config INTEL_SOC_DTS_THERMAL
config INT340X_THERMAL config INT340X_THERMAL
tristate "ACPI INT340X thermal drivers" tristate "ACPI INT340X thermal drivers"
depends on X86 && ACPI depends on X86 && ACPI
select THERMAL_GOV_USER_SPACE
help help
Newer laptops and tablets that use ACPI may have thermal sensors and Newer laptops and tablets that use ACPI may have thermal sensors and
other devices with thermal control capabilities outside the core other devices with thermal control capabilities outside the core

View File

@ -13,6 +13,7 @@
#include <linux/module.h> #include <linux/module.h>
#include <linux/platform_device.h> #include <linux/platform_device.h>
#include <linux/acpi.h> #include <linux/acpi.h>
#include <linux/thermal.h>
struct art { struct art {
acpi_handle source; acpi_handle source;
@ -60,6 +61,8 @@ static u8 *int3400_thermal_uuids[INT3400_THERMAL_MAXIMUM_UUID] = {
struct int3400_thermal_priv { struct int3400_thermal_priv {
struct acpi_device *adev; struct acpi_device *adev;
struct thermal_zone_device *thermal;
int mode;
int art_count; int art_count;
struct art *arts; struct art *arts;
int trt_count; int trt_count;
@ -114,6 +117,36 @@ end:
return result; return result;
} }
static int int3400_thermal_run_osc(acpi_handle handle,
enum int3400_thermal_uuid uuid, bool enable)
{
u32 ret, buf[2];
acpi_status status;
int result = 0;
struct acpi_osc_context context = {
.uuid_str = int3400_thermal_uuids[uuid],
.rev = 1,
.cap.length = 8,
};
buf[OSC_QUERY_DWORD] = 0;
buf[OSC_SUPPORT_DWORD] = enable;
context.cap.pointer = buf;
status = acpi_run_osc(handle, &context);
if (ACPI_SUCCESS(status)) {
ret = *((u32 *)(context.ret.pointer + 4));
if (ret != enable)
result = -EPERM;
} else
result = -EPERM;
kfree(context.ret.pointer);
return result;
}
static int parse_art(struct int3400_thermal_priv *priv) static int parse_art(struct int3400_thermal_priv *priv)
{ {
acpi_handle handle = priv->adev->handle; acpi_handle handle = priv->adev->handle;
@ -243,6 +276,61 @@ end:
return result; return result;
} }
static int int3400_thermal_get_temp(struct thermal_zone_device *thermal,
unsigned long *temp)
{
*temp = 20 * 1000; /* faked temp sensor with 20C */
return 0;
}
static int int3400_thermal_get_mode(struct thermal_zone_device *thermal,
enum thermal_device_mode *mode)
{
struct int3400_thermal_priv *priv = thermal->devdata;
if (!priv)
return -EINVAL;
*mode = priv->mode;
return 0;
}
static int int3400_thermal_set_mode(struct thermal_zone_device *thermal,
enum thermal_device_mode mode)
{
struct int3400_thermal_priv *priv = thermal->devdata;
bool enable;
int result = 0;
if (!priv)
return -EINVAL;
if (mode == THERMAL_DEVICE_ENABLED)
enable = true;
else if (mode == THERMAL_DEVICE_DISABLED)
enable = false;
else
return -EINVAL;
if (enable != priv->mode) {
priv->mode = enable;
/* currently, only PASSIVE COOLING is supported */
result = int3400_thermal_run_osc(priv->adev->handle,
INT3400_THERMAL_PASSIVE_1, enable);
}
return result;
}
static struct thermal_zone_device_ops int3400_thermal_ops = {
.get_temp = int3400_thermal_get_temp,
};
static struct thermal_zone_params int3400_thermal_params = {
.governor_name = "user_space",
.no_hwmon = true,
};
static int int3400_thermal_probe(struct platform_device *pdev) static int int3400_thermal_probe(struct platform_device *pdev)
{ {
struct acpi_device *adev = ACPI_COMPANION(&pdev->dev); struct acpi_device *adev = ACPI_COMPANION(&pdev->dev);
@ -272,7 +360,21 @@ static int int3400_thermal_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, priv); platform_set_drvdata(pdev, priv);
if (priv->uuid_bitmap & 1 << INT3400_THERMAL_PASSIVE_1) {
int3400_thermal_ops.get_mode = int3400_thermal_get_mode;
int3400_thermal_ops.set_mode = int3400_thermal_set_mode;
}
priv->thermal = thermal_zone_device_register("INT3400 Thermal", 0, 0,
priv, &int3400_thermal_ops,
&int3400_thermal_params, 0, 0);
if (IS_ERR(priv->thermal)) {
result = PTR_ERR(priv->thermal);
goto free_trt;
}
return 0; return 0;
free_trt:
kfree(priv->trts);
free_art: free_art:
kfree(priv->arts); kfree(priv->arts);
free_priv: free_priv:
@ -284,6 +386,7 @@ static int int3400_thermal_remove(struct platform_device *pdev)
{ {
struct int3400_thermal_priv *priv = platform_get_drvdata(pdev); struct int3400_thermal_priv *priv = platform_get_drvdata(pdev);
thermal_zone_device_unregister(priv->thermal);
kfree(priv->trts); kfree(priv->trts);
kfree(priv->arts); kfree(priv->arts);
kfree(priv); kfree(priv);