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