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

Commit 89d3fa45 authored by Linus Torvalds's avatar Linus Torvalds
Browse files
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
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -55,6 +55,7 @@ acpi-$(CONFIG_ACPI_PROCFS_POWER) += cm_sbs.o
ifdef CONFIG_ACPI_VIDEO
acpi-y				+= video_detect.o
endif
acpi-y				+= acpi_lpat.o

# These are (potentially) separate modules

+161 −0
Original line number Diff line number Diff line
/*
 * 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");
+18 −115
Original line number Diff line number Diff line
@@ -16,20 +16,15 @@
#include <linux/module.h>
#include <linux/acpi.h>
#include <linux/regmap.h>
#include <acpi/acpi_lpat.h>
#include "intel_pmic.h"

#define PMIC_POWER_OPREGION_ID		0x8d
#define PMIC_THERMAL_OPREGION_ID	0x8c

struct acpi_lpat {
	int temp;
	int raw;
};

struct intel_pmic_opregion {
	struct mutex lock;
	struct acpi_lpat *lpat;
	int lpat_count;
	struct acpi_lpat_conversion_table *lpat_table;
	struct regmap *regmap;
	struct intel_pmic_opregion_data *data;
};
@@ -50,105 +45,6 @@ static int pmic_get_reg_bit(int address, struct pmic_table *table,
	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,
		acpi_physical_address address, u32 bits, u64 *value64,
		void *handler_context, void *region_context)
@@ -192,12 +88,12 @@ static int pmic_read_temp(struct intel_pmic_opregion *opregion,
	if (raw_temp < 0)
		return raw_temp;

	if (!opregion->lpat) {
	if (!opregion->lpat_table) {
		*value = raw_temp;
		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)
		return temp;

@@ -223,9 +119,8 @@ static int pmic_thermal_aux(struct intel_pmic_opregion *opregion, int reg,
	if (!opregion->data->update_aux)
		return -ENXIO;

	if (opregion->lpat) {
		raw_temp = temp_to_raw(opregion->lpat, opregion->lpat_count,
				       *value);
	if (opregion->lpat_table) {
		raw_temp = acpi_lpat_temp_to_raw(opregion->lpat_table, *value);
		if (raw_temp < 0)
			return raw_temp;
	} else {
@@ -314,6 +209,7 @@ int intel_pmic_install_opregion_handler(struct device *dev, acpi_handle handle,
{
	acpi_status status;
	struct intel_pmic_opregion *opregion;
	int ret;

	if (!dev || !regmap || !d)
		return -EINVAL;
@@ -327,14 +223,16 @@ int intel_pmic_install_opregion_handler(struct device *dev, acpi_handle handle,

	mutex_init(&opregion->lock);
	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,
						    PMIC_POWER_OPREGION_ID,
						    intel_pmic_power_handler,
						    NULL, opregion);
	if (ACPI_FAILURE(status))
		return -ENODEV;
	if (ACPI_FAILURE(status)) {
		ret = -ENODEV;
		goto out_error;
	}

	status = acpi_install_address_space_handler(handle,
						    PMIC_THERMAL_OPREGION_ID,
@@ -343,11 +241,16 @@ int intel_pmic_install_opregion_handler(struct device *dev, acpi_handle handle,
	if (ACPI_FAILURE(status)) {
		acpi_remove_address_space_handler(handle, PMIC_POWER_OPREGION_ID,
						  intel_pmic_power_handler);
		return -ENODEV;
		ret = -ENODEV;
		goto out_error;
	}

	opregion->data = d;
	return 0;

out_error:
	acpi_lpat_free_conversion_table(opregion->lpat_table);
	return ret;
}
EXPORT_SYMBOL_GPL(intel_pmic_install_opregion_handler);

+1 −0
Original line number Diff line number Diff line
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)	+= int3403_thermal.o
obj-$(CONFIG_INT340X_THERMAL)	+= processor_thermal_device.o
+0 −4
Original line number Diff line number Diff line
@@ -18,19 +18,15 @@

enum int3400_thermal_uuid {
	INT3400_THERMAL_PASSIVE_1,
	INT3400_THERMAL_PASSIVE_2,
	INT3400_THERMAL_ACTIVE,
	INT3400_THERMAL_CRITICAL,
	INT3400_THERMAL_COOLING_MODE,
	INT3400_THERMAL_MAXIMUM_UUID,
};

static u8 *int3400_thermal_uuids[INT3400_THERMAL_MAXIMUM_UUID] = {
	"42A441D6-AE6A-462b-A84B-4A8CE79027D3",
	"9E04115A-AE87-4D1C-9500-0F3E340BFE75",
	"3A95C389-E4B8-4629-A526-C52C88626BAE",
	"97C68AE7-15FA-499c-B8C9-5DA81D606E0A",
	"16CAF1B7-DD38-40ed-B1C1-1B8A1913D531",
};

struct int3400_thermal_priv {
Loading