xref: /openbmc/linux/drivers/hwmon/asus_atk0110.c (revision 18e255558574c5663c9d72fe82c099d2115aee55)
12c03d07aSLuca Tettamanti /*
22c03d07aSLuca Tettamanti  * Copyright (C) 2007-2009 Luca Tettamanti <kronos.it@gmail.com>
32c03d07aSLuca Tettamanti  *
42c03d07aSLuca Tettamanti  * This file is released under the GPLv2
52c03d07aSLuca Tettamanti  * See COPYING in the top level directory of the kernel tree.
62c03d07aSLuca Tettamanti  */
72c03d07aSLuca Tettamanti 
82c03d07aSLuca Tettamanti #include <linux/kernel.h>
92c03d07aSLuca Tettamanti #include <linux/hwmon.h>
102c03d07aSLuca Tettamanti #include <linux/list.h>
112c03d07aSLuca Tettamanti #include <linux/module.h>
122c03d07aSLuca Tettamanti 
132c03d07aSLuca Tettamanti #include <acpi/acpi.h>
142c03d07aSLuca Tettamanti #include <acpi/acpixf.h>
152c03d07aSLuca Tettamanti #include <acpi/acpi_drivers.h>
162c03d07aSLuca Tettamanti #include <acpi/acpi_bus.h>
172c03d07aSLuca Tettamanti 
182c03d07aSLuca Tettamanti 
192c03d07aSLuca Tettamanti #define ATK_HID "ATK0110"
202c03d07aSLuca Tettamanti 
212c03d07aSLuca Tettamanti /* Minimum time between readings, enforced in order to avoid
222c03d07aSLuca Tettamanti  * hogging the CPU.
232c03d07aSLuca Tettamanti  */
242c03d07aSLuca Tettamanti #define CACHE_TIME		HZ
252c03d07aSLuca Tettamanti 
262c03d07aSLuca Tettamanti #define BOARD_ID		"MBIF"
272c03d07aSLuca Tettamanti #define METHOD_ENUMERATE	"GGRP"
282c03d07aSLuca Tettamanti #define METHOD_READ		"GITM"
292c03d07aSLuca Tettamanti #define METHOD_WRITE		"SITM"
302c03d07aSLuca Tettamanti #define METHOD_OLD_READ_TMP	"RTMP"
312c03d07aSLuca Tettamanti #define METHOD_OLD_READ_VLT	"RVLT"
322c03d07aSLuca Tettamanti #define METHOD_OLD_READ_FAN	"RFAN"
332c03d07aSLuca Tettamanti #define METHOD_OLD_ENUM_TMP	"TSIF"
342c03d07aSLuca Tettamanti #define METHOD_OLD_ENUM_VLT	"VSIF"
352c03d07aSLuca Tettamanti #define METHOD_OLD_ENUM_FAN	"FSIF"
362c03d07aSLuca Tettamanti 
372c03d07aSLuca Tettamanti #define ATK_MUX_HWMON		0x00000006ULL
382c03d07aSLuca Tettamanti 
392c03d07aSLuca Tettamanti #define ATK_CLASS_MASK		0xff000000ULL
402c03d07aSLuca Tettamanti #define ATK_CLASS_FREQ_CTL	0x03000000ULL
412c03d07aSLuca Tettamanti #define ATK_CLASS_FAN_CTL	0x04000000ULL
422c03d07aSLuca Tettamanti #define ATK_CLASS_HWMON		0x06000000ULL
432c03d07aSLuca Tettamanti 
442c03d07aSLuca Tettamanti #define ATK_TYPE_MASK		0x00ff0000ULL
452c03d07aSLuca Tettamanti #define HWMON_TYPE_VOLT		0x00020000ULL
462c03d07aSLuca Tettamanti #define HWMON_TYPE_TEMP		0x00030000ULL
472c03d07aSLuca Tettamanti #define HWMON_TYPE_FAN		0x00040000ULL
482c03d07aSLuca Tettamanti 
492c03d07aSLuca Tettamanti #define HWMON_SENSOR_ID_MASK	0x0000ffffULL
502c03d07aSLuca Tettamanti 
512c03d07aSLuca Tettamanti enum atk_pack_member {
522c03d07aSLuca Tettamanti 	HWMON_PACK_FLAGS,
532c03d07aSLuca Tettamanti 	HWMON_PACK_NAME,
542c03d07aSLuca Tettamanti 	HWMON_PACK_LIMIT1,
552c03d07aSLuca Tettamanti 	HWMON_PACK_LIMIT2,
562c03d07aSLuca Tettamanti 	HWMON_PACK_ENABLE
572c03d07aSLuca Tettamanti };
582c03d07aSLuca Tettamanti 
592c03d07aSLuca Tettamanti /* New package format */
602c03d07aSLuca Tettamanti #define _HWMON_NEW_PACK_SIZE	7
612c03d07aSLuca Tettamanti #define _HWMON_NEW_PACK_FLAGS	0
622c03d07aSLuca Tettamanti #define _HWMON_NEW_PACK_NAME	1
632c03d07aSLuca Tettamanti #define _HWMON_NEW_PACK_UNK1	2
642c03d07aSLuca Tettamanti #define _HWMON_NEW_PACK_UNK2	3
652c03d07aSLuca Tettamanti #define _HWMON_NEW_PACK_LIMIT1	4
662c03d07aSLuca Tettamanti #define _HWMON_NEW_PACK_LIMIT2	5
672c03d07aSLuca Tettamanti #define _HWMON_NEW_PACK_ENABLE	6
682c03d07aSLuca Tettamanti 
692c03d07aSLuca Tettamanti /* Old package format */
702c03d07aSLuca Tettamanti #define _HWMON_OLD_PACK_SIZE	5
712c03d07aSLuca Tettamanti #define _HWMON_OLD_PACK_FLAGS	0
722c03d07aSLuca Tettamanti #define _HWMON_OLD_PACK_NAME	1
732c03d07aSLuca Tettamanti #define _HWMON_OLD_PACK_LIMIT1	2
742c03d07aSLuca Tettamanti #define _HWMON_OLD_PACK_LIMIT2	3
752c03d07aSLuca Tettamanti #define _HWMON_OLD_PACK_ENABLE	4
762c03d07aSLuca Tettamanti 
772c03d07aSLuca Tettamanti 
782c03d07aSLuca Tettamanti struct atk_data {
792c03d07aSLuca Tettamanti 	struct device *hwmon_dev;
802c03d07aSLuca Tettamanti 	acpi_handle atk_handle;
812c03d07aSLuca Tettamanti 	struct acpi_device *acpi_dev;
822c03d07aSLuca Tettamanti 
832c03d07aSLuca Tettamanti 	bool old_interface;
842c03d07aSLuca Tettamanti 
852c03d07aSLuca Tettamanti 	/* old interface */
862c03d07aSLuca Tettamanti 	acpi_handle rtmp_handle;
872c03d07aSLuca Tettamanti 	acpi_handle rvlt_handle;
882c03d07aSLuca Tettamanti 	acpi_handle rfan_handle;
892c03d07aSLuca Tettamanti 	/* new inteface */
902c03d07aSLuca Tettamanti 	acpi_handle enumerate_handle;
912c03d07aSLuca Tettamanti 	acpi_handle read_handle;
922c03d07aSLuca Tettamanti 
932c03d07aSLuca Tettamanti 	int voltage_count;
942c03d07aSLuca Tettamanti 	int temperature_count;
952c03d07aSLuca Tettamanti 	int fan_count;
962c03d07aSLuca Tettamanti 	struct list_head sensor_list;
972c03d07aSLuca Tettamanti };
982c03d07aSLuca Tettamanti 
992c03d07aSLuca Tettamanti 
1002c03d07aSLuca Tettamanti typedef ssize_t (*sysfs_show_func)(struct device *dev,
1012c03d07aSLuca Tettamanti 			struct device_attribute *attr, char *buf);
1022c03d07aSLuca Tettamanti 
1032c03d07aSLuca Tettamanti static const struct acpi_device_id atk_ids[] = {
1042c03d07aSLuca Tettamanti 	{ATK_HID, 0},
1052c03d07aSLuca Tettamanti 	{"", 0},
1062c03d07aSLuca Tettamanti };
1072c03d07aSLuca Tettamanti MODULE_DEVICE_TABLE(acpi, atk_ids);
1082c03d07aSLuca Tettamanti 
1092c03d07aSLuca Tettamanti #define ATTR_NAME_SIZE 16 /* Worst case is "tempN_input" */
1102c03d07aSLuca Tettamanti 
1112c03d07aSLuca Tettamanti struct atk_sensor_data {
1122c03d07aSLuca Tettamanti 	struct list_head list;
1132c03d07aSLuca Tettamanti 	struct atk_data *data;
1142c03d07aSLuca Tettamanti 	struct device_attribute label_attr;
1152c03d07aSLuca Tettamanti 	struct device_attribute input_attr;
1162c03d07aSLuca Tettamanti 	struct device_attribute limit1_attr;
1172c03d07aSLuca Tettamanti 	struct device_attribute limit2_attr;
1182c03d07aSLuca Tettamanti 	char label_attr_name[ATTR_NAME_SIZE];
1192c03d07aSLuca Tettamanti 	char input_attr_name[ATTR_NAME_SIZE];
1202c03d07aSLuca Tettamanti 	char limit1_attr_name[ATTR_NAME_SIZE];
1212c03d07aSLuca Tettamanti 	char limit2_attr_name[ATTR_NAME_SIZE];
1222c03d07aSLuca Tettamanti 	u64 id;
1232c03d07aSLuca Tettamanti 	u64 type;
1242c03d07aSLuca Tettamanti 	u64 limit1;
1252c03d07aSLuca Tettamanti 	u64 limit2;
1262c03d07aSLuca Tettamanti 	u64 cached_value;
1272c03d07aSLuca Tettamanti 	unsigned long last_updated; /* in jiffies */
1282c03d07aSLuca Tettamanti 	bool is_valid;
1292c03d07aSLuca Tettamanti 	char const *acpi_name;
1302c03d07aSLuca Tettamanti };
1312c03d07aSLuca Tettamanti 
132*18e25555SLuca Tettamanti /* Return buffer format:
133*18e25555SLuca Tettamanti  * [0-3] "value" is valid flag
134*18e25555SLuca Tettamanti  * [4-7] value
135*18e25555SLuca Tettamanti  * [8- ] unknown stuff on newer mobos
136*18e25555SLuca Tettamanti  */
137*18e25555SLuca Tettamanti struct atk_acpi_ret_buffer {
138*18e25555SLuca Tettamanti 	u32 flags;
139*18e25555SLuca Tettamanti 	u32 value;
140*18e25555SLuca Tettamanti 	u8 data[];
141*18e25555SLuca Tettamanti };
142*18e25555SLuca Tettamanti 
143*18e25555SLuca Tettamanti /* Input buffer used for GITM and SITM methods */
144*18e25555SLuca Tettamanti struct atk_acpi_input_buf {
145*18e25555SLuca Tettamanti 	u32 id;
146*18e25555SLuca Tettamanti 	u32 param1;
147*18e25555SLuca Tettamanti 	u32 param2;
1482c03d07aSLuca Tettamanti };
1492c03d07aSLuca Tettamanti 
1502c03d07aSLuca Tettamanti static int atk_add(struct acpi_device *device);
1512c03d07aSLuca Tettamanti static int atk_remove(struct acpi_device *device, int type);
1522c03d07aSLuca Tettamanti static void atk_print_sensor(struct atk_data *data, union acpi_object *obj);
1532c03d07aSLuca Tettamanti static int atk_read_value(struct atk_sensor_data *sensor, u64 *value);
1542c03d07aSLuca Tettamanti static void atk_free_sensors(struct atk_data *data);
1552c03d07aSLuca Tettamanti 
1562c03d07aSLuca Tettamanti static struct acpi_driver atk_driver = {
1572c03d07aSLuca Tettamanti 	.name	= ATK_HID,
1582c03d07aSLuca Tettamanti 	.class	= "hwmon",
1592c03d07aSLuca Tettamanti 	.ids	= atk_ids,
1602c03d07aSLuca Tettamanti 	.ops	= {
1612c03d07aSLuca Tettamanti 		.add	= atk_add,
1622c03d07aSLuca Tettamanti 		.remove	= atk_remove,
1632c03d07aSLuca Tettamanti 	},
1642c03d07aSLuca Tettamanti };
1652c03d07aSLuca Tettamanti 
1662c03d07aSLuca Tettamanti #define input_to_atk_sensor(attr) \
1672c03d07aSLuca Tettamanti 	container_of(attr, struct atk_sensor_data, input_attr)
1682c03d07aSLuca Tettamanti 
1692c03d07aSLuca Tettamanti #define label_to_atk_sensor(attr) \
1702c03d07aSLuca Tettamanti 	container_of(attr, struct atk_sensor_data, label_attr)
1712c03d07aSLuca Tettamanti 
1722c03d07aSLuca Tettamanti #define limit1_to_atk_sensor(attr) \
1732c03d07aSLuca Tettamanti 	container_of(attr, struct atk_sensor_data, limit1_attr)
1742c03d07aSLuca Tettamanti 
1752c03d07aSLuca Tettamanti #define limit2_to_atk_sensor(attr) \
1762c03d07aSLuca Tettamanti 	container_of(attr, struct atk_sensor_data, limit2_attr)
1772c03d07aSLuca Tettamanti 
1782c03d07aSLuca Tettamanti static ssize_t atk_input_show(struct device *dev,
1792c03d07aSLuca Tettamanti 		struct device_attribute *attr, char *buf)
1802c03d07aSLuca Tettamanti {
1812c03d07aSLuca Tettamanti 	struct atk_sensor_data *s = input_to_atk_sensor(attr);
1822c03d07aSLuca Tettamanti 	u64 value;
1832c03d07aSLuca Tettamanti 	int err;
1842c03d07aSLuca Tettamanti 
1852c03d07aSLuca Tettamanti 	err = atk_read_value(s, &value);
1862c03d07aSLuca Tettamanti 	if (err)
1872c03d07aSLuca Tettamanti 		return err;
1882c03d07aSLuca Tettamanti 
1892c03d07aSLuca Tettamanti 	if (s->type == HWMON_TYPE_TEMP)
1902c03d07aSLuca Tettamanti 		/* ACPI returns decidegree */
1912c03d07aSLuca Tettamanti 		value *= 100;
1922c03d07aSLuca Tettamanti 
1932c03d07aSLuca Tettamanti 	return sprintf(buf, "%llu\n", value);
1942c03d07aSLuca Tettamanti }
1952c03d07aSLuca Tettamanti 
1962c03d07aSLuca Tettamanti static ssize_t atk_label_show(struct device *dev,
1972c03d07aSLuca Tettamanti 		struct device_attribute *attr, char *buf)
1982c03d07aSLuca Tettamanti {
1992c03d07aSLuca Tettamanti 	struct atk_sensor_data *s = label_to_atk_sensor(attr);
2002c03d07aSLuca Tettamanti 
2012c03d07aSLuca Tettamanti 	return sprintf(buf, "%s\n", s->acpi_name);
2022c03d07aSLuca Tettamanti }
2032c03d07aSLuca Tettamanti 
2042c03d07aSLuca Tettamanti static ssize_t atk_limit1_show(struct device *dev,
2052c03d07aSLuca Tettamanti 		struct device_attribute *attr, char *buf)
2062c03d07aSLuca Tettamanti {
2072c03d07aSLuca Tettamanti 	struct atk_sensor_data *s = limit1_to_atk_sensor(attr);
2082c03d07aSLuca Tettamanti 	u64 value = s->limit1;
2092c03d07aSLuca Tettamanti 
2102c03d07aSLuca Tettamanti 	if (s->type == HWMON_TYPE_TEMP)
2112c03d07aSLuca Tettamanti 		value *= 100;
2122c03d07aSLuca Tettamanti 
2132c03d07aSLuca Tettamanti 	return sprintf(buf, "%lld\n", value);
2142c03d07aSLuca Tettamanti }
2152c03d07aSLuca Tettamanti 
2162c03d07aSLuca Tettamanti static ssize_t atk_limit2_show(struct device *dev,
2172c03d07aSLuca Tettamanti 		struct device_attribute *attr, char *buf)
2182c03d07aSLuca Tettamanti {
2192c03d07aSLuca Tettamanti 	struct atk_sensor_data *s = limit2_to_atk_sensor(attr);
2202c03d07aSLuca Tettamanti 	u64 value = s->limit2;
2212c03d07aSLuca Tettamanti 
2222c03d07aSLuca Tettamanti 	if (s->type == HWMON_TYPE_TEMP)
2232c03d07aSLuca Tettamanti 		value *= 100;
2242c03d07aSLuca Tettamanti 
2252c03d07aSLuca Tettamanti 	return sprintf(buf, "%lld\n", value);
2262c03d07aSLuca Tettamanti }
2272c03d07aSLuca Tettamanti 
2282c03d07aSLuca Tettamanti static ssize_t atk_name_show(struct device *dev,
2292c03d07aSLuca Tettamanti 				struct device_attribute *attr, char *buf)
2302c03d07aSLuca Tettamanti {
2312c03d07aSLuca Tettamanti 	return sprintf(buf, "atk0110\n");
2322c03d07aSLuca Tettamanti }
2332c03d07aSLuca Tettamanti static struct device_attribute atk_name_attr =
2342c03d07aSLuca Tettamanti 		__ATTR(name, 0444, atk_name_show, NULL);
2352c03d07aSLuca Tettamanti 
2362c03d07aSLuca Tettamanti static void atk_init_attribute(struct device_attribute *attr, char *name,
2372c03d07aSLuca Tettamanti 		sysfs_show_func show)
2382c03d07aSLuca Tettamanti {
2392c03d07aSLuca Tettamanti 	attr->attr.name = name;
2402c03d07aSLuca Tettamanti 	attr->attr.mode = 0444;
2412c03d07aSLuca Tettamanti 	attr->show = show;
2422c03d07aSLuca Tettamanti 	attr->store = NULL;
2432c03d07aSLuca Tettamanti }
2442c03d07aSLuca Tettamanti 
2452c03d07aSLuca Tettamanti 
2462c03d07aSLuca Tettamanti static union acpi_object *atk_get_pack_member(struct atk_data *data,
2472c03d07aSLuca Tettamanti 						union acpi_object *pack,
2482c03d07aSLuca Tettamanti 						enum atk_pack_member m)
2492c03d07aSLuca Tettamanti {
2502c03d07aSLuca Tettamanti 	bool old_if = data->old_interface;
2512c03d07aSLuca Tettamanti 	int offset;
2522c03d07aSLuca Tettamanti 
2532c03d07aSLuca Tettamanti 	switch (m) {
2542c03d07aSLuca Tettamanti 	case HWMON_PACK_FLAGS:
2552c03d07aSLuca Tettamanti 		offset = old_if ? _HWMON_OLD_PACK_FLAGS : _HWMON_NEW_PACK_FLAGS;
2562c03d07aSLuca Tettamanti 		break;
2572c03d07aSLuca Tettamanti 	case HWMON_PACK_NAME:
2582c03d07aSLuca Tettamanti 		offset = old_if ? _HWMON_OLD_PACK_NAME : _HWMON_NEW_PACK_NAME;
2592c03d07aSLuca Tettamanti 		break;
2602c03d07aSLuca Tettamanti 	case HWMON_PACK_LIMIT1:
2612c03d07aSLuca Tettamanti 		offset = old_if ? _HWMON_OLD_PACK_LIMIT1 :
2622c03d07aSLuca Tettamanti 				  _HWMON_NEW_PACK_LIMIT1;
2632c03d07aSLuca Tettamanti 		break;
2642c03d07aSLuca Tettamanti 	case HWMON_PACK_LIMIT2:
2652c03d07aSLuca Tettamanti 		offset = old_if ? _HWMON_OLD_PACK_LIMIT2 :
2662c03d07aSLuca Tettamanti 				  _HWMON_NEW_PACK_LIMIT2;
2672c03d07aSLuca Tettamanti 		break;
2682c03d07aSLuca Tettamanti 	case HWMON_PACK_ENABLE:
2692c03d07aSLuca Tettamanti 		offset = old_if ? _HWMON_OLD_PACK_ENABLE :
2702c03d07aSLuca Tettamanti 				  _HWMON_NEW_PACK_ENABLE;
2712c03d07aSLuca Tettamanti 		break;
2722c03d07aSLuca Tettamanti 	default:
2732c03d07aSLuca Tettamanti 		return NULL;
2742c03d07aSLuca Tettamanti 	}
2752c03d07aSLuca Tettamanti 
2762c03d07aSLuca Tettamanti 	return &pack->package.elements[offset];
2772c03d07aSLuca Tettamanti }
2782c03d07aSLuca Tettamanti 
2792c03d07aSLuca Tettamanti 
2802c03d07aSLuca Tettamanti /* New package format is:
2812c03d07aSLuca Tettamanti  * - flag (int)
2822c03d07aSLuca Tettamanti  *	class - used for de-muxing the request to the correct GITn
2832c03d07aSLuca Tettamanti  *	type (volt, temp, fan)
2842c03d07aSLuca Tettamanti  *	sensor id |
2852c03d07aSLuca Tettamanti  *	sensor id - used for de-muxing the request _inside_ the GITn
2862c03d07aSLuca Tettamanti  * - name (str)
2872c03d07aSLuca Tettamanti  * - unknown (int)
2882c03d07aSLuca Tettamanti  * - unknown (int)
2892c03d07aSLuca Tettamanti  * - limit1 (int)
2902c03d07aSLuca Tettamanti  * - limit2 (int)
2912c03d07aSLuca Tettamanti  * - enable (int)
2922c03d07aSLuca Tettamanti  *
2932c03d07aSLuca Tettamanti  * The old package has the same format but it's missing the two unknown fields.
2942c03d07aSLuca Tettamanti  */
2952c03d07aSLuca Tettamanti static int validate_hwmon_pack(struct atk_data *data, union acpi_object *obj)
2962c03d07aSLuca Tettamanti {
2972c03d07aSLuca Tettamanti 	struct device *dev = &data->acpi_dev->dev;
2982c03d07aSLuca Tettamanti 	union acpi_object *tmp;
2992c03d07aSLuca Tettamanti 	bool old_if = data->old_interface;
3002c03d07aSLuca Tettamanti 	int const expected_size = old_if ? _HWMON_OLD_PACK_SIZE :
3012c03d07aSLuca Tettamanti 					   _HWMON_NEW_PACK_SIZE;
3022c03d07aSLuca Tettamanti 
3032c03d07aSLuca Tettamanti 	if (obj->type != ACPI_TYPE_PACKAGE) {
3042c03d07aSLuca Tettamanti 		dev_warn(dev, "Invalid type: %d\n", obj->type);
3052c03d07aSLuca Tettamanti 		return -EINVAL;
3062c03d07aSLuca Tettamanti 	}
3072c03d07aSLuca Tettamanti 
3082c03d07aSLuca Tettamanti 	if (obj->package.count != expected_size) {
3092c03d07aSLuca Tettamanti 		dev_warn(dev, "Invalid package size: %d, expected: %d\n",
3102c03d07aSLuca Tettamanti 				obj->package.count, expected_size);
3112c03d07aSLuca Tettamanti 		return -EINVAL;
3122c03d07aSLuca Tettamanti 	}
3132c03d07aSLuca Tettamanti 
3142c03d07aSLuca Tettamanti 	tmp = atk_get_pack_member(data, obj, HWMON_PACK_FLAGS);
3152c03d07aSLuca Tettamanti 	if (tmp->type != ACPI_TYPE_INTEGER) {
3162c03d07aSLuca Tettamanti 		dev_warn(dev, "Invalid type (flag): %d\n", tmp->type);
3172c03d07aSLuca Tettamanti 		return -EINVAL;
3182c03d07aSLuca Tettamanti 	}
3192c03d07aSLuca Tettamanti 
3202c03d07aSLuca Tettamanti 	tmp = atk_get_pack_member(data, obj, HWMON_PACK_NAME);
3212c03d07aSLuca Tettamanti 	if (tmp->type != ACPI_TYPE_STRING) {
3222c03d07aSLuca Tettamanti 		dev_warn(dev, "Invalid type (name): %d\n", tmp->type);
3232c03d07aSLuca Tettamanti 		return -EINVAL;
3242c03d07aSLuca Tettamanti 	}
3252c03d07aSLuca Tettamanti 
3262c03d07aSLuca Tettamanti 	/* Don't check... we don't know what they're useful for anyway */
3272c03d07aSLuca Tettamanti #if 0
3282c03d07aSLuca Tettamanti 	tmp = &obj->package.elements[HWMON_PACK_UNK1];
3292c03d07aSLuca Tettamanti 	if (tmp->type != ACPI_TYPE_INTEGER) {
3302c03d07aSLuca Tettamanti 		dev_warn(dev, "Invalid type (unk1): %d\n", tmp->type);
3312c03d07aSLuca Tettamanti 		return -EINVAL;
3322c03d07aSLuca Tettamanti 	}
3332c03d07aSLuca Tettamanti 
3342c03d07aSLuca Tettamanti 	tmp = &obj->package.elements[HWMON_PACK_UNK2];
3352c03d07aSLuca Tettamanti 	if (tmp->type != ACPI_TYPE_INTEGER) {
3362c03d07aSLuca Tettamanti 		dev_warn(dev, "Invalid type (unk2): %d\n", tmp->type);
3372c03d07aSLuca Tettamanti 		return -EINVAL;
3382c03d07aSLuca Tettamanti 	}
3392c03d07aSLuca Tettamanti #endif
3402c03d07aSLuca Tettamanti 
3412c03d07aSLuca Tettamanti 	tmp = atk_get_pack_member(data, obj, HWMON_PACK_LIMIT1);
3422c03d07aSLuca Tettamanti 	if (tmp->type != ACPI_TYPE_INTEGER) {
3432c03d07aSLuca Tettamanti 		dev_warn(dev, "Invalid type (limit1): %d\n", tmp->type);
3442c03d07aSLuca Tettamanti 		return -EINVAL;
3452c03d07aSLuca Tettamanti 	}
3462c03d07aSLuca Tettamanti 
3472c03d07aSLuca Tettamanti 	tmp = atk_get_pack_member(data, obj, HWMON_PACK_LIMIT2);
3482c03d07aSLuca Tettamanti 	if (tmp->type != ACPI_TYPE_INTEGER) {
3492c03d07aSLuca Tettamanti 		dev_warn(dev, "Invalid type (limit2): %d\n", tmp->type);
3502c03d07aSLuca Tettamanti 		return -EINVAL;
3512c03d07aSLuca Tettamanti 	}
3522c03d07aSLuca Tettamanti 
3532c03d07aSLuca Tettamanti 	tmp = atk_get_pack_member(data, obj, HWMON_PACK_ENABLE);
3542c03d07aSLuca Tettamanti 	if (tmp->type != ACPI_TYPE_INTEGER) {
3552c03d07aSLuca Tettamanti 		dev_warn(dev, "Invalid type (enable): %d\n", tmp->type);
3562c03d07aSLuca Tettamanti 		return -EINVAL;
3572c03d07aSLuca Tettamanti 	}
3582c03d07aSLuca Tettamanti 
3592c03d07aSLuca Tettamanti 	atk_print_sensor(data, obj);
3602c03d07aSLuca Tettamanti 
3612c03d07aSLuca Tettamanti 	return 0;
3622c03d07aSLuca Tettamanti }
3632c03d07aSLuca Tettamanti 
364b9008708SLuca Tettamanti #ifdef DEBUG
3652c03d07aSLuca Tettamanti static char const *atk_sensor_type(union acpi_object *flags)
3662c03d07aSLuca Tettamanti {
3672c03d07aSLuca Tettamanti 	u64 type = flags->integer.value & ATK_TYPE_MASK;
3682c03d07aSLuca Tettamanti 	char const *what;
3692c03d07aSLuca Tettamanti 
3702c03d07aSLuca Tettamanti 	switch (type) {
3712c03d07aSLuca Tettamanti 	case HWMON_TYPE_VOLT:
3722c03d07aSLuca Tettamanti 		what = "voltage";
3732c03d07aSLuca Tettamanti 		break;
3742c03d07aSLuca Tettamanti 	case HWMON_TYPE_TEMP:
3752c03d07aSLuca Tettamanti 		what = "temperature";
3762c03d07aSLuca Tettamanti 		break;
3772c03d07aSLuca Tettamanti 	case HWMON_TYPE_FAN:
3782c03d07aSLuca Tettamanti 		what = "fan";
3792c03d07aSLuca Tettamanti 		break;
3802c03d07aSLuca Tettamanti 	default:
3812c03d07aSLuca Tettamanti 		what = "unknown";
3822c03d07aSLuca Tettamanti 		break;
3832c03d07aSLuca Tettamanti 	}
3842c03d07aSLuca Tettamanti 
3852c03d07aSLuca Tettamanti 	return what;
3862c03d07aSLuca Tettamanti }
387b9008708SLuca Tettamanti #endif
3882c03d07aSLuca Tettamanti 
3892c03d07aSLuca Tettamanti static void atk_print_sensor(struct atk_data *data, union acpi_object *obj)
3902c03d07aSLuca Tettamanti {
3912c03d07aSLuca Tettamanti #ifdef DEBUG
3922c03d07aSLuca Tettamanti 	struct device *dev = &data->acpi_dev->dev;
3932c03d07aSLuca Tettamanti 	union acpi_object *flags;
3942c03d07aSLuca Tettamanti 	union acpi_object *name;
3952c03d07aSLuca Tettamanti 	union acpi_object *limit1;
3962c03d07aSLuca Tettamanti 	union acpi_object *limit2;
3972c03d07aSLuca Tettamanti 	union acpi_object *enable;
3982c03d07aSLuca Tettamanti 	char const *what;
3992c03d07aSLuca Tettamanti 
4002c03d07aSLuca Tettamanti 	flags = atk_get_pack_member(data, obj, HWMON_PACK_FLAGS);
4012c03d07aSLuca Tettamanti 	name = atk_get_pack_member(data, obj, HWMON_PACK_NAME);
4022c03d07aSLuca Tettamanti 	limit1 = atk_get_pack_member(data, obj, HWMON_PACK_LIMIT1);
4032c03d07aSLuca Tettamanti 	limit2 = atk_get_pack_member(data, obj, HWMON_PACK_LIMIT2);
4042c03d07aSLuca Tettamanti 	enable = atk_get_pack_member(data, obj, HWMON_PACK_ENABLE);
4052c03d07aSLuca Tettamanti 
4062c03d07aSLuca Tettamanti 	what = atk_sensor_type(flags);
4072c03d07aSLuca Tettamanti 
4082c03d07aSLuca Tettamanti 	dev_dbg(dev, "%s: %#llx %s [%llu-%llu] %s\n", what,
4092c03d07aSLuca Tettamanti 			flags->integer.value,
4102c03d07aSLuca Tettamanti 			name->string.pointer,
4112c03d07aSLuca Tettamanti 			limit1->integer.value, limit2->integer.value,
4122c03d07aSLuca Tettamanti 			enable->integer.value ? "enabled" : "disabled");
4132c03d07aSLuca Tettamanti #endif
4142c03d07aSLuca Tettamanti }
4152c03d07aSLuca Tettamanti 
4162c03d07aSLuca Tettamanti static int atk_read_value_old(struct atk_sensor_data *sensor, u64 *value)
4172c03d07aSLuca Tettamanti {
4182c03d07aSLuca Tettamanti 	struct atk_data *data = sensor->data;
4192c03d07aSLuca Tettamanti 	struct device *dev = &data->acpi_dev->dev;
4202c03d07aSLuca Tettamanti 	struct acpi_object_list params;
4212c03d07aSLuca Tettamanti 	union acpi_object id;
4222c03d07aSLuca Tettamanti 	acpi_status status;
4232c03d07aSLuca Tettamanti 	acpi_handle method;
4242c03d07aSLuca Tettamanti 
4252c03d07aSLuca Tettamanti 	switch (sensor->type) {
4262c03d07aSLuca Tettamanti 	case HWMON_TYPE_VOLT:
4272c03d07aSLuca Tettamanti 		method = data->rvlt_handle;
4282c03d07aSLuca Tettamanti 		break;
4292c03d07aSLuca Tettamanti 	case HWMON_TYPE_TEMP:
4302c03d07aSLuca Tettamanti 		method = data->rtmp_handle;
4312c03d07aSLuca Tettamanti 		break;
4322c03d07aSLuca Tettamanti 	case HWMON_TYPE_FAN:
4332c03d07aSLuca Tettamanti 		method = data->rfan_handle;
4342c03d07aSLuca Tettamanti 		break;
4352c03d07aSLuca Tettamanti 	default:
4362c03d07aSLuca Tettamanti 		return -EINVAL;
4372c03d07aSLuca Tettamanti 	}
4382c03d07aSLuca Tettamanti 
4392c03d07aSLuca Tettamanti 	id.type = ACPI_TYPE_INTEGER;
4402c03d07aSLuca Tettamanti 	id.integer.value = sensor->id;
4412c03d07aSLuca Tettamanti 
4422c03d07aSLuca Tettamanti 	params.count = 1;
4432c03d07aSLuca Tettamanti 	params.pointer = &id;
4442c03d07aSLuca Tettamanti 
4452c03d07aSLuca Tettamanti 	status = acpi_evaluate_integer(method, NULL, &params, value);
4462c03d07aSLuca Tettamanti 	if (status != AE_OK) {
4472c03d07aSLuca Tettamanti 		dev_warn(dev, "%s: ACPI exception: %s\n", __func__,
4482c03d07aSLuca Tettamanti 				acpi_format_exception(status));
4492c03d07aSLuca Tettamanti 		return -EIO;
4502c03d07aSLuca Tettamanti 	}
4512c03d07aSLuca Tettamanti 
4522c03d07aSLuca Tettamanti 	return 0;
4532c03d07aSLuca Tettamanti }
4542c03d07aSLuca Tettamanti 
455*18e25555SLuca Tettamanti static union acpi_object *atk_ggrp(struct atk_data *data, u16 mux)
456*18e25555SLuca Tettamanti {
457*18e25555SLuca Tettamanti 	struct device *dev = &data->acpi_dev->dev;
458*18e25555SLuca Tettamanti 	struct acpi_buffer buf;
459*18e25555SLuca Tettamanti 	acpi_status ret;
460*18e25555SLuca Tettamanti 	struct acpi_object_list params;
461*18e25555SLuca Tettamanti 	union acpi_object id;
462*18e25555SLuca Tettamanti 	union acpi_object *pack;
463*18e25555SLuca Tettamanti 
464*18e25555SLuca Tettamanti 	id.type = ACPI_TYPE_INTEGER;
465*18e25555SLuca Tettamanti 	id.integer.value = mux;
466*18e25555SLuca Tettamanti 	params.count = 1;
467*18e25555SLuca Tettamanti 	params.pointer = &id;
468*18e25555SLuca Tettamanti 
469*18e25555SLuca Tettamanti 	buf.length = ACPI_ALLOCATE_BUFFER;
470*18e25555SLuca Tettamanti 	ret = acpi_evaluate_object(data->enumerate_handle, NULL, &params, &buf);
471*18e25555SLuca Tettamanti 	if (ret != AE_OK) {
472*18e25555SLuca Tettamanti 		dev_err(dev, "GGRP[%#x] ACPI exception: %s\n", mux,
473*18e25555SLuca Tettamanti 				acpi_format_exception(ret));
474*18e25555SLuca Tettamanti 		return ERR_PTR(-EIO);
475*18e25555SLuca Tettamanti 	}
476*18e25555SLuca Tettamanti 	pack = buf.pointer;
477*18e25555SLuca Tettamanti 	if (pack->type != ACPI_TYPE_PACKAGE) {
478*18e25555SLuca Tettamanti 		/* Execution was successful, but the id was not found */
479*18e25555SLuca Tettamanti 		ACPI_FREE(pack);
480*18e25555SLuca Tettamanti 		return ERR_PTR(-ENOENT);
481*18e25555SLuca Tettamanti 	}
482*18e25555SLuca Tettamanti 
483*18e25555SLuca Tettamanti 	if (pack->package.count < 1) {
484*18e25555SLuca Tettamanti 		dev_err(dev, "GGRP[%#x] package is too small\n", mux);
485*18e25555SLuca Tettamanti 		ACPI_FREE(pack);
486*18e25555SLuca Tettamanti 		return ERR_PTR(-EIO);
487*18e25555SLuca Tettamanti 	}
488*18e25555SLuca Tettamanti 	return pack;
489*18e25555SLuca Tettamanti }
490*18e25555SLuca Tettamanti 
491*18e25555SLuca Tettamanti static union acpi_object *atk_gitm(struct atk_data *data, u64 id)
492*18e25555SLuca Tettamanti {
493*18e25555SLuca Tettamanti 	struct device *dev = &data->acpi_dev->dev;
494*18e25555SLuca Tettamanti 	struct atk_acpi_input_buf buf;
495*18e25555SLuca Tettamanti 	union acpi_object tmp;
496*18e25555SLuca Tettamanti 	struct acpi_object_list params;
497*18e25555SLuca Tettamanti 	struct acpi_buffer ret;
498*18e25555SLuca Tettamanti 	union acpi_object *obj;
499*18e25555SLuca Tettamanti 	acpi_status status;
500*18e25555SLuca Tettamanti 
501*18e25555SLuca Tettamanti 	buf.id = id;
502*18e25555SLuca Tettamanti 	buf.param1 = 0;
503*18e25555SLuca Tettamanti 	buf.param2 = 0;
504*18e25555SLuca Tettamanti 
505*18e25555SLuca Tettamanti 	tmp.type = ACPI_TYPE_BUFFER;
506*18e25555SLuca Tettamanti 	tmp.buffer.pointer = (u8 *)&buf;
507*18e25555SLuca Tettamanti 	tmp.buffer.length = sizeof(buf);
508*18e25555SLuca Tettamanti 
509*18e25555SLuca Tettamanti 	params.count = 1;
510*18e25555SLuca Tettamanti 	params.pointer = (void *)&tmp;
511*18e25555SLuca Tettamanti 
512*18e25555SLuca Tettamanti 	ret.length = ACPI_ALLOCATE_BUFFER;
513*18e25555SLuca Tettamanti 	status = acpi_evaluate_object_typed(data->read_handle, NULL, &params,
514*18e25555SLuca Tettamanti 			&ret, ACPI_TYPE_BUFFER);
515*18e25555SLuca Tettamanti 	if (status != AE_OK) {
516*18e25555SLuca Tettamanti 		dev_warn(dev, "GITM[%#llx] ACPI exception: %s\n", id,
517*18e25555SLuca Tettamanti 				acpi_format_exception(status));
518*18e25555SLuca Tettamanti 		return ERR_PTR(-EIO);
519*18e25555SLuca Tettamanti 	}
520*18e25555SLuca Tettamanti 	obj = ret.pointer;
521*18e25555SLuca Tettamanti 
522*18e25555SLuca Tettamanti 	/* Sanity check */
523*18e25555SLuca Tettamanti 	if (obj->buffer.length < 8) {
524*18e25555SLuca Tettamanti 		dev_warn(dev, "Unexpected ASBF length: %u\n",
525*18e25555SLuca Tettamanti 				obj->buffer.length);
526*18e25555SLuca Tettamanti 		ACPI_FREE(obj);
527*18e25555SLuca Tettamanti 		return ERR_PTR(-EIO);
528*18e25555SLuca Tettamanti 	}
529*18e25555SLuca Tettamanti 	return obj;
530*18e25555SLuca Tettamanti }
531*18e25555SLuca Tettamanti 
5322c03d07aSLuca Tettamanti static int atk_read_value_new(struct atk_sensor_data *sensor, u64 *value)
5332c03d07aSLuca Tettamanti {
5342c03d07aSLuca Tettamanti 	struct atk_data *data = sensor->data;
5352c03d07aSLuca Tettamanti 	struct device *dev = &data->acpi_dev->dev;
536*18e25555SLuca Tettamanti 	union acpi_object *obj;
537*18e25555SLuca Tettamanti 	struct atk_acpi_ret_buffer *buf;
538*18e25555SLuca Tettamanti 	int err = 0;
5392c03d07aSLuca Tettamanti 
540*18e25555SLuca Tettamanti 	obj = atk_gitm(data, sensor->id);
541*18e25555SLuca Tettamanti 	if (IS_ERR(obj))
542*18e25555SLuca Tettamanti 		return PTR_ERR(obj);
5432c03d07aSLuca Tettamanti 
544*18e25555SLuca Tettamanti 	buf = (struct atk_acpi_ret_buffer *)obj->buffer.pointer;
545*18e25555SLuca Tettamanti 	if (buf->flags == 0) {
5462c03d07aSLuca Tettamanti 		/* The reading is not valid, possible causes:
5472c03d07aSLuca Tettamanti 		 * - sensor failure
5482c03d07aSLuca Tettamanti 		 * - enumeration was FUBAR (and we didn't notice)
5492c03d07aSLuca Tettamanti 		 */
550*18e25555SLuca Tettamanti 		dev_warn(dev, "Read failed, sensor = %#llx\n", sensor->id);
551*18e25555SLuca Tettamanti 		err = -EIO;
552*18e25555SLuca Tettamanti 		goto out;
5532c03d07aSLuca Tettamanti 	}
5542c03d07aSLuca Tettamanti 
555*18e25555SLuca Tettamanti 	*value = buf->value;
556*18e25555SLuca Tettamanti out:
557*18e25555SLuca Tettamanti 	ACPI_FREE(obj);
558*18e25555SLuca Tettamanti 	return err;
5592c03d07aSLuca Tettamanti }
5602c03d07aSLuca Tettamanti 
5612c03d07aSLuca Tettamanti static int atk_read_value(struct atk_sensor_data *sensor, u64 *value)
5622c03d07aSLuca Tettamanti {
5632c03d07aSLuca Tettamanti 	int err;
5642c03d07aSLuca Tettamanti 
5652c03d07aSLuca Tettamanti 	if (!sensor->is_valid ||
5662c03d07aSLuca Tettamanti 	    time_after(jiffies, sensor->last_updated + CACHE_TIME)) {
5672c03d07aSLuca Tettamanti 		if (sensor->data->old_interface)
5682c03d07aSLuca Tettamanti 			err = atk_read_value_old(sensor, value);
5692c03d07aSLuca Tettamanti 		else
5702c03d07aSLuca Tettamanti 			err = atk_read_value_new(sensor, value);
5712c03d07aSLuca Tettamanti 
5722c03d07aSLuca Tettamanti 		sensor->is_valid = true;
5732c03d07aSLuca Tettamanti 		sensor->last_updated = jiffies;
5742c03d07aSLuca Tettamanti 		sensor->cached_value = *value;
5752c03d07aSLuca Tettamanti 	} else {
5762c03d07aSLuca Tettamanti 		*value = sensor->cached_value;
5772c03d07aSLuca Tettamanti 		err = 0;
5782c03d07aSLuca Tettamanti 	}
5792c03d07aSLuca Tettamanti 
5802c03d07aSLuca Tettamanti 	return err;
5812c03d07aSLuca Tettamanti }
5822c03d07aSLuca Tettamanti 
5832c03d07aSLuca Tettamanti static int atk_add_sensor(struct atk_data *data, union acpi_object *obj)
5842c03d07aSLuca Tettamanti {
5852c03d07aSLuca Tettamanti 	struct device *dev = &data->acpi_dev->dev;
5862c03d07aSLuca Tettamanti 	union acpi_object *flags;
5872c03d07aSLuca Tettamanti 	union acpi_object *name;
5882c03d07aSLuca Tettamanti 	union acpi_object *limit1;
5892c03d07aSLuca Tettamanti 	union acpi_object *limit2;
5902c03d07aSLuca Tettamanti 	union acpi_object *enable;
5912c03d07aSLuca Tettamanti 	struct atk_sensor_data *sensor;
5922c03d07aSLuca Tettamanti 	char const *base_name;
5932c03d07aSLuca Tettamanti 	char const *limit1_name;
5942c03d07aSLuca Tettamanti 	char const *limit2_name;
5952c03d07aSLuca Tettamanti 	u64 type;
5962c03d07aSLuca Tettamanti 	int err;
5972c03d07aSLuca Tettamanti 	int *num;
5982c03d07aSLuca Tettamanti 	int start;
5992c03d07aSLuca Tettamanti 
6002c03d07aSLuca Tettamanti 	if (obj->type != ACPI_TYPE_PACKAGE) {
6012c03d07aSLuca Tettamanti 		/* wft is this? */
6022c03d07aSLuca Tettamanti 		dev_warn(dev, "Unknown type for ACPI object: (%d)\n",
6032c03d07aSLuca Tettamanti 				obj->type);
6042c03d07aSLuca Tettamanti 		return -EINVAL;
6052c03d07aSLuca Tettamanti 	}
6062c03d07aSLuca Tettamanti 
6072c03d07aSLuca Tettamanti 	err = validate_hwmon_pack(data, obj);
6082c03d07aSLuca Tettamanti 	if (err)
6092c03d07aSLuca Tettamanti 		return err;
6102c03d07aSLuca Tettamanti 
6112c03d07aSLuca Tettamanti 	/* Ok, we have a valid hwmon package */
6122c03d07aSLuca Tettamanti 	type = atk_get_pack_member(data, obj, HWMON_PACK_FLAGS)->integer.value
6132c03d07aSLuca Tettamanti 	       & ATK_TYPE_MASK;
6142c03d07aSLuca Tettamanti 
6152c03d07aSLuca Tettamanti 	switch (type) {
6162c03d07aSLuca Tettamanti 	case HWMON_TYPE_VOLT:
6172c03d07aSLuca Tettamanti 		base_name = "in";
6182c03d07aSLuca Tettamanti 		limit1_name = "min";
6192c03d07aSLuca Tettamanti 		limit2_name = "max";
6202c03d07aSLuca Tettamanti 		num = &data->voltage_count;
6212c03d07aSLuca Tettamanti 		start = 0;
6222c03d07aSLuca Tettamanti 		break;
6232c03d07aSLuca Tettamanti 	case HWMON_TYPE_TEMP:
6242c03d07aSLuca Tettamanti 		base_name = "temp";
6252c03d07aSLuca Tettamanti 		limit1_name = "max";
6262c03d07aSLuca Tettamanti 		limit2_name = "crit";
6272c03d07aSLuca Tettamanti 		num = &data->temperature_count;
6282c03d07aSLuca Tettamanti 		start = 1;
6292c03d07aSLuca Tettamanti 		break;
6302c03d07aSLuca Tettamanti 	case HWMON_TYPE_FAN:
6312c03d07aSLuca Tettamanti 		base_name = "fan";
6322c03d07aSLuca Tettamanti 		limit1_name = "min";
6332c03d07aSLuca Tettamanti 		limit2_name = "max";
6342c03d07aSLuca Tettamanti 		num = &data->fan_count;
6352c03d07aSLuca Tettamanti 		start = 1;
6362c03d07aSLuca Tettamanti 		break;
6372c03d07aSLuca Tettamanti 	default:
6382c03d07aSLuca Tettamanti 		dev_warn(dev, "Unknown sensor type: %#llx\n", type);
6392c03d07aSLuca Tettamanti 		return -EINVAL;
6402c03d07aSLuca Tettamanti 	}
6412c03d07aSLuca Tettamanti 
6422c03d07aSLuca Tettamanti 	enable = atk_get_pack_member(data, obj, HWMON_PACK_ENABLE);
6432c03d07aSLuca Tettamanti 	if (!enable->integer.value)
6442c03d07aSLuca Tettamanti 		/* sensor is disabled */
6452c03d07aSLuca Tettamanti 		return 0;
6462c03d07aSLuca Tettamanti 
6472c03d07aSLuca Tettamanti 	flags = atk_get_pack_member(data, obj, HWMON_PACK_FLAGS);
6482c03d07aSLuca Tettamanti 	name = atk_get_pack_member(data, obj, HWMON_PACK_NAME);
6492c03d07aSLuca Tettamanti 	limit1 = atk_get_pack_member(data, obj, HWMON_PACK_LIMIT1);
6502c03d07aSLuca Tettamanti 	limit2 = atk_get_pack_member(data, obj, HWMON_PACK_LIMIT2);
6512c03d07aSLuca Tettamanti 
6522c03d07aSLuca Tettamanti 	sensor = kzalloc(sizeof(*sensor), GFP_KERNEL);
6532c03d07aSLuca Tettamanti 	if (!sensor)
6542c03d07aSLuca Tettamanti 		return -ENOMEM;
6552c03d07aSLuca Tettamanti 
6562c03d07aSLuca Tettamanti 	sensor->acpi_name = kstrdup(name->string.pointer, GFP_KERNEL);
6572c03d07aSLuca Tettamanti 	if (!sensor->acpi_name) {
6582c03d07aSLuca Tettamanti 		err = -ENOMEM;
6592c03d07aSLuca Tettamanti 		goto out;
6602c03d07aSLuca Tettamanti 	}
6612c03d07aSLuca Tettamanti 
6622c03d07aSLuca Tettamanti 	INIT_LIST_HEAD(&sensor->list);
6632c03d07aSLuca Tettamanti 	sensor->type = type;
6642c03d07aSLuca Tettamanti 	sensor->data = data;
6652c03d07aSLuca Tettamanti 	sensor->id = flags->integer.value;
6662c03d07aSLuca Tettamanti 	sensor->limit1 = limit1->integer.value;
6678d282497SLuca Tettamanti 	if (data->old_interface)
6682c03d07aSLuca Tettamanti 		sensor->limit2 = limit2->integer.value;
6698d282497SLuca Tettamanti 	else
6708d282497SLuca Tettamanti 		/* The upper limit is expressed as delta from lower limit */
6718d282497SLuca Tettamanti 		sensor->limit2 = sensor->limit1 + limit2->integer.value;
6722c03d07aSLuca Tettamanti 
6732c03d07aSLuca Tettamanti 	snprintf(sensor->input_attr_name, ATTR_NAME_SIZE,
6742c03d07aSLuca Tettamanti 			"%s%d_input", base_name, start + *num);
6752c03d07aSLuca Tettamanti 	atk_init_attribute(&sensor->input_attr,
6762c03d07aSLuca Tettamanti 			sensor->input_attr_name,
6772c03d07aSLuca Tettamanti 			atk_input_show);
6782c03d07aSLuca Tettamanti 
6792c03d07aSLuca Tettamanti 	snprintf(sensor->label_attr_name, ATTR_NAME_SIZE,
6802c03d07aSLuca Tettamanti 			"%s%d_label", base_name, start + *num);
6812c03d07aSLuca Tettamanti 	atk_init_attribute(&sensor->label_attr,
6822c03d07aSLuca Tettamanti 			sensor->label_attr_name,
6832c03d07aSLuca Tettamanti 			atk_label_show);
6842c03d07aSLuca Tettamanti 
6852c03d07aSLuca Tettamanti 	snprintf(sensor->limit1_attr_name, ATTR_NAME_SIZE,
6862c03d07aSLuca Tettamanti 			"%s%d_%s", base_name, start + *num, limit1_name);
6872c03d07aSLuca Tettamanti 	atk_init_attribute(&sensor->limit1_attr,
6882c03d07aSLuca Tettamanti 			sensor->limit1_attr_name,
6892c03d07aSLuca Tettamanti 			atk_limit1_show);
6902c03d07aSLuca Tettamanti 
6912c03d07aSLuca Tettamanti 	snprintf(sensor->limit2_attr_name, ATTR_NAME_SIZE,
6922c03d07aSLuca Tettamanti 			"%s%d_%s", base_name, start + *num, limit2_name);
6932c03d07aSLuca Tettamanti 	atk_init_attribute(&sensor->limit2_attr,
6942c03d07aSLuca Tettamanti 			sensor->limit2_attr_name,
6952c03d07aSLuca Tettamanti 			atk_limit2_show);
6962c03d07aSLuca Tettamanti 
6972c03d07aSLuca Tettamanti 	list_add(&sensor->list, &data->sensor_list);
6982c03d07aSLuca Tettamanti 	(*num)++;
6992c03d07aSLuca Tettamanti 
7002c03d07aSLuca Tettamanti 	return 1;
7012c03d07aSLuca Tettamanti out:
7022c03d07aSLuca Tettamanti 	kfree(sensor->acpi_name);
7032c03d07aSLuca Tettamanti 	kfree(sensor);
7042c03d07aSLuca Tettamanti 	return err;
7052c03d07aSLuca Tettamanti }
7062c03d07aSLuca Tettamanti 
7072c03d07aSLuca Tettamanti static int atk_enumerate_old_hwmon(struct atk_data *data)
7082c03d07aSLuca Tettamanti {
7092c03d07aSLuca Tettamanti 	struct device *dev = &data->acpi_dev->dev;
7102c03d07aSLuca Tettamanti 	struct acpi_buffer buf;
7112c03d07aSLuca Tettamanti 	union acpi_object *pack;
7122c03d07aSLuca Tettamanti 	acpi_status status;
7132c03d07aSLuca Tettamanti 	int i, ret;
7142c03d07aSLuca Tettamanti 	int count = 0;
7152c03d07aSLuca Tettamanti 
7162c03d07aSLuca Tettamanti 	/* Voltages */
7172c03d07aSLuca Tettamanti 	buf.length = ACPI_ALLOCATE_BUFFER;
7182c03d07aSLuca Tettamanti 	status = acpi_evaluate_object_typed(data->atk_handle,
7192c03d07aSLuca Tettamanti 			METHOD_OLD_ENUM_VLT, NULL, &buf, ACPI_TYPE_PACKAGE);
7202c03d07aSLuca Tettamanti 	if (status != AE_OK) {
7212c03d07aSLuca Tettamanti 		dev_warn(dev, METHOD_OLD_ENUM_VLT ": ACPI exception: %s\n",
7222c03d07aSLuca Tettamanti 				acpi_format_exception(status));
7232c03d07aSLuca Tettamanti 
7242c03d07aSLuca Tettamanti 		return -ENODEV;
7252c03d07aSLuca Tettamanti 	}
7262c03d07aSLuca Tettamanti 
7272c03d07aSLuca Tettamanti 	pack = buf.pointer;
7282c03d07aSLuca Tettamanti 	for (i = 1; i < pack->package.count; i++) {
7292c03d07aSLuca Tettamanti 		union acpi_object *obj = &pack->package.elements[i];
7302c03d07aSLuca Tettamanti 
7312c03d07aSLuca Tettamanti 		ret = atk_add_sensor(data, obj);
7322c03d07aSLuca Tettamanti 		if (ret > 0)
7332c03d07aSLuca Tettamanti 			count++;
7342c03d07aSLuca Tettamanti 	}
7352c03d07aSLuca Tettamanti 	ACPI_FREE(buf.pointer);
7362c03d07aSLuca Tettamanti 
7372c03d07aSLuca Tettamanti 	/* Temperatures */
7382c03d07aSLuca Tettamanti 	buf.length = ACPI_ALLOCATE_BUFFER;
7392c03d07aSLuca Tettamanti 	status = acpi_evaluate_object_typed(data->atk_handle,
7402c03d07aSLuca Tettamanti 			METHOD_OLD_ENUM_TMP, NULL, &buf, ACPI_TYPE_PACKAGE);
7412c03d07aSLuca Tettamanti 	if (status != AE_OK) {
7422c03d07aSLuca Tettamanti 		dev_warn(dev, METHOD_OLD_ENUM_TMP ": ACPI exception: %s\n",
7432c03d07aSLuca Tettamanti 				acpi_format_exception(status));
7442c03d07aSLuca Tettamanti 
7452c03d07aSLuca Tettamanti 		ret = -ENODEV;
7462c03d07aSLuca Tettamanti 		goto cleanup;
7472c03d07aSLuca Tettamanti 	}
7482c03d07aSLuca Tettamanti 
7492c03d07aSLuca Tettamanti 	pack = buf.pointer;
7502c03d07aSLuca Tettamanti 	for (i = 1; i < pack->package.count; i++) {
7512c03d07aSLuca Tettamanti 		union acpi_object *obj = &pack->package.elements[i];
7522c03d07aSLuca Tettamanti 
7532c03d07aSLuca Tettamanti 		ret = atk_add_sensor(data, obj);
7542c03d07aSLuca Tettamanti 		if (ret > 0)
7552c03d07aSLuca Tettamanti 			count++;
7562c03d07aSLuca Tettamanti 	}
7572c03d07aSLuca Tettamanti 	ACPI_FREE(buf.pointer);
7582c03d07aSLuca Tettamanti 
7592c03d07aSLuca Tettamanti 	/* Fans */
7602c03d07aSLuca Tettamanti 	buf.length = ACPI_ALLOCATE_BUFFER;
7612c03d07aSLuca Tettamanti 	status = acpi_evaluate_object_typed(data->atk_handle,
7622c03d07aSLuca Tettamanti 			METHOD_OLD_ENUM_FAN, NULL, &buf, ACPI_TYPE_PACKAGE);
7632c03d07aSLuca Tettamanti 	if (status != AE_OK) {
7642c03d07aSLuca Tettamanti 		dev_warn(dev, METHOD_OLD_ENUM_FAN ": ACPI exception: %s\n",
7652c03d07aSLuca Tettamanti 				acpi_format_exception(status));
7662c03d07aSLuca Tettamanti 
7672c03d07aSLuca Tettamanti 		ret = -ENODEV;
7682c03d07aSLuca Tettamanti 		goto cleanup;
7692c03d07aSLuca Tettamanti 	}
7702c03d07aSLuca Tettamanti 
7712c03d07aSLuca Tettamanti 	pack = buf.pointer;
7722c03d07aSLuca Tettamanti 	for (i = 1; i < pack->package.count; i++) {
7732c03d07aSLuca Tettamanti 		union acpi_object *obj = &pack->package.elements[i];
7742c03d07aSLuca Tettamanti 
7752c03d07aSLuca Tettamanti 		ret = atk_add_sensor(data, obj);
7762c03d07aSLuca Tettamanti 		if (ret > 0)
7772c03d07aSLuca Tettamanti 			count++;
7782c03d07aSLuca Tettamanti 	}
7792c03d07aSLuca Tettamanti 	ACPI_FREE(buf.pointer);
7802c03d07aSLuca Tettamanti 
7812c03d07aSLuca Tettamanti 	return count;
7822c03d07aSLuca Tettamanti cleanup:
7832c03d07aSLuca Tettamanti 	atk_free_sensors(data);
7842c03d07aSLuca Tettamanti 	return ret;
7852c03d07aSLuca Tettamanti }
7862c03d07aSLuca Tettamanti 
7872c03d07aSLuca Tettamanti static int atk_enumerate_new_hwmon(struct atk_data *data)
7882c03d07aSLuca Tettamanti {
7892c03d07aSLuca Tettamanti 	struct device *dev = &data->acpi_dev->dev;
7902c03d07aSLuca Tettamanti 	union acpi_object *pack;
7912c03d07aSLuca Tettamanti 	int err;
7922c03d07aSLuca Tettamanti 	int i;
7932c03d07aSLuca Tettamanti 
7942c03d07aSLuca Tettamanti 	dev_dbg(dev, "Enumerating hwmon sensors\n");
7952c03d07aSLuca Tettamanti 
796*18e25555SLuca Tettamanti 	pack = atk_ggrp(data, ATK_MUX_HWMON);
797*18e25555SLuca Tettamanti 	if (IS_ERR(pack))
798*18e25555SLuca Tettamanti 		return PTR_ERR(pack);
7992c03d07aSLuca Tettamanti 
8002c03d07aSLuca Tettamanti 	for (i = 0; i < pack->package.count; i++) {
8012c03d07aSLuca Tettamanti 		union acpi_object *obj = &pack->package.elements[i];
8022c03d07aSLuca Tettamanti 
8032c03d07aSLuca Tettamanti 		atk_add_sensor(data, obj);
8042c03d07aSLuca Tettamanti 	}
8052c03d07aSLuca Tettamanti 
8062c03d07aSLuca Tettamanti 	err = data->voltage_count + data->temperature_count + data->fan_count;
8072c03d07aSLuca Tettamanti 
808*18e25555SLuca Tettamanti 	ACPI_FREE(pack);
8092c03d07aSLuca Tettamanti 	return err;
8102c03d07aSLuca Tettamanti }
8112c03d07aSLuca Tettamanti 
8122c03d07aSLuca Tettamanti static int atk_create_files(struct atk_data *data)
8132c03d07aSLuca Tettamanti {
8142c03d07aSLuca Tettamanti 	struct atk_sensor_data *s;
8152c03d07aSLuca Tettamanti 	int err;
8162c03d07aSLuca Tettamanti 
8172c03d07aSLuca Tettamanti 	list_for_each_entry(s, &data->sensor_list, list) {
8182c03d07aSLuca Tettamanti 		err = device_create_file(data->hwmon_dev, &s->input_attr);
8192c03d07aSLuca Tettamanti 		if (err)
8202c03d07aSLuca Tettamanti 			return err;
8212c03d07aSLuca Tettamanti 		err = device_create_file(data->hwmon_dev, &s->label_attr);
8222c03d07aSLuca Tettamanti 		if (err)
8232c03d07aSLuca Tettamanti 			return err;
8242c03d07aSLuca Tettamanti 		err = device_create_file(data->hwmon_dev, &s->limit1_attr);
8252c03d07aSLuca Tettamanti 		if (err)
8262c03d07aSLuca Tettamanti 			return err;
8272c03d07aSLuca Tettamanti 		err = device_create_file(data->hwmon_dev, &s->limit2_attr);
8282c03d07aSLuca Tettamanti 		if (err)
8292c03d07aSLuca Tettamanti 			return err;
8302c03d07aSLuca Tettamanti 	}
8312c03d07aSLuca Tettamanti 
8322c03d07aSLuca Tettamanti 	err = device_create_file(data->hwmon_dev, &atk_name_attr);
8332c03d07aSLuca Tettamanti 
8342c03d07aSLuca Tettamanti 	return err;
8352c03d07aSLuca Tettamanti }
8362c03d07aSLuca Tettamanti 
8372c03d07aSLuca Tettamanti static void atk_remove_files(struct atk_data *data)
8382c03d07aSLuca Tettamanti {
8392c03d07aSLuca Tettamanti 	struct atk_sensor_data *s;
8402c03d07aSLuca Tettamanti 
8412c03d07aSLuca Tettamanti 	list_for_each_entry(s, &data->sensor_list, list) {
8422c03d07aSLuca Tettamanti 		device_remove_file(data->hwmon_dev, &s->input_attr);
8432c03d07aSLuca Tettamanti 		device_remove_file(data->hwmon_dev, &s->label_attr);
8442c03d07aSLuca Tettamanti 		device_remove_file(data->hwmon_dev, &s->limit1_attr);
8452c03d07aSLuca Tettamanti 		device_remove_file(data->hwmon_dev, &s->limit2_attr);
8462c03d07aSLuca Tettamanti 	}
8472c03d07aSLuca Tettamanti 	device_remove_file(data->hwmon_dev, &atk_name_attr);
8482c03d07aSLuca Tettamanti }
8492c03d07aSLuca Tettamanti 
8502c03d07aSLuca Tettamanti static void atk_free_sensors(struct atk_data *data)
8512c03d07aSLuca Tettamanti {
8522c03d07aSLuca Tettamanti 	struct list_head *head = &data->sensor_list;
8532c03d07aSLuca Tettamanti 	struct atk_sensor_data *s, *tmp;
8542c03d07aSLuca Tettamanti 
8552c03d07aSLuca Tettamanti 	list_for_each_entry_safe(s, tmp, head, list) {
8562c03d07aSLuca Tettamanti 		kfree(s->acpi_name);
8572c03d07aSLuca Tettamanti 		kfree(s);
8582c03d07aSLuca Tettamanti 	}
8592c03d07aSLuca Tettamanti }
8602c03d07aSLuca Tettamanti 
8612c03d07aSLuca Tettamanti static int atk_register_hwmon(struct atk_data *data)
8622c03d07aSLuca Tettamanti {
8632c03d07aSLuca Tettamanti 	struct device *dev = &data->acpi_dev->dev;
8642c03d07aSLuca Tettamanti 	int err;
8652c03d07aSLuca Tettamanti 
8662c03d07aSLuca Tettamanti 	dev_dbg(dev, "registering hwmon device\n");
8672c03d07aSLuca Tettamanti 	data->hwmon_dev = hwmon_device_register(dev);
8682c03d07aSLuca Tettamanti 	if (IS_ERR(data->hwmon_dev))
8692c03d07aSLuca Tettamanti 		return PTR_ERR(data->hwmon_dev);
8702c03d07aSLuca Tettamanti 
8712c03d07aSLuca Tettamanti 	dev_dbg(dev, "populating sysfs directory\n");
8722c03d07aSLuca Tettamanti 	err = atk_create_files(data);
8732c03d07aSLuca Tettamanti 	if (err)
8742c03d07aSLuca Tettamanti 		goto remove;
8752c03d07aSLuca Tettamanti 
8762c03d07aSLuca Tettamanti 	return 0;
8772c03d07aSLuca Tettamanti remove:
8782c03d07aSLuca Tettamanti 	/* Cleanup the registered files */
8792c03d07aSLuca Tettamanti 	atk_remove_files(data);
8802c03d07aSLuca Tettamanti 	hwmon_device_unregister(data->hwmon_dev);
8812c03d07aSLuca Tettamanti 	return err;
8822c03d07aSLuca Tettamanti }
8832c03d07aSLuca Tettamanti 
8842c03d07aSLuca Tettamanti static int atk_check_old_if(struct atk_data *data)
8852c03d07aSLuca Tettamanti {
8862c03d07aSLuca Tettamanti 	struct device *dev = &data->acpi_dev->dev;
8872c03d07aSLuca Tettamanti 	acpi_handle ret;
8882c03d07aSLuca Tettamanti 	acpi_status status;
8892c03d07aSLuca Tettamanti 
8902c03d07aSLuca Tettamanti 	/* RTMP: read temperature */
8912c03d07aSLuca Tettamanti 	status = acpi_get_handle(data->atk_handle, METHOD_OLD_READ_TMP, &ret);
8922c03d07aSLuca Tettamanti 	if (status != AE_OK) {
8932c03d07aSLuca Tettamanti 		dev_dbg(dev, "method " METHOD_OLD_READ_TMP " not found: %s\n",
8942c03d07aSLuca Tettamanti 				acpi_format_exception(status));
8952c03d07aSLuca Tettamanti 		return -ENODEV;
8962c03d07aSLuca Tettamanti 	}
8972c03d07aSLuca Tettamanti 	data->rtmp_handle = ret;
8982c03d07aSLuca Tettamanti 
8992c03d07aSLuca Tettamanti 	/* RVLT: read voltage */
9002c03d07aSLuca Tettamanti 	status = acpi_get_handle(data->atk_handle, METHOD_OLD_READ_VLT, &ret);
9012c03d07aSLuca Tettamanti 	if (status != AE_OK) {
9022c03d07aSLuca Tettamanti 		dev_dbg(dev, "method " METHOD_OLD_READ_VLT " not found: %s\n",
9032c03d07aSLuca Tettamanti 				acpi_format_exception(status));
9042c03d07aSLuca Tettamanti 		return -ENODEV;
9052c03d07aSLuca Tettamanti 	}
9062c03d07aSLuca Tettamanti 	data->rvlt_handle = ret;
9072c03d07aSLuca Tettamanti 
9082c03d07aSLuca Tettamanti 	/* RFAN: read fan status */
9092c03d07aSLuca Tettamanti 	status = acpi_get_handle(data->atk_handle, METHOD_OLD_READ_FAN, &ret);
9102c03d07aSLuca Tettamanti 	if (status != AE_OK) {
9112c03d07aSLuca Tettamanti 		dev_dbg(dev, "method " METHOD_OLD_READ_FAN " not found: %s\n",
9122c03d07aSLuca Tettamanti 				acpi_format_exception(status));
9132c03d07aSLuca Tettamanti 		return -ENODEV;
9142c03d07aSLuca Tettamanti 	}
9152c03d07aSLuca Tettamanti 	data->rfan_handle = ret;
9162c03d07aSLuca Tettamanti 
9172c03d07aSLuca Tettamanti 	return 0;
9182c03d07aSLuca Tettamanti }
9192c03d07aSLuca Tettamanti 
9202c03d07aSLuca Tettamanti static int atk_check_new_if(struct atk_data *data)
9212c03d07aSLuca Tettamanti {
9222c03d07aSLuca Tettamanti 	struct device *dev = &data->acpi_dev->dev;
9232c03d07aSLuca Tettamanti 	acpi_handle ret;
9242c03d07aSLuca Tettamanti 	acpi_status status;
9252c03d07aSLuca Tettamanti 
9262c03d07aSLuca Tettamanti 	/* Enumeration */
9272c03d07aSLuca Tettamanti 	status = acpi_get_handle(data->atk_handle, METHOD_ENUMERATE, &ret);
9282c03d07aSLuca Tettamanti 	if (status != AE_OK) {
9292c03d07aSLuca Tettamanti 		dev_dbg(dev, "method " METHOD_ENUMERATE " not found: %s\n",
9302c03d07aSLuca Tettamanti 				acpi_format_exception(status));
9312c03d07aSLuca Tettamanti 		return -ENODEV;
9322c03d07aSLuca Tettamanti 	}
9332c03d07aSLuca Tettamanti 	data->enumerate_handle = ret;
9342c03d07aSLuca Tettamanti 
9352c03d07aSLuca Tettamanti 	/* De-multiplexer (read) */
9362c03d07aSLuca Tettamanti 	status = acpi_get_handle(data->atk_handle, METHOD_READ, &ret);
9372c03d07aSLuca Tettamanti 	if (status != AE_OK) {
9382c03d07aSLuca Tettamanti 		dev_dbg(dev, "method " METHOD_READ " not found: %s\n",
9392c03d07aSLuca Tettamanti 				acpi_format_exception(status));
9402c03d07aSLuca Tettamanti 		return -ENODEV;
9412c03d07aSLuca Tettamanti 	}
9422c03d07aSLuca Tettamanti 	data->read_handle = ret;
9432c03d07aSLuca Tettamanti 
9442c03d07aSLuca Tettamanti 	return 0;
9452c03d07aSLuca Tettamanti }
9462c03d07aSLuca Tettamanti 
9472c03d07aSLuca Tettamanti static int atk_add(struct acpi_device *device)
9482c03d07aSLuca Tettamanti {
9492c03d07aSLuca Tettamanti 	acpi_status ret;
9502c03d07aSLuca Tettamanti 	int err;
9512c03d07aSLuca Tettamanti 	struct acpi_buffer buf;
9522c03d07aSLuca Tettamanti 	union acpi_object *obj;
9532c03d07aSLuca Tettamanti 	struct atk_data *data;
9542c03d07aSLuca Tettamanti 
9552c03d07aSLuca Tettamanti 	dev_dbg(&device->dev, "adding...\n");
9562c03d07aSLuca Tettamanti 
9572c03d07aSLuca Tettamanti 	data = kzalloc(sizeof(*data), GFP_KERNEL);
9582c03d07aSLuca Tettamanti 	if (!data)
9592c03d07aSLuca Tettamanti 		return -ENOMEM;
9602c03d07aSLuca Tettamanti 
9612c03d07aSLuca Tettamanti 	data->acpi_dev = device;
9622c03d07aSLuca Tettamanti 	data->atk_handle = device->handle;
9632c03d07aSLuca Tettamanti 	INIT_LIST_HEAD(&data->sensor_list);
9642c03d07aSLuca Tettamanti 
9652c03d07aSLuca Tettamanti 	buf.length = ACPI_ALLOCATE_BUFFER;
9662c03d07aSLuca Tettamanti 	ret = acpi_evaluate_object_typed(data->atk_handle, BOARD_ID, NULL,
9672c03d07aSLuca Tettamanti 			&buf, ACPI_TYPE_PACKAGE);
9682c03d07aSLuca Tettamanti 	if (ret != AE_OK) {
9692c03d07aSLuca Tettamanti 		dev_dbg(&device->dev, "atk: method MBIF not found\n");
9702c03d07aSLuca Tettamanti 		err = -ENODEV;
9712c03d07aSLuca Tettamanti 		goto out;
9722c03d07aSLuca Tettamanti 	}
9732c03d07aSLuca Tettamanti 
9742c03d07aSLuca Tettamanti 	obj = buf.pointer;
9752c03d07aSLuca Tettamanti 	if (obj->package.count >= 2 &&
9762c03d07aSLuca Tettamanti 			obj->package.elements[1].type == ACPI_TYPE_STRING) {
9772c03d07aSLuca Tettamanti 		dev_dbg(&device->dev, "board ID = %s\n",
9782c03d07aSLuca Tettamanti 				obj->package.elements[1].string.pointer);
9792c03d07aSLuca Tettamanti 	}
9802c03d07aSLuca Tettamanti 	ACPI_FREE(buf.pointer);
9812c03d07aSLuca Tettamanti 
9822c03d07aSLuca Tettamanti 	/* Check for hwmon methods: first check "old" style methods; note that
9832c03d07aSLuca Tettamanti 	 * both may be present: in this case we stick to the old interface;
9842c03d07aSLuca Tettamanti 	 * analysis of multiple DSDTs indicates that when both interfaces
9852c03d07aSLuca Tettamanti 	 * are present the new one (GGRP/GITM) is not functional.
9862c03d07aSLuca Tettamanti 	 */
9872c03d07aSLuca Tettamanti 	err = atk_check_old_if(data);
9882c03d07aSLuca Tettamanti 	if (!err) {
9892c03d07aSLuca Tettamanti 		dev_dbg(&device->dev, "Using old hwmon interface\n");
9902c03d07aSLuca Tettamanti 		data->old_interface = true;
9912c03d07aSLuca Tettamanti 	} else {
9922c03d07aSLuca Tettamanti 		err = atk_check_new_if(data);
9932c03d07aSLuca Tettamanti 		if (err)
9942c03d07aSLuca Tettamanti 			goto out;
9952c03d07aSLuca Tettamanti 
9962c03d07aSLuca Tettamanti 		dev_dbg(&device->dev, "Using new hwmon interface\n");
9972c03d07aSLuca Tettamanti 		data->old_interface = false;
9982c03d07aSLuca Tettamanti 	}
9992c03d07aSLuca Tettamanti 
10002c03d07aSLuca Tettamanti 	if (data->old_interface)
10012c03d07aSLuca Tettamanti 		err = atk_enumerate_old_hwmon(data);
10022c03d07aSLuca Tettamanti 	else
10032c03d07aSLuca Tettamanti 		err = atk_enumerate_new_hwmon(data);
10042c03d07aSLuca Tettamanti 	if (err < 0)
10052c03d07aSLuca Tettamanti 		goto out;
10062c03d07aSLuca Tettamanti 	if (err == 0) {
10072c03d07aSLuca Tettamanti 		dev_info(&device->dev,
10082c03d07aSLuca Tettamanti 			 "No usable sensor detected, bailing out\n");
10092c03d07aSLuca Tettamanti 		err = -ENODEV;
10102c03d07aSLuca Tettamanti 		goto out;
10112c03d07aSLuca Tettamanti 	}
10122c03d07aSLuca Tettamanti 
10132c03d07aSLuca Tettamanti 	err = atk_register_hwmon(data);
10142c03d07aSLuca Tettamanti 	if (err)
10152c03d07aSLuca Tettamanti 		goto cleanup;
10162c03d07aSLuca Tettamanti 
10172c03d07aSLuca Tettamanti 	device->driver_data = data;
10182c03d07aSLuca Tettamanti 	return 0;
10192c03d07aSLuca Tettamanti cleanup:
10202c03d07aSLuca Tettamanti 	atk_free_sensors(data);
10212c03d07aSLuca Tettamanti out:
10222c03d07aSLuca Tettamanti 	kfree(data);
10232c03d07aSLuca Tettamanti 	return err;
10242c03d07aSLuca Tettamanti }
10252c03d07aSLuca Tettamanti 
10262c03d07aSLuca Tettamanti static int atk_remove(struct acpi_device *device, int type)
10272c03d07aSLuca Tettamanti {
10282c03d07aSLuca Tettamanti 	struct atk_data *data = device->driver_data;
10292c03d07aSLuca Tettamanti 	dev_dbg(&device->dev, "removing...\n");
10302c03d07aSLuca Tettamanti 
10312c03d07aSLuca Tettamanti 	device->driver_data = NULL;
10322c03d07aSLuca Tettamanti 
10332c03d07aSLuca Tettamanti 	atk_remove_files(data);
10342c03d07aSLuca Tettamanti 	atk_free_sensors(data);
10352c03d07aSLuca Tettamanti 	hwmon_device_unregister(data->hwmon_dev);
10362c03d07aSLuca Tettamanti 
10372c03d07aSLuca Tettamanti 	kfree(data);
10382c03d07aSLuca Tettamanti 
10392c03d07aSLuca Tettamanti 	return 0;
10402c03d07aSLuca Tettamanti }
10412c03d07aSLuca Tettamanti 
10422c03d07aSLuca Tettamanti static int __init atk0110_init(void)
10432c03d07aSLuca Tettamanti {
10442c03d07aSLuca Tettamanti 	int ret;
10452c03d07aSLuca Tettamanti 
10462c03d07aSLuca Tettamanti 	ret = acpi_bus_register_driver(&atk_driver);
10472c03d07aSLuca Tettamanti 	if (ret)
10482c03d07aSLuca Tettamanti 		pr_info("atk: acpi_bus_register_driver failed: %d\n", ret);
10492c03d07aSLuca Tettamanti 
10502c03d07aSLuca Tettamanti 	return ret;
10512c03d07aSLuca Tettamanti }
10522c03d07aSLuca Tettamanti 
10532c03d07aSLuca Tettamanti static void __exit atk0110_exit(void)
10542c03d07aSLuca Tettamanti {
10552c03d07aSLuca Tettamanti 	acpi_bus_unregister_driver(&atk_driver);
10562c03d07aSLuca Tettamanti }
10572c03d07aSLuca Tettamanti 
10582c03d07aSLuca Tettamanti module_init(atk0110_init);
10592c03d07aSLuca Tettamanti module_exit(atk0110_exit);
10602c03d07aSLuca Tettamanti 
10612c03d07aSLuca Tettamanti MODULE_LICENSE("GPL");
1062