aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorZhang Rui <rui.zhang@intel.com>2014-03-14 00:45:05 -0400
committerZhang Rui <rui.zhang@intel.com>2014-10-10 01:57:09 -0400
commit816cab931f288c92a3404b1b984576f4822b0445 (patch)
treef09e5a1e9124056e086e53fbbea39bbf2d9acf32
parente3ec483a7e24c6ebb5eb763ee56c65c239701066 (diff)
Thermal: introduce int3400 thermal driver
Introduce int3400 thermal driver. And make INT3400 driver enumerate the other int340x thermal components shown in _ART/_TRT. Signed-off-by: Zhang Rui <rui.zhang@intel.com>
-rw-r--r--drivers/acpi/int340x_thermal.c2
-rw-r--r--drivers/thermal/Kconfig2
-rw-r--r--drivers/thermal/Makefile1
-rw-r--r--drivers/thermal/int340x_thermal/Makefile1
-rw-r--r--drivers/thermal/int340x_thermal/int3400_thermal.c245
5 files changed, 249 insertions, 2 deletions
diff --git a/drivers/acpi/int340x_thermal.c b/drivers/acpi/int340x_thermal.c
index 2103bb6d9016..a27d31d1ba24 100644
--- a/drivers/acpi/int340x_thermal.c
+++ b/drivers/acpi/int340x_thermal.c
@@ -33,7 +33,7 @@ static const struct acpi_device_id int340x_thermal_device_ids[] = {
33static int int340x_thermal_handler_attach(struct acpi_device *adev, 33static int int340x_thermal_handler_attach(struct acpi_device *adev,
34 const struct acpi_device_id *id) 34 const struct acpi_device_id *id)
35{ 35{
36#ifdef CONFIG_INT340X_THERMAL 36#if defined(CONFIG_INT340X_THERMAL) || defined(CONFIG_INT340X_THERMAL_MODULE)
37 if (id->driver_data == DO_ENUMERATION) 37 if (id->driver_data == DO_ENUMERATION)
38 acpi_create_platform_device(adev); 38 acpi_create_platform_device(adev);
39#endif 39#endif
diff --git a/drivers/thermal/Kconfig b/drivers/thermal/Kconfig
index 2ff7416ca930..6f5a87a8f19f 100644
--- a/drivers/thermal/Kconfig
+++ b/drivers/thermal/Kconfig
@@ -235,7 +235,7 @@ config INTEL_SOC_DTS_THERMAL
235 was set by the driver based on the TJ MAX temperature. 235 was set by the driver based on the TJ MAX temperature.
236 236
237config INT340X_THERMAL 237config INT340X_THERMAL
238 bool 238 tristate "ACPI INT340X thermal drivers"
239 depends on X86 && ACPI 239 depends on X86 && ACPI
240 help 240 help
241 Newer laptops and tablets that use ACPI may have thermal sensors and 241 Newer laptops and tablets that use ACPI may have thermal sensors and
diff --git a/drivers/thermal/Makefile b/drivers/thermal/Makefile
index 31e232f84b6b..216503eaa232 100644
--- a/drivers/thermal/Makefile
+++ b/drivers/thermal/Makefile
@@ -32,4 +32,5 @@ obj-$(CONFIG_X86_PKG_TEMP_THERMAL) += x86_pkg_temp_thermal.o
32obj-$(CONFIG_INTEL_SOC_DTS_THERMAL) += intel_soc_dts_thermal.o 32obj-$(CONFIG_INTEL_SOC_DTS_THERMAL) += intel_soc_dts_thermal.o
33obj-$(CONFIG_TI_SOC_THERMAL) += ti-soc-thermal/ 33obj-$(CONFIG_TI_SOC_THERMAL) += ti-soc-thermal/
34obj-$(CONFIG_ACPI_INT3403_THERMAL) += int3403_thermal.o 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/int340x_thermal/Makefile b/drivers/thermal/int340x_thermal/Makefile
new file mode 100644
index 000000000000..e10a53bcefe7
--- /dev/null
+++ b/drivers/thermal/int340x_thermal/Makefile
@@ -0,0 +1 @@
obj-$(CONFIG_INT340X_THERMAL) += int3400_thermal.o
diff --git a/drivers/thermal/int340x_thermal/int3400_thermal.c b/drivers/thermal/int340x_thermal/int3400_thermal.c
new file mode 100644
index 000000000000..308c1850edee
--- /dev/null
+++ b/drivers/thermal/int340x_thermal/int3400_thermal.c
@@ -0,0 +1,245 @@
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
17struct art {
18 acpi_handle source;
19 acpi_handle target;
20 u64 weight;
21 u64 ac0_max;
22 u64 ac1_max;
23 u64 ac2_max;
24 u64 ac3_max;
25 u64 ac4_max;
26 u64 ac5_max;
27 u64 ac6_max;
28 u64 ac7_max;
29 u64 ac8_max;
30 u64 ac9_max;
31};
32
33struct trt {
34 acpi_handle source;
35 acpi_handle target;
36 u64 influence;
37 u64 sampling_period;
38 u64 reverved1;
39 u64 reverved2;
40 u64 reverved3;
41 u64 reverved4;
42};
43
44struct int3400_thermal_priv {
45 struct acpi_device *adev;
46 int art_count;
47 struct art *arts;
48 int trt_count;
49 struct trt *trts;
50};
51
52static int parse_art(struct int3400_thermal_priv *priv)
53{
54 acpi_handle handle = priv->adev->handle;
55 acpi_status status;
56 int result = 0;
57 int i;
58 struct acpi_device *adev;
59 union acpi_object *p;
60 struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
61 struct acpi_buffer element = { 0, NULL };
62 struct acpi_buffer art_format = {
63 sizeof("RRNNNNNNNNNNN"), "RRNNNNNNNNNNN" };
64
65 if (!acpi_has_method(handle, "_ART"))
66 return 0;
67
68 status = acpi_evaluate_object(handle, "_ART", NULL, &buffer);
69 if (ACPI_FAILURE(status))
70 return -ENODEV;
71
72 p = buffer.pointer;
73 if (!p || (p->type != ACPI_TYPE_PACKAGE)) {
74 pr_err("Invalid _ART data\n");
75 result = -EFAULT;
76 goto end;
77 }
78
79 /* ignore p->package.elements[0], as this is _ART Revision field */
80 priv->art_count = p->package.count - 1;
81 priv->arts = kzalloc(sizeof(struct art) * priv->art_count, GFP_KERNEL);
82 if (!priv->arts) {
83 result = -ENOMEM;
84 goto end;
85 }
86
87 for (i = 0; i < priv->art_count; i++) {
88 struct art *art = &(priv->arts[i]);
89
90 element.length = sizeof(struct art);
91 element.pointer = art;
92
93 status = acpi_extract_package(&(p->package.elements[i + 1]),
94 &art_format, &element);
95 if (ACPI_FAILURE(status)) {
96 pr_err("Invalid _ART data");
97 result = -EFAULT;
98 kfree(priv->arts);
99 goto end;
100 }
101 result = acpi_bus_get_device(art->source, &adev);
102 if (!result)
103 acpi_create_platform_device(adev, NULL);
104 else
105 pr_warn("Failed to get source ACPI device\n");
106 result = acpi_bus_get_device(art->target, &adev);
107 if (!result)
108 acpi_create_platform_device(adev, NULL);
109 else
110 pr_warn("Failed to get source ACPI device\n");
111 }
112end:
113 kfree(buffer.pointer);
114 return result;
115}
116
117static int parse_trt(struct int3400_thermal_priv *priv)
118{
119 acpi_handle handle = priv->adev->handle;
120 acpi_status status;
121 int result = 0;
122 int i;
123 struct acpi_device *adev;
124 union acpi_object *p;
125 struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
126 struct acpi_buffer element = { 0, NULL };
127 struct acpi_buffer trt_format = { sizeof("RRNNNNNN"), "RRNNNNNN" };
128
129 if (!acpi_has_method(handle, "_TRT"))
130 return 0;
131
132 status = acpi_evaluate_object(handle, "_TRT", NULL, &buffer);
133 if (ACPI_FAILURE(status))
134 return -ENODEV;
135
136 p = buffer.pointer;
137 if (!p || (p->type != ACPI_TYPE_PACKAGE)) {
138 pr_err("Invalid _TRT data\n");
139 result = -EFAULT;
140 goto end;
141 }
142
143 priv->trt_count = p->package.count;
144 priv->trts = kzalloc(sizeof(struct trt) * priv->trt_count, GFP_KERNEL);
145 if (!priv->trts) {
146 result = -ENOMEM;
147 goto end;
148 }
149
150 for (i = 0; i < priv->trt_count; i++) {
151 struct trt *trt = &(priv->trts[i]);
152
153 element.length = sizeof(struct trt);
154 element.pointer = trt;
155
156 status = acpi_extract_package(&(p->package.elements[i]),
157 &trt_format, &element);
158 if (ACPI_FAILURE(status)) {
159 pr_err("Invalid _ART data");
160 result = -EFAULT;
161 kfree(priv->trts);
162 goto end;
163 }
164
165 result = acpi_bus_get_device(trt->source, &adev);
166 if (!result)
167 acpi_create_platform_device(adev, NULL);
168 else
169 pr_warn("Failed to get source ACPI device\n");
170 result = acpi_bus_get_device(trt->target, &adev);
171 if (!result)
172 acpi_create_platform_device(adev, NULL);
173 else
174 pr_warn("Failed to get target ACPI device\n");
175 }
176end:
177 kfree(buffer.pointer);
178 return result;
179}
180
181static int int3400_thermal_probe(struct platform_device *pdev)
182{
183 struct acpi_device *adev = ACPI_COMPANION(&pdev->dev);
184 struct int3400_thermal_priv *priv;
185 int result;
186
187 if (!adev)
188 return -ENODEV;
189
190 priv = kzalloc(sizeof(struct int3400_thermal_priv), GFP_KERNEL);
191 if (!priv)
192 return -ENOMEM;
193
194 priv->adev = adev;
195
196 result = parse_art(priv);
197 if (result)
198 goto free_priv;
199
200 result = parse_trt(priv);
201 if (result)
202 goto free_art;
203
204 platform_set_drvdata(pdev, priv);
205
206 return 0;
207free_art:
208 kfree(priv->arts);
209free_priv:
210 kfree(priv);
211 return result;
212}
213
214static int int3400_thermal_remove(struct platform_device *pdev)
215{
216 struct int3400_thermal_priv *priv = platform_get_drvdata(pdev);
217
218 kfree(priv->trts);
219 kfree(priv->arts);
220 kfree(priv);
221 return 0;
222}
223
224static const struct acpi_device_id int3400_thermal_match[] = {
225 {"INT3400", 0},
226 {}
227};
228
229MODULE_DEVICE_TABLE(acpi, int3400_thermal_match);
230
231static struct platform_driver int3400_thermal_driver = {
232 .probe = int3400_thermal_probe,
233 .remove = int3400_thermal_remove,
234 .driver = {
235 .name = "int3400 thermal",
236 .owner = THIS_MODULE,
237 .acpi_match_table = ACPI_PTR(int3400_thermal_match),
238 },
239};
240
241module_platform_driver(int3400_thermal_driver);
242
243MODULE_DESCRIPTION("INT3400 Thermal driver");
244MODULE_AUTHOR("Zhang Rui <rui.zhang@intel.com>");
245MODULE_LICENSE("GPL");