18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci * Copyright (C) 2007-2009 Luca Tettamanti <kronos.it@gmail.com>
48c2ecf20Sopenharmony_ci *
58c2ecf20Sopenharmony_ci * See COPYING in the top level directory of the kernel tree.
68c2ecf20Sopenharmony_ci */
78c2ecf20Sopenharmony_ci
88c2ecf20Sopenharmony_ci#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
98c2ecf20Sopenharmony_ci
108c2ecf20Sopenharmony_ci#include <linux/debugfs.h>
118c2ecf20Sopenharmony_ci#include <linux/kernel.h>
128c2ecf20Sopenharmony_ci#include <linux/hwmon.h>
138c2ecf20Sopenharmony_ci#include <linux/list.h>
148c2ecf20Sopenharmony_ci#include <linux/module.h>
158c2ecf20Sopenharmony_ci#include <linux/slab.h>
168c2ecf20Sopenharmony_ci#include <linux/dmi.h>
178c2ecf20Sopenharmony_ci#include <linux/jiffies.h>
188c2ecf20Sopenharmony_ci#include <linux/err.h>
198c2ecf20Sopenharmony_ci#include <linux/acpi.h>
208c2ecf20Sopenharmony_ci
218c2ecf20Sopenharmony_ci#define ATK_HID "ATK0110"
228c2ecf20Sopenharmony_ci
238c2ecf20Sopenharmony_cistatic bool new_if;
248c2ecf20Sopenharmony_cimodule_param(new_if, bool, 0);
258c2ecf20Sopenharmony_ciMODULE_PARM_DESC(new_if, "Override detection heuristic and force the use of the new ATK0110 interface");
268c2ecf20Sopenharmony_ci
278c2ecf20Sopenharmony_cistatic const struct dmi_system_id __initconst atk_force_new_if[] = {
288c2ecf20Sopenharmony_ci	{
298c2ecf20Sopenharmony_ci		/* Old interface has broken MCH temp monitoring */
308c2ecf20Sopenharmony_ci		.ident = "Asus Sabertooth X58",
318c2ecf20Sopenharmony_ci		.matches = {
328c2ecf20Sopenharmony_ci			DMI_MATCH(DMI_BOARD_NAME, "SABERTOOTH X58")
338c2ecf20Sopenharmony_ci		}
348c2ecf20Sopenharmony_ci	}, {
358c2ecf20Sopenharmony_ci		/* Old interface reads the same sensor for fan0 and fan1 */
368c2ecf20Sopenharmony_ci		.ident = "Asus M5A78L",
378c2ecf20Sopenharmony_ci		.matches = {
388c2ecf20Sopenharmony_ci			DMI_MATCH(DMI_BOARD_NAME, "M5A78L")
398c2ecf20Sopenharmony_ci		}
408c2ecf20Sopenharmony_ci	},
418c2ecf20Sopenharmony_ci	{ }
428c2ecf20Sopenharmony_ci};
438c2ecf20Sopenharmony_ci
448c2ecf20Sopenharmony_ci/*
458c2ecf20Sopenharmony_ci * Minimum time between readings, enforced in order to avoid
468c2ecf20Sopenharmony_ci * hogging the CPU.
478c2ecf20Sopenharmony_ci */
488c2ecf20Sopenharmony_ci#define CACHE_TIME		HZ
498c2ecf20Sopenharmony_ci
508c2ecf20Sopenharmony_ci#define BOARD_ID		"MBIF"
518c2ecf20Sopenharmony_ci#define METHOD_ENUMERATE	"GGRP"
528c2ecf20Sopenharmony_ci#define METHOD_READ		"GITM"
538c2ecf20Sopenharmony_ci#define METHOD_WRITE		"SITM"
548c2ecf20Sopenharmony_ci#define METHOD_OLD_READ_TMP	"RTMP"
558c2ecf20Sopenharmony_ci#define METHOD_OLD_READ_VLT	"RVLT"
568c2ecf20Sopenharmony_ci#define METHOD_OLD_READ_FAN	"RFAN"
578c2ecf20Sopenharmony_ci#define METHOD_OLD_ENUM_TMP	"TSIF"
588c2ecf20Sopenharmony_ci#define METHOD_OLD_ENUM_VLT	"VSIF"
598c2ecf20Sopenharmony_ci#define METHOD_OLD_ENUM_FAN	"FSIF"
608c2ecf20Sopenharmony_ci
618c2ecf20Sopenharmony_ci#define ATK_MUX_HWMON		0x00000006ULL
628c2ecf20Sopenharmony_ci#define ATK_MUX_MGMT		0x00000011ULL
638c2ecf20Sopenharmony_ci
648c2ecf20Sopenharmony_ci#define ATK_CLASS_MASK		0xff000000ULL
658c2ecf20Sopenharmony_ci#define ATK_CLASS_FREQ_CTL	0x03000000ULL
668c2ecf20Sopenharmony_ci#define ATK_CLASS_FAN_CTL	0x04000000ULL
678c2ecf20Sopenharmony_ci#define ATK_CLASS_HWMON		0x06000000ULL
688c2ecf20Sopenharmony_ci#define ATK_CLASS_MGMT		0x11000000ULL
698c2ecf20Sopenharmony_ci
708c2ecf20Sopenharmony_ci#define ATK_TYPE_MASK		0x00ff0000ULL
718c2ecf20Sopenharmony_ci#define HWMON_TYPE_VOLT		0x00020000ULL
728c2ecf20Sopenharmony_ci#define HWMON_TYPE_TEMP		0x00030000ULL
738c2ecf20Sopenharmony_ci#define HWMON_TYPE_FAN		0x00040000ULL
748c2ecf20Sopenharmony_ci
758c2ecf20Sopenharmony_ci#define ATK_ELEMENT_ID_MASK	0x0000ffffULL
768c2ecf20Sopenharmony_ci
778c2ecf20Sopenharmony_ci#define ATK_EC_ID		0x11060004ULL
788c2ecf20Sopenharmony_ci
798c2ecf20Sopenharmony_cienum atk_pack_member {
808c2ecf20Sopenharmony_ci	HWMON_PACK_FLAGS,
818c2ecf20Sopenharmony_ci	HWMON_PACK_NAME,
828c2ecf20Sopenharmony_ci	HWMON_PACK_LIMIT1,
838c2ecf20Sopenharmony_ci	HWMON_PACK_LIMIT2,
848c2ecf20Sopenharmony_ci	HWMON_PACK_ENABLE
858c2ecf20Sopenharmony_ci};
868c2ecf20Sopenharmony_ci
878c2ecf20Sopenharmony_ci/* New package format */
888c2ecf20Sopenharmony_ci#define _HWMON_NEW_PACK_SIZE	7
898c2ecf20Sopenharmony_ci#define _HWMON_NEW_PACK_FLAGS	0
908c2ecf20Sopenharmony_ci#define _HWMON_NEW_PACK_NAME	1
918c2ecf20Sopenharmony_ci#define _HWMON_NEW_PACK_UNK1	2
928c2ecf20Sopenharmony_ci#define _HWMON_NEW_PACK_UNK2	3
938c2ecf20Sopenharmony_ci#define _HWMON_NEW_PACK_LIMIT1	4
948c2ecf20Sopenharmony_ci#define _HWMON_NEW_PACK_LIMIT2	5
958c2ecf20Sopenharmony_ci#define _HWMON_NEW_PACK_ENABLE	6
968c2ecf20Sopenharmony_ci
978c2ecf20Sopenharmony_ci/* Old package format */
988c2ecf20Sopenharmony_ci#define _HWMON_OLD_PACK_SIZE	5
998c2ecf20Sopenharmony_ci#define _HWMON_OLD_PACK_FLAGS	0
1008c2ecf20Sopenharmony_ci#define _HWMON_OLD_PACK_NAME	1
1018c2ecf20Sopenharmony_ci#define _HWMON_OLD_PACK_LIMIT1	2
1028c2ecf20Sopenharmony_ci#define _HWMON_OLD_PACK_LIMIT2	3
1038c2ecf20Sopenharmony_ci#define _HWMON_OLD_PACK_ENABLE	4
1048c2ecf20Sopenharmony_ci
1058c2ecf20Sopenharmony_ci
1068c2ecf20Sopenharmony_cistruct atk_data {
1078c2ecf20Sopenharmony_ci	struct device *hwmon_dev;
1088c2ecf20Sopenharmony_ci	acpi_handle atk_handle;
1098c2ecf20Sopenharmony_ci	struct acpi_device *acpi_dev;
1108c2ecf20Sopenharmony_ci
1118c2ecf20Sopenharmony_ci	bool old_interface;
1128c2ecf20Sopenharmony_ci
1138c2ecf20Sopenharmony_ci	/* old interface */
1148c2ecf20Sopenharmony_ci	acpi_handle rtmp_handle;
1158c2ecf20Sopenharmony_ci	acpi_handle rvlt_handle;
1168c2ecf20Sopenharmony_ci	acpi_handle rfan_handle;
1178c2ecf20Sopenharmony_ci	/* new interface */
1188c2ecf20Sopenharmony_ci	acpi_handle enumerate_handle;
1198c2ecf20Sopenharmony_ci	acpi_handle read_handle;
1208c2ecf20Sopenharmony_ci	acpi_handle write_handle;
1218c2ecf20Sopenharmony_ci
1228c2ecf20Sopenharmony_ci	bool disable_ec;
1238c2ecf20Sopenharmony_ci
1248c2ecf20Sopenharmony_ci	int voltage_count;
1258c2ecf20Sopenharmony_ci	int temperature_count;
1268c2ecf20Sopenharmony_ci	int fan_count;
1278c2ecf20Sopenharmony_ci	struct list_head sensor_list;
1288c2ecf20Sopenharmony_ci	struct attribute_group attr_group;
1298c2ecf20Sopenharmony_ci	const struct attribute_group *attr_groups[2];
1308c2ecf20Sopenharmony_ci
1318c2ecf20Sopenharmony_ci	struct {
1328c2ecf20Sopenharmony_ci		struct dentry *root;
1338c2ecf20Sopenharmony_ci		u32 id;
1348c2ecf20Sopenharmony_ci	} debugfs;
1358c2ecf20Sopenharmony_ci};
1368c2ecf20Sopenharmony_ci
1378c2ecf20Sopenharmony_ci
1388c2ecf20Sopenharmony_citypedef ssize_t (*sysfs_show_func)(struct device *dev,
1398c2ecf20Sopenharmony_ci			struct device_attribute *attr, char *buf);
1408c2ecf20Sopenharmony_ci
1418c2ecf20Sopenharmony_cistatic const struct acpi_device_id atk_ids[] = {
1428c2ecf20Sopenharmony_ci	{ATK_HID, 0},
1438c2ecf20Sopenharmony_ci	{"", 0},
1448c2ecf20Sopenharmony_ci};
1458c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(acpi, atk_ids);
1468c2ecf20Sopenharmony_ci
1478c2ecf20Sopenharmony_ci#define ATTR_NAME_SIZE 16 /* Worst case is "tempN_input" */
1488c2ecf20Sopenharmony_ci
1498c2ecf20Sopenharmony_cistruct atk_sensor_data {
1508c2ecf20Sopenharmony_ci	struct list_head list;
1518c2ecf20Sopenharmony_ci	struct atk_data *data;
1528c2ecf20Sopenharmony_ci	struct device_attribute label_attr;
1538c2ecf20Sopenharmony_ci	struct device_attribute input_attr;
1548c2ecf20Sopenharmony_ci	struct device_attribute limit1_attr;
1558c2ecf20Sopenharmony_ci	struct device_attribute limit2_attr;
1568c2ecf20Sopenharmony_ci	char label_attr_name[ATTR_NAME_SIZE];
1578c2ecf20Sopenharmony_ci	char input_attr_name[ATTR_NAME_SIZE];
1588c2ecf20Sopenharmony_ci	char limit1_attr_name[ATTR_NAME_SIZE];
1598c2ecf20Sopenharmony_ci	char limit2_attr_name[ATTR_NAME_SIZE];
1608c2ecf20Sopenharmony_ci	u64 id;
1618c2ecf20Sopenharmony_ci	u64 type;
1628c2ecf20Sopenharmony_ci	u64 limit1;
1638c2ecf20Sopenharmony_ci	u64 limit2;
1648c2ecf20Sopenharmony_ci	u64 cached_value;
1658c2ecf20Sopenharmony_ci	unsigned long last_updated; /* in jiffies */
1668c2ecf20Sopenharmony_ci	bool is_valid;
1678c2ecf20Sopenharmony_ci	char const *acpi_name;
1688c2ecf20Sopenharmony_ci};
1698c2ecf20Sopenharmony_ci
1708c2ecf20Sopenharmony_ci/*
1718c2ecf20Sopenharmony_ci * Return buffer format:
1728c2ecf20Sopenharmony_ci * [0-3] "value" is valid flag
1738c2ecf20Sopenharmony_ci * [4-7] value
1748c2ecf20Sopenharmony_ci * [8- ] unknown stuff on newer mobos
1758c2ecf20Sopenharmony_ci */
1768c2ecf20Sopenharmony_cistruct atk_acpi_ret_buffer {
1778c2ecf20Sopenharmony_ci	u32 flags;
1788c2ecf20Sopenharmony_ci	u32 value;
1798c2ecf20Sopenharmony_ci	u8 data[];
1808c2ecf20Sopenharmony_ci};
1818c2ecf20Sopenharmony_ci
1828c2ecf20Sopenharmony_ci/* Input buffer used for GITM and SITM methods */
1838c2ecf20Sopenharmony_cistruct atk_acpi_input_buf {
1848c2ecf20Sopenharmony_ci	u32 id;
1858c2ecf20Sopenharmony_ci	u32 param1;
1868c2ecf20Sopenharmony_ci	u32 param2;
1878c2ecf20Sopenharmony_ci};
1888c2ecf20Sopenharmony_ci
1898c2ecf20Sopenharmony_cistatic int atk_add(struct acpi_device *device);
1908c2ecf20Sopenharmony_cistatic int atk_remove(struct acpi_device *device);
1918c2ecf20Sopenharmony_cistatic void atk_print_sensor(struct atk_data *data, union acpi_object *obj);
1928c2ecf20Sopenharmony_cistatic int atk_read_value(struct atk_sensor_data *sensor, u64 *value);
1938c2ecf20Sopenharmony_ci
1948c2ecf20Sopenharmony_cistatic struct acpi_driver atk_driver = {
1958c2ecf20Sopenharmony_ci	.name	= ATK_HID,
1968c2ecf20Sopenharmony_ci	.class	= "hwmon",
1978c2ecf20Sopenharmony_ci	.ids	= atk_ids,
1988c2ecf20Sopenharmony_ci	.ops	= {
1998c2ecf20Sopenharmony_ci		.add	= atk_add,
2008c2ecf20Sopenharmony_ci		.remove	= atk_remove,
2018c2ecf20Sopenharmony_ci	},
2028c2ecf20Sopenharmony_ci};
2038c2ecf20Sopenharmony_ci
2048c2ecf20Sopenharmony_ci#define input_to_atk_sensor(attr) \
2058c2ecf20Sopenharmony_ci	container_of(attr, struct atk_sensor_data, input_attr)
2068c2ecf20Sopenharmony_ci
2078c2ecf20Sopenharmony_ci#define label_to_atk_sensor(attr) \
2088c2ecf20Sopenharmony_ci	container_of(attr, struct atk_sensor_data, label_attr)
2098c2ecf20Sopenharmony_ci
2108c2ecf20Sopenharmony_ci#define limit1_to_atk_sensor(attr) \
2118c2ecf20Sopenharmony_ci	container_of(attr, struct atk_sensor_data, limit1_attr)
2128c2ecf20Sopenharmony_ci
2138c2ecf20Sopenharmony_ci#define limit2_to_atk_sensor(attr) \
2148c2ecf20Sopenharmony_ci	container_of(attr, struct atk_sensor_data, limit2_attr)
2158c2ecf20Sopenharmony_ci
2168c2ecf20Sopenharmony_cistatic ssize_t atk_input_show(struct device *dev,
2178c2ecf20Sopenharmony_ci		struct device_attribute *attr, char *buf)
2188c2ecf20Sopenharmony_ci{
2198c2ecf20Sopenharmony_ci	struct atk_sensor_data *s = input_to_atk_sensor(attr);
2208c2ecf20Sopenharmony_ci	u64 value;
2218c2ecf20Sopenharmony_ci	int err;
2228c2ecf20Sopenharmony_ci
2238c2ecf20Sopenharmony_ci	err = atk_read_value(s, &value);
2248c2ecf20Sopenharmony_ci	if (err)
2258c2ecf20Sopenharmony_ci		return err;
2268c2ecf20Sopenharmony_ci
2278c2ecf20Sopenharmony_ci	if (s->type == HWMON_TYPE_TEMP)
2288c2ecf20Sopenharmony_ci		/* ACPI returns decidegree */
2298c2ecf20Sopenharmony_ci		value *= 100;
2308c2ecf20Sopenharmony_ci
2318c2ecf20Sopenharmony_ci	return sprintf(buf, "%llu\n", value);
2328c2ecf20Sopenharmony_ci}
2338c2ecf20Sopenharmony_ci
2348c2ecf20Sopenharmony_cistatic ssize_t atk_label_show(struct device *dev,
2358c2ecf20Sopenharmony_ci		struct device_attribute *attr, char *buf)
2368c2ecf20Sopenharmony_ci{
2378c2ecf20Sopenharmony_ci	struct atk_sensor_data *s = label_to_atk_sensor(attr);
2388c2ecf20Sopenharmony_ci
2398c2ecf20Sopenharmony_ci	return sprintf(buf, "%s\n", s->acpi_name);
2408c2ecf20Sopenharmony_ci}
2418c2ecf20Sopenharmony_ci
2428c2ecf20Sopenharmony_cistatic ssize_t atk_limit1_show(struct device *dev,
2438c2ecf20Sopenharmony_ci		struct device_attribute *attr, char *buf)
2448c2ecf20Sopenharmony_ci{
2458c2ecf20Sopenharmony_ci	struct atk_sensor_data *s = limit1_to_atk_sensor(attr);
2468c2ecf20Sopenharmony_ci	u64 value = s->limit1;
2478c2ecf20Sopenharmony_ci
2488c2ecf20Sopenharmony_ci	if (s->type == HWMON_TYPE_TEMP)
2498c2ecf20Sopenharmony_ci		value *= 100;
2508c2ecf20Sopenharmony_ci
2518c2ecf20Sopenharmony_ci	return sprintf(buf, "%lld\n", value);
2528c2ecf20Sopenharmony_ci}
2538c2ecf20Sopenharmony_ci
2548c2ecf20Sopenharmony_cistatic ssize_t atk_limit2_show(struct device *dev,
2558c2ecf20Sopenharmony_ci		struct device_attribute *attr, char *buf)
2568c2ecf20Sopenharmony_ci{
2578c2ecf20Sopenharmony_ci	struct atk_sensor_data *s = limit2_to_atk_sensor(attr);
2588c2ecf20Sopenharmony_ci	u64 value = s->limit2;
2598c2ecf20Sopenharmony_ci
2608c2ecf20Sopenharmony_ci	if (s->type == HWMON_TYPE_TEMP)
2618c2ecf20Sopenharmony_ci		value *= 100;
2628c2ecf20Sopenharmony_ci
2638c2ecf20Sopenharmony_ci	return sprintf(buf, "%lld\n", value);
2648c2ecf20Sopenharmony_ci}
2658c2ecf20Sopenharmony_ci
2668c2ecf20Sopenharmony_cistatic void atk_init_attribute(struct device_attribute *attr, char *name,
2678c2ecf20Sopenharmony_ci		sysfs_show_func show)
2688c2ecf20Sopenharmony_ci{
2698c2ecf20Sopenharmony_ci	sysfs_attr_init(&attr->attr);
2708c2ecf20Sopenharmony_ci	attr->attr.name = name;
2718c2ecf20Sopenharmony_ci	attr->attr.mode = 0444;
2728c2ecf20Sopenharmony_ci	attr->show = show;
2738c2ecf20Sopenharmony_ci	attr->store = NULL;
2748c2ecf20Sopenharmony_ci}
2758c2ecf20Sopenharmony_ci
2768c2ecf20Sopenharmony_ci
2778c2ecf20Sopenharmony_cistatic union acpi_object *atk_get_pack_member(struct atk_data *data,
2788c2ecf20Sopenharmony_ci						union acpi_object *pack,
2798c2ecf20Sopenharmony_ci						enum atk_pack_member m)
2808c2ecf20Sopenharmony_ci{
2818c2ecf20Sopenharmony_ci	bool old_if = data->old_interface;
2828c2ecf20Sopenharmony_ci	int offset;
2838c2ecf20Sopenharmony_ci
2848c2ecf20Sopenharmony_ci	switch (m) {
2858c2ecf20Sopenharmony_ci	case HWMON_PACK_FLAGS:
2868c2ecf20Sopenharmony_ci		offset = old_if ? _HWMON_OLD_PACK_FLAGS : _HWMON_NEW_PACK_FLAGS;
2878c2ecf20Sopenharmony_ci		break;
2888c2ecf20Sopenharmony_ci	case HWMON_PACK_NAME:
2898c2ecf20Sopenharmony_ci		offset = old_if ? _HWMON_OLD_PACK_NAME : _HWMON_NEW_PACK_NAME;
2908c2ecf20Sopenharmony_ci		break;
2918c2ecf20Sopenharmony_ci	case HWMON_PACK_LIMIT1:
2928c2ecf20Sopenharmony_ci		offset = old_if ? _HWMON_OLD_PACK_LIMIT1 :
2938c2ecf20Sopenharmony_ci				  _HWMON_NEW_PACK_LIMIT1;
2948c2ecf20Sopenharmony_ci		break;
2958c2ecf20Sopenharmony_ci	case HWMON_PACK_LIMIT2:
2968c2ecf20Sopenharmony_ci		offset = old_if ? _HWMON_OLD_PACK_LIMIT2 :
2978c2ecf20Sopenharmony_ci				  _HWMON_NEW_PACK_LIMIT2;
2988c2ecf20Sopenharmony_ci		break;
2998c2ecf20Sopenharmony_ci	case HWMON_PACK_ENABLE:
3008c2ecf20Sopenharmony_ci		offset = old_if ? _HWMON_OLD_PACK_ENABLE :
3018c2ecf20Sopenharmony_ci				  _HWMON_NEW_PACK_ENABLE;
3028c2ecf20Sopenharmony_ci		break;
3038c2ecf20Sopenharmony_ci	default:
3048c2ecf20Sopenharmony_ci		return NULL;
3058c2ecf20Sopenharmony_ci	}
3068c2ecf20Sopenharmony_ci
3078c2ecf20Sopenharmony_ci	return &pack->package.elements[offset];
3088c2ecf20Sopenharmony_ci}
3098c2ecf20Sopenharmony_ci
3108c2ecf20Sopenharmony_ci
3118c2ecf20Sopenharmony_ci/*
3128c2ecf20Sopenharmony_ci * New package format is:
3138c2ecf20Sopenharmony_ci * - flag (int)
3148c2ecf20Sopenharmony_ci *	class - used for de-muxing the request to the correct GITn
3158c2ecf20Sopenharmony_ci *	type (volt, temp, fan)
3168c2ecf20Sopenharmony_ci *	sensor id |
3178c2ecf20Sopenharmony_ci *	sensor id - used for de-muxing the request _inside_ the GITn
3188c2ecf20Sopenharmony_ci * - name (str)
3198c2ecf20Sopenharmony_ci * - unknown (int)
3208c2ecf20Sopenharmony_ci * - unknown (int)
3218c2ecf20Sopenharmony_ci * - limit1 (int)
3228c2ecf20Sopenharmony_ci * - limit2 (int)
3238c2ecf20Sopenharmony_ci * - enable (int)
3248c2ecf20Sopenharmony_ci *
3258c2ecf20Sopenharmony_ci * The old package has the same format but it's missing the two unknown fields.
3268c2ecf20Sopenharmony_ci */
3278c2ecf20Sopenharmony_cistatic int validate_hwmon_pack(struct atk_data *data, union acpi_object *obj)
3288c2ecf20Sopenharmony_ci{
3298c2ecf20Sopenharmony_ci	struct device *dev = &data->acpi_dev->dev;
3308c2ecf20Sopenharmony_ci	union acpi_object *tmp;
3318c2ecf20Sopenharmony_ci	bool old_if = data->old_interface;
3328c2ecf20Sopenharmony_ci	int const expected_size = old_if ? _HWMON_OLD_PACK_SIZE :
3338c2ecf20Sopenharmony_ci					   _HWMON_NEW_PACK_SIZE;
3348c2ecf20Sopenharmony_ci
3358c2ecf20Sopenharmony_ci	if (obj->type != ACPI_TYPE_PACKAGE) {
3368c2ecf20Sopenharmony_ci		dev_warn(dev, "Invalid type: %d\n", obj->type);
3378c2ecf20Sopenharmony_ci		return -EINVAL;
3388c2ecf20Sopenharmony_ci	}
3398c2ecf20Sopenharmony_ci
3408c2ecf20Sopenharmony_ci	if (obj->package.count != expected_size) {
3418c2ecf20Sopenharmony_ci		dev_warn(dev, "Invalid package size: %d, expected: %d\n",
3428c2ecf20Sopenharmony_ci				obj->package.count, expected_size);
3438c2ecf20Sopenharmony_ci		return -EINVAL;
3448c2ecf20Sopenharmony_ci	}
3458c2ecf20Sopenharmony_ci
3468c2ecf20Sopenharmony_ci	tmp = atk_get_pack_member(data, obj, HWMON_PACK_FLAGS);
3478c2ecf20Sopenharmony_ci	if (tmp->type != ACPI_TYPE_INTEGER) {
3488c2ecf20Sopenharmony_ci		dev_warn(dev, "Invalid type (flag): %d\n", tmp->type);
3498c2ecf20Sopenharmony_ci		return -EINVAL;
3508c2ecf20Sopenharmony_ci	}
3518c2ecf20Sopenharmony_ci
3528c2ecf20Sopenharmony_ci	tmp = atk_get_pack_member(data, obj, HWMON_PACK_NAME);
3538c2ecf20Sopenharmony_ci	if (tmp->type != ACPI_TYPE_STRING) {
3548c2ecf20Sopenharmony_ci		dev_warn(dev, "Invalid type (name): %d\n", tmp->type);
3558c2ecf20Sopenharmony_ci		return -EINVAL;
3568c2ecf20Sopenharmony_ci	}
3578c2ecf20Sopenharmony_ci
3588c2ecf20Sopenharmony_ci	/* Don't check... we don't know what they're useful for anyway */
3598c2ecf20Sopenharmony_ci#if 0
3608c2ecf20Sopenharmony_ci	tmp = &obj->package.elements[HWMON_PACK_UNK1];
3618c2ecf20Sopenharmony_ci	if (tmp->type != ACPI_TYPE_INTEGER) {
3628c2ecf20Sopenharmony_ci		dev_warn(dev, "Invalid type (unk1): %d\n", tmp->type);
3638c2ecf20Sopenharmony_ci		return -EINVAL;
3648c2ecf20Sopenharmony_ci	}
3658c2ecf20Sopenharmony_ci
3668c2ecf20Sopenharmony_ci	tmp = &obj->package.elements[HWMON_PACK_UNK2];
3678c2ecf20Sopenharmony_ci	if (tmp->type != ACPI_TYPE_INTEGER) {
3688c2ecf20Sopenharmony_ci		dev_warn(dev, "Invalid type (unk2): %d\n", tmp->type);
3698c2ecf20Sopenharmony_ci		return -EINVAL;
3708c2ecf20Sopenharmony_ci	}
3718c2ecf20Sopenharmony_ci#endif
3728c2ecf20Sopenharmony_ci
3738c2ecf20Sopenharmony_ci	tmp = atk_get_pack_member(data, obj, HWMON_PACK_LIMIT1);
3748c2ecf20Sopenharmony_ci	if (tmp->type != ACPI_TYPE_INTEGER) {
3758c2ecf20Sopenharmony_ci		dev_warn(dev, "Invalid type (limit1): %d\n", tmp->type);
3768c2ecf20Sopenharmony_ci		return -EINVAL;
3778c2ecf20Sopenharmony_ci	}
3788c2ecf20Sopenharmony_ci
3798c2ecf20Sopenharmony_ci	tmp = atk_get_pack_member(data, obj, HWMON_PACK_LIMIT2);
3808c2ecf20Sopenharmony_ci	if (tmp->type != ACPI_TYPE_INTEGER) {
3818c2ecf20Sopenharmony_ci		dev_warn(dev, "Invalid type (limit2): %d\n", tmp->type);
3828c2ecf20Sopenharmony_ci		return -EINVAL;
3838c2ecf20Sopenharmony_ci	}
3848c2ecf20Sopenharmony_ci
3858c2ecf20Sopenharmony_ci	tmp = atk_get_pack_member(data, obj, HWMON_PACK_ENABLE);
3868c2ecf20Sopenharmony_ci	if (tmp->type != ACPI_TYPE_INTEGER) {
3878c2ecf20Sopenharmony_ci		dev_warn(dev, "Invalid type (enable): %d\n", tmp->type);
3888c2ecf20Sopenharmony_ci		return -EINVAL;
3898c2ecf20Sopenharmony_ci	}
3908c2ecf20Sopenharmony_ci
3918c2ecf20Sopenharmony_ci	atk_print_sensor(data, obj);
3928c2ecf20Sopenharmony_ci
3938c2ecf20Sopenharmony_ci	return 0;
3948c2ecf20Sopenharmony_ci}
3958c2ecf20Sopenharmony_ci
3968c2ecf20Sopenharmony_ci#ifdef DEBUG
3978c2ecf20Sopenharmony_cistatic char const *atk_sensor_type(union acpi_object *flags)
3988c2ecf20Sopenharmony_ci{
3998c2ecf20Sopenharmony_ci	u64 type = flags->integer.value & ATK_TYPE_MASK;
4008c2ecf20Sopenharmony_ci	char const *what;
4018c2ecf20Sopenharmony_ci
4028c2ecf20Sopenharmony_ci	switch (type) {
4038c2ecf20Sopenharmony_ci	case HWMON_TYPE_VOLT:
4048c2ecf20Sopenharmony_ci		what = "voltage";
4058c2ecf20Sopenharmony_ci		break;
4068c2ecf20Sopenharmony_ci	case HWMON_TYPE_TEMP:
4078c2ecf20Sopenharmony_ci		what = "temperature";
4088c2ecf20Sopenharmony_ci		break;
4098c2ecf20Sopenharmony_ci	case HWMON_TYPE_FAN:
4108c2ecf20Sopenharmony_ci		what = "fan";
4118c2ecf20Sopenharmony_ci		break;
4128c2ecf20Sopenharmony_ci	default:
4138c2ecf20Sopenharmony_ci		what = "unknown";
4148c2ecf20Sopenharmony_ci		break;
4158c2ecf20Sopenharmony_ci	}
4168c2ecf20Sopenharmony_ci
4178c2ecf20Sopenharmony_ci	return what;
4188c2ecf20Sopenharmony_ci}
4198c2ecf20Sopenharmony_ci#endif
4208c2ecf20Sopenharmony_ci
4218c2ecf20Sopenharmony_cistatic void atk_print_sensor(struct atk_data *data, union acpi_object *obj)
4228c2ecf20Sopenharmony_ci{
4238c2ecf20Sopenharmony_ci#ifdef DEBUG
4248c2ecf20Sopenharmony_ci	struct device *dev = &data->acpi_dev->dev;
4258c2ecf20Sopenharmony_ci	union acpi_object *flags;
4268c2ecf20Sopenharmony_ci	union acpi_object *name;
4278c2ecf20Sopenharmony_ci	union acpi_object *limit1;
4288c2ecf20Sopenharmony_ci	union acpi_object *limit2;
4298c2ecf20Sopenharmony_ci	union acpi_object *enable;
4308c2ecf20Sopenharmony_ci	char const *what;
4318c2ecf20Sopenharmony_ci
4328c2ecf20Sopenharmony_ci	flags = atk_get_pack_member(data, obj, HWMON_PACK_FLAGS);
4338c2ecf20Sopenharmony_ci	name = atk_get_pack_member(data, obj, HWMON_PACK_NAME);
4348c2ecf20Sopenharmony_ci	limit1 = atk_get_pack_member(data, obj, HWMON_PACK_LIMIT1);
4358c2ecf20Sopenharmony_ci	limit2 = atk_get_pack_member(data, obj, HWMON_PACK_LIMIT2);
4368c2ecf20Sopenharmony_ci	enable = atk_get_pack_member(data, obj, HWMON_PACK_ENABLE);
4378c2ecf20Sopenharmony_ci
4388c2ecf20Sopenharmony_ci	what = atk_sensor_type(flags);
4398c2ecf20Sopenharmony_ci
4408c2ecf20Sopenharmony_ci	dev_dbg(dev, "%s: %#llx %s [%llu-%llu] %s\n", what,
4418c2ecf20Sopenharmony_ci			flags->integer.value,
4428c2ecf20Sopenharmony_ci			name->string.pointer,
4438c2ecf20Sopenharmony_ci			limit1->integer.value, limit2->integer.value,
4448c2ecf20Sopenharmony_ci			enable->integer.value ? "enabled" : "disabled");
4458c2ecf20Sopenharmony_ci#endif
4468c2ecf20Sopenharmony_ci}
4478c2ecf20Sopenharmony_ci
4488c2ecf20Sopenharmony_cistatic int atk_read_value_old(struct atk_sensor_data *sensor, u64 *value)
4498c2ecf20Sopenharmony_ci{
4508c2ecf20Sopenharmony_ci	struct atk_data *data = sensor->data;
4518c2ecf20Sopenharmony_ci	struct device *dev = &data->acpi_dev->dev;
4528c2ecf20Sopenharmony_ci	struct acpi_object_list params;
4538c2ecf20Sopenharmony_ci	union acpi_object id;
4548c2ecf20Sopenharmony_ci	acpi_status status;
4558c2ecf20Sopenharmony_ci	acpi_handle method;
4568c2ecf20Sopenharmony_ci
4578c2ecf20Sopenharmony_ci	switch (sensor->type) {
4588c2ecf20Sopenharmony_ci	case HWMON_TYPE_VOLT:
4598c2ecf20Sopenharmony_ci		method = data->rvlt_handle;
4608c2ecf20Sopenharmony_ci		break;
4618c2ecf20Sopenharmony_ci	case HWMON_TYPE_TEMP:
4628c2ecf20Sopenharmony_ci		method = data->rtmp_handle;
4638c2ecf20Sopenharmony_ci		break;
4648c2ecf20Sopenharmony_ci	case HWMON_TYPE_FAN:
4658c2ecf20Sopenharmony_ci		method = data->rfan_handle;
4668c2ecf20Sopenharmony_ci		break;
4678c2ecf20Sopenharmony_ci	default:
4688c2ecf20Sopenharmony_ci		return -EINVAL;
4698c2ecf20Sopenharmony_ci	}
4708c2ecf20Sopenharmony_ci
4718c2ecf20Sopenharmony_ci	id.type = ACPI_TYPE_INTEGER;
4728c2ecf20Sopenharmony_ci	id.integer.value = sensor->id;
4738c2ecf20Sopenharmony_ci
4748c2ecf20Sopenharmony_ci	params.count = 1;
4758c2ecf20Sopenharmony_ci	params.pointer = &id;
4768c2ecf20Sopenharmony_ci
4778c2ecf20Sopenharmony_ci	status = acpi_evaluate_integer(method, NULL, &params, value);
4788c2ecf20Sopenharmony_ci	if (status != AE_OK) {
4798c2ecf20Sopenharmony_ci		dev_warn(dev, "%s: ACPI exception: %s\n", __func__,
4808c2ecf20Sopenharmony_ci				acpi_format_exception(status));
4818c2ecf20Sopenharmony_ci		return -EIO;
4828c2ecf20Sopenharmony_ci	}
4838c2ecf20Sopenharmony_ci
4848c2ecf20Sopenharmony_ci	return 0;
4858c2ecf20Sopenharmony_ci}
4868c2ecf20Sopenharmony_ci
4878c2ecf20Sopenharmony_cistatic union acpi_object *atk_ggrp(struct atk_data *data, u16 mux)
4888c2ecf20Sopenharmony_ci{
4898c2ecf20Sopenharmony_ci	struct device *dev = &data->acpi_dev->dev;
4908c2ecf20Sopenharmony_ci	struct acpi_buffer buf;
4918c2ecf20Sopenharmony_ci	acpi_status ret;
4928c2ecf20Sopenharmony_ci	struct acpi_object_list params;
4938c2ecf20Sopenharmony_ci	union acpi_object id;
4948c2ecf20Sopenharmony_ci	union acpi_object *pack;
4958c2ecf20Sopenharmony_ci
4968c2ecf20Sopenharmony_ci	id.type = ACPI_TYPE_INTEGER;
4978c2ecf20Sopenharmony_ci	id.integer.value = mux;
4988c2ecf20Sopenharmony_ci	params.count = 1;
4998c2ecf20Sopenharmony_ci	params.pointer = &id;
5008c2ecf20Sopenharmony_ci
5018c2ecf20Sopenharmony_ci	buf.length = ACPI_ALLOCATE_BUFFER;
5028c2ecf20Sopenharmony_ci	ret = acpi_evaluate_object(data->enumerate_handle, NULL, &params, &buf);
5038c2ecf20Sopenharmony_ci	if (ret != AE_OK) {
5048c2ecf20Sopenharmony_ci		dev_err(dev, "GGRP[%#x] ACPI exception: %s\n", mux,
5058c2ecf20Sopenharmony_ci				acpi_format_exception(ret));
5068c2ecf20Sopenharmony_ci		return ERR_PTR(-EIO);
5078c2ecf20Sopenharmony_ci	}
5088c2ecf20Sopenharmony_ci	pack = buf.pointer;
5098c2ecf20Sopenharmony_ci	if (pack->type != ACPI_TYPE_PACKAGE) {
5108c2ecf20Sopenharmony_ci		/* Execution was successful, but the id was not found */
5118c2ecf20Sopenharmony_ci		ACPI_FREE(pack);
5128c2ecf20Sopenharmony_ci		return ERR_PTR(-ENOENT);
5138c2ecf20Sopenharmony_ci	}
5148c2ecf20Sopenharmony_ci
5158c2ecf20Sopenharmony_ci	if (pack->package.count < 1) {
5168c2ecf20Sopenharmony_ci		dev_err(dev, "GGRP[%#x] package is too small\n", mux);
5178c2ecf20Sopenharmony_ci		ACPI_FREE(pack);
5188c2ecf20Sopenharmony_ci		return ERR_PTR(-EIO);
5198c2ecf20Sopenharmony_ci	}
5208c2ecf20Sopenharmony_ci	return pack;
5218c2ecf20Sopenharmony_ci}
5228c2ecf20Sopenharmony_ci
5238c2ecf20Sopenharmony_cistatic union acpi_object *atk_gitm(struct atk_data *data, u64 id)
5248c2ecf20Sopenharmony_ci{
5258c2ecf20Sopenharmony_ci	struct device *dev = &data->acpi_dev->dev;
5268c2ecf20Sopenharmony_ci	struct atk_acpi_input_buf buf;
5278c2ecf20Sopenharmony_ci	union acpi_object tmp;
5288c2ecf20Sopenharmony_ci	struct acpi_object_list params;
5298c2ecf20Sopenharmony_ci	struct acpi_buffer ret;
5308c2ecf20Sopenharmony_ci	union acpi_object *obj;
5318c2ecf20Sopenharmony_ci	acpi_status status;
5328c2ecf20Sopenharmony_ci
5338c2ecf20Sopenharmony_ci	buf.id = id;
5348c2ecf20Sopenharmony_ci	buf.param1 = 0;
5358c2ecf20Sopenharmony_ci	buf.param2 = 0;
5368c2ecf20Sopenharmony_ci
5378c2ecf20Sopenharmony_ci	tmp.type = ACPI_TYPE_BUFFER;
5388c2ecf20Sopenharmony_ci	tmp.buffer.pointer = (u8 *)&buf;
5398c2ecf20Sopenharmony_ci	tmp.buffer.length = sizeof(buf);
5408c2ecf20Sopenharmony_ci
5418c2ecf20Sopenharmony_ci	params.count = 1;
5428c2ecf20Sopenharmony_ci	params.pointer = (void *)&tmp;
5438c2ecf20Sopenharmony_ci
5448c2ecf20Sopenharmony_ci	ret.length = ACPI_ALLOCATE_BUFFER;
5458c2ecf20Sopenharmony_ci	status = acpi_evaluate_object_typed(data->read_handle, NULL, &params,
5468c2ecf20Sopenharmony_ci			&ret, ACPI_TYPE_BUFFER);
5478c2ecf20Sopenharmony_ci	if (status != AE_OK) {
5488c2ecf20Sopenharmony_ci		dev_warn(dev, "GITM[%#llx] ACPI exception: %s\n", id,
5498c2ecf20Sopenharmony_ci				acpi_format_exception(status));
5508c2ecf20Sopenharmony_ci		return ERR_PTR(-EIO);
5518c2ecf20Sopenharmony_ci	}
5528c2ecf20Sopenharmony_ci	obj = ret.pointer;
5538c2ecf20Sopenharmony_ci
5548c2ecf20Sopenharmony_ci	/* Sanity check */
5558c2ecf20Sopenharmony_ci	if (obj->buffer.length < 8) {
5568c2ecf20Sopenharmony_ci		dev_warn(dev, "Unexpected ASBF length: %u\n",
5578c2ecf20Sopenharmony_ci				obj->buffer.length);
5588c2ecf20Sopenharmony_ci		ACPI_FREE(obj);
5598c2ecf20Sopenharmony_ci		return ERR_PTR(-EIO);
5608c2ecf20Sopenharmony_ci	}
5618c2ecf20Sopenharmony_ci	return obj;
5628c2ecf20Sopenharmony_ci}
5638c2ecf20Sopenharmony_ci
5648c2ecf20Sopenharmony_cistatic union acpi_object *atk_sitm(struct atk_data *data,
5658c2ecf20Sopenharmony_ci		struct atk_acpi_input_buf *buf)
5668c2ecf20Sopenharmony_ci{
5678c2ecf20Sopenharmony_ci	struct device *dev = &data->acpi_dev->dev;
5688c2ecf20Sopenharmony_ci	struct acpi_object_list params;
5698c2ecf20Sopenharmony_ci	union acpi_object tmp;
5708c2ecf20Sopenharmony_ci	struct acpi_buffer ret;
5718c2ecf20Sopenharmony_ci	union acpi_object *obj;
5728c2ecf20Sopenharmony_ci	acpi_status status;
5738c2ecf20Sopenharmony_ci
5748c2ecf20Sopenharmony_ci	tmp.type = ACPI_TYPE_BUFFER;
5758c2ecf20Sopenharmony_ci	tmp.buffer.pointer = (u8 *)buf;
5768c2ecf20Sopenharmony_ci	tmp.buffer.length = sizeof(*buf);
5778c2ecf20Sopenharmony_ci
5788c2ecf20Sopenharmony_ci	params.count = 1;
5798c2ecf20Sopenharmony_ci	params.pointer = &tmp;
5808c2ecf20Sopenharmony_ci
5818c2ecf20Sopenharmony_ci	ret.length = ACPI_ALLOCATE_BUFFER;
5828c2ecf20Sopenharmony_ci	status = acpi_evaluate_object_typed(data->write_handle, NULL, &params,
5838c2ecf20Sopenharmony_ci			&ret, ACPI_TYPE_BUFFER);
5848c2ecf20Sopenharmony_ci	if (status != AE_OK) {
5858c2ecf20Sopenharmony_ci		dev_warn(dev, "SITM[%#x] ACPI exception: %s\n", buf->id,
5868c2ecf20Sopenharmony_ci				acpi_format_exception(status));
5878c2ecf20Sopenharmony_ci		return ERR_PTR(-EIO);
5888c2ecf20Sopenharmony_ci	}
5898c2ecf20Sopenharmony_ci	obj = ret.pointer;
5908c2ecf20Sopenharmony_ci
5918c2ecf20Sopenharmony_ci	/* Sanity check */
5928c2ecf20Sopenharmony_ci	if (obj->buffer.length < 8) {
5938c2ecf20Sopenharmony_ci		dev_warn(dev, "Unexpected ASBF length: %u\n",
5948c2ecf20Sopenharmony_ci				obj->buffer.length);
5958c2ecf20Sopenharmony_ci		ACPI_FREE(obj);
5968c2ecf20Sopenharmony_ci		return ERR_PTR(-EIO);
5978c2ecf20Sopenharmony_ci	}
5988c2ecf20Sopenharmony_ci	return obj;
5998c2ecf20Sopenharmony_ci}
6008c2ecf20Sopenharmony_ci
6018c2ecf20Sopenharmony_cistatic int atk_read_value_new(struct atk_sensor_data *sensor, u64 *value)
6028c2ecf20Sopenharmony_ci{
6038c2ecf20Sopenharmony_ci	struct atk_data *data = sensor->data;
6048c2ecf20Sopenharmony_ci	struct device *dev = &data->acpi_dev->dev;
6058c2ecf20Sopenharmony_ci	union acpi_object *obj;
6068c2ecf20Sopenharmony_ci	struct atk_acpi_ret_buffer *buf;
6078c2ecf20Sopenharmony_ci	int err = 0;
6088c2ecf20Sopenharmony_ci
6098c2ecf20Sopenharmony_ci	obj = atk_gitm(data, sensor->id);
6108c2ecf20Sopenharmony_ci	if (IS_ERR(obj))
6118c2ecf20Sopenharmony_ci		return PTR_ERR(obj);
6128c2ecf20Sopenharmony_ci
6138c2ecf20Sopenharmony_ci	buf = (struct atk_acpi_ret_buffer *)obj->buffer.pointer;
6148c2ecf20Sopenharmony_ci	if (buf->flags == 0) {
6158c2ecf20Sopenharmony_ci		/*
6168c2ecf20Sopenharmony_ci		 * The reading is not valid, possible causes:
6178c2ecf20Sopenharmony_ci		 * - sensor failure
6188c2ecf20Sopenharmony_ci		 * - enumeration was FUBAR (and we didn't notice)
6198c2ecf20Sopenharmony_ci		 */
6208c2ecf20Sopenharmony_ci		dev_warn(dev, "Read failed, sensor = %#llx\n", sensor->id);
6218c2ecf20Sopenharmony_ci		err = -EIO;
6228c2ecf20Sopenharmony_ci		goto out;
6238c2ecf20Sopenharmony_ci	}
6248c2ecf20Sopenharmony_ci
6258c2ecf20Sopenharmony_ci	*value = buf->value;
6268c2ecf20Sopenharmony_ciout:
6278c2ecf20Sopenharmony_ci	ACPI_FREE(obj);
6288c2ecf20Sopenharmony_ci	return err;
6298c2ecf20Sopenharmony_ci}
6308c2ecf20Sopenharmony_ci
6318c2ecf20Sopenharmony_cistatic int atk_read_value(struct atk_sensor_data *sensor, u64 *value)
6328c2ecf20Sopenharmony_ci{
6338c2ecf20Sopenharmony_ci	int err;
6348c2ecf20Sopenharmony_ci
6358c2ecf20Sopenharmony_ci	if (!sensor->is_valid ||
6368c2ecf20Sopenharmony_ci	    time_after(jiffies, sensor->last_updated + CACHE_TIME)) {
6378c2ecf20Sopenharmony_ci		if (sensor->data->old_interface)
6388c2ecf20Sopenharmony_ci			err = atk_read_value_old(sensor, value);
6398c2ecf20Sopenharmony_ci		else
6408c2ecf20Sopenharmony_ci			err = atk_read_value_new(sensor, value);
6418c2ecf20Sopenharmony_ci
6428c2ecf20Sopenharmony_ci		if (err)
6438c2ecf20Sopenharmony_ci			return err;
6448c2ecf20Sopenharmony_ci
6458c2ecf20Sopenharmony_ci		sensor->is_valid = true;
6468c2ecf20Sopenharmony_ci		sensor->last_updated = jiffies;
6478c2ecf20Sopenharmony_ci		sensor->cached_value = *value;
6488c2ecf20Sopenharmony_ci	} else {
6498c2ecf20Sopenharmony_ci		*value = sensor->cached_value;
6508c2ecf20Sopenharmony_ci		err = 0;
6518c2ecf20Sopenharmony_ci	}
6528c2ecf20Sopenharmony_ci
6538c2ecf20Sopenharmony_ci	return err;
6548c2ecf20Sopenharmony_ci}
6558c2ecf20Sopenharmony_ci
6568c2ecf20Sopenharmony_ci#ifdef CONFIG_DEBUG_FS
6578c2ecf20Sopenharmony_cistatic int atk_debugfs_gitm_get(void *p, u64 *val)
6588c2ecf20Sopenharmony_ci{
6598c2ecf20Sopenharmony_ci	struct atk_data *data = p;
6608c2ecf20Sopenharmony_ci	union acpi_object *ret;
6618c2ecf20Sopenharmony_ci	struct atk_acpi_ret_buffer *buf;
6628c2ecf20Sopenharmony_ci	int err = 0;
6638c2ecf20Sopenharmony_ci
6648c2ecf20Sopenharmony_ci	if (!data->read_handle)
6658c2ecf20Sopenharmony_ci		return -ENODEV;
6668c2ecf20Sopenharmony_ci
6678c2ecf20Sopenharmony_ci	if (!data->debugfs.id)
6688c2ecf20Sopenharmony_ci		return -EINVAL;
6698c2ecf20Sopenharmony_ci
6708c2ecf20Sopenharmony_ci	ret = atk_gitm(data, data->debugfs.id);
6718c2ecf20Sopenharmony_ci	if (IS_ERR(ret))
6728c2ecf20Sopenharmony_ci		return PTR_ERR(ret);
6738c2ecf20Sopenharmony_ci
6748c2ecf20Sopenharmony_ci	buf = (struct atk_acpi_ret_buffer *)ret->buffer.pointer;
6758c2ecf20Sopenharmony_ci	if (buf->flags)
6768c2ecf20Sopenharmony_ci		*val = buf->value;
6778c2ecf20Sopenharmony_ci	else
6788c2ecf20Sopenharmony_ci		err = -EIO;
6798c2ecf20Sopenharmony_ci
6808c2ecf20Sopenharmony_ci	ACPI_FREE(ret);
6818c2ecf20Sopenharmony_ci	return err;
6828c2ecf20Sopenharmony_ci}
6838c2ecf20Sopenharmony_ci
6848c2ecf20Sopenharmony_ciDEFINE_DEBUGFS_ATTRIBUTE(atk_debugfs_gitm, atk_debugfs_gitm_get, NULL,
6858c2ecf20Sopenharmony_ci			 "0x%08llx\n");
6868c2ecf20Sopenharmony_ci
6878c2ecf20Sopenharmony_cistatic int atk_acpi_print(char *buf, size_t sz, union acpi_object *obj)
6888c2ecf20Sopenharmony_ci{
6898c2ecf20Sopenharmony_ci	int ret = 0;
6908c2ecf20Sopenharmony_ci
6918c2ecf20Sopenharmony_ci	switch (obj->type) {
6928c2ecf20Sopenharmony_ci	case ACPI_TYPE_INTEGER:
6938c2ecf20Sopenharmony_ci		ret = snprintf(buf, sz, "0x%08llx\n", obj->integer.value);
6948c2ecf20Sopenharmony_ci		break;
6958c2ecf20Sopenharmony_ci	case ACPI_TYPE_STRING:
6968c2ecf20Sopenharmony_ci		ret = snprintf(buf, sz, "%s\n", obj->string.pointer);
6978c2ecf20Sopenharmony_ci		break;
6988c2ecf20Sopenharmony_ci	}
6998c2ecf20Sopenharmony_ci
7008c2ecf20Sopenharmony_ci	return ret;
7018c2ecf20Sopenharmony_ci}
7028c2ecf20Sopenharmony_ci
7038c2ecf20Sopenharmony_cistatic void atk_pack_print(char *buf, size_t sz, union acpi_object *pack)
7048c2ecf20Sopenharmony_ci{
7058c2ecf20Sopenharmony_ci	int ret;
7068c2ecf20Sopenharmony_ci	int i;
7078c2ecf20Sopenharmony_ci
7088c2ecf20Sopenharmony_ci	for (i = 0; i < pack->package.count; i++) {
7098c2ecf20Sopenharmony_ci		union acpi_object *obj = &pack->package.elements[i];
7108c2ecf20Sopenharmony_ci
7118c2ecf20Sopenharmony_ci		ret = atk_acpi_print(buf, sz, obj);
7128c2ecf20Sopenharmony_ci		if (ret >= sz)
7138c2ecf20Sopenharmony_ci			break;
7148c2ecf20Sopenharmony_ci		buf += ret;
7158c2ecf20Sopenharmony_ci		sz -= ret;
7168c2ecf20Sopenharmony_ci	}
7178c2ecf20Sopenharmony_ci}
7188c2ecf20Sopenharmony_ci
7198c2ecf20Sopenharmony_cistatic int atk_debugfs_ggrp_open(struct inode *inode, struct file *file)
7208c2ecf20Sopenharmony_ci{
7218c2ecf20Sopenharmony_ci	struct atk_data *data = inode->i_private;
7228c2ecf20Sopenharmony_ci	char *buf = NULL;
7238c2ecf20Sopenharmony_ci	union acpi_object *ret;
7248c2ecf20Sopenharmony_ci	u8 cls;
7258c2ecf20Sopenharmony_ci	int i;
7268c2ecf20Sopenharmony_ci
7278c2ecf20Sopenharmony_ci	if (!data->enumerate_handle)
7288c2ecf20Sopenharmony_ci		return -ENODEV;
7298c2ecf20Sopenharmony_ci	if (!data->debugfs.id)
7308c2ecf20Sopenharmony_ci		return -EINVAL;
7318c2ecf20Sopenharmony_ci
7328c2ecf20Sopenharmony_ci	cls = (data->debugfs.id & 0xff000000) >> 24;
7338c2ecf20Sopenharmony_ci	ret = atk_ggrp(data, cls);
7348c2ecf20Sopenharmony_ci	if (IS_ERR(ret))
7358c2ecf20Sopenharmony_ci		return PTR_ERR(ret);
7368c2ecf20Sopenharmony_ci
7378c2ecf20Sopenharmony_ci	for (i = 0; i < ret->package.count; i++) {
7388c2ecf20Sopenharmony_ci		union acpi_object *pack = &ret->package.elements[i];
7398c2ecf20Sopenharmony_ci		union acpi_object *id;
7408c2ecf20Sopenharmony_ci
7418c2ecf20Sopenharmony_ci		if (pack->type != ACPI_TYPE_PACKAGE)
7428c2ecf20Sopenharmony_ci			continue;
7438c2ecf20Sopenharmony_ci		if (!pack->package.count)
7448c2ecf20Sopenharmony_ci			continue;
7458c2ecf20Sopenharmony_ci		id = &pack->package.elements[0];
7468c2ecf20Sopenharmony_ci		if (id->integer.value == data->debugfs.id) {
7478c2ecf20Sopenharmony_ci			/* Print the package */
7488c2ecf20Sopenharmony_ci			buf = kzalloc(512, GFP_KERNEL);
7498c2ecf20Sopenharmony_ci			if (!buf) {
7508c2ecf20Sopenharmony_ci				ACPI_FREE(ret);
7518c2ecf20Sopenharmony_ci				return -ENOMEM;
7528c2ecf20Sopenharmony_ci			}
7538c2ecf20Sopenharmony_ci			atk_pack_print(buf, 512, pack);
7548c2ecf20Sopenharmony_ci			break;
7558c2ecf20Sopenharmony_ci		}
7568c2ecf20Sopenharmony_ci	}
7578c2ecf20Sopenharmony_ci	ACPI_FREE(ret);
7588c2ecf20Sopenharmony_ci
7598c2ecf20Sopenharmony_ci	if (!buf)
7608c2ecf20Sopenharmony_ci		return -EINVAL;
7618c2ecf20Sopenharmony_ci
7628c2ecf20Sopenharmony_ci	file->private_data = buf;
7638c2ecf20Sopenharmony_ci
7648c2ecf20Sopenharmony_ci	return nonseekable_open(inode, file);
7658c2ecf20Sopenharmony_ci}
7668c2ecf20Sopenharmony_ci
7678c2ecf20Sopenharmony_cistatic ssize_t atk_debugfs_ggrp_read(struct file *file, char __user *buf,
7688c2ecf20Sopenharmony_ci		size_t count, loff_t *pos)
7698c2ecf20Sopenharmony_ci{
7708c2ecf20Sopenharmony_ci	char *str = file->private_data;
7718c2ecf20Sopenharmony_ci	size_t len = strlen(str);
7728c2ecf20Sopenharmony_ci
7738c2ecf20Sopenharmony_ci	return simple_read_from_buffer(buf, count, pos, str, len);
7748c2ecf20Sopenharmony_ci}
7758c2ecf20Sopenharmony_ci
7768c2ecf20Sopenharmony_cistatic int atk_debugfs_ggrp_release(struct inode *inode, struct file *file)
7778c2ecf20Sopenharmony_ci{
7788c2ecf20Sopenharmony_ci	kfree(file->private_data);
7798c2ecf20Sopenharmony_ci	return 0;
7808c2ecf20Sopenharmony_ci}
7818c2ecf20Sopenharmony_ci
7828c2ecf20Sopenharmony_cistatic const struct file_operations atk_debugfs_ggrp_fops = {
7838c2ecf20Sopenharmony_ci	.read		= atk_debugfs_ggrp_read,
7848c2ecf20Sopenharmony_ci	.open		= atk_debugfs_ggrp_open,
7858c2ecf20Sopenharmony_ci	.release	= atk_debugfs_ggrp_release,
7868c2ecf20Sopenharmony_ci	.llseek		= no_llseek,
7878c2ecf20Sopenharmony_ci};
7888c2ecf20Sopenharmony_ci
7898c2ecf20Sopenharmony_cistatic void atk_debugfs_init(struct atk_data *data)
7908c2ecf20Sopenharmony_ci{
7918c2ecf20Sopenharmony_ci	struct dentry *d;
7928c2ecf20Sopenharmony_ci
7938c2ecf20Sopenharmony_ci	data->debugfs.id = 0;
7948c2ecf20Sopenharmony_ci
7958c2ecf20Sopenharmony_ci	d = debugfs_create_dir("asus_atk0110", NULL);
7968c2ecf20Sopenharmony_ci
7978c2ecf20Sopenharmony_ci	debugfs_create_x32("id", 0600, d, &data->debugfs.id);
7988c2ecf20Sopenharmony_ci	debugfs_create_file_unsafe("gitm", 0400, d, data, &atk_debugfs_gitm);
7998c2ecf20Sopenharmony_ci	debugfs_create_file("ggrp", 0400, d, data, &atk_debugfs_ggrp_fops);
8008c2ecf20Sopenharmony_ci
8018c2ecf20Sopenharmony_ci	data->debugfs.root = d;
8028c2ecf20Sopenharmony_ci}
8038c2ecf20Sopenharmony_ci
8048c2ecf20Sopenharmony_cistatic void atk_debugfs_cleanup(struct atk_data *data)
8058c2ecf20Sopenharmony_ci{
8068c2ecf20Sopenharmony_ci	debugfs_remove_recursive(data->debugfs.root);
8078c2ecf20Sopenharmony_ci}
8088c2ecf20Sopenharmony_ci
8098c2ecf20Sopenharmony_ci#else /* CONFIG_DEBUG_FS */
8108c2ecf20Sopenharmony_ci
8118c2ecf20Sopenharmony_cistatic void atk_debugfs_init(struct atk_data *data)
8128c2ecf20Sopenharmony_ci{
8138c2ecf20Sopenharmony_ci}
8148c2ecf20Sopenharmony_ci
8158c2ecf20Sopenharmony_cistatic void atk_debugfs_cleanup(struct atk_data *data)
8168c2ecf20Sopenharmony_ci{
8178c2ecf20Sopenharmony_ci}
8188c2ecf20Sopenharmony_ci#endif
8198c2ecf20Sopenharmony_ci
8208c2ecf20Sopenharmony_cistatic int atk_add_sensor(struct atk_data *data, union acpi_object *obj)
8218c2ecf20Sopenharmony_ci{
8228c2ecf20Sopenharmony_ci	struct device *dev = &data->acpi_dev->dev;
8238c2ecf20Sopenharmony_ci	union acpi_object *flags;
8248c2ecf20Sopenharmony_ci	union acpi_object *name;
8258c2ecf20Sopenharmony_ci	union acpi_object *limit1;
8268c2ecf20Sopenharmony_ci	union acpi_object *limit2;
8278c2ecf20Sopenharmony_ci	union acpi_object *enable;
8288c2ecf20Sopenharmony_ci	struct atk_sensor_data *sensor;
8298c2ecf20Sopenharmony_ci	char const *base_name;
8308c2ecf20Sopenharmony_ci	char const *limit1_name;
8318c2ecf20Sopenharmony_ci	char const *limit2_name;
8328c2ecf20Sopenharmony_ci	u64 type;
8338c2ecf20Sopenharmony_ci	int err;
8348c2ecf20Sopenharmony_ci	int *num;
8358c2ecf20Sopenharmony_ci	int start;
8368c2ecf20Sopenharmony_ci
8378c2ecf20Sopenharmony_ci	if (obj->type != ACPI_TYPE_PACKAGE) {
8388c2ecf20Sopenharmony_ci		/* wft is this? */
8398c2ecf20Sopenharmony_ci		dev_warn(dev, "Unknown type for ACPI object: (%d)\n",
8408c2ecf20Sopenharmony_ci				obj->type);
8418c2ecf20Sopenharmony_ci		return -EINVAL;
8428c2ecf20Sopenharmony_ci	}
8438c2ecf20Sopenharmony_ci
8448c2ecf20Sopenharmony_ci	err = validate_hwmon_pack(data, obj);
8458c2ecf20Sopenharmony_ci	if (err)
8468c2ecf20Sopenharmony_ci		return err;
8478c2ecf20Sopenharmony_ci
8488c2ecf20Sopenharmony_ci	/* Ok, we have a valid hwmon package */
8498c2ecf20Sopenharmony_ci	type = atk_get_pack_member(data, obj, HWMON_PACK_FLAGS)->integer.value
8508c2ecf20Sopenharmony_ci	       & ATK_TYPE_MASK;
8518c2ecf20Sopenharmony_ci
8528c2ecf20Sopenharmony_ci	switch (type) {
8538c2ecf20Sopenharmony_ci	case HWMON_TYPE_VOLT:
8548c2ecf20Sopenharmony_ci		base_name = "in";
8558c2ecf20Sopenharmony_ci		limit1_name = "min";
8568c2ecf20Sopenharmony_ci		limit2_name = "max";
8578c2ecf20Sopenharmony_ci		num = &data->voltage_count;
8588c2ecf20Sopenharmony_ci		start = 0;
8598c2ecf20Sopenharmony_ci		break;
8608c2ecf20Sopenharmony_ci	case HWMON_TYPE_TEMP:
8618c2ecf20Sopenharmony_ci		base_name = "temp";
8628c2ecf20Sopenharmony_ci		limit1_name = "max";
8638c2ecf20Sopenharmony_ci		limit2_name = "crit";
8648c2ecf20Sopenharmony_ci		num = &data->temperature_count;
8658c2ecf20Sopenharmony_ci		start = 1;
8668c2ecf20Sopenharmony_ci		break;
8678c2ecf20Sopenharmony_ci	case HWMON_TYPE_FAN:
8688c2ecf20Sopenharmony_ci		base_name = "fan";
8698c2ecf20Sopenharmony_ci		limit1_name = "min";
8708c2ecf20Sopenharmony_ci		limit2_name = "max";
8718c2ecf20Sopenharmony_ci		num = &data->fan_count;
8728c2ecf20Sopenharmony_ci		start = 1;
8738c2ecf20Sopenharmony_ci		break;
8748c2ecf20Sopenharmony_ci	default:
8758c2ecf20Sopenharmony_ci		dev_warn(dev, "Unknown sensor type: %#llx\n", type);
8768c2ecf20Sopenharmony_ci		return -EINVAL;
8778c2ecf20Sopenharmony_ci	}
8788c2ecf20Sopenharmony_ci
8798c2ecf20Sopenharmony_ci	enable = atk_get_pack_member(data, obj, HWMON_PACK_ENABLE);
8808c2ecf20Sopenharmony_ci	if (!enable->integer.value)
8818c2ecf20Sopenharmony_ci		/* sensor is disabled */
8828c2ecf20Sopenharmony_ci		return 0;
8838c2ecf20Sopenharmony_ci
8848c2ecf20Sopenharmony_ci	flags = atk_get_pack_member(data, obj, HWMON_PACK_FLAGS);
8858c2ecf20Sopenharmony_ci	name = atk_get_pack_member(data, obj, HWMON_PACK_NAME);
8868c2ecf20Sopenharmony_ci	limit1 = atk_get_pack_member(data, obj, HWMON_PACK_LIMIT1);
8878c2ecf20Sopenharmony_ci	limit2 = atk_get_pack_member(data, obj, HWMON_PACK_LIMIT2);
8888c2ecf20Sopenharmony_ci
8898c2ecf20Sopenharmony_ci	sensor = devm_kzalloc(dev, sizeof(*sensor), GFP_KERNEL);
8908c2ecf20Sopenharmony_ci	if (!sensor)
8918c2ecf20Sopenharmony_ci		return -ENOMEM;
8928c2ecf20Sopenharmony_ci
8938c2ecf20Sopenharmony_ci	sensor->acpi_name = devm_kstrdup(dev, name->string.pointer, GFP_KERNEL);
8948c2ecf20Sopenharmony_ci	if (!sensor->acpi_name)
8958c2ecf20Sopenharmony_ci		return -ENOMEM;
8968c2ecf20Sopenharmony_ci
8978c2ecf20Sopenharmony_ci	INIT_LIST_HEAD(&sensor->list);
8988c2ecf20Sopenharmony_ci	sensor->type = type;
8998c2ecf20Sopenharmony_ci	sensor->data = data;
9008c2ecf20Sopenharmony_ci	sensor->id = flags->integer.value;
9018c2ecf20Sopenharmony_ci	sensor->limit1 = limit1->integer.value;
9028c2ecf20Sopenharmony_ci	if (data->old_interface)
9038c2ecf20Sopenharmony_ci		sensor->limit2 = limit2->integer.value;
9048c2ecf20Sopenharmony_ci	else
9058c2ecf20Sopenharmony_ci		/* The upper limit is expressed as delta from lower limit */
9068c2ecf20Sopenharmony_ci		sensor->limit2 = sensor->limit1 + limit2->integer.value;
9078c2ecf20Sopenharmony_ci
9088c2ecf20Sopenharmony_ci	snprintf(sensor->input_attr_name, ATTR_NAME_SIZE,
9098c2ecf20Sopenharmony_ci			"%s%d_input", base_name, start + *num);
9108c2ecf20Sopenharmony_ci	atk_init_attribute(&sensor->input_attr,
9118c2ecf20Sopenharmony_ci			sensor->input_attr_name,
9128c2ecf20Sopenharmony_ci			atk_input_show);
9138c2ecf20Sopenharmony_ci
9148c2ecf20Sopenharmony_ci	snprintf(sensor->label_attr_name, ATTR_NAME_SIZE,
9158c2ecf20Sopenharmony_ci			"%s%d_label", base_name, start + *num);
9168c2ecf20Sopenharmony_ci	atk_init_attribute(&sensor->label_attr,
9178c2ecf20Sopenharmony_ci			sensor->label_attr_name,
9188c2ecf20Sopenharmony_ci			atk_label_show);
9198c2ecf20Sopenharmony_ci
9208c2ecf20Sopenharmony_ci	snprintf(sensor->limit1_attr_name, ATTR_NAME_SIZE,
9218c2ecf20Sopenharmony_ci			"%s%d_%s", base_name, start + *num, limit1_name);
9228c2ecf20Sopenharmony_ci	atk_init_attribute(&sensor->limit1_attr,
9238c2ecf20Sopenharmony_ci			sensor->limit1_attr_name,
9248c2ecf20Sopenharmony_ci			atk_limit1_show);
9258c2ecf20Sopenharmony_ci
9268c2ecf20Sopenharmony_ci	snprintf(sensor->limit2_attr_name, ATTR_NAME_SIZE,
9278c2ecf20Sopenharmony_ci			"%s%d_%s", base_name, start + *num, limit2_name);
9288c2ecf20Sopenharmony_ci	atk_init_attribute(&sensor->limit2_attr,
9298c2ecf20Sopenharmony_ci			sensor->limit2_attr_name,
9308c2ecf20Sopenharmony_ci			atk_limit2_show);
9318c2ecf20Sopenharmony_ci
9328c2ecf20Sopenharmony_ci	list_add(&sensor->list, &data->sensor_list);
9338c2ecf20Sopenharmony_ci	(*num)++;
9348c2ecf20Sopenharmony_ci
9358c2ecf20Sopenharmony_ci	return 1;
9368c2ecf20Sopenharmony_ci}
9378c2ecf20Sopenharmony_ci
9388c2ecf20Sopenharmony_cistatic int atk_enumerate_old_hwmon(struct atk_data *data)
9398c2ecf20Sopenharmony_ci{
9408c2ecf20Sopenharmony_ci	struct device *dev = &data->acpi_dev->dev;
9418c2ecf20Sopenharmony_ci	struct acpi_buffer buf;
9428c2ecf20Sopenharmony_ci	union acpi_object *pack;
9438c2ecf20Sopenharmony_ci	acpi_status status;
9448c2ecf20Sopenharmony_ci	int i, ret;
9458c2ecf20Sopenharmony_ci	int count = 0;
9468c2ecf20Sopenharmony_ci
9478c2ecf20Sopenharmony_ci	/* Voltages */
9488c2ecf20Sopenharmony_ci	buf.length = ACPI_ALLOCATE_BUFFER;
9498c2ecf20Sopenharmony_ci	status = acpi_evaluate_object_typed(data->atk_handle,
9508c2ecf20Sopenharmony_ci			METHOD_OLD_ENUM_VLT, NULL, &buf, ACPI_TYPE_PACKAGE);
9518c2ecf20Sopenharmony_ci	if (status != AE_OK) {
9528c2ecf20Sopenharmony_ci		dev_warn(dev, METHOD_OLD_ENUM_VLT ": ACPI exception: %s\n",
9538c2ecf20Sopenharmony_ci				acpi_format_exception(status));
9548c2ecf20Sopenharmony_ci
9558c2ecf20Sopenharmony_ci		return -ENODEV;
9568c2ecf20Sopenharmony_ci	}
9578c2ecf20Sopenharmony_ci
9588c2ecf20Sopenharmony_ci	pack = buf.pointer;
9598c2ecf20Sopenharmony_ci	for (i = 1; i < pack->package.count; i++) {
9608c2ecf20Sopenharmony_ci		union acpi_object *obj = &pack->package.elements[i];
9618c2ecf20Sopenharmony_ci
9628c2ecf20Sopenharmony_ci		ret = atk_add_sensor(data, obj);
9638c2ecf20Sopenharmony_ci		if (ret > 0)
9648c2ecf20Sopenharmony_ci			count++;
9658c2ecf20Sopenharmony_ci	}
9668c2ecf20Sopenharmony_ci	ACPI_FREE(buf.pointer);
9678c2ecf20Sopenharmony_ci
9688c2ecf20Sopenharmony_ci	/* Temperatures */
9698c2ecf20Sopenharmony_ci	buf.length = ACPI_ALLOCATE_BUFFER;
9708c2ecf20Sopenharmony_ci	status = acpi_evaluate_object_typed(data->atk_handle,
9718c2ecf20Sopenharmony_ci			METHOD_OLD_ENUM_TMP, NULL, &buf, ACPI_TYPE_PACKAGE);
9728c2ecf20Sopenharmony_ci	if (status != AE_OK) {
9738c2ecf20Sopenharmony_ci		dev_warn(dev, METHOD_OLD_ENUM_TMP ": ACPI exception: %s\n",
9748c2ecf20Sopenharmony_ci				acpi_format_exception(status));
9758c2ecf20Sopenharmony_ci
9768c2ecf20Sopenharmony_ci		return -ENODEV;
9778c2ecf20Sopenharmony_ci	}
9788c2ecf20Sopenharmony_ci
9798c2ecf20Sopenharmony_ci	pack = buf.pointer;
9808c2ecf20Sopenharmony_ci	for (i = 1; i < pack->package.count; i++) {
9818c2ecf20Sopenharmony_ci		union acpi_object *obj = &pack->package.elements[i];
9828c2ecf20Sopenharmony_ci
9838c2ecf20Sopenharmony_ci		ret = atk_add_sensor(data, obj);
9848c2ecf20Sopenharmony_ci		if (ret > 0)
9858c2ecf20Sopenharmony_ci			count++;
9868c2ecf20Sopenharmony_ci	}
9878c2ecf20Sopenharmony_ci	ACPI_FREE(buf.pointer);
9888c2ecf20Sopenharmony_ci
9898c2ecf20Sopenharmony_ci	/* Fans */
9908c2ecf20Sopenharmony_ci	buf.length = ACPI_ALLOCATE_BUFFER;
9918c2ecf20Sopenharmony_ci	status = acpi_evaluate_object_typed(data->atk_handle,
9928c2ecf20Sopenharmony_ci			METHOD_OLD_ENUM_FAN, NULL, &buf, ACPI_TYPE_PACKAGE);
9938c2ecf20Sopenharmony_ci	if (status != AE_OK) {
9948c2ecf20Sopenharmony_ci		dev_warn(dev, METHOD_OLD_ENUM_FAN ": ACPI exception: %s\n",
9958c2ecf20Sopenharmony_ci				acpi_format_exception(status));
9968c2ecf20Sopenharmony_ci
9978c2ecf20Sopenharmony_ci		return -ENODEV;
9988c2ecf20Sopenharmony_ci	}
9998c2ecf20Sopenharmony_ci
10008c2ecf20Sopenharmony_ci	pack = buf.pointer;
10018c2ecf20Sopenharmony_ci	for (i = 1; i < pack->package.count; i++) {
10028c2ecf20Sopenharmony_ci		union acpi_object *obj = &pack->package.elements[i];
10038c2ecf20Sopenharmony_ci
10048c2ecf20Sopenharmony_ci		ret = atk_add_sensor(data, obj);
10058c2ecf20Sopenharmony_ci		if (ret > 0)
10068c2ecf20Sopenharmony_ci			count++;
10078c2ecf20Sopenharmony_ci	}
10088c2ecf20Sopenharmony_ci	ACPI_FREE(buf.pointer);
10098c2ecf20Sopenharmony_ci
10108c2ecf20Sopenharmony_ci	return count;
10118c2ecf20Sopenharmony_ci}
10128c2ecf20Sopenharmony_ci
10138c2ecf20Sopenharmony_cistatic int atk_ec_present(struct atk_data *data)
10148c2ecf20Sopenharmony_ci{
10158c2ecf20Sopenharmony_ci	struct device *dev = &data->acpi_dev->dev;
10168c2ecf20Sopenharmony_ci	union acpi_object *pack;
10178c2ecf20Sopenharmony_ci	union acpi_object *ec;
10188c2ecf20Sopenharmony_ci	int ret;
10198c2ecf20Sopenharmony_ci	int i;
10208c2ecf20Sopenharmony_ci
10218c2ecf20Sopenharmony_ci	pack = atk_ggrp(data, ATK_MUX_MGMT);
10228c2ecf20Sopenharmony_ci	if (IS_ERR(pack)) {
10238c2ecf20Sopenharmony_ci		if (PTR_ERR(pack) == -ENOENT) {
10248c2ecf20Sopenharmony_ci			/* The MGMT class does not exists - that's ok */
10258c2ecf20Sopenharmony_ci			dev_dbg(dev, "Class %#llx not found\n", ATK_MUX_MGMT);
10268c2ecf20Sopenharmony_ci			return 0;
10278c2ecf20Sopenharmony_ci		}
10288c2ecf20Sopenharmony_ci		return PTR_ERR(pack);
10298c2ecf20Sopenharmony_ci	}
10308c2ecf20Sopenharmony_ci
10318c2ecf20Sopenharmony_ci	/* Search the EC */
10328c2ecf20Sopenharmony_ci	ec = NULL;
10338c2ecf20Sopenharmony_ci	for (i = 0; i < pack->package.count; i++) {
10348c2ecf20Sopenharmony_ci		union acpi_object *obj = &pack->package.elements[i];
10358c2ecf20Sopenharmony_ci		union acpi_object *id;
10368c2ecf20Sopenharmony_ci
10378c2ecf20Sopenharmony_ci		if (obj->type != ACPI_TYPE_PACKAGE)
10388c2ecf20Sopenharmony_ci			continue;
10398c2ecf20Sopenharmony_ci
10408c2ecf20Sopenharmony_ci		id = &obj->package.elements[0];
10418c2ecf20Sopenharmony_ci		if (id->type != ACPI_TYPE_INTEGER)
10428c2ecf20Sopenharmony_ci			continue;
10438c2ecf20Sopenharmony_ci
10448c2ecf20Sopenharmony_ci		if (id->integer.value == ATK_EC_ID) {
10458c2ecf20Sopenharmony_ci			ec = obj;
10468c2ecf20Sopenharmony_ci			break;
10478c2ecf20Sopenharmony_ci		}
10488c2ecf20Sopenharmony_ci	}
10498c2ecf20Sopenharmony_ci
10508c2ecf20Sopenharmony_ci	ret = (ec != NULL);
10518c2ecf20Sopenharmony_ci	if (!ret)
10528c2ecf20Sopenharmony_ci		/* The system has no EC */
10538c2ecf20Sopenharmony_ci		dev_dbg(dev, "EC not found\n");
10548c2ecf20Sopenharmony_ci
10558c2ecf20Sopenharmony_ci	ACPI_FREE(pack);
10568c2ecf20Sopenharmony_ci	return ret;
10578c2ecf20Sopenharmony_ci}
10588c2ecf20Sopenharmony_ci
10598c2ecf20Sopenharmony_cistatic int atk_ec_enabled(struct atk_data *data)
10608c2ecf20Sopenharmony_ci{
10618c2ecf20Sopenharmony_ci	struct device *dev = &data->acpi_dev->dev;
10628c2ecf20Sopenharmony_ci	union acpi_object *obj;
10638c2ecf20Sopenharmony_ci	struct atk_acpi_ret_buffer *buf;
10648c2ecf20Sopenharmony_ci	int err;
10658c2ecf20Sopenharmony_ci
10668c2ecf20Sopenharmony_ci	obj = atk_gitm(data, ATK_EC_ID);
10678c2ecf20Sopenharmony_ci	if (IS_ERR(obj)) {
10688c2ecf20Sopenharmony_ci		dev_err(dev, "Unable to query EC status\n");
10698c2ecf20Sopenharmony_ci		return PTR_ERR(obj);
10708c2ecf20Sopenharmony_ci	}
10718c2ecf20Sopenharmony_ci	buf = (struct atk_acpi_ret_buffer *)obj->buffer.pointer;
10728c2ecf20Sopenharmony_ci
10738c2ecf20Sopenharmony_ci	if (buf->flags == 0) {
10748c2ecf20Sopenharmony_ci		dev_err(dev, "Unable to query EC status\n");
10758c2ecf20Sopenharmony_ci		err = -EIO;
10768c2ecf20Sopenharmony_ci	} else {
10778c2ecf20Sopenharmony_ci		err = (buf->value != 0);
10788c2ecf20Sopenharmony_ci		dev_dbg(dev, "EC is %sabled\n",
10798c2ecf20Sopenharmony_ci				err ? "en" : "dis");
10808c2ecf20Sopenharmony_ci	}
10818c2ecf20Sopenharmony_ci
10828c2ecf20Sopenharmony_ci	ACPI_FREE(obj);
10838c2ecf20Sopenharmony_ci	return err;
10848c2ecf20Sopenharmony_ci}
10858c2ecf20Sopenharmony_ci
10868c2ecf20Sopenharmony_cistatic int atk_ec_ctl(struct atk_data *data, int enable)
10878c2ecf20Sopenharmony_ci{
10888c2ecf20Sopenharmony_ci	struct device *dev = &data->acpi_dev->dev;
10898c2ecf20Sopenharmony_ci	union acpi_object *obj;
10908c2ecf20Sopenharmony_ci	struct atk_acpi_input_buf sitm;
10918c2ecf20Sopenharmony_ci	struct atk_acpi_ret_buffer *ec_ret;
10928c2ecf20Sopenharmony_ci	int err = 0;
10938c2ecf20Sopenharmony_ci
10948c2ecf20Sopenharmony_ci	sitm.id = ATK_EC_ID;
10958c2ecf20Sopenharmony_ci	sitm.param1 = enable;
10968c2ecf20Sopenharmony_ci	sitm.param2 = 0;
10978c2ecf20Sopenharmony_ci
10988c2ecf20Sopenharmony_ci	obj = atk_sitm(data, &sitm);
10998c2ecf20Sopenharmony_ci	if (IS_ERR(obj)) {
11008c2ecf20Sopenharmony_ci		dev_err(dev, "Failed to %sable the EC\n",
11018c2ecf20Sopenharmony_ci				enable ? "en" : "dis");
11028c2ecf20Sopenharmony_ci		return PTR_ERR(obj);
11038c2ecf20Sopenharmony_ci	}
11048c2ecf20Sopenharmony_ci	ec_ret = (struct atk_acpi_ret_buffer *)obj->buffer.pointer;
11058c2ecf20Sopenharmony_ci	if (ec_ret->flags == 0) {
11068c2ecf20Sopenharmony_ci		dev_err(dev, "Failed to %sable the EC\n",
11078c2ecf20Sopenharmony_ci				enable ? "en" : "dis");
11088c2ecf20Sopenharmony_ci		err = -EIO;
11098c2ecf20Sopenharmony_ci	} else {
11108c2ecf20Sopenharmony_ci		dev_info(dev, "EC %sabled\n",
11118c2ecf20Sopenharmony_ci				enable ? "en" : "dis");
11128c2ecf20Sopenharmony_ci	}
11138c2ecf20Sopenharmony_ci
11148c2ecf20Sopenharmony_ci	ACPI_FREE(obj);
11158c2ecf20Sopenharmony_ci	return err;
11168c2ecf20Sopenharmony_ci}
11178c2ecf20Sopenharmony_ci
11188c2ecf20Sopenharmony_cistatic int atk_enumerate_new_hwmon(struct atk_data *data)
11198c2ecf20Sopenharmony_ci{
11208c2ecf20Sopenharmony_ci	struct device *dev = &data->acpi_dev->dev;
11218c2ecf20Sopenharmony_ci	union acpi_object *pack;
11228c2ecf20Sopenharmony_ci	int err;
11238c2ecf20Sopenharmony_ci	int i;
11248c2ecf20Sopenharmony_ci
11258c2ecf20Sopenharmony_ci	err = atk_ec_present(data);
11268c2ecf20Sopenharmony_ci	if (err < 0)
11278c2ecf20Sopenharmony_ci		return err;
11288c2ecf20Sopenharmony_ci	if (err) {
11298c2ecf20Sopenharmony_ci		err = atk_ec_enabled(data);
11308c2ecf20Sopenharmony_ci		if (err < 0)
11318c2ecf20Sopenharmony_ci			return err;
11328c2ecf20Sopenharmony_ci		/* If the EC was disabled we will disable it again on unload */
11338c2ecf20Sopenharmony_ci		data->disable_ec = err;
11348c2ecf20Sopenharmony_ci
11358c2ecf20Sopenharmony_ci		err = atk_ec_ctl(data, 1);
11368c2ecf20Sopenharmony_ci		if (err) {
11378c2ecf20Sopenharmony_ci			data->disable_ec = false;
11388c2ecf20Sopenharmony_ci			return err;
11398c2ecf20Sopenharmony_ci		}
11408c2ecf20Sopenharmony_ci	}
11418c2ecf20Sopenharmony_ci
11428c2ecf20Sopenharmony_ci	dev_dbg(dev, "Enumerating hwmon sensors\n");
11438c2ecf20Sopenharmony_ci
11448c2ecf20Sopenharmony_ci	pack = atk_ggrp(data, ATK_MUX_HWMON);
11458c2ecf20Sopenharmony_ci	if (IS_ERR(pack))
11468c2ecf20Sopenharmony_ci		return PTR_ERR(pack);
11478c2ecf20Sopenharmony_ci
11488c2ecf20Sopenharmony_ci	for (i = 0; i < pack->package.count; i++) {
11498c2ecf20Sopenharmony_ci		union acpi_object *obj = &pack->package.elements[i];
11508c2ecf20Sopenharmony_ci
11518c2ecf20Sopenharmony_ci		atk_add_sensor(data, obj);
11528c2ecf20Sopenharmony_ci	}
11538c2ecf20Sopenharmony_ci
11548c2ecf20Sopenharmony_ci	err = data->voltage_count + data->temperature_count + data->fan_count;
11558c2ecf20Sopenharmony_ci
11568c2ecf20Sopenharmony_ci	ACPI_FREE(pack);
11578c2ecf20Sopenharmony_ci	return err;
11588c2ecf20Sopenharmony_ci}
11598c2ecf20Sopenharmony_ci
11608c2ecf20Sopenharmony_cistatic int atk_init_attribute_groups(struct atk_data *data)
11618c2ecf20Sopenharmony_ci{
11628c2ecf20Sopenharmony_ci	struct device *dev = &data->acpi_dev->dev;
11638c2ecf20Sopenharmony_ci	struct atk_sensor_data *s;
11648c2ecf20Sopenharmony_ci	struct attribute **attrs;
11658c2ecf20Sopenharmony_ci	int i = 0;
11668c2ecf20Sopenharmony_ci	int len = (data->voltage_count + data->temperature_count
11678c2ecf20Sopenharmony_ci			+ data->fan_count) * 4 + 1;
11688c2ecf20Sopenharmony_ci
11698c2ecf20Sopenharmony_ci	attrs = devm_kcalloc(dev, len, sizeof(struct attribute *), GFP_KERNEL);
11708c2ecf20Sopenharmony_ci	if (!attrs)
11718c2ecf20Sopenharmony_ci		return -ENOMEM;
11728c2ecf20Sopenharmony_ci
11738c2ecf20Sopenharmony_ci	list_for_each_entry(s, &data->sensor_list, list) {
11748c2ecf20Sopenharmony_ci		attrs[i++] = &s->input_attr.attr;
11758c2ecf20Sopenharmony_ci		attrs[i++] = &s->label_attr.attr;
11768c2ecf20Sopenharmony_ci		attrs[i++] = &s->limit1_attr.attr;
11778c2ecf20Sopenharmony_ci		attrs[i++] = &s->limit2_attr.attr;
11788c2ecf20Sopenharmony_ci	}
11798c2ecf20Sopenharmony_ci
11808c2ecf20Sopenharmony_ci	data->attr_group.attrs = attrs;
11818c2ecf20Sopenharmony_ci	data->attr_groups[0] = &data->attr_group;
11828c2ecf20Sopenharmony_ci
11838c2ecf20Sopenharmony_ci	return 0;
11848c2ecf20Sopenharmony_ci}
11858c2ecf20Sopenharmony_ci
11868c2ecf20Sopenharmony_cistatic int atk_register_hwmon(struct atk_data *data)
11878c2ecf20Sopenharmony_ci{
11888c2ecf20Sopenharmony_ci	struct device *dev = &data->acpi_dev->dev;
11898c2ecf20Sopenharmony_ci
11908c2ecf20Sopenharmony_ci	dev_dbg(dev, "registering hwmon device\n");
11918c2ecf20Sopenharmony_ci	data->hwmon_dev = hwmon_device_register_with_groups(dev, "atk0110",
11928c2ecf20Sopenharmony_ci							    data,
11938c2ecf20Sopenharmony_ci							    data->attr_groups);
11948c2ecf20Sopenharmony_ci
11958c2ecf20Sopenharmony_ci	return PTR_ERR_OR_ZERO(data->hwmon_dev);
11968c2ecf20Sopenharmony_ci}
11978c2ecf20Sopenharmony_ci
11988c2ecf20Sopenharmony_cistatic int atk_probe_if(struct atk_data *data)
11998c2ecf20Sopenharmony_ci{
12008c2ecf20Sopenharmony_ci	struct device *dev = &data->acpi_dev->dev;
12018c2ecf20Sopenharmony_ci	acpi_handle ret;
12028c2ecf20Sopenharmony_ci	acpi_status status;
12038c2ecf20Sopenharmony_ci	int err = 0;
12048c2ecf20Sopenharmony_ci
12058c2ecf20Sopenharmony_ci	/* RTMP: read temperature */
12068c2ecf20Sopenharmony_ci	status = acpi_get_handle(data->atk_handle, METHOD_OLD_READ_TMP, &ret);
12078c2ecf20Sopenharmony_ci	if (ACPI_SUCCESS(status))
12088c2ecf20Sopenharmony_ci		data->rtmp_handle = ret;
12098c2ecf20Sopenharmony_ci	else
12108c2ecf20Sopenharmony_ci		dev_dbg(dev, "method " METHOD_OLD_READ_TMP " not found: %s\n",
12118c2ecf20Sopenharmony_ci				acpi_format_exception(status));
12128c2ecf20Sopenharmony_ci
12138c2ecf20Sopenharmony_ci	/* RVLT: read voltage */
12148c2ecf20Sopenharmony_ci	status = acpi_get_handle(data->atk_handle, METHOD_OLD_READ_VLT, &ret);
12158c2ecf20Sopenharmony_ci	if (ACPI_SUCCESS(status))
12168c2ecf20Sopenharmony_ci		data->rvlt_handle = ret;
12178c2ecf20Sopenharmony_ci	else
12188c2ecf20Sopenharmony_ci		dev_dbg(dev, "method " METHOD_OLD_READ_VLT " not found: %s\n",
12198c2ecf20Sopenharmony_ci				acpi_format_exception(status));
12208c2ecf20Sopenharmony_ci
12218c2ecf20Sopenharmony_ci	/* RFAN: read fan status */
12228c2ecf20Sopenharmony_ci	status = acpi_get_handle(data->atk_handle, METHOD_OLD_READ_FAN, &ret);
12238c2ecf20Sopenharmony_ci	if (ACPI_SUCCESS(status))
12248c2ecf20Sopenharmony_ci		data->rfan_handle = ret;
12258c2ecf20Sopenharmony_ci	else
12268c2ecf20Sopenharmony_ci		dev_dbg(dev, "method " METHOD_OLD_READ_FAN " not found: %s\n",
12278c2ecf20Sopenharmony_ci				acpi_format_exception(status));
12288c2ecf20Sopenharmony_ci
12298c2ecf20Sopenharmony_ci	/* Enumeration */
12308c2ecf20Sopenharmony_ci	status = acpi_get_handle(data->atk_handle, METHOD_ENUMERATE, &ret);
12318c2ecf20Sopenharmony_ci	if (ACPI_SUCCESS(status))
12328c2ecf20Sopenharmony_ci		data->enumerate_handle = ret;
12338c2ecf20Sopenharmony_ci	else
12348c2ecf20Sopenharmony_ci		dev_dbg(dev, "method " METHOD_ENUMERATE " not found: %s\n",
12358c2ecf20Sopenharmony_ci				acpi_format_exception(status));
12368c2ecf20Sopenharmony_ci
12378c2ecf20Sopenharmony_ci	/* De-multiplexer (read) */
12388c2ecf20Sopenharmony_ci	status = acpi_get_handle(data->atk_handle, METHOD_READ, &ret);
12398c2ecf20Sopenharmony_ci	if (ACPI_SUCCESS(status))
12408c2ecf20Sopenharmony_ci		data->read_handle = ret;
12418c2ecf20Sopenharmony_ci	else
12428c2ecf20Sopenharmony_ci		dev_dbg(dev, "method " METHOD_READ " not found: %s\n",
12438c2ecf20Sopenharmony_ci				acpi_format_exception(status));
12448c2ecf20Sopenharmony_ci
12458c2ecf20Sopenharmony_ci	/* De-multiplexer (write) */
12468c2ecf20Sopenharmony_ci	status = acpi_get_handle(data->atk_handle, METHOD_WRITE, &ret);
12478c2ecf20Sopenharmony_ci	if (ACPI_SUCCESS(status))
12488c2ecf20Sopenharmony_ci		data->write_handle = ret;
12498c2ecf20Sopenharmony_ci	else
12508c2ecf20Sopenharmony_ci		dev_dbg(dev, "method " METHOD_WRITE " not found: %s\n",
12518c2ecf20Sopenharmony_ci				 acpi_format_exception(status));
12528c2ecf20Sopenharmony_ci
12538c2ecf20Sopenharmony_ci	/*
12548c2ecf20Sopenharmony_ci	 * Check for hwmon methods: first check "old" style methods; note that
12558c2ecf20Sopenharmony_ci	 * both may be present: in this case we stick to the old interface;
12568c2ecf20Sopenharmony_ci	 * analysis of multiple DSDTs indicates that when both interfaces
12578c2ecf20Sopenharmony_ci	 * are present the new one (GGRP/GITM) is not functional.
12588c2ecf20Sopenharmony_ci	 */
12598c2ecf20Sopenharmony_ci	if (new_if)
12608c2ecf20Sopenharmony_ci		dev_info(dev, "Overriding interface detection\n");
12618c2ecf20Sopenharmony_ci	if (data->rtmp_handle &&
12628c2ecf20Sopenharmony_ci			data->rvlt_handle && data->rfan_handle && !new_if)
12638c2ecf20Sopenharmony_ci		data->old_interface = true;
12648c2ecf20Sopenharmony_ci	else if (data->enumerate_handle && data->read_handle &&
12658c2ecf20Sopenharmony_ci			data->write_handle)
12668c2ecf20Sopenharmony_ci		data->old_interface = false;
12678c2ecf20Sopenharmony_ci	else
12688c2ecf20Sopenharmony_ci		err = -ENODEV;
12698c2ecf20Sopenharmony_ci
12708c2ecf20Sopenharmony_ci	return err;
12718c2ecf20Sopenharmony_ci}
12728c2ecf20Sopenharmony_ci
12738c2ecf20Sopenharmony_cistatic int atk_add(struct acpi_device *device)
12748c2ecf20Sopenharmony_ci{
12758c2ecf20Sopenharmony_ci	acpi_status ret;
12768c2ecf20Sopenharmony_ci	int err;
12778c2ecf20Sopenharmony_ci	struct acpi_buffer buf;
12788c2ecf20Sopenharmony_ci	union acpi_object *obj;
12798c2ecf20Sopenharmony_ci	struct atk_data *data;
12808c2ecf20Sopenharmony_ci
12818c2ecf20Sopenharmony_ci	dev_dbg(&device->dev, "adding...\n");
12828c2ecf20Sopenharmony_ci
12838c2ecf20Sopenharmony_ci	data = devm_kzalloc(&device->dev, sizeof(*data), GFP_KERNEL);
12848c2ecf20Sopenharmony_ci	if (!data)
12858c2ecf20Sopenharmony_ci		return -ENOMEM;
12868c2ecf20Sopenharmony_ci
12878c2ecf20Sopenharmony_ci	data->acpi_dev = device;
12888c2ecf20Sopenharmony_ci	data->atk_handle = device->handle;
12898c2ecf20Sopenharmony_ci	INIT_LIST_HEAD(&data->sensor_list);
12908c2ecf20Sopenharmony_ci	data->disable_ec = false;
12918c2ecf20Sopenharmony_ci
12928c2ecf20Sopenharmony_ci	buf.length = ACPI_ALLOCATE_BUFFER;
12938c2ecf20Sopenharmony_ci	ret = acpi_evaluate_object_typed(data->atk_handle, BOARD_ID, NULL,
12948c2ecf20Sopenharmony_ci			&buf, ACPI_TYPE_PACKAGE);
12958c2ecf20Sopenharmony_ci	if (ret != AE_OK) {
12968c2ecf20Sopenharmony_ci		dev_dbg(&device->dev, "atk: method MBIF not found\n");
12978c2ecf20Sopenharmony_ci	} else {
12988c2ecf20Sopenharmony_ci		obj = buf.pointer;
12998c2ecf20Sopenharmony_ci		if (obj->package.count >= 2) {
13008c2ecf20Sopenharmony_ci			union acpi_object *id = &obj->package.elements[1];
13018c2ecf20Sopenharmony_ci			if (id->type == ACPI_TYPE_STRING)
13028c2ecf20Sopenharmony_ci				dev_dbg(&device->dev, "board ID = %s\n",
13038c2ecf20Sopenharmony_ci					id->string.pointer);
13048c2ecf20Sopenharmony_ci		}
13058c2ecf20Sopenharmony_ci		ACPI_FREE(buf.pointer);
13068c2ecf20Sopenharmony_ci	}
13078c2ecf20Sopenharmony_ci
13088c2ecf20Sopenharmony_ci	err = atk_probe_if(data);
13098c2ecf20Sopenharmony_ci	if (err) {
13108c2ecf20Sopenharmony_ci		dev_err(&device->dev, "No usable hwmon interface detected\n");
13118c2ecf20Sopenharmony_ci		goto out;
13128c2ecf20Sopenharmony_ci	}
13138c2ecf20Sopenharmony_ci
13148c2ecf20Sopenharmony_ci	if (data->old_interface) {
13158c2ecf20Sopenharmony_ci		dev_dbg(&device->dev, "Using old hwmon interface\n");
13168c2ecf20Sopenharmony_ci		err = atk_enumerate_old_hwmon(data);
13178c2ecf20Sopenharmony_ci	} else {
13188c2ecf20Sopenharmony_ci		dev_dbg(&device->dev, "Using new hwmon interface\n");
13198c2ecf20Sopenharmony_ci		err = atk_enumerate_new_hwmon(data);
13208c2ecf20Sopenharmony_ci	}
13218c2ecf20Sopenharmony_ci	if (err < 0)
13228c2ecf20Sopenharmony_ci		goto out;
13238c2ecf20Sopenharmony_ci	if (err == 0) {
13248c2ecf20Sopenharmony_ci		dev_info(&device->dev,
13258c2ecf20Sopenharmony_ci			 "No usable sensor detected, bailing out\n");
13268c2ecf20Sopenharmony_ci		err = -ENODEV;
13278c2ecf20Sopenharmony_ci		goto out;
13288c2ecf20Sopenharmony_ci	}
13298c2ecf20Sopenharmony_ci
13308c2ecf20Sopenharmony_ci	err = atk_init_attribute_groups(data);
13318c2ecf20Sopenharmony_ci	if (err)
13328c2ecf20Sopenharmony_ci		goto out;
13338c2ecf20Sopenharmony_ci	err = atk_register_hwmon(data);
13348c2ecf20Sopenharmony_ci	if (err)
13358c2ecf20Sopenharmony_ci		goto out;
13368c2ecf20Sopenharmony_ci
13378c2ecf20Sopenharmony_ci	atk_debugfs_init(data);
13388c2ecf20Sopenharmony_ci
13398c2ecf20Sopenharmony_ci	device->driver_data = data;
13408c2ecf20Sopenharmony_ci	return 0;
13418c2ecf20Sopenharmony_ciout:
13428c2ecf20Sopenharmony_ci	if (data->disable_ec)
13438c2ecf20Sopenharmony_ci		atk_ec_ctl(data, 0);
13448c2ecf20Sopenharmony_ci	return err;
13458c2ecf20Sopenharmony_ci}
13468c2ecf20Sopenharmony_ci
13478c2ecf20Sopenharmony_cistatic int atk_remove(struct acpi_device *device)
13488c2ecf20Sopenharmony_ci{
13498c2ecf20Sopenharmony_ci	struct atk_data *data = device->driver_data;
13508c2ecf20Sopenharmony_ci	dev_dbg(&device->dev, "removing...\n");
13518c2ecf20Sopenharmony_ci
13528c2ecf20Sopenharmony_ci	device->driver_data = NULL;
13538c2ecf20Sopenharmony_ci
13548c2ecf20Sopenharmony_ci	atk_debugfs_cleanup(data);
13558c2ecf20Sopenharmony_ci
13568c2ecf20Sopenharmony_ci	hwmon_device_unregister(data->hwmon_dev);
13578c2ecf20Sopenharmony_ci
13588c2ecf20Sopenharmony_ci	if (data->disable_ec) {
13598c2ecf20Sopenharmony_ci		if (atk_ec_ctl(data, 0))
13608c2ecf20Sopenharmony_ci			dev_err(&device->dev, "Failed to disable EC\n");
13618c2ecf20Sopenharmony_ci	}
13628c2ecf20Sopenharmony_ci
13638c2ecf20Sopenharmony_ci	return 0;
13648c2ecf20Sopenharmony_ci}
13658c2ecf20Sopenharmony_ci
13668c2ecf20Sopenharmony_cistatic int __init atk0110_init(void)
13678c2ecf20Sopenharmony_ci{
13688c2ecf20Sopenharmony_ci	int ret;
13698c2ecf20Sopenharmony_ci
13708c2ecf20Sopenharmony_ci	/* Make sure it's safe to access the device through ACPI */
13718c2ecf20Sopenharmony_ci	if (!acpi_resources_are_enforced()) {
13728c2ecf20Sopenharmony_ci		pr_err("Resources not safely usable due to acpi_enforce_resources kernel parameter\n");
13738c2ecf20Sopenharmony_ci		return -EBUSY;
13748c2ecf20Sopenharmony_ci	}
13758c2ecf20Sopenharmony_ci
13768c2ecf20Sopenharmony_ci	if (dmi_check_system(atk_force_new_if))
13778c2ecf20Sopenharmony_ci		new_if = true;
13788c2ecf20Sopenharmony_ci
13798c2ecf20Sopenharmony_ci	ret = acpi_bus_register_driver(&atk_driver);
13808c2ecf20Sopenharmony_ci	if (ret)
13818c2ecf20Sopenharmony_ci		pr_info("acpi_bus_register_driver failed: %d\n", ret);
13828c2ecf20Sopenharmony_ci
13838c2ecf20Sopenharmony_ci	return ret;
13848c2ecf20Sopenharmony_ci}
13858c2ecf20Sopenharmony_ci
13868c2ecf20Sopenharmony_cistatic void __exit atk0110_exit(void)
13878c2ecf20Sopenharmony_ci{
13888c2ecf20Sopenharmony_ci	acpi_bus_unregister_driver(&atk_driver);
13898c2ecf20Sopenharmony_ci}
13908c2ecf20Sopenharmony_ci
13918c2ecf20Sopenharmony_cimodule_init(atk0110_init);
13928c2ecf20Sopenharmony_cimodule_exit(atk0110_exit);
13938c2ecf20Sopenharmony_ci
13948c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL");
1395