Commit 89d3fa45 authored by Linus Torvalds's avatar Linus Torvalds

Merge branch 'next' of git://git.kernel.org/pub/scm/linux/kernel/git/rzhang/linux

Pull thermal managament updates from Zhang Rui:
 "Specifics:

   - Abstract the code and introduce helper functions for all int340x
     thermal drivers.  From: Srinivas Pandruvada.

   - Reorganize the ACPI LPAT table support code so that it can be
     shared for both ACPI PMIC driver and int340x thermal driver.

   - Add support for Braswell in intel_soc_dts thermal driver.

   - a couple of small fixes/cleanups for step_wise governor and int340x
     thermal driver"

* 'next' of git://git.kernel.org/pub/scm/linux/kernel/git/rzhang/linux:
  Thermal/int340x_thermal: remove unused uuids.
  thermal: step_wise: spelling fixes
  thermal: int340x: fix sparse warning
  Thermal/int340x: LPAT conversion for temperature
  ACPI / PMIC: Use common LPAT table handling functions
  ACPI / LPAT: Common table processing functions
  thermal: Intel SoC DTS: Add Braswell support
  Thermal/int340x/int3402: Provide notification support
  Thermal/int340x/processor_thermal: Add thermal zone support
  Thermal/int340x/int3403: Use int340x thermal API
  Thermal/int340x/int3402: Use int340x thermal API
  Thermal/int340x: Add common thermal zone handler
parents 477ea116 31908f45
...@@ -55,6 +55,7 @@ acpi-$(CONFIG_ACPI_PROCFS_POWER) += cm_sbs.o ...@@ -55,6 +55,7 @@ acpi-$(CONFIG_ACPI_PROCFS_POWER) += cm_sbs.o
ifdef CONFIG_ACPI_VIDEO ifdef CONFIG_ACPI_VIDEO
acpi-y += video_detect.o acpi-y += video_detect.o
endif endif
acpi-y += acpi_lpat.o
# These are (potentially) separate modules # These are (potentially) separate modules
......
/*
* acpi_lpat.c - LPAT table processing functions
*
* Copyright (C) 2015 Intel Corporation. All rights reserved.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License version
* 2 as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#include <linux/module.h>
#include <linux/acpi.h>
#include <acpi/acpi_lpat.h>
/**
* acpi_lpat_raw_to_temp(): Return temperature from raw value through
* LPAT conversion table
*
* @lpat_table: the temperature_raw mapping table structure
* @raw: the raw value, used as a key to get the temerature from the
* above mapping table
*
* A positive converted temperarure value will be returned on success,
* a negative errno will be returned in error cases.
*/
int acpi_lpat_raw_to_temp(struct acpi_lpat_conversion_table *lpat_table,
int raw)
{
int i, delta_temp, delta_raw, temp;
struct acpi_lpat *lpat = lpat_table->lpat;
for (i = 0; i < lpat_table->lpat_count - 1; i++) {
if ((raw >= lpat[i].raw && raw <= lpat[i+1].raw) ||
(raw <= lpat[i].raw && raw >= lpat[i+1].raw))
break;
}
if (i == lpat_table->lpat_count - 1)
return -ENOENT;
delta_temp = lpat[i+1].temp - lpat[i].temp;
delta_raw = lpat[i+1].raw - lpat[i].raw;
temp = lpat[i].temp + (raw - lpat[i].raw) * delta_temp / delta_raw;
return temp;
}
EXPORT_SYMBOL_GPL(acpi_lpat_raw_to_temp);
/**
* acpi_lpat_temp_to_raw(): Return raw value from temperature through
* LPAT conversion table
*
* @lpat: the temperature_raw mapping table
* @temp: the temperature, used as a key to get the raw value from the
* above mapping table
*
* A positive converted temperature value will be returned on success,
* a negative errno will be returned in error cases.
*/
int acpi_lpat_temp_to_raw(struct acpi_lpat_conversion_table *lpat_table,
int temp)
{
int i, delta_temp, delta_raw, raw;
struct acpi_lpat *lpat = lpat_table->lpat;
for (i = 0; i < lpat_table->lpat_count - 1; i++) {
if (temp >= lpat[i].temp && temp <= lpat[i+1].temp)
break;
}
if (i == lpat_table->lpat_count - 1)
return -ENOENT;
delta_temp = lpat[i+1].temp - lpat[i].temp;
delta_raw = lpat[i+1].raw - lpat[i].raw;
raw = lpat[i].raw + (temp - lpat[i].temp) * delta_raw / delta_temp;
return raw;
}
EXPORT_SYMBOL_GPL(acpi_lpat_temp_to_raw);
/**
* acpi_lpat_get_conversion_table(): Parse ACPI LPAT table if present.
*
* @handle: Handle to acpi device
*
* Parse LPAT table to a struct of type acpi_lpat_table. On success
* it returns a pointer to newly allocated table. This table must
* be freed by the caller when finished processing, using a call to
* acpi_lpat_free_conversion_table.
*/
struct acpi_lpat_conversion_table *acpi_lpat_get_conversion_table(acpi_handle
handle)
{
struct acpi_lpat_conversion_table *lpat_table = NULL;
struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
union acpi_object *obj_p, *obj_e;
int *lpat, i;
acpi_status status;
status = acpi_evaluate_object(handle, "LPAT", NULL, &buffer);
if (ACPI_FAILURE(status))
return NULL;
obj_p = (union acpi_object *)buffer.pointer;
if (!obj_p || (obj_p->type != ACPI_TYPE_PACKAGE) ||
(obj_p->package.count % 2) || (obj_p->package.count < 4))
goto out;
lpat = kcalloc(obj_p->package.count, sizeof(int), GFP_KERNEL);
if (!lpat)
goto out;
for (i = 0; i < obj_p->package.count; i++) {
obj_e = &obj_p->package.elements[i];
if (obj_e->type != ACPI_TYPE_INTEGER) {
kfree(lpat);
goto out;
}
lpat[i] = (s64)obj_e->integer.value;
}
lpat_table = kzalloc(sizeof(*lpat_table), GFP_KERNEL);
if (!lpat_table) {
kfree(lpat);
goto out;
}
lpat_table->lpat = (struct acpi_lpat *)lpat;
lpat_table->lpat_count = obj_p->package.count / 2;
out:
kfree(buffer.pointer);
return lpat_table;
}
EXPORT_SYMBOL_GPL(acpi_lpat_get_conversion_table);
/**
* acpi_lpat_free_conversion_table(): Free LPAT table.
*
* @lpat_table: the temperature_raw mapping table structure
*
* Frees the LPAT table previously allocated by a call to
* acpi_lpat_get_conversion_table.
*/
void acpi_lpat_free_conversion_table(struct acpi_lpat_conversion_table
*lpat_table)
{
if (lpat_table) {
kfree(lpat_table->lpat);
kfree(lpat_table);
}
}
EXPORT_SYMBOL_GPL(acpi_lpat_free_conversion_table);
MODULE_LICENSE("GPL");
...@@ -16,20 +16,15 @@ ...@@ -16,20 +16,15 @@
#include <linux/module.h> #include <linux/module.h>
#include <linux/acpi.h> #include <linux/acpi.h>
#include <linux/regmap.h> #include <linux/regmap.h>
#include <acpi/acpi_lpat.h>
#include "intel_pmic.h" #include "intel_pmic.h"
#define PMIC_POWER_OPREGION_ID 0x8d #define PMIC_POWER_OPREGION_ID 0x8d
#define PMIC_THERMAL_OPREGION_ID 0x8c #define PMIC_THERMAL_OPREGION_ID 0x8c
struct acpi_lpat {
int temp;
int raw;
};
struct intel_pmic_opregion { struct intel_pmic_opregion {
struct mutex lock; struct mutex lock;
struct acpi_lpat *lpat; struct acpi_lpat_conversion_table *lpat_table;
int lpat_count;
struct regmap *regmap; struct regmap *regmap;
struct intel_pmic_opregion_data *data; struct intel_pmic_opregion_data *data;
}; };
...@@ -50,105 +45,6 @@ static int pmic_get_reg_bit(int address, struct pmic_table *table, ...@@ -50,105 +45,6 @@ static int pmic_get_reg_bit(int address, struct pmic_table *table,
return -ENOENT; return -ENOENT;
} }
/**
* raw_to_temp(): Return temperature from raw value through LPAT table
*
* @lpat: the temperature_raw mapping table
* @count: the count of the above mapping table
* @raw: the raw value, used as a key to get the temerature from the
* above mapping table
*
* A positive value will be returned on success, a negative errno will
* be returned in error cases.
*/
static int raw_to_temp(struct acpi_lpat *lpat, int count, int raw)
{
int i, delta_temp, delta_raw, temp;
for (i = 0; i < count - 1; i++) {
if ((raw >= lpat[i].raw && raw <= lpat[i+1].raw) ||
(raw <= lpat[i].raw && raw >= lpat[i+1].raw))
break;
}
if (i == count - 1)
return -ENOENT;
delta_temp = lpat[i+1].temp - lpat[i].temp;
delta_raw = lpat[i+1].raw - lpat[i].raw;
temp = lpat[i].temp + (raw - lpat[i].raw) * delta_temp / delta_raw;
return temp;
}
/**
* temp_to_raw(): Return raw value from temperature through LPAT table
*
* @lpat: the temperature_raw mapping table
* @count: the count of the above mapping table
* @temp: the temperature, used as a key to get the raw value from the
* above mapping table
*
* A positive value will be returned on success, a negative errno will
* be returned in error cases.
*/
static int temp_to_raw(struct acpi_lpat *lpat, int count, int temp)
{
int i, delta_temp, delta_raw, raw;
for (i = 0; i < count - 1; i++) {
if (temp >= lpat[i].temp && temp <= lpat[i+1].temp)
break;
}
if (i == count - 1)
return -ENOENT;
delta_temp = lpat[i+1].temp - lpat[i].temp;
delta_raw = lpat[i+1].raw - lpat[i].raw;
raw = lpat[i].raw + (temp - lpat[i].temp) * delta_raw / delta_temp;
return raw;
}
static void pmic_thermal_lpat(struct intel_pmic_opregion *opregion,
acpi_handle handle, struct device *dev)
{
struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
union acpi_object *obj_p, *obj_e;
int *lpat, i;
acpi_status status;
status = acpi_evaluate_object(handle, "LPAT", NULL, &buffer);
if (ACPI_FAILURE(status))
return;
obj_p = (union acpi_object *)buffer.pointer;
if (!obj_p || (obj_p->type != ACPI_TYPE_PACKAGE) ||
(obj_p->package.count % 2) || (obj_p->package.count < 4))
goto out;
lpat = devm_kmalloc(dev, sizeof(int) * obj_p->package.count,
GFP_KERNEL);
if (!lpat)
goto out;
for (i = 0; i < obj_p->package.count; i++) {
obj_e = &obj_p->package.elements[i];
if (obj_e->type != ACPI_TYPE_INTEGER) {
devm_kfree(dev, lpat);
goto out;
}
lpat[i] = (s64)obj_e->integer.value;
}
opregion->lpat = (struct acpi_lpat *)lpat;
opregion->lpat_count = obj_p->package.count / 2;
out:
kfree(buffer.pointer);
}
static acpi_status intel_pmic_power_handler(u32 function, static acpi_status intel_pmic_power_handler(u32 function,
acpi_physical_address address, u32 bits, u64 *value64, acpi_physical_address address, u32 bits, u64 *value64,
void *handler_context, void *region_context) void *handler_context, void *region_context)
...@@ -192,12 +88,12 @@ static int pmic_read_temp(struct intel_pmic_opregion *opregion, ...@@ -192,12 +88,12 @@ static int pmic_read_temp(struct intel_pmic_opregion *opregion,
if (raw_temp < 0) if (raw_temp < 0)
return raw_temp; return raw_temp;
if (!opregion->lpat) { if (!opregion->lpat_table) {
*value = raw_temp; *value = raw_temp;
return 0; return 0;
} }
temp = raw_to_temp(opregion->lpat, opregion->lpat_count, raw_temp); temp = acpi_lpat_raw_to_temp(opregion->lpat_table, raw_temp);
if (temp < 0) if (temp < 0)
return temp; return temp;
...@@ -223,9 +119,8 @@ static int pmic_thermal_aux(struct intel_pmic_opregion *opregion, int reg, ...@@ -223,9 +119,8 @@ static int pmic_thermal_aux(struct intel_pmic_opregion *opregion, int reg,
if (!opregion->data->update_aux) if (!opregion->data->update_aux)
return -ENXIO; return -ENXIO;
if (opregion->lpat) { if (opregion->lpat_table) {
raw_temp = temp_to_raw(opregion->lpat, opregion->lpat_count, raw_temp = acpi_lpat_temp_to_raw(opregion->lpat_table, *value);
*value);
if (raw_temp < 0) if (raw_temp < 0)
return raw_temp; return raw_temp;
} else { } else {
...@@ -314,6 +209,7 @@ int intel_pmic_install_opregion_handler(struct device *dev, acpi_handle handle, ...@@ -314,6 +209,7 @@ int intel_pmic_install_opregion_handler(struct device *dev, acpi_handle handle,
{ {
acpi_status status; acpi_status status;
struct intel_pmic_opregion *opregion; struct intel_pmic_opregion *opregion;
int ret;
if (!dev || !regmap || !d) if (!dev || !regmap || !d)
return -EINVAL; return -EINVAL;
...@@ -327,14 +223,16 @@ int intel_pmic_install_opregion_handler(struct device *dev, acpi_handle handle, ...@@ -327,14 +223,16 @@ int intel_pmic_install_opregion_handler(struct device *dev, acpi_handle handle,
mutex_init(&opregion->lock); mutex_init(&opregion->lock);
opregion->regmap = regmap; opregion->regmap = regmap;
pmic_thermal_lpat(opregion, handle, dev); opregion->lpat_table = acpi_lpat_get_conversion_table(handle);
status = acpi_install_address_space_handler(handle, status = acpi_install_address_space_handler(handle,
PMIC_POWER_OPREGION_ID, PMIC_POWER_OPREGION_ID,
intel_pmic_power_handler, intel_pmic_power_handler,
NULL, opregion); NULL, opregion);
if (ACPI_FAILURE(status)) if (ACPI_FAILURE(status)) {
return -ENODEV; ret = -ENODEV;
goto out_error;
}
status = acpi_install_address_space_handler(handle, status = acpi_install_address_space_handler(handle,
PMIC_THERMAL_OPREGION_ID, PMIC_THERMAL_OPREGION_ID,
...@@ -343,11 +241,16 @@ int intel_pmic_install_opregion_handler(struct device *dev, acpi_handle handle, ...@@ -343,11 +241,16 @@ int intel_pmic_install_opregion_handler(struct device *dev, acpi_handle handle,
if (ACPI_FAILURE(status)) { if (ACPI_FAILURE(status)) {
acpi_remove_address_space_handler(handle, PMIC_POWER_OPREGION_ID, acpi_remove_address_space_handler(handle, PMIC_POWER_OPREGION_ID,
intel_pmic_power_handler); intel_pmic_power_handler);
return -ENODEV; ret = -ENODEV;
goto out_error;
} }
opregion->data = d; opregion->data = d;
return 0; return 0;
out_error:
acpi_lpat_free_conversion_table(opregion->lpat_table);
return ret;
} }
EXPORT_SYMBOL_GPL(intel_pmic_install_opregion_handler); EXPORT_SYMBOL_GPL(intel_pmic_install_opregion_handler);
......
obj-$(CONFIG_INT340X_THERMAL) += int3400_thermal.o obj-$(CONFIG_INT340X_THERMAL) += int3400_thermal.o
obj-$(CONFIG_INT340X_THERMAL) += int340x_thermal_zone.o
obj-$(CONFIG_INT340X_THERMAL) += int3402_thermal.o obj-$(CONFIG_INT340X_THERMAL) += int3402_thermal.o
obj-$(CONFIG_INT340X_THERMAL) += int3403_thermal.o obj-$(CONFIG_INT340X_THERMAL) += int3403_thermal.o
obj-$(CONFIG_INT340X_THERMAL) += processor_thermal_device.o obj-$(CONFIG_INT340X_THERMAL) += processor_thermal_device.o
......
...@@ -18,19 +18,15 @@ ...@@ -18,19 +18,15 @@
enum int3400_thermal_uuid { enum int3400_thermal_uuid {
INT3400_THERMAL_PASSIVE_1, INT3400_THERMAL_PASSIVE_1,
INT3400_THERMAL_PASSIVE_2,
INT3400_THERMAL_ACTIVE, INT3400_THERMAL_ACTIVE,
INT3400_THERMAL_CRITICAL, INT3400_THERMAL_CRITICAL,
INT3400_THERMAL_COOLING_MODE,
INT3400_THERMAL_MAXIMUM_UUID, INT3400_THERMAL_MAXIMUM_UUID,
}; };
static u8 *int3400_thermal_uuids[INT3400_THERMAL_MAXIMUM_UUID] = { static u8 *int3400_thermal_uuids[INT3400_THERMAL_MAXIMUM_UUID] = {
"42A441D6-AE6A-462b-A84B-4A8CE79027D3", "42A441D6-AE6A-462b-A84B-4A8CE79027D3",
"9E04115A-AE87-4D1C-9500-0F3E340BFE75",
"3A95C389-E4B8-4629-A526-C52C88626BAE", "3A95C389-E4B8-4629-A526-C52C88626BAE",
"97C68AE7-15FA-499c-B8C9-5DA81D606E0A", "97C68AE7-15FA-499c-B8C9-5DA81D606E0A",
"16CAF1B7-DD38-40ed-B1C1-1B8A1913D531",
}; };
struct int3400_thermal_priv { struct int3400_thermal_priv {
......
...@@ -14,152 +14,39 @@ ...@@ -14,152 +14,39 @@
#include <linux/platform_device.h> #include <linux/platform_device.h>
#include <linux/acpi.h> #include <linux/acpi.h>
#include <linux/thermal.h> #include <linux/thermal.h>
#include "int340x_thermal_zone.h"
#define ACPI_ACTIVE_COOLING_MAX_NR 10 #define INT3402_PERF_CHANGED_EVENT 0x80
#define INT3402_THERMAL_EVENT 0x90
struct active_trip {
unsigned long temp;
int id;
bool valid;
};
struct int3402_thermal_data { struct int3402_thermal_data {
unsigned long *aux_trips;
int aux_trip_nr;
unsigned long psv_temp;
int psv_trip_id;
unsigned long crt_temp;
int crt_trip_id;
unsigned long hot_temp;
int hot_trip_id;
struct active_trip act_trips[ACPI_ACTIVE_COOLING_MAX_NR];
acpi_handle *handle; acpi_handle *handle;
struct int34x_thermal_zone *int340x_zone;
}; };
static int int3402_thermal_get_zone_temp(struct thermal_zone_device *zone, static void int3402_notify(acpi_handle handle, u32 event, void *data)
unsigned long *temp)
{ {
struct int3402_thermal_data *d = zone->devdata; struct int3402_thermal_data *priv = data;
unsigned long long tmp;
acpi_status status;
status = acpi_evaluate_integer(d->handle, "_TMP", NULL, &tmp);
if (ACPI_FAILURE(status))
return -ENODEV;
/* _TMP returns the temperature in tenths of degrees Kelvin */ if (!priv)
*temp = DECI_KELVIN_TO_MILLICELSIUS(tmp); return;
return 0; switch (event) {
} case INT3402_PERF_CHANGED_EVENT:
static int int3402_thermal_get_trip_temp(struct thermal_zone_device *zone,
int trip, unsigned long *temp)
{
struct int3402_thermal_data *d = zone->devdata;
int i;
if (trip < d->aux_trip_nr)
*temp = d->aux_trips[trip];
else if (trip == d->crt_trip_id)
*temp = d->crt_temp;
else if (trip == d->psv_trip_id)
*temp = d->psv_temp;
else if (trip == d->hot_trip_id)
*temp = d->hot_temp;
else {
for (i = 0; i < ACPI_ACTIVE_COOLING_MAX_NR; i++) {
if (d->act_trips[i].valid &&
d->act_trips[i].id == trip) {
*temp = d->act_trips[i].temp;
break; break;
} case INT3402_THERMAL_EVENT:
} int340x_thermal_zone_device_update(priv->int340x_zone);
if (i == ACPI_ACTIVE_COOLING_MAX_NR) break;
return -EINVAL; default:
}
return 0;
}
static int int3402_thermal_get_trip_type(struct thermal_zone_device *zone,
int trip, enum thermal_trip_type *type)
{
struct int3402_thermal_data *d = zone->devdata;
int i;
if (trip < d->aux_trip_nr)
*type = THERMAL_TRIP_PASSIVE;
else if (trip == d->crt_trip_id)
*type = THERMAL_TRIP_CRITICAL;
else if (trip == d->hot_trip_id)
*type = THERMAL_TRIP_HOT;
else if (trip == d->psv_trip_id)
*type = THERMAL_TRIP_PASSIVE;
else {
for (i = 0; i < ACPI_ACTIVE_COOLING_MAX_NR; i++) {
if (d->act_trips[i].valid &&
d->act_trips[i].id == trip) {
*type = THERMAL_TRIP_ACTIVE;
break; break;
} }
}
if (i == ACPI_ACTIVE_COOLING_MAX_NR)
return -EINVAL;
}
return 0;
}
static int int3402_thermal_set_trip_temp(struct thermal_zone_device *zone, int trip,
unsigned long temp)
{
struct int3402_thermal_data *d = zone->devdata;
acpi_status status;
char name[10];
snprintf(name, sizeof(name), "PAT%d", trip);
status = acpi_execute_simple_method(d->handle, name,
MILLICELSIUS_TO_DECI_KELVIN(temp));
if (ACPI_FAILURE(status))
return -EIO;
d->aux_trips[trip] = temp;
return 0;
}
static struct thermal_zone_device_ops int3402_thermal_zone_ops = {
.get_temp = int3402_thermal_get_zone_temp,
.get_trip_temp = int3402_thermal_get_trip_temp,
.get_trip_type = int3402_thermal_get_trip_type,
.set_trip_temp = int3402_thermal_set_trip_temp,
};
static struct thermal_zone_params int3402_thermal_params = {
.governor_name = "user_space",
.no_hwmon = true,
};
static int int3402_thermal_get_temp(acpi_handle handle, char *name,
unsigned long *temp)
{
unsigned long long r;
acpi_status status;
status = acpi_evaluate_integer(handle, name, NULL, &r);
if (ACPI_FAILURE(status))
return -EIO;
*temp = DECI_KELVIN_TO_MILLICELSIUS(r);
return 0;
} }
static int int3402_thermal_probe(struct platform_device *pdev) static int int3402_thermal_probe(struct platform_device *pdev)
{ {
struct acpi_device *adev = ACPI_COMPANION(&pdev->dev); struct acpi_device *adev = ACPI_COMPANION(&pdev->dev);
struct int3402_thermal_data *d; struct int3402_thermal_data *d;
struct thermal_zone_device *zone; int ret;
acpi_status status;
unsigned long long trip_cnt;
int trip_mask = 0, i;
if (!acpi_has_method(adev->handle, "_TMP")) if (!acpi_has_method(adev->handle, "_TMP"))
return -ENODEV; return -ENODEV;
...@@ -168,54 +55,33 @@ static int int3402_thermal_probe(struct platform_device *pdev) ...@@ -168,54 +55,33 @@ static int int3402_thermal_probe(struct platform_device *pdev)
if (!d) if (!d)
return -ENOMEM; return -ENOMEM;
status = acpi_evaluate_integer(adev->handle, "PATC", NULL, &trip_cnt); d->int340x_zone = int340x_thermal_zone_add(adev, NULL);
if (ACPI_FAILURE(status)) if (IS_ERR(d->int340x_zone))
trip_cnt = 0; return PTR_ERR(d->int340x_zone);
else {
d->aux_trips = devm_kzalloc(&pdev->dev, ret = acpi_install_notify_handler(adev->handle,
sizeof(*d->aux_trips) * trip_cnt, GFP_KERNEL); ACPI_DEVICE_NOTIFY,
if (!d->aux_trips) int3402_notify,
return -ENOMEM; d);
trip_mask = trip_cnt - 1; if (ret) {
d->handle = adev->handle; int340x_thermal_zone_remove(d->int340x_zone);
d->aux_trip_nr = trip_cnt; return ret;
}
d->crt_trip_id = -1;
if (!int3402_thermal_get_temp(adev->handle, "_CRT", &d->crt_temp))
d->crt_trip_id = trip_cnt++;
d->hot_trip_id = -1;
if (!int3402_thermal_get_temp(adev->handle, "_HOT", &d->hot_temp))
d->hot_trip_id = trip_cnt++;
d->psv_trip_id = -1;
if (!int3402_thermal_get_temp(adev->handle, "_PSV", &d->psv_temp))
d->psv_trip_id = trip_cnt++;
for (i = 0; i < ACPI_ACTIVE_COOLING_MAX_NR; i++) {
char name[5] = { '_', 'A', 'C', '0' + i, '\0' };
if (int3402_thermal_get_temp(adev->handle, name,
&d->act_trips[i].temp))
break;
d->act_trips[i].id = trip_cnt++;
d->act_trips[i].valid = true;
} }
zone = thermal_zone_device_register(acpi_device_bid(adev), trip_cnt, d->handle = adev->handle;
trip_mask, d, platform_set_drvdata(pdev, d);
&int3402_thermal_zone_ops,
&int3402_thermal_params,
0, 0);
if (IS_ERR(zone))
return PTR_ERR(zone);
platform_set_drvdata(pdev, zone);
return 0; return 0;
} }
static int int3402_thermal_remove(struct platform_device *pdev) static int int3402_thermal_remove(struct platform_device *pdev)
{ {
struct thermal_zone_device *zone = platform_get_drvdata(pdev); struct int3402_thermal_data *d = platform_get_drvdata(pdev);
acpi_remove_notify_handler(d->handle,
ACPI_DEVICE_NOTIFY, int3402_notify);
int340x_thermal_zone_remove(d->int340x_zone);
thermal_zone_device_unregister(zone);
return 0; return 0;
} }
......
...@@ -19,6 +19,7 @@ ...@@ -19,6 +19,7 @@
#include <linux/acpi.h> #include <linux/acpi.h>
#include <linux/thermal.h> #include <linux/thermal.h>
#include <linux/platform_device.h> #include <linux/platform_device.h>
#include "int340x_thermal_zone.h"
#define INT3403_TYPE_SENSOR 0x03 #define INT3403_TYPE_SENSOR 0x03
#define INT3403_TYPE_CHARGER 0x0B #define INT3403_TYPE_CHARGER 0x0B
...@@ -26,18 +27,9 @@ ...@@ -26,18 +27,9 @@
#define INT3403_PERF_CHANGED_EVENT 0x80 #define INT3403_PERF_CHANGED_EVENT 0x80
#define INT3403_THERMAL_EVENT 0x90 #define INT3403_THERMAL_EVENT 0x90
#define DECI_KELVIN_TO_MILLI_CELSIUS(t, off) (((t) - (off)) * 100) /* Preserved structure for future expandbility */
#define KELVIN_OFFSET 2732
#define MILLI_CELSIUS_TO_DECI_KELVIN(t, off) (((t) / 100) + (off))
struct int3403_sensor { struct int3403_sensor {
struct thermal_zone_device *tzone; struct int34x_thermal_zone *int340x_zone;
unsigned long *thresholds;
unsigned long crit_temp;
int crit_trip_id;
unsigned long psv_temp;
int psv_trip_id;
}; };
struct int3403_performance_state { struct int3403_performance_state {
...@@ -63,126 +55,6 @@ struct int3403_priv { ...@@ -63,126 +55,6 @@ struct int3403_priv {
void *priv; void *priv;
}; };
static int sys_get_curr_temp(struct thermal_zone_device *tzone,
unsigned long *temp)
{
struct int3403_priv *priv = tzone->devdata;
struct acpi_device *device = priv->adev;
unsigned long long tmp;
acpi_status status;
status = acpi_evaluate_integer(device->handle, "_TMP", NULL, &tmp);
if (ACPI_FAILURE(status))
return -EIO;
*temp = DECI_KELVIN_TO_MILLI_CELSIUS(tmp, KELVIN_OFFSET);
return 0;
}
static int sys_get_trip_hyst(struct thermal_zone_device *tzone,
int trip, unsigned long *temp)
{
struct int3403_priv *priv = tzone->devdata;
struct acpi_device *device = priv->adev;
unsigned long long hyst;
acpi_status status;
status = acpi_evaluate_integer(device->handle, "GTSH", NULL, &hyst);
if (ACPI_FAILURE(status))
return -EIO;
/*
* Thermal hysteresis represents a temperature difference.
* Kelvin and Celsius have same degree size. So the
* conversion here between tenths of degree Kelvin unit
* and Milli-Celsius unit is just to multiply 100.
*/
*temp = hyst * 100;
return 0;
}
static int sys_get_trip_temp(struct thermal_zone_device *tzone,
int trip, unsigned long *temp)
{
struct int3403_priv *priv = tzone->devdata;
struct int3403_sensor *obj = priv->priv;
if (priv->type != INT3403_TYPE_SENSOR || !obj)
return -EINVAL;
if (trip == obj->crit_trip_id)
*temp = obj->crit_temp;
else if (trip == obj->psv_trip_id)
*temp = obj->psv_temp;
else {
/*
* get_trip_temp is a mandatory callback but
* PATx method doesn't return any value, so return
* cached value, which was last set from user space
*/
*temp = obj->thresholds[trip];
}
return 0;
}
static int sys_get_trip_type(struct thermal_zone_device *thermal,
int trip, enum thermal_trip_type *type)
{
struct int3403_priv *priv = thermal->devdata;
struct int3403_sensor *obj = priv->priv;
/* Mandatory callback, may not mean much here */
if (trip == obj->crit_trip_id)
*type = THERMAL_TRIP_CRITICAL;
else
*type = THERMAL_TRIP_PASSIVE;
return 0;
}
int sys_set_trip_temp(struct thermal_zone_device *tzone, int trip,
unsigned long temp)
{
struct int3403_priv *priv = tzone->devdata;
struct acpi_device *device = priv->adev;
struct int3403_sensor *obj = priv->priv;
acpi_status status;
char name[10];
int ret = 0;
snprintf(name, sizeof(name), "PAT%d", trip);
if (acpi_has_method(device->handle, name)) {
status = acpi_execute_simple_method(device->handle, name,
MILLI_CELSIUS_TO_DECI_KELVIN(temp,
KELVIN_OFFSET));
if (ACPI_FAILURE(status))
ret = -EIO;
else
obj->thresholds[trip] = temp;
} else {
ret = -EIO;
dev_err(&device->dev, "sys_set_trip_temp: method not found\n");
}
return ret;
}
static struct thermal_zone_device_ops tzone_ops = {
.get_temp = sys_get_curr_temp,
.get_trip_temp = sys_get_trip_temp,
.get_trip_type = sys_get_trip_type,
.set_trip_temp = sys_set_trip_temp,
.get_trip_hyst = sys_get_trip_hyst,
};
static struct thermal_zone_params int3403_thermal_params = {
.governor_name = "user_space",
.no_hwmon = true,
};
static void int3403_notify(acpi_handle handle, static void int3403_notify(acpi_handle handle,
u32 event, void *data) u32 event, void *data)
{ {
...@@ -200,7 +72,7 @@ static void int3403_notify(acpi_handle handle, ...@@ -200,7 +72,7 @@ static void int3403_notify(acpi_handle handle,
case INT3403_PERF_CHANGED_EVENT: case INT3403_PERF_CHANGED_EVENT:
break; break;
case INT3403_THERMAL_EVENT: case INT3403_THERMAL_EVENT:
thermal_zone_device_update(obj->tzone); int340x_thermal_zone_device_update(obj->int340x_zone);
break; break;
default: default:
dev_err(&priv->pdev->dev, "Unsupported event [0x%x]\n", event); dev_err(&priv->pdev->dev, "Unsupported event [0x%x]\n", event);
...@@ -208,41 +80,10 @@ static void int3403_notify(acpi_handle handle, ...@@ -208,41 +80,10 @@ static void int3403_notify(acpi_handle handle,
} }
} }
static int sys_get_trip_crt(struct acpi_device *device, unsigned long *temp)
{
unsigned long long crt;
acpi_status status;
status = acpi_evaluate_integer(device->handle, "_CRT", NULL, &crt);
if (ACPI_FAILURE(status))
return -EIO;
*temp = DECI_KELVIN_TO_MILLI_CELSIUS(crt, KELVIN_OFFSET);
return 0;
}
static int sys_get_trip_psv(struct acpi_device *device, unsigned long *temp)
{
unsigned long long psv;
acpi_status status;
status = acpi_evaluate_integer(device->handle, "_PSV", NULL, &psv);
if (ACPI_FAILURE(status))
return -EIO;
*temp = DECI_KELVIN_TO_MILLI_CELSIUS(psv, KELVIN_OFFSET);
return 0;
}
static int int3403_sensor_add(struct int3403_priv *priv) static int int3403_sensor_add(struct int3403_priv *priv)
{ {
int result = 0; int result = 0;
acpi_status status;
struct int3403_sensor *obj; struct int3403_sensor *obj;
unsigned long long trip_cnt;
int trip_mask = 0;
obj = devm_kzalloc(&priv->pdev->dev, sizeof(*obj), GFP_KERNEL); obj = devm_kzalloc(&priv->pdev->dev, sizeof(*obj), GFP_KERNEL);
if (!obj) if (!obj)
...@@ -250,39 +91,9 @@ static int int3403_sensor_add(struct int3403_priv *priv) ...@@ -250,39 +91,9 @@ static int int3403_sensor_add(struct int3403_priv *priv)
priv->priv = obj; priv->priv = obj;
status = acpi_evaluate_integer(priv->adev->handle, "PATC", NULL, obj->int340x_zone = int340x_thermal_zone_add(priv->adev, NULL);
&trip_cnt); if (IS_ERR(obj->int340x_zone))
if (ACPI_FAILURE(status)) return PTR_ERR(obj->int340x_zone);
trip_cnt = 0;
if (trip_cnt) {
/* We have to cache, thresholds can't be readback */
obj->thresholds = devm_kzalloc(&priv->pdev->dev,
sizeof(*obj->thresholds) * trip_cnt,
GFP_KERNEL);
if (!obj->thresholds) {
result = -ENOMEM;
goto err_free_obj;
}
trip_mask = BIT(trip_cnt) - 1;
}
obj->psv_trip_id = -1;
if (!sys_get_trip_psv(priv->adev, &obj->psv_temp))
obj->psv_trip_id = trip_cnt++;
obj->crit_trip_id = -1;
if (!sys_get_trip_crt(priv->adev, &obj->crit_temp))
obj->crit_trip_id = trip_cnt++;
obj->tzone = thermal_zone_device_register(acpi_device_bid(priv->adev),
trip_cnt, trip_mask, priv, &tzone_ops,
&int3403_thermal_params, 0, 0);
if (IS_ERR(obj->tzone)) {
result = PTR_ERR(obj->tzone);
obj->tzone = NULL;
goto err_free_obj;
}
result = acpi_install_notify_handler(priv->adev->handle, result = acpi_install_notify_handler(priv->adev->handle,
ACPI_DEVICE_NOTIFY, int3403_notify, ACPI_DEVICE_NOTIFY, int3403_notify,
...@@ -293,7 +104,7 @@ static int int3403_sensor_add(struct int3403_priv *priv) ...@@ -293,7 +104,7 @@ static int int3403_sensor_add(struct int3403_priv *priv)
return 0; return 0;
err_free_obj: err_free_obj:
thermal_zone_device_unregister(obj->tzone); int340x_thermal_zone_remove(obj->int340x_zone);
return result; return result;
} }
...@@ -303,7 +114,8 @@ static int int3403_sensor_remove(struct int3403_priv *priv) ...@@ -303,7 +114,8 @@ static int int3403_sensor_remove(struct int3403_priv *priv)
acpi_remove_notify_handler(priv->adev->handle, acpi_remove_notify_handler(priv->adev->handle,
ACPI_DEVICE_NOTIFY, int3403_notify); ACPI_DEVICE_NOTIFY, int3403_notify);
thermal_zone_device_unregister(obj->tzone); int340x_thermal_zone_remove(obj->int340x_zone);
return 0; return 0;
} }
......
/*
* int340x_thermal_zone.c
* Copyright (c) 2015, Intel Corporation.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
*/
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/acpi.h>
#include <linux/thermal.h>
#include "int340x_thermal_zone.h"
static int int340x_thermal_get_zone_temp(struct thermal_zone_device *zone,
unsigned long *temp)
{
struct int34x_thermal_zone *d = zone->devdata;
unsigned long long tmp;
acpi_status status;
if (d->override_ops && d->override_ops->get_temp)
return d->override_ops->get_temp(zone, temp);
status = acpi_evaluate_integer(d->adev->handle, "_TMP", NULL, &tmp);
if (ACPI_FAILURE(status))
return -EIO;
if (d->lpat_table) {
int conv_temp;
conv_temp = acpi_lpat_raw_to_temp(d->lpat_table, (int)tmp);
if (conv_temp < 0)
return conv_temp;
*temp = (unsigned long)conv_temp * 10;
} else
/* _TMP returns the temperature in tenths of degrees Kelvin */
*temp = DECI_KELVIN_TO_MILLICELSIUS(tmp);
return 0;
}
static int int340x_thermal_get_trip_temp(struct thermal_zone_device *zone,
int trip, unsigned long *temp)
{
struct int34x_thermal_zone *d = zone->devdata;
int i;
if (d->override_ops && d->override_ops->get_trip_temp)
return d->override_ops->get_trip_temp(zone, trip, temp);
if (trip < d->aux_trip_nr)
*temp = d->aux_trips[trip];
else if (trip == d->crt_trip_id)
*temp = d->crt_temp;
else if (trip == d->psv_trip_id)
*temp = d->psv_temp;
else if (trip == d->hot_trip_id)
*temp = d->hot_temp;
else {
for (i = 0; i < INT340X_THERMAL_MAX_ACT_TRIP_COUNT; i++) {
if (d->act_trips[i].valid &&
d->act_trips[i].id == trip) {
*temp = d->act_trips[i].temp;
break;
}
}
if (i == INT340X_THERMAL_MAX_ACT_TRIP_COUNT)
return -EINVAL;
}
return 0;
}
static int int340x_thermal_get_trip_type(struct thermal_zone_device *zone,
int trip,
enum thermal_trip_type *type)
{
struct int34x_thermal_zone *d = zone->devdata;
int i;
if (d->override_ops && d->override_ops->get_trip_type)
return d->override_ops->get_trip_type(zone, trip, type);
if (trip < d->aux_trip_nr)
*type = THERMAL_TRIP_PASSIVE;
else if (trip == d->crt_trip_id)
*type = THERMAL_TRIP_CRITICAL;
else if (trip == d->hot_trip_id)
*type = THERMAL_TRIP_HOT;
else if (trip == d->psv_trip_id)
*type = THERMAL_TRIP_PASSIVE;
else {
for (i = 0; i < INT340X_THERMAL_MAX_ACT_TRIP_COUNT; i++) {
if (d->act_trips[i].valid &&
d->act_trips[i].id == trip) {
*type = THERMAL_TRIP_ACTIVE;
break;
}
}
if (i == INT340X_THERMAL_MAX_ACT_TRIP_COUNT)
return -EINVAL;
}
return 0;
}
static int int340x_thermal_set_trip_temp(struct thermal_zone_device *zone,
int trip, unsigned long temp)
{
struct int34x_thermal_zone *d = zone->devdata;
acpi_status status;
char name[10];
if (d->override_ops && d->override_ops->set_trip_temp)
return d->override_ops->set_trip_temp(zone, trip, temp);
snprintf(name, sizeof(name), "PAT%d", trip);
status = acpi_execute_simple_method(d->adev->handle, name,
MILLICELSIUS_TO_DECI_KELVIN(temp));
if (ACPI_FAILURE(status))
return -EIO;
d->aux_trips[trip] = temp;
return 0;
}
static int int340x_thermal_get_trip_hyst(struct thermal_zone_device *zone,
int trip, unsigned long *temp)
{
struct int34x_thermal_zone *d = zone->devdata;
acpi_status status;
unsigned long long hyst;
if (d->override_ops && d->override_ops->get_trip_hyst)
return d->override_ops->get_trip_hyst(zone, trip, temp);
status = acpi_evaluate_integer(d->adev->handle, "GTSH", NULL, &hyst);
if (ACPI_FAILURE(status))
return -EIO;
*temp = hyst * 100;
return 0;
}
static struct thermal_zone_device_ops int340x_thermal_zone_ops = {
.get_temp = int340x_thermal_get_zone_temp,
.get_trip_temp = int340x_thermal_get_trip_temp,
.get_trip_type = int340x_thermal_get_trip_type,
.set_trip_temp = int340x_thermal_set_trip_temp,
.get_trip_hyst = int340x_thermal_get_trip_hyst,
};
static int int340x_thermal_get_trip_config(acpi_handle handle, char *name,
unsigned long *temp)
{
unsigned long long r;
acpi_status status;
status = acpi_evaluate_integer(handle, name, NULL, &r);
if (ACPI_FAILURE(status))
return -EIO;
*temp = DECI_KELVIN_TO_MILLICELSIUS(r);
return 0;
}
static struct thermal_zone_params int340x_thermal_params = {
.governor_name = "user_space",
.no_hwmon = true,
};
struct int34x_thermal_zone *int340x_thermal_zone_add(struct acpi_device *adev,
struct thermal_zone_device_ops *override_ops)
{
struct int34x_thermal_zone *int34x_thermal_zone;
acpi_status status;
unsigned long long trip_cnt;
int trip_mask = 0, i;
int ret;
int34x_thermal_zone = kzalloc(sizeof(*int34x_thermal_zone),
GFP_KERNEL);
if (!int34x_thermal_zone)
return ERR_PTR(-ENOMEM);
int34x_thermal_zone->adev = adev;
int34x_thermal_zone->override_ops = override_ops;
status = acpi_evaluate_integer(adev->handle, "PATC", NULL, &trip_cnt);
if (ACPI_FAILURE(status))
trip_cnt = 0;
else {
int34x_thermal_zone->aux_trips = kzalloc(
sizeof(*int34x_thermal_zone->aux_trips) *
trip_cnt, GFP_KERNEL);
if (!int34x_thermal_zone->aux_trips) {
ret = -ENOMEM;
goto free_mem;
}
trip_mask = BIT(trip_cnt) - 1;
int34x_thermal_zone->aux_trip_nr = trip_cnt;
}
int34x_thermal_zone->crt_trip_id = -1;
if (!int340x_thermal_get_trip_config(adev->handle, "_CRT",
&int34x_thermal_zone->crt_temp))
int34x_thermal_zone->crt_trip_id = trip_cnt++;
int34x_thermal_zone->hot_trip_id = -1;
if (!int340x_thermal_get_trip_config(adev->handle, "_HOT",
&int34x_thermal_zone->hot_temp))
int34x_thermal_zone->hot_trip_id = trip_cnt++;
int34x_thermal_zone->psv_trip_id = -1;
if (!int340x_thermal_get_trip_config(adev->handle, "_PSV",
&int34x_thermal_zone->psv_temp))
int34x_thermal_zone->psv_trip_id = trip_cnt++;
for (i = 0; i < INT340X_THERMAL_MAX_ACT_TRIP_COUNT; i++) {
char name[5] = { '_', 'A', 'C', '0' + i, '\0' };
if (int340x_thermal_get_trip_config(adev->handle, name,
&int34x_thermal_zone->act_trips[i].temp))
break;
int34x_thermal_zone->act_trips[i].id = trip_cnt++;
int34x_thermal_zone->act_trips[i].valid = true;
}
int34x_thermal_zone->lpat_table = acpi_lpat_get_conversion_table(
adev->handle);
int34x_thermal_zone->zone = thermal_zone_device_register(
acpi_device_bid(adev),
trip_cnt,
trip_mask, int34x_thermal_zone,
&int340x_thermal_zone_ops,
&int340x_thermal_params,
0, 0);
if (IS_ERR(int34x_thermal_zone->zone)) {
ret = PTR_ERR(int34x_thermal_zone->zone);
goto free_lpat;
}
return int34x_thermal_zone;
free_lpat:
acpi_lpat_free_conversion_table(int34x_thermal_zone->lpat_table);
free_mem:
kfree(int34x_thermal_zone);
return ERR_PTR(ret);
}
EXPORT_SYMBOL_GPL(int340x_thermal_zone_add);
void int340x_thermal_zone_remove(struct int34x_thermal_zone
*int34x_thermal_zone)
{
thermal_zone_device_unregister(int34x_thermal_zone->zone);
acpi_lpat_free_conversion_table(int34x_thermal_zone->lpat_table);
kfree(int34x_thermal_zone);
}
EXPORT_SYMBOL_GPL(int340x_thermal_zone_remove);
MODULE_AUTHOR("Aaron Lu <aaron.lu@intel.com>");
MODULE_AUTHOR("Srinivas Pandruvada <srinivas.pandruvada@linux.intel.com>");
MODULE_DESCRIPTION("Intel INT340x common thermal zone handler");
MODULE_LICENSE("GPL v2");
/*
* int340x_thermal_zone.h
* Copyright (c) 2015, Intel Corporation.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
*/
#ifndef __INT340X_THERMAL_ZONE_H__
#define __INT340X_THERMAL_ZONE_H__
#include <acpi/acpi_lpat.h>
#define INT340X_THERMAL_MAX_ACT_TRIP_COUNT 10
struct active_trip {
unsigned long temp;
int id;
bool valid;
};
struct int34x_thermal_zone {
struct acpi_device *adev;
struct active_trip act_trips[INT340X_THERMAL_MAX_ACT_TRIP_COUNT];
unsigned long *aux_trips;
int aux_trip_nr;
unsigned long psv_temp;
int psv_trip_id;
unsigned long crt_temp;
int crt_trip_id;
unsigned long hot_temp;
int hot_trip_id;
struct thermal_zone_device *zone;
struct thermal_zone_device_ops *override_ops;
void *priv_data;
struct acpi_lpat_conversion_table *lpat_table;
};
struct int34x_thermal_zone *int340x_thermal_zone_add(struct acpi_device *,
struct thermal_zone_device_ops *override_ops);
void int340x_thermal_zone_remove(struct int34x_thermal_zone *);
static inline void int340x_thermal_zone_set_priv_data(
struct int34x_thermal_zone *tzone, void *priv_data)
{
tzone->priv_data = priv_data;
}
static inline void *int340x_thermal_zone_get_priv_data(
struct int34x_thermal_zone *tzone)
{
return tzone->priv_data;
}
static inline void int340x_thermal_zone_device_update(
struct int34x_thermal_zone *tzone)
{
thermal_zone_device_update(tzone->zone);
}
#endif
...@@ -18,6 +18,8 @@ ...@@ -18,6 +18,8 @@
#include <linux/pci.h> #include <linux/pci.h>
#include <linux/platform_device.h> #include <linux/platform_device.h>
#include <linux/acpi.h> #include <linux/acpi.h>
#include <linux/thermal.h>
#include "int340x_thermal_zone.h"
/* Broadwell-U/HSB thermal reporting device */ /* Broadwell-U/HSB thermal reporting device */
#define PCI_DEVICE_ID_PROC_BDW_THERMAL 0x1603 #define PCI_DEVICE_ID_PROC_BDW_THERMAL 0x1603
...@@ -39,6 +41,7 @@ struct proc_thermal_device { ...@@ -39,6 +41,7 @@ struct proc_thermal_device {
struct device *dev; struct device *dev;
struct acpi_device *adev; struct acpi_device *adev;
struct power_config power_limits[2]; struct power_config power_limits[2];
struct int34x_thermal_zone *int340x_zone;
}; };
enum proc_thermal_emum_mode_type { enum proc_thermal_emum_mode_type {
...@@ -117,6 +120,72 @@ static struct attribute_group power_limit_attribute_group = { ...@@ -117,6 +120,72 @@ static struct attribute_group power_limit_attribute_group = {
.name = "power_limits" .name = "power_limits"
}; };
static int stored_tjmax; /* since it is fixed, we can have local storage */
static int get_tjmax(void)
{
u32 eax, edx;
u32 val;
int err;
err = rdmsr_safe(MSR_IA32_TEMPERATURE_TARGET, &eax, &edx);
if (err)
return err;
val = (eax >> 16) & 0xff;
if (val)
return val;
return -EINVAL;
}
static int read_temp_msr(unsigned long *temp)
{
int cpu;
u32 eax, edx;
int err;
unsigned long curr_temp_off = 0;
*temp = 0;
for_each_online_cpu(cpu) {
err = rdmsr_safe_on_cpu(cpu, MSR_IA32_THERM_STATUS, &eax,
&edx);
if (err)
goto err_ret;
else {
if (eax & 0x80000000) {
curr_temp_off = (eax >> 16) & 0x7f;
if (!*temp || curr_temp_off < *temp)
*temp = curr_temp_off;
} else {
err = -EINVAL;
goto err_ret;
}
}
}
return 0;
err_ret:
return err;
}
static int proc_thermal_get_zone_temp(struct thermal_zone_device *zone,
unsigned long *temp)
{
int ret;
ret = read_temp_msr(temp);
if (!ret)
*temp = (stored_tjmax - *temp) * 1000;
return ret;
}
static struct thermal_zone_device_ops proc_thermal_local_ops = {
.get_temp = proc_thermal_get_zone_temp,
};
static int proc_thermal_add(struct device *dev, static int proc_thermal_add(struct device *dev,
struct proc_thermal_device **priv) struct proc_thermal_device **priv)
{ {
...@@ -126,6 +195,8 @@ static int proc_thermal_add(struct device *dev, ...@@ -126,6 +195,8 @@ static int proc_thermal_add(struct device *dev,
struct acpi_buffer buf = { ACPI_ALLOCATE_BUFFER, NULL }; struct acpi_buffer buf = { ACPI_ALLOCATE_BUFFER, NULL };
union acpi_object *elements, *ppcc; union acpi_object *elements, *ppcc;
union acpi_object *p; union acpi_object *p;
unsigned long long tmp;
struct thermal_zone_device_ops *ops = NULL;
int i; int i;
int ret; int ret;
...@@ -178,6 +249,24 @@ static int proc_thermal_add(struct device *dev, ...@@ -178,6 +249,24 @@ static int proc_thermal_add(struct device *dev,
ret = sysfs_create_group(&dev->kobj, ret = sysfs_create_group(&dev->kobj,
&power_limit_attribute_group); &power_limit_attribute_group);
if (ret)
goto free_buffer;
status = acpi_evaluate_integer(adev->handle, "_TMP", NULL, &tmp);
if (ACPI_FAILURE(status)) {
/* there is no _TMP method, add local method */
stored_tjmax = get_tjmax();
if (stored_tjmax > 0)
ops = &proc_thermal_local_ops;
}
proc_priv->int340x_zone = int340x_thermal_zone_add(adev, ops);
if (IS_ERR(proc_priv->int340x_zone)) {
sysfs_remove_group(&proc_priv->dev->kobj,
&power_limit_attribute_group);
ret = PTR_ERR(proc_priv->int340x_zone);
} else
ret = 0;
free_buffer: free_buffer:
kfree(buf.pointer); kfree(buf.pointer);
...@@ -185,8 +274,9 @@ static int proc_thermal_add(struct device *dev, ...@@ -185,8 +274,9 @@ static int proc_thermal_add(struct device *dev,
return ret; return ret;
} }
void proc_thermal_remove(struct proc_thermal_device *proc_priv) static void proc_thermal_remove(struct proc_thermal_device *proc_priv)
{ {
int340x_thermal_zone_remove(proc_priv->int340x_zone);
sysfs_remove_group(&proc_priv->dev->kobj, sysfs_remove_group(&proc_priv->dev->kobj,
&power_limit_attribute_group); &power_limit_attribute_group);
} }
......
...@@ -309,10 +309,13 @@ static int soc_dts_enable(int id) ...@@ -309,10 +309,13 @@ static int soc_dts_enable(int id)
return ret; return ret;
} }
static struct soc_sensor_entry *alloc_soc_dts(int id, u32 tj_max) static struct soc_sensor_entry *alloc_soc_dts(int id, u32 tj_max,
bool notification_support)
{ {
struct soc_sensor_entry *aux_entry; struct soc_sensor_entry *aux_entry;
char name[10]; char name[10];
int trip_count = 0;
int trip_mask = 0;
int err; int err;
aux_entry = kzalloc(sizeof(*aux_entry), GFP_KERNEL); aux_entry = kzalloc(sizeof(*aux_entry), GFP_KERNEL);
...@@ -332,11 +335,16 @@ static struct soc_sensor_entry *alloc_soc_dts(int id, u32 tj_max) ...@@ -332,11 +335,16 @@ static struct soc_sensor_entry *alloc_soc_dts(int id, u32 tj_max)
aux_entry->tj_max = tj_max; aux_entry->tj_max = tj_max;
aux_entry->temp_mask = 0x00FF << (id * 8); aux_entry->temp_mask = 0x00FF << (id * 8);
aux_entry->temp_shift = id * 8; aux_entry->temp_shift = id * 8;
if (notification_support) {
trip_count = SOC_MAX_DTS_TRIPS;
trip_mask = 0x02;
}
snprintf(name, sizeof(name), "soc_dts%d", id); snprintf(name, sizeof(name), "soc_dts%d", id);
aux_entry->tzone = thermal_zone_device_register(name, aux_entry->tzone = thermal_zone_device_register(name,
SOC_MAX_DTS_TRIPS, trip_count,
0x02, trip_mask,
aux_entry, &tzone_ops, NULL, 0, 0); aux_entry, &tzone_ops,
NULL, 0, 0);
if (IS_ERR(aux_entry->tzone)) { if (IS_ERR(aux_entry->tzone)) {
err = PTR_ERR(aux_entry->tzone); err = PTR_ERR(aux_entry->tzone);
goto err_ret; goto err_ret;
...@@ -402,6 +410,7 @@ static irqreturn_t soc_irq_thread_fn(int irq, void *dev_data) ...@@ -402,6 +410,7 @@ static irqreturn_t soc_irq_thread_fn(int irq, void *dev_data)
static const struct x86_cpu_id soc_thermal_ids[] = { static const struct x86_cpu_id soc_thermal_ids[] = {
{ X86_VENDOR_INTEL, X86_FAMILY_ANY, 0x37, 0, BYT_SOC_DTS_APIC_IRQ}, { X86_VENDOR_INTEL, X86_FAMILY_ANY, 0x37, 0, BYT_SOC_DTS_APIC_IRQ},
{ X86_VENDOR_INTEL, X86_FAMILY_ANY, 0x4c, 0, 0},
{} {}
}; };
MODULE_DEVICE_TABLE(x86cpu, soc_thermal_ids); MODULE_DEVICE_TABLE(x86cpu, soc_thermal_ids);
...@@ -420,8 +429,11 @@ static int __init intel_soc_thermal_init(void) ...@@ -420,8 +429,11 @@ static int __init intel_soc_thermal_init(void)
if (get_tj_max(&tj_max)) if (get_tj_max(&tj_max))
return -EINVAL; return -EINVAL;
soc_dts_thres_irq = (int)match_cpu->driver_data;
for (i = 0; i < SOC_MAX_DTS_SENSORS; ++i) { for (i = 0; i < SOC_MAX_DTS_SENSORS; ++i) {
soc_dts[i] = alloc_soc_dts(i, tj_max); soc_dts[i] = alloc_soc_dts(i, tj_max,
soc_dts_thres_irq ? true : false);
if (IS_ERR(soc_dts[i])) { if (IS_ERR(soc_dts[i])) {
err = PTR_ERR(soc_dts[i]); err = PTR_ERR(soc_dts[i]);
goto err_free; goto err_free;
...@@ -430,8 +442,7 @@ static int __init intel_soc_thermal_init(void) ...@@ -430,8 +442,7 @@ static int __init intel_soc_thermal_init(void)
spin_lock_init(&intr_notify_lock); spin_lock_init(&intr_notify_lock);
soc_dts_thres_irq = (int)match_cpu->driver_data; if (soc_dts_thres_irq) {
err = request_threaded_irq(soc_dts_thres_irq, NULL, err = request_threaded_irq(soc_dts_thres_irq, NULL,
soc_irq_thread_fn, soc_irq_thread_fn,
IRQF_TRIGGER_RISING | IRQF_ONESHOT, IRQF_TRIGGER_RISING | IRQF_ONESHOT,
...@@ -440,6 +451,7 @@ static int __init intel_soc_thermal_init(void) ...@@ -440,6 +451,7 @@ static int __init intel_soc_thermal_init(void)
pr_err("request_threaded_irq ret %d\n", err); pr_err("request_threaded_irq ret %d\n", err);
goto err_free; goto err_free;
} }
}
for (i = 0; i < SOC_MAX_DTS_SENSORS; ++i) { for (i = 0; i < SOC_MAX_DTS_SENSORS; ++i) {
err = update_trip_temp(soc_dts[i], 0, tj_max - crit_offset); err = update_trip_temp(soc_dts[i], 0, tj_max - crit_offset);
...@@ -451,6 +463,7 @@ static int __init intel_soc_thermal_init(void) ...@@ -451,6 +463,7 @@ static int __init intel_soc_thermal_init(void)
err_trip_temp: err_trip_temp:
i = SOC_MAX_DTS_SENSORS; i = SOC_MAX_DTS_SENSORS;
if (soc_dts_thres_irq)
free_irq(soc_dts_thres_irq, soc_dts); free_irq(soc_dts_thres_irq, soc_dts);
err_free: err_free:
while (--i >= 0) while (--i >= 0)
...@@ -466,6 +479,7 @@ static void __exit intel_soc_thermal_exit(void) ...@@ -466,6 +479,7 @@ static void __exit intel_soc_thermal_exit(void)
for (i = 0; i < SOC_MAX_DTS_SENSORS; ++i) for (i = 0; i < SOC_MAX_DTS_SENSORS; ++i)
update_trip_temp(soc_dts[i], 0, 0); update_trip_temp(soc_dts[i], 0, 0);
if (soc_dts_thres_irq)
free_irq(soc_dts_thres_irq, soc_dts); free_irq(soc_dts_thres_irq, soc_dts);
for (i = 0; i < SOC_MAX_DTS_SENSORS; ++i) for (i = 0; i < SOC_MAX_DTS_SENSORS; ++i)
......
...@@ -45,7 +45,7 @@ ...@@ -45,7 +45,7 @@
* c. if the trend is THERMAL_TREND_RAISE_FULL, do nothing * c. if the trend is THERMAL_TREND_RAISE_FULL, do nothing
* d. if the trend is THERMAL_TREND_DROP_FULL, use lower limit, * d. if the trend is THERMAL_TREND_DROP_FULL, use lower limit,
* if the cooling state already equals lower limit, * if the cooling state already equals lower limit,
* deactive the thermal instance * deactivate the thermal instance
*/ */
static unsigned long get_target_state(struct thermal_instance *instance, static unsigned long get_target_state(struct thermal_instance *instance,
enum thermal_trend trend, bool throttle) enum thermal_trend trend, bool throttle)
...@@ -169,7 +169,7 @@ static void thermal_zone_trip_update(struct thermal_zone_device *tz, int trip) ...@@ -169,7 +169,7 @@ static void thermal_zone_trip_update(struct thermal_zone_device *tz, int trip)
} }
/** /**
* step_wise_throttle - throttles devices asscciated with the given zone * step_wise_throttle - throttles devices associated with the given zone
* @tz - thermal_zone_device * @tz - thermal_zone_device
* @trip - the trip point * @trip - the trip point
* @trip_type - type of the trip point * @trip_type - type of the trip point
......
/*
* acpi_lpat.h - LPAT table processing functions
*
* Copyright (C) 2015 Intel Corporation. All rights reserved.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License version
* 2 as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#ifndef ACPI_LPAT_H
#define ACPI_LPAT_H
struct acpi_lpat {
int temp;
int raw;
};
struct acpi_lpat_conversion_table {
struct acpi_lpat *lpat;
int lpat_count;
};
#ifdef CONFIG_ACPI
int acpi_lpat_raw_to_temp(struct acpi_lpat_conversion_table *lpat_table,
int raw);
int acpi_lpat_temp_to_raw(struct acpi_lpat_conversion_table *lpat_table,
int temp);
struct acpi_lpat_conversion_table *acpi_lpat_get_conversion_table(acpi_handle
handle);
void acpi_lpat_free_conversion_table(struct acpi_lpat_conversion_table
*lpat_table);
#else
static int acpi_lpat_raw_to_temp(struct acpi_lpat_conversion_table *lpat_table,
int raw)
{
return 0;
}
static int acpi_lpat_temp_to_raw(struct acpi_lpat_conversion_table *lpat_table,
int temp)
{
return 0;
}
static struct acpi_lpat_conversion_table *acpi_lpat_get_conversion_table(
acpi_handle handle)
{
return NULL;
}
static void acpi_lpat_free_conversion_table(struct acpi_lpat_conversion_table
*lpat_table)
{
}
#endif
#endif
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