aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Documentation/devicetree/bindings/thermal/imx-thermal.txt5
-rw-r--r--drivers/acpi/Kconfig2
-rw-r--r--drivers/acpi/Makefile1
-rw-r--r--drivers/acpi/acpi_platform.c1
-rw-r--r--drivers/acpi/device_pm.c1
-rw-r--r--drivers/acpi/fan.c338
-rw-r--r--drivers/acpi/int340x_thermal.c51
-rw-r--r--drivers/acpi/internal.h10
-rw-r--r--drivers/acpi/scan.c1
-rw-r--r--drivers/acpi/thermal.c18
-rw-r--r--drivers/acpi/utils.c28
-rw-r--r--drivers/thermal/Kconfig49
-rw-r--r--drivers/thermal/Makefile3
-rw-r--r--drivers/thermal/fair_share.c12
-rw-r--r--drivers/thermal/gov_bang_bang.c131
-rw-r--r--drivers/thermal/imx_thermal.c91
-rw-r--r--drivers/thermal/int3403_thermal.c296
-rw-r--r--drivers/thermal/int340x_thermal/Makefile4
-rw-r--r--drivers/thermal/int340x_thermal/acpi_thermal_rel.c400
-rw-r--r--drivers/thermal/int340x_thermal/acpi_thermal_rel.h84
-rw-r--r--drivers/thermal/int340x_thermal/int3400_thermal.c271
-rw-r--r--drivers/thermal/int340x_thermal/int3402_thermal.c242
-rw-r--r--drivers/thermal/int340x_thermal/int3403_thermal.c477
-rw-r--r--drivers/thermal/of-thermal.c12
-rw-r--r--drivers/thermal/step_wise.c7
-rw-r--r--drivers/thermal/thermal_core.c12
-rw-r--r--drivers/thermal/thermal_core.h8
-rw-r--r--include/acpi/acpi_bus.h1
-rw-r--r--include/linux/acpi.h1
-rw-r--r--include/linux/thermal.h4
-rw-r--r--include/trace/events/thermal.h83
31 files changed, 2222 insertions, 422 deletions
diff --git a/Documentation/devicetree/bindings/thermal/imx-thermal.txt b/Documentation/devicetree/bindings/thermal/imx-thermal.txt
index 1f0f67234a91..3c67bd50aa10 100644
--- a/Documentation/devicetree/bindings/thermal/imx-thermal.txt
+++ b/Documentation/devicetree/bindings/thermal/imx-thermal.txt
@@ -1,7 +1,10 @@
1* Temperature Monitor (TEMPMON) on Freescale i.MX SoCs 1* Temperature Monitor (TEMPMON) on Freescale i.MX SoCs
2 2
3Required properties: 3Required properties:
4- compatible : "fsl,imx6q-thermal" 4- compatible : "fsl,imx6q-tempmon" for i.MX6Q, "fsl,imx6sx-tempmon" for i.MX6SX.
5 i.MX6SX has two more IRQs than i.MX6Q, one is IRQ_LOW and the other is IRQ_PANIC,
6 when temperature is below than low threshold, IRQ_LOW will be triggered, when temperature
7 is higher than panic threshold, system will auto reboot by SRC module.
5- fsl,tempmon : phandle pointer to system controller that contains TEMPMON 8- fsl,tempmon : phandle pointer to system controller that contains TEMPMON
6 control registers, e.g. ANATOP on imx6q. 9 control registers, e.g. ANATOP on imx6q.
7- fsl,tempmon-data : phandle pointer to fuse controller that contains TEMPMON 10- fsl,tempmon-data : phandle pointer to fuse controller that contains TEMPMON
diff --git a/drivers/acpi/Kconfig b/drivers/acpi/Kconfig
index d0f3265fb85d..b23fe37f67c0 100644
--- a/drivers/acpi/Kconfig
+++ b/drivers/acpi/Kconfig
@@ -144,7 +144,7 @@ config ACPI_VIDEO
144 144
145config ACPI_FAN 145config ACPI_FAN
146 tristate "Fan" 146 tristate "Fan"
147 select THERMAL 147 depends on THERMAL
148 default y 148 default y
149 help 149 help
150 This driver supports ACPI fan devices, allowing user-mode 150 This driver supports ACPI fan devices, allowing user-mode
diff --git a/drivers/acpi/Makefile b/drivers/acpi/Makefile
index 505d4d79fe3e..c3b2fcb729f3 100644
--- a/drivers/acpi/Makefile
+++ b/drivers/acpi/Makefile
@@ -43,6 +43,7 @@ acpi-y += pci_root.o pci_link.o pci_irq.o
43acpi-y += acpi_lpss.o 43acpi-y += acpi_lpss.o
44acpi-y += acpi_platform.o 44acpi-y += acpi_platform.o
45acpi-y += acpi_pnp.o 45acpi-y += acpi_pnp.o
46acpi-y += int340x_thermal.o
46acpi-y += power.o 47acpi-y += power.o
47acpi-y += event.o 48acpi-y += event.o
48acpi-y += sysfs.o 49acpi-y += sysfs.o
diff --git a/drivers/acpi/acpi_platform.c b/drivers/acpi/acpi_platform.c
index 2bf9082f7523..a3c89a1bcf54 100644
--- a/drivers/acpi/acpi_platform.c
+++ b/drivers/acpi/acpi_platform.c
@@ -113,3 +113,4 @@ struct platform_device *acpi_create_platform_device(struct acpi_device *adev)
113 kfree(resources); 113 kfree(resources);
114 return pdev; 114 return pdev;
115} 115}
116EXPORT_SYMBOL_GPL(acpi_create_platform_device);
diff --git a/drivers/acpi/device_pm.c b/drivers/acpi/device_pm.c
index bea6896be122..7103de034c9e 100644
--- a/drivers/acpi/device_pm.c
+++ b/drivers/acpi/device_pm.c
@@ -343,6 +343,7 @@ int acpi_device_update_power(struct acpi_device *device, int *state_p)
343 343
344 return 0; 344 return 0;
345} 345}
346EXPORT_SYMBOL_GPL(acpi_device_update_power);
346 347
347int acpi_bus_update_power(acpi_handle handle, int *state_p) 348int acpi_bus_update_power(acpi_handle handle, int *state_p)
348{ 349{
diff --git a/drivers/acpi/fan.c b/drivers/acpi/fan.c
index 5328b1090e08..caf9b76b7ef8 100644
--- a/drivers/acpi/fan.c
+++ b/drivers/acpi/fan.c
@@ -30,22 +30,19 @@
30#include <linux/uaccess.h> 30#include <linux/uaccess.h>
31#include <linux/thermal.h> 31#include <linux/thermal.h>
32#include <linux/acpi.h> 32#include <linux/acpi.h>
33 33#include <linux/platform_device.h>
34#define ACPI_FAN_CLASS "fan" 34#include <linux/sort.h>
35#define ACPI_FAN_FILE_STATE "state"
36
37#define _COMPONENT ACPI_FAN_COMPONENT
38ACPI_MODULE_NAME("fan");
39 35
40MODULE_AUTHOR("Paul Diefenbaugh"); 36MODULE_AUTHOR("Paul Diefenbaugh");
41MODULE_DESCRIPTION("ACPI Fan Driver"); 37MODULE_DESCRIPTION("ACPI Fan Driver");
42MODULE_LICENSE("GPL"); 38MODULE_LICENSE("GPL");
43 39
44static int acpi_fan_add(struct acpi_device *device); 40static int acpi_fan_probe(struct platform_device *pdev);
45static int acpi_fan_remove(struct acpi_device *device); 41static int acpi_fan_remove(struct platform_device *pdev);
46 42
47static const struct acpi_device_id fan_device_ids[] = { 43static const struct acpi_device_id fan_device_ids[] = {
48 {"PNP0C0B", 0}, 44 {"PNP0C0B", 0},
45 {"INT3404", 0},
49 {"", 0}, 46 {"", 0},
50}; 47};
51MODULE_DEVICE_TABLE(acpi, fan_device_ids); 48MODULE_DEVICE_TABLE(acpi, fan_device_ids);
@@ -64,37 +61,100 @@ static struct dev_pm_ops acpi_fan_pm = {
64#define FAN_PM_OPS_PTR NULL 61#define FAN_PM_OPS_PTR NULL
65#endif 62#endif
66 63
67static struct acpi_driver acpi_fan_driver = { 64struct acpi_fan_fps {
68 .name = "fan", 65 u64 control;
69 .class = ACPI_FAN_CLASS, 66 u64 trip_point;
70 .ids = fan_device_ids, 67 u64 speed;
71 .ops = { 68 u64 noise_level;
72 .add = acpi_fan_add, 69 u64 power;
73 .remove = acpi_fan_remove, 70};
74 }, 71
75 .drv.pm = FAN_PM_OPS_PTR, 72struct acpi_fan_fif {
73 u64 revision;
74 u64 fine_grain_ctrl;
75 u64 step_size;
76 u64 low_speed_notification;
77};
78
79struct acpi_fan {
80 bool acpi4;
81 struct acpi_fan_fif fif;
82 struct acpi_fan_fps *fps;
83 int fps_count;
84 struct thermal_cooling_device *cdev;
85};
86
87static struct platform_driver acpi_fan_driver = {
88 .probe = acpi_fan_probe,
89 .remove = acpi_fan_remove,
90 .driver = {
91 .name = "acpi-fan",
92 .acpi_match_table = fan_device_ids,
93 .pm = FAN_PM_OPS_PTR,
94 },
76}; 95};
77 96
78/* thermal cooling device callbacks */ 97/* thermal cooling device callbacks */
79static int fan_get_max_state(struct thermal_cooling_device *cdev, unsigned long 98static int fan_get_max_state(struct thermal_cooling_device *cdev, unsigned long
80 *state) 99 *state)
81{ 100{
82 /* ACPI fan device only support two states: ON/OFF */ 101 struct acpi_device *device = cdev->devdata;
83 *state = 1; 102 struct acpi_fan *fan = acpi_driver_data(device);
103
104 if (fan->acpi4)
105 *state = fan->fps_count - 1;
106 else
107 *state = 1;
84 return 0; 108 return 0;
85} 109}
86 110
87static int fan_get_cur_state(struct thermal_cooling_device *cdev, unsigned long 111static int fan_get_state_acpi4(struct acpi_device *device, unsigned long *state)
88 *state) 112{
113 struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
114 struct acpi_fan *fan = acpi_driver_data(device);
115 union acpi_object *obj;
116 acpi_status status;
117 int control, i;
118
119 status = acpi_evaluate_object(device->handle, "_FST", NULL, &buffer);
120 if (ACPI_FAILURE(status)) {
121 dev_err(&device->dev, "Get fan state failed\n");
122 return status;
123 }
124
125 obj = buffer.pointer;
126 if (!obj || obj->type != ACPI_TYPE_PACKAGE ||
127 obj->package.count != 3 ||
128 obj->package.elements[1].type != ACPI_TYPE_INTEGER) {
129 dev_err(&device->dev, "Invalid _FST data\n");
130 status = -EINVAL;
131 goto err;
132 }
133
134 control = obj->package.elements[1].integer.value;
135 for (i = 0; i < fan->fps_count; i++) {
136 if (control == fan->fps[i].control)
137 break;
138 }
139 if (i == fan->fps_count) {
140 dev_dbg(&device->dev, "Invalid control value returned\n");
141 status = -EINVAL;
142 goto err;
143 }
144
145 *state = i;
146
147err:
148 kfree(obj);
149 return status;
150}
151
152static int fan_get_state(struct acpi_device *device, unsigned long *state)
89{ 153{
90 struct acpi_device *device = cdev->devdata;
91 int result; 154 int result;
92 int acpi_state = ACPI_STATE_D0; 155 int acpi_state = ACPI_STATE_D0;
93 156
94 if (!device) 157 result = acpi_device_update_power(device, &acpi_state);
95 return -EINVAL;
96
97 result = acpi_bus_update_power(device->handle, &acpi_state);
98 if (result) 158 if (result)
99 return result; 159 return result;
100 160
@@ -103,21 +163,57 @@ static int fan_get_cur_state(struct thermal_cooling_device *cdev, unsigned long
103 return 0; 163 return 0;
104} 164}
105 165
106static int 166static int fan_get_cur_state(struct thermal_cooling_device *cdev, unsigned long
107fan_set_cur_state(struct thermal_cooling_device *cdev, unsigned long state) 167 *state)
108{ 168{
109 struct acpi_device *device = cdev->devdata; 169 struct acpi_device *device = cdev->devdata;
110 int result; 170 struct acpi_fan *fan = acpi_driver_data(device);
111 171
112 if (!device || (state != 0 && state != 1)) 172 if (fan->acpi4)
173 return fan_get_state_acpi4(device, state);
174 else
175 return fan_get_state(device, state);
176}
177
178static int fan_set_state(struct acpi_device *device, unsigned long state)
179{
180 if (state != 0 && state != 1)
113 return -EINVAL; 181 return -EINVAL;
114 182
115 result = acpi_bus_set_power(device->handle, 183 return acpi_device_set_power(device,
116 state ? ACPI_STATE_D0 : ACPI_STATE_D3_COLD); 184 state ? ACPI_STATE_D0 : ACPI_STATE_D3_COLD);
185}
117 186
118 return result; 187static int fan_set_state_acpi4(struct acpi_device *device, unsigned long state)
188{
189 struct acpi_fan *fan = acpi_driver_data(device);
190 acpi_status status;
191
192 if (state >= fan->fps_count)
193 return -EINVAL;
194
195 status = acpi_execute_simple_method(device->handle, "_FSL",
196 fan->fps[state].control);
197 if (ACPI_FAILURE(status)) {
198 dev_dbg(&device->dev, "Failed to set state by _FSL\n");
199 return status;
200 }
201
202 return 0;
119} 203}
120 204
205static int
206fan_set_cur_state(struct thermal_cooling_device *cdev, unsigned long state)
207{
208 struct acpi_device *device = cdev->devdata;
209 struct acpi_fan *fan = acpi_driver_data(device);
210
211 if (fan->acpi4)
212 return fan_set_state_acpi4(device, state);
213 else
214 return fan_set_state(device, state);
215 }
216
121static const struct thermal_cooling_device_ops fan_cooling_ops = { 217static const struct thermal_cooling_device_ops fan_cooling_ops = {
122 .get_max_state = fan_get_max_state, 218 .get_max_state = fan_get_max_state,
123 .get_cur_state = fan_get_cur_state, 219 .get_cur_state = fan_get_cur_state,
@@ -129,21 +225,125 @@ static const struct thermal_cooling_device_ops fan_cooling_ops = {
129 * -------------------------------------------------------------------------- 225 * --------------------------------------------------------------------------
130*/ 226*/
131 227
132static int acpi_fan_add(struct acpi_device *device) 228static bool acpi_fan_is_acpi4(struct acpi_device *device)
133{ 229{
134 int result = 0; 230 return acpi_has_method(device->handle, "_FIF") &&
135 struct thermal_cooling_device *cdev; 231 acpi_has_method(device->handle, "_FPS") &&
232 acpi_has_method(device->handle, "_FSL") &&
233 acpi_has_method(device->handle, "_FST");
234}
136 235
137 if (!device) 236static int acpi_fan_get_fif(struct acpi_device *device)
138 return -EINVAL; 237{
238 struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
239 struct acpi_fan *fan = acpi_driver_data(device);
240 struct acpi_buffer format = { sizeof("NNNN"), "NNNN" };
241 struct acpi_buffer fif = { sizeof(fan->fif), &fan->fif };
242 union acpi_object *obj;
243 acpi_status status;
244
245 status = acpi_evaluate_object(device->handle, "_FIF", NULL, &buffer);
246 if (ACPI_FAILURE(status))
247 return status;
248
249 obj = buffer.pointer;
250 if (!obj || obj->type != ACPI_TYPE_PACKAGE) {
251 dev_err(&device->dev, "Invalid _FIF data\n");
252 status = -EINVAL;
253 goto err;
254 }
139 255
140 strcpy(acpi_device_name(device), "Fan"); 256 status = acpi_extract_package(obj, &format, &fif);
141 strcpy(acpi_device_class(device), ACPI_FAN_CLASS); 257 if (ACPI_FAILURE(status)) {
258 dev_err(&device->dev, "Invalid _FIF element\n");
259 status = -EINVAL;
260 }
142 261
143 result = acpi_bus_update_power(device->handle, NULL); 262err:
144 if (result) { 263 kfree(obj);
145 dev_err(&device->dev, "Setting initial power state\n"); 264 return status;
146 goto end; 265}
266
267static int acpi_fan_speed_cmp(const void *a, const void *b)
268{
269 const struct acpi_fan_fps *fps1 = a;
270 const struct acpi_fan_fps *fps2 = b;
271 return fps1->speed - fps2->speed;
272}
273
274static int acpi_fan_get_fps(struct acpi_device *device)
275{
276 struct acpi_fan *fan = acpi_driver_data(device);
277 struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
278 union acpi_object *obj;
279 acpi_status status;
280 int i;
281
282 status = acpi_evaluate_object(device->handle, "_FPS", NULL, &buffer);
283 if (ACPI_FAILURE(status))
284 return status;
285
286 obj = buffer.pointer;
287 if (!obj || obj->type != ACPI_TYPE_PACKAGE || obj->package.count < 2) {
288 dev_err(&device->dev, "Invalid _FPS data\n");
289 status = -EINVAL;
290 goto err;
291 }
292
293 fan->fps_count = obj->package.count - 1; /* minus revision field */
294 fan->fps = devm_kzalloc(&device->dev,
295 fan->fps_count * sizeof(struct acpi_fan_fps),
296 GFP_KERNEL);
297 if (!fan->fps) {
298 dev_err(&device->dev, "Not enough memory\n");
299 status = -ENOMEM;
300 goto err;
301 }
302 for (i = 0; i < fan->fps_count; i++) {
303 struct acpi_buffer format = { sizeof("NNNNN"), "NNNNN" };
304 struct acpi_buffer fps = { sizeof(fan->fps[i]), &fan->fps[i] };
305 status = acpi_extract_package(&obj->package.elements[i + 1],
306 &format, &fps);
307 if (ACPI_FAILURE(status)) {
308 dev_err(&device->dev, "Invalid _FPS element\n");
309 break;
310 }
311 }
312
313 /* sort the state array according to fan speed in increase order */
314 sort(fan->fps, fan->fps_count, sizeof(*fan->fps),
315 acpi_fan_speed_cmp, NULL);
316
317err:
318 kfree(obj);
319 return status;
320}
321
322static int acpi_fan_probe(struct platform_device *pdev)
323{
324 int result = 0;
325 struct thermal_cooling_device *cdev;
326 struct acpi_fan *fan;
327 struct acpi_device *device = ACPI_COMPANION(&pdev->dev);
328
329 fan = devm_kzalloc(&pdev->dev, sizeof(*fan), GFP_KERNEL);
330 if (!fan) {
331 dev_err(&device->dev, "No memory for fan\n");
332 return -ENOMEM;
333 }
334 device->driver_data = fan;
335 platform_set_drvdata(pdev, fan);
336
337 if (acpi_fan_is_acpi4(device)) {
338 if (acpi_fan_get_fif(device) || acpi_fan_get_fps(device))
339 goto end;
340 fan->acpi4 = true;
341 } else {
342 result = acpi_device_update_power(device, NULL);
343 if (result) {
344 dev_err(&device->dev, "Setting initial power state\n");
345 goto end;
346 }
147 } 347 }
148 348
149 cdev = thermal_cooling_device_register("Fan", device, 349 cdev = thermal_cooling_device_register("Fan", device,
@@ -153,44 +353,32 @@ static int acpi_fan_add(struct acpi_device *device)
153 goto end; 353 goto end;
154 } 354 }
155 355
156 dev_dbg(&device->dev, "registered as cooling_device%d\n", cdev->id); 356 dev_dbg(&pdev->dev, "registered as cooling_device%d\n", cdev->id);
157 357
158 device->driver_data = cdev; 358 fan->cdev = cdev;
159 result = sysfs_create_link(&device->dev.kobj, 359 result = sysfs_create_link(&pdev->dev.kobj,
160 &cdev->device.kobj, 360 &cdev->device.kobj,
161 "thermal_cooling"); 361 "thermal_cooling");
162 if (result) 362 if (result)
163 dev_err(&device->dev, "Failed to create sysfs link " 363 dev_err(&pdev->dev, "Failed to create sysfs link 'thermal_cooling'\n");
164 "'thermal_cooling'\n");
165 364
166 result = sysfs_create_link(&cdev->device.kobj, 365 result = sysfs_create_link(&cdev->device.kobj,
167 &device->dev.kobj, 366 &pdev->dev.kobj,
168 "device"); 367 "device");
169 if (result) 368 if (result)
170 dev_err(&device->dev, "Failed to create sysfs link 'device'\n"); 369 dev_err(&pdev->dev, "Failed to create sysfs link 'device'\n");
171
172 dev_info(&device->dev, "ACPI: %s [%s] (%s)\n",
173 acpi_device_name(device), acpi_device_bid(device),
174 !device->power.state ? "on" : "off");
175 370
176end: 371end:
177 return result; 372 return result;
178} 373}
179 374
180static int acpi_fan_remove(struct acpi_device *device) 375static int acpi_fan_remove(struct platform_device *pdev)
181{ 376{
182 struct thermal_cooling_device *cdev; 377 struct acpi_fan *fan = platform_get_drvdata(pdev);
183
184 if (!device)
185 return -EINVAL;
186
187 cdev = acpi_driver_data(device);
188 if (!cdev)
189 return -EINVAL;
190 378
191 sysfs_remove_link(&device->dev.kobj, "thermal_cooling"); 379 sysfs_remove_link(&pdev->dev.kobj, "thermal_cooling");
192 sysfs_remove_link(&cdev->device.kobj, "device"); 380 sysfs_remove_link(&fan->cdev->device.kobj, "device");
193 thermal_cooling_device_unregister(cdev); 381 thermal_cooling_device_unregister(fan->cdev);
194 382
195 return 0; 383 return 0;
196} 384}
@@ -198,10 +386,11 @@ static int acpi_fan_remove(struct acpi_device *device)
198#ifdef CONFIG_PM_SLEEP 386#ifdef CONFIG_PM_SLEEP
199static int acpi_fan_suspend(struct device *dev) 387static int acpi_fan_suspend(struct device *dev)
200{ 388{
201 if (!dev) 389 struct acpi_fan *fan = dev_get_drvdata(dev);
202 return -EINVAL; 390 if (fan->acpi4)
391 return 0;
203 392
204 acpi_bus_set_power(to_acpi_device(dev)->handle, ACPI_STATE_D0); 393 acpi_device_set_power(ACPI_COMPANION(dev), ACPI_STATE_D0);
205 394
206 return AE_OK; 395 return AE_OK;
207} 396}
@@ -209,11 +398,12 @@ static int acpi_fan_suspend(struct device *dev)
209static int acpi_fan_resume(struct device *dev) 398static int acpi_fan_resume(struct device *dev)
210{ 399{
211 int result; 400 int result;
401 struct acpi_fan *fan = dev_get_drvdata(dev);
212 402
213 if (!dev) 403 if (fan->acpi4)
214 return -EINVAL; 404 return 0;
215 405
216 result = acpi_bus_update_power(to_acpi_device(dev)->handle, NULL); 406 result = acpi_device_update_power(ACPI_COMPANION(dev), NULL);
217 if (result) 407 if (result)
218 dev_err(dev, "Error updating fan power state\n"); 408 dev_err(dev, "Error updating fan power state\n");
219 409
@@ -221,4 +411,4 @@ static int acpi_fan_resume(struct device *dev)
221} 411}
222#endif 412#endif
223 413
224module_acpi_driver(acpi_fan_driver); 414module_platform_driver(acpi_fan_driver);
diff --git a/drivers/acpi/int340x_thermal.c b/drivers/acpi/int340x_thermal.c
new file mode 100644
index 000000000000..a27d31d1ba24
--- /dev/null
+++ b/drivers/acpi/int340x_thermal.c
@@ -0,0 +1,51 @@
1/*
2 * ACPI support for int340x thermal drivers
3 *
4 * Copyright (C) 2014, Intel Corporation
5 * Authors: Zhang Rui <rui.zhang@intel.com>
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License version 2 as
9 * published by the Free Software Foundation.
10 */
11
12#include <linux/acpi.h>
13#include <linux/module.h>
14
15#include "internal.h"
16
17#define DO_ENUMERATION 0x01
18static const struct acpi_device_id int340x_thermal_device_ids[] = {
19 {"INT3400", DO_ENUMERATION },
20 {"INT3401"},
21 {"INT3402"},
22 {"INT3403"},
23 {"INT3404"},
24 {"INT3406"},
25 {"INT3407"},
26 {"INT3408"},
27 {"INT3409"},
28 {"INT340A"},
29 {"INT340B"},
30 {""},
31};
32
33static int int340x_thermal_handler_attach(struct acpi_device *adev,
34 const struct acpi_device_id *id)
35{
36#if defined(CONFIG_INT340X_THERMAL) || defined(CONFIG_INT340X_THERMAL_MODULE)
37 if (id->driver_data == DO_ENUMERATION)
38 acpi_create_platform_device(adev);
39#endif
40 return 1;
41}
42
43static struct acpi_scan_handler int340x_thermal_handler = {
44 .ids = int340x_thermal_device_ids,
45 .attach = int340x_thermal_handler_attach,
46};
47
48void __init acpi_int340x_thermal_init(void)
49{
50 acpi_scan_add_handler(&int340x_thermal_handler);
51}
diff --git a/drivers/acpi/internal.h b/drivers/acpi/internal.h
index 4c5cf77e7576..447f6d679b29 100644
--- a/drivers/acpi/internal.h
+++ b/drivers/acpi/internal.h
@@ -31,6 +31,7 @@ void acpi_pci_link_init(void);
31void acpi_processor_init(void); 31void acpi_processor_init(void);
32void acpi_platform_init(void); 32void acpi_platform_init(void);
33void acpi_pnp_init(void); 33void acpi_pnp_init(void);
34void acpi_int340x_thermal_init(void);
34int acpi_sysfs_init(void); 35int acpi_sysfs_init(void);
35void acpi_container_init(void); 36void acpi_container_init(void);
36void acpi_memory_hotplug_init(void); 37void acpi_memory_hotplug_init(void);
@@ -103,8 +104,6 @@ int acpi_power_get_inferred_state(struct acpi_device *device, int *state);
103int acpi_power_on_resources(struct acpi_device *device, int state); 104int acpi_power_on_resources(struct acpi_device *device, int state);
104int acpi_power_transition(struct acpi_device *device, int state); 105int acpi_power_transition(struct acpi_device *device, int state);
105 106
106int acpi_device_update_power(struct acpi_device *device, int *state_p);
107
108int acpi_wakeup_device_init(void); 107int acpi_wakeup_device_init(void);
109 108
110#ifdef CONFIG_ARCH_MIGHT_HAVE_ACPI_PDC 109#ifdef CONFIG_ARCH_MIGHT_HAVE_ACPI_PDC
@@ -168,13 +167,6 @@ static inline void suspend_nvs_restore(void) {}
168#endif 167#endif
169 168
170/*-------------------------------------------------------------------------- 169/*--------------------------------------------------------------------------
171 Platform bus support
172 -------------------------------------------------------------------------- */
173struct platform_device;
174
175struct platform_device *acpi_create_platform_device(struct acpi_device *adev);
176
177/*--------------------------------------------------------------------------
178 Video 170 Video
179 -------------------------------------------------------------------------- */ 171 -------------------------------------------------------------------------- */
180#if defined(CONFIG_ACPI_VIDEO) || defined(CONFIG_ACPI_VIDEO_MODULE) 172#if defined(CONFIG_ACPI_VIDEO) || defined(CONFIG_ACPI_VIDEO_MODULE)
diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c
index ae44d8654c82..095c6ddde8a3 100644
--- a/drivers/acpi/scan.c
+++ b/drivers/acpi/scan.c
@@ -2315,6 +2315,7 @@ int __init acpi_scan_init(void)
2315 acpi_container_init(); 2315 acpi_container_init();
2316 acpi_memory_hotplug_init(); 2316 acpi_memory_hotplug_init();
2317 acpi_pnp_init(); 2317 acpi_pnp_init();
2318 acpi_int340x_thermal_init();
2318 2319
2319 mutex_lock(&acpi_scan_lock); 2320 mutex_lock(&acpi_scan_lock);
2320 /* 2321 /*
diff --git a/drivers/acpi/thermal.c b/drivers/acpi/thermal.c
index 112817e963e0..d24fa1964eb8 100644
--- a/drivers/acpi/thermal.c
+++ b/drivers/acpi/thermal.c
@@ -528,7 +528,6 @@ static void acpi_thermal_check(void *data)
528} 528}
529 529
530/* sys I/F for generic thermal sysfs support */ 530/* sys I/F for generic thermal sysfs support */
531#define KELVIN_TO_MILLICELSIUS(t, off) (((t) - (off)) * 100)
532 531
533static int thermal_get_temp(struct thermal_zone_device *thermal, 532static int thermal_get_temp(struct thermal_zone_device *thermal,
534 unsigned long *temp) 533 unsigned long *temp)
@@ -543,7 +542,8 @@ static int thermal_get_temp(struct thermal_zone_device *thermal,
543 if (result) 542 if (result)
544 return result; 543 return result;
545 544
546 *temp = KELVIN_TO_MILLICELSIUS(tz->temperature, tz->kelvin_offset); 545 *temp = DECI_KELVIN_TO_MILLICELSIUS_WITH_OFFSET(tz->temperature,
546 tz->kelvin_offset);
547 return 0; 547 return 0;
548} 548}
549 549
@@ -647,7 +647,7 @@ static int thermal_get_trip_temp(struct thermal_zone_device *thermal,
647 647
648 if (tz->trips.critical.flags.valid) { 648 if (tz->trips.critical.flags.valid) {
649 if (!trip) { 649 if (!trip) {
650 *temp = KELVIN_TO_MILLICELSIUS( 650 *temp = DECI_KELVIN_TO_MILLICELSIUS_WITH_OFFSET(
651 tz->trips.critical.temperature, 651 tz->trips.critical.temperature,
652 tz->kelvin_offset); 652 tz->kelvin_offset);
653 return 0; 653 return 0;
@@ -657,7 +657,7 @@ static int thermal_get_trip_temp(struct thermal_zone_device *thermal,
657 657
658 if (tz->trips.hot.flags.valid) { 658 if (tz->trips.hot.flags.valid) {
659 if (!trip) { 659 if (!trip) {
660 *temp = KELVIN_TO_MILLICELSIUS( 660 *temp = DECI_KELVIN_TO_MILLICELSIUS_WITH_OFFSET(
661 tz->trips.hot.temperature, 661 tz->trips.hot.temperature,
662 tz->kelvin_offset); 662 tz->kelvin_offset);
663 return 0; 663 return 0;
@@ -667,7 +667,7 @@ static int thermal_get_trip_temp(struct thermal_zone_device *thermal,
667 667
668 if (tz->trips.passive.flags.valid) { 668 if (tz->trips.passive.flags.valid) {
669 if (!trip) { 669 if (!trip) {
670 *temp = KELVIN_TO_MILLICELSIUS( 670 *temp = DECI_KELVIN_TO_MILLICELSIUS_WITH_OFFSET(
671 tz->trips.passive.temperature, 671 tz->trips.passive.temperature,
672 tz->kelvin_offset); 672 tz->kelvin_offset);
673 return 0; 673 return 0;
@@ -678,7 +678,7 @@ static int thermal_get_trip_temp(struct thermal_zone_device *thermal,
678 for (i = 0; i < ACPI_THERMAL_MAX_ACTIVE && 678 for (i = 0; i < ACPI_THERMAL_MAX_ACTIVE &&
679 tz->trips.active[i].flags.valid; i++) { 679 tz->trips.active[i].flags.valid; i++) {
680 if (!trip) { 680 if (!trip) {
681 *temp = KELVIN_TO_MILLICELSIUS( 681 *temp = DECI_KELVIN_TO_MILLICELSIUS_WITH_OFFSET(
682 tz->trips.active[i].temperature, 682 tz->trips.active[i].temperature,
683 tz->kelvin_offset); 683 tz->kelvin_offset);
684 return 0; 684 return 0;
@@ -694,7 +694,7 @@ static int thermal_get_crit_temp(struct thermal_zone_device *thermal,
694 struct acpi_thermal *tz = thermal->devdata; 694 struct acpi_thermal *tz = thermal->devdata;
695 695
696 if (tz->trips.critical.flags.valid) { 696 if (tz->trips.critical.flags.valid) {
697 *temperature = KELVIN_TO_MILLICELSIUS( 697 *temperature = DECI_KELVIN_TO_MILLICELSIUS_WITH_OFFSET(
698 tz->trips.critical.temperature, 698 tz->trips.critical.temperature,
699 tz->kelvin_offset); 699 tz->kelvin_offset);
700 return 0; 700 return 0;
@@ -714,8 +714,8 @@ static int thermal_get_trend(struct thermal_zone_device *thermal,
714 714
715 if (type == THERMAL_TRIP_ACTIVE) { 715 if (type == THERMAL_TRIP_ACTIVE) {
716 unsigned long trip_temp; 716 unsigned long trip_temp;
717 unsigned long temp = KELVIN_TO_MILLICELSIUS(tz->temperature, 717 unsigned long temp = DECI_KELVIN_TO_MILLICELSIUS_WITH_OFFSET(
718 tz->kelvin_offset); 718 tz->temperature, tz->kelvin_offset);
719 if (thermal_get_trip_temp(thermal, trip, &trip_temp)) 719 if (thermal_get_trip_temp(thermal, trip, &trip_temp))
720 return -EINVAL; 720 return -EINVAL;
721 721
diff --git a/drivers/acpi/utils.c b/drivers/acpi/utils.c
index 834f35c4bf8d..371ac12d25b1 100644
--- a/drivers/acpi/utils.c
+++ b/drivers/acpi/utils.c
@@ -149,6 +149,21 @@ acpi_extract_package(union acpi_object *package,
149 break; 149 break;
150 } 150 }
151 break; 151 break;
152 case ACPI_TYPE_LOCAL_REFERENCE:
153 switch (format_string[i]) {
154 case 'R':
155 size_required += sizeof(void *);
156 tail_offset += sizeof(void *);
157 break;
158 default:
159 printk(KERN_WARNING PREFIX "Invalid package element"
160 " [%d] got reference,"
161 " expecting [%c]\n",
162 i, format_string[i]);
163 return AE_BAD_DATA;
164 break;
165 }
166 break;
152 167
153 case ACPI_TYPE_PACKAGE: 168 case ACPI_TYPE_PACKAGE:
154 default: 169 default:
@@ -247,7 +262,18 @@ acpi_extract_package(union acpi_object *package,
247 break; 262 break;
248 } 263 }
249 break; 264 break;
250 265 case ACPI_TYPE_LOCAL_REFERENCE:
266 switch (format_string[i]) {
267 case 'R':
268 *(void **)head =
269 (void *)element->reference.handle;
270 head += sizeof(void *);
271 break;
272 default:
273 /* Should never get here */
274 break;
275 }
276 break;
251 case ACPI_TYPE_PACKAGE: 277 case ACPI_TYPE_PACKAGE:
252 /* TBD: handle nested packages... */ 278 /* TBD: handle nested packages... */
253 default: 279 default:
diff --git a/drivers/thermal/Kconfig b/drivers/thermal/Kconfig
index ef5587fe2c69..f554d25b4399 100644
--- a/drivers/thermal/Kconfig
+++ b/drivers/thermal/Kconfig
@@ -84,6 +84,16 @@ config THERMAL_GOV_STEP_WISE
84 Enable this to manage platform thermals using a simple linear 84 Enable this to manage platform thermals using a simple linear
85 governor. 85 governor.
86 86
87config THERMAL_GOV_BANG_BANG
88 bool "Bang Bang thermal governor"
89 default n
90 help
91 Enable this to manage platform thermals using bang bang governor.
92
93 Say 'Y' here if you want to use two point temperature regulation
94 used for fans without throttling. Some fan drivers depend on this
95 governor to be enabled (e.g. acerhdf).
96
87config THERMAL_GOV_USER_SPACE 97config THERMAL_GOV_USER_SPACE
88 bool "User_space thermal governor" 98 bool "User_space thermal governor"
89 help 99 help
@@ -207,21 +217,6 @@ config X86_PKG_TEMP_THERMAL
207 two trip points which can be set by user to get notifications via thermal 217 two trip points which can be set by user to get notifications via thermal
208 notification methods. 218 notification methods.
209 219
210config ACPI_INT3403_THERMAL
211 tristate "ACPI INT3403 thermal driver"
212 depends on X86 && ACPI
213 help
214 Newer laptops and tablets that use ACPI may have thermal sensors
215 outside the core CPU/SOC for thermal safety reasons. These
216 temperature sensors are also exposed for the OS to use via the so
217 called INT3403 ACPI object. This driver will, on devices that have
218 such sensors, expose the temperature information from these sensors
219 to userspace via the normal thermal framework. This means that a wide
220 range of applications and GUI widgets can show this information to
221 the user or use this information for making decisions. For example,
222 the Intel Thermal Daemon can use this information to allow the user
223 to select his laptop to run without turning on the fans.
224
225config INTEL_SOC_DTS_THERMAL 220config INTEL_SOC_DTS_THERMAL
226 tristate "Intel SoCs DTS thermal driver" 221 tristate "Intel SoCs DTS thermal driver"
227 depends on X86 && IOSF_MBI 222 depends on X86 && IOSF_MBI
@@ -234,6 +229,30 @@ config INTEL_SOC_DTS_THERMAL
234 notification methods.The other trip is a critical trip point, which 229 notification methods.The other trip is a critical trip point, which
235 was set by the driver based on the TJ MAX temperature. 230 was set by the driver based on the TJ MAX temperature.
236 231
232config INT340X_THERMAL
233 tristate "ACPI INT340X thermal drivers"
234 depends on X86 && ACPI
235 select THERMAL_GOV_USER_SPACE
236 select ACPI_THERMAL_REL
237 select ACPI_FAN
238 help
239 Newer laptops and tablets that use ACPI may have thermal sensors and
240 other devices with thermal control capabilities outside the core
241 CPU/SOC, for thermal safety reasons.
242 They are exposed for the OS to use via the INT3400 ACPI device object
243 as the master, and INT3401~INT340B ACPI device objects as the slaves.
244 Enable this to expose the temperature information and cooling ability
245 from these objects to userspace via the normal thermal framework.
246 This means that a wide range of applications and GUI widgets can show
247 the information to the user or use this information for making
248 decisions. For example, the Intel Thermal Daemon can use this
249 information to allow the user to select his laptop to run without
250 turning on the fans.
251
252config ACPI_THERMAL_REL
253 tristate
254 depends on ACPI
255
237menu "Texas Instruments thermal drivers" 256menu "Texas Instruments thermal drivers"
238source "drivers/thermal/ti-soc-thermal/Kconfig" 257source "drivers/thermal/ti-soc-thermal/Kconfig"
239endmenu 258endmenu
diff --git a/drivers/thermal/Makefile b/drivers/thermal/Makefile
index 31e232f84b6b..39c4fe87da2f 100644
--- a/drivers/thermal/Makefile
+++ b/drivers/thermal/Makefile
@@ -11,6 +11,7 @@ thermal_sys-$(CONFIG_THERMAL_OF) += of-thermal.o
11 11
12# governors 12# governors
13thermal_sys-$(CONFIG_THERMAL_GOV_FAIR_SHARE) += fair_share.o 13thermal_sys-$(CONFIG_THERMAL_GOV_FAIR_SHARE) += fair_share.o
14thermal_sys-$(CONFIG_THERMAL_GOV_BANG_BANG) += gov_bang_bang.o
14thermal_sys-$(CONFIG_THERMAL_GOV_STEP_WISE) += step_wise.o 15thermal_sys-$(CONFIG_THERMAL_GOV_STEP_WISE) += step_wise.o
15thermal_sys-$(CONFIG_THERMAL_GOV_USER_SPACE) += user_space.o 16thermal_sys-$(CONFIG_THERMAL_GOV_USER_SPACE) += user_space.o
16 17
@@ -31,5 +32,5 @@ obj-$(CONFIG_INTEL_POWERCLAMP) += intel_powerclamp.o
31obj-$(CONFIG_X86_PKG_TEMP_THERMAL) += x86_pkg_temp_thermal.o 32obj-$(CONFIG_X86_PKG_TEMP_THERMAL) += x86_pkg_temp_thermal.o
32obj-$(CONFIG_INTEL_SOC_DTS_THERMAL) += intel_soc_dts_thermal.o 33obj-$(CONFIG_INTEL_SOC_DTS_THERMAL) += intel_soc_dts_thermal.o
33obj-$(CONFIG_TI_SOC_THERMAL) += ti-soc-thermal/ 34obj-$(CONFIG_TI_SOC_THERMAL) += ti-soc-thermal/
34obj-$(CONFIG_ACPI_INT3403_THERMAL) += int3403_thermal.o 35obj-$(CONFIG_INT340X_THERMAL) += int340x_thermal/
35obj-$(CONFIG_ST_THERMAL) += st/ 36obj-$(CONFIG_ST_THERMAL) += st/
diff --git a/drivers/thermal/fair_share.c b/drivers/thermal/fair_share.c
index 944ba2f340c8..6e0a3fbfae86 100644
--- a/drivers/thermal/fair_share.c
+++ b/drivers/thermal/fair_share.c
@@ -23,6 +23,7 @@
23 */ 23 */
24 24
25#include <linux/thermal.h> 25#include <linux/thermal.h>
26#include <trace/events/thermal.h>
26 27
27#include "thermal_core.h" 28#include "thermal_core.h"
28 29
@@ -34,6 +35,7 @@ static int get_trip_level(struct thermal_zone_device *tz)
34{ 35{
35 int count = 0; 36 int count = 0;
36 unsigned long trip_temp; 37 unsigned long trip_temp;
38 enum thermal_trip_type trip_type;
37 39
38 if (tz->trips == 0 || !tz->ops->get_trip_temp) 40 if (tz->trips == 0 || !tz->ops->get_trip_temp)
39 return 0; 41 return 0;
@@ -43,6 +45,16 @@ static int get_trip_level(struct thermal_zone_device *tz)
43 if (tz->temperature < trip_temp) 45 if (tz->temperature < trip_temp)
44 break; 46 break;
45 } 47 }
48
49 /*
50 * count > 0 only if temperature is greater than first trip
51 * point, in which case, trip_point = count - 1
52 */
53 if (count > 0) {
54 tz->ops->get_trip_type(tz, count - 1, &trip_type);
55 trace_thermal_zone_trip(tz, count - 1, trip_type);
56 }
57
46 return count; 58 return count;
47} 59}
48 60
diff --git a/drivers/thermal/gov_bang_bang.c b/drivers/thermal/gov_bang_bang.c
new file mode 100644
index 000000000000..c5dd76b2ee74
--- /dev/null
+++ b/drivers/thermal/gov_bang_bang.c
@@ -0,0 +1,131 @@
1/*
2 * gov_bang_bang.c - A simple thermal throttling governor using hysteresis
3 *
4 * Copyright (C) 2014 Peter Feuerer <peter@piie.net>
5 *
6 * Based on step_wise.c with following Copyrights:
7 * Copyright (C) 2012 Intel Corp
8 * Copyright (C) 2012 Durgadoss R <durgadoss.r@intel.com>
9 *
10 *
11 * This program is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License as published by
13 * the Free Software Foundation, version 2.
14 *
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
18 * the GNU General Public License for more details.
19 *
20 */
21
22#include <linux/thermal.h>
23
24#include "thermal_core.h"
25
26static void thermal_zone_trip_update(struct thermal_zone_device *tz, int trip)
27{
28 long trip_temp;
29 unsigned long trip_hyst;
30 struct thermal_instance *instance;
31
32 tz->ops->get_trip_temp(tz, trip, &trip_temp);
33 tz->ops->get_trip_hyst(tz, trip, &trip_hyst);
34
35 dev_dbg(&tz->device, "Trip%d[temp=%ld]:temp=%d:hyst=%ld\n",
36 trip, trip_temp, tz->temperature,
37 trip_hyst);
38
39 mutex_lock(&tz->lock);
40
41 list_for_each_entry(instance, &tz->thermal_instances, tz_node) {
42 if (instance->trip != trip)
43 continue;
44
45 /* in case fan is in initial state, switch the fan off */
46 if (instance->target == THERMAL_NO_TARGET)
47 instance->target = 0;
48
49 /* in case fan is neither on nor off set the fan to active */
50 if (instance->target != 0 && instance->target != 1) {
51 pr_warn("Thermal instance %s controlled by bang-bang has unexpected state: %ld\n",
52 instance->name, instance->target);
53 instance->target = 1;
54 }
55
56 /*
57 * enable fan when temperature exceeds trip_temp and disable
58 * the fan in case it falls below trip_temp minus hysteresis
59 */
60 if (instance->target == 0 && tz->temperature >= trip_temp)
61 instance->target = 1;
62 else if (instance->target == 1 &&
63 tz->temperature < trip_temp - trip_hyst)
64 instance->target = 0;
65
66 dev_dbg(&instance->cdev->device, "target=%d\n",
67 (int)instance->target);
68
69 instance->cdev->updated = false; /* cdev needs update */
70 }
71
72 mutex_unlock(&tz->lock);
73}
74
75/**
76 * bang_bang_control - controls devices associated with the given zone
77 * @tz - thermal_zone_device
78 * @trip - the trip point
79 *
80 * Regulation Logic: a two point regulation, deliver cooling state depending
81 * on the previous state shown in this diagram:
82 *
83 * Fan: OFF ON
84 *
85 * |
86 * |
87 * trip_temp: +---->+
88 * | | ^
89 * | | |
90 * | | Temperature
91 * (trip_temp - hyst): +<----+
92 * |
93 * |
94 * |
95 *
96 * * If the fan is not running and temperature exceeds trip_temp, the fan
97 * gets turned on.
98 * * In case the fan is running, temperature must fall below
99 * (trip_temp - hyst) so that the fan gets turned off again.
100 *
101 */
102static int bang_bang_control(struct thermal_zone_device *tz, int trip)
103{
104 struct thermal_instance *instance;
105
106 thermal_zone_trip_update(tz, trip);
107
108 mutex_lock(&tz->lock);
109
110 list_for_each_entry(instance, &tz->thermal_instances, tz_node)
111 thermal_cdev_update(instance->cdev);
112
113 mutex_unlock(&tz->lock);
114
115 return 0;
116}
117
118static struct thermal_governor thermal_gov_bang_bang = {
119 .name = "bang_bang",
120 .throttle = bang_bang_control,
121};
122
123int thermal_gov_bang_bang_register(void)
124{
125 return thermal_register_governor(&thermal_gov_bang_bang);
126}
127
128void thermal_gov_bang_bang_unregister(void)
129{
130 thermal_unregister_governor(&thermal_gov_bang_bang);
131}
diff --git a/drivers/thermal/imx_thermal.c b/drivers/thermal/imx_thermal.c
index 2c516f2eebed..461bf3d033a0 100644
--- a/drivers/thermal/imx_thermal.c
+++ b/drivers/thermal/imx_thermal.c
@@ -19,6 +19,7 @@
19#include <linux/mfd/syscon.h> 19#include <linux/mfd/syscon.h>
20#include <linux/module.h> 20#include <linux/module.h>
21#include <linux/of.h> 21#include <linux/of.h>
22#include <linux/of_device.h>
22#include <linux/platform_device.h> 23#include <linux/platform_device.h>
23#include <linux/regmap.h> 24#include <linux/regmap.h>
24#include <linux/slab.h> 25#include <linux/slab.h>
@@ -31,6 +32,11 @@
31 32
32#define MISC0 0x0150 33#define MISC0 0x0150
33#define MISC0_REFTOP_SELBIASOFF (1 << 3) 34#define MISC0_REFTOP_SELBIASOFF (1 << 3)
35#define MISC1 0x0160
36#define MISC1_IRQ_TEMPHIGH (1 << 29)
37/* Below LOW and PANIC bits are only for TEMPMON_IMX6SX */
38#define MISC1_IRQ_TEMPLOW (1 << 28)
39#define MISC1_IRQ_TEMPPANIC (1 << 27)
34 40
35#define TEMPSENSE0 0x0180 41#define TEMPSENSE0 0x0180
36#define TEMPSENSE0_ALARM_VALUE_SHIFT 20 42#define TEMPSENSE0_ALARM_VALUE_SHIFT 20
@@ -43,6 +49,12 @@
43 49
44#define TEMPSENSE1 0x0190 50#define TEMPSENSE1 0x0190
45#define TEMPSENSE1_MEASURE_FREQ 0xffff 51#define TEMPSENSE1_MEASURE_FREQ 0xffff
52/* Below TEMPSENSE2 is only for TEMPMON_IMX6SX */
53#define TEMPSENSE2 0x0290
54#define TEMPSENSE2_LOW_VALUE_SHIFT 0
55#define TEMPSENSE2_LOW_VALUE_MASK 0xfff
56#define TEMPSENSE2_PANIC_VALUE_SHIFT 16
57#define TEMPSENSE2_PANIC_VALUE_MASK 0xfff0000
46 58
47#define OCOTP_ANA1 0x04e0 59#define OCOTP_ANA1 0x04e0
48 60
@@ -66,6 +78,21 @@ enum imx_thermal_trip {
66#define FACTOR1 15976 78#define FACTOR1 15976
67#define FACTOR2 4297157 79#define FACTOR2 4297157
68 80
81#define TEMPMON_IMX6Q 1
82#define TEMPMON_IMX6SX 2
83
84struct thermal_soc_data {
85 u32 version;
86};
87
88static struct thermal_soc_data thermal_imx6q_data = {
89 .version = TEMPMON_IMX6Q,
90};
91
92static struct thermal_soc_data thermal_imx6sx_data = {
93 .version = TEMPMON_IMX6SX,
94};
95
69struct imx_thermal_data { 96struct imx_thermal_data {
70 struct thermal_zone_device *tz; 97 struct thermal_zone_device *tz;
71 struct thermal_cooling_device *cdev; 98 struct thermal_cooling_device *cdev;
@@ -79,8 +106,21 @@ struct imx_thermal_data {
79 bool irq_enabled; 106 bool irq_enabled;
80 int irq; 107 int irq;
81 struct clk *thermal_clk; 108 struct clk *thermal_clk;
109 const struct thermal_soc_data *socdata;
82}; 110};
83 111
112static void imx_set_panic_temp(struct imx_thermal_data *data,
113 signed long panic_temp)
114{
115 struct regmap *map = data->tempmon;
116 int critical_value;
117
118 critical_value = (data->c2 - panic_temp) / data->c1;
119 regmap_write(map, TEMPSENSE2 + REG_CLR, TEMPSENSE2_PANIC_VALUE_MASK);
120 regmap_write(map, TEMPSENSE2 + REG_SET, critical_value <<
121 TEMPSENSE2_PANIC_VALUE_SHIFT);
122}
123
84static void imx_set_alarm_temp(struct imx_thermal_data *data, 124static void imx_set_alarm_temp(struct imx_thermal_data *data,
85 signed long alarm_temp) 125 signed long alarm_temp)
86{ 126{
@@ -142,13 +182,17 @@ static int imx_get_temp(struct thermal_zone_device *tz, unsigned long *temp)
142 /* See imx_get_sensor_data() for formula derivation */ 182 /* See imx_get_sensor_data() for formula derivation */
143 *temp = data->c2 - n_meas * data->c1; 183 *temp = data->c2 - n_meas * data->c1;
144 184
145 /* Update alarm value to next higher trip point */ 185 /* Update alarm value to next higher trip point for TEMPMON_IMX6Q */
146 if (data->alarm_temp == data->temp_passive && *temp >= data->temp_passive) 186 if (data->socdata->version == TEMPMON_IMX6Q) {
147 imx_set_alarm_temp(data, data->temp_critical); 187 if (data->alarm_temp == data->temp_passive &&
148 if (data->alarm_temp == data->temp_critical && *temp < data->temp_passive) { 188 *temp >= data->temp_passive)
149 imx_set_alarm_temp(data, data->temp_passive); 189 imx_set_alarm_temp(data, data->temp_critical);
150 dev_dbg(&tz->device, "thermal alarm off: T < %lu\n", 190 if (data->alarm_temp == data->temp_critical &&
151 data->alarm_temp / 1000); 191 *temp < data->temp_passive) {
192 imx_set_alarm_temp(data, data->temp_passive);
193 dev_dbg(&tz->device, "thermal alarm off: T < %lu\n",
194 data->alarm_temp / 1000);
195 }
152 } 196 }
153 197
154 if (*temp != data->last_temp) { 198 if (*temp != data->last_temp) {
@@ -398,8 +442,17 @@ static irqreturn_t imx_thermal_alarm_irq_thread(int irq, void *dev)
398 return IRQ_HANDLED; 442 return IRQ_HANDLED;
399} 443}
400 444
445static const struct of_device_id of_imx_thermal_match[] = {
446 { .compatible = "fsl,imx6q-tempmon", .data = &thermal_imx6q_data, },
447 { .compatible = "fsl,imx6sx-tempmon", .data = &thermal_imx6sx_data, },
448 { /* end */ }
449};
450MODULE_DEVICE_TABLE(of, of_imx_thermal_match);
451
401static int imx_thermal_probe(struct platform_device *pdev) 452static int imx_thermal_probe(struct platform_device *pdev)
402{ 453{
454 const struct of_device_id *of_id =
455 of_match_device(of_imx_thermal_match, &pdev->dev);
403 struct imx_thermal_data *data; 456 struct imx_thermal_data *data;
404 struct cpumask clip_cpus; 457 struct cpumask clip_cpus;
405 struct regmap *map; 458 struct regmap *map;
@@ -418,6 +471,20 @@ static int imx_thermal_probe(struct platform_device *pdev)
418 } 471 }
419 data->tempmon = map; 472 data->tempmon = map;
420 473
474 data->socdata = of_id->data;
475
476 /* make sure the IRQ flag is clear before enabling irq on i.MX6SX */
477 if (data->socdata->version == TEMPMON_IMX6SX) {
478 regmap_write(map, MISC1 + REG_CLR, MISC1_IRQ_TEMPHIGH |
479 MISC1_IRQ_TEMPLOW | MISC1_IRQ_TEMPPANIC);
480 /*
481 * reset value of LOW ALARM is incorrect, set it to lowest
482 * value to avoid false trigger of low alarm.
483 */
484 regmap_write(map, TEMPSENSE2 + REG_SET,
485 TEMPSENSE2_LOW_VALUE_MASK);
486 }
487
421 data->irq = platform_get_irq(pdev, 0); 488 data->irq = platform_get_irq(pdev, 0);
422 if (data->irq < 0) 489 if (data->irq < 0)
423 return data->irq; 490 return data->irq;
@@ -489,6 +556,10 @@ static int imx_thermal_probe(struct platform_device *pdev)
489 measure_freq = DIV_ROUND_UP(32768, 10); /* 10 Hz */ 556 measure_freq = DIV_ROUND_UP(32768, 10); /* 10 Hz */
490 regmap_write(map, TEMPSENSE1 + REG_SET, measure_freq); 557 regmap_write(map, TEMPSENSE1 + REG_SET, measure_freq);
491 imx_set_alarm_temp(data, data->temp_passive); 558 imx_set_alarm_temp(data, data->temp_passive);
559
560 if (data->socdata->version == TEMPMON_IMX6SX)
561 imx_set_panic_temp(data, data->temp_critical);
562
492 regmap_write(map, TEMPSENSE0 + REG_CLR, TEMPSENSE0_POWER_DOWN); 563 regmap_write(map, TEMPSENSE0 + REG_CLR, TEMPSENSE0_POWER_DOWN);
493 regmap_write(map, TEMPSENSE0 + REG_SET, TEMPSENSE0_MEASURE_TEMP); 564 regmap_write(map, TEMPSENSE0 + REG_SET, TEMPSENSE0_MEASURE_TEMP);
494 565
@@ -550,12 +621,6 @@ static int imx_thermal_resume(struct device *dev)
550static SIMPLE_DEV_PM_OPS(imx_thermal_pm_ops, 621static SIMPLE_DEV_PM_OPS(imx_thermal_pm_ops,
551 imx_thermal_suspend, imx_thermal_resume); 622 imx_thermal_suspend, imx_thermal_resume);
552 623
553static const struct of_device_id of_imx_thermal_match[] = {
554 { .compatible = "fsl,imx6q-tempmon", },
555 { /* end */ }
556};
557MODULE_DEVICE_TABLE(of, of_imx_thermal_match);
558
559static struct platform_driver imx_thermal = { 624static struct platform_driver imx_thermal = {
560 .driver = { 625 .driver = {
561 .name = "imx_thermal", 626 .name = "imx_thermal",
diff --git a/drivers/thermal/int3403_thermal.c b/drivers/thermal/int3403_thermal.c
deleted file mode 100644
index 17554eeb3953..000000000000
--- a/drivers/thermal/int3403_thermal.c
+++ /dev/null
@@ -1,296 +0,0 @@
1/*
2 * ACPI INT3403 thermal driver
3 * Copyright (c) 2013, 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/types.h>
19#include <linux/acpi.h>
20#include <linux/thermal.h>
21
22#define INT3403_TYPE_SENSOR 0x03
23#define INT3403_PERF_CHANGED_EVENT 0x80
24#define INT3403_THERMAL_EVENT 0x90
25
26#define DECI_KELVIN_TO_MILLI_CELSIUS(t, off) (((t) - (off)) * 100)
27#define KELVIN_OFFSET 2732
28#define MILLI_CELSIUS_TO_DECI_KELVIN(t, off) (((t) / 100) + (off))
29
30#define ACPI_INT3403_CLASS "int3403"
31#define ACPI_INT3403_FILE_STATE "state"
32
33struct int3403_sensor {
34 struct thermal_zone_device *tzone;
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
42static int sys_get_curr_temp(struct thermal_zone_device *tzone,
43 unsigned long *temp)
44{
45 struct acpi_device *device = tzone->devdata;
46 unsigned long long tmp;
47 acpi_status status;
48
49 status = acpi_evaluate_integer(device->handle, "_TMP", NULL, &tmp);
50 if (ACPI_FAILURE(status))
51 return -EIO;
52
53 *temp = DECI_KELVIN_TO_MILLI_CELSIUS(tmp, KELVIN_OFFSET);
54
55 return 0;
56}
57
58static int sys_get_trip_hyst(struct thermal_zone_device *tzone,
59 int trip, unsigned long *temp)
60{
61 struct acpi_device *device = tzone->devdata;
62 unsigned long long hyst;
63 acpi_status status;
64
65 status = acpi_evaluate_integer(device->handle, "GTSH", NULL, &hyst);
66 if (ACPI_FAILURE(status))
67 return -EIO;
68
69 /*
70 * Thermal hysteresis represents a temperature difference.
71 * Kelvin and Celsius have same degree size. So the
72 * conversion here between tenths of degree Kelvin unit
73 * and Milli-Celsius unit is just to multiply 100.
74 */
75 *temp = hyst * 100;
76
77 return 0;
78}
79
80static int sys_get_trip_temp(struct thermal_zone_device *tzone,
81 int trip, unsigned long *temp)
82{
83 struct acpi_device *device = tzone->devdata;
84 struct int3403_sensor *obj = acpi_driver_data(device);
85
86 if (trip == obj->crit_trip_id)
87 *temp = obj->crit_temp;
88 else if (trip == obj->psv_trip_id)
89 *temp = obj->psv_temp;
90 else {
91 /*
92 * get_trip_temp is a mandatory callback but
93 * PATx method doesn't return any value, so return
94 * cached value, which was last set from user space.
95 */
96 *temp = obj->thresholds[trip];
97 }
98
99 return 0;
100}
101
102static int sys_get_trip_type(struct thermal_zone_device *thermal,
103 int trip, enum thermal_trip_type *type)
104{
105 struct acpi_device *device = thermal->devdata;
106 struct int3403_sensor *obj = acpi_driver_data(device);
107
108 /* Mandatory callback, may not mean much here */
109 if (trip == obj->crit_trip_id)
110 *type = THERMAL_TRIP_CRITICAL;
111 else
112 *type = THERMAL_TRIP_PASSIVE;
113
114 return 0;
115}
116
117int sys_set_trip_temp(struct thermal_zone_device *tzone, int trip,
118 unsigned long temp)
119{
120 struct acpi_device *device = tzone->devdata;
121 acpi_status status;
122 char name[10];
123 int ret = 0;
124 struct int3403_sensor *obj = acpi_driver_data(device);
125
126 snprintf(name, sizeof(name), "PAT%d", trip);
127 if (acpi_has_method(device->handle, name)) {
128 status = acpi_execute_simple_method(device->handle, name,
129 MILLI_CELSIUS_TO_DECI_KELVIN(temp,
130 KELVIN_OFFSET));
131 if (ACPI_FAILURE(status))
132 ret = -EIO;
133 else
134 obj->thresholds[trip] = temp;
135 } else {
136 ret = -EIO;
137 dev_err(&device->dev, "sys_set_trip_temp: method not found\n");
138 }
139
140 return ret;
141}
142
143static struct thermal_zone_device_ops tzone_ops = {
144 .get_temp = sys_get_curr_temp,
145 .get_trip_temp = sys_get_trip_temp,
146 .get_trip_type = sys_get_trip_type,
147 .set_trip_temp = sys_set_trip_temp,
148 .get_trip_hyst = sys_get_trip_hyst,
149};
150
151static void acpi_thermal_notify(struct acpi_device *device, u32 event)
152{
153 struct int3403_sensor *obj;
154
155 if (!device)
156 return;
157
158 obj = acpi_driver_data(device);
159 if (!obj)
160 return;
161
162 switch (event) {
163 case INT3403_PERF_CHANGED_EVENT:
164 break;
165 case INT3403_THERMAL_EVENT:
166 thermal_zone_device_update(obj->tzone);
167 break;
168 default:
169 dev_err(&device->dev, "Unsupported event [0x%x]\n", event);
170 break;
171 }
172}
173
174static int sys_get_trip_crt(struct acpi_device *device, unsigned long *temp)
175{
176 unsigned long long crt;
177 acpi_status status;
178
179 status = acpi_evaluate_integer(device->handle, "_CRT", NULL, &crt);
180 if (ACPI_FAILURE(status))
181 return -EIO;
182
183 *temp = DECI_KELVIN_TO_MILLI_CELSIUS(crt, KELVIN_OFFSET);
184
185 return 0;
186}
187
188static int sys_get_trip_psv(struct acpi_device *device, unsigned long *temp)
189{
190 unsigned long long psv;
191 acpi_status status;
192
193 status = acpi_evaluate_integer(device->handle, "_PSV", NULL, &psv);
194 if (ACPI_FAILURE(status))
195 return -EIO;
196
197 *temp = DECI_KELVIN_TO_MILLI_CELSIUS(psv, KELVIN_OFFSET);
198
199 return 0;
200}
201
202static int acpi_int3403_add(struct acpi_device *device)
203{
204 int result = 0;
205 unsigned long long ptyp;
206 acpi_status status;
207 struct int3403_sensor *obj;
208 unsigned long long trip_cnt;
209 int trip_mask = 0;
210
211 if (!device)
212 return -EINVAL;
213
214 status = acpi_evaluate_integer(device->handle, "PTYP", NULL, &ptyp);
215 if (ACPI_FAILURE(status))
216 return -EINVAL;
217
218 if (ptyp != INT3403_TYPE_SENSOR)
219 return -EINVAL;
220
221 obj = devm_kzalloc(&device->dev, sizeof(*obj), GFP_KERNEL);
222 if (!obj)
223 return -ENOMEM;
224
225 device->driver_data = obj;
226
227 status = acpi_evaluate_integer(device->handle, "PATC", NULL,
228 &trip_cnt);
229 if (ACPI_FAILURE(status))
230 trip_cnt = 0;
231
232 if (trip_cnt) {
233 /* We have to cache, thresholds can't be readback */
234 obj->thresholds = devm_kzalloc(&device->dev,
235 sizeof(*obj->thresholds) * trip_cnt,
236 GFP_KERNEL);
237 if (!obj->thresholds)
238 return -ENOMEM;
239 trip_mask = BIT(trip_cnt) - 1;
240 }
241
242 obj->psv_trip_id = -1;
243 if (!sys_get_trip_psv(device, &obj->psv_temp))
244 obj->psv_trip_id = trip_cnt++;
245
246 obj->crit_trip_id = -1;
247 if (!sys_get_trip_crt(device, &obj->crit_temp))
248 obj->crit_trip_id = trip_cnt++;
249
250 obj->tzone = thermal_zone_device_register(acpi_device_bid(device),
251 trip_cnt, trip_mask, device, &tzone_ops,
252 NULL, 0, 0);
253 if (IS_ERR(obj->tzone)) {
254 result = PTR_ERR(obj->tzone);
255 return result;
256 }
257
258 strcpy(acpi_device_name(device), "INT3403");
259 strcpy(acpi_device_class(device), ACPI_INT3403_CLASS);
260
261 return 0;
262}
263
264static int acpi_int3403_remove(struct acpi_device *device)
265{
266 struct int3403_sensor *obj;
267
268 obj = acpi_driver_data(device);
269 thermal_zone_device_unregister(obj->tzone);
270
271 return 0;
272}
273
274ACPI_MODULE_NAME("int3403");
275static const struct acpi_device_id int3403_device_ids[] = {
276 {"INT3403", 0},
277 {"", 0},
278};
279MODULE_DEVICE_TABLE(acpi, int3403_device_ids);
280
281static struct acpi_driver acpi_int3403_driver = {
282 .name = "INT3403",
283 .class = ACPI_INT3403_CLASS,
284 .ids = int3403_device_ids,
285 .ops = {
286 .add = acpi_int3403_add,
287 .remove = acpi_int3403_remove,
288 .notify = acpi_thermal_notify,
289 },
290};
291
292module_acpi_driver(acpi_int3403_driver);
293
294MODULE_AUTHOR("Srinivas Pandruvada <srinivas.pandruvada@linux.intel.com>");
295MODULE_LICENSE("GPL v2");
296MODULE_DESCRIPTION("ACPI INT3403 thermal driver");
diff --git a/drivers/thermal/int340x_thermal/Makefile b/drivers/thermal/int340x_thermal/Makefile
new file mode 100644
index 000000000000..ffe40bffaf1a
--- /dev/null
+++ b/drivers/thermal/int340x_thermal/Makefile
@@ -0,0 +1,4 @@
1obj-$(CONFIG_INT340X_THERMAL) += int3400_thermal.o
2obj-$(CONFIG_INT340X_THERMAL) += int3402_thermal.o
3obj-$(CONFIG_INT340X_THERMAL) += int3403_thermal.o
4obj-$(CONFIG_ACPI_THERMAL_REL) += acpi_thermal_rel.o
diff --git a/drivers/thermal/int340x_thermal/acpi_thermal_rel.c b/drivers/thermal/int340x_thermal/acpi_thermal_rel.c
new file mode 100644
index 000000000000..0d8db808f0ae
--- /dev/null
+++ b/drivers/thermal/int340x_thermal/acpi_thermal_rel.c
@@ -0,0 +1,400 @@
1/* acpi_thermal_rel.c driver for exporting ACPI thermal relationship
2 *
3 * Copyright (c) 2014 Intel Corp
4 *
5 * This program is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 as published by
7 * the Free Software Foundation.
8 *
9 */
10
11/*
12 * Two functionalities included:
13 * 1. Export _TRT, _ART, via misc device interface to the userspace.
14 * 2. Provide parsing result to kernel drivers
15 *
16 */
17#include <linux/init.h>
18#include <linux/export.h>
19#include <linux/module.h>
20#include <linux/device.h>
21#include <linux/platform_device.h>
22#include <linux/io.h>
23#include <linux/acpi.h>
24#include <linux/uaccess.h>
25#include <linux/miscdevice.h>
26#include "acpi_thermal_rel.h"
27
28static acpi_handle acpi_thermal_rel_handle;
29static DEFINE_SPINLOCK(acpi_thermal_rel_chrdev_lock);
30static int acpi_thermal_rel_chrdev_count; /* #times opened */
31static int acpi_thermal_rel_chrdev_exclu; /* already open exclusive? */
32
33static int acpi_thermal_rel_open(struct inode *inode, struct file *file)
34{
35 spin_lock(&acpi_thermal_rel_chrdev_lock);
36 if (acpi_thermal_rel_chrdev_exclu ||
37 (acpi_thermal_rel_chrdev_count && (file->f_flags & O_EXCL))) {
38 spin_unlock(&acpi_thermal_rel_chrdev_lock);
39 return -EBUSY;
40 }
41
42 if (file->f_flags & O_EXCL)
43 acpi_thermal_rel_chrdev_exclu = 1;
44 acpi_thermal_rel_chrdev_count++;
45
46 spin_unlock(&acpi_thermal_rel_chrdev_lock);
47
48 return nonseekable_open(inode, file);
49}
50
51static int acpi_thermal_rel_release(struct inode *inode, struct file *file)
52{
53 spin_lock(&acpi_thermal_rel_chrdev_lock);
54 acpi_thermal_rel_chrdev_count--;
55 acpi_thermal_rel_chrdev_exclu = 0;
56 spin_unlock(&acpi_thermal_rel_chrdev_lock);
57
58 return 0;
59}
60
61/**
62 * acpi_parse_trt - Thermal Relationship Table _TRT for passive cooling
63 *
64 * @handle: ACPI handle of the device contains _TRT
65 * @art_count: the number of valid entries resulted from parsing _TRT
66 * @artp: pointer to pointer of array of art entries in parsing result
67 * @create_dev: whether to create platform devices for target and source
68 *
69 */
70int acpi_parse_trt(acpi_handle handle, int *trt_count, struct trt **trtp,
71 bool create_dev)
72{
73 acpi_status status;
74 int result = 0;
75 int i;
76 int nr_bad_entries = 0;
77 struct trt *trts;
78 struct acpi_device *adev;
79 union acpi_object *p;
80 struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
81 struct acpi_buffer element = { 0, NULL };
82 struct acpi_buffer trt_format = { sizeof("RRNNNNNN"), "RRNNNNNN" };
83
84 if (!acpi_has_method(handle, "_TRT"))
85 return 0;
86
87 status = acpi_evaluate_object(handle, "_TRT", NULL, &buffer);
88 if (ACPI_FAILURE(status))
89 return -ENODEV;
90
91 p = buffer.pointer;
92 if (!p || (p->type != ACPI_TYPE_PACKAGE)) {
93 pr_err("Invalid _TRT data\n");
94 result = -EFAULT;
95 goto end;
96 }
97
98 *trt_count = p->package.count;
99 trts = kzalloc(*trt_count * sizeof(struct trt), GFP_KERNEL);
100 if (!trts) {
101 result = -ENOMEM;
102 goto end;
103 }
104
105 for (i = 0; i < *trt_count; i++) {
106 struct trt *trt = &trts[i - nr_bad_entries];
107
108 element.length = sizeof(struct trt);
109 element.pointer = trt;
110
111 status = acpi_extract_package(&(p->package.elements[i]),
112 &trt_format, &element);
113 if (ACPI_FAILURE(status)) {
114 nr_bad_entries++;
115 pr_warn("_TRT package %d is invalid, ignored\n", i);
116 continue;
117 }
118 if (!create_dev)
119 continue;
120
121 result = acpi_bus_get_device(trt->source, &adev);
122 if (!result)
123 acpi_create_platform_device(adev);
124 else
125 pr_warn("Failed to get source ACPI device\n");
126
127 result = acpi_bus_get_device(trt->target, &adev);
128 if (!result)
129 acpi_create_platform_device(adev);
130 else
131 pr_warn("Failed to get target ACPI device\n");
132 }
133
134 *trtp = trts;
135 /* don't count bad entries */
136 *trt_count -= nr_bad_entries;
137end:
138 kfree(buffer.pointer);
139 return result;
140}
141EXPORT_SYMBOL(acpi_parse_trt);
142
143/**
144 * acpi_parse_art - Parse Active Relationship Table _ART
145 *
146 * @handle: ACPI handle of the device contains _ART
147 * @art_count: the number of valid entries resulted from parsing _ART
148 * @artp: pointer to pointer of array of art entries in parsing result
149 * @create_dev: whether to create platform devices for target and source
150 *
151 */
152int acpi_parse_art(acpi_handle handle, int *art_count, struct art **artp,
153 bool create_dev)
154{
155 acpi_status status;
156 int result = 0;
157 int i;
158 int nr_bad_entries = 0;
159 struct art *arts;
160 struct acpi_device *adev;
161 union acpi_object *p;
162 struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
163 struct acpi_buffer element = { 0, NULL };
164 struct acpi_buffer art_format = {
165 sizeof("RRNNNNNNNNNNN"), "RRNNNNNNNNNNN" };
166
167 if (!acpi_has_method(handle, "_ART"))
168 return 0;
169
170 status = acpi_evaluate_object(handle, "_ART", NULL, &buffer);
171 if (ACPI_FAILURE(status))
172 return -ENODEV;
173
174 p = buffer.pointer;
175 if (!p || (p->type != ACPI_TYPE_PACKAGE)) {
176 pr_err("Invalid _ART data\n");
177 result = -EFAULT;
178 goto end;
179 }
180
181 /* ignore p->package.elements[0], as this is _ART Revision field */
182 *art_count = p->package.count - 1;
183 arts = kzalloc(*art_count * sizeof(struct art), GFP_KERNEL);
184 if (!arts) {
185 result = -ENOMEM;
186 goto end;
187 }
188
189 for (i = 0; i < *art_count; i++) {
190 struct art *art = &arts[i - nr_bad_entries];
191
192 element.length = sizeof(struct art);
193 element.pointer = art;
194
195 status = acpi_extract_package(&(p->package.elements[i + 1]),
196 &art_format, &element);
197 if (ACPI_FAILURE(status)) {
198 pr_warn("_ART package %d is invalid, ignored", i);
199 nr_bad_entries++;
200 continue;
201 }
202 if (!create_dev)
203 continue;
204
205 if (art->source) {
206 result = acpi_bus_get_device(art->source, &adev);
207 if (!result)
208 acpi_create_platform_device(adev);
209 else
210 pr_warn("Failed to get source ACPI device\n");
211 }
212 if (art->target) {
213 result = acpi_bus_get_device(art->target, &adev);
214 if (!result)
215 acpi_create_platform_device(adev);
216 else
217 pr_warn("Failed to get source ACPI device\n");
218 }
219 }
220
221 *artp = arts;
222 /* don't count bad entries */
223 *art_count -= nr_bad_entries;
224end:
225 kfree(buffer.pointer);
226 return result;
227}
228EXPORT_SYMBOL(acpi_parse_art);
229
230
231/* get device name from acpi handle */
232static void get_single_name(acpi_handle handle, char *name)
233{
234 struct acpi_buffer buffer = {ACPI_ALLOCATE_BUFFER};
235
236 if (ACPI_FAILURE(acpi_get_name(handle, ACPI_SINGLE_NAME, &buffer)))
237 pr_warn("Failed get name from handle\n");
238 else {
239 memcpy(name, buffer.pointer, ACPI_NAME_SIZE);
240 kfree(buffer.pointer);
241 }
242}
243
244static int fill_art(char __user *ubuf)
245{
246 int i;
247 int ret;
248 int count;
249 int art_len;
250 struct art *arts = NULL;
251 union art_object *art_user;
252
253 ret = acpi_parse_art(acpi_thermal_rel_handle, &count, &arts, false);
254 if (ret)
255 goto free_art;
256 art_len = count * sizeof(union art_object);
257 art_user = kzalloc(art_len, GFP_KERNEL);
258 if (!art_user) {
259 ret = -ENOMEM;
260 goto free_art;
261 }
262 /* now fill in user art data */
263 for (i = 0; i < count; i++) {
264 /* userspace art needs device name instead of acpi reference */
265 get_single_name(arts[i].source, art_user[i].source_device);
266 get_single_name(arts[i].target, art_user[i].target_device);
267 /* copy the rest int data in addition to source and target */
268 memcpy(&art_user[i].weight, &arts[i].weight,
269 sizeof(u64) * (ACPI_NR_ART_ELEMENTS - 2));
270 }
271
272 if (copy_to_user(ubuf, art_user, art_len))
273 ret = -EFAULT;
274 kfree(art_user);
275free_art:
276 kfree(arts);
277 return ret;
278}
279
280static int fill_trt(char __user *ubuf)
281{
282 int i;
283 int ret;
284 int count;
285 int trt_len;
286 struct trt *trts = NULL;
287 union trt_object *trt_user;
288
289 ret = acpi_parse_trt(acpi_thermal_rel_handle, &count, &trts, false);
290 if (ret)
291 goto free_trt;
292 trt_len = count * sizeof(union trt_object);
293 trt_user = kzalloc(trt_len, GFP_KERNEL);
294 if (!trt_user) {
295 ret = -ENOMEM;
296 goto free_trt;
297 }
298 /* now fill in user trt data */
299 for (i = 0; i < count; i++) {
300 /* userspace trt needs device name instead of acpi reference */
301 get_single_name(trts[i].source, trt_user[i].source_device);
302 get_single_name(trts[i].target, trt_user[i].target_device);
303 trt_user[i].sample_period = trts[i].sample_period;
304 trt_user[i].influence = trts[i].influence;
305 }
306
307 if (copy_to_user(ubuf, trt_user, trt_len))
308 ret = -EFAULT;
309 kfree(trt_user);
310free_trt:
311 kfree(trts);
312 return ret;
313}
314
315static long acpi_thermal_rel_ioctl(struct file *f, unsigned int cmd,
316 unsigned long __arg)
317{
318 int ret = 0;
319 unsigned long length = 0;
320 unsigned long count = 0;
321 char __user *arg = (void __user *)__arg;
322 struct trt *trts;
323 struct art *arts;
324
325 switch (cmd) {
326 case ACPI_THERMAL_GET_TRT_COUNT:
327 ret = acpi_parse_trt(acpi_thermal_rel_handle, (int *)&count,
328 &trts, false);
329 kfree(trts);
330 if (!ret)
331 return put_user(count, (unsigned long __user *)__arg);
332 return ret;
333 case ACPI_THERMAL_GET_TRT_LEN:
334 ret = acpi_parse_trt(acpi_thermal_rel_handle, (int *)&count,
335 &trts, false);
336 kfree(trts);
337 length = count * sizeof(union trt_object);
338 if (!ret)
339 return put_user(length, (unsigned long __user *)__arg);
340 return ret;
341 case ACPI_THERMAL_GET_TRT:
342 return fill_trt(arg);
343 case ACPI_THERMAL_GET_ART_COUNT:
344 ret = acpi_parse_art(acpi_thermal_rel_handle, (int *)&count,
345 &arts, false);
346 kfree(arts);
347 if (!ret)
348 return put_user(count, (unsigned long __user *)__arg);
349 return ret;
350 case ACPI_THERMAL_GET_ART_LEN:
351 ret = acpi_parse_art(acpi_thermal_rel_handle, (int *)&count,
352 &arts, false);
353 kfree(arts);
354 length = count * sizeof(union art_object);
355 if (!ret)
356 return put_user(length, (unsigned long __user *)__arg);
357 return ret;
358
359 case ACPI_THERMAL_GET_ART:
360 return fill_art(arg);
361
362 default:
363 return -ENOTTY;
364 }
365}
366
367static const struct file_operations acpi_thermal_rel_fops = {
368 .owner = THIS_MODULE,
369 .open = acpi_thermal_rel_open,
370 .release = acpi_thermal_rel_release,
371 .unlocked_ioctl = acpi_thermal_rel_ioctl,
372 .llseek = no_llseek,
373};
374
375static struct miscdevice acpi_thermal_rel_misc_device = {
376 .minor = MISC_DYNAMIC_MINOR,
377 "acpi_thermal_rel",
378 &acpi_thermal_rel_fops
379};
380
381int acpi_thermal_rel_misc_device_add(acpi_handle handle)
382{
383 acpi_thermal_rel_handle = handle;
384
385 return misc_register(&acpi_thermal_rel_misc_device);
386}
387EXPORT_SYMBOL(acpi_thermal_rel_misc_device_add);
388
389int acpi_thermal_rel_misc_device_remove(acpi_handle handle)
390{
391 misc_deregister(&acpi_thermal_rel_misc_device);
392
393 return 0;
394}
395EXPORT_SYMBOL(acpi_thermal_rel_misc_device_remove);
396
397MODULE_AUTHOR("Zhang Rui <rui.zhang@intel.com>");
398MODULE_AUTHOR("Jacob Pan <jacob.jun.pan@intel.com");
399MODULE_DESCRIPTION("Intel acpi thermal rel misc dev driver");
400MODULE_LICENSE("GPL v2");
diff --git a/drivers/thermal/int340x_thermal/acpi_thermal_rel.h b/drivers/thermal/int340x_thermal/acpi_thermal_rel.h
new file mode 100644
index 000000000000..f00700bc9d79
--- /dev/null
+++ b/drivers/thermal/int340x_thermal/acpi_thermal_rel.h
@@ -0,0 +1,84 @@
1#ifndef __ACPI_ACPI_THERMAL_H
2#define __ACPI_ACPI_THERMAL_H
3
4#include <asm/ioctl.h>
5
6#define ACPI_THERMAL_MAGIC 's'
7
8#define ACPI_THERMAL_GET_TRT_LEN _IOR(ACPI_THERMAL_MAGIC, 1, unsigned long)
9#define ACPI_THERMAL_GET_ART_LEN _IOR(ACPI_THERMAL_MAGIC, 2, unsigned long)
10#define ACPI_THERMAL_GET_TRT_COUNT _IOR(ACPI_THERMAL_MAGIC, 3, unsigned long)
11#define ACPI_THERMAL_GET_ART_COUNT _IOR(ACPI_THERMAL_MAGIC, 4, unsigned long)
12
13#define ACPI_THERMAL_GET_TRT _IOR(ACPI_THERMAL_MAGIC, 5, unsigned long)
14#define ACPI_THERMAL_GET_ART _IOR(ACPI_THERMAL_MAGIC, 6, unsigned long)
15
16struct art {
17 acpi_handle source;
18 acpi_handle target;
19 u64 weight;
20 u64 ac0_max;
21 u64 ac1_max;
22 u64 ac2_max;
23 u64 ac3_max;
24 u64 ac4_max;
25 u64 ac5_max;
26 u64 ac6_max;
27 u64 ac7_max;
28 u64 ac8_max;
29 u64 ac9_max;
30} __packed;
31
32struct trt {
33 acpi_handle source;
34 acpi_handle target;
35 u64 influence;
36 u64 sample_period;
37 u64 reverved1;
38 u64 reverved2;
39 u64 reverved3;
40 u64 reverved4;
41} __packed;
42
43#define ACPI_NR_ART_ELEMENTS 13
44/* for usrspace */
45union art_object {
46 struct {
47 char source_device[8]; /* ACPI single name */
48 char target_device[8]; /* ACPI single name */
49 u64 weight;
50 u64 ac0_max_level;
51 u64 ac1_max_level;
52 u64 ac2_max_level;
53 u64 ac3_max_level;
54 u64 ac4_max_level;
55 u64 ac5_max_level;
56 u64 ac6_max_level;
57 u64 ac7_max_level;
58 u64 ac8_max_level;
59 u64 ac9_max_level;
60 };
61 u64 __data[ACPI_NR_ART_ELEMENTS];
62};
63
64union trt_object {
65 struct {
66 char source_device[8]; /* ACPI single name */
67 char target_device[8]; /* ACPI single name */
68 u64 influence;
69 u64 sample_period;
70 u64 reserved[4];
71 };
72 u64 __data[8];
73};
74
75#ifdef __KERNEL__
76int acpi_thermal_rel_misc_device_add(acpi_handle handle);
77int acpi_thermal_rel_misc_device_remove(acpi_handle handle);
78int acpi_parse_art(acpi_handle handle, int *art_count, struct art **arts,
79 bool create_dev);
80int acpi_parse_trt(acpi_handle handle, int *trt_count, struct trt **trts,
81 bool create_dev);
82#endif
83
84#endif /* __ACPI_ACPI_THERMAL_H */
diff --git a/drivers/thermal/int340x_thermal/int3400_thermal.c b/drivers/thermal/int340x_thermal/int3400_thermal.c
new file mode 100644
index 000000000000..edc1cce117ba
--- /dev/null
+++ b/drivers/thermal/int340x_thermal/int3400_thermal.c
@@ -0,0 +1,271 @@
1/*
2 * INT3400 thermal driver
3 *
4 * Copyright (C) 2014, Intel Corporation
5 * Authors: Zhang Rui <rui.zhang@intel.com>
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License version 2 as
9 * published by the Free Software Foundation.
10 *
11 */
12
13#include <linux/module.h>
14#include <linux/platform_device.h>
15#include <linux/acpi.h>
16#include <linux/thermal.h>
17#include "acpi_thermal_rel.h"
18
19enum int3400_thermal_uuid {
20 INT3400_THERMAL_PASSIVE_1,
21 INT3400_THERMAL_PASSIVE_2,
22 INT3400_THERMAL_ACTIVE,
23 INT3400_THERMAL_CRITICAL,
24 INT3400_THERMAL_COOLING_MODE,
25 INT3400_THERMAL_MAXIMUM_UUID,
26};
27
28static u8 *int3400_thermal_uuids[INT3400_THERMAL_MAXIMUM_UUID] = {
29 "42A441D6-AE6A-462b-A84B-4A8CE79027D3",
30 "9E04115A-AE87-4D1C-9500-0F3E340BFE75",
31 "3A95C389-E4B8-4629-A526-C52C88626BAE",
32 "97C68AE7-15FA-499c-B8C9-5DA81D606E0A",
33 "16CAF1B7-DD38-40ed-B1C1-1B8A1913D531",
34};
35
36struct int3400_thermal_priv {
37 struct acpi_device *adev;
38 struct thermal_zone_device *thermal;
39 int mode;
40 int art_count;
41 struct art *arts;
42 int trt_count;
43 struct trt *trts;
44 u8 uuid_bitmap;
45 int rel_misc_dev_res;
46};
47
48static int int3400_thermal_get_uuids(struct int3400_thermal_priv *priv)
49{
50 struct acpi_buffer buf = { ACPI_ALLOCATE_BUFFER, NULL};
51 union acpi_object *obja, *objb;
52 int i, j;
53 int result = 0;
54 acpi_status status;
55
56 status = acpi_evaluate_object(priv->adev->handle, "IDSP", NULL, &buf);
57 if (ACPI_FAILURE(status))
58 return -ENODEV;
59
60 obja = (union acpi_object *)buf.pointer;
61 if (obja->type != ACPI_TYPE_PACKAGE) {
62 result = -EINVAL;
63 goto end;
64 }
65
66 for (i = 0; i < obja->package.count; i++) {
67 objb = &obja->package.elements[i];
68 if (objb->type != ACPI_TYPE_BUFFER) {
69 result = -EINVAL;
70 goto end;
71 }
72
73 /* UUID must be 16 bytes */
74 if (objb->buffer.length != 16) {
75 result = -EINVAL;
76 goto end;
77 }
78
79 for (j = 0; j < INT3400_THERMAL_MAXIMUM_UUID; j++) {
80 u8 uuid[16];
81
82 acpi_str_to_uuid(int3400_thermal_uuids[j], uuid);
83 if (!strncmp(uuid, objb->buffer.pointer, 16)) {
84 priv->uuid_bitmap |= (1 << j);
85 break;
86 }
87 }
88 }
89
90end:
91 kfree(buf.pointer);
92 return result;
93}
94
95static int int3400_thermal_run_osc(acpi_handle handle,
96 enum int3400_thermal_uuid uuid, bool enable)
97{
98 u32 ret, buf[2];
99 acpi_status status;
100 int result = 0;
101 struct acpi_osc_context context = {
102 .uuid_str = int3400_thermal_uuids[uuid],
103 .rev = 1,
104 .cap.length = 8,
105 };
106
107 buf[OSC_QUERY_DWORD] = 0;
108 buf[OSC_SUPPORT_DWORD] = enable;
109
110 context.cap.pointer = buf;
111
112 status = acpi_run_osc(handle, &context);
113 if (ACPI_SUCCESS(status)) {
114 ret = *((u32 *)(context.ret.pointer + 4));
115 if (ret != enable)
116 result = -EPERM;
117 } else
118 result = -EPERM;
119
120 kfree(context.ret.pointer);
121 return result;
122}
123
124static int int3400_thermal_get_temp(struct thermal_zone_device *thermal,
125 unsigned long *temp)
126{
127 *temp = 20 * 1000; /* faked temp sensor with 20C */
128 return 0;
129}
130
131static int int3400_thermal_get_mode(struct thermal_zone_device *thermal,
132 enum thermal_device_mode *mode)
133{
134 struct int3400_thermal_priv *priv = thermal->devdata;
135
136 if (!priv)
137 return -EINVAL;
138
139 *mode = priv->mode;
140
141 return 0;
142}
143
144static int int3400_thermal_set_mode(struct thermal_zone_device *thermal,
145 enum thermal_device_mode mode)
146{
147 struct int3400_thermal_priv *priv = thermal->devdata;
148 bool enable;
149 int result = 0;
150
151 if (!priv)
152 return -EINVAL;
153
154 if (mode == THERMAL_DEVICE_ENABLED)
155 enable = true;
156 else if (mode == THERMAL_DEVICE_DISABLED)
157 enable = false;
158 else
159 return -EINVAL;
160
161 if (enable != priv->mode) {
162 priv->mode = enable;
163 /* currently, only PASSIVE COOLING is supported */
164 result = int3400_thermal_run_osc(priv->adev->handle,
165 INT3400_THERMAL_PASSIVE_1, enable);
166 }
167 return result;
168}
169
170static struct thermal_zone_device_ops int3400_thermal_ops = {
171 .get_temp = int3400_thermal_get_temp,
172};
173
174static struct thermal_zone_params int3400_thermal_params = {
175 .governor_name = "user_space",
176 .no_hwmon = true,
177};
178
179static int int3400_thermal_probe(struct platform_device *pdev)
180{
181 struct acpi_device *adev = ACPI_COMPANION(&pdev->dev);
182 struct int3400_thermal_priv *priv;
183 int result;
184
185 if (!adev)
186 return -ENODEV;
187
188 priv = kzalloc(sizeof(struct int3400_thermal_priv), GFP_KERNEL);
189 if (!priv)
190 return -ENOMEM;
191
192 priv->adev = adev;
193
194 result = int3400_thermal_get_uuids(priv);
195 if (result)
196 goto free_priv;
197
198 result = acpi_parse_art(priv->adev->handle, &priv->art_count,
199 &priv->arts, true);
200 if (result)
201 goto free_priv;
202
203
204 result = acpi_parse_trt(priv->adev->handle, &priv->trt_count,
205 &priv->trts, true);
206 if (result)
207 goto free_art;
208
209 platform_set_drvdata(pdev, priv);
210
211 if (priv->uuid_bitmap & 1 << INT3400_THERMAL_PASSIVE_1) {
212 int3400_thermal_ops.get_mode = int3400_thermal_get_mode;
213 int3400_thermal_ops.set_mode = int3400_thermal_set_mode;
214 }
215 priv->thermal = thermal_zone_device_register("INT3400 Thermal", 0, 0,
216 priv, &int3400_thermal_ops,
217 &int3400_thermal_params, 0, 0);
218 if (IS_ERR(priv->thermal)) {
219 result = PTR_ERR(priv->thermal);
220 goto free_trt;
221 }
222
223 priv->rel_misc_dev_res = acpi_thermal_rel_misc_device_add(
224 priv->adev->handle);
225
226 return 0;
227free_trt:
228 kfree(priv->trts);
229free_art:
230 kfree(priv->arts);
231free_priv:
232 kfree(priv);
233 return result;
234}
235
236static int int3400_thermal_remove(struct platform_device *pdev)
237{
238 struct int3400_thermal_priv *priv = platform_get_drvdata(pdev);
239
240 if (!priv->rel_misc_dev_res)
241 acpi_thermal_rel_misc_device_remove(priv->adev->handle);
242
243 thermal_zone_device_unregister(priv->thermal);
244 kfree(priv->trts);
245 kfree(priv->arts);
246 kfree(priv);
247 return 0;
248}
249
250static const struct acpi_device_id int3400_thermal_match[] = {
251 {"INT3400", 0},
252 {}
253};
254
255MODULE_DEVICE_TABLE(acpi, int3400_thermal_match);
256
257static struct platform_driver int3400_thermal_driver = {
258 .probe = int3400_thermal_probe,
259 .remove = int3400_thermal_remove,
260 .driver = {
261 .name = "int3400 thermal",
262 .owner = THIS_MODULE,
263 .acpi_match_table = ACPI_PTR(int3400_thermal_match),
264 },
265};
266
267module_platform_driver(int3400_thermal_driver);
268
269MODULE_DESCRIPTION("INT3400 Thermal driver");
270MODULE_AUTHOR("Zhang Rui <rui.zhang@intel.com>");
271MODULE_LICENSE("GPL");
diff --git a/drivers/thermal/int340x_thermal/int3402_thermal.c b/drivers/thermal/int340x_thermal/int3402_thermal.c
new file mode 100644
index 000000000000..a5d08c14ba24
--- /dev/null
+++ b/drivers/thermal/int340x_thermal/int3402_thermal.c
@@ -0,0 +1,242 @@
1/*
2 * INT3402 thermal driver for memory temperature reporting
3 *
4 * Copyright (C) 2014, Intel Corporation
5 * Authors: Aaron Lu <aaron.lu@intel.com>
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License version 2 as
9 * published by the Free Software Foundation.
10 *
11 */
12
13#include <linux/module.h>
14#include <linux/platform_device.h>
15#include <linux/acpi.h>
16#include <linux/thermal.h>
17
18#define ACPI_ACTIVE_COOLING_MAX_NR 10
19
20struct active_trip {
21 unsigned long temp;
22 int id;
23 bool valid;
24};
25
26struct 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;
37};
38
39static int int3402_thermal_get_zone_temp(struct thermal_zone_device *zone,
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{
59 struct int3402_thermal_data *d = zone->devdata;
60 int i;
61
62 if (trip < d->aux_trip_nr)
63 *temp = d->aux_trips[trip];
64 else if (trip == d->crt_trip_id)
65 *temp = d->crt_temp;
66 else if (trip == d->psv_trip_id)
67 *temp = d->psv_temp;
68 else if (trip == d->hot_trip_id)
69 *temp = d->hot_temp;
70 else {
71 for (i = 0; i < ACPI_ACTIVE_COOLING_MAX_NR; i++) {
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 }
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}
154
155static int int3402_thermal_probe(struct platform_device *pdev)
156{
157 struct acpi_device *adev = ACPI_COMPANION(&pdev->dev);
158 struct int3402_thermal_data *d;
159 struct thermal_zone_device *zone;
160 acpi_status status;
161 unsigned long long trip_cnt;
162 int trip_mask = 0, i;
163
164 if (!acpi_has_method(adev->handle, "_TMP"))
165 return -ENODEV;
166
167 d = devm_kzalloc(&pdev->dev, sizeof(*d), GFP_KERNEL);
168 if (!d)
169 return -ENOMEM;
170
171 status = acpi_evaluate_integer(adev->handle, "PATC", NULL, &trip_cnt);
172 if (ACPI_FAILURE(status))
173 trip_cnt = 0;
174 else {
175 d->aux_trips = devm_kzalloc(&pdev->dev,
176 sizeof(*d->aux_trips) * trip_cnt, GFP_KERNEL);
177 if (!d->aux_trips)
178 return -ENOMEM;
179 trip_mask = trip_cnt - 1;
180 d->handle = adev->handle;
181 d->aux_trip_nr = trip_cnt;
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 }
201
202 zone = thermal_zone_device_register(acpi_device_bid(adev), trip_cnt,
203 trip_mask, 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
211 return 0;
212}
213
214static int int3402_thermal_remove(struct platform_device *pdev)
215{
216 struct thermal_zone_device *zone = platform_get_drvdata(pdev);
217
218 thermal_zone_device_unregister(zone);
219 return 0;
220}
221
222static const struct acpi_device_id int3402_thermal_match[] = {
223 {"INT3402", 0},
224 {}
225};
226
227MODULE_DEVICE_TABLE(acpi, int3402_thermal_match);
228
229static struct platform_driver int3402_thermal_driver = {
230 .probe = int3402_thermal_probe,
231 .remove = int3402_thermal_remove,
232 .driver = {
233 .name = "int3402 thermal",
234 .owner = THIS_MODULE,
235 .acpi_match_table = int3402_thermal_match,
236 },
237};
238
239module_platform_driver(int3402_thermal_driver);
240
241MODULE_DESCRIPTION("INT3402 Thermal driver");
242MODULE_LICENSE("GPL");
diff --git a/drivers/thermal/int340x_thermal/int3403_thermal.c b/drivers/thermal/int340x_thermal/int3403_thermal.c
new file mode 100644
index 000000000000..d20dba986f0f
--- /dev/null
+++ b/drivers/thermal/int340x_thermal/int3403_thermal.c
@@ -0,0 +1,477 @@
1/*
2 * ACPI INT3403 thermal driver
3 * Copyright (c) 2013, 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/types.h>
19#include <linux/acpi.h>
20#include <linux/thermal.h>
21#include <linux/platform_device.h>
22
23#define INT3403_TYPE_SENSOR 0x03
24#define INT3403_TYPE_CHARGER 0x0B
25#define INT3403_TYPE_BATTERY 0x0C
26#define INT3403_PERF_CHANGED_EVENT 0x80
27#define INT3403_THERMAL_EVENT 0x90
28
29#define DECI_KELVIN_TO_MILLI_CELSIUS(t, off) (((t) - (off)) * 100)
30#define KELVIN_OFFSET 2732
31#define MILLI_CELSIUS_TO_DECI_KELVIN(t, off) (((t) / 100) + (off))
32
33struct int3403_sensor {
34 struct thermal_zone_device *tzone;
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};
42
43struct int3403_performance_state {
44 u64 performance;
45 u64 power;
46 u64 latency;
47 u64 linear;
48 u64 control;
49 u64 raw_performace;
50 char *raw_unit;
51 int reserved;
52};
53
54struct int3403_cdev {
55 struct thermal_cooling_device *cdev;
56 unsigned long max_state;
57};
58
59struct int3403_priv {
60 struct platform_device *pdev;
61 struct acpi_device *adev;
62 unsigned long long type;
63 void *priv;
64};
65
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 *temp = DECI_KELVIN_TO_MILLI_CELSIUS(hyst, KELVIN_OFFSET);
96
97 return 0;
98}
99
100static int sys_get_trip_temp(struct thermal_zone_device *tzone,
101 int trip, unsigned long *temp)
102{
103 struct int3403_priv *priv = tzone->devdata;
104 struct int3403_sensor *obj = priv->priv;
105
106 if (priv->type != INT3403_TYPE_SENSOR || !obj)
107 return -EINVAL;
108
109 if (trip == obj->crit_trip_id)
110 *temp = obj->crit_temp;
111 else if (trip == obj->psv_trip_id)
112 *temp = obj->psv_temp;
113 else {
114 /*
115 * get_trip_temp is a mandatory callback but
116 * PATx method doesn't return any value, so return
117 * cached value, which was last set from user space
118 */
119 *temp = obj->thresholds[trip];
120 }
121
122 return 0;
123}
124
125static int sys_get_trip_type(struct thermal_zone_device *thermal,
126 int trip, enum thermal_trip_type *type)
127{
128 struct int3403_priv *priv = thermal->devdata;
129 struct int3403_sensor *obj = priv->priv;
130
131 /* Mandatory callback, may not mean much here */
132 if (trip == obj->crit_trip_id)
133 *type = THERMAL_TRIP_CRITICAL;
134 else
135 *type = THERMAL_TRIP_PASSIVE;
136
137 return 0;
138}
139
140int sys_set_trip_temp(struct thermal_zone_device *tzone, int trip,
141 unsigned long temp)
142{
143 struct int3403_priv *priv = tzone->devdata;
144 struct acpi_device *device = priv->adev;
145 struct int3403_sensor *obj = priv->priv;
146 acpi_status status;
147 char name[10];
148 int ret = 0;
149
150 snprintf(name, sizeof(name), "PAT%d", trip);
151 if (acpi_has_method(device->handle, name)) {
152 status = acpi_execute_simple_method(device->handle, name,
153 MILLI_CELSIUS_TO_DECI_KELVIN(temp,
154 KELVIN_OFFSET));
155 if (ACPI_FAILURE(status))
156 ret = -EIO;
157 else
158 obj->thresholds[trip] = temp;
159 } else {
160 ret = -EIO;
161 dev_err(&device->dev, "sys_set_trip_temp: method not found\n");
162 }
163
164 return ret;
165}
166
167static struct thermal_zone_device_ops tzone_ops = {
168 .get_temp = sys_get_curr_temp,
169 .get_trip_temp = sys_get_trip_temp,
170 .get_trip_type = sys_get_trip_type,
171 .set_trip_temp = sys_set_trip_temp,
172 .get_trip_hyst = sys_get_trip_hyst,
173};
174
175static struct thermal_zone_params int3403_thermal_params = {
176 .governor_name = "user_space",
177 .no_hwmon = true,
178};
179
180static void int3403_notify(acpi_handle handle,
181 u32 event, void *data)
182{
183 struct int3403_priv *priv = data;
184 struct int3403_sensor *obj;
185
186 if (!priv)
187 return;
188
189 obj = priv->priv;
190 if (priv->type != INT3403_TYPE_SENSOR || !obj)
191 return;
192
193 switch (event) {
194 case INT3403_PERF_CHANGED_EVENT:
195 break;
196 case INT3403_THERMAL_EVENT:
197 thermal_zone_device_update(obj->tzone);
198 break;
199 default:
200 dev_err(&priv->pdev->dev, "Unsupported event [0x%x]\n", event);
201 break;
202 }
203}
204
205static int sys_get_trip_crt(struct acpi_device *device, unsigned long *temp)
206{
207 unsigned long long crt;
208 acpi_status status;
209
210 status = acpi_evaluate_integer(device->handle, "_CRT", NULL, &crt);
211 if (ACPI_FAILURE(status))
212 return -EIO;
213
214 *temp = DECI_KELVIN_TO_MILLI_CELSIUS(crt, KELVIN_OFFSET);
215
216 return 0;
217}
218
219static int sys_get_trip_psv(struct acpi_device *device, unsigned long *temp)
220{
221 unsigned long long psv;
222 acpi_status status;
223
224 status = acpi_evaluate_integer(device->handle, "_PSV", NULL, &psv);
225 if (ACPI_FAILURE(status))
226 return -EIO;
227
228 *temp = DECI_KELVIN_TO_MILLI_CELSIUS(psv, KELVIN_OFFSET);
229
230 return 0;
231}
232
233static int int3403_sensor_add(struct int3403_priv *priv)
234{
235 int result = 0;
236 acpi_status status;
237 struct int3403_sensor *obj;
238 unsigned long long trip_cnt;
239 int trip_mask = 0;
240
241 obj = devm_kzalloc(&priv->pdev->dev, sizeof(*obj), GFP_KERNEL);
242 if (!obj)
243 return -ENOMEM;
244
245 priv->priv = obj;
246
247 status = acpi_evaluate_integer(priv->adev->handle, "PATC", NULL,
248 &trip_cnt);
249 if (ACPI_FAILURE(status))
250 trip_cnt = 0;
251
252 if (trip_cnt) {
253 /* We have to cache, thresholds can't be readback */
254 obj->thresholds = devm_kzalloc(&priv->pdev->dev,
255 sizeof(*obj->thresholds) * trip_cnt,
256 GFP_KERNEL);
257 if (!obj->thresholds) {
258 result = -ENOMEM;
259 goto err_free_obj;
260 }
261 trip_mask = BIT(trip_cnt) - 1;
262 }
263
264 obj->psv_trip_id = -1;
265 if (!sys_get_trip_psv(priv->adev, &obj->psv_temp))
266 obj->psv_trip_id = trip_cnt++;
267
268 obj->crit_trip_id = -1;
269 if (!sys_get_trip_crt(priv->adev, &obj->crit_temp))
270 obj->crit_trip_id = trip_cnt++;
271
272 obj->tzone = thermal_zone_device_register(acpi_device_bid(priv->adev),
273 trip_cnt, trip_mask, priv, &tzone_ops,
274 &int3403_thermal_params, 0, 0);
275 if (IS_ERR(obj->tzone)) {
276 result = PTR_ERR(obj->tzone);
277 obj->tzone = NULL;
278 goto err_free_obj;
279 }
280
281 result = acpi_install_notify_handler(priv->adev->handle,
282 ACPI_DEVICE_NOTIFY, int3403_notify,
283 (void *)priv);
284 if (result)
285 goto err_free_obj;
286
287 return 0;
288
289 err_free_obj:
290 if (obj->tzone)
291 thermal_zone_device_unregister(obj->tzone);
292 return result;
293}
294
295static int int3403_sensor_remove(struct int3403_priv *priv)
296{
297 struct int3403_sensor *obj = priv->priv;
298
299 thermal_zone_device_unregister(obj->tzone);
300 return 0;
301}
302
303/* INT3403 Cooling devices */
304static int int3403_get_max_state(struct thermal_cooling_device *cdev,
305 unsigned long *state)
306{
307 struct int3403_priv *priv = cdev->devdata;
308 struct int3403_cdev *obj = priv->priv;
309
310 *state = obj->max_state;
311 return 0;
312}
313
314static int int3403_get_cur_state(struct thermal_cooling_device *cdev,
315 unsigned long *state)
316{
317 struct int3403_priv *priv = cdev->devdata;
318 unsigned long long level;
319 acpi_status status;
320
321 status = acpi_evaluate_integer(priv->adev->handle, "PPPC", NULL, &level);
322 if (ACPI_SUCCESS(status)) {
323 *state = level;
324 return 0;
325 } else
326 return -EINVAL;
327}
328
329static int
330int3403_set_cur_state(struct thermal_cooling_device *cdev, unsigned long state)
331{
332 struct int3403_priv *priv = cdev->devdata;
333 acpi_status status;
334
335 status = acpi_execute_simple_method(priv->adev->handle, "SPPC", state);
336 if (ACPI_SUCCESS(status))
337 return 0;
338 else
339 return -EINVAL;
340}
341
342static const struct thermal_cooling_device_ops int3403_cooling_ops = {
343 .get_max_state = int3403_get_max_state,
344 .get_cur_state = int3403_get_cur_state,
345 .set_cur_state = int3403_set_cur_state,
346};
347
348static int int3403_cdev_add(struct int3403_priv *priv)
349{
350 int result = 0;
351 acpi_status status;
352 struct int3403_cdev *obj;
353 struct acpi_buffer buf = { ACPI_ALLOCATE_BUFFER, NULL };
354 union acpi_object *p;
355
356 obj = devm_kzalloc(&priv->pdev->dev, sizeof(*obj), GFP_KERNEL);
357 if (!obj)
358 return -ENOMEM;
359
360 status = acpi_evaluate_object(priv->adev->handle, "PPSS", NULL, &buf);
361 if (ACPI_FAILURE(status))
362 return -ENODEV;
363
364 p = buf.pointer;
365 if (!p || (p->type != ACPI_TYPE_PACKAGE)) {
366 printk(KERN_WARNING "Invalid PPSS data\n");
367 return -EFAULT;
368 }
369
370 obj->max_state = p->package.count - 1;
371 obj->cdev =
372 thermal_cooling_device_register(acpi_device_bid(priv->adev),
373 priv, &int3403_cooling_ops);
374 if (IS_ERR(obj->cdev))
375 result = PTR_ERR(obj->cdev);
376
377 priv->priv = obj;
378
379 /* TODO: add ACPI notification support */
380
381 return result;
382}
383
384static int int3403_cdev_remove(struct int3403_priv *priv)
385{
386 struct int3403_cdev *obj = priv->priv;
387
388 thermal_cooling_device_unregister(obj->cdev);
389 return 0;
390}
391
392static int int3403_add(struct platform_device *pdev)
393{
394 struct int3403_priv *priv;
395 int result = 0;
396 acpi_status status;
397
398 priv = devm_kzalloc(&pdev->dev, sizeof(struct int3403_priv),
399 GFP_KERNEL);
400 if (!priv)
401 return -ENOMEM;
402
403 priv->pdev = pdev;
404 priv->adev = ACPI_COMPANION(&(pdev->dev));
405 if (!priv->adev) {
406 result = -EINVAL;
407 goto err;
408 }
409
410 status = acpi_evaluate_integer(priv->adev->handle, "PTYP",
411 NULL, &priv->type);
412 if (ACPI_FAILURE(status)) {
413 result = -EINVAL;
414 goto err;
415 }
416
417 platform_set_drvdata(pdev, priv);
418 switch (priv->type) {
419 case INT3403_TYPE_SENSOR:
420 result = int3403_sensor_add(priv);
421 break;
422 case INT3403_TYPE_CHARGER:
423 case INT3403_TYPE_BATTERY:
424 result = int3403_cdev_add(priv);
425 break;
426 default:
427 result = -EINVAL;
428 }
429
430 if (result)
431 goto err;
432 return result;
433
434err:
435 return result;
436}
437
438static int int3403_remove(struct platform_device *pdev)
439{
440 struct int3403_priv *priv = platform_get_drvdata(pdev);
441
442 switch (priv->type) {
443 case INT3403_TYPE_SENSOR:
444 int3403_sensor_remove(priv);
445 break;
446 case INT3403_TYPE_CHARGER:
447 case INT3403_TYPE_BATTERY:
448 int3403_cdev_remove(priv);
449 break;
450 default:
451 break;
452 }
453
454 return 0;
455}
456
457static const struct acpi_device_id int3403_device_ids[] = {
458 {"INT3403", 0},
459 {"", 0},
460};
461MODULE_DEVICE_TABLE(acpi, int3403_device_ids);
462
463static struct platform_driver int3403_driver = {
464 .probe = int3403_add,
465 .remove = int3403_remove,
466 .driver = {
467 .name = "int3403 thermal",
468 .owner = THIS_MODULE,
469 .acpi_match_table = int3403_device_ids,
470 },
471};
472
473module_platform_driver(int3403_driver);
474
475MODULE_AUTHOR("Srinivas Pandruvada <srinivas.pandruvada@linux.intel.com>");
476MODULE_LICENSE("GPL v2");
477MODULE_DESCRIPTION("ACPI INT3403 thermal driver");
diff --git a/drivers/thermal/of-thermal.c b/drivers/thermal/of-thermal.c
index 4b2b999b7611..f8eb625b8400 100644
--- a/drivers/thermal/of-thermal.c
+++ b/drivers/thermal/of-thermal.c
@@ -401,6 +401,10 @@ thermal_zone_of_sensor_register(struct device *dev, int sensor_id,
401 struct of_phandle_args sensor_specs; 401 struct of_phandle_args sensor_specs;
402 int ret, id; 402 int ret, id;
403 403
404 /* Check whether child is enabled or not */
405 if (!of_device_is_available(child))
406 continue;
407
404 /* For now, thermal framework supports only 1 sensor per zone */ 408 /* For now, thermal framework supports only 1 sensor per zone */
405 ret = of_parse_phandle_with_args(child, "thermal-sensors", 409 ret = of_parse_phandle_with_args(child, "thermal-sensors",
406 "#thermal-sensor-cells", 410 "#thermal-sensor-cells",
@@ -771,6 +775,10 @@ int __init of_parse_thermal_zones(void)
771 struct thermal_zone_device *zone; 775 struct thermal_zone_device *zone;
772 struct thermal_zone_params *tzp; 776 struct thermal_zone_params *tzp;
773 777
778 /* Check whether child is enabled or not */
779 if (!of_device_is_available(child))
780 continue;
781
774 tz = thermal_of_build_thermal_zone(child); 782 tz = thermal_of_build_thermal_zone(child);
775 if (IS_ERR(tz)) { 783 if (IS_ERR(tz)) {
776 pr_err("failed to build thermal zone %s: %ld\n", 784 pr_err("failed to build thermal zone %s: %ld\n",
@@ -838,6 +846,10 @@ void of_thermal_destroy_zones(void)
838 for_each_child_of_node(np, child) { 846 for_each_child_of_node(np, child) {
839 struct thermal_zone_device *zone; 847 struct thermal_zone_device *zone;
840 848
849 /* Check whether child is enabled or not */
850 if (!of_device_is_available(child))
851 continue;
852
841 zone = thermal_zone_get_zone_by_name(child->name); 853 zone = thermal_zone_get_zone_by_name(child->name);
842 if (IS_ERR(zone)) 854 if (IS_ERR(zone))
843 continue; 855 continue;
diff --git a/drivers/thermal/step_wise.c b/drivers/thermal/step_wise.c
index f251521baaa2..fdd1f523a1ed 100644
--- a/drivers/thermal/step_wise.c
+++ b/drivers/thermal/step_wise.c
@@ -23,6 +23,7 @@
23 */ 23 */
24 24
25#include <linux/thermal.h> 25#include <linux/thermal.h>
26#include <trace/events/thermal.h>
26 27
27#include "thermal_core.h" 28#include "thermal_core.h"
28 29
@@ -76,7 +77,7 @@ static unsigned long get_target_state(struct thermal_instance *instance,
76 next_target = instance->upper; 77 next_target = instance->upper;
77 break; 78 break;
78 case THERMAL_TREND_DROPPING: 79 case THERMAL_TREND_DROPPING:
79 if (cur_state == instance->lower) { 80 if (cur_state <= instance->lower) {
80 if (!throttle) 81 if (!throttle)
81 next_target = THERMAL_NO_TARGET; 82 next_target = THERMAL_NO_TARGET;
82 } else { 83 } else {
@@ -129,8 +130,10 @@ static void thermal_zone_trip_update(struct thermal_zone_device *tz, int trip)
129 130
130 trend = get_tz_trend(tz, trip); 131 trend = get_tz_trend(tz, trip);
131 132
132 if (tz->temperature >= trip_temp) 133 if (tz->temperature >= trip_temp) {
133 throttle = true; 134 throttle = true;
135 trace_thermal_zone_trip(tz, trip, trip_type);
136 }
134 137
135 dev_dbg(&tz->device, "Trip%d[type=%d,temp=%ld]:trend=%d,throttle=%d\n", 138 dev_dbg(&tz->device, "Trip%d[type=%d,temp=%ld]:trend=%d,throttle=%d\n",
136 trip, trip_type, trip_temp, trend, throttle); 139 trip, trip_type, trip_temp, trend, throttle);
diff --git a/drivers/thermal/thermal_core.c b/drivers/thermal/thermal_core.c
index 1e23f4f8d2c2..9bf10aa6069b 100644
--- a/drivers/thermal/thermal_core.c
+++ b/drivers/thermal/thermal_core.c
@@ -38,6 +38,9 @@
38#include <net/netlink.h> 38#include <net/netlink.h>
39#include <net/genetlink.h> 39#include <net/genetlink.h>
40 40
41#define CREATE_TRACE_POINTS
42#include <trace/events/thermal.h>
43
41#include "thermal_core.h" 44#include "thermal_core.h"
42#include "thermal_hwmon.h" 45#include "thermal_hwmon.h"
43 46
@@ -368,6 +371,8 @@ static void handle_critical_trips(struct thermal_zone_device *tz,
368 if (tz->temperature < trip_temp) 371 if (tz->temperature < trip_temp)
369 return; 372 return;
370 373
374 trace_thermal_zone_trip(tz, trip, trip_type);
375
371 if (tz->ops->notify) 376 if (tz->ops->notify)
372 tz->ops->notify(tz, trip, trip_type); 377 tz->ops->notify(tz, trip, trip_type);
373 378
@@ -463,6 +468,7 @@ static void update_temperature(struct thermal_zone_device *tz)
463 tz->temperature = temp; 468 tz->temperature = temp;
464 mutex_unlock(&tz->lock); 469 mutex_unlock(&tz->lock);
465 470
471 trace_thermal_temperature(tz);
466 dev_dbg(&tz->device, "last_temperature=%d, current_temperature=%d\n", 472 dev_dbg(&tz->device, "last_temperature=%d, current_temperature=%d\n",
467 tz->last_temperature, tz->temperature); 473 tz->last_temperature, tz->temperature);
468} 474}
@@ -1287,6 +1293,7 @@ void thermal_cdev_update(struct thermal_cooling_device *cdev)
1287 mutex_unlock(&cdev->lock); 1293 mutex_unlock(&cdev->lock);
1288 cdev->ops->set_cur_state(cdev, target); 1294 cdev->ops->set_cur_state(cdev, target);
1289 cdev->updated = true; 1295 cdev->updated = true;
1296 trace_cdev_update(cdev, target);
1290 dev_dbg(&cdev->device, "set to state %lu\n", target); 1297 dev_dbg(&cdev->device, "set to state %lu\n", target);
1291} 1298}
1292EXPORT_SYMBOL(thermal_cdev_update); 1299EXPORT_SYMBOL(thermal_cdev_update);
@@ -1790,6 +1797,10 @@ static int __init thermal_register_governors(void)
1790 if (result) 1797 if (result)
1791 return result; 1798 return result;
1792 1799
1800 result = thermal_gov_bang_bang_register();
1801 if (result)
1802 return result;
1803
1793 return thermal_gov_user_space_register(); 1804 return thermal_gov_user_space_register();
1794} 1805}
1795 1806
@@ -1797,6 +1808,7 @@ static void thermal_unregister_governors(void)
1797{ 1808{
1798 thermal_gov_step_wise_unregister(); 1809 thermal_gov_step_wise_unregister();
1799 thermal_gov_fair_share_unregister(); 1810 thermal_gov_fair_share_unregister();
1811 thermal_gov_bang_bang_unregister();
1800 thermal_gov_user_space_unregister(); 1812 thermal_gov_user_space_unregister();
1801} 1813}
1802 1814
diff --git a/drivers/thermal/thermal_core.h b/drivers/thermal/thermal_core.h
index 3db339fb636f..d15d243de27a 100644
--- a/drivers/thermal/thermal_core.h
+++ b/drivers/thermal/thermal_core.h
@@ -69,6 +69,14 @@ static inline int thermal_gov_fair_share_register(void) { return 0; }
69static inline void thermal_gov_fair_share_unregister(void) {} 69static inline void thermal_gov_fair_share_unregister(void) {}
70#endif /* CONFIG_THERMAL_GOV_FAIR_SHARE */ 70#endif /* CONFIG_THERMAL_GOV_FAIR_SHARE */
71 71
72#ifdef CONFIG_THERMAL_GOV_BANG_BANG
73int thermal_gov_bang_bang_register(void);
74void thermal_gov_bang_bang_unregister(void);
75#else
76static inline int thermal_gov_bang_bang_register(void) { return 0; }
77static inline void thermal_gov_bang_bang_unregister(void) {}
78#endif /* CONFIG_THERMAL_GOV_BANG_BANG */
79
72#ifdef CONFIG_THERMAL_GOV_USER_SPACE 80#ifdef CONFIG_THERMAL_GOV_USER_SPACE
73int thermal_gov_user_space_register(void); 81int thermal_gov_user_space_register(void);
74void thermal_gov_user_space_unregister(void); 82void thermal_gov_user_space_unregister(void);
diff --git a/include/acpi/acpi_bus.h b/include/acpi/acpi_bus.h
index 57ee0528aacb..f34a0835aa4f 100644
--- a/include/acpi/acpi_bus.h
+++ b/include/acpi/acpi_bus.h
@@ -433,6 +433,7 @@ int acpi_device_set_power(struct acpi_device *device, int state);
433int acpi_bus_init_power(struct acpi_device *device); 433int acpi_bus_init_power(struct acpi_device *device);
434int acpi_device_fix_up_power(struct acpi_device *device); 434int acpi_device_fix_up_power(struct acpi_device *device);
435int acpi_bus_update_power(acpi_handle handle, int *state_p); 435int acpi_bus_update_power(acpi_handle handle, int *state_p);
436int acpi_device_update_power(struct acpi_device *device, int *state_p);
436bool acpi_bus_power_manageable(acpi_handle handle); 437bool acpi_bus_power_manageable(acpi_handle handle);
437 438
438#ifdef CONFIG_PM 439#ifdef CONFIG_PM
diff --git a/include/linux/acpi.h b/include/linux/acpi.h
index b7926bb9b444..407a12f663eb 100644
--- a/include/linux/acpi.h
+++ b/include/linux/acpi.h
@@ -432,6 +432,7 @@ static inline bool acpi_driver_match_device(struct device *dev,
432int acpi_device_uevent_modalias(struct device *, struct kobj_uevent_env *); 432int acpi_device_uevent_modalias(struct device *, struct kobj_uevent_env *);
433int acpi_device_modalias(struct device *, char *, int); 433int acpi_device_modalias(struct device *, char *, int);
434 434
435struct platform_device *acpi_create_platform_device(struct acpi_device *);
435#define ACPI_PTR(_ptr) (_ptr) 436#define ACPI_PTR(_ptr) (_ptr)
436 437
437#else /* !CONFIG_ACPI */ 438#else /* !CONFIG_ACPI */
diff --git a/include/linux/thermal.h b/include/linux/thermal.h
index 0305cde21a74..ef90838b36a0 100644
--- a/include/linux/thermal.h
+++ b/include/linux/thermal.h
@@ -44,6 +44,10 @@
44#define KELVIN_TO_CELSIUS(t) (long)(((long)t-2732 >= 0) ? \ 44#define KELVIN_TO_CELSIUS(t) (long)(((long)t-2732 >= 0) ? \
45 ((long)t-2732+5)/10 : ((long)t-2732-5)/10) 45 ((long)t-2732+5)/10 : ((long)t-2732-5)/10)
46#define CELSIUS_TO_KELVIN(t) ((t)*10+2732) 46#define CELSIUS_TO_KELVIN(t) ((t)*10+2732)
47#define DECI_KELVIN_TO_MILLICELSIUS_WITH_OFFSET(t, off) (((t) - (off)) * 100)
48#define DECI_KELVIN_TO_MILLICELSIUS(t) DECI_KELVIN_TO_MILLICELSIUS_WITH_OFFSET(t, 2732)
49#define MILLICELSIUS_TO_DECI_KELVIN_WITH_OFFSET(t, off) (((t) / 100) + (off))
50#define MILLICELSIUS_TO_DECI_KELVIN(t) MILLICELSIUS_TO_DECI_KELVIN_WITH_OFFSET(t, 2732)
47 51
48/* Adding event notification support elements */ 52/* Adding event notification support elements */
49#define THERMAL_GENL_FAMILY_NAME "thermal_event" 53#define THERMAL_GENL_FAMILY_NAME "thermal_event"
diff --git a/include/trace/events/thermal.h b/include/trace/events/thermal.h
new file mode 100644
index 000000000000..0f4f95d63c03
--- /dev/null
+++ b/include/trace/events/thermal.h
@@ -0,0 +1,83 @@
1#undef TRACE_SYSTEM
2#define TRACE_SYSTEM thermal
3
4#if !defined(_TRACE_THERMAL_H) || defined(TRACE_HEADER_MULTI_READ)
5#define _TRACE_THERMAL_H
6
7#include <linux/thermal.h>
8#include <linux/tracepoint.h>
9
10TRACE_EVENT(thermal_temperature,
11
12 TP_PROTO(struct thermal_zone_device *tz),
13
14 TP_ARGS(tz),
15
16 TP_STRUCT__entry(
17 __string(thermal_zone, tz->type)
18 __field(int, id)
19 __field(int, temp_prev)
20 __field(int, temp)
21 ),
22
23 TP_fast_assign(
24 __assign_str(thermal_zone, tz->type);
25 __entry->id = tz->id;
26 __entry->temp_prev = tz->last_temperature;
27 __entry->temp = tz->temperature;
28 ),
29
30 TP_printk("thermal_zone=%s id=%d temp_prev=%d temp=%d",
31 __get_str(thermal_zone), __entry->id, __entry->temp_prev,
32 __entry->temp)
33);
34
35TRACE_EVENT(cdev_update,
36
37 TP_PROTO(struct thermal_cooling_device *cdev, unsigned long target),
38
39 TP_ARGS(cdev, target),
40
41 TP_STRUCT__entry(
42 __string(type, cdev->type)
43 __field(unsigned long, target)
44 ),
45
46 TP_fast_assign(
47 __assign_str(type, cdev->type);
48 __entry->target = target;
49 ),
50
51 TP_printk("type=%s target=%lu", __get_str(type), __entry->target)
52);
53
54TRACE_EVENT(thermal_zone_trip,
55
56 TP_PROTO(struct thermal_zone_device *tz, int trip,
57 enum thermal_trip_type trip_type),
58
59 TP_ARGS(tz, trip, trip_type),
60
61 TP_STRUCT__entry(
62 __string(thermal_zone, tz->type)
63 __field(int, id)
64 __field(int, trip)
65 __field(enum thermal_trip_type, trip_type)
66 ),
67
68 TP_fast_assign(
69 __assign_str(thermal_zone, tz->type);
70 __entry->id = tz->id;
71 __entry->trip = trip;
72 __entry->trip_type = trip_type;
73 ),
74
75 TP_printk("thermal_zone=%s id=%d trip=%d trip_type=%d",
76 __get_str(thermal_zone), __entry->id, __entry->trip,
77 __entry->trip_type)
78);
79
80#endif /* _TRACE_THERMAL_H */
81
82/* This part must be outside protection */
83#include <trace/define_trace.h>