aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/thermal
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/thermal')
-rw-r--r--drivers/thermal/Kconfig7
-rw-r--r--drivers/thermal/Makefile1
-rw-r--r--drivers/thermal/int3403_thermal.c237
3 files changed, 245 insertions, 0 deletions
diff --git a/drivers/thermal/Kconfig b/drivers/thermal/Kconfig
index f35a1f75b15b..8928e6447380 100644
--- a/drivers/thermal/Kconfig
+++ b/drivers/thermal/Kconfig
@@ -192,6 +192,13 @@ config X86_PKG_TEMP_THERMAL
192 two trip points which can be set by user to get notifications via thermal 192 two trip points which can be set by user to get notifications via thermal
193 notification methods. 193 notification methods.
194 194
195config ACPI_INT3403_THERMAL
196 tristate "ACPI INT3403 thermal driver"
197 depends on X86 && ACPI
198 help
199 This driver uses ACPI INT3403 device objects. If present, it will
200 register each INT3403 thermal sensor as a thermal zone.
201
195menu "Texas Instruments thermal drivers" 202menu "Texas Instruments thermal drivers"
196source "drivers/thermal/ti-soc-thermal/Kconfig" 203source "drivers/thermal/ti-soc-thermal/Kconfig"
197endmenu 204endmenu
diff --git a/drivers/thermal/Makefile b/drivers/thermal/Makefile
index 584b36319d51..aa1bba92784e 100644
--- a/drivers/thermal/Makefile
+++ b/drivers/thermal/Makefile
@@ -29,3 +29,4 @@ obj-$(CONFIG_DB8500_CPUFREQ_COOLING) += db8500_cpufreq_cooling.o
29obj-$(CONFIG_INTEL_POWERCLAMP) += intel_powerclamp.o 29obj-$(CONFIG_INTEL_POWERCLAMP) += intel_powerclamp.o
30obj-$(CONFIG_X86_PKG_TEMP_THERMAL) += x86_pkg_temp_thermal.o 30obj-$(CONFIG_X86_PKG_TEMP_THERMAL) += x86_pkg_temp_thermal.o
31obj-$(CONFIG_TI_SOC_THERMAL) += ti-soc-thermal/ 31obj-$(CONFIG_TI_SOC_THERMAL) += ti-soc-thermal/
32obj-$(CONFIG_ACPI_INT3403_THERMAL) += int3403_thermal.o
diff --git a/drivers/thermal/int3403_thermal.c b/drivers/thermal/int3403_thermal.c
new file mode 100644
index 000000000000..1301681d9a77
--- /dev/null
+++ b/drivers/thermal/int3403_thermal.c
@@ -0,0 +1,237 @@
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};
37
38static int sys_get_curr_temp(struct thermal_zone_device *tzone,
39 unsigned long *temp)
40{
41 struct acpi_device *device = tzone->devdata;
42 unsigned long long tmp;
43 acpi_status status;
44
45 status = acpi_evaluate_integer(device->handle, "_TMP", NULL, &tmp);
46 if (ACPI_FAILURE(status))
47 return -EIO;
48
49 *temp = DECI_KELVIN_TO_MILLI_CELSIUS(tmp, KELVIN_OFFSET);
50
51 return 0;
52}
53
54static int sys_get_trip_hyst(struct thermal_zone_device *tzone,
55 int trip, unsigned long *temp)
56{
57 struct acpi_device *device = tzone->devdata;
58 unsigned long long hyst;
59 acpi_status status;
60
61 status = acpi_evaluate_integer(device->handle, "GTSH", NULL, &hyst);
62 if (ACPI_FAILURE(status))
63 return -EIO;
64
65 *temp = DECI_KELVIN_TO_MILLI_CELSIUS(hyst, KELVIN_OFFSET);
66
67 return 0;
68}
69
70static int sys_get_trip_temp(struct thermal_zone_device *tzone,
71 int trip, unsigned long *temp)
72{
73 struct acpi_device *device = tzone->devdata;
74 struct int3403_sensor *obj = acpi_driver_data(device);
75
76 /*
77 * get_trip_temp is a mandatory callback but
78 * PATx method doesn't return any value, so return
79 * cached value, which was last set from user space.
80 */
81 *temp = obj->thresholds[trip];
82
83 return 0;
84}
85
86static int sys_get_trip_type(struct thermal_zone_device *thermal,
87 int trip, enum thermal_trip_type *type)
88{
89 /* Mandatory callback, may not mean much here */
90 *type = THERMAL_TRIP_PASSIVE;
91
92 return 0;
93}
94
95int sys_set_trip_temp(struct thermal_zone_device *tzone, int trip,
96 unsigned long temp)
97{
98 struct acpi_device *device = tzone->devdata;
99 acpi_status status;
100 char name[10];
101 int ret = 0;
102 struct int3403_sensor *obj = acpi_driver_data(device);
103
104 snprintf(name, sizeof(name), "PAT%d", trip);
105 if (acpi_has_method(device->handle, name)) {
106 status = acpi_execute_simple_method(device->handle, name,
107 MILLI_CELSIUS_TO_DECI_KELVIN(temp,
108 KELVIN_OFFSET));
109 if (ACPI_FAILURE(status))
110 ret = -EIO;
111 else
112 obj->thresholds[trip] = temp;
113 } else {
114 ret = -EIO;
115 dev_err(&device->dev, "sys_set_trip_temp: method not found\n");
116 }
117
118 return ret;
119}
120
121static struct thermal_zone_device_ops tzone_ops = {
122 .get_temp = sys_get_curr_temp,
123 .get_trip_temp = sys_get_trip_temp,
124 .get_trip_type = sys_get_trip_type,
125 .set_trip_temp = sys_set_trip_temp,
126 .get_trip_hyst = sys_get_trip_hyst,
127};
128
129static void acpi_thermal_notify(struct acpi_device *device, u32 event)
130{
131 struct int3403_sensor *obj;
132
133 if (!device)
134 return;
135
136 obj = acpi_driver_data(device);
137 if (!obj)
138 return;
139
140 switch (event) {
141 case INT3403_PERF_CHANGED_EVENT:
142 break;
143 case INT3403_THERMAL_EVENT:
144 thermal_zone_device_update(obj->tzone);
145 break;
146 default:
147 dev_err(&device->dev, "Unsupported event [0x%x]\n", event);
148 break;
149 }
150}
151
152static int acpi_int3403_add(struct acpi_device *device)
153{
154 int result = 0;
155 unsigned long long ptyp;
156 acpi_status status;
157 struct int3403_sensor *obj;
158 unsigned long long trip_cnt;
159 int trip_mask = 0;
160
161 if (!device)
162 return -EINVAL;
163
164 status = acpi_evaluate_integer(device->handle, "PTYP", NULL, &ptyp);
165 if (ACPI_FAILURE(status))
166 return -EINVAL;
167
168 if (ptyp != INT3403_TYPE_SENSOR)
169 return -EINVAL;
170
171 obj = devm_kzalloc(&device->dev, sizeof(*obj), GFP_KERNEL);
172 if (!obj)
173 return -ENOMEM;
174
175 device->driver_data = obj;
176
177 status = acpi_evaluate_integer(device->handle, "PATC", NULL,
178 &trip_cnt);
179 if (ACPI_FAILURE(status))
180 trip_cnt = 0;
181
182 if (trip_cnt) {
183 /* We have to cache, thresholds can't be readback */
184 obj->thresholds = devm_kzalloc(&device->dev,
185 sizeof(*obj->thresholds) * trip_cnt,
186 GFP_KERNEL);
187 if (!obj->thresholds)
188 return -ENOMEM;
189 trip_mask = BIT(trip_cnt) - 1;
190 }
191 obj->tzone = thermal_zone_device_register(acpi_device_bid(device),
192 trip_cnt, trip_mask, device, &tzone_ops,
193 NULL, 0, 0);
194 if (IS_ERR(obj->tzone)) {
195 result = PTR_ERR(obj->tzone);
196 return result;
197 }
198
199 strcpy(acpi_device_name(device), "INT3403");
200 strcpy(acpi_device_class(device), ACPI_INT3403_CLASS);
201
202 return 0;
203}
204
205static int acpi_int3403_remove(struct acpi_device *device)
206{
207 struct int3403_sensor *obj;
208
209 obj = acpi_driver_data(device);
210 thermal_zone_device_unregister(obj->tzone);
211
212 return 0;
213}
214
215ACPI_MODULE_NAME("int3403");
216static const struct acpi_device_id int3403_device_ids[] = {
217 {"INT3403", 0},
218 {"", 0},
219};
220MODULE_DEVICE_TABLE(acpi, int3403_device_ids);
221
222static struct acpi_driver acpi_int3403_driver = {
223 .name = "INT3403",
224 .class = ACPI_INT3403_CLASS,
225 .ids = int3403_device_ids,
226 .ops = {
227 .add = acpi_int3403_add,
228 .remove = acpi_int3403_remove,
229 .notify = acpi_thermal_notify,
230 },
231};
232
233module_acpi_driver(acpi_int3403_driver);
234
235MODULE_AUTHOR("Srinivas Pandruvada <srinivas.pandruvada@linux.intel.com>");
236MODULE_LICENSE("GPL v2");
237MODULE_DESCRIPTION("ACPI INT3403 thermal driver");