aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorZhang Rui <rui.zhang@intel.com>2014-10-17 02:30:58 -0400
committerZhang Rui <rui.zhang@intel.com>2014-10-17 02:30:58 -0400
commit6ceaf58abe25e86292152005c51169796bad3407 (patch)
treee97a032bc9dc63da9939136bd32ed5e0ad0f09bc
parent9ceaa81efd1dd5ec83cf6be5a9445809583a03b6 (diff)
parentd8054749c6795073cb427465a726213d45898f68 (diff)
Merge branch 'int340x-thermal' of .git into next
-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.c341
-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/Kconfig39
-rw-r--r--drivers/thermal/Makefile2
-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--include/acpi/acpi_bus.h1
-rw-r--r--include/linux/acpi.h1
-rw-r--r--include/linux/thermal.h4
22 files changed, 1867 insertions, 408 deletions
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 67075f800e34..91775475e367 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 8acf53e62966..e007c4987bea 100644
--- a/drivers/acpi/fan.c
+++ b/drivers/acpi/fan.c
@@ -30,24 +30,19 @@
30#include <asm/uaccess.h> 30#include <asm/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 PREFIX "ACPI: " 34#include <linux/sort.h>
35
36#define ACPI_FAN_CLASS "fan"
37#define ACPI_FAN_FILE_STATE "state"
38
39#define _COMPONENT ACPI_FAN_COMPONENT
40ACPI_MODULE_NAME("fan");
41 35
42MODULE_AUTHOR("Paul Diefenbaugh"); 36MODULE_AUTHOR("Paul Diefenbaugh");
43MODULE_DESCRIPTION("ACPI Fan Driver"); 37MODULE_DESCRIPTION("ACPI Fan Driver");
44MODULE_LICENSE("GPL"); 38MODULE_LICENSE("GPL");
45 39
46static int acpi_fan_add(struct acpi_device *device); 40static int acpi_fan_probe(struct platform_device *pdev);
47static int acpi_fan_remove(struct acpi_device *device); 41static int acpi_fan_remove(struct platform_device *pdev);
48 42
49static const struct acpi_device_id fan_device_ids[] = { 43static const struct acpi_device_id fan_device_ids[] = {
50 {"PNP0C0B", 0}, 44 {"PNP0C0B", 0},
45 {"INT3404", 0},
51 {"", 0}, 46 {"", 0},
52}; 47};
53MODULE_DEVICE_TABLE(acpi, fan_device_ids); 48MODULE_DEVICE_TABLE(acpi, fan_device_ids);
@@ -66,37 +61,100 @@ static struct dev_pm_ops acpi_fan_pm = {
66#define FAN_PM_OPS_PTR NULL 61#define FAN_PM_OPS_PTR NULL
67#endif 62#endif
68 63
69static struct acpi_driver acpi_fan_driver = { 64struct acpi_fan_fps {
70 .name = "fan", 65 u64 control;
71 .class = ACPI_FAN_CLASS, 66 u64 trip_point;
72 .ids = fan_device_ids, 67 u64 speed;
73 .ops = { 68 u64 noise_level;
74 .add = acpi_fan_add, 69 u64 power;
75 .remove = acpi_fan_remove, 70};
76 }, 71
77 .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 },
78}; 95};
79 96
80/* thermal cooling device callbacks */ 97/* thermal cooling device callbacks */
81static 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
82 *state) 99 *state)
83{ 100{
84 /* ACPI fan device only support two states: ON/OFF */ 101 struct acpi_device *device = cdev->devdata;
85 *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;
86 return 0; 108 return 0;
87} 109}
88 110
89static 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)
90 *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)
91{ 153{
92 struct acpi_device *device = cdev->devdata;
93 int result; 154 int result;
94 int acpi_state = ACPI_STATE_D0; 155 int acpi_state = ACPI_STATE_D0;
95 156
96 if (!device) 157 result = acpi_device_update_power(device, &acpi_state);
97 return -EINVAL;
98
99 result = acpi_bus_update_power(device->handle, &acpi_state);
100 if (result) 158 if (result)
101 return result; 159 return result;
102 160
@@ -105,21 +163,57 @@ static int fan_get_cur_state(struct thermal_cooling_device *cdev, unsigned long
105 return 0; 163 return 0;
106} 164}
107 165
108static int 166static int fan_get_cur_state(struct thermal_cooling_device *cdev, unsigned long
109fan_set_cur_state(struct thermal_cooling_device *cdev, unsigned long state) 167 *state)
110{ 168{
111 struct acpi_device *device = cdev->devdata; 169 struct acpi_device *device = cdev->devdata;
112 int result; 170 struct acpi_fan *fan = acpi_driver_data(device);
113 171
114 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)
115 return -EINVAL; 181 return -EINVAL;
116 182
117 result = acpi_bus_set_power(device->handle, 183 return acpi_device_set_power(device,
118 state ? ACPI_STATE_D0 : ACPI_STATE_D3_COLD); 184 state ? ACPI_STATE_D0 : ACPI_STATE_D3_COLD);
185}
119 186
120 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;
121} 203}
122 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
123static const struct thermal_cooling_device_ops fan_cooling_ops = { 217static const struct thermal_cooling_device_ops fan_cooling_ops = {
124 .get_max_state = fan_get_max_state, 218 .get_max_state = fan_get_max_state,
125 .get_cur_state = fan_get_cur_state, 219 .get_cur_state = fan_get_cur_state,
@@ -130,21 +224,125 @@ static const struct thermal_cooling_device_ops fan_cooling_ops = {
130 Driver Interface 224 Driver Interface
131 -------------------------------------------------------------------------- */ 225 -------------------------------------------------------------------------- */
132 226
133static int acpi_fan_add(struct acpi_device *device) 227static bool acpi_fan_is_acpi4(struct acpi_device *device)
134{ 228{
135 int result = 0; 229 return acpi_has_method(device->handle, "_FIF") &&
136 struct thermal_cooling_device *cdev; 230 acpi_has_method(device->handle, "_FPS") &&
231 acpi_has_method(device->handle, "_FSL") &&
232 acpi_has_method(device->handle, "_FST");
233}
137 234
138 if (!device) 235static int acpi_fan_get_fif(struct acpi_device *device)
139 return -EINVAL; 236{
237 struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
238 struct acpi_fan *fan = acpi_driver_data(device);
239 struct acpi_buffer format = { sizeof("NNNN"), "NNNN" };
240 struct acpi_buffer fif = { sizeof(fan->fif), &fan->fif };
241 union acpi_object *obj;
242 acpi_status status;
243
244 status = acpi_evaluate_object(device->handle, "_FIF", NULL, &buffer);
245 if (ACPI_FAILURE(status))
246 return status;
247
248 obj = buffer.pointer;
249 if (!obj || obj->type != ACPI_TYPE_PACKAGE) {
250 dev_err(&device->dev, "Invalid _FIF data\n");
251 status = -EINVAL;
252 goto err;
253 }
140 254
141 strcpy(acpi_device_name(device), "Fan"); 255 status = acpi_extract_package(obj, &format, &fif);
142 strcpy(acpi_device_class(device), ACPI_FAN_CLASS); 256 if (ACPI_FAILURE(status)) {
257 dev_err(&device->dev, "Invalid _FIF element\n");
258 status = -EINVAL;
259 }
143 260
144 result = acpi_bus_update_power(device->handle, NULL); 261err:
145 if (result) { 262 kfree(obj);
146 printk(KERN_ERR PREFIX "Setting initial power state\n"); 263 return status;
147 goto end; 264}
265
266static int acpi_fan_speed_cmp(const void *a, const void *b)
267{
268 const struct acpi_fan_fps *fps1 = a;
269 const struct acpi_fan_fps *fps2 = b;
270 return fps1->speed - fps2->speed;
271}
272
273static int acpi_fan_get_fps(struct acpi_device *device)
274{
275 struct acpi_fan *fan = acpi_driver_data(device);
276 struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
277 union acpi_object *obj;
278 acpi_status status;
279 int i;
280
281 status = acpi_evaluate_object(device->handle, "_FPS", NULL, &buffer);
282 if (ACPI_FAILURE(status))
283 return status;
284
285 obj = buffer.pointer;
286 if (!obj || obj->type != ACPI_TYPE_PACKAGE || obj->package.count < 2) {
287 dev_err(&device->dev, "Invalid _FPS data\n");
288 status = -EINVAL;
289 goto err;
290 }
291
292 fan->fps_count = obj->package.count - 1; /* minus revision field */
293 fan->fps = devm_kzalloc(&device->dev,
294 fan->fps_count * sizeof(struct acpi_fan_fps),
295 GFP_KERNEL);
296 if (!fan->fps) {
297 dev_err(&device->dev, "Not enough memory\n");
298 status = -ENOMEM;
299 goto err;
300 }
301 for (i = 0; i < fan->fps_count; i++) {
302 struct acpi_buffer format = { sizeof("NNNNN"), "NNNNN" };
303 struct acpi_buffer fps = { sizeof(fan->fps[i]), &fan->fps[i] };
304 status = acpi_extract_package(&obj->package.elements[i + 1],
305 &format, &fps);
306 if (ACPI_FAILURE(status)) {
307 dev_err(&device->dev, "Invalid _FPS element\n");
308 break;
309 }
310 }
311
312 /* sort the state array according to fan speed in increase order */
313 sort(fan->fps, fan->fps_count, sizeof(*fan->fps),
314 acpi_fan_speed_cmp, NULL);
315
316err:
317 kfree(obj);
318 return status;
319}
320
321static int acpi_fan_probe(struct platform_device *pdev)
322{
323 int result = 0;
324 struct thermal_cooling_device *cdev;
325 struct acpi_fan *fan;
326 struct acpi_device *device = ACPI_COMPANION(&pdev->dev);
327
328 fan = devm_kzalloc(&pdev->dev, sizeof(*fan), GFP_KERNEL);
329 if (!fan) {
330 dev_err(&device->dev, "No memory for fan\n");
331 return -ENOMEM;
332 }
333 device->driver_data = fan;
334 platform_set_drvdata(pdev, fan);
335
336 if (acpi_fan_is_acpi4(device)) {
337 if (acpi_fan_get_fif(device) || acpi_fan_get_fps(device))
338 goto end;
339 fan->acpi4 = true;
340 } else {
341 result = acpi_device_update_power(device, NULL);
342 if (result) {
343 dev_err(&device->dev, "Setting initial power state\n");
344 goto end;
345 }
148 } 346 }
149 347
150 cdev = thermal_cooling_device_register("Fan", device, 348 cdev = thermal_cooling_device_register("Fan", device,
@@ -154,45 +352,34 @@ static int acpi_fan_add(struct acpi_device *device)
154 goto end; 352 goto end;
155 } 353 }
156 354
157 dev_dbg(&device->dev, "registered as cooling_device%d\n", cdev->id); 355 dev_dbg(&pdev->dev, "registered as cooling_device%d\n", cdev->id);
158 356
159 device->driver_data = cdev; 357 fan->cdev = cdev;
160 result = sysfs_create_link(&device->dev.kobj, 358 result = sysfs_create_link(&pdev->dev.kobj,
161 &cdev->device.kobj, 359 &cdev->device.kobj,
162 "thermal_cooling"); 360 "thermal_cooling");
163 if (result) 361 if (result)
164 dev_err(&device->dev, "Failed to create sysfs link " 362 dev_err(&pdev->dev, "Failed to create sysfs link "
165 "'thermal_cooling'\n"); 363 "'thermal_cooling'\n");
166 364
167 result = sysfs_create_link(&cdev->device.kobj, 365 result = sysfs_create_link(&cdev->device.kobj,
168 &device->dev.kobj, 366 &pdev->dev.kobj,
169 "device"); 367 "device");
170 if (result) 368 if (result)
171 dev_err(&device->dev, "Failed to create sysfs link " 369 dev_err(&pdev->dev, "Failed to create sysfs link "
172 "'device'\n"); 370 "'device'\n");
173 371
174 printk(KERN_INFO PREFIX "%s [%s] (%s)\n",
175 acpi_device_name(device), acpi_device_bid(device),
176 !device->power.state ? "on" : "off");
177
178end: 372end:
179 return result; 373 return result;
180} 374}
181 375
182static int acpi_fan_remove(struct acpi_device *device) 376static int acpi_fan_remove(struct platform_device *pdev)
183{ 377{
184 struct thermal_cooling_device *cdev; 378 struct acpi_fan *fan = platform_get_drvdata(pdev);
185
186 if (!device)
187 return -EINVAL;
188
189 cdev = acpi_driver_data(device);
190 if (!cdev)
191 return -EINVAL;
192 379
193 sysfs_remove_link(&device->dev.kobj, "thermal_cooling"); 380 sysfs_remove_link(&pdev->dev.kobj, "thermal_cooling");
194 sysfs_remove_link(&cdev->device.kobj, "device"); 381 sysfs_remove_link(&fan->cdev->device.kobj, "device");
195 thermal_cooling_device_unregister(cdev); 382 thermal_cooling_device_unregister(fan->cdev);
196 383
197 return 0; 384 return 0;
198} 385}
@@ -200,10 +387,11 @@ static int acpi_fan_remove(struct acpi_device *device)
200#ifdef CONFIG_PM_SLEEP 387#ifdef CONFIG_PM_SLEEP
201static int acpi_fan_suspend(struct device *dev) 388static int acpi_fan_suspend(struct device *dev)
202{ 389{
203 if (!dev) 390 struct acpi_fan *fan = dev_get_drvdata(dev);
204 return -EINVAL; 391 if (fan->acpi4)
392 return 0;
205 393
206 acpi_bus_set_power(to_acpi_device(dev)->handle, ACPI_STATE_D0); 394 acpi_device_set_power(ACPI_COMPANION(dev), ACPI_STATE_D0);
207 395
208 return AE_OK; 396 return AE_OK;
209} 397}
@@ -211,16 +399,17 @@ static int acpi_fan_suspend(struct device *dev)
211static int acpi_fan_resume(struct device *dev) 399static int acpi_fan_resume(struct device *dev)
212{ 400{
213 int result; 401 int result;
402 struct acpi_fan *fan = dev_get_drvdata(dev);
214 403
215 if (!dev) 404 if (fan->acpi4)
216 return -EINVAL; 405 return 0;
217 406
218 result = acpi_bus_update_power(to_acpi_device(dev)->handle, NULL); 407 result = acpi_device_update_power(ACPI_COMPANION(dev), NULL);
219 if (result) 408 if (result)
220 printk(KERN_ERR PREFIX "Error updating fan power state\n"); 409 dev_err(dev, "Error updating fan power state\n");
221 410
222 return result; 411 return result;
223} 412}
224#endif 413#endif
225 414
226module_acpi_driver(acpi_fan_driver); 415module_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 0a817ad24f16..eed9740651f8 100644
--- a/drivers/acpi/scan.c
+++ b/drivers/acpi/scan.c
@@ -2306,6 +2306,7 @@ int __init acpi_scan_init(void)
2306 acpi_container_init(); 2306 acpi_container_init();
2307 acpi_memory_hotplug_init(); 2307 acpi_memory_hotplug_init();
2308 acpi_pnp_init(); 2308 acpi_pnp_init();
2309 acpi_int340x_thermal_init();
2309 2310
2310 mutex_lock(&acpi_scan_lock); 2311 mutex_lock(&acpi_scan_lock);
2311 /* 2312 /*
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 07c8c5a5ee95..1ed7aba99d8d 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 2500ecc48260..9b012ff65220 100644
--- a/drivers/thermal/Kconfig
+++ b/drivers/thermal/Kconfig
@@ -217,21 +217,6 @@ config X86_PKG_TEMP_THERMAL
217 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
218 notification methods. 218 notification methods.
219 219
220config ACPI_INT3403_THERMAL
221 tristate "ACPI INT3403 thermal driver"
222 depends on X86 && ACPI
223 help
224 Newer laptops and tablets that use ACPI may have thermal sensors
225 outside the core CPU/SOC for thermal safety reasons. These
226 temperature sensors are also exposed for the OS to use via the so
227 called INT3403 ACPI object. This driver will, on devices that have
228 such sensors, expose the temperature information from these sensors
229 to userspace via the normal thermal framework. This means that a wide
230 range of applications and GUI widgets can show this information to
231 the user or use this information for making decisions. For example,
232 the Intel Thermal Daemon can use this information to allow the user
233 to select his laptop to run without turning on the fans.
234
235config INTEL_SOC_DTS_THERMAL 220config INTEL_SOC_DTS_THERMAL
236 tristate "Intel SoCs DTS thermal driver" 221 tristate "Intel SoCs DTS thermal driver"
237 depends on X86 && IOSF_MBI 222 depends on X86 && IOSF_MBI
@@ -244,6 +229,30 @@ config INTEL_SOC_DTS_THERMAL
244 notification methods.The other trip is a critical trip point, which 229 notification methods.The other trip is a critical trip point, which
245 was set by the driver based on the TJ MAX temperature. 230 was set by the driver based on the TJ MAX temperature.
246 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
247menu "Texas Instruments thermal drivers" 256menu "Texas Instruments thermal drivers"
248source "drivers/thermal/ti-soc-thermal/Kconfig" 257source "drivers/thermal/ti-soc-thermal/Kconfig"
249endmenu 258endmenu
diff --git a/drivers/thermal/Makefile b/drivers/thermal/Makefile
index b7e65423d7b6..39c4fe87da2f 100644
--- a/drivers/thermal/Makefile
+++ b/drivers/thermal/Makefile
@@ -32,5 +32,5 @@ obj-$(CONFIG_INTEL_POWERCLAMP) += intel_powerclamp.o
32obj-$(CONFIG_X86_PKG_TEMP_THERMAL) += x86_pkg_temp_thermal.o 32obj-$(CONFIG_X86_PKG_TEMP_THERMAL) += x86_pkg_temp_thermal.o
33obj-$(CONFIG_INTEL_SOC_DTS_THERMAL) += intel_soc_dts_thermal.o 33obj-$(CONFIG_INTEL_SOC_DTS_THERMAL) += intel_soc_dts_thermal.o
34obj-$(CONFIG_TI_SOC_THERMAL) += ti-soc-thermal/ 34obj-$(CONFIG_TI_SOC_THERMAL) += ti-soc-thermal/
35obj-$(CONFIG_ACPI_INT3403_THERMAL) += int3403_thermal.o 35obj-$(CONFIG_INT340X_THERMAL) += int340x_thermal/
36obj-$(CONFIG_ST_THERMAL) += st/ 36obj-$(CONFIG_ST_THERMAL) += st/
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/include/acpi/acpi_bus.h b/include/acpi/acpi_bus.h
index bcfd808b1098..6ca32812f3da 100644
--- a/include/acpi/acpi_bus.h
+++ b/include/acpi/acpi_bus.h
@@ -435,6 +435,7 @@ int acpi_device_set_power(struct acpi_device *device, int state);
435int acpi_bus_init_power(struct acpi_device *device); 435int acpi_bus_init_power(struct acpi_device *device);
436int acpi_device_fix_up_power(struct acpi_device *device); 436int acpi_device_fix_up_power(struct acpi_device *device);
437int acpi_bus_update_power(acpi_handle handle, int *state_p); 437int acpi_bus_update_power(acpi_handle handle, int *state_p);
438int acpi_device_update_power(struct acpi_device *device, int *state_p);
438bool acpi_bus_power_manageable(acpi_handle handle); 439bool acpi_bus_power_manageable(acpi_handle handle);
439 440
440#ifdef CONFIG_PM 441#ifdef CONFIG_PM
diff --git a/include/linux/acpi.h b/include/linux/acpi.h
index 807cbc46d73e..2c24c2c1be45 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"