Merge branches 'intel-dts-soc-thermal' and 'int340x-enhancement' of .git into next
diff --git a/drivers/acpi/Makefile b/drivers/acpi/Makefile
index f74317c..d22253d 100644
--- a/drivers/acpi/Makefile
+++ b/drivers/acpi/Makefile
@@ -55,6 +55,7 @@
 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 0000000..feb61c1
--- /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/drivers/acpi/pmic/intel_pmic.c b/drivers/acpi/pmic/intel_pmic.c
index a732e5d..bd772cd 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 @@
 	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 @@
 	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 @@
 	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 @@
 {
 	acpi_status status;
 	struct intel_pmic_opregion *opregion;
+	int ret;
 
 	if (!dev || !regmap || !d)
 		return -EINVAL;
@@ -327,14 +223,16 @@
 
 	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 @@
 	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);
 
diff --git a/drivers/thermal/int340x_thermal/Makefile b/drivers/thermal/int340x_thermal/Makefile
index d441369..ba77a34 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/int3402_thermal.c b/drivers/thermal/int340x_thermal/int3402_thermal.c
index c5cbc3a..69df3d9 100644
--- a/drivers/thermal/int340x_thermal/int3402_thermal.c
+++ b/drivers/thermal/int340x_thermal/int3402_thermal.c
@@ -14,152 +14,39 @@
 #include <linux/platform_device.h>
 #include <linux/acpi.h>
 #include <linux/thermal.h>
+#include "int340x_thermal_zone.h"
 
-#define ACPI_ACTIVE_COOLING_MAX_NR 10
-
-struct active_trip {
-	unsigned long temp;
-	int id;
-	bool valid;
-};
+#define INT3402_PERF_CHANGED_EVENT	0x80
+#define INT3402_THERMAL_EVENT		0x90
 
 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)
+static void int3402_notify(acpi_handle handle, u32 event, void *data)
 {
-	struct int3402_thermal_data *d = zone->devdata;
-	unsigned long long tmp;
-	acpi_status status;
+	struct int3402_thermal_data *priv = data;
 
-	status = acpi_evaluate_integer(d->handle, "_TMP", NULL, &tmp);
-	if (ACPI_FAILURE(status))
-		return -ENODEV;
+	if (!priv)
+		return;
 
-	/* _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;
+	switch (event) {
+	case INT3402_PERF_CHANGED_EVENT:
+		break;
+	case INT3402_THERMAL_EVENT:
+		int340x_thermal_zone_device_update(priv->int340x_zone);
+		break;
+	default:
+		break;
 	}
-	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;
+	int ret;
 
 	if (!acpi_has_method(adev->handle, "_TMP"))
 		return -ENODEV;
@@ -168,54 +55,33 @@
 	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->int340x_zone = int340x_thermal_zone_add(adev, NULL);
+	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->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->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);
 
-	thermal_zone_device_unregister(zone);
+	acpi_remove_notify_handler(d->handle,
+				   ACPI_DEVICE_NOTIFY, int3402_notify);
+	int340x_thermal_zone_remove(d->int340x_zone);
+
 	return 0;
 }
 
diff --git a/drivers/thermal/int340x_thermal/int3403_thermal.c b/drivers/thermal/int340x_thermal/int3403_thermal.c
index 0faf500..50a7a08 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 @@
 	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 @@
 	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 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 @@
 
 	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 @@
 	return 0;
 
  err_free_obj:
-	thermal_zone_device_unregister(obj->tzone);
+	int340x_thermal_zone_remove(obj->int340x_zone);
 	return result;
 }
 
@@ -303,7 +114,8 @@
 
 	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;
 }
 
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 0000000..f88b088
--- /dev/null
+++ b/drivers/thermal/int340x_thermal/int340x_thermal_zone.c
@@ -0,0 +1,276 @@
+/*
+ * 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");
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 0000000..9f38ab7
--- /dev/null
+++ b/drivers/thermal/int340x_thermal/int340x_thermal_zone.h
@@ -0,0 +1,68 @@
+/*
+ * 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
diff --git a/drivers/thermal/int340x_thermal/processor_thermal_device.c b/drivers/thermal/int340x_thermal/processor_thermal_device.c
index 0fe5dbb..7c3848d 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 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 @@
 	.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 @@
 	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 @@
 
 	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 @@
 
 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);
 }
diff --git a/include/acpi/acpi_lpat.h b/include/acpi/acpi_lpat.h
new file mode 100644
index 0000000..da37e12
--- /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