aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLuca Tettamanti <kronos.it@gmail.com>2009-04-07 09:32:59 -0400
committerJean Delvare <khali@linux-fr.org>2009-04-07 09:32:59 -0400
commit2c03d07ad54db03b813bb98c469790c07ca9f5dd (patch)
tree3ca6b4c0f3ea3d20cb9acc410c2e822846d0d590
parent797eaa4b0242a41cb6bc913890b9ec22ec8788ed (diff)
hwmon: Add Asus ATK0110 support
Asus boards have an ACPI interface for interacting with the hwmon (fan, temperatures, voltages) subsystem; this driver exposes the relevant information via the standard sysfs interface. There are two different ACPI interfaces: - an old one (based on RVLT/RFAN/RTMP) - a new one (GGRP/GITM) Both may be present but there a few cases (my board, sigh) where the new interface is just an empty stub; the driver defaults to the old one when both are present. The old interface has received a considerable testing, but I'm still awaiting confirmation from my tester that the new one is working as expected (hence the debug code is still enabled). Currently all the attributes are read-only, though a (partial) control should be possible with a bit more work. Signed-off-by: Luca Tettamanti <kronos.it@gmail.com> Signed-off-by: Hans de Goede <hdegoede@redhat.com> Signed-off-by: Jean Delvare <khali@linux-fr.org>
-rw-r--r--drivers/acpi/acpica/nsxfeval.c3
-rw-r--r--drivers/hwmon/Kconfig12
-rw-r--r--drivers/hwmon/Makefile1
-rw-r--r--drivers/hwmon/asus_atk0110.c1009
-rw-r--r--include/acpi/acpixf.h2
5 files changed, 1023 insertions, 4 deletions
diff --git a/drivers/acpi/acpica/nsxfeval.c b/drivers/acpi/acpica/nsxfeval.c
index 045054037c2d..daf4ad37896d 100644
--- a/drivers/acpi/acpica/nsxfeval.c
+++ b/drivers/acpi/acpica/nsxfeval.c
@@ -53,7 +53,6 @@ ACPI_MODULE_NAME("nsxfeval")
53/* Local prototypes */ 53/* Local prototypes */
54static void acpi_ns_resolve_references(struct acpi_evaluate_info *info); 54static void acpi_ns_resolve_references(struct acpi_evaluate_info *info);
55 55
56#ifdef ACPI_FUTURE_USAGE
57/******************************************************************************* 56/*******************************************************************************
58 * 57 *
59 * FUNCTION: acpi_evaluate_object_typed 58 * FUNCTION: acpi_evaluate_object_typed
@@ -147,7 +146,7 @@ acpi_evaluate_object_typed(acpi_handle handle,
147} 146}
148 147
149ACPI_EXPORT_SYMBOL(acpi_evaluate_object_typed) 148ACPI_EXPORT_SYMBOL(acpi_evaluate_object_typed)
150#endif /* ACPI_FUTURE_USAGE */ 149
151/******************************************************************************* 150/*******************************************************************************
152 * 151 *
153 * FUNCTION: acpi_evaluate_object 152 * FUNCTION: acpi_evaluate_object
diff --git a/drivers/hwmon/Kconfig b/drivers/hwmon/Kconfig
index ce52bf2f235e..6c0f1bad8821 100644
--- a/drivers/hwmon/Kconfig
+++ b/drivers/hwmon/Kconfig
@@ -248,6 +248,18 @@ config SENSORS_ASB100
248 This driver can also be built as a module. If so, the module 248 This driver can also be built as a module. If so, the module
249 will be called asb100. 249 will be called asb100.
250 250
251config SENSORS_ATK0110
252 tristate "ASUS ATK0110 ACPI hwmon"
253 depends on X86 && ACPI && EXPERIMENTAL
254 help
255 If you say yes here you get support for the ACPI hardware
256 monitoring interface found in many ASUS motherboards. This
257 driver will provide readings of fans, voltages and temperatures
258 through the system firmware.
259
260 This driver can also be built as a module. If so, the module
261 will be called asus_atk0110.
262
251config SENSORS_ATXP1 263config SENSORS_ATXP1
252 tristate "Attansic ATXP1 VID controller" 264 tristate "Attansic ATXP1 VID controller"
253 depends on I2C && EXPERIMENTAL 265 depends on I2C && EXPERIMENTAL
diff --git a/drivers/hwmon/Makefile b/drivers/hwmon/Makefile
index 3a6b1f06f8f4..556855b09037 100644
--- a/drivers/hwmon/Makefile
+++ b/drivers/hwmon/Makefile
@@ -32,6 +32,7 @@ obj-$(CONFIG_SENSORS_ADT7475) += adt7475.o
32 32
33obj-$(CONFIG_SENSORS_APPLESMC) += applesmc.o 33obj-$(CONFIG_SENSORS_APPLESMC) += applesmc.o
34obj-$(CONFIG_SENSORS_AMS) += ams/ 34obj-$(CONFIG_SENSORS_AMS) += ams/
35obj-$(CONFIG_SENSORS_ATK0110) += asus_atk0110.o
35obj-$(CONFIG_SENSORS_ATXP1) += atxp1.o 36obj-$(CONFIG_SENSORS_ATXP1) += atxp1.o
36obj-$(CONFIG_SENSORS_CORETEMP) += coretemp.o 37obj-$(CONFIG_SENSORS_CORETEMP) += coretemp.o
37obj-$(CONFIG_SENSORS_DME1737) += dme1737.o 38obj-$(CONFIG_SENSORS_DME1737) += dme1737.o
diff --git a/drivers/hwmon/asus_atk0110.c b/drivers/hwmon/asus_atk0110.c
new file mode 100644
index 000000000000..0897edef2574
--- /dev/null
+++ b/drivers/hwmon/asus_atk0110.c
@@ -0,0 +1,1009 @@
1/*
2 * Copyright (C) 2007-2009 Luca Tettamanti <kronos.it@gmail.com>
3 *
4 * This file is released under the GPLv2
5 * See COPYING in the top level directory of the kernel tree.
6 */
7
8#include <linux/kernel.h>
9#include <linux/hwmon.h>
10#include <linux/list.h>
11#include <linux/module.h>
12
13#include <acpi/acpi.h>
14#include <acpi/acpixf.h>
15#include <acpi/acpi_drivers.h>
16#include <acpi/acpi_bus.h>
17
18
19#define ATK_HID "ATK0110"
20
21/* Minimum time between readings, enforced in order to avoid
22 * hogging the CPU.
23 */
24#define CACHE_TIME HZ
25
26#define BOARD_ID "MBIF"
27#define METHOD_ENUMERATE "GGRP"
28#define METHOD_READ "GITM"
29#define METHOD_WRITE "SITM"
30#define METHOD_OLD_READ_TMP "RTMP"
31#define METHOD_OLD_READ_VLT "RVLT"
32#define METHOD_OLD_READ_FAN "RFAN"
33#define METHOD_OLD_ENUM_TMP "TSIF"
34#define METHOD_OLD_ENUM_VLT "VSIF"
35#define METHOD_OLD_ENUM_FAN "FSIF"
36
37#define ATK_MUX_HWMON 0x00000006ULL
38
39#define ATK_CLASS_MASK 0xff000000ULL
40#define ATK_CLASS_FREQ_CTL 0x03000000ULL
41#define ATK_CLASS_FAN_CTL 0x04000000ULL
42#define ATK_CLASS_HWMON 0x06000000ULL
43
44#define ATK_TYPE_MASK 0x00ff0000ULL
45#define HWMON_TYPE_VOLT 0x00020000ULL
46#define HWMON_TYPE_TEMP 0x00030000ULL
47#define HWMON_TYPE_FAN 0x00040000ULL
48
49#define HWMON_SENSOR_ID_MASK 0x0000ffffULL
50
51enum atk_pack_member {
52 HWMON_PACK_FLAGS,
53 HWMON_PACK_NAME,
54 HWMON_PACK_LIMIT1,
55 HWMON_PACK_LIMIT2,
56 HWMON_PACK_ENABLE
57};
58
59/* New package format */
60#define _HWMON_NEW_PACK_SIZE 7
61#define _HWMON_NEW_PACK_FLAGS 0
62#define _HWMON_NEW_PACK_NAME 1
63#define _HWMON_NEW_PACK_UNK1 2
64#define _HWMON_NEW_PACK_UNK2 3
65#define _HWMON_NEW_PACK_LIMIT1 4
66#define _HWMON_NEW_PACK_LIMIT2 5
67#define _HWMON_NEW_PACK_ENABLE 6
68
69/* Old package format */
70#define _HWMON_OLD_PACK_SIZE 5
71#define _HWMON_OLD_PACK_FLAGS 0
72#define _HWMON_OLD_PACK_NAME 1
73#define _HWMON_OLD_PACK_LIMIT1 2
74#define _HWMON_OLD_PACK_LIMIT2 3
75#define _HWMON_OLD_PACK_ENABLE 4
76
77
78struct atk_data {
79 struct device *hwmon_dev;
80 acpi_handle atk_handle;
81 struct acpi_device *acpi_dev;
82
83 bool old_interface;
84
85 /* old interface */
86 acpi_handle rtmp_handle;
87 acpi_handle rvlt_handle;
88 acpi_handle rfan_handle;
89 /* new inteface */
90 acpi_handle enumerate_handle;
91 acpi_handle read_handle;
92
93 int voltage_count;
94 int temperature_count;
95 int fan_count;
96 struct list_head sensor_list;
97};
98
99
100typedef ssize_t (*sysfs_show_func)(struct device *dev,
101 struct device_attribute *attr, char *buf);
102
103static const struct acpi_device_id atk_ids[] = {
104 {ATK_HID, 0},
105 {"", 0},
106};
107MODULE_DEVICE_TABLE(acpi, atk_ids);
108
109#define ATTR_NAME_SIZE 16 /* Worst case is "tempN_input" */
110
111struct atk_sensor_data {
112 struct list_head list;
113 struct atk_data *data;
114 struct device_attribute label_attr;
115 struct device_attribute input_attr;
116 struct device_attribute limit1_attr;
117 struct device_attribute limit2_attr;
118 char label_attr_name[ATTR_NAME_SIZE];
119 char input_attr_name[ATTR_NAME_SIZE];
120 char limit1_attr_name[ATTR_NAME_SIZE];
121 char limit2_attr_name[ATTR_NAME_SIZE];
122 u64 id;
123 u64 type;
124 u64 limit1;
125 u64 limit2;
126 u64 cached_value;
127 unsigned long last_updated; /* in jiffies */
128 bool is_valid;
129 char const *acpi_name;
130};
131
132struct atk_acpi_buffer_u64 {
133 union acpi_object buf;
134 u64 value;
135};
136
137static int atk_add(struct acpi_device *device);
138static int atk_remove(struct acpi_device *device, int type);
139static void atk_print_sensor(struct atk_data *data, union acpi_object *obj);
140static int atk_read_value(struct atk_sensor_data *sensor, u64 *value);
141static void atk_free_sensors(struct atk_data *data);
142
143static struct acpi_driver atk_driver = {
144 .name = ATK_HID,
145 .class = "hwmon",
146 .ids = atk_ids,
147 .ops = {
148 .add = atk_add,
149 .remove = atk_remove,
150 },
151};
152
153#define input_to_atk_sensor(attr) \
154 container_of(attr, struct atk_sensor_data, input_attr)
155
156#define label_to_atk_sensor(attr) \
157 container_of(attr, struct atk_sensor_data, label_attr)
158
159#define limit1_to_atk_sensor(attr) \
160 container_of(attr, struct atk_sensor_data, limit1_attr)
161
162#define limit2_to_atk_sensor(attr) \
163 container_of(attr, struct atk_sensor_data, limit2_attr)
164
165static ssize_t atk_input_show(struct device *dev,
166 struct device_attribute *attr, char *buf)
167{
168 struct atk_sensor_data *s = input_to_atk_sensor(attr);
169 u64 value;
170 int err;
171
172 err = atk_read_value(s, &value);
173 if (err)
174 return err;
175
176 if (s->type == HWMON_TYPE_TEMP)
177 /* ACPI returns decidegree */
178 value *= 100;
179
180 return sprintf(buf, "%llu\n", value);
181}
182
183static ssize_t atk_label_show(struct device *dev,
184 struct device_attribute *attr, char *buf)
185{
186 struct atk_sensor_data *s = label_to_atk_sensor(attr);
187
188 return sprintf(buf, "%s\n", s->acpi_name);
189}
190
191static ssize_t atk_limit1_show(struct device *dev,
192 struct device_attribute *attr, char *buf)
193{
194 struct atk_sensor_data *s = limit1_to_atk_sensor(attr);
195 u64 value = s->limit1;
196
197 if (s->type == HWMON_TYPE_TEMP)
198 value *= 100;
199
200 return sprintf(buf, "%lld\n", value);
201}
202
203static ssize_t atk_limit2_show(struct device *dev,
204 struct device_attribute *attr, char *buf)
205{
206 struct atk_sensor_data *s = limit2_to_atk_sensor(attr);
207 u64 value = s->limit2;
208
209 if (s->type == HWMON_TYPE_TEMP)
210 value *= 100;
211
212 return sprintf(buf, "%lld\n", value);
213}
214
215static ssize_t atk_name_show(struct device *dev,
216 struct device_attribute *attr, char *buf)
217{
218 return sprintf(buf, "atk0110\n");
219}
220static struct device_attribute atk_name_attr =
221 __ATTR(name, 0444, atk_name_show, NULL);
222
223static void atk_init_attribute(struct device_attribute *attr, char *name,
224 sysfs_show_func show)
225{
226 attr->attr.name = name;
227 attr->attr.mode = 0444;
228 attr->show = show;
229 attr->store = NULL;
230}
231
232
233static union acpi_object *atk_get_pack_member(struct atk_data *data,
234 union acpi_object *pack,
235 enum atk_pack_member m)
236{
237 bool old_if = data->old_interface;
238 int offset;
239
240 switch (m) {
241 case HWMON_PACK_FLAGS:
242 offset = old_if ? _HWMON_OLD_PACK_FLAGS : _HWMON_NEW_PACK_FLAGS;
243 break;
244 case HWMON_PACK_NAME:
245 offset = old_if ? _HWMON_OLD_PACK_NAME : _HWMON_NEW_PACK_NAME;
246 break;
247 case HWMON_PACK_LIMIT1:
248 offset = old_if ? _HWMON_OLD_PACK_LIMIT1 :
249 _HWMON_NEW_PACK_LIMIT1;
250 break;
251 case HWMON_PACK_LIMIT2:
252 offset = old_if ? _HWMON_OLD_PACK_LIMIT2 :
253 _HWMON_NEW_PACK_LIMIT2;
254 break;
255 case HWMON_PACK_ENABLE:
256 offset = old_if ? _HWMON_OLD_PACK_ENABLE :
257 _HWMON_NEW_PACK_ENABLE;
258 break;
259 default:
260 return NULL;
261 }
262
263 return &pack->package.elements[offset];
264}
265
266
267/* New package format is:
268 * - flag (int)
269 * class - used for de-muxing the request to the correct GITn
270 * type (volt, temp, fan)
271 * sensor id |
272 * sensor id - used for de-muxing the request _inside_ the GITn
273 * - name (str)
274 * - unknown (int)
275 * - unknown (int)
276 * - limit1 (int)
277 * - limit2 (int)
278 * - enable (int)
279 *
280 * The old package has the same format but it's missing the two unknown fields.
281 */
282static int validate_hwmon_pack(struct atk_data *data, union acpi_object *obj)
283{
284 struct device *dev = &data->acpi_dev->dev;
285 union acpi_object *tmp;
286 bool old_if = data->old_interface;
287 int const expected_size = old_if ? _HWMON_OLD_PACK_SIZE :
288 _HWMON_NEW_PACK_SIZE;
289
290 if (obj->type != ACPI_TYPE_PACKAGE) {
291 dev_warn(dev, "Invalid type: %d\n", obj->type);
292 return -EINVAL;
293 }
294
295 if (obj->package.count != expected_size) {
296 dev_warn(dev, "Invalid package size: %d, expected: %d\n",
297 obj->package.count, expected_size);
298 return -EINVAL;
299 }
300
301 tmp = atk_get_pack_member(data, obj, HWMON_PACK_FLAGS);
302 if (tmp->type != ACPI_TYPE_INTEGER) {
303 dev_warn(dev, "Invalid type (flag): %d\n", tmp->type);
304 return -EINVAL;
305 }
306
307 tmp = atk_get_pack_member(data, obj, HWMON_PACK_NAME);
308 if (tmp->type != ACPI_TYPE_STRING) {
309 dev_warn(dev, "Invalid type (name): %d\n", tmp->type);
310 return -EINVAL;
311 }
312
313 /* Don't check... we don't know what they're useful for anyway */
314#if 0
315 tmp = &obj->package.elements[HWMON_PACK_UNK1];
316 if (tmp->type != ACPI_TYPE_INTEGER) {
317 dev_warn(dev, "Invalid type (unk1): %d\n", tmp->type);
318 return -EINVAL;
319 }
320
321 tmp = &obj->package.elements[HWMON_PACK_UNK2];
322 if (tmp->type != ACPI_TYPE_INTEGER) {
323 dev_warn(dev, "Invalid type (unk2): %d\n", tmp->type);
324 return -EINVAL;
325 }
326#endif
327
328 tmp = atk_get_pack_member(data, obj, HWMON_PACK_LIMIT1);
329 if (tmp->type != ACPI_TYPE_INTEGER) {
330 dev_warn(dev, "Invalid type (limit1): %d\n", tmp->type);
331 return -EINVAL;
332 }
333
334 tmp = atk_get_pack_member(data, obj, HWMON_PACK_LIMIT2);
335 if (tmp->type != ACPI_TYPE_INTEGER) {
336 dev_warn(dev, "Invalid type (limit2): %d\n", tmp->type);
337 return -EINVAL;
338 }
339
340 tmp = atk_get_pack_member(data, obj, HWMON_PACK_ENABLE);
341 if (tmp->type != ACPI_TYPE_INTEGER) {
342 dev_warn(dev, "Invalid type (enable): %d\n", tmp->type);
343 return -EINVAL;
344 }
345
346 atk_print_sensor(data, obj);
347
348 return 0;
349}
350
351static char const *atk_sensor_type(union acpi_object *flags)
352{
353 u64 type = flags->integer.value & ATK_TYPE_MASK;
354 char const *what;
355
356 switch (type) {
357 case HWMON_TYPE_VOLT:
358 what = "voltage";
359 break;
360 case HWMON_TYPE_TEMP:
361 what = "temperature";
362 break;
363 case HWMON_TYPE_FAN:
364 what = "fan";
365 break;
366 default:
367 what = "unknown";
368 break;
369 }
370
371 return what;
372}
373
374static void atk_print_sensor(struct atk_data *data, union acpi_object *obj)
375{
376#ifdef DEBUG
377 struct device *dev = &data->acpi_dev->dev;
378 union acpi_object *flags;
379 union acpi_object *name;
380 union acpi_object *limit1;
381 union acpi_object *limit2;
382 union acpi_object *enable;
383 char const *what;
384
385 flags = atk_get_pack_member(data, obj, HWMON_PACK_FLAGS);
386 name = atk_get_pack_member(data, obj, HWMON_PACK_NAME);
387 limit1 = atk_get_pack_member(data, obj, HWMON_PACK_LIMIT1);
388 limit2 = atk_get_pack_member(data, obj, HWMON_PACK_LIMIT2);
389 enable = atk_get_pack_member(data, obj, HWMON_PACK_ENABLE);
390
391 what = atk_sensor_type(flags);
392
393 dev_dbg(dev, "%s: %#llx %s [%llu-%llu] %s\n", what,
394 flags->integer.value,
395 name->string.pointer,
396 limit1->integer.value, limit2->integer.value,
397 enable->integer.value ? "enabled" : "disabled");
398#endif
399}
400
401static int atk_read_value_old(struct atk_sensor_data *sensor, u64 *value)
402{
403 struct atk_data *data = sensor->data;
404 struct device *dev = &data->acpi_dev->dev;
405 struct acpi_object_list params;
406 union acpi_object id;
407 acpi_status status;
408 acpi_handle method;
409
410 switch (sensor->type) {
411 case HWMON_TYPE_VOLT:
412 method = data->rvlt_handle;
413 break;
414 case HWMON_TYPE_TEMP:
415 method = data->rtmp_handle;
416 break;
417 case HWMON_TYPE_FAN:
418 method = data->rfan_handle;
419 break;
420 default:
421 return -EINVAL;
422 }
423
424 id.type = ACPI_TYPE_INTEGER;
425 id.integer.value = sensor->id;
426
427 params.count = 1;
428 params.pointer = &id;
429
430 status = acpi_evaluate_integer(method, NULL, &params, value);
431 if (status != AE_OK) {
432 dev_warn(dev, "%s: ACPI exception: %s\n", __func__,
433 acpi_format_exception(status));
434 return -EIO;
435 }
436
437 return 0;
438}
439
440static int atk_read_value_new(struct atk_sensor_data *sensor, u64 *value)
441{
442 struct atk_data *data = sensor->data;
443 struct device *dev = &data->acpi_dev->dev;
444 struct acpi_object_list params;
445 struct acpi_buffer ret;
446 union acpi_object id;
447 struct atk_acpi_buffer_u64 tmp;
448 acpi_status status;
449
450 id.type = ACPI_TYPE_INTEGER;
451 id.integer.value = sensor->id;
452
453 params.count = 1;
454 params.pointer = &id;
455
456 tmp.buf.type = ACPI_TYPE_BUFFER;
457 tmp.buf.buffer.pointer = (u8 *)&tmp.value;
458 tmp.buf.buffer.length = sizeof(u64);
459 ret.length = sizeof(tmp);
460 ret.pointer = &tmp;
461
462 status = acpi_evaluate_object_typed(data->read_handle, NULL, &params,
463 &ret, ACPI_TYPE_BUFFER);
464 if (status != AE_OK) {
465 dev_warn(dev, "%s: ACPI exception: %s\n", __func__,
466 acpi_format_exception(status));
467 return -EIO;
468 }
469
470 /* Return buffer format:
471 * [0-3] "value" is valid flag
472 * [4-7] value
473 */
474 if (!(tmp.value & 0xffffffff)) {
475 /* The reading is not valid, possible causes:
476 * - sensor failure
477 * - enumeration was FUBAR (and we didn't notice)
478 */
479 dev_info(dev, "Failure: %#llx\n", tmp.value);
480 return -EIO;
481 }
482
483 *value = (tmp.value & 0xffffffff00000000ULL) >> 32;
484
485 return 0;
486}
487
488static int atk_read_value(struct atk_sensor_data *sensor, u64 *value)
489{
490 int err;
491
492 if (!sensor->is_valid ||
493 time_after(jiffies, sensor->last_updated + CACHE_TIME)) {
494 if (sensor->data->old_interface)
495 err = atk_read_value_old(sensor, value);
496 else
497 err = atk_read_value_new(sensor, value);
498
499 sensor->is_valid = true;
500 sensor->last_updated = jiffies;
501 sensor->cached_value = *value;
502 } else {
503 *value = sensor->cached_value;
504 err = 0;
505 }
506
507 return err;
508}
509
510static int atk_add_sensor(struct atk_data *data, union acpi_object *obj)
511{
512 struct device *dev = &data->acpi_dev->dev;
513 union acpi_object *flags;
514 union acpi_object *name;
515 union acpi_object *limit1;
516 union acpi_object *limit2;
517 union acpi_object *enable;
518 struct atk_sensor_data *sensor;
519 char const *base_name;
520 char const *limit1_name;
521 char const *limit2_name;
522 u64 type;
523 int err;
524 int *num;
525 int start;
526
527 if (obj->type != ACPI_TYPE_PACKAGE) {
528 /* wft is this? */
529 dev_warn(dev, "Unknown type for ACPI object: (%d)\n",
530 obj->type);
531 return -EINVAL;
532 }
533
534 err = validate_hwmon_pack(data, obj);
535 if (err)
536 return err;
537
538 /* Ok, we have a valid hwmon package */
539 type = atk_get_pack_member(data, obj, HWMON_PACK_FLAGS)->integer.value
540 & ATK_TYPE_MASK;
541
542 switch (type) {
543 case HWMON_TYPE_VOLT:
544 base_name = "in";
545 limit1_name = "min";
546 limit2_name = "max";
547 num = &data->voltage_count;
548 start = 0;
549 break;
550 case HWMON_TYPE_TEMP:
551 base_name = "temp";
552 limit1_name = "max";
553 limit2_name = "crit";
554 num = &data->temperature_count;
555 start = 1;
556 break;
557 case HWMON_TYPE_FAN:
558 base_name = "fan";
559 limit1_name = "min";
560 limit2_name = "max";
561 num = &data->fan_count;
562 start = 1;
563 break;
564 default:
565 dev_warn(dev, "Unknown sensor type: %#llx\n", type);
566 return -EINVAL;
567 }
568
569 enable = atk_get_pack_member(data, obj, HWMON_PACK_ENABLE);
570 if (!enable->integer.value)
571 /* sensor is disabled */
572 return 0;
573
574 flags = atk_get_pack_member(data, obj, HWMON_PACK_FLAGS);
575 name = atk_get_pack_member(data, obj, HWMON_PACK_NAME);
576 limit1 = atk_get_pack_member(data, obj, HWMON_PACK_LIMIT1);
577 limit2 = atk_get_pack_member(data, obj, HWMON_PACK_LIMIT2);
578
579 sensor = kzalloc(sizeof(*sensor), GFP_KERNEL);
580 if (!sensor)
581 return -ENOMEM;
582
583 sensor->acpi_name = kstrdup(name->string.pointer, GFP_KERNEL);
584 if (!sensor->acpi_name) {
585 err = -ENOMEM;
586 goto out;
587 }
588
589 INIT_LIST_HEAD(&sensor->list);
590 sensor->type = type;
591 sensor->data = data;
592 sensor->id = flags->integer.value;
593 sensor->limit1 = limit1->integer.value;
594 sensor->limit2 = limit2->integer.value;
595
596 snprintf(sensor->input_attr_name, ATTR_NAME_SIZE,
597 "%s%d_input", base_name, start + *num);
598 atk_init_attribute(&sensor->input_attr,
599 sensor->input_attr_name,
600 atk_input_show);
601
602 snprintf(sensor->label_attr_name, ATTR_NAME_SIZE,
603 "%s%d_label", base_name, start + *num);
604 atk_init_attribute(&sensor->label_attr,
605 sensor->label_attr_name,
606 atk_label_show);
607
608 snprintf(sensor->limit1_attr_name, ATTR_NAME_SIZE,
609 "%s%d_%s", base_name, start + *num, limit1_name);
610 atk_init_attribute(&sensor->limit1_attr,
611 sensor->limit1_attr_name,
612 atk_limit1_show);
613
614 snprintf(sensor->limit2_attr_name, ATTR_NAME_SIZE,
615 "%s%d_%s", base_name, start + *num, limit2_name);
616 atk_init_attribute(&sensor->limit2_attr,
617 sensor->limit2_attr_name,
618 atk_limit2_show);
619
620 list_add(&sensor->list, &data->sensor_list);
621 (*num)++;
622
623 return 1;
624out:
625 kfree(sensor->acpi_name);
626 kfree(sensor);
627 return err;
628}
629
630static int atk_enumerate_old_hwmon(struct atk_data *data)
631{
632 struct device *dev = &data->acpi_dev->dev;
633 struct acpi_buffer buf;
634 union acpi_object *pack;
635 acpi_status status;
636 int i, ret;
637 int count = 0;
638
639 /* Voltages */
640 buf.length = ACPI_ALLOCATE_BUFFER;
641 status = acpi_evaluate_object_typed(data->atk_handle,
642 METHOD_OLD_ENUM_VLT, NULL, &buf, ACPI_TYPE_PACKAGE);
643 if (status != AE_OK) {
644 dev_warn(dev, METHOD_OLD_ENUM_VLT ": ACPI exception: %s\n",
645 acpi_format_exception(status));
646
647 return -ENODEV;
648 }
649
650 pack = buf.pointer;
651 for (i = 1; i < pack->package.count; i++) {
652 union acpi_object *obj = &pack->package.elements[i];
653
654 ret = atk_add_sensor(data, obj);
655 if (ret > 0)
656 count++;
657 }
658 ACPI_FREE(buf.pointer);
659
660 /* Temperatures */
661 buf.length = ACPI_ALLOCATE_BUFFER;
662 status = acpi_evaluate_object_typed(data->atk_handle,
663 METHOD_OLD_ENUM_TMP, NULL, &buf, ACPI_TYPE_PACKAGE);
664 if (status != AE_OK) {
665 dev_warn(dev, METHOD_OLD_ENUM_TMP ": ACPI exception: %s\n",
666 acpi_format_exception(status));
667
668 ret = -ENODEV;
669 goto cleanup;
670 }
671
672 pack = buf.pointer;
673 for (i = 1; i < pack->package.count; i++) {
674 union acpi_object *obj = &pack->package.elements[i];
675
676 ret = atk_add_sensor(data, obj);
677 if (ret > 0)
678 count++;
679 }
680 ACPI_FREE(buf.pointer);
681
682 /* Fans */
683 buf.length = ACPI_ALLOCATE_BUFFER;
684 status = acpi_evaluate_object_typed(data->atk_handle,
685 METHOD_OLD_ENUM_FAN, NULL, &buf, ACPI_TYPE_PACKAGE);
686 if (status != AE_OK) {
687 dev_warn(dev, METHOD_OLD_ENUM_FAN ": ACPI exception: %s\n",
688 acpi_format_exception(status));
689
690 ret = -ENODEV;
691 goto cleanup;
692 }
693
694 pack = buf.pointer;
695 for (i = 1; i < pack->package.count; i++) {
696 union acpi_object *obj = &pack->package.elements[i];
697
698 ret = atk_add_sensor(data, obj);
699 if (ret > 0)
700 count++;
701 }
702 ACPI_FREE(buf.pointer);
703
704 return count;
705cleanup:
706 atk_free_sensors(data);
707 return ret;
708}
709
710static int atk_enumerate_new_hwmon(struct atk_data *data)
711{
712 struct device *dev = &data->acpi_dev->dev;
713 struct acpi_buffer buf;
714 acpi_status ret;
715 struct acpi_object_list params;
716 union acpi_object id;
717 union acpi_object *pack;
718 int err;
719 int i;
720
721 dev_dbg(dev, "Enumerating hwmon sensors\n");
722
723 id.type = ACPI_TYPE_INTEGER;
724 id.integer.value = ATK_MUX_HWMON;
725 params.count = 1;
726 params.pointer = &id;
727
728 buf.length = ACPI_ALLOCATE_BUFFER;
729 ret = acpi_evaluate_object_typed(data->enumerate_handle, NULL, &params,
730 &buf, ACPI_TYPE_PACKAGE);
731 if (ret != AE_OK) {
732 dev_warn(dev, METHOD_ENUMERATE ": ACPI exception: %s\n",
733 acpi_format_exception(ret));
734 return -ENODEV;
735 }
736
737 /* Result must be a package */
738 pack = buf.pointer;
739
740 if (pack->package.count < 1) {
741 dev_dbg(dev, "%s: hwmon package is too small: %d\n", __func__,
742 pack->package.count);
743 err = -EINVAL;
744 goto out;
745 }
746
747 for (i = 0; i < pack->package.count; i++) {
748 union acpi_object *obj = &pack->package.elements[i];
749
750 atk_add_sensor(data, obj);
751 }
752
753 err = data->voltage_count + data->temperature_count + data->fan_count;
754
755out:
756 ACPI_FREE(buf.pointer);
757 return err;
758}
759
760static int atk_create_files(struct atk_data *data)
761{
762 struct atk_sensor_data *s;
763 int err;
764
765 list_for_each_entry(s, &data->sensor_list, list) {
766 err = device_create_file(data->hwmon_dev, &s->input_attr);
767 if (err)
768 return err;
769 err = device_create_file(data->hwmon_dev, &s->label_attr);
770 if (err)
771 return err;
772 err = device_create_file(data->hwmon_dev, &s->limit1_attr);
773 if (err)
774 return err;
775 err = device_create_file(data->hwmon_dev, &s->limit2_attr);
776 if (err)
777 return err;
778 }
779
780 err = device_create_file(data->hwmon_dev, &atk_name_attr);
781
782 return err;
783}
784
785static void atk_remove_files(struct atk_data *data)
786{
787 struct atk_sensor_data *s;
788
789 list_for_each_entry(s, &data->sensor_list, list) {
790 device_remove_file(data->hwmon_dev, &s->input_attr);
791 device_remove_file(data->hwmon_dev, &s->label_attr);
792 device_remove_file(data->hwmon_dev, &s->limit1_attr);
793 device_remove_file(data->hwmon_dev, &s->limit2_attr);
794 }
795 device_remove_file(data->hwmon_dev, &atk_name_attr);
796}
797
798static void atk_free_sensors(struct atk_data *data)
799{
800 struct list_head *head = &data->sensor_list;
801 struct atk_sensor_data *s, *tmp;
802
803 list_for_each_entry_safe(s, tmp, head, list) {
804 kfree(s->acpi_name);
805 kfree(s);
806 }
807}
808
809static int atk_register_hwmon(struct atk_data *data)
810{
811 struct device *dev = &data->acpi_dev->dev;
812 int err;
813
814 dev_dbg(dev, "registering hwmon device\n");
815 data->hwmon_dev = hwmon_device_register(dev);
816 if (IS_ERR(data->hwmon_dev))
817 return PTR_ERR(data->hwmon_dev);
818
819 dev_dbg(dev, "populating sysfs directory\n");
820 err = atk_create_files(data);
821 if (err)
822 goto remove;
823
824 return 0;
825remove:
826 /* Cleanup the registered files */
827 atk_remove_files(data);
828 hwmon_device_unregister(data->hwmon_dev);
829 return err;
830}
831
832static int atk_check_old_if(struct atk_data *data)
833{
834 struct device *dev = &data->acpi_dev->dev;
835 acpi_handle ret;
836 acpi_status status;
837
838 /* RTMP: read temperature */
839 status = acpi_get_handle(data->atk_handle, METHOD_OLD_READ_TMP, &ret);
840 if (status != AE_OK) {
841 dev_dbg(dev, "method " METHOD_OLD_READ_TMP " not found: %s\n",
842 acpi_format_exception(status));
843 return -ENODEV;
844 }
845 data->rtmp_handle = ret;
846
847 /* RVLT: read voltage */
848 status = acpi_get_handle(data->atk_handle, METHOD_OLD_READ_VLT, &ret);
849 if (status != AE_OK) {
850 dev_dbg(dev, "method " METHOD_OLD_READ_VLT " not found: %s\n",
851 acpi_format_exception(status));
852 return -ENODEV;
853 }
854 data->rvlt_handle = ret;
855
856 /* RFAN: read fan status */
857 status = acpi_get_handle(data->atk_handle, METHOD_OLD_READ_FAN, &ret);
858 if (status != AE_OK) {
859 dev_dbg(dev, "method " METHOD_OLD_READ_FAN " not found: %s\n",
860 acpi_format_exception(status));
861 return -ENODEV;
862 }
863 data->rfan_handle = ret;
864
865 return 0;
866}
867
868static int atk_check_new_if(struct atk_data *data)
869{
870 struct device *dev = &data->acpi_dev->dev;
871 acpi_handle ret;
872 acpi_status status;
873
874 /* Enumeration */
875 status = acpi_get_handle(data->atk_handle, METHOD_ENUMERATE, &ret);
876 if (status != AE_OK) {
877 dev_dbg(dev, "method " METHOD_ENUMERATE " not found: %s\n",
878 acpi_format_exception(status));
879 return -ENODEV;
880 }
881 data->enumerate_handle = ret;
882
883 /* De-multiplexer (read) */
884 status = acpi_get_handle(data->atk_handle, METHOD_READ, &ret);
885 if (status != AE_OK) {
886 dev_dbg(dev, "method " METHOD_READ " not found: %s\n",
887 acpi_format_exception(status));
888 return -ENODEV;
889 }
890 data->read_handle = ret;
891
892 return 0;
893}
894
895static int atk_add(struct acpi_device *device)
896{
897 acpi_status ret;
898 int err;
899 struct acpi_buffer buf;
900 union acpi_object *obj;
901 struct atk_data *data;
902
903 dev_dbg(&device->dev, "adding...\n");
904
905 data = kzalloc(sizeof(*data), GFP_KERNEL);
906 if (!data)
907 return -ENOMEM;
908
909 data->acpi_dev = device;
910 data->atk_handle = device->handle;
911 INIT_LIST_HEAD(&data->sensor_list);
912
913 buf.length = ACPI_ALLOCATE_BUFFER;
914 ret = acpi_evaluate_object_typed(data->atk_handle, BOARD_ID, NULL,
915 &buf, ACPI_TYPE_PACKAGE);
916 if (ret != AE_OK) {
917 dev_dbg(&device->dev, "atk: method MBIF not found\n");
918 err = -ENODEV;
919 goto out;
920 }
921
922 obj = buf.pointer;
923 if (obj->package.count >= 2 &&
924 obj->package.elements[1].type == ACPI_TYPE_STRING) {
925 dev_dbg(&device->dev, "board ID = %s\n",
926 obj->package.elements[1].string.pointer);
927 }
928 ACPI_FREE(buf.pointer);
929
930 /* Check for hwmon methods: first check "old" style methods; note that
931 * both may be present: in this case we stick to the old interface;
932 * analysis of multiple DSDTs indicates that when both interfaces
933 * are present the new one (GGRP/GITM) is not functional.
934 */
935 err = atk_check_old_if(data);
936 if (!err) {
937 dev_dbg(&device->dev, "Using old hwmon interface\n");
938 data->old_interface = true;
939 } else {
940 err = atk_check_new_if(data);
941 if (err)
942 goto out;
943
944 dev_dbg(&device->dev, "Using new hwmon interface\n");
945 data->old_interface = false;
946 }
947
948 if (data->old_interface)
949 err = atk_enumerate_old_hwmon(data);
950 else
951 err = atk_enumerate_new_hwmon(data);
952 if (err < 0)
953 goto out;
954 if (err == 0) {
955 dev_info(&device->dev,
956 "No usable sensor detected, bailing out\n");
957 err = -ENODEV;
958 goto out;
959 }
960
961 err = atk_register_hwmon(data);
962 if (err)
963 goto cleanup;
964
965 device->driver_data = data;
966 return 0;
967cleanup:
968 atk_free_sensors(data);
969out:
970 kfree(data);
971 return err;
972}
973
974static int atk_remove(struct acpi_device *device, int type)
975{
976 struct atk_data *data = device->driver_data;
977 dev_dbg(&device->dev, "removing...\n");
978
979 device->driver_data = NULL;
980
981 atk_remove_files(data);
982 atk_free_sensors(data);
983 hwmon_device_unregister(data->hwmon_dev);
984
985 kfree(data);
986
987 return 0;
988}
989
990static int __init atk0110_init(void)
991{
992 int ret;
993
994 ret = acpi_bus_register_driver(&atk_driver);
995 if (ret)
996 pr_info("atk: acpi_bus_register_driver failed: %d\n", ret);
997
998 return ret;
999}
1000
1001static void __exit atk0110_exit(void)
1002{
1003 acpi_bus_unregister_driver(&atk_driver);
1004}
1005
1006module_init(atk0110_init);
1007module_exit(atk0110_exit);
1008
1009MODULE_LICENSE("GPL");
diff --git a/include/acpi/acpixf.h b/include/acpi/acpixf.h
index aeaf7cd41dc7..4db89e98535d 100644
--- a/include/acpi/acpixf.h
+++ b/include/acpi/acpixf.h
@@ -191,14 +191,12 @@ acpi_evaluate_object(acpi_handle object,
191 struct acpi_object_list *parameter_objects, 191 struct acpi_object_list *parameter_objects,
192 struct acpi_buffer *return_object_buffer); 192 struct acpi_buffer *return_object_buffer);
193 193
194#ifdef ACPI_FUTURE_USAGE
195acpi_status 194acpi_status
196acpi_evaluate_object_typed(acpi_handle object, 195acpi_evaluate_object_typed(acpi_handle object,
197 acpi_string pathname, 196 acpi_string pathname,
198 struct acpi_object_list *external_params, 197 struct acpi_object_list *external_params,
199 struct acpi_buffer *return_buffer, 198 struct acpi_buffer *return_buffer,
200 acpi_object_type return_type); 199 acpi_object_type return_type);
201#endif
202 200
203acpi_status 201acpi_status
204acpi_get_object_info(acpi_handle handle, struct acpi_buffer *return_buffer); 202acpi_get_object_info(acpi_handle handle, struct acpi_buffer *return_buffer);