diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2015-02-19 14:28:36 -0500 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2015-02-19 14:28:36 -0500 |
commit | 89d3fa45b4add00cd0056361a2498e978cb1e119 (patch) | |
tree | b717ab79c3258c3838d7d0753c5aeae61984e17c | |
parent | 477ea1169667a88d8ee12d83a0b0863091fb8670 (diff) | |
parent | 31908f45a583e8f21db37f402b6e8d5739945afd (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/Makefile | 1 | ||||
-rw-r--r-- | drivers/acpi/acpi_lpat.c | 161 | ||||
-rw-r--r-- | drivers/acpi/pmic/intel_pmic.c | 133 | ||||
-rw-r--r-- | drivers/thermal/int340x_thermal/Makefile | 1 | ||||
-rw-r--r-- | drivers/thermal/int340x_thermal/int3400_thermal.c | 4 | ||||
-rw-r--r-- | drivers/thermal/int340x_thermal/int3402_thermal.c | 208 | ||||
-rw-r--r-- | drivers/thermal/int340x_thermal/int3403_thermal.c | 208 | ||||
-rw-r--r-- | drivers/thermal/int340x_thermal/int340x_thermal_zone.c | 276 | ||||
-rw-r--r-- | drivers/thermal/int340x_thermal/int340x_thermal_zone.h | 68 | ||||
-rw-r--r-- | drivers/thermal/int340x_thermal/processor_thermal_device.c | 92 | ||||
-rw-r--r-- | drivers/thermal/intel_soc_dts_thermal.c | 46 | ||||
-rw-r--r-- | drivers/thermal/step_wise.c | 4 | ||||
-rw-r--r-- | include/acpi/acpi_lpat.h | 65 |
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 | |||
55 | ifdef CONFIG_ACPI_VIDEO | 55 | ifdef CONFIG_ACPI_VIDEO |
56 | acpi-y += video_detect.o | 56 | acpi-y += video_detect.o |
57 | endif | 57 | endif |
58 | acpi-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 | */ | ||
31 | int 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 | } | ||
52 | EXPORT_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 | */ | ||
65 | int 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 | } | ||
85 | EXPORT_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 | */ | ||
97 | struct 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 | |||
137 | out: | ||
138 | kfree(buffer.pointer); | ||
139 | return lpat_table; | ||
140 | } | ||
141 | EXPORT_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 | */ | ||
151 | void 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 | } | ||
159 | EXPORT_SYMBOL_GPL(acpi_lpat_free_conversion_table); | ||
160 | |||
161 | MODULE_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 | ||
24 | struct acpi_lpat { | ||
25 | int temp; | ||
26 | int raw; | ||
27 | }; | ||
28 | |||
29 | struct intel_pmic_opregion { | 25 | struct 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 | */ | ||
64 | static 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 | */ | ||
95 | static 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 | |||
114 | static 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 | |||
148 | out: | ||
149 | kfree(buffer.pointer); | ||
150 | } | ||
151 | |||
152 | static acpi_status intel_pmic_power_handler(u32 function, | 48 | static 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 | |||
251 | out_error: | ||
252 | acpi_lpat_free_conversion_table(opregion->lpat_table); | ||
253 | return ret; | ||
351 | } | 254 | } |
352 | EXPORT_SYMBOL_GPL(intel_pmic_install_opregion_handler); | 255 | EXPORT_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 @@ | |||
1 | obj-$(CONFIG_INT340X_THERMAL) += int3400_thermal.o | 1 | obj-$(CONFIG_INT340X_THERMAL) += int3400_thermal.o |
2 | obj-$(CONFIG_INT340X_THERMAL) += int340x_thermal_zone.o | ||
2 | obj-$(CONFIG_INT340X_THERMAL) += int3402_thermal.o | 3 | obj-$(CONFIG_INT340X_THERMAL) += int3402_thermal.o |
3 | obj-$(CONFIG_INT340X_THERMAL) += int3403_thermal.o | 4 | obj-$(CONFIG_INT340X_THERMAL) += int3403_thermal.o |
4 | obj-$(CONFIG_INT340X_THERMAL) += processor_thermal_device.o | 5 | obj-$(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 | ||
19 | enum int3400_thermal_uuid { | 19 | enum 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 | ||
28 | static u8 *int3400_thermal_uuids[INT3400_THERMAL_MAXIMUM_UUID] = { | 26 | static 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 | ||
36 | struct int3400_thermal_priv { | 32 | struct 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 | |
20 | struct active_trip { | ||
21 | unsigned long temp; | ||
22 | int id; | ||
23 | bool valid; | ||
24 | }; | ||
25 | 21 | ||
26 | struct int3402_thermal_data { | 22 | struct 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 | ||
39 | static int int3402_thermal_get_zone_temp(struct thermal_zone_device *zone, | 27 | static 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 | |||
56 | static 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 | |||
84 | static 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 | |||
112 | static 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 | |||
129 | static 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 | |||
136 | static struct thermal_zone_params int3402_thermal_params = { | ||
137 | .governor_name = "user_space", | ||
138 | .no_hwmon = true, | ||
139 | }; | ||
140 | |||
141 | static 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 | ||
155 | static int int3402_thermal_probe(struct platform_device *pdev) | 45 | static 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 | ||
214 | static int int3402_thermal_remove(struct platform_device *pdev) | 77 | static 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 | |||
33 | struct int3403_sensor { | 31 | struct 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 | ||
43 | struct int3403_performance_state { | 35 | struct int3403_performance_state { |
@@ -63,126 +55,6 @@ struct int3403_priv { | |||
63 | void *priv; | 55 | void *priv; |
64 | }; | 56 | }; |
65 | 57 | ||
66 | static 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 | |||
83 | static 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 | |||
106 | static 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 | |||
131 | static 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 | |||
146 | int 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 | |||
173 | static 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 | |||
181 | static struct thermal_zone_params int3403_thermal_params = { | ||
182 | .governor_name = "user_space", | ||
183 | .no_hwmon = true, | ||
184 | }; | ||
185 | |||
186 | static void int3403_notify(acpi_handle handle, | 58 | static 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 | ||
211 | static 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 | |||
225 | static 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 | |||
239 | static int int3403_sensor_add(struct int3403_priv *priv) | 83 | static 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 | |||
22 | static 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 | |||
51 | static 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 | |||
83 | static 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 | |||
116 | static 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 | |||
138 | static 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 | |||
157 | static 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 | |||
165 | static 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 | |||
180 | static struct thermal_zone_params int340x_thermal_params = { | ||
181 | .governor_name = "user_space", | ||
182 | .no_hwmon = true, | ||
183 | }; | ||
184 | |||
185 | struct 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 | |||
256 | free_lpat: | ||
257 | acpi_lpat_free_conversion_table(int34x_thermal_zone->lpat_table); | ||
258 | free_mem: | ||
259 | kfree(int34x_thermal_zone); | ||
260 | return ERR_PTR(ret); | ||
261 | } | ||
262 | EXPORT_SYMBOL_GPL(int340x_thermal_zone_add); | ||
263 | |||
264 | void 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 | } | ||
271 | EXPORT_SYMBOL_GPL(int340x_thermal_zone_remove); | ||
272 | |||
273 | MODULE_AUTHOR("Aaron Lu <aaron.lu@intel.com>"); | ||
274 | MODULE_AUTHOR("Srinivas Pandruvada <srinivas.pandruvada@linux.intel.com>"); | ||
275 | MODULE_DESCRIPTION("Intel INT340x common thermal zone handler"); | ||
276 | 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 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 | |||
23 | struct active_trip { | ||
24 | unsigned long temp; | ||
25 | int id; | ||
26 | bool valid; | ||
27 | }; | ||
28 | |||
29 | struct 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 | |||
46 | struct int34x_thermal_zone *int340x_thermal_zone_add(struct acpi_device *, | ||
47 | struct thermal_zone_device_ops *override_ops); | ||
48 | void int340x_thermal_zone_remove(struct int34x_thermal_zone *); | ||
49 | |||
50 | static 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 | |||
56 | static inline void *int340x_thermal_zone_get_priv_data( | ||
57 | struct int34x_thermal_zone *tzone) | ||
58 | { | ||
59 | return tzone->priv_data; | ||
60 | } | ||
61 | |||
62 | static 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 | ||
44 | enum proc_thermal_emum_mode_type { | 47 | enum 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 | ||
123 | static int stored_tjmax; /* since it is fixed, we can have local storage */ | ||
124 | |||
125 | static 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 | |||
142 | static 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; | ||
169 | err_ret: | ||
170 | return err; | ||
171 | } | ||
172 | |||
173 | static 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 | |||
185 | static struct thermal_zone_device_ops proc_thermal_local_ops = { | ||
186 | .get_temp = proc_thermal_get_zone_temp, | ||
187 | }; | ||
188 | |||
120 | static int proc_thermal_add(struct device *dev, | 189 | static 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 | ||
182 | free_buffer: | 271 | free_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 | ||
188 | void proc_thermal_remove(struct proc_thermal_device *proc_priv) | 277 | static 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 | ||
312 | static struct soc_sensor_entry *alloc_soc_dts(int id, u32 tj_max) | 312 | static 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 | ||
403 | static const struct x86_cpu_id soc_thermal_ids[] = { | 411 | static 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 | }; |
407 | MODULE_DEVICE_TABLE(x86cpu, soc_thermal_ids); | 416 | MODULE_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 | ||
452 | err_trip_temp: | 464 | err_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); | ||
455 | err_free: | 468 | err_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 | */ |
50 | static unsigned long get_target_state(struct thermal_instance *instance, | 50 | static 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 | |||
19 | struct acpi_lpat { | ||
20 | int temp; | ||
21 | int raw; | ||
22 | }; | ||
23 | |||
24 | struct acpi_lpat_conversion_table { | ||
25 | struct acpi_lpat *lpat; | ||
26 | int lpat_count; | ||
27 | }; | ||
28 | |||
29 | #ifdef CONFIG_ACPI | ||
30 | |||
31 | int acpi_lpat_raw_to_temp(struct acpi_lpat_conversion_table *lpat_table, | ||
32 | int raw); | ||
33 | int acpi_lpat_temp_to_raw(struct acpi_lpat_conversion_table *lpat_table, | ||
34 | int temp); | ||
35 | struct acpi_lpat_conversion_table *acpi_lpat_get_conversion_table(acpi_handle | ||
36 | handle); | ||
37 | void acpi_lpat_free_conversion_table(struct acpi_lpat_conversion_table | ||
38 | *lpat_table); | ||
39 | |||
40 | #else | ||
41 | static int acpi_lpat_raw_to_temp(struct acpi_lpat_conversion_table *lpat_table, | ||
42 | int raw) | ||
43 | { | ||
44 | return 0; | ||
45 | } | ||
46 | |||
47 | static int acpi_lpat_temp_to_raw(struct acpi_lpat_conversion_table *lpat_table, | ||
48 | int temp) | ||
49 | { | ||
50 | return 0; | ||
51 | } | ||
52 | |||
53 | static struct acpi_lpat_conversion_table *acpi_lpat_get_conversion_table( | ||
54 | acpi_handle handle) | ||
55 | { | ||
56 | return NULL; | ||
57 | } | ||
58 | |||
59 | static void acpi_lpat_free_conversion_table(struct acpi_lpat_conversion_table | ||
60 | *lpat_table) | ||
61 | { | ||
62 | } | ||
63 | |||
64 | #endif | ||
65 | #endif | ||