From 5fbf7f27fa3da2c7b538772cfe3340391ef8b3b9 Mon Sep 17 00:00:00 2001
From: Srinivas Pandruvada <srinivas.pandruvada@linux.intel.com>
Date: Fri, 16 Jan 2015 15:59:03 -0800
Subject: Thermal/int340x: Add common thermal zone handler

Most of the processing for each int340x driver to add a thermal zone
is very similar and every driver has to duplicate code.
Created a common module, which exports API to add and remove zones.
In this way, we not only avoid duplicate code but also helps in
bug fixes and enhancements.
If for some driver default processing for thermal zone callback is
not enough they can overide individual callback.
The code for this driver is primarily copied from int3402_thermal.c.

Signed-off-by: Srinivas Pandruvada <srinivas.pandruvada@linux.intel.com>
Signed-off-by: Zhang Rui <rui.zhang@intel.com>
---
 drivers/thermal/int340x_thermal/Makefile           |   1 +
 .../thermal/int340x_thermal/int340x_thermal_zone.c | 262 +++++++++++++++++++++
 .../thermal/int340x_thermal/int340x_thermal_zone.h |  65 +++++
 3 files changed, 328 insertions(+)
 create mode 100644 drivers/thermal/int340x_thermal/int340x_thermal_zone.c
 create mode 100644 drivers/thermal/int340x_thermal/int340x_thermal_zone.h

(limited to 'drivers')

diff --git a/drivers/thermal/int340x_thermal/Makefile b/drivers/thermal/int340x_thermal/Makefile
index d4413698a85..ba77a34f659 100644
--- a/drivers/thermal/int340x_thermal/Makefile
+++ b/drivers/thermal/int340x_thermal/Makefile
@@ -1,4 +1,5 @@
 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
diff --git a/drivers/thermal/int340x_thermal/int340x_thermal_zone.c b/drivers/thermal/int340x_thermal/int340x_thermal_zone.c
new file mode 100644
index 00000000000..162e545cc93
--- /dev/null
+++ b/drivers/thermal/int340x_thermal/int340x_thermal_zone.c
@@ -0,0 +1,262 @@
+/*
+ * 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;
+
+	/* _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->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_mem;
+	}
+
+	return int34x_thermal_zone;
+
+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);
+	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");
diff --git a/drivers/thermal/int340x_thermal/int340x_thermal_zone.h b/drivers/thermal/int340x_thermal/int340x_thermal_zone.h
new file mode 100644
index 00000000000..11f2f5260c3
--- /dev/null
+++ b/drivers/thermal/int340x_thermal/int340x_thermal_zone.h
@@ -0,0 +1,65 @@
+/*
+ * 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__
+
+#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 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
-- 
cgit v1.2.3-70-g09d2


From 820cdeba4086c74eb977088f1f9d31fd4c0aba9a Mon Sep 17 00:00:00 2001
From: Srinivas Pandruvada <srinivas.pandruvada@linux.intel.com>
Date: Fri, 16 Jan 2015 15:59:04 -0800
Subject: Thermal/int340x/int3402: Use int340x thermal API

Using APIs from int340x thermal zone module to add and remove thermal
zones.

Signed-off-by: Srinivas Pandruvada <srinivas.pandruvada@linux.intel.com>
Signed-off-by: Zhang Rui <rui.zhang@intel.com>
---
 drivers/thermal/int340x_thermal/int3402_thermal.c | 189 ++--------------------
 1 file changed, 11 insertions(+), 178 deletions(-)

(limited to 'drivers')

diff --git a/drivers/thermal/int340x_thermal/int3402_thermal.c b/drivers/thermal/int340x_thermal/int3402_thermal.c
index c5cbc3af3a0..7ffc749ce0f 100644
--- a/drivers/thermal/int340x_thermal/int3402_thermal.c
+++ b/drivers/thermal/int340x_thermal/int3402_thermal.c
@@ -14,152 +14,17 @@
 #include <linux/platform_device.h>
 #include <linux/acpi.h>
 #include <linux/thermal.h>
-
-#define ACPI_ACTIVE_COOLING_MAX_NR 10
-
-struct active_trip {
-	unsigned long temp;
-	int id;
-	bool valid;
-};
+#include "int340x_thermal_zone.h"
 
 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;
+	struct int34x_thermal_zone *int340x_zone;
 };
 
-static int int3402_thermal_get_zone_temp(struct thermal_zone_device *zone,
-					 unsigned long *temp)
-{
-	struct int3402_thermal_data *d = zone->devdata;
-	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 */
-	*temp = DECI_KELVIN_TO_MILLICELSIUS(tmp);
-
-	return 0;
-}
-
-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;
-			}
-		}
-		if (i == ACPI_ACTIVE_COOLING_MAX_NR)
-			return -EINVAL;
-	}
-	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;
-			}
-		}
-		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)
 {
 	struct acpi_device *adev = ACPI_COMPANION(&pdev->dev);
 	struct int3402_thermal_data *d;
-	struct thermal_zone_device *zone;
-	acpi_status status;
-	unsigned long long trip_cnt;
-	int trip_mask = 0, i;
 
 	if (!acpi_has_method(adev->handle, "_TMP"))
 		return -ENODEV;
@@ -168,54 +33,22 @@ static int int3402_thermal_probe(struct platform_device *pdev)
 	if (!d)
 		return -ENOMEM;
 
-	status = acpi_evaluate_integer(adev->handle, "PATC", NULL, &trip_cnt);
-	if (ACPI_FAILURE(status))
-		trip_cnt = 0;
-	else {
-		d->aux_trips = devm_kzalloc(&pdev->dev,
-				sizeof(*d->aux_trips) * trip_cnt, GFP_KERNEL);
-		if (!d->aux_trips)
-			return -ENOMEM;
-		trip_mask = trip_cnt - 1;
-		d->handle = adev->handle;
-		d->aux_trip_nr = trip_cnt;
-	}
-
-	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,
-					    trip_mask, d,
-					    &int3402_thermal_zone_ops,
-					    &int3402_thermal_params,
-					    0, 0);
-	if (IS_ERR(zone))
-		return PTR_ERR(zone);
-	platform_set_drvdata(pdev, zone);
+	d->int340x_zone = int340x_thermal_zone_add(adev, NULL);
+	if (IS_ERR(d->int340x_zone))
+		return PTR_ERR(d->int340x_zone);
+
+	d->handle = adev->handle;
+	platform_set_drvdata(pdev, d);
 
 	return 0;
 }
 
 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);
+
+	int340x_thermal_zone_remove(d->int340x_zone);
 
-	thermal_zone_device_unregister(zone);
 	return 0;
 }
 
-- 
cgit v1.2.3-70-g09d2


From 593df40475b719103e095aa1116653636662077e Mon Sep 17 00:00:00 2001
From: Srinivas Pandruvada <srinivas.pandruvada@linux.intel.com>
Date: Fri, 16 Jan 2015 15:59:05 -0800
Subject: Thermal/int340x/int3403: Use int340x thermal API

Using APIs from int340x thermal zone module to add and remove thermal
zones.

Signed-off-by: Srinivas Pandruvada <srinivas.pandruvada@linux.intel.com>
Signed-off-by: Zhang Rui <rui.zhang@intel.com>
---
 drivers/thermal/int340x_thermal/int3403_thermal.c | 208 ++--------------------
 1 file changed, 10 insertions(+), 198 deletions(-)

(limited to 'drivers')

diff --git a/drivers/thermal/int340x_thermal/int3403_thermal.c b/drivers/thermal/int340x_thermal/int3403_thermal.c
index 0faf500d8a7..50a7a08e3a1 100644
--- a/drivers/thermal/int340x_thermal/int3403_thermal.c
+++ b/drivers/thermal/int340x_thermal/int3403_thermal.c
@@ -19,6 +19,7 @@
 #include <linux/acpi.h>
 #include <linux/thermal.h>
 #include <linux/platform_device.h>
+#include "int340x_thermal_zone.h"
 
 #define INT3403_TYPE_SENSOR		0x03
 #define INT3403_TYPE_CHARGER		0x0B
@@ -26,18 +27,9 @@
 #define INT3403_PERF_CHANGED_EVENT	0x80
 #define INT3403_THERMAL_EVENT		0x90
 
-#define DECI_KELVIN_TO_MILLI_CELSIUS(t, off) (((t) - (off)) * 100)
-#define KELVIN_OFFSET	2732
-#define MILLI_CELSIUS_TO_DECI_KELVIN(t, off) (((t) / 100) + (off))
-
+/* Preserved structure for future expandbility */
 struct int3403_sensor {
-	struct thermal_zone_device *tzone;
-	unsigned long *thresholds;
-	unsigned long	crit_temp;
-	int		crit_trip_id;
-	unsigned long	psv_temp;
-	int		psv_trip_id;
-
+	struct int34x_thermal_zone *int340x_zone;
 };
 
 struct int3403_performance_state {
@@ -63,126 +55,6 @@ struct int3403_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,
 		u32 event, void *data)
 {
@@ -200,7 +72,7 @@ static void int3403_notify(acpi_handle handle,
 	case INT3403_PERF_CHANGED_EVENT:
 		break;
 	case INT3403_THERMAL_EVENT:
-		thermal_zone_device_update(obj->tzone);
+		int340x_thermal_zone_device_update(obj->int340x_zone);
 		break;
 	default:
 		dev_err(&priv->pdev->dev, "Unsupported event [0x%x]\n", event);
@@ -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)
 {
 	int result = 0;
-	acpi_status status;
 	struct int3403_sensor *obj;
-	unsigned long long trip_cnt;
-	int trip_mask = 0;
 
 	obj = devm_kzalloc(&priv->pdev->dev, sizeof(*obj), GFP_KERNEL);
 	if (!obj)
@@ -250,39 +91,9 @@ static int int3403_sensor_add(struct int3403_priv *priv)
 
 	priv->priv = obj;
 
-	status = acpi_evaluate_integer(priv->adev->handle, "PATC", NULL,
-						&trip_cnt);
-	if (ACPI_FAILURE(status))
-		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;
-	}
+	obj->int340x_zone = int340x_thermal_zone_add(priv->adev, NULL);
+	if (IS_ERR(obj->int340x_zone))
+		return PTR_ERR(obj->int340x_zone);
 
 	result = acpi_install_notify_handler(priv->adev->handle,
 			ACPI_DEVICE_NOTIFY, int3403_notify,
@@ -293,7 +104,7 @@ static int int3403_sensor_add(struct int3403_priv *priv)
 	return 0;
 
  err_free_obj:
-	thermal_zone_device_unregister(obj->tzone);
+	int340x_thermal_zone_remove(obj->int340x_zone);
 	return result;
 }
 
@@ -303,7 +114,8 @@ static int int3403_sensor_remove(struct int3403_priv *priv)
 
 	acpi_remove_notify_handler(priv->adev->handle,
 				   ACPI_DEVICE_NOTIFY, int3403_notify);
-	thermal_zone_device_unregister(obj->tzone);
+	int340x_thermal_zone_remove(obj->int340x_zone);
+
 	return 0;
 }
 
-- 
cgit v1.2.3-70-g09d2


From 1c55be020806eeffbda6f1a981511e46427eb4ec Mon Sep 17 00:00:00 2001
From: Srinivas Pandruvada <srinivas.pandruvada@linux.intel.com>
Date: Fri, 16 Jan 2015 15:59:06 -0800
Subject: Thermal/int340x/processor_thermal: Add thermal zone support

Added thermal zones for processor thermal using APIs provided by
int340x thermal zone module.
Like other INT340x devices, processor thermal device can also contain
trip points and way to get temperature. On some platform there is
no ACPI _TMP method, in those platform using IA64 architecture MSRs to
get temperature.

Signed-off-by: Srinivas Pandruvada <srinivas.pandruvada@linux.intel.com>
Signed-off-by: Zhang Rui <rui.zhang@intel.com>
---
 .../int340x_thermal/processor_thermal_device.c     | 90 ++++++++++++++++++++++
 1 file changed, 90 insertions(+)

(limited to 'drivers')

diff --git a/drivers/thermal/int340x_thermal/processor_thermal_device.c b/drivers/thermal/int340x_thermal/processor_thermal_device.c
index 0fe5dbbea96..7c3848da2df 100644
--- a/drivers/thermal/int340x_thermal/processor_thermal_device.c
+++ b/drivers/thermal/int340x_thermal/processor_thermal_device.c
@@ -18,6 +18,8 @@
 #include <linux/pci.h>
 #include <linux/platform_device.h>
 #include <linux/acpi.h>
+#include <linux/thermal.h>
+#include "int340x_thermal_zone.h"
 
 /* Broadwell-U/HSB thermal reporting device */
 #define PCI_DEVICE_ID_PROC_BDW_THERMAL	0x1603
@@ -39,6 +41,7 @@ struct proc_thermal_device {
 	struct device *dev;
 	struct acpi_device *adev;
 	struct power_config power_limits[2];
+	struct int34x_thermal_zone *int340x_zone;
 };
 
 enum proc_thermal_emum_mode_type {
@@ -117,6 +120,72 @@ static struct attribute_group power_limit_attribute_group = {
 	.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,
 			    struct proc_thermal_device **priv)
 {
@@ -126,6 +195,8 @@ static int proc_thermal_add(struct device *dev,
 	struct acpi_buffer buf = { ACPI_ALLOCATE_BUFFER, NULL };
 	union acpi_object *elements, *ppcc;
 	union acpi_object *p;
+	unsigned long long tmp;
+	struct thermal_zone_device_ops *ops = NULL;
 	int i;
 	int ret;
 
@@ -178,6 +249,24 @@ static int proc_thermal_add(struct device *dev,
 
 	ret = sysfs_create_group(&dev->kobj,
 				 &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:
 	kfree(buf.pointer);
@@ -187,6 +276,7 @@ free_buffer:
 
 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,
 			   &power_limit_attribute_group);
 }
-- 
cgit v1.2.3-70-g09d2


From acebf7eea449f8e18f443804f1f20bc090f22d0a Mon Sep 17 00:00:00 2001
From: Srinivas Pandruvada <srinivas.pandruvada@linux.intel.com>
Date: Tue, 23 Dec 2014 15:29:57 -0800
Subject: Thermal/int340x/int3402: Provide notification support

This driver supports programmable trips, but didn't register
notification handler to receive threshold violation notification.

Signed-off-by: Srinivas Pandruvada <srinivas.pandruvada@linux.intel.com>
Signed-off-by: Zhang Rui <rui.zhang@intel.com>
---
 drivers/thermal/int340x_thermal/int3402_thermal.c | 33 +++++++++++++++++++++++
 1 file changed, 33 insertions(+)

(limited to 'drivers')

diff --git a/drivers/thermal/int340x_thermal/int3402_thermal.c b/drivers/thermal/int340x_thermal/int3402_thermal.c
index 7ffc749ce0f..69df3d96030 100644
--- a/drivers/thermal/int340x_thermal/int3402_thermal.c
+++ b/drivers/thermal/int340x_thermal/int3402_thermal.c
@@ -16,15 +16,37 @@
 #include <linux/thermal.h>
 #include "int340x_thermal_zone.h"
 
+#define INT3402_PERF_CHANGED_EVENT	0x80
+#define INT3402_THERMAL_EVENT		0x90
+
 struct int3402_thermal_data {
 	acpi_handle *handle;
 	struct int34x_thermal_zone *int340x_zone;
 };
 
+static void int3402_notify(acpi_handle handle, u32 event, void *data)
+{
+	struct int3402_thermal_data *priv = data;
+
+	if (!priv)
+		return;
+
+	switch (event) {
+	case INT3402_PERF_CHANGED_EVENT:
+		break;
+	case INT3402_THERMAL_EVENT:
+		int340x_thermal_zone_device_update(priv->int340x_zone);
+		break;
+	default:
+		break;
+	}
+}
+
 static int int3402_thermal_probe(struct platform_device *pdev)
 {
 	struct acpi_device *adev = ACPI_COMPANION(&pdev->dev);
 	struct int3402_thermal_data *d;
+	int ret;
 
 	if (!acpi_has_method(adev->handle, "_TMP"))
 		return -ENODEV;
@@ -37,6 +59,15 @@ static int int3402_thermal_probe(struct platform_device *pdev)
 	if (IS_ERR(d->int340x_zone))
 		return PTR_ERR(d->int340x_zone);
 
+	ret = acpi_install_notify_handler(adev->handle,
+					  ACPI_DEVICE_NOTIFY,
+					  int3402_notify,
+					  d);
+	if (ret) {
+		int340x_thermal_zone_remove(d->int340x_zone);
+		return ret;
+	}
+
 	d->handle = adev->handle;
 	platform_set_drvdata(pdev, d);
 
@@ -47,6 +78,8 @@ static int int3402_thermal_remove(struct platform_device *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);
 
 	return 0;
-- 
cgit v1.2.3-70-g09d2


From c55d62820efe3b847a21c78634356b5e4ec6d010 Mon Sep 17 00:00:00 2001
From: Srinivas Pandruvada <srinivas.pandruvada@linux.intel.com>
Date: Wed, 28 Jan 2015 11:56:46 -0800
Subject: ACPI / LPAT: Common table processing functions

Since LPAT table processing is also required for other thermal drivers,
moved LPAT table related functions from intel PMIC driver (intel_pmic.c)
to a stand alonge module with exported interfaces.
In this way there will be no code duplication.

Signed-off-by: Srinivas Pandruvada <srinivas.pandruvada@linux.intel.com>
Signed-off-by: Zhang Rui <rui.zhang@intel.com>
---
 drivers/acpi/Makefile    |   1 +
 drivers/acpi/acpi_lpat.c | 161 +++++++++++++++++++++++++++++++++++++++++++++++
 include/acpi/acpi_lpat.h |  65 +++++++++++++++++++
 3 files changed, 227 insertions(+)
 create mode 100644 drivers/acpi/acpi_lpat.c
 create mode 100644 include/acpi/acpi_lpat.h

(limited to 'drivers')

diff --git a/drivers/acpi/Makefile b/drivers/acpi/Makefile
index f74317cc1ca..d22253d5b9f 100644
--- a/drivers/acpi/Makefile
+++ b/drivers/acpi/Makefile
@@ -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
 
diff --git a/drivers/acpi/acpi_lpat.c b/drivers/acpi/acpi_lpat.c
new file mode 100644
index 00000000000..feb61c1630e
--- /dev/null
+++ b/drivers/acpi/acpi_lpat.c
@@ -0,0 +1,161 @@
+/*
+ * 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");
diff --git a/include/acpi/acpi_lpat.h b/include/acpi/acpi_lpat.h
new file mode 100644
index 00000000000..da37e12d23e
--- /dev/null
+++ b/include/acpi/acpi_lpat.h
@@ -0,0 +1,65 @@
+/*
+ * 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
-- 
cgit v1.2.3-70-g09d2


From ac586e2d6afb1935246c75f0e27a5c628712dbfa Mon Sep 17 00:00:00 2001
From: Srinivas Pandruvada <srinivas.pandruvada@linux.intel.com>
Date: Wed, 28 Jan 2015 11:56:47 -0800
Subject: ACPI / PMIC: Use common LPAT table handling functions

The LPAT table processing functions from this modules are moved to a
standalone module with exported interface functions.
Using new interface functions in this module.

Signed-off-by: Srinivas Pandruvada <srinivas.pandruvada@linux.intel.com>
Signed-off-by: Zhang Rui <rui.zhang@intel.com>
---
 drivers/acpi/pmic/intel_pmic.c | 133 ++++++-----------------------------------
 1 file changed, 18 insertions(+), 115 deletions(-)

(limited to 'drivers')

diff --git a/drivers/acpi/pmic/intel_pmic.c b/drivers/acpi/pmic/intel_pmic.c
index a732e5d7e32..bd772cd5649 100644
--- a/drivers/acpi/pmic/intel_pmic.c
+++ b/drivers/acpi/pmic/intel_pmic.c
@@ -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);
 
-- 
cgit v1.2.3-70-g09d2


From 317d9dda0522c18eb230367c88601c2e46cda4f8 Mon Sep 17 00:00:00 2001
From: Srinivas Pandruvada <srinivas.pandruvada@linux.intel.com>
Date: Wed, 28 Jan 2015 11:56:48 -0800
Subject: Thermal/int340x: LPAT conversion for temperature

When LPAT table is present, we need to convert raw temperature to
real temp using LPAT.

Signed-off-by: Srinivas Pandruvada <srinivas.pandruvada@linux.intel.com>
Signed-off-by: Zhang Rui <rui.zhang@intel.com>
---
 .../thermal/int340x_thermal/int340x_thermal_zone.c   | 20 +++++++++++++++++---
 .../thermal/int340x_thermal/int340x_thermal_zone.h   |  3 +++
 2 files changed, 20 insertions(+), 3 deletions(-)

(limited to 'drivers')

diff --git a/drivers/thermal/int340x_thermal/int340x_thermal_zone.c b/drivers/thermal/int340x_thermal/int340x_thermal_zone.c
index 162e545cc93..f88b0887702 100644
--- a/drivers/thermal/int340x_thermal/int340x_thermal_zone.c
+++ b/drivers/thermal/int340x_thermal/int340x_thermal_zone.c
@@ -33,8 +33,17 @@ static int int340x_thermal_get_zone_temp(struct thermal_zone_device *zone,
 	if (ACPI_FAILURE(status))
 		return -EIO;
 
-	/* _TMP returns the temperature in tenths of degrees Kelvin */
-	*temp = DECI_KELVIN_TO_MILLICELSIUS(tmp);
+	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;
 }
@@ -227,6 +236,8 @@ struct int34x_thermal_zone *int340x_thermal_zone_add(struct acpi_device *adev,
 		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),
@@ -237,11 +248,13 @@ struct int34x_thermal_zone *int340x_thermal_zone_add(struct acpi_device *adev,
 						0, 0);
 	if (IS_ERR(int34x_thermal_zone->zone)) {
 		ret = PTR_ERR(int34x_thermal_zone->zone);
-		goto free_mem;
+		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);
@@ -252,6 +265,7 @@ 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);
diff --git a/drivers/thermal/int340x_thermal/int340x_thermal_zone.h b/drivers/thermal/int340x_thermal/int340x_thermal_zone.h
index 11f2f5260c3..9f38ab72c4b 100644
--- a/drivers/thermal/int340x_thermal/int340x_thermal_zone.h
+++ b/drivers/thermal/int340x_thermal/int340x_thermal_zone.h
@@ -16,6 +16,8 @@
 #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 {
@@ -38,6 +40,7 @@ struct int34x_thermal_zone {
 	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 *,
-- 
cgit v1.2.3-70-g09d2