aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2015-02-19 14:28:36 -0500
committerLinus Torvalds <torvalds@linux-foundation.org>2015-02-19 14:28:36 -0500
commit89d3fa45b4add00cd0056361a2498e978cb1e119 (patch)
treeb717ab79c3258c3838d7d0753c5aeae61984e17c
parent477ea1169667a88d8ee12d83a0b0863091fb8670 (diff)
parent31908f45a583e8f21db37f402b6e8d5739945afd (diff)
Merge branch 'next' of git://git.kernel.org/pub/scm/linux/kernel/git/rzhang/linux
Pull thermal managament updates from Zhang Rui: "Specifics: - Abstract the code and introduce helper functions for all int340x thermal drivers. From: Srinivas Pandruvada. - Reorganize the ACPI LPAT table support code so that it can be shared for both ACPI PMIC driver and int340x thermal driver. - Add support for Braswell in intel_soc_dts thermal driver. - a couple of small fixes/cleanups for step_wise governor and int340x thermal driver" * 'next' of git://git.kernel.org/pub/scm/linux/kernel/git/rzhang/linux: Thermal/int340x_thermal: remove unused uuids. thermal: step_wise: spelling fixes thermal: int340x: fix sparse warning Thermal/int340x: LPAT conversion for temperature ACPI / PMIC: Use common LPAT table handling functions ACPI / LPAT: Common table processing functions thermal: Intel SoC DTS: Add Braswell support Thermal/int340x/int3402: Provide notification support Thermal/int340x/processor_thermal: Add thermal zone support Thermal/int340x/int3403: Use int340x thermal API Thermal/int340x/int3402: Use int340x thermal API Thermal/int340x: Add common thermal zone handler
-rw-r--r--drivers/acpi/Makefile1
-rw-r--r--drivers/acpi/acpi_lpat.c161
-rw-r--r--drivers/acpi/pmic/intel_pmic.c133
-rw-r--r--drivers/thermal/int340x_thermal/Makefile1
-rw-r--r--drivers/thermal/int340x_thermal/int3400_thermal.c4
-rw-r--r--drivers/thermal/int340x_thermal/int3402_thermal.c208
-rw-r--r--drivers/thermal/int340x_thermal/int3403_thermal.c208
-rw-r--r--drivers/thermal/int340x_thermal/int340x_thermal_zone.c276
-rw-r--r--drivers/thermal/int340x_thermal/int340x_thermal_zone.h68
-rw-r--r--drivers/thermal/int340x_thermal/processor_thermal_device.c92
-rw-r--r--drivers/thermal/intel_soc_dts_thermal.c46
-rw-r--r--drivers/thermal/step_wise.c4
-rw-r--r--include/acpi/acpi_lpat.h65
13 files changed, 760 insertions, 507 deletions
diff --git a/drivers/acpi/Makefile b/drivers/acpi/Makefile
index b18cd2151ddb..623b117ad1a2 100644
--- a/drivers/acpi/Makefile
+++ b/drivers/acpi/Makefile
@@ -55,6 +55,7 @@ acpi-$(CONFIG_ACPI_PROCFS_POWER) += cm_sbs.o
55ifdef CONFIG_ACPI_VIDEO 55ifdef CONFIG_ACPI_VIDEO
56acpi-y += video_detect.o 56acpi-y += video_detect.o
57endif 57endif
58acpi-y += acpi_lpat.o
58 59
59# These are (potentially) separate modules 60# These are (potentially) separate modules
60 61
diff --git a/drivers/acpi/acpi_lpat.c b/drivers/acpi/acpi_lpat.c
new file mode 100644
index 000000000000..feb61c1630eb
--- /dev/null
+++ b/drivers/acpi/acpi_lpat.c
@@ -0,0 +1,161 @@
1/*
2 * acpi_lpat.c - LPAT table processing functions
3 *
4 * Copyright (C) 2015 Intel Corporation. All rights reserved.
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License version
8 * 2 as published by the Free Software Foundation.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 */
15
16#include <linux/module.h>
17#include <linux/acpi.h>
18#include <acpi/acpi_lpat.h>
19
20/**
21 * acpi_lpat_raw_to_temp(): Return temperature from raw value through
22 * LPAT conversion table
23 *
24 * @lpat_table: the temperature_raw mapping table structure
25 * @raw: the raw value, used as a key to get the temerature from the
26 * above mapping table
27 *
28 * A positive converted temperarure value will be returned on success,
29 * a negative errno will be returned in error cases.
30 */
31int acpi_lpat_raw_to_temp(struct acpi_lpat_conversion_table *lpat_table,
32 int raw)
33{
34 int i, delta_temp, delta_raw, temp;
35 struct acpi_lpat *lpat = lpat_table->lpat;
36
37 for (i = 0; i < lpat_table->lpat_count - 1; i++) {
38 if ((raw >= lpat[i].raw && raw <= lpat[i+1].raw) ||
39 (raw <= lpat[i].raw && raw >= lpat[i+1].raw))
40 break;
41 }
42
43 if (i == lpat_table->lpat_count - 1)
44 return -ENOENT;
45
46 delta_temp = lpat[i+1].temp - lpat[i].temp;
47 delta_raw = lpat[i+1].raw - lpat[i].raw;
48 temp = lpat[i].temp + (raw - lpat[i].raw) * delta_temp / delta_raw;
49
50 return temp;
51}
52EXPORT_SYMBOL_GPL(acpi_lpat_raw_to_temp);
53
54/**
55 * acpi_lpat_temp_to_raw(): Return raw value from temperature through
56 * LPAT conversion table
57 *
58 * @lpat: the temperature_raw mapping table
59 * @temp: the temperature, used as a key to get the raw value from the
60 * above mapping table
61 *
62 * A positive converted temperature value will be returned on success,
63 * a negative errno will be returned in error cases.
64 */
65int acpi_lpat_temp_to_raw(struct acpi_lpat_conversion_table *lpat_table,
66 int temp)
67{
68 int i, delta_temp, delta_raw, raw;
69 struct acpi_lpat *lpat = lpat_table->lpat;
70
71 for (i = 0; i < lpat_table->lpat_count - 1; i++) {
72 if (temp >= lpat[i].temp && temp <= lpat[i+1].temp)
73 break;
74 }
75
76 if (i == lpat_table->lpat_count - 1)
77 return -ENOENT;
78
79 delta_temp = lpat[i+1].temp - lpat[i].temp;
80 delta_raw = lpat[i+1].raw - lpat[i].raw;
81 raw = lpat[i].raw + (temp - lpat[i].temp) * delta_raw / delta_temp;
82
83 return raw;
84}
85EXPORT_SYMBOL_GPL(acpi_lpat_temp_to_raw);
86
87/**
88 * acpi_lpat_get_conversion_table(): Parse ACPI LPAT table if present.
89 *
90 * @handle: Handle to acpi device
91 *
92 * Parse LPAT table to a struct of type acpi_lpat_table. On success
93 * it returns a pointer to newly allocated table. This table must
94 * be freed by the caller when finished processing, using a call to
95 * acpi_lpat_free_conversion_table.
96 */
97struct acpi_lpat_conversion_table *acpi_lpat_get_conversion_table(acpi_handle
98 handle)
99{
100 struct acpi_lpat_conversion_table *lpat_table = NULL;
101 struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
102 union acpi_object *obj_p, *obj_e;
103 int *lpat, i;
104 acpi_status status;
105
106 status = acpi_evaluate_object(handle, "LPAT", NULL, &buffer);
107 if (ACPI_FAILURE(status))
108 return NULL;
109
110 obj_p = (union acpi_object *)buffer.pointer;
111 if (!obj_p || (obj_p->type != ACPI_TYPE_PACKAGE) ||
112 (obj_p->package.count % 2) || (obj_p->package.count < 4))
113 goto out;
114
115 lpat = kcalloc(obj_p->package.count, sizeof(int), GFP_KERNEL);
116 if (!lpat)
117 goto out;
118
119 for (i = 0; i < obj_p->package.count; i++) {
120 obj_e = &obj_p->package.elements[i];
121 if (obj_e->type != ACPI_TYPE_INTEGER) {
122 kfree(lpat);
123 goto out;
124 }
125 lpat[i] = (s64)obj_e->integer.value;
126 }
127
128 lpat_table = kzalloc(sizeof(*lpat_table), GFP_KERNEL);
129 if (!lpat_table) {
130 kfree(lpat);
131 goto out;
132 }
133
134 lpat_table->lpat = (struct acpi_lpat *)lpat;
135 lpat_table->lpat_count = obj_p->package.count / 2;
136
137out:
138 kfree(buffer.pointer);
139 return lpat_table;
140}
141EXPORT_SYMBOL_GPL(acpi_lpat_get_conversion_table);
142
143/**
144 * acpi_lpat_free_conversion_table(): Free LPAT table.
145 *
146 * @lpat_table: the temperature_raw mapping table structure
147 *
148 * Frees the LPAT table previously allocated by a call to
149 * acpi_lpat_get_conversion_table.
150 */
151void acpi_lpat_free_conversion_table(struct acpi_lpat_conversion_table
152 *lpat_table)
153{
154 if (lpat_table) {
155 kfree(lpat_table->lpat);
156 kfree(lpat_table);
157 }
158}
159EXPORT_SYMBOL_GPL(acpi_lpat_free_conversion_table);
160
161MODULE_LICENSE("GPL");
diff --git a/drivers/acpi/pmic/intel_pmic.c b/drivers/acpi/pmic/intel_pmic.c
index a732e5d7e322..bd772cd56494 100644
--- a/drivers/acpi/pmic/intel_pmic.c
+++ b/drivers/acpi/pmic/intel_pmic.c
@@ -16,20 +16,15 @@
16#include <linux/module.h> 16#include <linux/module.h>
17#include <linux/acpi.h> 17#include <linux/acpi.h>
18#include <linux/regmap.h> 18#include <linux/regmap.h>
19#include <acpi/acpi_lpat.h>
19#include "intel_pmic.h" 20#include "intel_pmic.h"
20 21
21#define PMIC_POWER_OPREGION_ID 0x8d 22#define PMIC_POWER_OPREGION_ID 0x8d
22#define PMIC_THERMAL_OPREGION_ID 0x8c 23#define PMIC_THERMAL_OPREGION_ID 0x8c
23 24
24struct acpi_lpat {
25 int temp;
26 int raw;
27};
28
29struct intel_pmic_opregion { 25struct intel_pmic_opregion {
30 struct mutex lock; 26 struct mutex lock;
31 struct acpi_lpat *lpat; 27 struct acpi_lpat_conversion_table *lpat_table;
32 int lpat_count;
33 struct regmap *regmap; 28 struct regmap *regmap;
34 struct intel_pmic_opregion_data *data; 29 struct intel_pmic_opregion_data *data;
35}; 30};
@@ -50,105 +45,6 @@ static int pmic_get_reg_bit(int address, struct pmic_table *table,
50 return -ENOENT; 45 return -ENOENT;
51} 46}
52 47
53/**
54 * raw_to_temp(): Return temperature from raw value through LPAT table
55 *
56 * @lpat: the temperature_raw mapping table
57 * @count: the count of the above mapping table
58 * @raw: the raw value, used as a key to get the temerature from the
59 * above mapping table
60 *
61 * A positive value will be returned on success, a negative errno will
62 * be returned in error cases.
63 */
64static int raw_to_temp(struct acpi_lpat *lpat, int count, int raw)
65{
66 int i, delta_temp, delta_raw, temp;
67
68 for (i = 0; i < count - 1; i++) {
69 if ((raw >= lpat[i].raw && raw <= lpat[i+1].raw) ||
70 (raw <= lpat[i].raw && raw >= lpat[i+1].raw))
71 break;
72 }
73
74 if (i == count - 1)
75 return -ENOENT;
76
77 delta_temp = lpat[i+1].temp - lpat[i].temp;
78 delta_raw = lpat[i+1].raw - lpat[i].raw;
79 temp = lpat[i].temp + (raw - lpat[i].raw) * delta_temp / delta_raw;
80
81 return temp;
82}
83
84/**
85 * temp_to_raw(): Return raw value from temperature through LPAT table
86 *
87 * @lpat: the temperature_raw mapping table
88 * @count: the count of the above mapping table
89 * @temp: the temperature, used as a key to get the raw value from the
90 * above mapping table
91 *
92 * A positive value will be returned on success, a negative errno will
93 * be returned in error cases.
94 */
95static int temp_to_raw(struct acpi_lpat *lpat, int count, int temp)
96{
97 int i, delta_temp, delta_raw, raw;
98
99 for (i = 0; i < count - 1; i++) {
100 if (temp >= lpat[i].temp && temp <= lpat[i+1].temp)
101 break;
102 }
103
104 if (i == count - 1)
105 return -ENOENT;
106
107 delta_temp = lpat[i+1].temp - lpat[i].temp;
108 delta_raw = lpat[i+1].raw - lpat[i].raw;
109 raw = lpat[i].raw + (temp - lpat[i].temp) * delta_raw / delta_temp;
110
111 return raw;
112}
113
114static void pmic_thermal_lpat(struct intel_pmic_opregion *opregion,
115 acpi_handle handle, struct device *dev)
116{
117 struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
118 union acpi_object *obj_p, *obj_e;
119 int *lpat, i;
120 acpi_status status;
121
122 status = acpi_evaluate_object(handle, "LPAT", NULL, &buffer);
123 if (ACPI_FAILURE(status))
124 return;
125
126 obj_p = (union acpi_object *)buffer.pointer;
127 if (!obj_p || (obj_p->type != ACPI_TYPE_PACKAGE) ||
128 (obj_p->package.count % 2) || (obj_p->package.count < 4))
129 goto out;
130
131 lpat = devm_kmalloc(dev, sizeof(int) * obj_p->package.count,
132 GFP_KERNEL);
133 if (!lpat)
134 goto out;
135
136 for (i = 0; i < obj_p->package.count; i++) {
137 obj_e = &obj_p->package.elements[i];
138 if (obj_e->type != ACPI_TYPE_INTEGER) {
139 devm_kfree(dev, lpat);
140 goto out;
141 }
142 lpat[i] = (s64)obj_e->integer.value;
143 }
144
145 opregion->lpat = (struct acpi_lpat *)lpat;
146 opregion->lpat_count = obj_p->package.count / 2;
147
148out:
149 kfree(buffer.pointer);
150}
151
152static acpi_status intel_pmic_power_handler(u32 function, 48static acpi_status intel_pmic_power_handler(u32 function,
153 acpi_physical_address address, u32 bits, u64 *value64, 49 acpi_physical_address address, u32 bits, u64 *value64,
154 void *handler_context, void *region_context) 50 void *handler_context, void *region_context)
@@ -192,12 +88,12 @@ static int pmic_read_temp(struct intel_pmic_opregion *opregion,
192 if (raw_temp < 0) 88 if (raw_temp < 0)
193 return raw_temp; 89 return raw_temp;
194 90
195 if (!opregion->lpat) { 91 if (!opregion->lpat_table) {
196 *value = raw_temp; 92 *value = raw_temp;
197 return 0; 93 return 0;
198 } 94 }
199 95
200 temp = raw_to_temp(opregion->lpat, opregion->lpat_count, raw_temp); 96 temp = acpi_lpat_raw_to_temp(opregion->lpat_table, raw_temp);
201 if (temp < 0) 97 if (temp < 0)
202 return temp; 98 return temp;
203 99
@@ -223,9 +119,8 @@ static int pmic_thermal_aux(struct intel_pmic_opregion *opregion, int reg,
223 if (!opregion->data->update_aux) 119 if (!opregion->data->update_aux)
224 return -ENXIO; 120 return -ENXIO;
225 121
226 if (opregion->lpat) { 122 if (opregion->lpat_table) {
227 raw_temp = temp_to_raw(opregion->lpat, opregion->lpat_count, 123 raw_temp = acpi_lpat_temp_to_raw(opregion->lpat_table, *value);
228 *value);
229 if (raw_temp < 0) 124 if (raw_temp < 0)
230 return raw_temp; 125 return raw_temp;
231 } else { 126 } else {
@@ -314,6 +209,7 @@ int intel_pmic_install_opregion_handler(struct device *dev, acpi_handle handle,
314{ 209{
315 acpi_status status; 210 acpi_status status;
316 struct intel_pmic_opregion *opregion; 211 struct intel_pmic_opregion *opregion;
212 int ret;
317 213
318 if (!dev || !regmap || !d) 214 if (!dev || !regmap || !d)
319 return -EINVAL; 215 return -EINVAL;
@@ -327,14 +223,16 @@ int intel_pmic_install_opregion_handler(struct device *dev, acpi_handle handle,
327 223
328 mutex_init(&opregion->lock); 224 mutex_init(&opregion->lock);
329 opregion->regmap = regmap; 225 opregion->regmap = regmap;
330 pmic_thermal_lpat(opregion, handle, dev); 226 opregion->lpat_table = acpi_lpat_get_conversion_table(handle);
331 227
332 status = acpi_install_address_space_handler(handle, 228 status = acpi_install_address_space_handler(handle,
333 PMIC_POWER_OPREGION_ID, 229 PMIC_POWER_OPREGION_ID,
334 intel_pmic_power_handler, 230 intel_pmic_power_handler,
335 NULL, opregion); 231 NULL, opregion);
336 if (ACPI_FAILURE(status)) 232 if (ACPI_FAILURE(status)) {
337 return -ENODEV; 233 ret = -ENODEV;
234 goto out_error;
235 }
338 236
339 status = acpi_install_address_space_handler(handle, 237 status = acpi_install_address_space_handler(handle,
340 PMIC_THERMAL_OPREGION_ID, 238 PMIC_THERMAL_OPREGION_ID,
@@ -343,11 +241,16 @@ int intel_pmic_install_opregion_handler(struct device *dev, acpi_handle handle,
343 if (ACPI_FAILURE(status)) { 241 if (ACPI_FAILURE(status)) {
344 acpi_remove_address_space_handler(handle, PMIC_POWER_OPREGION_ID, 242 acpi_remove_address_space_handler(handle, PMIC_POWER_OPREGION_ID,
345 intel_pmic_power_handler); 243 intel_pmic_power_handler);
346 return -ENODEV; 244 ret = -ENODEV;
245 goto out_error;
347 } 246 }
348 247
349 opregion->data = d; 248 opregion->data = d;
350 return 0; 249 return 0;
250
251out_error:
252 acpi_lpat_free_conversion_table(opregion->lpat_table);
253 return ret;
351} 254}
352EXPORT_SYMBOL_GPL(intel_pmic_install_opregion_handler); 255EXPORT_SYMBOL_GPL(intel_pmic_install_opregion_handler);
353 256
diff --git a/drivers/thermal/int340x_thermal/Makefile b/drivers/thermal/int340x_thermal/Makefile
index d4413698a85f..ba77a34f659f 100644
--- a/drivers/thermal/int340x_thermal/Makefile
+++ b/drivers/thermal/int340x_thermal/Makefile
@@ -1,4 +1,5 @@
1obj-$(CONFIG_INT340X_THERMAL) += int3400_thermal.o 1obj-$(CONFIG_INT340X_THERMAL) += int3400_thermal.o
2obj-$(CONFIG_INT340X_THERMAL) += int340x_thermal_zone.o
2obj-$(CONFIG_INT340X_THERMAL) += int3402_thermal.o 3obj-$(CONFIG_INT340X_THERMAL) += int3402_thermal.o
3obj-$(CONFIG_INT340X_THERMAL) += int3403_thermal.o 4obj-$(CONFIG_INT340X_THERMAL) += int3403_thermal.o
4obj-$(CONFIG_INT340X_THERMAL) += processor_thermal_device.o 5obj-$(CONFIG_INT340X_THERMAL) += processor_thermal_device.o
diff --git a/drivers/thermal/int340x_thermal/int3400_thermal.c b/drivers/thermal/int340x_thermal/int3400_thermal.c
index 65a98a97df07..25d244cbbe8f 100644
--- a/drivers/thermal/int340x_thermal/int3400_thermal.c
+++ b/drivers/thermal/int340x_thermal/int3400_thermal.c
@@ -18,19 +18,15 @@
18 18
19enum int3400_thermal_uuid { 19enum int3400_thermal_uuid {
20 INT3400_THERMAL_PASSIVE_1, 20 INT3400_THERMAL_PASSIVE_1,
21 INT3400_THERMAL_PASSIVE_2,
22 INT3400_THERMAL_ACTIVE, 21 INT3400_THERMAL_ACTIVE,
23 INT3400_THERMAL_CRITICAL, 22 INT3400_THERMAL_CRITICAL,
24 INT3400_THERMAL_COOLING_MODE,
25 INT3400_THERMAL_MAXIMUM_UUID, 23 INT3400_THERMAL_MAXIMUM_UUID,
26}; 24};
27 25
28static u8 *int3400_thermal_uuids[INT3400_THERMAL_MAXIMUM_UUID] = { 26static u8 *int3400_thermal_uuids[INT3400_THERMAL_MAXIMUM_UUID] = {
29 "42A441D6-AE6A-462b-A84B-4A8CE79027D3", 27 "42A441D6-AE6A-462b-A84B-4A8CE79027D3",
30 "9E04115A-AE87-4D1C-9500-0F3E340BFE75",
31 "3A95C389-E4B8-4629-A526-C52C88626BAE", 28 "3A95C389-E4B8-4629-A526-C52C88626BAE",
32 "97C68AE7-15FA-499c-B8C9-5DA81D606E0A", 29 "97C68AE7-15FA-499c-B8C9-5DA81D606E0A",
33 "16CAF1B7-DD38-40ed-B1C1-1B8A1913D531",
34}; 30};
35 31
36struct int3400_thermal_priv { 32struct int3400_thermal_priv {
diff --git a/drivers/thermal/int340x_thermal/int3402_thermal.c b/drivers/thermal/int340x_thermal/int3402_thermal.c
index c5cbc3af3a05..69df3d960303 100644
--- a/drivers/thermal/int340x_thermal/int3402_thermal.c
+++ b/drivers/thermal/int340x_thermal/int3402_thermal.c
@@ -14,152 +14,39 @@
14#include <linux/platform_device.h> 14#include <linux/platform_device.h>
15#include <linux/acpi.h> 15#include <linux/acpi.h>
16#include <linux/thermal.h> 16#include <linux/thermal.h>
17#include "int340x_thermal_zone.h"
17 18
18#define ACPI_ACTIVE_COOLING_MAX_NR 10 19#define INT3402_PERF_CHANGED_EVENT 0x80
19 20#define INT3402_THERMAL_EVENT 0x90
20struct active_trip {
21 unsigned long temp;
22 int id;
23 bool valid;
24};
25 21
26struct int3402_thermal_data { 22struct int3402_thermal_data {
27 unsigned long *aux_trips;
28 int aux_trip_nr;
29 unsigned long psv_temp;
30 int psv_trip_id;
31 unsigned long crt_temp;
32 int crt_trip_id;
33 unsigned long hot_temp;
34 int hot_trip_id;
35 struct active_trip act_trips[ACPI_ACTIVE_COOLING_MAX_NR];
36 acpi_handle *handle; 23 acpi_handle *handle;
24 struct int34x_thermal_zone *int340x_zone;
37}; 25};
38 26
39static int int3402_thermal_get_zone_temp(struct thermal_zone_device *zone, 27static void int3402_notify(acpi_handle handle, u32 event, void *data)
40 unsigned long *temp)
41{
42 struct int3402_thermal_data *d = zone->devdata;
43 unsigned long long tmp;
44 acpi_status status;
45
46 status = acpi_evaluate_integer(d->handle, "_TMP", NULL, &tmp);
47 if (ACPI_FAILURE(status))
48 return -ENODEV;
49
50 /* _TMP returns the temperature in tenths of degrees Kelvin */
51 *temp = DECI_KELVIN_TO_MILLICELSIUS(tmp);
52
53 return 0;
54}
55
56static int int3402_thermal_get_trip_temp(struct thermal_zone_device *zone,
57 int trip, unsigned long *temp)
58{ 28{
59 struct int3402_thermal_data *d = zone->devdata; 29 struct int3402_thermal_data *priv = data;
60 int i; 30
61 31 if (!priv)
62 if (trip < d->aux_trip_nr) 32 return;
63 *temp = d->aux_trips[trip]; 33
64 else if (trip == d->crt_trip_id) 34 switch (event) {
65 *temp = d->crt_temp; 35 case INT3402_PERF_CHANGED_EVENT:
66 else if (trip == d->psv_trip_id) 36 break;
67 *temp = d->psv_temp; 37 case INT3402_THERMAL_EVENT:
68 else if (trip == d->hot_trip_id) 38 int340x_thermal_zone_device_update(priv->int340x_zone);
69 *temp = d->hot_temp; 39 break;
70 else { 40 default:
71 for (i = 0; i < ACPI_ACTIVE_COOLING_MAX_NR; i++) { 41 break;
72 if (d->act_trips[i].valid &&
73 d->act_trips[i].id == trip) {
74 *temp = d->act_trips[i].temp;
75 break;
76 }
77 }
78 if (i == ACPI_ACTIVE_COOLING_MAX_NR)
79 return -EINVAL;
80 } 42 }
81 return 0;
82}
83
84static int int3402_thermal_get_trip_type(struct thermal_zone_device *zone,
85 int trip, enum thermal_trip_type *type)
86{
87 struct int3402_thermal_data *d = zone->devdata;
88 int i;
89
90 if (trip < d->aux_trip_nr)
91 *type = THERMAL_TRIP_PASSIVE;
92 else if (trip == d->crt_trip_id)
93 *type = THERMAL_TRIP_CRITICAL;
94 else if (trip == d->hot_trip_id)
95 *type = THERMAL_TRIP_HOT;
96 else if (trip == d->psv_trip_id)
97 *type = THERMAL_TRIP_PASSIVE;
98 else {
99 for (i = 0; i < ACPI_ACTIVE_COOLING_MAX_NR; i++) {
100 if (d->act_trips[i].valid &&
101 d->act_trips[i].id == trip) {
102 *type = THERMAL_TRIP_ACTIVE;
103 break;
104 }
105 }
106 if (i == ACPI_ACTIVE_COOLING_MAX_NR)
107 return -EINVAL;
108 }
109 return 0;
110}
111
112static int int3402_thermal_set_trip_temp(struct thermal_zone_device *zone, int trip,
113 unsigned long temp)
114{
115 struct int3402_thermal_data *d = zone->devdata;
116 acpi_status status;
117 char name[10];
118
119 snprintf(name, sizeof(name), "PAT%d", trip);
120 status = acpi_execute_simple_method(d->handle, name,
121 MILLICELSIUS_TO_DECI_KELVIN(temp));
122 if (ACPI_FAILURE(status))
123 return -EIO;
124
125 d->aux_trips[trip] = temp;
126 return 0;
127}
128
129static struct thermal_zone_device_ops int3402_thermal_zone_ops = {
130 .get_temp = int3402_thermal_get_zone_temp,
131 .get_trip_temp = int3402_thermal_get_trip_temp,
132 .get_trip_type = int3402_thermal_get_trip_type,
133 .set_trip_temp = int3402_thermal_set_trip_temp,
134};
135
136static struct thermal_zone_params int3402_thermal_params = {
137 .governor_name = "user_space",
138 .no_hwmon = true,
139};
140
141static int int3402_thermal_get_temp(acpi_handle handle, char *name,
142 unsigned long *temp)
143{
144 unsigned long long r;
145 acpi_status status;
146
147 status = acpi_evaluate_integer(handle, name, NULL, &r);
148 if (ACPI_FAILURE(status))
149 return -EIO;
150
151 *temp = DECI_KELVIN_TO_MILLICELSIUS(r);
152 return 0;
153} 43}
154 44
155static int int3402_thermal_probe(struct platform_device *pdev) 45static int int3402_thermal_probe(struct platform_device *pdev)
156{ 46{
157 struct acpi_device *adev = ACPI_COMPANION(&pdev->dev); 47 struct acpi_device *adev = ACPI_COMPANION(&pdev->dev);
158 struct int3402_thermal_data *d; 48 struct int3402_thermal_data *d;
159 struct thermal_zone_device *zone; 49 int ret;
160 acpi_status status;
161 unsigned long long trip_cnt;
162 int trip_mask = 0, i;
163 50
164 if (!acpi_has_method(adev->handle, "_TMP")) 51 if (!acpi_has_method(adev->handle, "_TMP"))
165 return -ENODEV; 52 return -ENODEV;
@@ -168,54 +55,33 @@ static int int3402_thermal_probe(struct platform_device *pdev)
168 if (!d) 55 if (!d)
169 return -ENOMEM; 56 return -ENOMEM;
170 57
171 status = acpi_evaluate_integer(adev->handle, "PATC", NULL, &trip_cnt); 58 d->int340x_zone = int340x_thermal_zone_add(adev, NULL);
172 if (ACPI_FAILURE(status)) 59 if (IS_ERR(d->int340x_zone))
173 trip_cnt = 0; 60 return PTR_ERR(d->int340x_zone);
174 else { 61
175 d->aux_trips = devm_kzalloc(&pdev->dev, 62 ret = acpi_install_notify_handler(adev->handle,
176 sizeof(*d->aux_trips) * trip_cnt, GFP_KERNEL); 63 ACPI_DEVICE_NOTIFY,
177 if (!d->aux_trips) 64 int3402_notify,
178 return -ENOMEM; 65 d);
179 trip_mask = trip_cnt - 1; 66 if (ret) {
180 d->handle = adev->handle; 67 int340x_thermal_zone_remove(d->int340x_zone);
181 d->aux_trip_nr = trip_cnt; 68 return ret;
182 }
183
184 d->crt_trip_id = -1;
185 if (!int3402_thermal_get_temp(adev->handle, "_CRT", &d->crt_temp))
186 d->crt_trip_id = trip_cnt++;
187 d->hot_trip_id = -1;
188 if (!int3402_thermal_get_temp(adev->handle, "_HOT", &d->hot_temp))
189 d->hot_trip_id = trip_cnt++;
190 d->psv_trip_id = -1;
191 if (!int3402_thermal_get_temp(adev->handle, "_PSV", &d->psv_temp))
192 d->psv_trip_id = trip_cnt++;
193 for (i = 0; i < ACPI_ACTIVE_COOLING_MAX_NR; i++) {
194 char name[5] = { '_', 'A', 'C', '0' + i, '\0' };
195 if (int3402_thermal_get_temp(adev->handle, name,
196 &d->act_trips[i].temp))
197 break;
198 d->act_trips[i].id = trip_cnt++;
199 d->act_trips[i].valid = true;
200 } 69 }
201 70
202 zone = thermal_zone_device_register(acpi_device_bid(adev), trip_cnt, 71 d->handle = adev->handle;
203 trip_mask, d, 72 platform_set_drvdata(pdev, d);
204 &int3402_thermal_zone_ops,
205 &int3402_thermal_params,
206 0, 0);
207 if (IS_ERR(zone))
208 return PTR_ERR(zone);
209 platform_set_drvdata(pdev, zone);
210 73
211 return 0; 74 return 0;
212} 75}
213 76
214static int int3402_thermal_remove(struct platform_device *pdev) 77static int int3402_thermal_remove(struct platform_device *pdev)
215{ 78{
216 struct thermal_zone_device *zone = platform_get_drvdata(pdev); 79 struct int3402_thermal_data *d = platform_get_drvdata(pdev);
80
81 acpi_remove_notify_handler(d->handle,
82 ACPI_DEVICE_NOTIFY, int3402_notify);
83 int340x_thermal_zone_remove(d->int340x_zone);
217 84
218 thermal_zone_device_unregister(zone);
219 return 0; 85 return 0;
220} 86}
221 87
diff --git a/drivers/thermal/int340x_thermal/int3403_thermal.c b/drivers/thermal/int340x_thermal/int3403_thermal.c
index 0faf500d8a77..50a7a08e3a15 100644
--- a/drivers/thermal/int340x_thermal/int3403_thermal.c
+++ b/drivers/thermal/int340x_thermal/int3403_thermal.c
@@ -19,6 +19,7 @@
19#include <linux/acpi.h> 19#include <linux/acpi.h>
20#include <linux/thermal.h> 20#include <linux/thermal.h>
21#include <linux/platform_device.h> 21#include <linux/platform_device.h>
22#include "int340x_thermal_zone.h"
22 23
23#define INT3403_TYPE_SENSOR 0x03 24#define INT3403_TYPE_SENSOR 0x03
24#define INT3403_TYPE_CHARGER 0x0B 25#define INT3403_TYPE_CHARGER 0x0B
@@ -26,18 +27,9 @@
26#define INT3403_PERF_CHANGED_EVENT 0x80 27#define INT3403_PERF_CHANGED_EVENT 0x80
27#define INT3403_THERMAL_EVENT 0x90 28#define INT3403_THERMAL_EVENT 0x90
28 29
29#define DECI_KELVIN_TO_MILLI_CELSIUS(t, off) (((t) - (off)) * 100) 30/* Preserved structure for future expandbility */
30#define KELVIN_OFFSET 2732
31#define MILLI_CELSIUS_TO_DECI_KELVIN(t, off) (((t) / 100) + (off))
32
33struct int3403_sensor { 31struct int3403_sensor {
34 struct thermal_zone_device *tzone; 32 struct int34x_thermal_zone *int340x_zone;
35 unsigned long *thresholds;
36 unsigned long crit_temp;
37 int crit_trip_id;
38 unsigned long psv_temp;
39 int psv_trip_id;
40
41}; 33};
42 34
43struct int3403_performance_state { 35struct int3403_performance_state {
@@ -63,126 +55,6 @@ struct int3403_priv {
63 void *priv; 55 void *priv;
64}; 56};
65 57
66static int sys_get_curr_temp(struct thermal_zone_device *tzone,
67 unsigned long *temp)
68{
69 struct int3403_priv *priv = tzone->devdata;
70 struct acpi_device *device = priv->adev;
71 unsigned long long tmp;
72 acpi_status status;
73
74 status = acpi_evaluate_integer(device->handle, "_TMP", NULL, &tmp);
75 if (ACPI_FAILURE(status))
76 return -EIO;
77
78 *temp = DECI_KELVIN_TO_MILLI_CELSIUS(tmp, KELVIN_OFFSET);
79
80 return 0;
81}
82
83static int sys_get_trip_hyst(struct thermal_zone_device *tzone,
84 int trip, unsigned long *temp)
85{
86 struct int3403_priv *priv = tzone->devdata;
87 struct acpi_device *device = priv->adev;
88 unsigned long long hyst;
89 acpi_status status;
90
91 status = acpi_evaluate_integer(device->handle, "GTSH", NULL, &hyst);
92 if (ACPI_FAILURE(status))
93 return -EIO;
94
95 /*
96 * Thermal hysteresis represents a temperature difference.
97 * Kelvin and Celsius have same degree size. So the
98 * conversion here between tenths of degree Kelvin unit
99 * and Milli-Celsius unit is just to multiply 100.
100 */
101 *temp = hyst * 100;
102
103 return 0;
104}
105
106static int sys_get_trip_temp(struct thermal_zone_device *tzone,
107 int trip, unsigned long *temp)
108{
109 struct int3403_priv *priv = tzone->devdata;
110 struct int3403_sensor *obj = priv->priv;
111
112 if (priv->type != INT3403_TYPE_SENSOR || !obj)
113 return -EINVAL;
114
115 if (trip == obj->crit_trip_id)
116 *temp = obj->crit_temp;
117 else if (trip == obj->psv_trip_id)
118 *temp = obj->psv_temp;
119 else {
120 /*
121 * get_trip_temp is a mandatory callback but
122 * PATx method doesn't return any value, so return
123 * cached value, which was last set from user space
124 */
125 *temp = obj->thresholds[trip];
126 }
127
128 return 0;
129}
130
131static int sys_get_trip_type(struct thermal_zone_device *thermal,
132 int trip, enum thermal_trip_type *type)
133{
134 struct int3403_priv *priv = thermal->devdata;
135 struct int3403_sensor *obj = priv->priv;
136
137 /* Mandatory callback, may not mean much here */
138 if (trip == obj->crit_trip_id)
139 *type = THERMAL_TRIP_CRITICAL;
140 else
141 *type = THERMAL_TRIP_PASSIVE;
142
143 return 0;
144}
145
146int sys_set_trip_temp(struct thermal_zone_device *tzone, int trip,
147 unsigned long temp)
148{
149 struct int3403_priv *priv = tzone->devdata;
150 struct acpi_device *device = priv->adev;
151 struct int3403_sensor *obj = priv->priv;
152 acpi_status status;
153 char name[10];
154 int ret = 0;
155
156 snprintf(name, sizeof(name), "PAT%d", trip);
157 if (acpi_has_method(device->handle, name)) {
158 status = acpi_execute_simple_method(device->handle, name,
159 MILLI_CELSIUS_TO_DECI_KELVIN(temp,
160 KELVIN_OFFSET));
161 if (ACPI_FAILURE(status))
162 ret = -EIO;
163 else
164 obj->thresholds[trip] = temp;
165 } else {
166 ret = -EIO;
167 dev_err(&device->dev, "sys_set_trip_temp: method not found\n");
168 }
169
170 return ret;
171}
172
173static struct thermal_zone_device_ops tzone_ops = {
174 .get_temp = sys_get_curr_temp,
175 .get_trip_temp = sys_get_trip_temp,
176 .get_trip_type = sys_get_trip_type,
177 .set_trip_temp = sys_set_trip_temp,
178 .get_trip_hyst = sys_get_trip_hyst,
179};
180
181static struct thermal_zone_params int3403_thermal_params = {
182 .governor_name = "user_space",
183 .no_hwmon = true,
184};
185
186static void int3403_notify(acpi_handle handle, 58static void int3403_notify(acpi_handle handle,
187 u32 event, void *data) 59 u32 event, void *data)
188{ 60{
@@ -200,7 +72,7 @@ static void int3403_notify(acpi_handle handle,
200 case INT3403_PERF_CHANGED_EVENT: 72 case INT3403_PERF_CHANGED_EVENT:
201 break; 73 break;
202 case INT3403_THERMAL_EVENT: 74 case INT3403_THERMAL_EVENT:
203 thermal_zone_device_update(obj->tzone); 75 int340x_thermal_zone_device_update(obj->int340x_zone);
204 break; 76 break;
205 default: 77 default:
206 dev_err(&priv->pdev->dev, "Unsupported event [0x%x]\n", event); 78 dev_err(&priv->pdev->dev, "Unsupported event [0x%x]\n", event);
@@ -208,41 +80,10 @@ static void int3403_notify(acpi_handle handle,
208 } 80 }
209} 81}
210 82
211static int sys_get_trip_crt(struct acpi_device *device, unsigned long *temp)
212{
213 unsigned long long crt;
214 acpi_status status;
215
216 status = acpi_evaluate_integer(device->handle, "_CRT", NULL, &crt);
217 if (ACPI_FAILURE(status))
218 return -EIO;
219
220 *temp = DECI_KELVIN_TO_MILLI_CELSIUS(crt, KELVIN_OFFSET);
221
222 return 0;
223}
224
225static int sys_get_trip_psv(struct acpi_device *device, unsigned long *temp)
226{
227 unsigned long long psv;
228 acpi_status status;
229
230 status = acpi_evaluate_integer(device->handle, "_PSV", NULL, &psv);
231 if (ACPI_FAILURE(status))
232 return -EIO;
233
234 *temp = DECI_KELVIN_TO_MILLI_CELSIUS(psv, KELVIN_OFFSET);
235
236 return 0;
237}
238
239static int int3403_sensor_add(struct int3403_priv *priv) 83static int int3403_sensor_add(struct int3403_priv *priv)
240{ 84{
241 int result = 0; 85 int result = 0;
242 acpi_status status;
243 struct int3403_sensor *obj; 86 struct int3403_sensor *obj;
244 unsigned long long trip_cnt;
245 int trip_mask = 0;
246 87
247 obj = devm_kzalloc(&priv->pdev->dev, sizeof(*obj), GFP_KERNEL); 88 obj = devm_kzalloc(&priv->pdev->dev, sizeof(*obj), GFP_KERNEL);
248 if (!obj) 89 if (!obj)
@@ -250,39 +91,9 @@ static int int3403_sensor_add(struct int3403_priv *priv)
250 91
251 priv->priv = obj; 92 priv->priv = obj;
252 93
253 status = acpi_evaluate_integer(priv->adev->handle, "PATC", NULL, 94 obj->int340x_zone = int340x_thermal_zone_add(priv->adev, NULL);
254 &trip_cnt); 95 if (IS_ERR(obj->int340x_zone))
255 if (ACPI_FAILURE(status)) 96 return PTR_ERR(obj->int340x_zone);
256 trip_cnt = 0;
257
258 if (trip_cnt) {
259 /* We have to cache, thresholds can't be readback */
260 obj->thresholds = devm_kzalloc(&priv->pdev->dev,
261 sizeof(*obj->thresholds) * trip_cnt,
262 GFP_KERNEL);
263 if (!obj->thresholds) {
264 result = -ENOMEM;
265 goto err_free_obj;
266 }
267 trip_mask = BIT(trip_cnt) - 1;
268 }
269
270 obj->psv_trip_id = -1;
271 if (!sys_get_trip_psv(priv->adev, &obj->psv_temp))
272 obj->psv_trip_id = trip_cnt++;
273
274 obj->crit_trip_id = -1;
275 if (!sys_get_trip_crt(priv->adev, &obj->crit_temp))
276 obj->crit_trip_id = trip_cnt++;
277
278 obj->tzone = thermal_zone_device_register(acpi_device_bid(priv->adev),
279 trip_cnt, trip_mask, priv, &tzone_ops,
280 &int3403_thermal_params, 0, 0);
281 if (IS_ERR(obj->tzone)) {
282 result = PTR_ERR(obj->tzone);
283 obj->tzone = NULL;
284 goto err_free_obj;
285 }
286 97
287 result = acpi_install_notify_handler(priv->adev->handle, 98 result = acpi_install_notify_handler(priv->adev->handle,
288 ACPI_DEVICE_NOTIFY, int3403_notify, 99 ACPI_DEVICE_NOTIFY, int3403_notify,
@@ -293,7 +104,7 @@ static int int3403_sensor_add(struct int3403_priv *priv)
293 return 0; 104 return 0;
294 105
295 err_free_obj: 106 err_free_obj:
296 thermal_zone_device_unregister(obj->tzone); 107 int340x_thermal_zone_remove(obj->int340x_zone);
297 return result; 108 return result;
298} 109}
299 110
@@ -303,7 +114,8 @@ static int int3403_sensor_remove(struct int3403_priv *priv)
303 114
304 acpi_remove_notify_handler(priv->adev->handle, 115 acpi_remove_notify_handler(priv->adev->handle,
305 ACPI_DEVICE_NOTIFY, int3403_notify); 116 ACPI_DEVICE_NOTIFY, int3403_notify);
306 thermal_zone_device_unregister(obj->tzone); 117 int340x_thermal_zone_remove(obj->int340x_zone);
118
307 return 0; 119 return 0;
308} 120}
309 121
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 000000000000..f88b08877025
--- /dev/null
+++ b/drivers/thermal/int340x_thermal/int340x_thermal_zone.c
@@ -0,0 +1,276 @@
1/*
2 * int340x_thermal_zone.c
3 * Copyright (c) 2015, Intel Corporation.
4 *
5 * This program is free software; you can redistribute it and/or modify it
6 * under the terms and conditions of the GNU General Public License,
7 * version 2, as published by the Free Software Foundation.
8 *
9 * This program is distributed in the hope it will be useful, but WITHOUT
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
12 * more details.
13 *
14 */
15#include <linux/kernel.h>
16#include <linux/module.h>
17#include <linux/init.h>
18#include <linux/acpi.h>
19#include <linux/thermal.h>
20#include "int340x_thermal_zone.h"
21
22static int int340x_thermal_get_zone_temp(struct thermal_zone_device *zone,
23 unsigned long *temp)
24{
25 struct int34x_thermal_zone *d = zone->devdata;
26 unsigned long long tmp;
27 acpi_status status;
28
29 if (d->override_ops && d->override_ops->get_temp)
30 return d->override_ops->get_temp(zone, temp);
31
32 status = acpi_evaluate_integer(d->adev->handle, "_TMP", NULL, &tmp);
33 if (ACPI_FAILURE(status))
34 return -EIO;
35
36 if (d->lpat_table) {
37 int conv_temp;
38
39 conv_temp = acpi_lpat_raw_to_temp(d->lpat_table, (int)tmp);
40 if (conv_temp < 0)
41 return conv_temp;
42
43 *temp = (unsigned long)conv_temp * 10;
44 } else
45 /* _TMP returns the temperature in tenths of degrees Kelvin */
46 *temp = DECI_KELVIN_TO_MILLICELSIUS(tmp);
47
48 return 0;
49}
50
51static int int340x_thermal_get_trip_temp(struct thermal_zone_device *zone,
52 int trip, unsigned long *temp)
53{
54 struct int34x_thermal_zone *d = zone->devdata;
55 int i;
56
57 if (d->override_ops && d->override_ops->get_trip_temp)
58 return d->override_ops->get_trip_temp(zone, trip, temp);
59
60 if (trip < d->aux_trip_nr)
61 *temp = d->aux_trips[trip];
62 else if (trip == d->crt_trip_id)
63 *temp = d->crt_temp;
64 else if (trip == d->psv_trip_id)
65 *temp = d->psv_temp;
66 else if (trip == d->hot_trip_id)
67 *temp = d->hot_temp;
68 else {
69 for (i = 0; i < INT340X_THERMAL_MAX_ACT_TRIP_COUNT; i++) {
70 if (d->act_trips[i].valid &&
71 d->act_trips[i].id == trip) {
72 *temp = d->act_trips[i].temp;
73 break;
74 }
75 }
76 if (i == INT340X_THERMAL_MAX_ACT_TRIP_COUNT)
77 return -EINVAL;
78 }
79
80 return 0;
81}
82
83static int int340x_thermal_get_trip_type(struct thermal_zone_device *zone,
84 int trip,
85 enum thermal_trip_type *type)
86{
87 struct int34x_thermal_zone *d = zone->devdata;
88 int i;
89
90 if (d->override_ops && d->override_ops->get_trip_type)
91 return d->override_ops->get_trip_type(zone, trip, type);
92
93 if (trip < d->aux_trip_nr)
94 *type = THERMAL_TRIP_PASSIVE;
95 else if (trip == d->crt_trip_id)
96 *type = THERMAL_TRIP_CRITICAL;
97 else if (trip == d->hot_trip_id)
98 *type = THERMAL_TRIP_HOT;
99 else if (trip == d->psv_trip_id)
100 *type = THERMAL_TRIP_PASSIVE;
101 else {
102 for (i = 0; i < INT340X_THERMAL_MAX_ACT_TRIP_COUNT; i++) {
103 if (d->act_trips[i].valid &&
104 d->act_trips[i].id == trip) {
105 *type = THERMAL_TRIP_ACTIVE;
106 break;
107 }
108 }
109 if (i == INT340X_THERMAL_MAX_ACT_TRIP_COUNT)
110 return -EINVAL;
111 }
112
113 return 0;
114}
115
116static int int340x_thermal_set_trip_temp(struct thermal_zone_device *zone,
117 int trip, unsigned long temp)
118{
119 struct int34x_thermal_zone *d = zone->devdata;
120 acpi_status status;
121 char name[10];
122
123 if (d->override_ops && d->override_ops->set_trip_temp)
124 return d->override_ops->set_trip_temp(zone, trip, temp);
125
126 snprintf(name, sizeof(name), "PAT%d", trip);
127 status = acpi_execute_simple_method(d->adev->handle, name,
128 MILLICELSIUS_TO_DECI_KELVIN(temp));
129 if (ACPI_FAILURE(status))
130 return -EIO;
131
132 d->aux_trips[trip] = temp;
133
134 return 0;
135}
136
137
138static int int340x_thermal_get_trip_hyst(struct thermal_zone_device *zone,
139 int trip, unsigned long *temp)
140{
141 struct int34x_thermal_zone *d = zone->devdata;
142 acpi_status status;
143 unsigned long long hyst;
144
145 if (d->override_ops && d->override_ops->get_trip_hyst)
146 return d->override_ops->get_trip_hyst(zone, trip, temp);
147
148 status = acpi_evaluate_integer(d->adev->handle, "GTSH", NULL, &hyst);
149 if (ACPI_FAILURE(status))
150 return -EIO;
151
152 *temp = hyst * 100;
153
154 return 0;
155}
156
157static struct thermal_zone_device_ops int340x_thermal_zone_ops = {
158 .get_temp = int340x_thermal_get_zone_temp,
159 .get_trip_temp = int340x_thermal_get_trip_temp,
160 .get_trip_type = int340x_thermal_get_trip_type,
161 .set_trip_temp = int340x_thermal_set_trip_temp,
162 .get_trip_hyst = int340x_thermal_get_trip_hyst,
163};
164
165static int int340x_thermal_get_trip_config(acpi_handle handle, char *name,
166 unsigned long *temp)
167{
168 unsigned long long r;
169 acpi_status status;
170
171 status = acpi_evaluate_integer(handle, name, NULL, &r);
172 if (ACPI_FAILURE(status))
173 return -EIO;
174
175 *temp = DECI_KELVIN_TO_MILLICELSIUS(r);
176
177 return 0;
178}
179
180static struct thermal_zone_params int340x_thermal_params = {
181 .governor_name = "user_space",
182 .no_hwmon = true,
183};
184
185struct int34x_thermal_zone *int340x_thermal_zone_add(struct acpi_device *adev,
186 struct thermal_zone_device_ops *override_ops)
187{
188 struct int34x_thermal_zone *int34x_thermal_zone;
189 acpi_status status;
190 unsigned long long trip_cnt;
191 int trip_mask = 0, i;
192 int ret;
193
194 int34x_thermal_zone = kzalloc(sizeof(*int34x_thermal_zone),
195 GFP_KERNEL);
196 if (!int34x_thermal_zone)
197 return ERR_PTR(-ENOMEM);
198
199 int34x_thermal_zone->adev = adev;
200 int34x_thermal_zone->override_ops = override_ops;
201
202 status = acpi_evaluate_integer(adev->handle, "PATC", NULL, &trip_cnt);
203 if (ACPI_FAILURE(status))
204 trip_cnt = 0;
205 else {
206 int34x_thermal_zone->aux_trips = kzalloc(
207 sizeof(*int34x_thermal_zone->aux_trips) *
208 trip_cnt, GFP_KERNEL);
209 if (!int34x_thermal_zone->aux_trips) {
210 ret = -ENOMEM;
211 goto free_mem;
212 }
213 trip_mask = BIT(trip_cnt) - 1;
214 int34x_thermal_zone->aux_trip_nr = trip_cnt;
215 }
216
217 int34x_thermal_zone->crt_trip_id = -1;
218 if (!int340x_thermal_get_trip_config(adev->handle, "_CRT",
219 &int34x_thermal_zone->crt_temp))
220 int34x_thermal_zone->crt_trip_id = trip_cnt++;
221 int34x_thermal_zone->hot_trip_id = -1;
222 if (!int340x_thermal_get_trip_config(adev->handle, "_HOT",
223 &int34x_thermal_zone->hot_temp))
224 int34x_thermal_zone->hot_trip_id = trip_cnt++;
225 int34x_thermal_zone->psv_trip_id = -1;
226 if (!int340x_thermal_get_trip_config(adev->handle, "_PSV",
227 &int34x_thermal_zone->psv_temp))
228 int34x_thermal_zone->psv_trip_id = trip_cnt++;
229 for (i = 0; i < INT340X_THERMAL_MAX_ACT_TRIP_COUNT; i++) {
230 char name[5] = { '_', 'A', 'C', '0' + i, '\0' };
231
232 if (int340x_thermal_get_trip_config(adev->handle, name,
233 &int34x_thermal_zone->act_trips[i].temp))
234 break;
235
236 int34x_thermal_zone->act_trips[i].id = trip_cnt++;
237 int34x_thermal_zone->act_trips[i].valid = true;
238 }
239 int34x_thermal_zone->lpat_table = acpi_lpat_get_conversion_table(
240 adev->handle);
241
242 int34x_thermal_zone->zone = thermal_zone_device_register(
243 acpi_device_bid(adev),
244 trip_cnt,
245 trip_mask, int34x_thermal_zone,
246 &int340x_thermal_zone_ops,
247 &int340x_thermal_params,
248 0, 0);
249 if (IS_ERR(int34x_thermal_zone->zone)) {
250 ret = PTR_ERR(int34x_thermal_zone->zone);
251 goto free_lpat;
252 }
253
254 return int34x_thermal_zone;
255
256free_lpat:
257 acpi_lpat_free_conversion_table(int34x_thermal_zone->lpat_table);
258free_mem:
259 kfree(int34x_thermal_zone);
260 return ERR_PTR(ret);
261}
262EXPORT_SYMBOL_GPL(int340x_thermal_zone_add);
263
264void int340x_thermal_zone_remove(struct int34x_thermal_zone
265 *int34x_thermal_zone)
266{
267 thermal_zone_device_unregister(int34x_thermal_zone->zone);
268 acpi_lpat_free_conversion_table(int34x_thermal_zone->lpat_table);
269 kfree(int34x_thermal_zone);
270}
271EXPORT_SYMBOL_GPL(int340x_thermal_zone_remove);
272
273MODULE_AUTHOR("Aaron Lu <aaron.lu@intel.com>");
274MODULE_AUTHOR("Srinivas Pandruvada <srinivas.pandruvada@linux.intel.com>");
275MODULE_DESCRIPTION("Intel INT340x common thermal zone handler");
276MODULE_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 000000000000..9f38ab72c4bf
--- /dev/null
+++ b/drivers/thermal/int340x_thermal/int340x_thermal_zone.h
@@ -0,0 +1,68 @@
1/*
2 * int340x_thermal_zone.h
3 * Copyright (c) 2015, Intel Corporation.
4 *
5 * This program is free software; you can redistribute it and/or modify it
6 * under the terms and conditions of the GNU General Public License,
7 * version 2, as published by the Free Software Foundation.
8 *
9 * This program is distributed in the hope it will be useful, but WITHOUT
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
12 * more details.
13 *
14 */
15
16#ifndef __INT340X_THERMAL_ZONE_H__
17#define __INT340X_THERMAL_ZONE_H__
18
19#include <acpi/acpi_lpat.h>
20
21#define INT340X_THERMAL_MAX_ACT_TRIP_COUNT 10
22
23struct active_trip {
24 unsigned long temp;
25 int id;
26 bool valid;
27};
28
29struct int34x_thermal_zone {
30 struct acpi_device *adev;
31 struct active_trip act_trips[INT340X_THERMAL_MAX_ACT_TRIP_COUNT];
32 unsigned long *aux_trips;
33 int aux_trip_nr;
34 unsigned long psv_temp;
35 int psv_trip_id;
36 unsigned long crt_temp;
37 int crt_trip_id;
38 unsigned long hot_temp;
39 int hot_trip_id;
40 struct thermal_zone_device *zone;
41 struct thermal_zone_device_ops *override_ops;
42 void *priv_data;
43 struct acpi_lpat_conversion_table *lpat_table;
44};
45
46struct int34x_thermal_zone *int340x_thermal_zone_add(struct acpi_device *,
47 struct thermal_zone_device_ops *override_ops);
48void int340x_thermal_zone_remove(struct int34x_thermal_zone *);
49
50static inline void int340x_thermal_zone_set_priv_data(
51 struct int34x_thermal_zone *tzone, void *priv_data)
52{
53 tzone->priv_data = priv_data;
54}
55
56static inline void *int340x_thermal_zone_get_priv_data(
57 struct int34x_thermal_zone *tzone)
58{
59 return tzone->priv_data;
60}
61
62static inline void int340x_thermal_zone_device_update(
63 struct int34x_thermal_zone *tzone)
64{
65 thermal_zone_device_update(tzone->zone);
66}
67
68#endif
diff --git a/drivers/thermal/int340x_thermal/processor_thermal_device.c b/drivers/thermal/int340x_thermal/processor_thermal_device.c
index 0fe5dbbea968..5e8d8e91ea6d 100644
--- a/drivers/thermal/int340x_thermal/processor_thermal_device.c
+++ b/drivers/thermal/int340x_thermal/processor_thermal_device.c
@@ -18,6 +18,8 @@
18#include <linux/pci.h> 18#include <linux/pci.h>
19#include <linux/platform_device.h> 19#include <linux/platform_device.h>
20#include <linux/acpi.h> 20#include <linux/acpi.h>
21#include <linux/thermal.h>
22#include "int340x_thermal_zone.h"
21 23
22/* Broadwell-U/HSB thermal reporting device */ 24/* Broadwell-U/HSB thermal reporting device */
23#define PCI_DEVICE_ID_PROC_BDW_THERMAL 0x1603 25#define PCI_DEVICE_ID_PROC_BDW_THERMAL 0x1603
@@ -39,6 +41,7 @@ struct proc_thermal_device {
39 struct device *dev; 41 struct device *dev;
40 struct acpi_device *adev; 42 struct acpi_device *adev;
41 struct power_config power_limits[2]; 43 struct power_config power_limits[2];
44 struct int34x_thermal_zone *int340x_zone;
42}; 45};
43 46
44enum proc_thermal_emum_mode_type { 47enum proc_thermal_emum_mode_type {
@@ -117,6 +120,72 @@ static struct attribute_group power_limit_attribute_group = {
117 .name = "power_limits" 120 .name = "power_limits"
118}; 121};
119 122
123static int stored_tjmax; /* since it is fixed, we can have local storage */
124
125static int get_tjmax(void)
126{
127 u32 eax, edx;
128 u32 val;
129 int err;
130
131 err = rdmsr_safe(MSR_IA32_TEMPERATURE_TARGET, &eax, &edx);
132 if (err)
133 return err;
134
135 val = (eax >> 16) & 0xff;
136 if (val)
137 return val;
138
139 return -EINVAL;
140}
141
142static int read_temp_msr(unsigned long *temp)
143{
144 int cpu;
145 u32 eax, edx;
146 int err;
147 unsigned long curr_temp_off = 0;
148
149 *temp = 0;
150
151 for_each_online_cpu(cpu) {
152 err = rdmsr_safe_on_cpu(cpu, MSR_IA32_THERM_STATUS, &eax,
153 &edx);
154 if (err)
155 goto err_ret;
156 else {
157 if (eax & 0x80000000) {
158 curr_temp_off = (eax >> 16) & 0x7f;
159 if (!*temp || curr_temp_off < *temp)
160 *temp = curr_temp_off;
161 } else {
162 err = -EINVAL;
163 goto err_ret;
164 }
165 }
166 }
167
168 return 0;
169err_ret:
170 return err;
171}
172
173static int proc_thermal_get_zone_temp(struct thermal_zone_device *zone,
174 unsigned long *temp)
175{
176 int ret;
177
178 ret = read_temp_msr(temp);
179 if (!ret)
180 *temp = (stored_tjmax - *temp) * 1000;
181
182 return ret;
183}
184
185static struct thermal_zone_device_ops proc_thermal_local_ops = {
186 .get_temp = proc_thermal_get_zone_temp,
187};
188
120static int proc_thermal_add(struct device *dev, 189static int proc_thermal_add(struct device *dev,
121 struct proc_thermal_device **priv) 190 struct proc_thermal_device **priv)
122{ 191{
@@ -126,6 +195,8 @@ static int proc_thermal_add(struct device *dev,
126 struct acpi_buffer buf = { ACPI_ALLOCATE_BUFFER, NULL }; 195 struct acpi_buffer buf = { ACPI_ALLOCATE_BUFFER, NULL };
127 union acpi_object *elements, *ppcc; 196 union acpi_object *elements, *ppcc;
128 union acpi_object *p; 197 union acpi_object *p;
198 unsigned long long tmp;
199 struct thermal_zone_device_ops *ops = NULL;
129 int i; 200 int i;
130 int ret; 201 int ret;
131 202
@@ -178,6 +249,24 @@ static int proc_thermal_add(struct device *dev,
178 249
179 ret = sysfs_create_group(&dev->kobj, 250 ret = sysfs_create_group(&dev->kobj,
180 &power_limit_attribute_group); 251 &power_limit_attribute_group);
252 if (ret)
253 goto free_buffer;
254
255 status = acpi_evaluate_integer(adev->handle, "_TMP", NULL, &tmp);
256 if (ACPI_FAILURE(status)) {
257 /* there is no _TMP method, add local method */
258 stored_tjmax = get_tjmax();
259 if (stored_tjmax > 0)
260 ops = &proc_thermal_local_ops;
261 }
262
263 proc_priv->int340x_zone = int340x_thermal_zone_add(adev, ops);
264 if (IS_ERR(proc_priv->int340x_zone)) {
265 sysfs_remove_group(&proc_priv->dev->kobj,
266 &power_limit_attribute_group);
267 ret = PTR_ERR(proc_priv->int340x_zone);
268 } else
269 ret = 0;
181 270
182free_buffer: 271free_buffer:
183 kfree(buf.pointer); 272 kfree(buf.pointer);
@@ -185,8 +274,9 @@ free_buffer:
185 return ret; 274 return ret;
186} 275}
187 276
188void proc_thermal_remove(struct proc_thermal_device *proc_priv) 277static void proc_thermal_remove(struct proc_thermal_device *proc_priv)
189{ 278{
279 int340x_thermal_zone_remove(proc_priv->int340x_zone);
190 sysfs_remove_group(&proc_priv->dev->kobj, 280 sysfs_remove_group(&proc_priv->dev->kobj,
191 &power_limit_attribute_group); 281 &power_limit_attribute_group);
192} 282}
diff --git a/drivers/thermal/intel_soc_dts_thermal.c b/drivers/thermal/intel_soc_dts_thermal.c
index 5580f5b24eb9..9013505e43b7 100644
--- a/drivers/thermal/intel_soc_dts_thermal.c
+++ b/drivers/thermal/intel_soc_dts_thermal.c
@@ -309,10 +309,13 @@ static int soc_dts_enable(int id)
309 return ret; 309 return ret;
310} 310}
311 311
312static struct soc_sensor_entry *alloc_soc_dts(int id, u32 tj_max) 312static struct soc_sensor_entry *alloc_soc_dts(int id, u32 tj_max,
313 bool notification_support)
313{ 314{
314 struct soc_sensor_entry *aux_entry; 315 struct soc_sensor_entry *aux_entry;
315 char name[10]; 316 char name[10];
317 int trip_count = 0;
318 int trip_mask = 0;
316 int err; 319 int err;
317 320
318 aux_entry = kzalloc(sizeof(*aux_entry), GFP_KERNEL); 321 aux_entry = kzalloc(sizeof(*aux_entry), GFP_KERNEL);
@@ -332,11 +335,16 @@ static struct soc_sensor_entry *alloc_soc_dts(int id, u32 tj_max)
332 aux_entry->tj_max = tj_max; 335 aux_entry->tj_max = tj_max;
333 aux_entry->temp_mask = 0x00FF << (id * 8); 336 aux_entry->temp_mask = 0x00FF << (id * 8);
334 aux_entry->temp_shift = id * 8; 337 aux_entry->temp_shift = id * 8;
338 if (notification_support) {
339 trip_count = SOC_MAX_DTS_TRIPS;
340 trip_mask = 0x02;
341 }
335 snprintf(name, sizeof(name), "soc_dts%d", id); 342 snprintf(name, sizeof(name), "soc_dts%d", id);
336 aux_entry->tzone = thermal_zone_device_register(name, 343 aux_entry->tzone = thermal_zone_device_register(name,
337 SOC_MAX_DTS_TRIPS, 344 trip_count,
338 0x02, 345 trip_mask,
339 aux_entry, &tzone_ops, NULL, 0, 0); 346 aux_entry, &tzone_ops,
347 NULL, 0, 0);
340 if (IS_ERR(aux_entry->tzone)) { 348 if (IS_ERR(aux_entry->tzone)) {
341 err = PTR_ERR(aux_entry->tzone); 349 err = PTR_ERR(aux_entry->tzone);
342 goto err_ret; 350 goto err_ret;
@@ -402,6 +410,7 @@ static irqreturn_t soc_irq_thread_fn(int irq, void *dev_data)
402 410
403static const struct x86_cpu_id soc_thermal_ids[] = { 411static const struct x86_cpu_id soc_thermal_ids[] = {
404 { X86_VENDOR_INTEL, X86_FAMILY_ANY, 0x37, 0, BYT_SOC_DTS_APIC_IRQ}, 412 { X86_VENDOR_INTEL, X86_FAMILY_ANY, 0x37, 0, BYT_SOC_DTS_APIC_IRQ},
413 { X86_VENDOR_INTEL, X86_FAMILY_ANY, 0x4c, 0, 0},
405 {} 414 {}
406}; 415};
407MODULE_DEVICE_TABLE(x86cpu, soc_thermal_ids); 416MODULE_DEVICE_TABLE(x86cpu, soc_thermal_ids);
@@ -420,8 +429,11 @@ static int __init intel_soc_thermal_init(void)
420 if (get_tj_max(&tj_max)) 429 if (get_tj_max(&tj_max))
421 return -EINVAL; 430 return -EINVAL;
422 431
432 soc_dts_thres_irq = (int)match_cpu->driver_data;
433
423 for (i = 0; i < SOC_MAX_DTS_SENSORS; ++i) { 434 for (i = 0; i < SOC_MAX_DTS_SENSORS; ++i) {
424 soc_dts[i] = alloc_soc_dts(i, tj_max); 435 soc_dts[i] = alloc_soc_dts(i, tj_max,
436 soc_dts_thres_irq ? true : false);
425 if (IS_ERR(soc_dts[i])) { 437 if (IS_ERR(soc_dts[i])) {
426 err = PTR_ERR(soc_dts[i]); 438 err = PTR_ERR(soc_dts[i]);
427 goto err_free; 439 goto err_free;
@@ -430,15 +442,15 @@ static int __init intel_soc_thermal_init(void)
430 442
431 spin_lock_init(&intr_notify_lock); 443 spin_lock_init(&intr_notify_lock);
432 444
433 soc_dts_thres_irq = (int)match_cpu->driver_data; 445 if (soc_dts_thres_irq) {
434 446 err = request_threaded_irq(soc_dts_thres_irq, NULL,
435 err = request_threaded_irq(soc_dts_thres_irq, NULL, 447 soc_irq_thread_fn,
436 soc_irq_thread_fn, 448 IRQF_TRIGGER_RISING | IRQF_ONESHOT,
437 IRQF_TRIGGER_RISING | IRQF_ONESHOT, 449 "soc_dts", soc_dts);
438 "soc_dts", soc_dts); 450 if (err) {
439 if (err) { 451 pr_err("request_threaded_irq ret %d\n", err);
440 pr_err("request_threaded_irq ret %d\n", err); 452 goto err_free;
441 goto err_free; 453 }
442 } 454 }
443 455
444 for (i = 0; i < SOC_MAX_DTS_SENSORS; ++i) { 456 for (i = 0; i < SOC_MAX_DTS_SENSORS; ++i) {
@@ -451,7 +463,8 @@ static int __init intel_soc_thermal_init(void)
451 463
452err_trip_temp: 464err_trip_temp:
453 i = SOC_MAX_DTS_SENSORS; 465 i = SOC_MAX_DTS_SENSORS;
454 free_irq(soc_dts_thres_irq, soc_dts); 466 if (soc_dts_thres_irq)
467 free_irq(soc_dts_thres_irq, soc_dts);
455err_free: 468err_free:
456 while (--i >= 0) 469 while (--i >= 0)
457 free_soc_dts(soc_dts[i]); 470 free_soc_dts(soc_dts[i]);
@@ -466,7 +479,8 @@ static void __exit intel_soc_thermal_exit(void)
466 for (i = 0; i < SOC_MAX_DTS_SENSORS; ++i) 479 for (i = 0; i < SOC_MAX_DTS_SENSORS; ++i)
467 update_trip_temp(soc_dts[i], 0, 0); 480 update_trip_temp(soc_dts[i], 0, 0);
468 481
469 free_irq(soc_dts_thres_irq, soc_dts); 482 if (soc_dts_thres_irq)
483 free_irq(soc_dts_thres_irq, soc_dts);
470 484
471 for (i = 0; i < SOC_MAX_DTS_SENSORS; ++i) 485 for (i = 0; i < SOC_MAX_DTS_SENSORS; ++i)
472 free_soc_dts(soc_dts[i]); 486 free_soc_dts(soc_dts[i]);
diff --git a/drivers/thermal/step_wise.c b/drivers/thermal/step_wise.c
index fdd1f523a1ed..5a0f12d08e8b 100644
--- a/drivers/thermal/step_wise.c
+++ b/drivers/thermal/step_wise.c
@@ -45,7 +45,7 @@
45 * c. if the trend is THERMAL_TREND_RAISE_FULL, do nothing 45 * c. if the trend is THERMAL_TREND_RAISE_FULL, do nothing
46 * d. if the trend is THERMAL_TREND_DROP_FULL, use lower limit, 46 * d. if the trend is THERMAL_TREND_DROP_FULL, use lower limit,
47 * if the cooling state already equals lower limit, 47 * if the cooling state already equals lower limit,
48 * deactive the thermal instance 48 * deactivate the thermal instance
49 */ 49 */
50static unsigned long get_target_state(struct thermal_instance *instance, 50static unsigned long get_target_state(struct thermal_instance *instance,
51 enum thermal_trend trend, bool throttle) 51 enum thermal_trend trend, bool throttle)
@@ -169,7 +169,7 @@ static void thermal_zone_trip_update(struct thermal_zone_device *tz, int trip)
169} 169}
170 170
171/** 171/**
172 * step_wise_throttle - throttles devices asscciated with the given zone 172 * step_wise_throttle - throttles devices associated with the given zone
173 * @tz - thermal_zone_device 173 * @tz - thermal_zone_device
174 * @trip - the trip point 174 * @trip - the trip point
175 * @trip_type - type of the trip point 175 * @trip_type - type of the trip point
diff --git a/include/acpi/acpi_lpat.h b/include/acpi/acpi_lpat.h
new file mode 100644
index 000000000000..da37e12d23e2
--- /dev/null
+++ b/include/acpi/acpi_lpat.h
@@ -0,0 +1,65 @@
1/*
2 * acpi_lpat.h - LPAT table processing functions
3 *
4 * Copyright (C) 2015 Intel Corporation. All rights reserved.
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License version
8 * 2 as published by the Free Software Foundation.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 */
15
16#ifndef ACPI_LPAT_H
17#define ACPI_LPAT_H
18
19struct acpi_lpat {
20 int temp;
21 int raw;
22};
23
24struct acpi_lpat_conversion_table {
25 struct acpi_lpat *lpat;
26 int lpat_count;
27};
28
29#ifdef CONFIG_ACPI
30
31int acpi_lpat_raw_to_temp(struct acpi_lpat_conversion_table *lpat_table,
32 int raw);
33int acpi_lpat_temp_to_raw(struct acpi_lpat_conversion_table *lpat_table,
34 int temp);
35struct acpi_lpat_conversion_table *acpi_lpat_get_conversion_table(acpi_handle
36 handle);
37void acpi_lpat_free_conversion_table(struct acpi_lpat_conversion_table
38 *lpat_table);
39
40#else
41static int acpi_lpat_raw_to_temp(struct acpi_lpat_conversion_table *lpat_table,
42 int raw)
43{
44 return 0;
45}
46
47static int acpi_lpat_temp_to_raw(struct acpi_lpat_conversion_table *lpat_table,
48 int temp)
49{
50 return 0;
51}
52
53static struct acpi_lpat_conversion_table *acpi_lpat_get_conversion_table(
54 acpi_handle handle)
55{
56 return NULL;
57}
58
59static void acpi_lpat_free_conversion_table(struct acpi_lpat_conversion_table
60 *lpat_table)
61{
62}
63
64#endif
65#endif