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, ¶ms, 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, ¶ms, &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, ¶ms, 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, ¶ms, 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