xref: /openbmc/linux/drivers/hwmon/asus_atk0110.c (revision 84fb029faa05e1de229a68829cca5dcf85c79894)
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 
8ac561494SJoe Perches #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
9ac561494SJoe Perches 
107e5eab11SLuca Tettamanti #include <linux/debugfs.h>
112c03d07aSLuca Tettamanti #include <linux/kernel.h>
122c03d07aSLuca Tettamanti #include <linux/hwmon.h>
132c03d07aSLuca Tettamanti #include <linux/list.h>
142c03d07aSLuca Tettamanti #include <linux/module.h>
155a0e3ad6STejun Heo #include <linux/slab.h>
1686ca33e8SLuca Tettamanti #include <linux/dmi.h>
17dcd8f392SJean Delvare #include <linux/jiffies.h>
18fa845740SJean Delvare #include <linux/err.h>
192c03d07aSLuca Tettamanti 
202c03d07aSLuca Tettamanti #include <acpi/acpi.h>
212c03d07aSLuca Tettamanti #include <acpi/acpixf.h>
222c03d07aSLuca Tettamanti #include <acpi/acpi_drivers.h>
232c03d07aSLuca Tettamanti #include <acpi/acpi_bus.h>
242c03d07aSLuca Tettamanti 
252c03d07aSLuca Tettamanti 
262c03d07aSLuca Tettamanti #define ATK_HID "ATK0110"
272c03d07aSLuca Tettamanti 
2886ca33e8SLuca Tettamanti static bool new_if;
2986ca33e8SLuca Tettamanti module_param(new_if, bool, 0);
3086ca33e8SLuca Tettamanti MODULE_PARM_DESC(new_if, "Override detection heuristic and force the use of the new ATK0110 interface");
3186ca33e8SLuca Tettamanti 
3286ca33e8SLuca Tettamanti static const struct dmi_system_id __initconst atk_force_new_if[] = {
3386ca33e8SLuca Tettamanti 	{
3486ca33e8SLuca Tettamanti 		/* Old interface has broken MCH temp monitoring */
3586ca33e8SLuca Tettamanti 		.ident = "Asus Sabertooth X58",
3686ca33e8SLuca Tettamanti 		.matches = {
3786ca33e8SLuca Tettamanti 			DMI_MATCH(DMI_BOARD_NAME, "SABERTOOTH X58")
3886ca33e8SLuca Tettamanti 		}
3943ca6cb2SLuca Tettamanti 	}, {
4043ca6cb2SLuca Tettamanti 		/* Old interface reads the same sensor for fan0 and fan1 */
4143ca6cb2SLuca Tettamanti 		.ident = "Asus M5A78L",
4243ca6cb2SLuca Tettamanti 		.matches = {
4343ca6cb2SLuca Tettamanti 			DMI_MATCH(DMI_BOARD_NAME, "M5A78L")
4443ca6cb2SLuca Tettamanti 		}
4586ca33e8SLuca Tettamanti 	},
4686ca33e8SLuca Tettamanti 	{ }
4786ca33e8SLuca Tettamanti };
4886ca33e8SLuca Tettamanti 
4975bdc936SGuenter Roeck /*
5075bdc936SGuenter Roeck  * Minimum time between readings, enforced in order to avoid
512c03d07aSLuca Tettamanti  * hogging the CPU.
522c03d07aSLuca Tettamanti  */
532c03d07aSLuca Tettamanti #define CACHE_TIME		HZ
542c03d07aSLuca Tettamanti 
552c03d07aSLuca Tettamanti #define BOARD_ID		"MBIF"
562c03d07aSLuca Tettamanti #define METHOD_ENUMERATE	"GGRP"
572c03d07aSLuca Tettamanti #define METHOD_READ		"GITM"
582c03d07aSLuca Tettamanti #define METHOD_WRITE		"SITM"
592c03d07aSLuca Tettamanti #define METHOD_OLD_READ_TMP	"RTMP"
602c03d07aSLuca Tettamanti #define METHOD_OLD_READ_VLT	"RVLT"
612c03d07aSLuca Tettamanti #define METHOD_OLD_READ_FAN	"RFAN"
622c03d07aSLuca Tettamanti #define METHOD_OLD_ENUM_TMP	"TSIF"
632c03d07aSLuca Tettamanti #define METHOD_OLD_ENUM_VLT	"VSIF"
642c03d07aSLuca Tettamanti #define METHOD_OLD_ENUM_FAN	"FSIF"
652c03d07aSLuca Tettamanti 
662c03d07aSLuca Tettamanti #define ATK_MUX_HWMON		0x00000006ULL
679e6eba61SLuca Tettamanti #define ATK_MUX_MGMT		0x00000011ULL
682c03d07aSLuca Tettamanti 
692c03d07aSLuca Tettamanti #define ATK_CLASS_MASK		0xff000000ULL
702c03d07aSLuca Tettamanti #define ATK_CLASS_FREQ_CTL	0x03000000ULL
712c03d07aSLuca Tettamanti #define ATK_CLASS_FAN_CTL	0x04000000ULL
722c03d07aSLuca Tettamanti #define ATK_CLASS_HWMON		0x06000000ULL
739e6eba61SLuca Tettamanti #define ATK_CLASS_MGMT		0x11000000ULL
742c03d07aSLuca Tettamanti 
752c03d07aSLuca Tettamanti #define ATK_TYPE_MASK		0x00ff0000ULL
762c03d07aSLuca Tettamanti #define HWMON_TYPE_VOLT		0x00020000ULL
772c03d07aSLuca Tettamanti #define HWMON_TYPE_TEMP		0x00030000ULL
782c03d07aSLuca Tettamanti #define HWMON_TYPE_FAN		0x00040000ULL
792c03d07aSLuca Tettamanti 
809e6eba61SLuca Tettamanti #define ATK_ELEMENT_ID_MASK	0x0000ffffULL
819e6eba61SLuca Tettamanti 
829e6eba61SLuca Tettamanti #define ATK_EC_ID		0x11060004ULL
832c03d07aSLuca Tettamanti 
842c03d07aSLuca Tettamanti enum atk_pack_member {
852c03d07aSLuca Tettamanti 	HWMON_PACK_FLAGS,
862c03d07aSLuca Tettamanti 	HWMON_PACK_NAME,
872c03d07aSLuca Tettamanti 	HWMON_PACK_LIMIT1,
882c03d07aSLuca Tettamanti 	HWMON_PACK_LIMIT2,
892c03d07aSLuca Tettamanti 	HWMON_PACK_ENABLE
902c03d07aSLuca Tettamanti };
912c03d07aSLuca Tettamanti 
922c03d07aSLuca Tettamanti /* New package format */
932c03d07aSLuca Tettamanti #define _HWMON_NEW_PACK_SIZE	7
942c03d07aSLuca Tettamanti #define _HWMON_NEW_PACK_FLAGS	0
952c03d07aSLuca Tettamanti #define _HWMON_NEW_PACK_NAME	1
962c03d07aSLuca Tettamanti #define _HWMON_NEW_PACK_UNK1	2
972c03d07aSLuca Tettamanti #define _HWMON_NEW_PACK_UNK2	3
982c03d07aSLuca Tettamanti #define _HWMON_NEW_PACK_LIMIT1	4
992c03d07aSLuca Tettamanti #define _HWMON_NEW_PACK_LIMIT2	5
1002c03d07aSLuca Tettamanti #define _HWMON_NEW_PACK_ENABLE	6
1012c03d07aSLuca Tettamanti 
1022c03d07aSLuca Tettamanti /* Old package format */
1032c03d07aSLuca Tettamanti #define _HWMON_OLD_PACK_SIZE	5
1042c03d07aSLuca Tettamanti #define _HWMON_OLD_PACK_FLAGS	0
1052c03d07aSLuca Tettamanti #define _HWMON_OLD_PACK_NAME	1
1062c03d07aSLuca Tettamanti #define _HWMON_OLD_PACK_LIMIT1	2
1072c03d07aSLuca Tettamanti #define _HWMON_OLD_PACK_LIMIT2	3
1082c03d07aSLuca Tettamanti #define _HWMON_OLD_PACK_ENABLE	4
1092c03d07aSLuca Tettamanti 
1102c03d07aSLuca Tettamanti 
1112c03d07aSLuca Tettamanti struct atk_data {
1122c03d07aSLuca Tettamanti 	struct device *hwmon_dev;
1132c03d07aSLuca Tettamanti 	acpi_handle atk_handle;
1142c03d07aSLuca Tettamanti 	struct acpi_device *acpi_dev;
1152c03d07aSLuca Tettamanti 
1162c03d07aSLuca Tettamanti 	bool old_interface;
1172c03d07aSLuca Tettamanti 
1182c03d07aSLuca Tettamanti 	/* old interface */
1192c03d07aSLuca Tettamanti 	acpi_handle rtmp_handle;
1202c03d07aSLuca Tettamanti 	acpi_handle rvlt_handle;
1212c03d07aSLuca Tettamanti 	acpi_handle rfan_handle;
122*84fb029fSLABBE Corentin 	/* new interface */
1232c03d07aSLuca Tettamanti 	acpi_handle enumerate_handle;
1242c03d07aSLuca Tettamanti 	acpi_handle read_handle;
1259e6eba61SLuca Tettamanti 	acpi_handle write_handle;
1269e6eba61SLuca Tettamanti 
1279e6eba61SLuca Tettamanti 	bool disable_ec;
1282c03d07aSLuca Tettamanti 
1292c03d07aSLuca Tettamanti 	int voltage_count;
1302c03d07aSLuca Tettamanti 	int temperature_count;
1312c03d07aSLuca Tettamanti 	int fan_count;
1322c03d07aSLuca Tettamanti 	struct list_head sensor_list;
1337e5eab11SLuca Tettamanti 
1347e5eab11SLuca Tettamanti 	struct {
1357e5eab11SLuca Tettamanti 		struct dentry *root;
1367e5eab11SLuca Tettamanti 		u32 id;
1377e5eab11SLuca Tettamanti 	} debugfs;
1382c03d07aSLuca Tettamanti };
1392c03d07aSLuca Tettamanti 
1402c03d07aSLuca Tettamanti 
1412c03d07aSLuca Tettamanti typedef ssize_t (*sysfs_show_func)(struct device *dev,
1422c03d07aSLuca Tettamanti 			struct device_attribute *attr, char *buf);
1432c03d07aSLuca Tettamanti 
1442c03d07aSLuca Tettamanti static const struct acpi_device_id atk_ids[] = {
1452c03d07aSLuca Tettamanti 	{ATK_HID, 0},
1462c03d07aSLuca Tettamanti 	{"", 0},
1472c03d07aSLuca Tettamanti };
1482c03d07aSLuca Tettamanti MODULE_DEVICE_TABLE(acpi, atk_ids);
1492c03d07aSLuca Tettamanti 
1502c03d07aSLuca Tettamanti #define ATTR_NAME_SIZE 16 /* Worst case is "tempN_input" */
1512c03d07aSLuca Tettamanti 
1522c03d07aSLuca Tettamanti struct atk_sensor_data {
1532c03d07aSLuca Tettamanti 	struct list_head list;
1542c03d07aSLuca Tettamanti 	struct atk_data *data;
1552c03d07aSLuca Tettamanti 	struct device_attribute label_attr;
1562c03d07aSLuca Tettamanti 	struct device_attribute input_attr;
1572c03d07aSLuca Tettamanti 	struct device_attribute limit1_attr;
1582c03d07aSLuca Tettamanti 	struct device_attribute limit2_attr;
1592c03d07aSLuca Tettamanti 	char label_attr_name[ATTR_NAME_SIZE];
1602c03d07aSLuca Tettamanti 	char input_attr_name[ATTR_NAME_SIZE];
1612c03d07aSLuca Tettamanti 	char limit1_attr_name[ATTR_NAME_SIZE];
1622c03d07aSLuca Tettamanti 	char limit2_attr_name[ATTR_NAME_SIZE];
1632c03d07aSLuca Tettamanti 	u64 id;
1642c03d07aSLuca Tettamanti 	u64 type;
1652c03d07aSLuca Tettamanti 	u64 limit1;
1662c03d07aSLuca Tettamanti 	u64 limit2;
1672c03d07aSLuca Tettamanti 	u64 cached_value;
1682c03d07aSLuca Tettamanti 	unsigned long last_updated; /* in jiffies */
1692c03d07aSLuca Tettamanti 	bool is_valid;
1702c03d07aSLuca Tettamanti 	char const *acpi_name;
1712c03d07aSLuca Tettamanti };
1722c03d07aSLuca Tettamanti 
17375bdc936SGuenter Roeck /*
17475bdc936SGuenter Roeck  * Return buffer format:
17518e25555SLuca Tettamanti  * [0-3] "value" is valid flag
17618e25555SLuca Tettamanti  * [4-7] value
17718e25555SLuca Tettamanti  * [8- ] unknown stuff on newer mobos
17818e25555SLuca Tettamanti  */
17918e25555SLuca Tettamanti struct atk_acpi_ret_buffer {
18018e25555SLuca Tettamanti 	u32 flags;
18118e25555SLuca Tettamanti 	u32 value;
18218e25555SLuca Tettamanti 	u8 data[];
18318e25555SLuca Tettamanti };
18418e25555SLuca Tettamanti 
18518e25555SLuca Tettamanti /* Input buffer used for GITM and SITM methods */
18618e25555SLuca Tettamanti struct atk_acpi_input_buf {
18718e25555SLuca Tettamanti 	u32 id;
18818e25555SLuca Tettamanti 	u32 param1;
18918e25555SLuca Tettamanti 	u32 param2;
1902c03d07aSLuca Tettamanti };
1912c03d07aSLuca Tettamanti 
1922c03d07aSLuca Tettamanti static int atk_add(struct acpi_device *device);
19351fac838SRafael J. Wysocki static int atk_remove(struct acpi_device *device);
1942c03d07aSLuca Tettamanti static void atk_print_sensor(struct atk_data *data, union acpi_object *obj);
1952c03d07aSLuca Tettamanti static int atk_read_value(struct atk_sensor_data *sensor, u64 *value);
1962c03d07aSLuca Tettamanti static void atk_free_sensors(struct atk_data *data);
1972c03d07aSLuca Tettamanti 
1982c03d07aSLuca Tettamanti static struct acpi_driver atk_driver = {
1992c03d07aSLuca Tettamanti 	.name	= ATK_HID,
2002c03d07aSLuca Tettamanti 	.class	= "hwmon",
2012c03d07aSLuca Tettamanti 	.ids	= atk_ids,
2022c03d07aSLuca Tettamanti 	.ops	= {
2032c03d07aSLuca Tettamanti 		.add	= atk_add,
2042c03d07aSLuca Tettamanti 		.remove	= atk_remove,
2052c03d07aSLuca Tettamanti 	},
2062c03d07aSLuca Tettamanti };
2072c03d07aSLuca Tettamanti 
2082c03d07aSLuca Tettamanti #define input_to_atk_sensor(attr) \
2092c03d07aSLuca Tettamanti 	container_of(attr, struct atk_sensor_data, input_attr)
2102c03d07aSLuca Tettamanti 
2112c03d07aSLuca Tettamanti #define label_to_atk_sensor(attr) \
2122c03d07aSLuca Tettamanti 	container_of(attr, struct atk_sensor_data, label_attr)
2132c03d07aSLuca Tettamanti 
2142c03d07aSLuca Tettamanti #define limit1_to_atk_sensor(attr) \
2152c03d07aSLuca Tettamanti 	container_of(attr, struct atk_sensor_data, limit1_attr)
2162c03d07aSLuca Tettamanti 
2172c03d07aSLuca Tettamanti #define limit2_to_atk_sensor(attr) \
2182c03d07aSLuca Tettamanti 	container_of(attr, struct atk_sensor_data, limit2_attr)
2192c03d07aSLuca Tettamanti 
2202c03d07aSLuca Tettamanti static ssize_t atk_input_show(struct device *dev,
2212c03d07aSLuca Tettamanti 		struct device_attribute *attr, char *buf)
2222c03d07aSLuca Tettamanti {
2232c03d07aSLuca Tettamanti 	struct atk_sensor_data *s = input_to_atk_sensor(attr);
2242c03d07aSLuca Tettamanti 	u64 value;
2252c03d07aSLuca Tettamanti 	int err;
2262c03d07aSLuca Tettamanti 
2272c03d07aSLuca Tettamanti 	err = atk_read_value(s, &value);
2282c03d07aSLuca Tettamanti 	if (err)
2292c03d07aSLuca Tettamanti 		return err;
2302c03d07aSLuca Tettamanti 
2312c03d07aSLuca Tettamanti 	if (s->type == HWMON_TYPE_TEMP)
2322c03d07aSLuca Tettamanti 		/* ACPI returns decidegree */
2332c03d07aSLuca Tettamanti 		value *= 100;
2342c03d07aSLuca Tettamanti 
2352c03d07aSLuca Tettamanti 	return sprintf(buf, "%llu\n", value);
2362c03d07aSLuca Tettamanti }
2372c03d07aSLuca Tettamanti 
2382c03d07aSLuca Tettamanti static ssize_t atk_label_show(struct device *dev,
2392c03d07aSLuca Tettamanti 		struct device_attribute *attr, char *buf)
2402c03d07aSLuca Tettamanti {
2412c03d07aSLuca Tettamanti 	struct atk_sensor_data *s = label_to_atk_sensor(attr);
2422c03d07aSLuca Tettamanti 
2432c03d07aSLuca Tettamanti 	return sprintf(buf, "%s\n", s->acpi_name);
2442c03d07aSLuca Tettamanti }
2452c03d07aSLuca Tettamanti 
2462c03d07aSLuca Tettamanti static ssize_t atk_limit1_show(struct device *dev,
2472c03d07aSLuca Tettamanti 		struct device_attribute *attr, char *buf)
2482c03d07aSLuca Tettamanti {
2492c03d07aSLuca Tettamanti 	struct atk_sensor_data *s = limit1_to_atk_sensor(attr);
2502c03d07aSLuca Tettamanti 	u64 value = s->limit1;
2512c03d07aSLuca Tettamanti 
2522c03d07aSLuca Tettamanti 	if (s->type == HWMON_TYPE_TEMP)
2532c03d07aSLuca Tettamanti 		value *= 100;
2542c03d07aSLuca Tettamanti 
2552c03d07aSLuca Tettamanti 	return sprintf(buf, "%lld\n", value);
2562c03d07aSLuca Tettamanti }
2572c03d07aSLuca Tettamanti 
2582c03d07aSLuca Tettamanti static ssize_t atk_limit2_show(struct device *dev,
2592c03d07aSLuca Tettamanti 		struct device_attribute *attr, char *buf)
2602c03d07aSLuca Tettamanti {
2612c03d07aSLuca Tettamanti 	struct atk_sensor_data *s = limit2_to_atk_sensor(attr);
2622c03d07aSLuca Tettamanti 	u64 value = s->limit2;
2632c03d07aSLuca Tettamanti 
2642c03d07aSLuca Tettamanti 	if (s->type == HWMON_TYPE_TEMP)
2652c03d07aSLuca Tettamanti 		value *= 100;
2662c03d07aSLuca Tettamanti 
2672c03d07aSLuca Tettamanti 	return sprintf(buf, "%lld\n", value);
2682c03d07aSLuca Tettamanti }
2692c03d07aSLuca Tettamanti 
2702c03d07aSLuca Tettamanti static ssize_t atk_name_show(struct device *dev,
2712c03d07aSLuca Tettamanti 				struct device_attribute *attr, char *buf)
2722c03d07aSLuca Tettamanti {
2732c03d07aSLuca Tettamanti 	return sprintf(buf, "atk0110\n");
2742c03d07aSLuca Tettamanti }
2752c03d07aSLuca Tettamanti static struct device_attribute atk_name_attr =
2762c03d07aSLuca Tettamanti 		__ATTR(name, 0444, atk_name_show, NULL);
2772c03d07aSLuca Tettamanti 
2782c03d07aSLuca Tettamanti static void atk_init_attribute(struct device_attribute *attr, char *name,
2792c03d07aSLuca Tettamanti 		sysfs_show_func show)
2802c03d07aSLuca Tettamanti {
2819a2d55beSGuenter Roeck 	sysfs_attr_init(&attr->attr);
2822c03d07aSLuca Tettamanti 	attr->attr.name = name;
2832c03d07aSLuca Tettamanti 	attr->attr.mode = 0444;
2842c03d07aSLuca Tettamanti 	attr->show = show;
2852c03d07aSLuca Tettamanti 	attr->store = NULL;
2862c03d07aSLuca Tettamanti }
2872c03d07aSLuca Tettamanti 
2882c03d07aSLuca Tettamanti 
2892c03d07aSLuca Tettamanti static union acpi_object *atk_get_pack_member(struct atk_data *data,
2902c03d07aSLuca Tettamanti 						union acpi_object *pack,
2912c03d07aSLuca Tettamanti 						enum atk_pack_member m)
2922c03d07aSLuca Tettamanti {
2932c03d07aSLuca Tettamanti 	bool old_if = data->old_interface;
2942c03d07aSLuca Tettamanti 	int offset;
2952c03d07aSLuca Tettamanti 
2962c03d07aSLuca Tettamanti 	switch (m) {
2972c03d07aSLuca Tettamanti 	case HWMON_PACK_FLAGS:
2982c03d07aSLuca Tettamanti 		offset = old_if ? _HWMON_OLD_PACK_FLAGS : _HWMON_NEW_PACK_FLAGS;
2992c03d07aSLuca Tettamanti 		break;
3002c03d07aSLuca Tettamanti 	case HWMON_PACK_NAME:
3012c03d07aSLuca Tettamanti 		offset = old_if ? _HWMON_OLD_PACK_NAME : _HWMON_NEW_PACK_NAME;
3022c03d07aSLuca Tettamanti 		break;
3032c03d07aSLuca Tettamanti 	case HWMON_PACK_LIMIT1:
3042c03d07aSLuca Tettamanti 		offset = old_if ? _HWMON_OLD_PACK_LIMIT1 :
3052c03d07aSLuca Tettamanti 				  _HWMON_NEW_PACK_LIMIT1;
3062c03d07aSLuca Tettamanti 		break;
3072c03d07aSLuca Tettamanti 	case HWMON_PACK_LIMIT2:
3082c03d07aSLuca Tettamanti 		offset = old_if ? _HWMON_OLD_PACK_LIMIT2 :
3092c03d07aSLuca Tettamanti 				  _HWMON_NEW_PACK_LIMIT2;
3102c03d07aSLuca Tettamanti 		break;
3112c03d07aSLuca Tettamanti 	case HWMON_PACK_ENABLE:
3122c03d07aSLuca Tettamanti 		offset = old_if ? _HWMON_OLD_PACK_ENABLE :
3132c03d07aSLuca Tettamanti 				  _HWMON_NEW_PACK_ENABLE;
3142c03d07aSLuca Tettamanti 		break;
3152c03d07aSLuca Tettamanti 	default:
3162c03d07aSLuca Tettamanti 		return NULL;
3172c03d07aSLuca Tettamanti 	}
3182c03d07aSLuca Tettamanti 
3192c03d07aSLuca Tettamanti 	return &pack->package.elements[offset];
3202c03d07aSLuca Tettamanti }
3212c03d07aSLuca Tettamanti 
3222c03d07aSLuca Tettamanti 
32375bdc936SGuenter Roeck /*
32475bdc936SGuenter Roeck  * New package format is:
3252c03d07aSLuca Tettamanti  * - flag (int)
3262c03d07aSLuca Tettamanti  *	class - used for de-muxing the request to the correct GITn
3272c03d07aSLuca Tettamanti  *	type (volt, temp, fan)
3282c03d07aSLuca Tettamanti  *	sensor id |
3292c03d07aSLuca Tettamanti  *	sensor id - used for de-muxing the request _inside_ the GITn
3302c03d07aSLuca Tettamanti  * - name (str)
3312c03d07aSLuca Tettamanti  * - unknown (int)
3322c03d07aSLuca Tettamanti  * - unknown (int)
3332c03d07aSLuca Tettamanti  * - limit1 (int)
3342c03d07aSLuca Tettamanti  * - limit2 (int)
3352c03d07aSLuca Tettamanti  * - enable (int)
3362c03d07aSLuca Tettamanti  *
3372c03d07aSLuca Tettamanti  * The old package has the same format but it's missing the two unknown fields.
3382c03d07aSLuca Tettamanti  */
3392c03d07aSLuca Tettamanti static int validate_hwmon_pack(struct atk_data *data, union acpi_object *obj)
3402c03d07aSLuca Tettamanti {
3412c03d07aSLuca Tettamanti 	struct device *dev = &data->acpi_dev->dev;
3422c03d07aSLuca Tettamanti 	union acpi_object *tmp;
3432c03d07aSLuca Tettamanti 	bool old_if = data->old_interface;
3442c03d07aSLuca Tettamanti 	int const expected_size = old_if ? _HWMON_OLD_PACK_SIZE :
3452c03d07aSLuca Tettamanti 					   _HWMON_NEW_PACK_SIZE;
3462c03d07aSLuca Tettamanti 
3472c03d07aSLuca Tettamanti 	if (obj->type != ACPI_TYPE_PACKAGE) {
3482c03d07aSLuca Tettamanti 		dev_warn(dev, "Invalid type: %d\n", obj->type);
3492c03d07aSLuca Tettamanti 		return -EINVAL;
3502c03d07aSLuca Tettamanti 	}
3512c03d07aSLuca Tettamanti 
3522c03d07aSLuca Tettamanti 	if (obj->package.count != expected_size) {
3532c03d07aSLuca Tettamanti 		dev_warn(dev, "Invalid package size: %d, expected: %d\n",
3542c03d07aSLuca Tettamanti 				obj->package.count, expected_size);
3552c03d07aSLuca Tettamanti 		return -EINVAL;
3562c03d07aSLuca Tettamanti 	}
3572c03d07aSLuca Tettamanti 
3582c03d07aSLuca Tettamanti 	tmp = atk_get_pack_member(data, obj, HWMON_PACK_FLAGS);
3592c03d07aSLuca Tettamanti 	if (tmp->type != ACPI_TYPE_INTEGER) {
3602c03d07aSLuca Tettamanti 		dev_warn(dev, "Invalid type (flag): %d\n", tmp->type);
3612c03d07aSLuca Tettamanti 		return -EINVAL;
3622c03d07aSLuca Tettamanti 	}
3632c03d07aSLuca Tettamanti 
3642c03d07aSLuca Tettamanti 	tmp = atk_get_pack_member(data, obj, HWMON_PACK_NAME);
3652c03d07aSLuca Tettamanti 	if (tmp->type != ACPI_TYPE_STRING) {
3662c03d07aSLuca Tettamanti 		dev_warn(dev, "Invalid type (name): %d\n", tmp->type);
3672c03d07aSLuca Tettamanti 		return -EINVAL;
3682c03d07aSLuca Tettamanti 	}
3692c03d07aSLuca Tettamanti 
3702c03d07aSLuca Tettamanti 	/* Don't check... we don't know what they're useful for anyway */
3712c03d07aSLuca Tettamanti #if 0
3722c03d07aSLuca Tettamanti 	tmp = &obj->package.elements[HWMON_PACK_UNK1];
3732c03d07aSLuca Tettamanti 	if (tmp->type != ACPI_TYPE_INTEGER) {
3742c03d07aSLuca Tettamanti 		dev_warn(dev, "Invalid type (unk1): %d\n", tmp->type);
3752c03d07aSLuca Tettamanti 		return -EINVAL;
3762c03d07aSLuca Tettamanti 	}
3772c03d07aSLuca Tettamanti 
3782c03d07aSLuca Tettamanti 	tmp = &obj->package.elements[HWMON_PACK_UNK2];
3792c03d07aSLuca Tettamanti 	if (tmp->type != ACPI_TYPE_INTEGER) {
3802c03d07aSLuca Tettamanti 		dev_warn(dev, "Invalid type (unk2): %d\n", tmp->type);
3812c03d07aSLuca Tettamanti 		return -EINVAL;
3822c03d07aSLuca Tettamanti 	}
3832c03d07aSLuca Tettamanti #endif
3842c03d07aSLuca Tettamanti 
3852c03d07aSLuca Tettamanti 	tmp = atk_get_pack_member(data, obj, HWMON_PACK_LIMIT1);
3862c03d07aSLuca Tettamanti 	if (tmp->type != ACPI_TYPE_INTEGER) {
3872c03d07aSLuca Tettamanti 		dev_warn(dev, "Invalid type (limit1): %d\n", tmp->type);
3882c03d07aSLuca Tettamanti 		return -EINVAL;
3892c03d07aSLuca Tettamanti 	}
3902c03d07aSLuca Tettamanti 
3912c03d07aSLuca Tettamanti 	tmp = atk_get_pack_member(data, obj, HWMON_PACK_LIMIT2);
3922c03d07aSLuca Tettamanti 	if (tmp->type != ACPI_TYPE_INTEGER) {
3932c03d07aSLuca Tettamanti 		dev_warn(dev, "Invalid type (limit2): %d\n", tmp->type);
3942c03d07aSLuca Tettamanti 		return -EINVAL;
3952c03d07aSLuca Tettamanti 	}
3962c03d07aSLuca Tettamanti 
3972c03d07aSLuca Tettamanti 	tmp = atk_get_pack_member(data, obj, HWMON_PACK_ENABLE);
3982c03d07aSLuca Tettamanti 	if (tmp->type != ACPI_TYPE_INTEGER) {
3992c03d07aSLuca Tettamanti 		dev_warn(dev, "Invalid type (enable): %d\n", tmp->type);
4002c03d07aSLuca Tettamanti 		return -EINVAL;
4012c03d07aSLuca Tettamanti 	}
4022c03d07aSLuca Tettamanti 
4032c03d07aSLuca Tettamanti 	atk_print_sensor(data, obj);
4042c03d07aSLuca Tettamanti 
4052c03d07aSLuca Tettamanti 	return 0;
4062c03d07aSLuca Tettamanti }
4072c03d07aSLuca Tettamanti 
408b9008708SLuca Tettamanti #ifdef DEBUG
4092c03d07aSLuca Tettamanti static char const *atk_sensor_type(union acpi_object *flags)
4102c03d07aSLuca Tettamanti {
4112c03d07aSLuca Tettamanti 	u64 type = flags->integer.value & ATK_TYPE_MASK;
4122c03d07aSLuca Tettamanti 	char const *what;
4132c03d07aSLuca Tettamanti 
4142c03d07aSLuca Tettamanti 	switch (type) {
4152c03d07aSLuca Tettamanti 	case HWMON_TYPE_VOLT:
4162c03d07aSLuca Tettamanti 		what = "voltage";
4172c03d07aSLuca Tettamanti 		break;
4182c03d07aSLuca Tettamanti 	case HWMON_TYPE_TEMP:
4192c03d07aSLuca Tettamanti 		what = "temperature";
4202c03d07aSLuca Tettamanti 		break;
4212c03d07aSLuca Tettamanti 	case HWMON_TYPE_FAN:
4222c03d07aSLuca Tettamanti 		what = "fan";
4232c03d07aSLuca Tettamanti 		break;
4242c03d07aSLuca Tettamanti 	default:
4252c03d07aSLuca Tettamanti 		what = "unknown";
4262c03d07aSLuca Tettamanti 		break;
4272c03d07aSLuca Tettamanti 	}
4282c03d07aSLuca Tettamanti 
4292c03d07aSLuca Tettamanti 	return what;
4302c03d07aSLuca Tettamanti }
431b9008708SLuca Tettamanti #endif
4322c03d07aSLuca Tettamanti 
4332c03d07aSLuca Tettamanti static void atk_print_sensor(struct atk_data *data, union acpi_object *obj)
4342c03d07aSLuca Tettamanti {
4352c03d07aSLuca Tettamanti #ifdef DEBUG
4362c03d07aSLuca Tettamanti 	struct device *dev = &data->acpi_dev->dev;
4372c03d07aSLuca Tettamanti 	union acpi_object *flags;
4382c03d07aSLuca Tettamanti 	union acpi_object *name;
4392c03d07aSLuca Tettamanti 	union acpi_object *limit1;
4402c03d07aSLuca Tettamanti 	union acpi_object *limit2;
4412c03d07aSLuca Tettamanti 	union acpi_object *enable;
4422c03d07aSLuca Tettamanti 	char const *what;
4432c03d07aSLuca Tettamanti 
4442c03d07aSLuca Tettamanti 	flags = atk_get_pack_member(data, obj, HWMON_PACK_FLAGS);
4452c03d07aSLuca Tettamanti 	name = atk_get_pack_member(data, obj, HWMON_PACK_NAME);
4462c03d07aSLuca Tettamanti 	limit1 = atk_get_pack_member(data, obj, HWMON_PACK_LIMIT1);
4472c03d07aSLuca Tettamanti 	limit2 = atk_get_pack_member(data, obj, HWMON_PACK_LIMIT2);
4482c03d07aSLuca Tettamanti 	enable = atk_get_pack_member(data, obj, HWMON_PACK_ENABLE);
4492c03d07aSLuca Tettamanti 
4502c03d07aSLuca Tettamanti 	what = atk_sensor_type(flags);
4512c03d07aSLuca Tettamanti 
4522c03d07aSLuca Tettamanti 	dev_dbg(dev, "%s: %#llx %s [%llu-%llu] %s\n", what,
4532c03d07aSLuca Tettamanti 			flags->integer.value,
4542c03d07aSLuca Tettamanti 			name->string.pointer,
4552c03d07aSLuca Tettamanti 			limit1->integer.value, limit2->integer.value,
4562c03d07aSLuca Tettamanti 			enable->integer.value ? "enabled" : "disabled");
4572c03d07aSLuca Tettamanti #endif
4582c03d07aSLuca Tettamanti }
4592c03d07aSLuca Tettamanti 
4602c03d07aSLuca Tettamanti static int atk_read_value_old(struct atk_sensor_data *sensor, u64 *value)
4612c03d07aSLuca Tettamanti {
4622c03d07aSLuca Tettamanti 	struct atk_data *data = sensor->data;
4632c03d07aSLuca Tettamanti 	struct device *dev = &data->acpi_dev->dev;
4642c03d07aSLuca Tettamanti 	struct acpi_object_list params;
4652c03d07aSLuca Tettamanti 	union acpi_object id;
4662c03d07aSLuca Tettamanti 	acpi_status status;
4672c03d07aSLuca Tettamanti 	acpi_handle method;
4682c03d07aSLuca Tettamanti 
4692c03d07aSLuca Tettamanti 	switch (sensor->type) {
4702c03d07aSLuca Tettamanti 	case HWMON_TYPE_VOLT:
4712c03d07aSLuca Tettamanti 		method = data->rvlt_handle;
4722c03d07aSLuca Tettamanti 		break;
4732c03d07aSLuca Tettamanti 	case HWMON_TYPE_TEMP:
4742c03d07aSLuca Tettamanti 		method = data->rtmp_handle;
4752c03d07aSLuca Tettamanti 		break;
4762c03d07aSLuca Tettamanti 	case HWMON_TYPE_FAN:
4772c03d07aSLuca Tettamanti 		method = data->rfan_handle;
4782c03d07aSLuca Tettamanti 		break;
4792c03d07aSLuca Tettamanti 	default:
4802c03d07aSLuca Tettamanti 		return -EINVAL;
4812c03d07aSLuca Tettamanti 	}
4822c03d07aSLuca Tettamanti 
4832c03d07aSLuca Tettamanti 	id.type = ACPI_TYPE_INTEGER;
4842c03d07aSLuca Tettamanti 	id.integer.value = sensor->id;
4852c03d07aSLuca Tettamanti 
4862c03d07aSLuca Tettamanti 	params.count = 1;
4872c03d07aSLuca Tettamanti 	params.pointer = &id;
4882c03d07aSLuca Tettamanti 
4892c03d07aSLuca Tettamanti 	status = acpi_evaluate_integer(method, NULL, &params, value);
4902c03d07aSLuca Tettamanti 	if (status != AE_OK) {
4912c03d07aSLuca Tettamanti 		dev_warn(dev, "%s: ACPI exception: %s\n", __func__,
4922c03d07aSLuca Tettamanti 				acpi_format_exception(status));
4932c03d07aSLuca Tettamanti 		return -EIO;
4942c03d07aSLuca Tettamanti 	}
4952c03d07aSLuca Tettamanti 
4962c03d07aSLuca Tettamanti 	return 0;
4972c03d07aSLuca Tettamanti }
4982c03d07aSLuca Tettamanti 
49918e25555SLuca Tettamanti static union acpi_object *atk_ggrp(struct atk_data *data, u16 mux)
50018e25555SLuca Tettamanti {
50118e25555SLuca Tettamanti 	struct device *dev = &data->acpi_dev->dev;
50218e25555SLuca Tettamanti 	struct acpi_buffer buf;
50318e25555SLuca Tettamanti 	acpi_status ret;
50418e25555SLuca Tettamanti 	struct acpi_object_list params;
50518e25555SLuca Tettamanti 	union acpi_object id;
50618e25555SLuca Tettamanti 	union acpi_object *pack;
50718e25555SLuca Tettamanti 
50818e25555SLuca Tettamanti 	id.type = ACPI_TYPE_INTEGER;
50918e25555SLuca Tettamanti 	id.integer.value = mux;
51018e25555SLuca Tettamanti 	params.count = 1;
51118e25555SLuca Tettamanti 	params.pointer = &id;
51218e25555SLuca Tettamanti 
51318e25555SLuca Tettamanti 	buf.length = ACPI_ALLOCATE_BUFFER;
51418e25555SLuca Tettamanti 	ret = acpi_evaluate_object(data->enumerate_handle, NULL, &params, &buf);
51518e25555SLuca Tettamanti 	if (ret != AE_OK) {
51618e25555SLuca Tettamanti 		dev_err(dev, "GGRP[%#x] ACPI exception: %s\n", mux,
51718e25555SLuca Tettamanti 				acpi_format_exception(ret));
51818e25555SLuca Tettamanti 		return ERR_PTR(-EIO);
51918e25555SLuca Tettamanti 	}
52018e25555SLuca Tettamanti 	pack = buf.pointer;
52118e25555SLuca Tettamanti 	if (pack->type != ACPI_TYPE_PACKAGE) {
52218e25555SLuca Tettamanti 		/* Execution was successful, but the id was not found */
52318e25555SLuca Tettamanti 		ACPI_FREE(pack);
52418e25555SLuca Tettamanti 		return ERR_PTR(-ENOENT);
52518e25555SLuca Tettamanti 	}
52618e25555SLuca Tettamanti 
52718e25555SLuca Tettamanti 	if (pack->package.count < 1) {
52818e25555SLuca Tettamanti 		dev_err(dev, "GGRP[%#x] package is too small\n", mux);
52918e25555SLuca Tettamanti 		ACPI_FREE(pack);
53018e25555SLuca Tettamanti 		return ERR_PTR(-EIO);
53118e25555SLuca Tettamanti 	}
53218e25555SLuca Tettamanti 	return pack;
53318e25555SLuca Tettamanti }
53418e25555SLuca Tettamanti 
53518e25555SLuca Tettamanti static union acpi_object *atk_gitm(struct atk_data *data, u64 id)
53618e25555SLuca Tettamanti {
53718e25555SLuca Tettamanti 	struct device *dev = &data->acpi_dev->dev;
53818e25555SLuca Tettamanti 	struct atk_acpi_input_buf buf;
53918e25555SLuca Tettamanti 	union acpi_object tmp;
54018e25555SLuca Tettamanti 	struct acpi_object_list params;
54118e25555SLuca Tettamanti 	struct acpi_buffer ret;
54218e25555SLuca Tettamanti 	union acpi_object *obj;
54318e25555SLuca Tettamanti 	acpi_status status;
54418e25555SLuca Tettamanti 
54518e25555SLuca Tettamanti 	buf.id = id;
54618e25555SLuca Tettamanti 	buf.param1 = 0;
54718e25555SLuca Tettamanti 	buf.param2 = 0;
54818e25555SLuca Tettamanti 
54918e25555SLuca Tettamanti 	tmp.type = ACPI_TYPE_BUFFER;
55018e25555SLuca Tettamanti 	tmp.buffer.pointer = (u8 *)&buf;
55118e25555SLuca Tettamanti 	tmp.buffer.length = sizeof(buf);
55218e25555SLuca Tettamanti 
55318e25555SLuca Tettamanti 	params.count = 1;
55418e25555SLuca Tettamanti 	params.pointer = (void *)&tmp;
55518e25555SLuca Tettamanti 
55618e25555SLuca Tettamanti 	ret.length = ACPI_ALLOCATE_BUFFER;
55718e25555SLuca Tettamanti 	status = acpi_evaluate_object_typed(data->read_handle, NULL, &params,
55818e25555SLuca Tettamanti 			&ret, ACPI_TYPE_BUFFER);
55918e25555SLuca Tettamanti 	if (status != AE_OK) {
56018e25555SLuca Tettamanti 		dev_warn(dev, "GITM[%#llx] ACPI exception: %s\n", id,
56118e25555SLuca Tettamanti 				acpi_format_exception(status));
56218e25555SLuca Tettamanti 		return ERR_PTR(-EIO);
56318e25555SLuca Tettamanti 	}
56418e25555SLuca Tettamanti 	obj = ret.pointer;
56518e25555SLuca Tettamanti 
56618e25555SLuca Tettamanti 	/* Sanity check */
56718e25555SLuca Tettamanti 	if (obj->buffer.length < 8) {
56818e25555SLuca Tettamanti 		dev_warn(dev, "Unexpected ASBF length: %u\n",
56918e25555SLuca Tettamanti 				obj->buffer.length);
57018e25555SLuca Tettamanti 		ACPI_FREE(obj);
57118e25555SLuca Tettamanti 		return ERR_PTR(-EIO);
57218e25555SLuca Tettamanti 	}
57318e25555SLuca Tettamanti 	return obj;
57418e25555SLuca Tettamanti }
57518e25555SLuca Tettamanti 
5769e6eba61SLuca Tettamanti static union acpi_object *atk_sitm(struct atk_data *data,
5779e6eba61SLuca Tettamanti 		struct atk_acpi_input_buf *buf)
5789e6eba61SLuca Tettamanti {
5799e6eba61SLuca Tettamanti 	struct device *dev = &data->acpi_dev->dev;
5809e6eba61SLuca Tettamanti 	struct acpi_object_list params;
5819e6eba61SLuca Tettamanti 	union acpi_object tmp;
5829e6eba61SLuca Tettamanti 	struct acpi_buffer ret;
5839e6eba61SLuca Tettamanti 	union acpi_object *obj;
5849e6eba61SLuca Tettamanti 	acpi_status status;
5859e6eba61SLuca Tettamanti 
5869e6eba61SLuca Tettamanti 	tmp.type = ACPI_TYPE_BUFFER;
5879e6eba61SLuca Tettamanti 	tmp.buffer.pointer = (u8 *)buf;
5889e6eba61SLuca Tettamanti 	tmp.buffer.length = sizeof(*buf);
5899e6eba61SLuca Tettamanti 
5909e6eba61SLuca Tettamanti 	params.count = 1;
5919e6eba61SLuca Tettamanti 	params.pointer = &tmp;
5929e6eba61SLuca Tettamanti 
5939e6eba61SLuca Tettamanti 	ret.length = ACPI_ALLOCATE_BUFFER;
5949e6eba61SLuca Tettamanti 	status = acpi_evaluate_object_typed(data->write_handle, NULL, &params,
5959e6eba61SLuca Tettamanti 			&ret, ACPI_TYPE_BUFFER);
5969e6eba61SLuca Tettamanti 	if (status != AE_OK) {
5979e6eba61SLuca Tettamanti 		dev_warn(dev, "SITM[%#x] ACPI exception: %s\n", buf->id,
5989e6eba61SLuca Tettamanti 				acpi_format_exception(status));
5999e6eba61SLuca Tettamanti 		return ERR_PTR(-EIO);
6009e6eba61SLuca Tettamanti 	}
6019e6eba61SLuca Tettamanti 	obj = ret.pointer;
6029e6eba61SLuca Tettamanti 
6039e6eba61SLuca Tettamanti 	/* Sanity check */
6049e6eba61SLuca Tettamanti 	if (obj->buffer.length < 8) {
6059e6eba61SLuca Tettamanti 		dev_warn(dev, "Unexpected ASBF length: %u\n",
6069e6eba61SLuca Tettamanti 				obj->buffer.length);
6079e6eba61SLuca Tettamanti 		ACPI_FREE(obj);
6089e6eba61SLuca Tettamanti 		return ERR_PTR(-EIO);
6099e6eba61SLuca Tettamanti 	}
6109e6eba61SLuca Tettamanti 	return obj;
6119e6eba61SLuca Tettamanti }
6129e6eba61SLuca Tettamanti 
6132c03d07aSLuca Tettamanti static int atk_read_value_new(struct atk_sensor_data *sensor, u64 *value)
6142c03d07aSLuca Tettamanti {
6152c03d07aSLuca Tettamanti 	struct atk_data *data = sensor->data;
6162c03d07aSLuca Tettamanti 	struct device *dev = &data->acpi_dev->dev;
61718e25555SLuca Tettamanti 	union acpi_object *obj;
61818e25555SLuca Tettamanti 	struct atk_acpi_ret_buffer *buf;
61918e25555SLuca Tettamanti 	int err = 0;
6202c03d07aSLuca Tettamanti 
62118e25555SLuca Tettamanti 	obj = atk_gitm(data, sensor->id);
62218e25555SLuca Tettamanti 	if (IS_ERR(obj))
62318e25555SLuca Tettamanti 		return PTR_ERR(obj);
6242c03d07aSLuca Tettamanti 
62518e25555SLuca Tettamanti 	buf = (struct atk_acpi_ret_buffer *)obj->buffer.pointer;
62618e25555SLuca Tettamanti 	if (buf->flags == 0) {
62775bdc936SGuenter Roeck 		/*
62875bdc936SGuenter Roeck 		 * The reading is not valid, possible causes:
6292c03d07aSLuca Tettamanti 		 * - sensor failure
6302c03d07aSLuca Tettamanti 		 * - enumeration was FUBAR (and we didn't notice)
6312c03d07aSLuca Tettamanti 		 */
63218e25555SLuca Tettamanti 		dev_warn(dev, "Read failed, sensor = %#llx\n", sensor->id);
63318e25555SLuca Tettamanti 		err = -EIO;
63418e25555SLuca Tettamanti 		goto out;
6352c03d07aSLuca Tettamanti 	}
6362c03d07aSLuca Tettamanti 
63718e25555SLuca Tettamanti 	*value = buf->value;
63818e25555SLuca Tettamanti out:
63918e25555SLuca Tettamanti 	ACPI_FREE(obj);
64018e25555SLuca Tettamanti 	return err;
6412c03d07aSLuca Tettamanti }
6422c03d07aSLuca Tettamanti 
6432c03d07aSLuca Tettamanti static int atk_read_value(struct atk_sensor_data *sensor, u64 *value)
6442c03d07aSLuca Tettamanti {
6452c03d07aSLuca Tettamanti 	int err;
6462c03d07aSLuca Tettamanti 
6472c03d07aSLuca Tettamanti 	if (!sensor->is_valid ||
6482c03d07aSLuca Tettamanti 	    time_after(jiffies, sensor->last_updated + CACHE_TIME)) {
6492c03d07aSLuca Tettamanti 		if (sensor->data->old_interface)
6502c03d07aSLuca Tettamanti 			err = atk_read_value_old(sensor, value);
6512c03d07aSLuca Tettamanti 		else
6522c03d07aSLuca Tettamanti 			err = atk_read_value_new(sensor, value);
6532c03d07aSLuca Tettamanti 
6542c03d07aSLuca Tettamanti 		sensor->is_valid = true;
6552c03d07aSLuca Tettamanti 		sensor->last_updated = jiffies;
6562c03d07aSLuca Tettamanti 		sensor->cached_value = *value;
6572c03d07aSLuca Tettamanti 	} else {
6582c03d07aSLuca Tettamanti 		*value = sensor->cached_value;
6592c03d07aSLuca Tettamanti 		err = 0;
6602c03d07aSLuca Tettamanti 	}
6612c03d07aSLuca Tettamanti 
6622c03d07aSLuca Tettamanti 	return err;
6632c03d07aSLuca Tettamanti }
6642c03d07aSLuca Tettamanti 
6657e5eab11SLuca Tettamanti #ifdef CONFIG_DEBUG_FS
6667e5eab11SLuca Tettamanti static int atk_debugfs_gitm_get(void *p, u64 *val)
6677e5eab11SLuca Tettamanti {
6687e5eab11SLuca Tettamanti 	struct atk_data *data = p;
6697e5eab11SLuca Tettamanti 	union acpi_object *ret;
6707e5eab11SLuca Tettamanti 	struct atk_acpi_ret_buffer *buf;
6717e5eab11SLuca Tettamanti 	int err = 0;
6727e5eab11SLuca Tettamanti 
6737e5eab11SLuca Tettamanti 	if (!data->read_handle)
6747e5eab11SLuca Tettamanti 		return -ENODEV;
6757e5eab11SLuca Tettamanti 
6767e5eab11SLuca Tettamanti 	if (!data->debugfs.id)
6777e5eab11SLuca Tettamanti 		return -EINVAL;
6787e5eab11SLuca Tettamanti 
6797e5eab11SLuca Tettamanti 	ret = atk_gitm(data, data->debugfs.id);
6807e5eab11SLuca Tettamanti 	if (IS_ERR(ret))
6817e5eab11SLuca Tettamanti 		return PTR_ERR(ret);
6827e5eab11SLuca Tettamanti 
6837e5eab11SLuca Tettamanti 	buf = (struct atk_acpi_ret_buffer *)ret->buffer.pointer;
6847e5eab11SLuca Tettamanti 	if (buf->flags)
6857e5eab11SLuca Tettamanti 		*val = buf->value;
6867e5eab11SLuca Tettamanti 	else
6877e5eab11SLuca Tettamanti 		err = -EIO;
6887e5eab11SLuca Tettamanti 
6890b8e77f1SLuca Tettamanti 	ACPI_FREE(ret);
6907e5eab11SLuca Tettamanti 	return err;
6917e5eab11SLuca Tettamanti }
6927e5eab11SLuca Tettamanti 
6937e5eab11SLuca Tettamanti DEFINE_SIMPLE_ATTRIBUTE(atk_debugfs_gitm,
6947e5eab11SLuca Tettamanti 			atk_debugfs_gitm_get,
6957e5eab11SLuca Tettamanti 			NULL,
6967e5eab11SLuca Tettamanti 			"0x%08llx\n")
6977e5eab11SLuca Tettamanti 
6987e5eab11SLuca Tettamanti static int atk_acpi_print(char *buf, size_t sz, union acpi_object *obj)
6997e5eab11SLuca Tettamanti {
7007e5eab11SLuca Tettamanti 	int ret = 0;
7017e5eab11SLuca Tettamanti 
7027e5eab11SLuca Tettamanti 	switch (obj->type) {
7037e5eab11SLuca Tettamanti 	case ACPI_TYPE_INTEGER:
7047e5eab11SLuca Tettamanti 		ret = snprintf(buf, sz, "0x%08llx\n", obj->integer.value);
7057e5eab11SLuca Tettamanti 		break;
7067e5eab11SLuca Tettamanti 	case ACPI_TYPE_STRING:
7077e5eab11SLuca Tettamanti 		ret = snprintf(buf, sz, "%s\n", obj->string.pointer);
7087e5eab11SLuca Tettamanti 		break;
7097e5eab11SLuca Tettamanti 	}
7107e5eab11SLuca Tettamanti 
7117e5eab11SLuca Tettamanti 	return ret;
7127e5eab11SLuca Tettamanti }
7137e5eab11SLuca Tettamanti 
7147e5eab11SLuca Tettamanti static void atk_pack_print(char *buf, size_t sz, union acpi_object *pack)
7157e5eab11SLuca Tettamanti {
7167e5eab11SLuca Tettamanti 	int ret;
7177e5eab11SLuca Tettamanti 	int i;
7187e5eab11SLuca Tettamanti 
7197e5eab11SLuca Tettamanti 	for (i = 0; i < pack->package.count; i++) {
7207e5eab11SLuca Tettamanti 		union acpi_object *obj = &pack->package.elements[i];
7217e5eab11SLuca Tettamanti 
7227e5eab11SLuca Tettamanti 		ret = atk_acpi_print(buf, sz, obj);
7237e5eab11SLuca Tettamanti 		if (ret >= sz)
7247e5eab11SLuca Tettamanti 			break;
7257e5eab11SLuca Tettamanti 		buf += ret;
7267e5eab11SLuca Tettamanti 		sz -= ret;
7277e5eab11SLuca Tettamanti 	}
7287e5eab11SLuca Tettamanti }
7297e5eab11SLuca Tettamanti 
7307e5eab11SLuca Tettamanti static int atk_debugfs_ggrp_open(struct inode *inode, struct file *file)
7317e5eab11SLuca Tettamanti {
7327e5eab11SLuca Tettamanti 	struct atk_data *data = inode->i_private;
7337e5eab11SLuca Tettamanti 	char *buf = NULL;
7347e5eab11SLuca Tettamanti 	union acpi_object *ret;
7357e5eab11SLuca Tettamanti 	u8 cls;
7367e5eab11SLuca Tettamanti 	int i;
7377e5eab11SLuca Tettamanti 
7387e5eab11SLuca Tettamanti 	if (!data->enumerate_handle)
7397e5eab11SLuca Tettamanti 		return -ENODEV;
7407e5eab11SLuca Tettamanti 	if (!data->debugfs.id)
7417e5eab11SLuca Tettamanti 		return -EINVAL;
7427e5eab11SLuca Tettamanti 
7437e5eab11SLuca Tettamanti 	cls = (data->debugfs.id & 0xff000000) >> 24;
7447e5eab11SLuca Tettamanti 	ret = atk_ggrp(data, cls);
7457e5eab11SLuca Tettamanti 	if (IS_ERR(ret))
7467e5eab11SLuca Tettamanti 		return PTR_ERR(ret);
7477e5eab11SLuca Tettamanti 
7487e5eab11SLuca Tettamanti 	for (i = 0; i < ret->package.count; i++) {
7497e5eab11SLuca Tettamanti 		union acpi_object *pack = &ret->package.elements[i];
7507e5eab11SLuca Tettamanti 		union acpi_object *id;
7517e5eab11SLuca Tettamanti 
7527e5eab11SLuca Tettamanti 		if (pack->type != ACPI_TYPE_PACKAGE)
7537e5eab11SLuca Tettamanti 			continue;
7547e5eab11SLuca Tettamanti 		if (!pack->package.count)
7557e5eab11SLuca Tettamanti 			continue;
7567e5eab11SLuca Tettamanti 		id = &pack->package.elements[0];
7577e5eab11SLuca Tettamanti 		if (id->integer.value == data->debugfs.id) {
7587e5eab11SLuca Tettamanti 			/* Print the package */
7597e5eab11SLuca Tettamanti 			buf = kzalloc(512, GFP_KERNEL);
7607e5eab11SLuca Tettamanti 			if (!buf) {
7617e5eab11SLuca Tettamanti 				ACPI_FREE(ret);
7627e5eab11SLuca Tettamanti 				return -ENOMEM;
7637e5eab11SLuca Tettamanti 			}
7647e5eab11SLuca Tettamanti 			atk_pack_print(buf, 512, pack);
7657e5eab11SLuca Tettamanti 			break;
7667e5eab11SLuca Tettamanti 		}
7677e5eab11SLuca Tettamanti 	}
7687e5eab11SLuca Tettamanti 	ACPI_FREE(ret);
7697e5eab11SLuca Tettamanti 
7707e5eab11SLuca Tettamanti 	if (!buf)
7717e5eab11SLuca Tettamanti 		return -EINVAL;
7727e5eab11SLuca Tettamanti 
7737e5eab11SLuca Tettamanti 	file->private_data = buf;
7747e5eab11SLuca Tettamanti 
7757e5eab11SLuca Tettamanti 	return nonseekable_open(inode, file);
7767e5eab11SLuca Tettamanti }
7777e5eab11SLuca Tettamanti 
7787e5eab11SLuca Tettamanti static ssize_t atk_debugfs_ggrp_read(struct file *file, char __user *buf,
7797e5eab11SLuca Tettamanti 		size_t count, loff_t *pos)
7807e5eab11SLuca Tettamanti {
7817e5eab11SLuca Tettamanti 	char *str = file->private_data;
7827e5eab11SLuca Tettamanti 	size_t len = strlen(str);
7837e5eab11SLuca Tettamanti 
7847e5eab11SLuca Tettamanti 	return simple_read_from_buffer(buf, count, pos, str, len);
7857e5eab11SLuca Tettamanti }
7867e5eab11SLuca Tettamanti 
7877e5eab11SLuca Tettamanti static int atk_debugfs_ggrp_release(struct inode *inode, struct file *file)
7887e5eab11SLuca Tettamanti {
7897e5eab11SLuca Tettamanti 	kfree(file->private_data);
7907e5eab11SLuca Tettamanti 	return 0;
7917e5eab11SLuca Tettamanti }
7927e5eab11SLuca Tettamanti 
7937e5eab11SLuca Tettamanti static const struct file_operations atk_debugfs_ggrp_fops = {
7947e5eab11SLuca Tettamanti 	.read		= atk_debugfs_ggrp_read,
7957e5eab11SLuca Tettamanti 	.open		= atk_debugfs_ggrp_open,
7967e5eab11SLuca Tettamanti 	.release	= atk_debugfs_ggrp_release,
7976038f373SArnd Bergmann 	.llseek		= no_llseek,
7987e5eab11SLuca Tettamanti };
7997e5eab11SLuca Tettamanti 
8007e5eab11SLuca Tettamanti static void atk_debugfs_init(struct atk_data *data)
8017e5eab11SLuca Tettamanti {
8027e5eab11SLuca Tettamanti 	struct dentry *d;
8037e5eab11SLuca Tettamanti 	struct dentry *f;
8047e5eab11SLuca Tettamanti 
8057e5eab11SLuca Tettamanti 	data->debugfs.id = 0;
8067e5eab11SLuca Tettamanti 
8077e5eab11SLuca Tettamanti 	d = debugfs_create_dir("asus_atk0110", NULL);
8087e5eab11SLuca Tettamanti 	if (!d || IS_ERR(d))
8097e5eab11SLuca Tettamanti 		return;
8107e5eab11SLuca Tettamanti 
8117e5eab11SLuca Tettamanti 	f = debugfs_create_x32("id", S_IRUSR | S_IWUSR, d, &data->debugfs.id);
8127e5eab11SLuca Tettamanti 	if (!f || IS_ERR(f))
8137e5eab11SLuca Tettamanti 		goto cleanup;
8147e5eab11SLuca Tettamanti 
8157e5eab11SLuca Tettamanti 	f = debugfs_create_file("gitm", S_IRUSR, d, data,
8167e5eab11SLuca Tettamanti 			&atk_debugfs_gitm);
8177e5eab11SLuca Tettamanti 	if (!f || IS_ERR(f))
8187e5eab11SLuca Tettamanti 		goto cleanup;
8197e5eab11SLuca Tettamanti 
8207e5eab11SLuca Tettamanti 	f = debugfs_create_file("ggrp", S_IRUSR, d, data,
8217e5eab11SLuca Tettamanti 			&atk_debugfs_ggrp_fops);
8227e5eab11SLuca Tettamanti 	if (!f || IS_ERR(f))
8237e5eab11SLuca Tettamanti 		goto cleanup;
8247e5eab11SLuca Tettamanti 
8257e5eab11SLuca Tettamanti 	data->debugfs.root = d;
8267e5eab11SLuca Tettamanti 
8277e5eab11SLuca Tettamanti 	return;
8287e5eab11SLuca Tettamanti cleanup:
8297e5eab11SLuca Tettamanti 	debugfs_remove_recursive(d);
8307e5eab11SLuca Tettamanti }
8317e5eab11SLuca Tettamanti 
8327e5eab11SLuca Tettamanti static void atk_debugfs_cleanup(struct atk_data *data)
8337e5eab11SLuca Tettamanti {
8347e5eab11SLuca Tettamanti 	debugfs_remove_recursive(data->debugfs.root);
8357e5eab11SLuca Tettamanti }
8367e5eab11SLuca Tettamanti 
8377e5eab11SLuca Tettamanti #else /* CONFIG_DEBUG_FS */
8387e5eab11SLuca Tettamanti 
8397e5eab11SLuca Tettamanti static void atk_debugfs_init(struct atk_data *data)
8407e5eab11SLuca Tettamanti {
8417e5eab11SLuca Tettamanti }
8427e5eab11SLuca Tettamanti 
8437e5eab11SLuca Tettamanti static void atk_debugfs_cleanup(struct atk_data *data)
8447e5eab11SLuca Tettamanti {
8457e5eab11SLuca Tettamanti }
8467e5eab11SLuca Tettamanti #endif
8477e5eab11SLuca Tettamanti 
8482c03d07aSLuca Tettamanti static int atk_add_sensor(struct atk_data *data, union acpi_object *obj)
8492c03d07aSLuca Tettamanti {
8502c03d07aSLuca Tettamanti 	struct device *dev = &data->acpi_dev->dev;
8512c03d07aSLuca Tettamanti 	union acpi_object *flags;
8522c03d07aSLuca Tettamanti 	union acpi_object *name;
8532c03d07aSLuca Tettamanti 	union acpi_object *limit1;
8542c03d07aSLuca Tettamanti 	union acpi_object *limit2;
8552c03d07aSLuca Tettamanti 	union acpi_object *enable;
8562c03d07aSLuca Tettamanti 	struct atk_sensor_data *sensor;
8572c03d07aSLuca Tettamanti 	char const *base_name;
8582c03d07aSLuca Tettamanti 	char const *limit1_name;
8592c03d07aSLuca Tettamanti 	char const *limit2_name;
8602c03d07aSLuca Tettamanti 	u64 type;
8612c03d07aSLuca Tettamanti 	int err;
8622c03d07aSLuca Tettamanti 	int *num;
8632c03d07aSLuca Tettamanti 	int start;
8642c03d07aSLuca Tettamanti 
8652c03d07aSLuca Tettamanti 	if (obj->type != ACPI_TYPE_PACKAGE) {
8662c03d07aSLuca Tettamanti 		/* wft is this? */
8672c03d07aSLuca Tettamanti 		dev_warn(dev, "Unknown type for ACPI object: (%d)\n",
8682c03d07aSLuca Tettamanti 				obj->type);
8692c03d07aSLuca Tettamanti 		return -EINVAL;
8702c03d07aSLuca Tettamanti 	}
8712c03d07aSLuca Tettamanti 
8722c03d07aSLuca Tettamanti 	err = validate_hwmon_pack(data, obj);
8732c03d07aSLuca Tettamanti 	if (err)
8742c03d07aSLuca Tettamanti 		return err;
8752c03d07aSLuca Tettamanti 
8762c03d07aSLuca Tettamanti 	/* Ok, we have a valid hwmon package */
8772c03d07aSLuca Tettamanti 	type = atk_get_pack_member(data, obj, HWMON_PACK_FLAGS)->integer.value
8782c03d07aSLuca Tettamanti 	       & ATK_TYPE_MASK;
8792c03d07aSLuca Tettamanti 
8802c03d07aSLuca Tettamanti 	switch (type) {
8812c03d07aSLuca Tettamanti 	case HWMON_TYPE_VOLT:
8822c03d07aSLuca Tettamanti 		base_name = "in";
8832c03d07aSLuca Tettamanti 		limit1_name = "min";
8842c03d07aSLuca Tettamanti 		limit2_name = "max";
8852c03d07aSLuca Tettamanti 		num = &data->voltage_count;
8862c03d07aSLuca Tettamanti 		start = 0;
8872c03d07aSLuca Tettamanti 		break;
8882c03d07aSLuca Tettamanti 	case HWMON_TYPE_TEMP:
8892c03d07aSLuca Tettamanti 		base_name = "temp";
8902c03d07aSLuca Tettamanti 		limit1_name = "max";
8912c03d07aSLuca Tettamanti 		limit2_name = "crit";
8922c03d07aSLuca Tettamanti 		num = &data->temperature_count;
8932c03d07aSLuca Tettamanti 		start = 1;
8942c03d07aSLuca Tettamanti 		break;
8952c03d07aSLuca Tettamanti 	case HWMON_TYPE_FAN:
8962c03d07aSLuca Tettamanti 		base_name = "fan";
8972c03d07aSLuca Tettamanti 		limit1_name = "min";
8982c03d07aSLuca Tettamanti 		limit2_name = "max";
8992c03d07aSLuca Tettamanti 		num = &data->fan_count;
9002c03d07aSLuca Tettamanti 		start = 1;
9012c03d07aSLuca Tettamanti 		break;
9022c03d07aSLuca Tettamanti 	default:
9032c03d07aSLuca Tettamanti 		dev_warn(dev, "Unknown sensor type: %#llx\n", type);
9042c03d07aSLuca Tettamanti 		return -EINVAL;
9052c03d07aSLuca Tettamanti 	}
9062c03d07aSLuca Tettamanti 
9072c03d07aSLuca Tettamanti 	enable = atk_get_pack_member(data, obj, HWMON_PACK_ENABLE);
9082c03d07aSLuca Tettamanti 	if (!enable->integer.value)
9092c03d07aSLuca Tettamanti 		/* sensor is disabled */
9102c03d07aSLuca Tettamanti 		return 0;
9112c03d07aSLuca Tettamanti 
9122c03d07aSLuca Tettamanti 	flags = atk_get_pack_member(data, obj, HWMON_PACK_FLAGS);
9132c03d07aSLuca Tettamanti 	name = atk_get_pack_member(data, obj, HWMON_PACK_NAME);
9142c03d07aSLuca Tettamanti 	limit1 = atk_get_pack_member(data, obj, HWMON_PACK_LIMIT1);
9152c03d07aSLuca Tettamanti 	limit2 = atk_get_pack_member(data, obj, HWMON_PACK_LIMIT2);
9162c03d07aSLuca Tettamanti 
9172c03d07aSLuca Tettamanti 	sensor = kzalloc(sizeof(*sensor), GFP_KERNEL);
9182c03d07aSLuca Tettamanti 	if (!sensor)
9192c03d07aSLuca Tettamanti 		return -ENOMEM;
9202c03d07aSLuca Tettamanti 
9212c03d07aSLuca Tettamanti 	sensor->acpi_name = kstrdup(name->string.pointer, GFP_KERNEL);
9222c03d07aSLuca Tettamanti 	if (!sensor->acpi_name) {
9232c03d07aSLuca Tettamanti 		err = -ENOMEM;
9242c03d07aSLuca Tettamanti 		goto out;
9252c03d07aSLuca Tettamanti 	}
9262c03d07aSLuca Tettamanti 
9272c03d07aSLuca Tettamanti 	INIT_LIST_HEAD(&sensor->list);
9282c03d07aSLuca Tettamanti 	sensor->type = type;
9292c03d07aSLuca Tettamanti 	sensor->data = data;
9302c03d07aSLuca Tettamanti 	sensor->id = flags->integer.value;
9312c03d07aSLuca Tettamanti 	sensor->limit1 = limit1->integer.value;
9328d282497SLuca Tettamanti 	if (data->old_interface)
9332c03d07aSLuca Tettamanti 		sensor->limit2 = limit2->integer.value;
9348d282497SLuca Tettamanti 	else
9358d282497SLuca Tettamanti 		/* The upper limit is expressed as delta from lower limit */
9368d282497SLuca Tettamanti 		sensor->limit2 = sensor->limit1 + limit2->integer.value;
9372c03d07aSLuca Tettamanti 
9382c03d07aSLuca Tettamanti 	snprintf(sensor->input_attr_name, ATTR_NAME_SIZE,
9392c03d07aSLuca Tettamanti 			"%s%d_input", base_name, start + *num);
9402c03d07aSLuca Tettamanti 	atk_init_attribute(&sensor->input_attr,
9412c03d07aSLuca Tettamanti 			sensor->input_attr_name,
9422c03d07aSLuca Tettamanti 			atk_input_show);
9432c03d07aSLuca Tettamanti 
9442c03d07aSLuca Tettamanti 	snprintf(sensor->label_attr_name, ATTR_NAME_SIZE,
9452c03d07aSLuca Tettamanti 			"%s%d_label", base_name, start + *num);
9462c03d07aSLuca Tettamanti 	atk_init_attribute(&sensor->label_attr,
9472c03d07aSLuca Tettamanti 			sensor->label_attr_name,
9482c03d07aSLuca Tettamanti 			atk_label_show);
9492c03d07aSLuca Tettamanti 
9502c03d07aSLuca Tettamanti 	snprintf(sensor->limit1_attr_name, ATTR_NAME_SIZE,
9512c03d07aSLuca Tettamanti 			"%s%d_%s", base_name, start + *num, limit1_name);
9522c03d07aSLuca Tettamanti 	atk_init_attribute(&sensor->limit1_attr,
9532c03d07aSLuca Tettamanti 			sensor->limit1_attr_name,
9542c03d07aSLuca Tettamanti 			atk_limit1_show);
9552c03d07aSLuca Tettamanti 
9562c03d07aSLuca Tettamanti 	snprintf(sensor->limit2_attr_name, ATTR_NAME_SIZE,
9572c03d07aSLuca Tettamanti 			"%s%d_%s", base_name, start + *num, limit2_name);
9582c03d07aSLuca Tettamanti 	atk_init_attribute(&sensor->limit2_attr,
9592c03d07aSLuca Tettamanti 			sensor->limit2_attr_name,
9602c03d07aSLuca Tettamanti 			atk_limit2_show);
9612c03d07aSLuca Tettamanti 
9622c03d07aSLuca Tettamanti 	list_add(&sensor->list, &data->sensor_list);
9632c03d07aSLuca Tettamanti 	(*num)++;
9642c03d07aSLuca Tettamanti 
9652c03d07aSLuca Tettamanti 	return 1;
9662c03d07aSLuca Tettamanti out:
9672c03d07aSLuca Tettamanti 	kfree(sensor);
9682c03d07aSLuca Tettamanti 	return err;
9692c03d07aSLuca Tettamanti }
9702c03d07aSLuca Tettamanti 
9712c03d07aSLuca Tettamanti static int atk_enumerate_old_hwmon(struct atk_data *data)
9722c03d07aSLuca Tettamanti {
9732c03d07aSLuca Tettamanti 	struct device *dev = &data->acpi_dev->dev;
9742c03d07aSLuca Tettamanti 	struct acpi_buffer buf;
9752c03d07aSLuca Tettamanti 	union acpi_object *pack;
9762c03d07aSLuca Tettamanti 	acpi_status status;
9772c03d07aSLuca Tettamanti 	int i, ret;
9782c03d07aSLuca Tettamanti 	int count = 0;
9792c03d07aSLuca Tettamanti 
9802c03d07aSLuca Tettamanti 	/* Voltages */
9812c03d07aSLuca Tettamanti 	buf.length = ACPI_ALLOCATE_BUFFER;
9822c03d07aSLuca Tettamanti 	status = acpi_evaluate_object_typed(data->atk_handle,
9832c03d07aSLuca Tettamanti 			METHOD_OLD_ENUM_VLT, NULL, &buf, ACPI_TYPE_PACKAGE);
9842c03d07aSLuca Tettamanti 	if (status != AE_OK) {
9852c03d07aSLuca Tettamanti 		dev_warn(dev, METHOD_OLD_ENUM_VLT ": ACPI exception: %s\n",
9862c03d07aSLuca Tettamanti 				acpi_format_exception(status));
9872c03d07aSLuca Tettamanti 
9882c03d07aSLuca Tettamanti 		return -ENODEV;
9892c03d07aSLuca Tettamanti 	}
9902c03d07aSLuca Tettamanti 
9912c03d07aSLuca Tettamanti 	pack = buf.pointer;
9922c03d07aSLuca Tettamanti 	for (i = 1; i < pack->package.count; i++) {
9932c03d07aSLuca Tettamanti 		union acpi_object *obj = &pack->package.elements[i];
9942c03d07aSLuca Tettamanti 
9952c03d07aSLuca Tettamanti 		ret = atk_add_sensor(data, obj);
9962c03d07aSLuca Tettamanti 		if (ret > 0)
9972c03d07aSLuca Tettamanti 			count++;
9982c03d07aSLuca Tettamanti 	}
9992c03d07aSLuca Tettamanti 	ACPI_FREE(buf.pointer);
10002c03d07aSLuca Tettamanti 
10012c03d07aSLuca Tettamanti 	/* Temperatures */
10022c03d07aSLuca Tettamanti 	buf.length = ACPI_ALLOCATE_BUFFER;
10032c03d07aSLuca Tettamanti 	status = acpi_evaluate_object_typed(data->atk_handle,
10042c03d07aSLuca Tettamanti 			METHOD_OLD_ENUM_TMP, NULL, &buf, ACPI_TYPE_PACKAGE);
10052c03d07aSLuca Tettamanti 	if (status != AE_OK) {
10062c03d07aSLuca Tettamanti 		dev_warn(dev, METHOD_OLD_ENUM_TMP ": ACPI exception: %s\n",
10072c03d07aSLuca Tettamanti 				acpi_format_exception(status));
10082c03d07aSLuca Tettamanti 
10092c03d07aSLuca Tettamanti 		ret = -ENODEV;
10102c03d07aSLuca Tettamanti 		goto cleanup;
10112c03d07aSLuca Tettamanti 	}
10122c03d07aSLuca Tettamanti 
10132c03d07aSLuca Tettamanti 	pack = buf.pointer;
10142c03d07aSLuca Tettamanti 	for (i = 1; i < pack->package.count; i++) {
10152c03d07aSLuca Tettamanti 		union acpi_object *obj = &pack->package.elements[i];
10162c03d07aSLuca Tettamanti 
10172c03d07aSLuca Tettamanti 		ret = atk_add_sensor(data, obj);
10182c03d07aSLuca Tettamanti 		if (ret > 0)
10192c03d07aSLuca Tettamanti 			count++;
10202c03d07aSLuca Tettamanti 	}
10212c03d07aSLuca Tettamanti 	ACPI_FREE(buf.pointer);
10222c03d07aSLuca Tettamanti 
10232c03d07aSLuca Tettamanti 	/* Fans */
10242c03d07aSLuca Tettamanti 	buf.length = ACPI_ALLOCATE_BUFFER;
10252c03d07aSLuca Tettamanti 	status = acpi_evaluate_object_typed(data->atk_handle,
10262c03d07aSLuca Tettamanti 			METHOD_OLD_ENUM_FAN, NULL, &buf, ACPI_TYPE_PACKAGE);
10272c03d07aSLuca Tettamanti 	if (status != AE_OK) {
10282c03d07aSLuca Tettamanti 		dev_warn(dev, METHOD_OLD_ENUM_FAN ": ACPI exception: %s\n",
10292c03d07aSLuca Tettamanti 				acpi_format_exception(status));
10302c03d07aSLuca Tettamanti 
10312c03d07aSLuca Tettamanti 		ret = -ENODEV;
10322c03d07aSLuca Tettamanti 		goto cleanup;
10332c03d07aSLuca Tettamanti 	}
10342c03d07aSLuca Tettamanti 
10352c03d07aSLuca Tettamanti 	pack = buf.pointer;
10362c03d07aSLuca Tettamanti 	for (i = 1; i < pack->package.count; i++) {
10372c03d07aSLuca Tettamanti 		union acpi_object *obj = &pack->package.elements[i];
10382c03d07aSLuca Tettamanti 
10392c03d07aSLuca Tettamanti 		ret = atk_add_sensor(data, obj);
10402c03d07aSLuca Tettamanti 		if (ret > 0)
10412c03d07aSLuca Tettamanti 			count++;
10422c03d07aSLuca Tettamanti 	}
10432c03d07aSLuca Tettamanti 	ACPI_FREE(buf.pointer);
10442c03d07aSLuca Tettamanti 
10452c03d07aSLuca Tettamanti 	return count;
10462c03d07aSLuca Tettamanti cleanup:
10472c03d07aSLuca Tettamanti 	atk_free_sensors(data);
10482c03d07aSLuca Tettamanti 	return ret;
10492c03d07aSLuca Tettamanti }
10502c03d07aSLuca Tettamanti 
10519e6eba61SLuca Tettamanti static int atk_ec_present(struct atk_data *data)
10529e6eba61SLuca Tettamanti {
10539e6eba61SLuca Tettamanti 	struct device *dev = &data->acpi_dev->dev;
10549e6eba61SLuca Tettamanti 	union acpi_object *pack;
10559e6eba61SLuca Tettamanti 	union acpi_object *ec;
10569e6eba61SLuca Tettamanti 	int ret;
10579e6eba61SLuca Tettamanti 	int i;
10589e6eba61SLuca Tettamanti 
10599e6eba61SLuca Tettamanti 	pack = atk_ggrp(data, ATK_MUX_MGMT);
10609e6eba61SLuca Tettamanti 	if (IS_ERR(pack)) {
10619e6eba61SLuca Tettamanti 		if (PTR_ERR(pack) == -ENOENT) {
10629e6eba61SLuca Tettamanti 			/* The MGMT class does not exists - that's ok */
10639e6eba61SLuca Tettamanti 			dev_dbg(dev, "Class %#llx not found\n", ATK_MUX_MGMT);
10649e6eba61SLuca Tettamanti 			return 0;
10659e6eba61SLuca Tettamanti 		}
10669e6eba61SLuca Tettamanti 		return PTR_ERR(pack);
10679e6eba61SLuca Tettamanti 	}
10689e6eba61SLuca Tettamanti 
10699e6eba61SLuca Tettamanti 	/* Search the EC */
10709e6eba61SLuca Tettamanti 	ec = NULL;
10719e6eba61SLuca Tettamanti 	for (i = 0; i < pack->package.count; i++) {
10729e6eba61SLuca Tettamanti 		union acpi_object *obj = &pack->package.elements[i];
10739e6eba61SLuca Tettamanti 		union acpi_object *id;
10749e6eba61SLuca Tettamanti 
10759e6eba61SLuca Tettamanti 		if (obj->type != ACPI_TYPE_PACKAGE)
10769e6eba61SLuca Tettamanti 			continue;
10779e6eba61SLuca Tettamanti 
10789e6eba61SLuca Tettamanti 		id = &obj->package.elements[0];
10799e6eba61SLuca Tettamanti 		if (id->type != ACPI_TYPE_INTEGER)
10809e6eba61SLuca Tettamanti 			continue;
10819e6eba61SLuca Tettamanti 
10829e6eba61SLuca Tettamanti 		if (id->integer.value == ATK_EC_ID) {
10839e6eba61SLuca Tettamanti 			ec = obj;
10849e6eba61SLuca Tettamanti 			break;
10859e6eba61SLuca Tettamanti 		}
10869e6eba61SLuca Tettamanti 	}
10879e6eba61SLuca Tettamanti 
10889e6eba61SLuca Tettamanti 	ret = (ec != NULL);
10899e6eba61SLuca Tettamanti 	if (!ret)
10909e6eba61SLuca Tettamanti 		/* The system has no EC */
10919e6eba61SLuca Tettamanti 		dev_dbg(dev, "EC not found\n");
10929e6eba61SLuca Tettamanti 
10939e6eba61SLuca Tettamanti 	ACPI_FREE(pack);
10949e6eba61SLuca Tettamanti 	return ret;
10959e6eba61SLuca Tettamanti }
10969e6eba61SLuca Tettamanti 
10979e6eba61SLuca Tettamanti static int atk_ec_enabled(struct atk_data *data)
10989e6eba61SLuca Tettamanti {
10999e6eba61SLuca Tettamanti 	struct device *dev = &data->acpi_dev->dev;
11009e6eba61SLuca Tettamanti 	union acpi_object *obj;
11019e6eba61SLuca Tettamanti 	struct atk_acpi_ret_buffer *buf;
11029e6eba61SLuca Tettamanti 	int err;
11039e6eba61SLuca Tettamanti 
11049e6eba61SLuca Tettamanti 	obj = atk_gitm(data, ATK_EC_ID);
11059e6eba61SLuca Tettamanti 	if (IS_ERR(obj)) {
11069e6eba61SLuca Tettamanti 		dev_err(dev, "Unable to query EC status\n");
11079e6eba61SLuca Tettamanti 		return PTR_ERR(obj);
11089e6eba61SLuca Tettamanti 	}
11099e6eba61SLuca Tettamanti 	buf = (struct atk_acpi_ret_buffer *)obj->buffer.pointer;
11109e6eba61SLuca Tettamanti 
11119e6eba61SLuca Tettamanti 	if (buf->flags == 0) {
11129e6eba61SLuca Tettamanti 		dev_err(dev, "Unable to query EC status\n");
11139e6eba61SLuca Tettamanti 		err = -EIO;
11149e6eba61SLuca Tettamanti 	} else {
11159e6eba61SLuca Tettamanti 		err = (buf->value != 0);
11169e6eba61SLuca Tettamanti 		dev_dbg(dev, "EC is %sabled\n",
11179e6eba61SLuca Tettamanti 				err ? "en" : "dis");
11189e6eba61SLuca Tettamanti 	}
11199e6eba61SLuca Tettamanti 
11209e6eba61SLuca Tettamanti 	ACPI_FREE(obj);
11219e6eba61SLuca Tettamanti 	return err;
11229e6eba61SLuca Tettamanti }
11239e6eba61SLuca Tettamanti 
11249e6eba61SLuca Tettamanti static int atk_ec_ctl(struct atk_data *data, int enable)
11259e6eba61SLuca Tettamanti {
11269e6eba61SLuca Tettamanti 	struct device *dev = &data->acpi_dev->dev;
11279e6eba61SLuca Tettamanti 	union acpi_object *obj;
11289e6eba61SLuca Tettamanti 	struct atk_acpi_input_buf sitm;
11299e6eba61SLuca Tettamanti 	struct atk_acpi_ret_buffer *ec_ret;
11309e6eba61SLuca Tettamanti 	int err = 0;
11319e6eba61SLuca Tettamanti 
11329e6eba61SLuca Tettamanti 	sitm.id = ATK_EC_ID;
11339e6eba61SLuca Tettamanti 	sitm.param1 = enable;
11349e6eba61SLuca Tettamanti 	sitm.param2 = 0;
11359e6eba61SLuca Tettamanti 
11369e6eba61SLuca Tettamanti 	obj = atk_sitm(data, &sitm);
11379e6eba61SLuca Tettamanti 	if (IS_ERR(obj)) {
11389e6eba61SLuca Tettamanti 		dev_err(dev, "Failed to %sable the EC\n",
11399e6eba61SLuca Tettamanti 				enable ? "en" : "dis");
11409e6eba61SLuca Tettamanti 		return PTR_ERR(obj);
11419e6eba61SLuca Tettamanti 	}
11429e6eba61SLuca Tettamanti 	ec_ret = (struct atk_acpi_ret_buffer *)obj->buffer.pointer;
11439e6eba61SLuca Tettamanti 	if (ec_ret->flags == 0) {
11449e6eba61SLuca Tettamanti 		dev_err(dev, "Failed to %sable the EC\n",
11459e6eba61SLuca Tettamanti 				enable ? "en" : "dis");
11469e6eba61SLuca Tettamanti 		err = -EIO;
11479e6eba61SLuca Tettamanti 	} else {
11489e6eba61SLuca Tettamanti 		dev_info(dev, "EC %sabled\n",
11499e6eba61SLuca Tettamanti 				enable ? "en" : "dis");
11509e6eba61SLuca Tettamanti 	}
11519e6eba61SLuca Tettamanti 
11529e6eba61SLuca Tettamanti 	ACPI_FREE(obj);
11539e6eba61SLuca Tettamanti 	return err;
11549e6eba61SLuca Tettamanti }
11559e6eba61SLuca Tettamanti 
11562c03d07aSLuca Tettamanti static int atk_enumerate_new_hwmon(struct atk_data *data)
11572c03d07aSLuca Tettamanti {
11582c03d07aSLuca Tettamanti 	struct device *dev = &data->acpi_dev->dev;
11592c03d07aSLuca Tettamanti 	union acpi_object *pack;
11602c03d07aSLuca Tettamanti 	int err;
11612c03d07aSLuca Tettamanti 	int i;
11622c03d07aSLuca Tettamanti 
11639e6eba61SLuca Tettamanti 	err = atk_ec_present(data);
11649e6eba61SLuca Tettamanti 	if (err < 0)
11659e6eba61SLuca Tettamanti 		return err;
11669e6eba61SLuca Tettamanti 	if (err) {
11679e6eba61SLuca Tettamanti 		err = atk_ec_enabled(data);
11689e6eba61SLuca Tettamanti 		if (err < 0)
11699e6eba61SLuca Tettamanti 			return err;
11709e6eba61SLuca Tettamanti 		/* If the EC was disabled we will disable it again on unload */
11719e6eba61SLuca Tettamanti 		data->disable_ec = err;
11729e6eba61SLuca Tettamanti 
11739e6eba61SLuca Tettamanti 		err = atk_ec_ctl(data, 1);
11749e6eba61SLuca Tettamanti 		if (err) {
11759e6eba61SLuca Tettamanti 			data->disable_ec = false;
11769e6eba61SLuca Tettamanti 			return err;
11779e6eba61SLuca Tettamanti 		}
11789e6eba61SLuca Tettamanti 	}
11799e6eba61SLuca Tettamanti 
11802c03d07aSLuca Tettamanti 	dev_dbg(dev, "Enumerating hwmon sensors\n");
11812c03d07aSLuca Tettamanti 
118218e25555SLuca Tettamanti 	pack = atk_ggrp(data, ATK_MUX_HWMON);
118318e25555SLuca Tettamanti 	if (IS_ERR(pack))
118418e25555SLuca Tettamanti 		return PTR_ERR(pack);
11852c03d07aSLuca Tettamanti 
11862c03d07aSLuca Tettamanti 	for (i = 0; i < pack->package.count; i++) {
11872c03d07aSLuca Tettamanti 		union acpi_object *obj = &pack->package.elements[i];
11882c03d07aSLuca Tettamanti 
11892c03d07aSLuca Tettamanti 		atk_add_sensor(data, obj);
11902c03d07aSLuca Tettamanti 	}
11912c03d07aSLuca Tettamanti 
11922c03d07aSLuca Tettamanti 	err = data->voltage_count + data->temperature_count + data->fan_count;
11932c03d07aSLuca Tettamanti 
119418e25555SLuca Tettamanti 	ACPI_FREE(pack);
11952c03d07aSLuca Tettamanti 	return err;
11962c03d07aSLuca Tettamanti }
11972c03d07aSLuca Tettamanti 
11982c03d07aSLuca Tettamanti static int atk_create_files(struct atk_data *data)
11992c03d07aSLuca Tettamanti {
12002c03d07aSLuca Tettamanti 	struct atk_sensor_data *s;
12012c03d07aSLuca Tettamanti 	int err;
12022c03d07aSLuca Tettamanti 
12032c03d07aSLuca Tettamanti 	list_for_each_entry(s, &data->sensor_list, list) {
12042c03d07aSLuca Tettamanti 		err = device_create_file(data->hwmon_dev, &s->input_attr);
12052c03d07aSLuca Tettamanti 		if (err)
12062c03d07aSLuca Tettamanti 			return err;
12072c03d07aSLuca Tettamanti 		err = device_create_file(data->hwmon_dev, &s->label_attr);
12082c03d07aSLuca Tettamanti 		if (err)
12092c03d07aSLuca Tettamanti 			return err;
12102c03d07aSLuca Tettamanti 		err = device_create_file(data->hwmon_dev, &s->limit1_attr);
12112c03d07aSLuca Tettamanti 		if (err)
12122c03d07aSLuca Tettamanti 			return err;
12132c03d07aSLuca Tettamanti 		err = device_create_file(data->hwmon_dev, &s->limit2_attr);
12142c03d07aSLuca Tettamanti 		if (err)
12152c03d07aSLuca Tettamanti 			return err;
12162c03d07aSLuca Tettamanti 	}
12172c03d07aSLuca Tettamanti 
12182c03d07aSLuca Tettamanti 	err = device_create_file(data->hwmon_dev, &atk_name_attr);
12192c03d07aSLuca Tettamanti 
12202c03d07aSLuca Tettamanti 	return err;
12212c03d07aSLuca Tettamanti }
12222c03d07aSLuca Tettamanti 
12232c03d07aSLuca Tettamanti static void atk_remove_files(struct atk_data *data)
12242c03d07aSLuca Tettamanti {
12252c03d07aSLuca Tettamanti 	struct atk_sensor_data *s;
12262c03d07aSLuca Tettamanti 
12272c03d07aSLuca Tettamanti 	list_for_each_entry(s, &data->sensor_list, list) {
12282c03d07aSLuca Tettamanti 		device_remove_file(data->hwmon_dev, &s->input_attr);
12292c03d07aSLuca Tettamanti 		device_remove_file(data->hwmon_dev, &s->label_attr);
12302c03d07aSLuca Tettamanti 		device_remove_file(data->hwmon_dev, &s->limit1_attr);
12312c03d07aSLuca Tettamanti 		device_remove_file(data->hwmon_dev, &s->limit2_attr);
12322c03d07aSLuca Tettamanti 	}
12332c03d07aSLuca Tettamanti 	device_remove_file(data->hwmon_dev, &atk_name_attr);
12342c03d07aSLuca Tettamanti }
12352c03d07aSLuca Tettamanti 
12362c03d07aSLuca Tettamanti static void atk_free_sensors(struct atk_data *data)
12372c03d07aSLuca Tettamanti {
12382c03d07aSLuca Tettamanti 	struct list_head *head = &data->sensor_list;
12392c03d07aSLuca Tettamanti 	struct atk_sensor_data *s, *tmp;
12402c03d07aSLuca Tettamanti 
12412c03d07aSLuca Tettamanti 	list_for_each_entry_safe(s, tmp, head, list) {
12422c03d07aSLuca Tettamanti 		kfree(s->acpi_name);
12432c03d07aSLuca Tettamanti 		kfree(s);
12442c03d07aSLuca Tettamanti 	}
12452c03d07aSLuca Tettamanti }
12462c03d07aSLuca Tettamanti 
12472c03d07aSLuca Tettamanti static int atk_register_hwmon(struct atk_data *data)
12482c03d07aSLuca Tettamanti {
12492c03d07aSLuca Tettamanti 	struct device *dev = &data->acpi_dev->dev;
12502c03d07aSLuca Tettamanti 	int err;
12512c03d07aSLuca Tettamanti 
12522c03d07aSLuca Tettamanti 	dev_dbg(dev, "registering hwmon device\n");
12532c03d07aSLuca Tettamanti 	data->hwmon_dev = hwmon_device_register(dev);
12542c03d07aSLuca Tettamanti 	if (IS_ERR(data->hwmon_dev))
12552c03d07aSLuca Tettamanti 		return PTR_ERR(data->hwmon_dev);
12562c03d07aSLuca Tettamanti 
12572c03d07aSLuca Tettamanti 	dev_dbg(dev, "populating sysfs directory\n");
12582c03d07aSLuca Tettamanti 	err = atk_create_files(data);
12592c03d07aSLuca Tettamanti 	if (err)
12602c03d07aSLuca Tettamanti 		goto remove;
12612c03d07aSLuca Tettamanti 
12622c03d07aSLuca Tettamanti 	return 0;
12632c03d07aSLuca Tettamanti remove:
12642c03d07aSLuca Tettamanti 	/* Cleanup the registered files */
12652c03d07aSLuca Tettamanti 	atk_remove_files(data);
12662c03d07aSLuca Tettamanti 	hwmon_device_unregister(data->hwmon_dev);
12672c03d07aSLuca Tettamanti 	return err;
12682c03d07aSLuca Tettamanti }
12692c03d07aSLuca Tettamanti 
12708ba406beSLuca Tettamanti static int atk_probe_if(struct atk_data *data)
12712c03d07aSLuca Tettamanti {
12722c03d07aSLuca Tettamanti 	struct device *dev = &data->acpi_dev->dev;
12732c03d07aSLuca Tettamanti 	acpi_handle ret;
12742c03d07aSLuca Tettamanti 	acpi_status status;
12758ba406beSLuca Tettamanti 	int err = 0;
12762c03d07aSLuca Tettamanti 
12772c03d07aSLuca Tettamanti 	/* RTMP: read temperature */
12782c03d07aSLuca Tettamanti 	status = acpi_get_handle(data->atk_handle, METHOD_OLD_READ_TMP, &ret);
12798ba406beSLuca Tettamanti 	if (ACPI_SUCCESS(status))
12808ba406beSLuca Tettamanti 		data->rtmp_handle = ret;
12818ba406beSLuca Tettamanti 	else
12822c03d07aSLuca Tettamanti 		dev_dbg(dev, "method " METHOD_OLD_READ_TMP " not found: %s\n",
12832c03d07aSLuca Tettamanti 				acpi_format_exception(status));
12842c03d07aSLuca Tettamanti 
12852c03d07aSLuca Tettamanti 	/* RVLT: read voltage */
12862c03d07aSLuca Tettamanti 	status = acpi_get_handle(data->atk_handle, METHOD_OLD_READ_VLT, &ret);
12878ba406beSLuca Tettamanti 	if (ACPI_SUCCESS(status))
12888ba406beSLuca Tettamanti 		data->rvlt_handle = ret;
12898ba406beSLuca Tettamanti 	else
12902c03d07aSLuca Tettamanti 		dev_dbg(dev, "method " METHOD_OLD_READ_VLT " not found: %s\n",
12912c03d07aSLuca Tettamanti 				acpi_format_exception(status));
12922c03d07aSLuca Tettamanti 
12932c03d07aSLuca Tettamanti 	/* RFAN: read fan status */
12942c03d07aSLuca Tettamanti 	status = acpi_get_handle(data->atk_handle, METHOD_OLD_READ_FAN, &ret);
12958ba406beSLuca Tettamanti 	if (ACPI_SUCCESS(status))
12968ba406beSLuca Tettamanti 		data->rfan_handle = ret;
12978ba406beSLuca Tettamanti 	else
12982c03d07aSLuca Tettamanti 		dev_dbg(dev, "method " METHOD_OLD_READ_FAN " not found: %s\n",
12992c03d07aSLuca Tettamanti 				acpi_format_exception(status));
13002c03d07aSLuca Tettamanti 
13012c03d07aSLuca Tettamanti 	/* Enumeration */
13022c03d07aSLuca Tettamanti 	status = acpi_get_handle(data->atk_handle, METHOD_ENUMERATE, &ret);
13038ba406beSLuca Tettamanti 	if (ACPI_SUCCESS(status))
13048ba406beSLuca Tettamanti 		data->enumerate_handle = ret;
13058ba406beSLuca Tettamanti 	else
13062c03d07aSLuca Tettamanti 		dev_dbg(dev, "method " METHOD_ENUMERATE " not found: %s\n",
13072c03d07aSLuca Tettamanti 				acpi_format_exception(status));
13082c03d07aSLuca Tettamanti 
13092c03d07aSLuca Tettamanti 	/* De-multiplexer (read) */
13102c03d07aSLuca Tettamanti 	status = acpi_get_handle(data->atk_handle, METHOD_READ, &ret);
13118ba406beSLuca Tettamanti 	if (ACPI_SUCCESS(status))
13128ba406beSLuca Tettamanti 		data->read_handle = ret;
13138ba406beSLuca Tettamanti 	else
13142c03d07aSLuca Tettamanti 		dev_dbg(dev, "method " METHOD_READ " not found: %s\n",
13152c03d07aSLuca Tettamanti 				acpi_format_exception(status));
13162c03d07aSLuca Tettamanti 
13179e6eba61SLuca Tettamanti 	/* De-multiplexer (write) */
13189e6eba61SLuca Tettamanti 	status = acpi_get_handle(data->atk_handle, METHOD_WRITE, &ret);
13198ba406beSLuca Tettamanti 	if (ACPI_SUCCESS(status))
13209e6eba61SLuca Tettamanti 		data->write_handle = ret;
13218ba406beSLuca Tettamanti 	else
13228ba406beSLuca Tettamanti 		dev_dbg(dev, "method " METHOD_WRITE " not found: %s\n",
13238ba406beSLuca Tettamanti 				 acpi_format_exception(status));
13249e6eba61SLuca Tettamanti 
132575bdc936SGuenter Roeck 	/*
132675bdc936SGuenter Roeck 	 * Check for hwmon methods: first check "old" style methods; note that
13278ba406beSLuca Tettamanti 	 * both may be present: in this case we stick to the old interface;
13288ba406beSLuca Tettamanti 	 * analysis of multiple DSDTs indicates that when both interfaces
13298ba406beSLuca Tettamanti 	 * are present the new one (GGRP/GITM) is not functional.
13308ba406beSLuca Tettamanti 	 */
133186ca33e8SLuca Tettamanti 	if (new_if)
133286ca33e8SLuca Tettamanti 		dev_info(dev, "Overriding interface detection\n");
1333c6e8ac04SFrans Meulenbroeks 	if (data->rtmp_handle &&
1334c6e8ac04SFrans Meulenbroeks 			data->rvlt_handle && data->rfan_handle && !new_if)
13358ba406beSLuca Tettamanti 		data->old_interface = true;
13368ba406beSLuca Tettamanti 	else if (data->enumerate_handle && data->read_handle &&
13378ba406beSLuca Tettamanti 			data->write_handle)
13388ba406beSLuca Tettamanti 		data->old_interface = false;
13398ba406beSLuca Tettamanti 	else
13408ba406beSLuca Tettamanti 		err = -ENODEV;
13418ba406beSLuca Tettamanti 
13428ba406beSLuca Tettamanti 	return err;
13432c03d07aSLuca Tettamanti }
13442c03d07aSLuca Tettamanti 
13452c03d07aSLuca Tettamanti static int atk_add(struct acpi_device *device)
13462c03d07aSLuca Tettamanti {
13472c03d07aSLuca Tettamanti 	acpi_status ret;
13482c03d07aSLuca Tettamanti 	int err;
13492c03d07aSLuca Tettamanti 	struct acpi_buffer buf;
13502c03d07aSLuca Tettamanti 	union acpi_object *obj;
13512c03d07aSLuca Tettamanti 	struct atk_data *data;
13522c03d07aSLuca Tettamanti 
13532c03d07aSLuca Tettamanti 	dev_dbg(&device->dev, "adding...\n");
13542c03d07aSLuca Tettamanti 
13552c03d07aSLuca Tettamanti 	data = kzalloc(sizeof(*data), GFP_KERNEL);
13562c03d07aSLuca Tettamanti 	if (!data)
13572c03d07aSLuca Tettamanti 		return -ENOMEM;
13582c03d07aSLuca Tettamanti 
13592c03d07aSLuca Tettamanti 	data->acpi_dev = device;
13602c03d07aSLuca Tettamanti 	data->atk_handle = device->handle;
13612c03d07aSLuca Tettamanti 	INIT_LIST_HEAD(&data->sensor_list);
13629e6eba61SLuca Tettamanti 	data->disable_ec = false;
13632c03d07aSLuca Tettamanti 
13642c03d07aSLuca Tettamanti 	buf.length = ACPI_ALLOCATE_BUFFER;
13652c03d07aSLuca Tettamanti 	ret = acpi_evaluate_object_typed(data->atk_handle, BOARD_ID, NULL,
13662c03d07aSLuca Tettamanti 			&buf, ACPI_TYPE_PACKAGE);
13672c03d07aSLuca Tettamanti 	if (ret != AE_OK) {
13682c03d07aSLuca Tettamanti 		dev_dbg(&device->dev, "atk: method MBIF not found\n");
13695542482bSLuca Tettamanti 	} else {
13702c03d07aSLuca Tettamanti 		obj = buf.pointer;
13715542482bSLuca Tettamanti 		if (obj->package.count >= 2) {
13725542482bSLuca Tettamanti 			union acpi_object *id = &obj->package.elements[1];
13735542482bSLuca Tettamanti 			if (id->type == ACPI_TYPE_STRING)
13742c03d07aSLuca Tettamanti 				dev_dbg(&device->dev, "board ID = %s\n",
13755542482bSLuca Tettamanti 					id->string.pointer);
13762c03d07aSLuca Tettamanti 		}
13772c03d07aSLuca Tettamanti 		ACPI_FREE(buf.pointer);
13785542482bSLuca Tettamanti 	}
13792c03d07aSLuca Tettamanti 
13808ba406beSLuca Tettamanti 	err = atk_probe_if(data);
13818ba406beSLuca Tettamanti 	if (err) {
13828ba406beSLuca Tettamanti 		dev_err(&device->dev, "No usable hwmon interface detected\n");
13832c03d07aSLuca Tettamanti 		goto out;
13842c03d07aSLuca Tettamanti 	}
13852c03d07aSLuca Tettamanti 
13868ba406beSLuca Tettamanti 	if (data->old_interface) {
13878ba406beSLuca Tettamanti 		dev_dbg(&device->dev, "Using old hwmon interface\n");
13882c03d07aSLuca Tettamanti 		err = atk_enumerate_old_hwmon(data);
13898ba406beSLuca Tettamanti 	} else {
13908ba406beSLuca Tettamanti 		dev_dbg(&device->dev, "Using new hwmon interface\n");
13912c03d07aSLuca Tettamanti 		err = atk_enumerate_new_hwmon(data);
13928ba406beSLuca Tettamanti 	}
13932c03d07aSLuca Tettamanti 	if (err < 0)
13942c03d07aSLuca Tettamanti 		goto out;
13952c03d07aSLuca Tettamanti 	if (err == 0) {
13962c03d07aSLuca Tettamanti 		dev_info(&device->dev,
13972c03d07aSLuca Tettamanti 			 "No usable sensor detected, bailing out\n");
13982c03d07aSLuca Tettamanti 		err = -ENODEV;
13992c03d07aSLuca Tettamanti 		goto out;
14002c03d07aSLuca Tettamanti 	}
14012c03d07aSLuca Tettamanti 
14022c03d07aSLuca Tettamanti 	err = atk_register_hwmon(data);
14032c03d07aSLuca Tettamanti 	if (err)
14042c03d07aSLuca Tettamanti 		goto cleanup;
14052c03d07aSLuca Tettamanti 
14067e5eab11SLuca Tettamanti 	atk_debugfs_init(data);
14077e5eab11SLuca Tettamanti 
14082c03d07aSLuca Tettamanti 	device->driver_data = data;
14092c03d07aSLuca Tettamanti 	return 0;
14102c03d07aSLuca Tettamanti cleanup:
14112c03d07aSLuca Tettamanti 	atk_free_sensors(data);
14122c03d07aSLuca Tettamanti out:
14139e6eba61SLuca Tettamanti 	if (data->disable_ec)
14149e6eba61SLuca Tettamanti 		atk_ec_ctl(data, 0);
14152c03d07aSLuca Tettamanti 	kfree(data);
14162c03d07aSLuca Tettamanti 	return err;
14172c03d07aSLuca Tettamanti }
14182c03d07aSLuca Tettamanti 
141951fac838SRafael J. Wysocki static int atk_remove(struct acpi_device *device)
14202c03d07aSLuca Tettamanti {
14212c03d07aSLuca Tettamanti 	struct atk_data *data = device->driver_data;
14222c03d07aSLuca Tettamanti 	dev_dbg(&device->dev, "removing...\n");
14232c03d07aSLuca Tettamanti 
14242c03d07aSLuca Tettamanti 	device->driver_data = NULL;
14252c03d07aSLuca Tettamanti 
14267e5eab11SLuca Tettamanti 	atk_debugfs_cleanup(data);
14277e5eab11SLuca Tettamanti 
14282c03d07aSLuca Tettamanti 	atk_remove_files(data);
14292c03d07aSLuca Tettamanti 	atk_free_sensors(data);
14302c03d07aSLuca Tettamanti 	hwmon_device_unregister(data->hwmon_dev);
14312c03d07aSLuca Tettamanti 
14329e6eba61SLuca Tettamanti 	if (data->disable_ec) {
14339e6eba61SLuca Tettamanti 		if (atk_ec_ctl(data, 0))
14349e6eba61SLuca Tettamanti 			dev_err(&device->dev, "Failed to disable EC\n");
14359e6eba61SLuca Tettamanti 	}
14369e6eba61SLuca Tettamanti 
14372c03d07aSLuca Tettamanti 	kfree(data);
14382c03d07aSLuca Tettamanti 
14392c03d07aSLuca Tettamanti 	return 0;
14402c03d07aSLuca Tettamanti }
14412c03d07aSLuca Tettamanti 
14422c03d07aSLuca Tettamanti static int __init atk0110_init(void)
14432c03d07aSLuca Tettamanti {
14442c03d07aSLuca Tettamanti 	int ret;
14452c03d07aSLuca Tettamanti 
144670dd6beaSJean Delvare 	/* Make sure it's safe to access the device through ACPI */
144770dd6beaSJean Delvare 	if (!acpi_resources_are_enforced()) {
1448ac561494SJoe Perches 		pr_err("Resources not safely usable due to acpi_enforce_resources kernel parameter\n");
144970dd6beaSJean Delvare 		return -EBUSY;
145070dd6beaSJean Delvare 	}
145170dd6beaSJean Delvare 
145286ca33e8SLuca Tettamanti 	if (dmi_check_system(atk_force_new_if))
145386ca33e8SLuca Tettamanti 		new_if = true;
145486ca33e8SLuca Tettamanti 
14552c03d07aSLuca Tettamanti 	ret = acpi_bus_register_driver(&atk_driver);
14562c03d07aSLuca Tettamanti 	if (ret)
1457ac561494SJoe Perches 		pr_info("acpi_bus_register_driver failed: %d\n", ret);
14582c03d07aSLuca Tettamanti 
14592c03d07aSLuca Tettamanti 	return ret;
14602c03d07aSLuca Tettamanti }
14612c03d07aSLuca Tettamanti 
14622c03d07aSLuca Tettamanti static void __exit atk0110_exit(void)
14632c03d07aSLuca Tettamanti {
14642c03d07aSLuca Tettamanti 	acpi_bus_unregister_driver(&atk_driver);
14652c03d07aSLuca Tettamanti }
14662c03d07aSLuca Tettamanti 
14672c03d07aSLuca Tettamanti module_init(atk0110_init);
14682c03d07aSLuca Tettamanti module_exit(atk0110_exit);
14692c03d07aSLuca Tettamanti 
14702c03d07aSLuca Tettamanti MODULE_LICENSE("GPL");
1471