12c03d07aSLuca Tettamanti /* 22c03d07aSLuca Tettamanti * Copyright (C) 2007-2009 Luca Tettamanti <kronos.it@gmail.com> 32c03d07aSLuca Tettamanti * 42c03d07aSLuca Tettamanti * This file is released under the GPLv2 52c03d07aSLuca Tettamanti * See COPYING in the top level directory of the kernel tree. 62c03d07aSLuca Tettamanti */ 72c03d07aSLuca Tettamanti 82c03d07aSLuca Tettamanti #include <linux/kernel.h> 92c03d07aSLuca Tettamanti #include <linux/hwmon.h> 102c03d07aSLuca Tettamanti #include <linux/list.h> 112c03d07aSLuca Tettamanti #include <linux/module.h> 122c03d07aSLuca Tettamanti 132c03d07aSLuca Tettamanti #include <acpi/acpi.h> 142c03d07aSLuca Tettamanti #include <acpi/acpixf.h> 152c03d07aSLuca Tettamanti #include <acpi/acpi_drivers.h> 162c03d07aSLuca Tettamanti #include <acpi/acpi_bus.h> 172c03d07aSLuca Tettamanti 182c03d07aSLuca Tettamanti 192c03d07aSLuca Tettamanti #define ATK_HID "ATK0110" 202c03d07aSLuca Tettamanti 212c03d07aSLuca Tettamanti /* Minimum time between readings, enforced in order to avoid 222c03d07aSLuca Tettamanti * hogging the CPU. 232c03d07aSLuca Tettamanti */ 242c03d07aSLuca Tettamanti #define CACHE_TIME HZ 252c03d07aSLuca Tettamanti 262c03d07aSLuca Tettamanti #define BOARD_ID "MBIF" 272c03d07aSLuca Tettamanti #define METHOD_ENUMERATE "GGRP" 282c03d07aSLuca Tettamanti #define METHOD_READ "GITM" 292c03d07aSLuca Tettamanti #define METHOD_WRITE "SITM" 302c03d07aSLuca Tettamanti #define METHOD_OLD_READ_TMP "RTMP" 312c03d07aSLuca Tettamanti #define METHOD_OLD_READ_VLT "RVLT" 322c03d07aSLuca Tettamanti #define METHOD_OLD_READ_FAN "RFAN" 332c03d07aSLuca Tettamanti #define METHOD_OLD_ENUM_TMP "TSIF" 342c03d07aSLuca Tettamanti #define METHOD_OLD_ENUM_VLT "VSIF" 352c03d07aSLuca Tettamanti #define METHOD_OLD_ENUM_FAN "FSIF" 362c03d07aSLuca Tettamanti 372c03d07aSLuca Tettamanti #define ATK_MUX_HWMON 0x00000006ULL 38*9e6eba61SLuca Tettamanti #define ATK_MUX_MGMT 0x00000011ULL 392c03d07aSLuca Tettamanti 402c03d07aSLuca Tettamanti #define ATK_CLASS_MASK 0xff000000ULL 412c03d07aSLuca Tettamanti #define ATK_CLASS_FREQ_CTL 0x03000000ULL 422c03d07aSLuca Tettamanti #define ATK_CLASS_FAN_CTL 0x04000000ULL 432c03d07aSLuca Tettamanti #define ATK_CLASS_HWMON 0x06000000ULL 44*9e6eba61SLuca Tettamanti #define ATK_CLASS_MGMT 0x11000000ULL 452c03d07aSLuca Tettamanti 462c03d07aSLuca Tettamanti #define ATK_TYPE_MASK 0x00ff0000ULL 472c03d07aSLuca Tettamanti #define HWMON_TYPE_VOLT 0x00020000ULL 482c03d07aSLuca Tettamanti #define HWMON_TYPE_TEMP 0x00030000ULL 492c03d07aSLuca Tettamanti #define HWMON_TYPE_FAN 0x00040000ULL 502c03d07aSLuca Tettamanti 51*9e6eba61SLuca Tettamanti #define ATK_ELEMENT_ID_MASK 0x0000ffffULL 52*9e6eba61SLuca Tettamanti 53*9e6eba61SLuca Tettamanti #define ATK_EC_ID 0x11060004ULL 542c03d07aSLuca Tettamanti 552c03d07aSLuca Tettamanti enum atk_pack_member { 562c03d07aSLuca Tettamanti HWMON_PACK_FLAGS, 572c03d07aSLuca Tettamanti HWMON_PACK_NAME, 582c03d07aSLuca Tettamanti HWMON_PACK_LIMIT1, 592c03d07aSLuca Tettamanti HWMON_PACK_LIMIT2, 602c03d07aSLuca Tettamanti HWMON_PACK_ENABLE 612c03d07aSLuca Tettamanti }; 622c03d07aSLuca Tettamanti 632c03d07aSLuca Tettamanti /* New package format */ 642c03d07aSLuca Tettamanti #define _HWMON_NEW_PACK_SIZE 7 652c03d07aSLuca Tettamanti #define _HWMON_NEW_PACK_FLAGS 0 662c03d07aSLuca Tettamanti #define _HWMON_NEW_PACK_NAME 1 672c03d07aSLuca Tettamanti #define _HWMON_NEW_PACK_UNK1 2 682c03d07aSLuca Tettamanti #define _HWMON_NEW_PACK_UNK2 3 692c03d07aSLuca Tettamanti #define _HWMON_NEW_PACK_LIMIT1 4 702c03d07aSLuca Tettamanti #define _HWMON_NEW_PACK_LIMIT2 5 712c03d07aSLuca Tettamanti #define _HWMON_NEW_PACK_ENABLE 6 722c03d07aSLuca Tettamanti 732c03d07aSLuca Tettamanti /* Old package format */ 742c03d07aSLuca Tettamanti #define _HWMON_OLD_PACK_SIZE 5 752c03d07aSLuca Tettamanti #define _HWMON_OLD_PACK_FLAGS 0 762c03d07aSLuca Tettamanti #define _HWMON_OLD_PACK_NAME 1 772c03d07aSLuca Tettamanti #define _HWMON_OLD_PACK_LIMIT1 2 782c03d07aSLuca Tettamanti #define _HWMON_OLD_PACK_LIMIT2 3 792c03d07aSLuca Tettamanti #define _HWMON_OLD_PACK_ENABLE 4 802c03d07aSLuca Tettamanti 812c03d07aSLuca Tettamanti 822c03d07aSLuca Tettamanti struct atk_data { 832c03d07aSLuca Tettamanti struct device *hwmon_dev; 842c03d07aSLuca Tettamanti acpi_handle atk_handle; 852c03d07aSLuca Tettamanti struct acpi_device *acpi_dev; 862c03d07aSLuca Tettamanti 872c03d07aSLuca Tettamanti bool old_interface; 882c03d07aSLuca Tettamanti 892c03d07aSLuca Tettamanti /* old interface */ 902c03d07aSLuca Tettamanti acpi_handle rtmp_handle; 912c03d07aSLuca Tettamanti acpi_handle rvlt_handle; 922c03d07aSLuca Tettamanti acpi_handle rfan_handle; 932c03d07aSLuca Tettamanti /* new inteface */ 942c03d07aSLuca Tettamanti acpi_handle enumerate_handle; 952c03d07aSLuca Tettamanti acpi_handle read_handle; 96*9e6eba61SLuca Tettamanti acpi_handle write_handle; 97*9e6eba61SLuca Tettamanti 98*9e6eba61SLuca Tettamanti bool disable_ec; 992c03d07aSLuca Tettamanti 1002c03d07aSLuca Tettamanti int voltage_count; 1012c03d07aSLuca Tettamanti int temperature_count; 1022c03d07aSLuca Tettamanti int fan_count; 1032c03d07aSLuca Tettamanti struct list_head sensor_list; 1042c03d07aSLuca Tettamanti }; 1052c03d07aSLuca Tettamanti 1062c03d07aSLuca Tettamanti 1072c03d07aSLuca Tettamanti typedef ssize_t (*sysfs_show_func)(struct device *dev, 1082c03d07aSLuca Tettamanti struct device_attribute *attr, char *buf); 1092c03d07aSLuca Tettamanti 1102c03d07aSLuca Tettamanti static const struct acpi_device_id atk_ids[] = { 1112c03d07aSLuca Tettamanti {ATK_HID, 0}, 1122c03d07aSLuca Tettamanti {"", 0}, 1132c03d07aSLuca Tettamanti }; 1142c03d07aSLuca Tettamanti MODULE_DEVICE_TABLE(acpi, atk_ids); 1152c03d07aSLuca Tettamanti 1162c03d07aSLuca Tettamanti #define ATTR_NAME_SIZE 16 /* Worst case is "tempN_input" */ 1172c03d07aSLuca Tettamanti 1182c03d07aSLuca Tettamanti struct atk_sensor_data { 1192c03d07aSLuca Tettamanti struct list_head list; 1202c03d07aSLuca Tettamanti struct atk_data *data; 1212c03d07aSLuca Tettamanti struct device_attribute label_attr; 1222c03d07aSLuca Tettamanti struct device_attribute input_attr; 1232c03d07aSLuca Tettamanti struct device_attribute limit1_attr; 1242c03d07aSLuca Tettamanti struct device_attribute limit2_attr; 1252c03d07aSLuca Tettamanti char label_attr_name[ATTR_NAME_SIZE]; 1262c03d07aSLuca Tettamanti char input_attr_name[ATTR_NAME_SIZE]; 1272c03d07aSLuca Tettamanti char limit1_attr_name[ATTR_NAME_SIZE]; 1282c03d07aSLuca Tettamanti char limit2_attr_name[ATTR_NAME_SIZE]; 1292c03d07aSLuca Tettamanti u64 id; 1302c03d07aSLuca Tettamanti u64 type; 1312c03d07aSLuca Tettamanti u64 limit1; 1322c03d07aSLuca Tettamanti u64 limit2; 1332c03d07aSLuca Tettamanti u64 cached_value; 1342c03d07aSLuca Tettamanti unsigned long last_updated; /* in jiffies */ 1352c03d07aSLuca Tettamanti bool is_valid; 1362c03d07aSLuca Tettamanti char const *acpi_name; 1372c03d07aSLuca Tettamanti }; 1382c03d07aSLuca Tettamanti 13918e25555SLuca Tettamanti /* Return buffer format: 14018e25555SLuca Tettamanti * [0-3] "value" is valid flag 14118e25555SLuca Tettamanti * [4-7] value 14218e25555SLuca Tettamanti * [8- ] unknown stuff on newer mobos 14318e25555SLuca Tettamanti */ 14418e25555SLuca Tettamanti struct atk_acpi_ret_buffer { 14518e25555SLuca Tettamanti u32 flags; 14618e25555SLuca Tettamanti u32 value; 14718e25555SLuca Tettamanti u8 data[]; 14818e25555SLuca Tettamanti }; 14918e25555SLuca Tettamanti 15018e25555SLuca Tettamanti /* Input buffer used for GITM and SITM methods */ 15118e25555SLuca Tettamanti struct atk_acpi_input_buf { 15218e25555SLuca Tettamanti u32 id; 15318e25555SLuca Tettamanti u32 param1; 15418e25555SLuca Tettamanti u32 param2; 1552c03d07aSLuca Tettamanti }; 1562c03d07aSLuca Tettamanti 1572c03d07aSLuca Tettamanti static int atk_add(struct acpi_device *device); 1582c03d07aSLuca Tettamanti static int atk_remove(struct acpi_device *device, int type); 1592c03d07aSLuca Tettamanti static void atk_print_sensor(struct atk_data *data, union acpi_object *obj); 1602c03d07aSLuca Tettamanti static int atk_read_value(struct atk_sensor_data *sensor, u64 *value); 1612c03d07aSLuca Tettamanti static void atk_free_sensors(struct atk_data *data); 1622c03d07aSLuca Tettamanti 1632c03d07aSLuca Tettamanti static struct acpi_driver atk_driver = { 1642c03d07aSLuca Tettamanti .name = ATK_HID, 1652c03d07aSLuca Tettamanti .class = "hwmon", 1662c03d07aSLuca Tettamanti .ids = atk_ids, 1672c03d07aSLuca Tettamanti .ops = { 1682c03d07aSLuca Tettamanti .add = atk_add, 1692c03d07aSLuca Tettamanti .remove = atk_remove, 1702c03d07aSLuca Tettamanti }, 1712c03d07aSLuca Tettamanti }; 1722c03d07aSLuca Tettamanti 1732c03d07aSLuca Tettamanti #define input_to_atk_sensor(attr) \ 1742c03d07aSLuca Tettamanti container_of(attr, struct atk_sensor_data, input_attr) 1752c03d07aSLuca Tettamanti 1762c03d07aSLuca Tettamanti #define label_to_atk_sensor(attr) \ 1772c03d07aSLuca Tettamanti container_of(attr, struct atk_sensor_data, label_attr) 1782c03d07aSLuca Tettamanti 1792c03d07aSLuca Tettamanti #define limit1_to_atk_sensor(attr) \ 1802c03d07aSLuca Tettamanti container_of(attr, struct atk_sensor_data, limit1_attr) 1812c03d07aSLuca Tettamanti 1822c03d07aSLuca Tettamanti #define limit2_to_atk_sensor(attr) \ 1832c03d07aSLuca Tettamanti container_of(attr, struct atk_sensor_data, limit2_attr) 1842c03d07aSLuca Tettamanti 1852c03d07aSLuca Tettamanti static ssize_t atk_input_show(struct device *dev, 1862c03d07aSLuca Tettamanti struct device_attribute *attr, char *buf) 1872c03d07aSLuca Tettamanti { 1882c03d07aSLuca Tettamanti struct atk_sensor_data *s = input_to_atk_sensor(attr); 1892c03d07aSLuca Tettamanti u64 value; 1902c03d07aSLuca Tettamanti int err; 1912c03d07aSLuca Tettamanti 1922c03d07aSLuca Tettamanti err = atk_read_value(s, &value); 1932c03d07aSLuca Tettamanti if (err) 1942c03d07aSLuca Tettamanti return err; 1952c03d07aSLuca Tettamanti 1962c03d07aSLuca Tettamanti if (s->type == HWMON_TYPE_TEMP) 1972c03d07aSLuca Tettamanti /* ACPI returns decidegree */ 1982c03d07aSLuca Tettamanti value *= 100; 1992c03d07aSLuca Tettamanti 2002c03d07aSLuca Tettamanti return sprintf(buf, "%llu\n", value); 2012c03d07aSLuca Tettamanti } 2022c03d07aSLuca Tettamanti 2032c03d07aSLuca Tettamanti static ssize_t atk_label_show(struct device *dev, 2042c03d07aSLuca Tettamanti struct device_attribute *attr, char *buf) 2052c03d07aSLuca Tettamanti { 2062c03d07aSLuca Tettamanti struct atk_sensor_data *s = label_to_atk_sensor(attr); 2072c03d07aSLuca Tettamanti 2082c03d07aSLuca Tettamanti return sprintf(buf, "%s\n", s->acpi_name); 2092c03d07aSLuca Tettamanti } 2102c03d07aSLuca Tettamanti 2112c03d07aSLuca Tettamanti static ssize_t atk_limit1_show(struct device *dev, 2122c03d07aSLuca Tettamanti struct device_attribute *attr, char *buf) 2132c03d07aSLuca Tettamanti { 2142c03d07aSLuca Tettamanti struct atk_sensor_data *s = limit1_to_atk_sensor(attr); 2152c03d07aSLuca Tettamanti u64 value = s->limit1; 2162c03d07aSLuca Tettamanti 2172c03d07aSLuca Tettamanti if (s->type == HWMON_TYPE_TEMP) 2182c03d07aSLuca Tettamanti value *= 100; 2192c03d07aSLuca Tettamanti 2202c03d07aSLuca Tettamanti return sprintf(buf, "%lld\n", value); 2212c03d07aSLuca Tettamanti } 2222c03d07aSLuca Tettamanti 2232c03d07aSLuca Tettamanti static ssize_t atk_limit2_show(struct device *dev, 2242c03d07aSLuca Tettamanti struct device_attribute *attr, char *buf) 2252c03d07aSLuca Tettamanti { 2262c03d07aSLuca Tettamanti struct atk_sensor_data *s = limit2_to_atk_sensor(attr); 2272c03d07aSLuca Tettamanti u64 value = s->limit2; 2282c03d07aSLuca Tettamanti 2292c03d07aSLuca Tettamanti if (s->type == HWMON_TYPE_TEMP) 2302c03d07aSLuca Tettamanti value *= 100; 2312c03d07aSLuca Tettamanti 2322c03d07aSLuca Tettamanti return sprintf(buf, "%lld\n", value); 2332c03d07aSLuca Tettamanti } 2342c03d07aSLuca Tettamanti 2352c03d07aSLuca Tettamanti static ssize_t atk_name_show(struct device *dev, 2362c03d07aSLuca Tettamanti struct device_attribute *attr, char *buf) 2372c03d07aSLuca Tettamanti { 2382c03d07aSLuca Tettamanti return sprintf(buf, "atk0110\n"); 2392c03d07aSLuca Tettamanti } 2402c03d07aSLuca Tettamanti static struct device_attribute atk_name_attr = 2412c03d07aSLuca Tettamanti __ATTR(name, 0444, atk_name_show, NULL); 2422c03d07aSLuca Tettamanti 2432c03d07aSLuca Tettamanti static void atk_init_attribute(struct device_attribute *attr, char *name, 2442c03d07aSLuca Tettamanti sysfs_show_func show) 2452c03d07aSLuca Tettamanti { 2462c03d07aSLuca Tettamanti attr->attr.name = name; 2472c03d07aSLuca Tettamanti attr->attr.mode = 0444; 2482c03d07aSLuca Tettamanti attr->show = show; 2492c03d07aSLuca Tettamanti attr->store = NULL; 2502c03d07aSLuca Tettamanti } 2512c03d07aSLuca Tettamanti 2522c03d07aSLuca Tettamanti 2532c03d07aSLuca Tettamanti static union acpi_object *atk_get_pack_member(struct atk_data *data, 2542c03d07aSLuca Tettamanti union acpi_object *pack, 2552c03d07aSLuca Tettamanti enum atk_pack_member m) 2562c03d07aSLuca Tettamanti { 2572c03d07aSLuca Tettamanti bool old_if = data->old_interface; 2582c03d07aSLuca Tettamanti int offset; 2592c03d07aSLuca Tettamanti 2602c03d07aSLuca Tettamanti switch (m) { 2612c03d07aSLuca Tettamanti case HWMON_PACK_FLAGS: 2622c03d07aSLuca Tettamanti offset = old_if ? _HWMON_OLD_PACK_FLAGS : _HWMON_NEW_PACK_FLAGS; 2632c03d07aSLuca Tettamanti break; 2642c03d07aSLuca Tettamanti case HWMON_PACK_NAME: 2652c03d07aSLuca Tettamanti offset = old_if ? _HWMON_OLD_PACK_NAME : _HWMON_NEW_PACK_NAME; 2662c03d07aSLuca Tettamanti break; 2672c03d07aSLuca Tettamanti case HWMON_PACK_LIMIT1: 2682c03d07aSLuca Tettamanti offset = old_if ? _HWMON_OLD_PACK_LIMIT1 : 2692c03d07aSLuca Tettamanti _HWMON_NEW_PACK_LIMIT1; 2702c03d07aSLuca Tettamanti break; 2712c03d07aSLuca Tettamanti case HWMON_PACK_LIMIT2: 2722c03d07aSLuca Tettamanti offset = old_if ? _HWMON_OLD_PACK_LIMIT2 : 2732c03d07aSLuca Tettamanti _HWMON_NEW_PACK_LIMIT2; 2742c03d07aSLuca Tettamanti break; 2752c03d07aSLuca Tettamanti case HWMON_PACK_ENABLE: 2762c03d07aSLuca Tettamanti offset = old_if ? _HWMON_OLD_PACK_ENABLE : 2772c03d07aSLuca Tettamanti _HWMON_NEW_PACK_ENABLE; 2782c03d07aSLuca Tettamanti break; 2792c03d07aSLuca Tettamanti default: 2802c03d07aSLuca Tettamanti return NULL; 2812c03d07aSLuca Tettamanti } 2822c03d07aSLuca Tettamanti 2832c03d07aSLuca Tettamanti return &pack->package.elements[offset]; 2842c03d07aSLuca Tettamanti } 2852c03d07aSLuca Tettamanti 2862c03d07aSLuca Tettamanti 2872c03d07aSLuca Tettamanti /* New package format is: 2882c03d07aSLuca Tettamanti * - flag (int) 2892c03d07aSLuca Tettamanti * class - used for de-muxing the request to the correct GITn 2902c03d07aSLuca Tettamanti * type (volt, temp, fan) 2912c03d07aSLuca Tettamanti * sensor id | 2922c03d07aSLuca Tettamanti * sensor id - used for de-muxing the request _inside_ the GITn 2932c03d07aSLuca Tettamanti * - name (str) 2942c03d07aSLuca Tettamanti * - unknown (int) 2952c03d07aSLuca Tettamanti * - unknown (int) 2962c03d07aSLuca Tettamanti * - limit1 (int) 2972c03d07aSLuca Tettamanti * - limit2 (int) 2982c03d07aSLuca Tettamanti * - enable (int) 2992c03d07aSLuca Tettamanti * 3002c03d07aSLuca Tettamanti * The old package has the same format but it's missing the two unknown fields. 3012c03d07aSLuca Tettamanti */ 3022c03d07aSLuca Tettamanti static int validate_hwmon_pack(struct atk_data *data, union acpi_object *obj) 3032c03d07aSLuca Tettamanti { 3042c03d07aSLuca Tettamanti struct device *dev = &data->acpi_dev->dev; 3052c03d07aSLuca Tettamanti union acpi_object *tmp; 3062c03d07aSLuca Tettamanti bool old_if = data->old_interface; 3072c03d07aSLuca Tettamanti int const expected_size = old_if ? _HWMON_OLD_PACK_SIZE : 3082c03d07aSLuca Tettamanti _HWMON_NEW_PACK_SIZE; 3092c03d07aSLuca Tettamanti 3102c03d07aSLuca Tettamanti if (obj->type != ACPI_TYPE_PACKAGE) { 3112c03d07aSLuca Tettamanti dev_warn(dev, "Invalid type: %d\n", obj->type); 3122c03d07aSLuca Tettamanti return -EINVAL; 3132c03d07aSLuca Tettamanti } 3142c03d07aSLuca Tettamanti 3152c03d07aSLuca Tettamanti if (obj->package.count != expected_size) { 3162c03d07aSLuca Tettamanti dev_warn(dev, "Invalid package size: %d, expected: %d\n", 3172c03d07aSLuca Tettamanti obj->package.count, expected_size); 3182c03d07aSLuca Tettamanti return -EINVAL; 3192c03d07aSLuca Tettamanti } 3202c03d07aSLuca Tettamanti 3212c03d07aSLuca Tettamanti tmp = atk_get_pack_member(data, obj, HWMON_PACK_FLAGS); 3222c03d07aSLuca Tettamanti if (tmp->type != ACPI_TYPE_INTEGER) { 3232c03d07aSLuca Tettamanti dev_warn(dev, "Invalid type (flag): %d\n", tmp->type); 3242c03d07aSLuca Tettamanti return -EINVAL; 3252c03d07aSLuca Tettamanti } 3262c03d07aSLuca Tettamanti 3272c03d07aSLuca Tettamanti tmp = atk_get_pack_member(data, obj, HWMON_PACK_NAME); 3282c03d07aSLuca Tettamanti if (tmp->type != ACPI_TYPE_STRING) { 3292c03d07aSLuca Tettamanti dev_warn(dev, "Invalid type (name): %d\n", tmp->type); 3302c03d07aSLuca Tettamanti return -EINVAL; 3312c03d07aSLuca Tettamanti } 3322c03d07aSLuca Tettamanti 3332c03d07aSLuca Tettamanti /* Don't check... we don't know what they're useful for anyway */ 3342c03d07aSLuca Tettamanti #if 0 3352c03d07aSLuca Tettamanti tmp = &obj->package.elements[HWMON_PACK_UNK1]; 3362c03d07aSLuca Tettamanti if (tmp->type != ACPI_TYPE_INTEGER) { 3372c03d07aSLuca Tettamanti dev_warn(dev, "Invalid type (unk1): %d\n", tmp->type); 3382c03d07aSLuca Tettamanti return -EINVAL; 3392c03d07aSLuca Tettamanti } 3402c03d07aSLuca Tettamanti 3412c03d07aSLuca Tettamanti tmp = &obj->package.elements[HWMON_PACK_UNK2]; 3422c03d07aSLuca Tettamanti if (tmp->type != ACPI_TYPE_INTEGER) { 3432c03d07aSLuca Tettamanti dev_warn(dev, "Invalid type (unk2): %d\n", tmp->type); 3442c03d07aSLuca Tettamanti return -EINVAL; 3452c03d07aSLuca Tettamanti } 3462c03d07aSLuca Tettamanti #endif 3472c03d07aSLuca Tettamanti 3482c03d07aSLuca Tettamanti tmp = atk_get_pack_member(data, obj, HWMON_PACK_LIMIT1); 3492c03d07aSLuca Tettamanti if (tmp->type != ACPI_TYPE_INTEGER) { 3502c03d07aSLuca Tettamanti dev_warn(dev, "Invalid type (limit1): %d\n", tmp->type); 3512c03d07aSLuca Tettamanti return -EINVAL; 3522c03d07aSLuca Tettamanti } 3532c03d07aSLuca Tettamanti 3542c03d07aSLuca Tettamanti tmp = atk_get_pack_member(data, obj, HWMON_PACK_LIMIT2); 3552c03d07aSLuca Tettamanti if (tmp->type != ACPI_TYPE_INTEGER) { 3562c03d07aSLuca Tettamanti dev_warn(dev, "Invalid type (limit2): %d\n", tmp->type); 3572c03d07aSLuca Tettamanti return -EINVAL; 3582c03d07aSLuca Tettamanti } 3592c03d07aSLuca Tettamanti 3602c03d07aSLuca Tettamanti tmp = atk_get_pack_member(data, obj, HWMON_PACK_ENABLE); 3612c03d07aSLuca Tettamanti if (tmp->type != ACPI_TYPE_INTEGER) { 3622c03d07aSLuca Tettamanti dev_warn(dev, "Invalid type (enable): %d\n", tmp->type); 3632c03d07aSLuca Tettamanti return -EINVAL; 3642c03d07aSLuca Tettamanti } 3652c03d07aSLuca Tettamanti 3662c03d07aSLuca Tettamanti atk_print_sensor(data, obj); 3672c03d07aSLuca Tettamanti 3682c03d07aSLuca Tettamanti return 0; 3692c03d07aSLuca Tettamanti } 3702c03d07aSLuca Tettamanti 371b9008708SLuca Tettamanti #ifdef DEBUG 3722c03d07aSLuca Tettamanti static char const *atk_sensor_type(union acpi_object *flags) 3732c03d07aSLuca Tettamanti { 3742c03d07aSLuca Tettamanti u64 type = flags->integer.value & ATK_TYPE_MASK; 3752c03d07aSLuca Tettamanti char const *what; 3762c03d07aSLuca Tettamanti 3772c03d07aSLuca Tettamanti switch (type) { 3782c03d07aSLuca Tettamanti case HWMON_TYPE_VOLT: 3792c03d07aSLuca Tettamanti what = "voltage"; 3802c03d07aSLuca Tettamanti break; 3812c03d07aSLuca Tettamanti case HWMON_TYPE_TEMP: 3822c03d07aSLuca Tettamanti what = "temperature"; 3832c03d07aSLuca Tettamanti break; 3842c03d07aSLuca Tettamanti case HWMON_TYPE_FAN: 3852c03d07aSLuca Tettamanti what = "fan"; 3862c03d07aSLuca Tettamanti break; 3872c03d07aSLuca Tettamanti default: 3882c03d07aSLuca Tettamanti what = "unknown"; 3892c03d07aSLuca Tettamanti break; 3902c03d07aSLuca Tettamanti } 3912c03d07aSLuca Tettamanti 3922c03d07aSLuca Tettamanti return what; 3932c03d07aSLuca Tettamanti } 394b9008708SLuca Tettamanti #endif 3952c03d07aSLuca Tettamanti 3962c03d07aSLuca Tettamanti static void atk_print_sensor(struct atk_data *data, union acpi_object *obj) 3972c03d07aSLuca Tettamanti { 3982c03d07aSLuca Tettamanti #ifdef DEBUG 3992c03d07aSLuca Tettamanti struct device *dev = &data->acpi_dev->dev; 4002c03d07aSLuca Tettamanti union acpi_object *flags; 4012c03d07aSLuca Tettamanti union acpi_object *name; 4022c03d07aSLuca Tettamanti union acpi_object *limit1; 4032c03d07aSLuca Tettamanti union acpi_object *limit2; 4042c03d07aSLuca Tettamanti union acpi_object *enable; 4052c03d07aSLuca Tettamanti char const *what; 4062c03d07aSLuca Tettamanti 4072c03d07aSLuca Tettamanti flags = atk_get_pack_member(data, obj, HWMON_PACK_FLAGS); 4082c03d07aSLuca Tettamanti name = atk_get_pack_member(data, obj, HWMON_PACK_NAME); 4092c03d07aSLuca Tettamanti limit1 = atk_get_pack_member(data, obj, HWMON_PACK_LIMIT1); 4102c03d07aSLuca Tettamanti limit2 = atk_get_pack_member(data, obj, HWMON_PACK_LIMIT2); 4112c03d07aSLuca Tettamanti enable = atk_get_pack_member(data, obj, HWMON_PACK_ENABLE); 4122c03d07aSLuca Tettamanti 4132c03d07aSLuca Tettamanti what = atk_sensor_type(flags); 4142c03d07aSLuca Tettamanti 4152c03d07aSLuca Tettamanti dev_dbg(dev, "%s: %#llx %s [%llu-%llu] %s\n", what, 4162c03d07aSLuca Tettamanti flags->integer.value, 4172c03d07aSLuca Tettamanti name->string.pointer, 4182c03d07aSLuca Tettamanti limit1->integer.value, limit2->integer.value, 4192c03d07aSLuca Tettamanti enable->integer.value ? "enabled" : "disabled"); 4202c03d07aSLuca Tettamanti #endif 4212c03d07aSLuca Tettamanti } 4222c03d07aSLuca Tettamanti 4232c03d07aSLuca Tettamanti static int atk_read_value_old(struct atk_sensor_data *sensor, u64 *value) 4242c03d07aSLuca Tettamanti { 4252c03d07aSLuca Tettamanti struct atk_data *data = sensor->data; 4262c03d07aSLuca Tettamanti struct device *dev = &data->acpi_dev->dev; 4272c03d07aSLuca Tettamanti struct acpi_object_list params; 4282c03d07aSLuca Tettamanti union acpi_object id; 4292c03d07aSLuca Tettamanti acpi_status status; 4302c03d07aSLuca Tettamanti acpi_handle method; 4312c03d07aSLuca Tettamanti 4322c03d07aSLuca Tettamanti switch (sensor->type) { 4332c03d07aSLuca Tettamanti case HWMON_TYPE_VOLT: 4342c03d07aSLuca Tettamanti method = data->rvlt_handle; 4352c03d07aSLuca Tettamanti break; 4362c03d07aSLuca Tettamanti case HWMON_TYPE_TEMP: 4372c03d07aSLuca Tettamanti method = data->rtmp_handle; 4382c03d07aSLuca Tettamanti break; 4392c03d07aSLuca Tettamanti case HWMON_TYPE_FAN: 4402c03d07aSLuca Tettamanti method = data->rfan_handle; 4412c03d07aSLuca Tettamanti break; 4422c03d07aSLuca Tettamanti default: 4432c03d07aSLuca Tettamanti return -EINVAL; 4442c03d07aSLuca Tettamanti } 4452c03d07aSLuca Tettamanti 4462c03d07aSLuca Tettamanti id.type = ACPI_TYPE_INTEGER; 4472c03d07aSLuca Tettamanti id.integer.value = sensor->id; 4482c03d07aSLuca Tettamanti 4492c03d07aSLuca Tettamanti params.count = 1; 4502c03d07aSLuca Tettamanti params.pointer = &id; 4512c03d07aSLuca Tettamanti 4522c03d07aSLuca Tettamanti status = acpi_evaluate_integer(method, NULL, ¶ms, value); 4532c03d07aSLuca Tettamanti if (status != AE_OK) { 4542c03d07aSLuca Tettamanti dev_warn(dev, "%s: ACPI exception: %s\n", __func__, 4552c03d07aSLuca Tettamanti acpi_format_exception(status)); 4562c03d07aSLuca Tettamanti return -EIO; 4572c03d07aSLuca Tettamanti } 4582c03d07aSLuca Tettamanti 4592c03d07aSLuca Tettamanti return 0; 4602c03d07aSLuca Tettamanti } 4612c03d07aSLuca Tettamanti 46218e25555SLuca Tettamanti static union acpi_object *atk_ggrp(struct atk_data *data, u16 mux) 46318e25555SLuca Tettamanti { 46418e25555SLuca Tettamanti struct device *dev = &data->acpi_dev->dev; 46518e25555SLuca Tettamanti struct acpi_buffer buf; 46618e25555SLuca Tettamanti acpi_status ret; 46718e25555SLuca Tettamanti struct acpi_object_list params; 46818e25555SLuca Tettamanti union acpi_object id; 46918e25555SLuca Tettamanti union acpi_object *pack; 47018e25555SLuca Tettamanti 47118e25555SLuca Tettamanti id.type = ACPI_TYPE_INTEGER; 47218e25555SLuca Tettamanti id.integer.value = mux; 47318e25555SLuca Tettamanti params.count = 1; 47418e25555SLuca Tettamanti params.pointer = &id; 47518e25555SLuca Tettamanti 47618e25555SLuca Tettamanti buf.length = ACPI_ALLOCATE_BUFFER; 47718e25555SLuca Tettamanti ret = acpi_evaluate_object(data->enumerate_handle, NULL, ¶ms, &buf); 47818e25555SLuca Tettamanti if (ret != AE_OK) { 47918e25555SLuca Tettamanti dev_err(dev, "GGRP[%#x] ACPI exception: %s\n", mux, 48018e25555SLuca Tettamanti acpi_format_exception(ret)); 48118e25555SLuca Tettamanti return ERR_PTR(-EIO); 48218e25555SLuca Tettamanti } 48318e25555SLuca Tettamanti pack = buf.pointer; 48418e25555SLuca Tettamanti if (pack->type != ACPI_TYPE_PACKAGE) { 48518e25555SLuca Tettamanti /* Execution was successful, but the id was not found */ 48618e25555SLuca Tettamanti ACPI_FREE(pack); 48718e25555SLuca Tettamanti return ERR_PTR(-ENOENT); 48818e25555SLuca Tettamanti } 48918e25555SLuca Tettamanti 49018e25555SLuca Tettamanti if (pack->package.count < 1) { 49118e25555SLuca Tettamanti dev_err(dev, "GGRP[%#x] package is too small\n", mux); 49218e25555SLuca Tettamanti ACPI_FREE(pack); 49318e25555SLuca Tettamanti return ERR_PTR(-EIO); 49418e25555SLuca Tettamanti } 49518e25555SLuca Tettamanti return pack; 49618e25555SLuca Tettamanti } 49718e25555SLuca Tettamanti 49818e25555SLuca Tettamanti static union acpi_object *atk_gitm(struct atk_data *data, u64 id) 49918e25555SLuca Tettamanti { 50018e25555SLuca Tettamanti struct device *dev = &data->acpi_dev->dev; 50118e25555SLuca Tettamanti struct atk_acpi_input_buf buf; 50218e25555SLuca Tettamanti union acpi_object tmp; 50318e25555SLuca Tettamanti struct acpi_object_list params; 50418e25555SLuca Tettamanti struct acpi_buffer ret; 50518e25555SLuca Tettamanti union acpi_object *obj; 50618e25555SLuca Tettamanti acpi_status status; 50718e25555SLuca Tettamanti 50818e25555SLuca Tettamanti buf.id = id; 50918e25555SLuca Tettamanti buf.param1 = 0; 51018e25555SLuca Tettamanti buf.param2 = 0; 51118e25555SLuca Tettamanti 51218e25555SLuca Tettamanti tmp.type = ACPI_TYPE_BUFFER; 51318e25555SLuca Tettamanti tmp.buffer.pointer = (u8 *)&buf; 51418e25555SLuca Tettamanti tmp.buffer.length = sizeof(buf); 51518e25555SLuca Tettamanti 51618e25555SLuca Tettamanti params.count = 1; 51718e25555SLuca Tettamanti params.pointer = (void *)&tmp; 51818e25555SLuca Tettamanti 51918e25555SLuca Tettamanti ret.length = ACPI_ALLOCATE_BUFFER; 52018e25555SLuca Tettamanti status = acpi_evaluate_object_typed(data->read_handle, NULL, ¶ms, 52118e25555SLuca Tettamanti &ret, ACPI_TYPE_BUFFER); 52218e25555SLuca Tettamanti if (status != AE_OK) { 52318e25555SLuca Tettamanti dev_warn(dev, "GITM[%#llx] ACPI exception: %s\n", id, 52418e25555SLuca Tettamanti acpi_format_exception(status)); 52518e25555SLuca Tettamanti return ERR_PTR(-EIO); 52618e25555SLuca Tettamanti } 52718e25555SLuca Tettamanti obj = ret.pointer; 52818e25555SLuca Tettamanti 52918e25555SLuca Tettamanti /* Sanity check */ 53018e25555SLuca Tettamanti if (obj->buffer.length < 8) { 53118e25555SLuca Tettamanti dev_warn(dev, "Unexpected ASBF length: %u\n", 53218e25555SLuca Tettamanti obj->buffer.length); 53318e25555SLuca Tettamanti ACPI_FREE(obj); 53418e25555SLuca Tettamanti return ERR_PTR(-EIO); 53518e25555SLuca Tettamanti } 53618e25555SLuca Tettamanti return obj; 53718e25555SLuca Tettamanti } 53818e25555SLuca Tettamanti 539*9e6eba61SLuca Tettamanti static union acpi_object *atk_sitm(struct atk_data *data, 540*9e6eba61SLuca Tettamanti struct atk_acpi_input_buf *buf) 541*9e6eba61SLuca Tettamanti { 542*9e6eba61SLuca Tettamanti struct device *dev = &data->acpi_dev->dev; 543*9e6eba61SLuca Tettamanti struct acpi_object_list params; 544*9e6eba61SLuca Tettamanti union acpi_object tmp; 545*9e6eba61SLuca Tettamanti struct acpi_buffer ret; 546*9e6eba61SLuca Tettamanti union acpi_object *obj; 547*9e6eba61SLuca Tettamanti acpi_status status; 548*9e6eba61SLuca Tettamanti 549*9e6eba61SLuca Tettamanti tmp.type = ACPI_TYPE_BUFFER; 550*9e6eba61SLuca Tettamanti tmp.buffer.pointer = (u8 *)buf; 551*9e6eba61SLuca Tettamanti tmp.buffer.length = sizeof(*buf); 552*9e6eba61SLuca Tettamanti 553*9e6eba61SLuca Tettamanti params.count = 1; 554*9e6eba61SLuca Tettamanti params.pointer = &tmp; 555*9e6eba61SLuca Tettamanti 556*9e6eba61SLuca Tettamanti ret.length = ACPI_ALLOCATE_BUFFER; 557*9e6eba61SLuca Tettamanti status = acpi_evaluate_object_typed(data->write_handle, NULL, ¶ms, 558*9e6eba61SLuca Tettamanti &ret, ACPI_TYPE_BUFFER); 559*9e6eba61SLuca Tettamanti if (status != AE_OK) { 560*9e6eba61SLuca Tettamanti dev_warn(dev, "SITM[%#x] ACPI exception: %s\n", buf->id, 561*9e6eba61SLuca Tettamanti acpi_format_exception(status)); 562*9e6eba61SLuca Tettamanti return ERR_PTR(-EIO); 563*9e6eba61SLuca Tettamanti } 564*9e6eba61SLuca Tettamanti obj = ret.pointer; 565*9e6eba61SLuca Tettamanti 566*9e6eba61SLuca Tettamanti /* Sanity check */ 567*9e6eba61SLuca Tettamanti if (obj->buffer.length < 8) { 568*9e6eba61SLuca Tettamanti dev_warn(dev, "Unexpected ASBF length: %u\n", 569*9e6eba61SLuca Tettamanti obj->buffer.length); 570*9e6eba61SLuca Tettamanti ACPI_FREE(obj); 571*9e6eba61SLuca Tettamanti return ERR_PTR(-EIO); 572*9e6eba61SLuca Tettamanti } 573*9e6eba61SLuca Tettamanti return obj; 574*9e6eba61SLuca Tettamanti } 575*9e6eba61SLuca Tettamanti 5762c03d07aSLuca Tettamanti static int atk_read_value_new(struct atk_sensor_data *sensor, u64 *value) 5772c03d07aSLuca Tettamanti { 5782c03d07aSLuca Tettamanti struct atk_data *data = sensor->data; 5792c03d07aSLuca Tettamanti struct device *dev = &data->acpi_dev->dev; 58018e25555SLuca Tettamanti union acpi_object *obj; 58118e25555SLuca Tettamanti struct atk_acpi_ret_buffer *buf; 58218e25555SLuca Tettamanti int err = 0; 5832c03d07aSLuca Tettamanti 58418e25555SLuca Tettamanti obj = atk_gitm(data, sensor->id); 58518e25555SLuca Tettamanti if (IS_ERR(obj)) 58618e25555SLuca Tettamanti return PTR_ERR(obj); 5872c03d07aSLuca Tettamanti 58818e25555SLuca Tettamanti buf = (struct atk_acpi_ret_buffer *)obj->buffer.pointer; 58918e25555SLuca Tettamanti if (buf->flags == 0) { 5902c03d07aSLuca Tettamanti /* The reading is not valid, possible causes: 5912c03d07aSLuca Tettamanti * - sensor failure 5922c03d07aSLuca Tettamanti * - enumeration was FUBAR (and we didn't notice) 5932c03d07aSLuca Tettamanti */ 59418e25555SLuca Tettamanti dev_warn(dev, "Read failed, sensor = %#llx\n", sensor->id); 59518e25555SLuca Tettamanti err = -EIO; 59618e25555SLuca Tettamanti goto out; 5972c03d07aSLuca Tettamanti } 5982c03d07aSLuca Tettamanti 59918e25555SLuca Tettamanti *value = buf->value; 60018e25555SLuca Tettamanti out: 60118e25555SLuca Tettamanti ACPI_FREE(obj); 60218e25555SLuca Tettamanti return err; 6032c03d07aSLuca Tettamanti } 6042c03d07aSLuca Tettamanti 6052c03d07aSLuca Tettamanti static int atk_read_value(struct atk_sensor_data *sensor, u64 *value) 6062c03d07aSLuca Tettamanti { 6072c03d07aSLuca Tettamanti int err; 6082c03d07aSLuca Tettamanti 6092c03d07aSLuca Tettamanti if (!sensor->is_valid || 6102c03d07aSLuca Tettamanti time_after(jiffies, sensor->last_updated + CACHE_TIME)) { 6112c03d07aSLuca Tettamanti if (sensor->data->old_interface) 6122c03d07aSLuca Tettamanti err = atk_read_value_old(sensor, value); 6132c03d07aSLuca Tettamanti else 6142c03d07aSLuca Tettamanti err = atk_read_value_new(sensor, value); 6152c03d07aSLuca Tettamanti 6162c03d07aSLuca Tettamanti sensor->is_valid = true; 6172c03d07aSLuca Tettamanti sensor->last_updated = jiffies; 6182c03d07aSLuca Tettamanti sensor->cached_value = *value; 6192c03d07aSLuca Tettamanti } else { 6202c03d07aSLuca Tettamanti *value = sensor->cached_value; 6212c03d07aSLuca Tettamanti err = 0; 6222c03d07aSLuca Tettamanti } 6232c03d07aSLuca Tettamanti 6242c03d07aSLuca Tettamanti return err; 6252c03d07aSLuca Tettamanti } 6262c03d07aSLuca Tettamanti 6272c03d07aSLuca Tettamanti static int atk_add_sensor(struct atk_data *data, union acpi_object *obj) 6282c03d07aSLuca Tettamanti { 6292c03d07aSLuca Tettamanti struct device *dev = &data->acpi_dev->dev; 6302c03d07aSLuca Tettamanti union acpi_object *flags; 6312c03d07aSLuca Tettamanti union acpi_object *name; 6322c03d07aSLuca Tettamanti union acpi_object *limit1; 6332c03d07aSLuca Tettamanti union acpi_object *limit2; 6342c03d07aSLuca Tettamanti union acpi_object *enable; 6352c03d07aSLuca Tettamanti struct atk_sensor_data *sensor; 6362c03d07aSLuca Tettamanti char const *base_name; 6372c03d07aSLuca Tettamanti char const *limit1_name; 6382c03d07aSLuca Tettamanti char const *limit2_name; 6392c03d07aSLuca Tettamanti u64 type; 6402c03d07aSLuca Tettamanti int err; 6412c03d07aSLuca Tettamanti int *num; 6422c03d07aSLuca Tettamanti int start; 6432c03d07aSLuca Tettamanti 6442c03d07aSLuca Tettamanti if (obj->type != ACPI_TYPE_PACKAGE) { 6452c03d07aSLuca Tettamanti /* wft is this? */ 6462c03d07aSLuca Tettamanti dev_warn(dev, "Unknown type for ACPI object: (%d)\n", 6472c03d07aSLuca Tettamanti obj->type); 6482c03d07aSLuca Tettamanti return -EINVAL; 6492c03d07aSLuca Tettamanti } 6502c03d07aSLuca Tettamanti 6512c03d07aSLuca Tettamanti err = validate_hwmon_pack(data, obj); 6522c03d07aSLuca Tettamanti if (err) 6532c03d07aSLuca Tettamanti return err; 6542c03d07aSLuca Tettamanti 6552c03d07aSLuca Tettamanti /* Ok, we have a valid hwmon package */ 6562c03d07aSLuca Tettamanti type = atk_get_pack_member(data, obj, HWMON_PACK_FLAGS)->integer.value 6572c03d07aSLuca Tettamanti & ATK_TYPE_MASK; 6582c03d07aSLuca Tettamanti 6592c03d07aSLuca Tettamanti switch (type) { 6602c03d07aSLuca Tettamanti case HWMON_TYPE_VOLT: 6612c03d07aSLuca Tettamanti base_name = "in"; 6622c03d07aSLuca Tettamanti limit1_name = "min"; 6632c03d07aSLuca Tettamanti limit2_name = "max"; 6642c03d07aSLuca Tettamanti num = &data->voltage_count; 6652c03d07aSLuca Tettamanti start = 0; 6662c03d07aSLuca Tettamanti break; 6672c03d07aSLuca Tettamanti case HWMON_TYPE_TEMP: 6682c03d07aSLuca Tettamanti base_name = "temp"; 6692c03d07aSLuca Tettamanti limit1_name = "max"; 6702c03d07aSLuca Tettamanti limit2_name = "crit"; 6712c03d07aSLuca Tettamanti num = &data->temperature_count; 6722c03d07aSLuca Tettamanti start = 1; 6732c03d07aSLuca Tettamanti break; 6742c03d07aSLuca Tettamanti case HWMON_TYPE_FAN: 6752c03d07aSLuca Tettamanti base_name = "fan"; 6762c03d07aSLuca Tettamanti limit1_name = "min"; 6772c03d07aSLuca Tettamanti limit2_name = "max"; 6782c03d07aSLuca Tettamanti num = &data->fan_count; 6792c03d07aSLuca Tettamanti start = 1; 6802c03d07aSLuca Tettamanti break; 6812c03d07aSLuca Tettamanti default: 6822c03d07aSLuca Tettamanti dev_warn(dev, "Unknown sensor type: %#llx\n", type); 6832c03d07aSLuca Tettamanti return -EINVAL; 6842c03d07aSLuca Tettamanti } 6852c03d07aSLuca Tettamanti 6862c03d07aSLuca Tettamanti enable = atk_get_pack_member(data, obj, HWMON_PACK_ENABLE); 6872c03d07aSLuca Tettamanti if (!enable->integer.value) 6882c03d07aSLuca Tettamanti /* sensor is disabled */ 6892c03d07aSLuca Tettamanti return 0; 6902c03d07aSLuca Tettamanti 6912c03d07aSLuca Tettamanti flags = atk_get_pack_member(data, obj, HWMON_PACK_FLAGS); 6922c03d07aSLuca Tettamanti name = atk_get_pack_member(data, obj, HWMON_PACK_NAME); 6932c03d07aSLuca Tettamanti limit1 = atk_get_pack_member(data, obj, HWMON_PACK_LIMIT1); 6942c03d07aSLuca Tettamanti limit2 = atk_get_pack_member(data, obj, HWMON_PACK_LIMIT2); 6952c03d07aSLuca Tettamanti 6962c03d07aSLuca Tettamanti sensor = kzalloc(sizeof(*sensor), GFP_KERNEL); 6972c03d07aSLuca Tettamanti if (!sensor) 6982c03d07aSLuca Tettamanti return -ENOMEM; 6992c03d07aSLuca Tettamanti 7002c03d07aSLuca Tettamanti sensor->acpi_name = kstrdup(name->string.pointer, GFP_KERNEL); 7012c03d07aSLuca Tettamanti if (!sensor->acpi_name) { 7022c03d07aSLuca Tettamanti err = -ENOMEM; 7032c03d07aSLuca Tettamanti goto out; 7042c03d07aSLuca Tettamanti } 7052c03d07aSLuca Tettamanti 7062c03d07aSLuca Tettamanti INIT_LIST_HEAD(&sensor->list); 7072c03d07aSLuca Tettamanti sensor->type = type; 7082c03d07aSLuca Tettamanti sensor->data = data; 7092c03d07aSLuca Tettamanti sensor->id = flags->integer.value; 7102c03d07aSLuca Tettamanti sensor->limit1 = limit1->integer.value; 7118d282497SLuca Tettamanti if (data->old_interface) 7122c03d07aSLuca Tettamanti sensor->limit2 = limit2->integer.value; 7138d282497SLuca Tettamanti else 7148d282497SLuca Tettamanti /* The upper limit is expressed as delta from lower limit */ 7158d282497SLuca Tettamanti sensor->limit2 = sensor->limit1 + limit2->integer.value; 7162c03d07aSLuca Tettamanti 7172c03d07aSLuca Tettamanti snprintf(sensor->input_attr_name, ATTR_NAME_SIZE, 7182c03d07aSLuca Tettamanti "%s%d_input", base_name, start + *num); 7192c03d07aSLuca Tettamanti atk_init_attribute(&sensor->input_attr, 7202c03d07aSLuca Tettamanti sensor->input_attr_name, 7212c03d07aSLuca Tettamanti atk_input_show); 7222c03d07aSLuca Tettamanti 7232c03d07aSLuca Tettamanti snprintf(sensor->label_attr_name, ATTR_NAME_SIZE, 7242c03d07aSLuca Tettamanti "%s%d_label", base_name, start + *num); 7252c03d07aSLuca Tettamanti atk_init_attribute(&sensor->label_attr, 7262c03d07aSLuca Tettamanti sensor->label_attr_name, 7272c03d07aSLuca Tettamanti atk_label_show); 7282c03d07aSLuca Tettamanti 7292c03d07aSLuca Tettamanti snprintf(sensor->limit1_attr_name, ATTR_NAME_SIZE, 7302c03d07aSLuca Tettamanti "%s%d_%s", base_name, start + *num, limit1_name); 7312c03d07aSLuca Tettamanti atk_init_attribute(&sensor->limit1_attr, 7322c03d07aSLuca Tettamanti sensor->limit1_attr_name, 7332c03d07aSLuca Tettamanti atk_limit1_show); 7342c03d07aSLuca Tettamanti 7352c03d07aSLuca Tettamanti snprintf(sensor->limit2_attr_name, ATTR_NAME_SIZE, 7362c03d07aSLuca Tettamanti "%s%d_%s", base_name, start + *num, limit2_name); 7372c03d07aSLuca Tettamanti atk_init_attribute(&sensor->limit2_attr, 7382c03d07aSLuca Tettamanti sensor->limit2_attr_name, 7392c03d07aSLuca Tettamanti atk_limit2_show); 7402c03d07aSLuca Tettamanti 7412c03d07aSLuca Tettamanti list_add(&sensor->list, &data->sensor_list); 7422c03d07aSLuca Tettamanti (*num)++; 7432c03d07aSLuca Tettamanti 7442c03d07aSLuca Tettamanti return 1; 7452c03d07aSLuca Tettamanti out: 7462c03d07aSLuca Tettamanti kfree(sensor->acpi_name); 7472c03d07aSLuca Tettamanti kfree(sensor); 7482c03d07aSLuca Tettamanti return err; 7492c03d07aSLuca Tettamanti } 7502c03d07aSLuca Tettamanti 7512c03d07aSLuca Tettamanti static int atk_enumerate_old_hwmon(struct atk_data *data) 7522c03d07aSLuca Tettamanti { 7532c03d07aSLuca Tettamanti struct device *dev = &data->acpi_dev->dev; 7542c03d07aSLuca Tettamanti struct acpi_buffer buf; 7552c03d07aSLuca Tettamanti union acpi_object *pack; 7562c03d07aSLuca Tettamanti acpi_status status; 7572c03d07aSLuca Tettamanti int i, ret; 7582c03d07aSLuca Tettamanti int count = 0; 7592c03d07aSLuca Tettamanti 7602c03d07aSLuca Tettamanti /* Voltages */ 7612c03d07aSLuca Tettamanti buf.length = ACPI_ALLOCATE_BUFFER; 7622c03d07aSLuca Tettamanti status = acpi_evaluate_object_typed(data->atk_handle, 7632c03d07aSLuca Tettamanti METHOD_OLD_ENUM_VLT, NULL, &buf, ACPI_TYPE_PACKAGE); 7642c03d07aSLuca Tettamanti if (status != AE_OK) { 7652c03d07aSLuca Tettamanti dev_warn(dev, METHOD_OLD_ENUM_VLT ": ACPI exception: %s\n", 7662c03d07aSLuca Tettamanti acpi_format_exception(status)); 7672c03d07aSLuca Tettamanti 7682c03d07aSLuca Tettamanti return -ENODEV; 7692c03d07aSLuca Tettamanti } 7702c03d07aSLuca Tettamanti 7712c03d07aSLuca Tettamanti pack = buf.pointer; 7722c03d07aSLuca Tettamanti for (i = 1; i < pack->package.count; i++) { 7732c03d07aSLuca Tettamanti union acpi_object *obj = &pack->package.elements[i]; 7742c03d07aSLuca Tettamanti 7752c03d07aSLuca Tettamanti ret = atk_add_sensor(data, obj); 7762c03d07aSLuca Tettamanti if (ret > 0) 7772c03d07aSLuca Tettamanti count++; 7782c03d07aSLuca Tettamanti } 7792c03d07aSLuca Tettamanti ACPI_FREE(buf.pointer); 7802c03d07aSLuca Tettamanti 7812c03d07aSLuca Tettamanti /* Temperatures */ 7822c03d07aSLuca Tettamanti buf.length = ACPI_ALLOCATE_BUFFER; 7832c03d07aSLuca Tettamanti status = acpi_evaluate_object_typed(data->atk_handle, 7842c03d07aSLuca Tettamanti METHOD_OLD_ENUM_TMP, NULL, &buf, ACPI_TYPE_PACKAGE); 7852c03d07aSLuca Tettamanti if (status != AE_OK) { 7862c03d07aSLuca Tettamanti dev_warn(dev, METHOD_OLD_ENUM_TMP ": ACPI exception: %s\n", 7872c03d07aSLuca Tettamanti acpi_format_exception(status)); 7882c03d07aSLuca Tettamanti 7892c03d07aSLuca Tettamanti ret = -ENODEV; 7902c03d07aSLuca Tettamanti goto cleanup; 7912c03d07aSLuca Tettamanti } 7922c03d07aSLuca Tettamanti 7932c03d07aSLuca Tettamanti pack = buf.pointer; 7942c03d07aSLuca Tettamanti for (i = 1; i < pack->package.count; i++) { 7952c03d07aSLuca Tettamanti union acpi_object *obj = &pack->package.elements[i]; 7962c03d07aSLuca Tettamanti 7972c03d07aSLuca Tettamanti ret = atk_add_sensor(data, obj); 7982c03d07aSLuca Tettamanti if (ret > 0) 7992c03d07aSLuca Tettamanti count++; 8002c03d07aSLuca Tettamanti } 8012c03d07aSLuca Tettamanti ACPI_FREE(buf.pointer); 8022c03d07aSLuca Tettamanti 8032c03d07aSLuca Tettamanti /* Fans */ 8042c03d07aSLuca Tettamanti buf.length = ACPI_ALLOCATE_BUFFER; 8052c03d07aSLuca Tettamanti status = acpi_evaluate_object_typed(data->atk_handle, 8062c03d07aSLuca Tettamanti METHOD_OLD_ENUM_FAN, NULL, &buf, ACPI_TYPE_PACKAGE); 8072c03d07aSLuca Tettamanti if (status != AE_OK) { 8082c03d07aSLuca Tettamanti dev_warn(dev, METHOD_OLD_ENUM_FAN ": ACPI exception: %s\n", 8092c03d07aSLuca Tettamanti acpi_format_exception(status)); 8102c03d07aSLuca Tettamanti 8112c03d07aSLuca Tettamanti ret = -ENODEV; 8122c03d07aSLuca Tettamanti goto cleanup; 8132c03d07aSLuca Tettamanti } 8142c03d07aSLuca Tettamanti 8152c03d07aSLuca Tettamanti pack = buf.pointer; 8162c03d07aSLuca Tettamanti for (i = 1; i < pack->package.count; i++) { 8172c03d07aSLuca Tettamanti union acpi_object *obj = &pack->package.elements[i]; 8182c03d07aSLuca Tettamanti 8192c03d07aSLuca Tettamanti ret = atk_add_sensor(data, obj); 8202c03d07aSLuca Tettamanti if (ret > 0) 8212c03d07aSLuca Tettamanti count++; 8222c03d07aSLuca Tettamanti } 8232c03d07aSLuca Tettamanti ACPI_FREE(buf.pointer); 8242c03d07aSLuca Tettamanti 8252c03d07aSLuca Tettamanti return count; 8262c03d07aSLuca Tettamanti cleanup: 8272c03d07aSLuca Tettamanti atk_free_sensors(data); 8282c03d07aSLuca Tettamanti return ret; 8292c03d07aSLuca Tettamanti } 8302c03d07aSLuca Tettamanti 831*9e6eba61SLuca Tettamanti static int atk_ec_present(struct atk_data *data) 832*9e6eba61SLuca Tettamanti { 833*9e6eba61SLuca Tettamanti struct device *dev = &data->acpi_dev->dev; 834*9e6eba61SLuca Tettamanti union acpi_object *pack; 835*9e6eba61SLuca Tettamanti union acpi_object *ec; 836*9e6eba61SLuca Tettamanti int ret; 837*9e6eba61SLuca Tettamanti int i; 838*9e6eba61SLuca Tettamanti 839*9e6eba61SLuca Tettamanti pack = atk_ggrp(data, ATK_MUX_MGMT); 840*9e6eba61SLuca Tettamanti if (IS_ERR(pack)) { 841*9e6eba61SLuca Tettamanti if (PTR_ERR(pack) == -ENOENT) { 842*9e6eba61SLuca Tettamanti /* The MGMT class does not exists - that's ok */ 843*9e6eba61SLuca Tettamanti dev_dbg(dev, "Class %#llx not found\n", ATK_MUX_MGMT); 844*9e6eba61SLuca Tettamanti return 0; 845*9e6eba61SLuca Tettamanti } 846*9e6eba61SLuca Tettamanti return PTR_ERR(pack); 847*9e6eba61SLuca Tettamanti } 848*9e6eba61SLuca Tettamanti 849*9e6eba61SLuca Tettamanti /* Search the EC */ 850*9e6eba61SLuca Tettamanti ec = NULL; 851*9e6eba61SLuca Tettamanti for (i = 0; i < pack->package.count; i++) { 852*9e6eba61SLuca Tettamanti union acpi_object *obj = &pack->package.elements[i]; 853*9e6eba61SLuca Tettamanti union acpi_object *id; 854*9e6eba61SLuca Tettamanti 855*9e6eba61SLuca Tettamanti if (obj->type != ACPI_TYPE_PACKAGE) 856*9e6eba61SLuca Tettamanti continue; 857*9e6eba61SLuca Tettamanti 858*9e6eba61SLuca Tettamanti id = &obj->package.elements[0]; 859*9e6eba61SLuca Tettamanti if (id->type != ACPI_TYPE_INTEGER) 860*9e6eba61SLuca Tettamanti continue; 861*9e6eba61SLuca Tettamanti 862*9e6eba61SLuca Tettamanti if (id->integer.value == ATK_EC_ID) { 863*9e6eba61SLuca Tettamanti ec = obj; 864*9e6eba61SLuca Tettamanti break; 865*9e6eba61SLuca Tettamanti } 866*9e6eba61SLuca Tettamanti } 867*9e6eba61SLuca Tettamanti 868*9e6eba61SLuca Tettamanti ret = (ec != NULL); 869*9e6eba61SLuca Tettamanti if (!ret) 870*9e6eba61SLuca Tettamanti /* The system has no EC */ 871*9e6eba61SLuca Tettamanti dev_dbg(dev, "EC not found\n"); 872*9e6eba61SLuca Tettamanti 873*9e6eba61SLuca Tettamanti ACPI_FREE(pack); 874*9e6eba61SLuca Tettamanti return ret; 875*9e6eba61SLuca Tettamanti } 876*9e6eba61SLuca Tettamanti 877*9e6eba61SLuca Tettamanti static int atk_ec_enabled(struct atk_data *data) 878*9e6eba61SLuca Tettamanti { 879*9e6eba61SLuca Tettamanti struct device *dev = &data->acpi_dev->dev; 880*9e6eba61SLuca Tettamanti union acpi_object *obj; 881*9e6eba61SLuca Tettamanti struct atk_acpi_ret_buffer *buf; 882*9e6eba61SLuca Tettamanti int err; 883*9e6eba61SLuca Tettamanti 884*9e6eba61SLuca Tettamanti obj = atk_gitm(data, ATK_EC_ID); 885*9e6eba61SLuca Tettamanti if (IS_ERR(obj)) { 886*9e6eba61SLuca Tettamanti dev_err(dev, "Unable to query EC status\n"); 887*9e6eba61SLuca Tettamanti return PTR_ERR(obj); 888*9e6eba61SLuca Tettamanti } 889*9e6eba61SLuca Tettamanti buf = (struct atk_acpi_ret_buffer *)obj->buffer.pointer; 890*9e6eba61SLuca Tettamanti 891*9e6eba61SLuca Tettamanti if (buf->flags == 0) { 892*9e6eba61SLuca Tettamanti dev_err(dev, "Unable to query EC status\n"); 893*9e6eba61SLuca Tettamanti err = -EIO; 894*9e6eba61SLuca Tettamanti } else { 895*9e6eba61SLuca Tettamanti err = (buf->value != 0); 896*9e6eba61SLuca Tettamanti dev_dbg(dev, "EC is %sabled\n", 897*9e6eba61SLuca Tettamanti err ? "en" : "dis"); 898*9e6eba61SLuca Tettamanti } 899*9e6eba61SLuca Tettamanti 900*9e6eba61SLuca Tettamanti ACPI_FREE(obj); 901*9e6eba61SLuca Tettamanti return err; 902*9e6eba61SLuca Tettamanti } 903*9e6eba61SLuca Tettamanti 904*9e6eba61SLuca Tettamanti static int atk_ec_ctl(struct atk_data *data, int enable) 905*9e6eba61SLuca Tettamanti { 906*9e6eba61SLuca Tettamanti struct device *dev = &data->acpi_dev->dev; 907*9e6eba61SLuca Tettamanti union acpi_object *obj; 908*9e6eba61SLuca Tettamanti struct atk_acpi_input_buf sitm; 909*9e6eba61SLuca Tettamanti struct atk_acpi_ret_buffer *ec_ret; 910*9e6eba61SLuca Tettamanti int err = 0; 911*9e6eba61SLuca Tettamanti 912*9e6eba61SLuca Tettamanti sitm.id = ATK_EC_ID; 913*9e6eba61SLuca Tettamanti sitm.param1 = enable; 914*9e6eba61SLuca Tettamanti sitm.param2 = 0; 915*9e6eba61SLuca Tettamanti 916*9e6eba61SLuca Tettamanti obj = atk_sitm(data, &sitm); 917*9e6eba61SLuca Tettamanti if (IS_ERR(obj)) { 918*9e6eba61SLuca Tettamanti dev_err(dev, "Failed to %sable the EC\n", 919*9e6eba61SLuca Tettamanti enable ? "en" : "dis"); 920*9e6eba61SLuca Tettamanti return PTR_ERR(obj); 921*9e6eba61SLuca Tettamanti } 922*9e6eba61SLuca Tettamanti ec_ret = (struct atk_acpi_ret_buffer *)obj->buffer.pointer; 923*9e6eba61SLuca Tettamanti if (ec_ret->flags == 0) { 924*9e6eba61SLuca Tettamanti dev_err(dev, "Failed to %sable the EC\n", 925*9e6eba61SLuca Tettamanti enable ? "en" : "dis"); 926*9e6eba61SLuca Tettamanti err = -EIO; 927*9e6eba61SLuca Tettamanti } else { 928*9e6eba61SLuca Tettamanti dev_info(dev, "EC %sabled\n", 929*9e6eba61SLuca Tettamanti enable ? "en" : "dis"); 930*9e6eba61SLuca Tettamanti } 931*9e6eba61SLuca Tettamanti 932*9e6eba61SLuca Tettamanti ACPI_FREE(obj); 933*9e6eba61SLuca Tettamanti return err; 934*9e6eba61SLuca Tettamanti } 935*9e6eba61SLuca Tettamanti 9362c03d07aSLuca Tettamanti static int atk_enumerate_new_hwmon(struct atk_data *data) 9372c03d07aSLuca Tettamanti { 9382c03d07aSLuca Tettamanti struct device *dev = &data->acpi_dev->dev; 9392c03d07aSLuca Tettamanti union acpi_object *pack; 9402c03d07aSLuca Tettamanti int err; 9412c03d07aSLuca Tettamanti int i; 9422c03d07aSLuca Tettamanti 943*9e6eba61SLuca Tettamanti err = atk_ec_present(data); 944*9e6eba61SLuca Tettamanti if (err < 0) 945*9e6eba61SLuca Tettamanti return err; 946*9e6eba61SLuca Tettamanti if (err) { 947*9e6eba61SLuca Tettamanti err = atk_ec_enabled(data); 948*9e6eba61SLuca Tettamanti if (err < 0) 949*9e6eba61SLuca Tettamanti return err; 950*9e6eba61SLuca Tettamanti /* If the EC was disabled we will disable it again on unload */ 951*9e6eba61SLuca Tettamanti data->disable_ec = err; 952*9e6eba61SLuca Tettamanti 953*9e6eba61SLuca Tettamanti err = atk_ec_ctl(data, 1); 954*9e6eba61SLuca Tettamanti if (err) { 955*9e6eba61SLuca Tettamanti data->disable_ec = false; 956*9e6eba61SLuca Tettamanti return err; 957*9e6eba61SLuca Tettamanti } 958*9e6eba61SLuca Tettamanti } 959*9e6eba61SLuca Tettamanti 9602c03d07aSLuca Tettamanti dev_dbg(dev, "Enumerating hwmon sensors\n"); 9612c03d07aSLuca Tettamanti 96218e25555SLuca Tettamanti pack = atk_ggrp(data, ATK_MUX_HWMON); 96318e25555SLuca Tettamanti if (IS_ERR(pack)) 96418e25555SLuca Tettamanti return PTR_ERR(pack); 9652c03d07aSLuca Tettamanti 9662c03d07aSLuca Tettamanti for (i = 0; i < pack->package.count; i++) { 9672c03d07aSLuca Tettamanti union acpi_object *obj = &pack->package.elements[i]; 9682c03d07aSLuca Tettamanti 9692c03d07aSLuca Tettamanti atk_add_sensor(data, obj); 9702c03d07aSLuca Tettamanti } 9712c03d07aSLuca Tettamanti 9722c03d07aSLuca Tettamanti err = data->voltage_count + data->temperature_count + data->fan_count; 9732c03d07aSLuca Tettamanti 97418e25555SLuca Tettamanti ACPI_FREE(pack); 9752c03d07aSLuca Tettamanti return err; 9762c03d07aSLuca Tettamanti } 9772c03d07aSLuca Tettamanti 9782c03d07aSLuca Tettamanti static int atk_create_files(struct atk_data *data) 9792c03d07aSLuca Tettamanti { 9802c03d07aSLuca Tettamanti struct atk_sensor_data *s; 9812c03d07aSLuca Tettamanti int err; 9822c03d07aSLuca Tettamanti 9832c03d07aSLuca Tettamanti list_for_each_entry(s, &data->sensor_list, list) { 9842c03d07aSLuca Tettamanti err = device_create_file(data->hwmon_dev, &s->input_attr); 9852c03d07aSLuca Tettamanti if (err) 9862c03d07aSLuca Tettamanti return err; 9872c03d07aSLuca Tettamanti err = device_create_file(data->hwmon_dev, &s->label_attr); 9882c03d07aSLuca Tettamanti if (err) 9892c03d07aSLuca Tettamanti return err; 9902c03d07aSLuca Tettamanti err = device_create_file(data->hwmon_dev, &s->limit1_attr); 9912c03d07aSLuca Tettamanti if (err) 9922c03d07aSLuca Tettamanti return err; 9932c03d07aSLuca Tettamanti err = device_create_file(data->hwmon_dev, &s->limit2_attr); 9942c03d07aSLuca Tettamanti if (err) 9952c03d07aSLuca Tettamanti return err; 9962c03d07aSLuca Tettamanti } 9972c03d07aSLuca Tettamanti 9982c03d07aSLuca Tettamanti err = device_create_file(data->hwmon_dev, &atk_name_attr); 9992c03d07aSLuca Tettamanti 10002c03d07aSLuca Tettamanti return err; 10012c03d07aSLuca Tettamanti } 10022c03d07aSLuca Tettamanti 10032c03d07aSLuca Tettamanti static void atk_remove_files(struct atk_data *data) 10042c03d07aSLuca Tettamanti { 10052c03d07aSLuca Tettamanti struct atk_sensor_data *s; 10062c03d07aSLuca Tettamanti 10072c03d07aSLuca Tettamanti list_for_each_entry(s, &data->sensor_list, list) { 10082c03d07aSLuca Tettamanti device_remove_file(data->hwmon_dev, &s->input_attr); 10092c03d07aSLuca Tettamanti device_remove_file(data->hwmon_dev, &s->label_attr); 10102c03d07aSLuca Tettamanti device_remove_file(data->hwmon_dev, &s->limit1_attr); 10112c03d07aSLuca Tettamanti device_remove_file(data->hwmon_dev, &s->limit2_attr); 10122c03d07aSLuca Tettamanti } 10132c03d07aSLuca Tettamanti device_remove_file(data->hwmon_dev, &atk_name_attr); 10142c03d07aSLuca Tettamanti } 10152c03d07aSLuca Tettamanti 10162c03d07aSLuca Tettamanti static void atk_free_sensors(struct atk_data *data) 10172c03d07aSLuca Tettamanti { 10182c03d07aSLuca Tettamanti struct list_head *head = &data->sensor_list; 10192c03d07aSLuca Tettamanti struct atk_sensor_data *s, *tmp; 10202c03d07aSLuca Tettamanti 10212c03d07aSLuca Tettamanti list_for_each_entry_safe(s, tmp, head, list) { 10222c03d07aSLuca Tettamanti kfree(s->acpi_name); 10232c03d07aSLuca Tettamanti kfree(s); 10242c03d07aSLuca Tettamanti } 10252c03d07aSLuca Tettamanti } 10262c03d07aSLuca Tettamanti 10272c03d07aSLuca Tettamanti static int atk_register_hwmon(struct atk_data *data) 10282c03d07aSLuca Tettamanti { 10292c03d07aSLuca Tettamanti struct device *dev = &data->acpi_dev->dev; 10302c03d07aSLuca Tettamanti int err; 10312c03d07aSLuca Tettamanti 10322c03d07aSLuca Tettamanti dev_dbg(dev, "registering hwmon device\n"); 10332c03d07aSLuca Tettamanti data->hwmon_dev = hwmon_device_register(dev); 10342c03d07aSLuca Tettamanti if (IS_ERR(data->hwmon_dev)) 10352c03d07aSLuca Tettamanti return PTR_ERR(data->hwmon_dev); 10362c03d07aSLuca Tettamanti 10372c03d07aSLuca Tettamanti dev_dbg(dev, "populating sysfs directory\n"); 10382c03d07aSLuca Tettamanti err = atk_create_files(data); 10392c03d07aSLuca Tettamanti if (err) 10402c03d07aSLuca Tettamanti goto remove; 10412c03d07aSLuca Tettamanti 10422c03d07aSLuca Tettamanti return 0; 10432c03d07aSLuca Tettamanti remove: 10442c03d07aSLuca Tettamanti /* Cleanup the registered files */ 10452c03d07aSLuca Tettamanti atk_remove_files(data); 10462c03d07aSLuca Tettamanti hwmon_device_unregister(data->hwmon_dev); 10472c03d07aSLuca Tettamanti return err; 10482c03d07aSLuca Tettamanti } 10492c03d07aSLuca Tettamanti 10502c03d07aSLuca Tettamanti static int atk_check_old_if(struct atk_data *data) 10512c03d07aSLuca Tettamanti { 10522c03d07aSLuca Tettamanti struct device *dev = &data->acpi_dev->dev; 10532c03d07aSLuca Tettamanti acpi_handle ret; 10542c03d07aSLuca Tettamanti acpi_status status; 10552c03d07aSLuca Tettamanti 10562c03d07aSLuca Tettamanti /* RTMP: read temperature */ 10572c03d07aSLuca Tettamanti status = acpi_get_handle(data->atk_handle, METHOD_OLD_READ_TMP, &ret); 10582c03d07aSLuca Tettamanti if (status != AE_OK) { 10592c03d07aSLuca Tettamanti dev_dbg(dev, "method " METHOD_OLD_READ_TMP " not found: %s\n", 10602c03d07aSLuca Tettamanti acpi_format_exception(status)); 10612c03d07aSLuca Tettamanti return -ENODEV; 10622c03d07aSLuca Tettamanti } 10632c03d07aSLuca Tettamanti data->rtmp_handle = ret; 10642c03d07aSLuca Tettamanti 10652c03d07aSLuca Tettamanti /* RVLT: read voltage */ 10662c03d07aSLuca Tettamanti status = acpi_get_handle(data->atk_handle, METHOD_OLD_READ_VLT, &ret); 10672c03d07aSLuca Tettamanti if (status != AE_OK) { 10682c03d07aSLuca Tettamanti dev_dbg(dev, "method " METHOD_OLD_READ_VLT " not found: %s\n", 10692c03d07aSLuca Tettamanti acpi_format_exception(status)); 10702c03d07aSLuca Tettamanti return -ENODEV; 10712c03d07aSLuca Tettamanti } 10722c03d07aSLuca Tettamanti data->rvlt_handle = ret; 10732c03d07aSLuca Tettamanti 10742c03d07aSLuca Tettamanti /* RFAN: read fan status */ 10752c03d07aSLuca Tettamanti status = acpi_get_handle(data->atk_handle, METHOD_OLD_READ_FAN, &ret); 10762c03d07aSLuca Tettamanti if (status != AE_OK) { 10772c03d07aSLuca Tettamanti dev_dbg(dev, "method " METHOD_OLD_READ_FAN " not found: %s\n", 10782c03d07aSLuca Tettamanti acpi_format_exception(status)); 10792c03d07aSLuca Tettamanti return -ENODEV; 10802c03d07aSLuca Tettamanti } 10812c03d07aSLuca Tettamanti data->rfan_handle = ret; 10822c03d07aSLuca Tettamanti 10832c03d07aSLuca Tettamanti return 0; 10842c03d07aSLuca Tettamanti } 10852c03d07aSLuca Tettamanti 10862c03d07aSLuca Tettamanti static int atk_check_new_if(struct atk_data *data) 10872c03d07aSLuca Tettamanti { 10882c03d07aSLuca Tettamanti struct device *dev = &data->acpi_dev->dev; 10892c03d07aSLuca Tettamanti acpi_handle ret; 10902c03d07aSLuca Tettamanti acpi_status status; 10912c03d07aSLuca Tettamanti 10922c03d07aSLuca Tettamanti /* Enumeration */ 10932c03d07aSLuca Tettamanti status = acpi_get_handle(data->atk_handle, METHOD_ENUMERATE, &ret); 10942c03d07aSLuca Tettamanti if (status != AE_OK) { 10952c03d07aSLuca Tettamanti dev_dbg(dev, "method " METHOD_ENUMERATE " not found: %s\n", 10962c03d07aSLuca Tettamanti acpi_format_exception(status)); 10972c03d07aSLuca Tettamanti return -ENODEV; 10982c03d07aSLuca Tettamanti } 10992c03d07aSLuca Tettamanti data->enumerate_handle = ret; 11002c03d07aSLuca Tettamanti 11012c03d07aSLuca Tettamanti /* De-multiplexer (read) */ 11022c03d07aSLuca Tettamanti status = acpi_get_handle(data->atk_handle, METHOD_READ, &ret); 11032c03d07aSLuca Tettamanti if (status != AE_OK) { 11042c03d07aSLuca Tettamanti dev_dbg(dev, "method " METHOD_READ " not found: %s\n", 11052c03d07aSLuca Tettamanti acpi_format_exception(status)); 11062c03d07aSLuca Tettamanti return -ENODEV; 11072c03d07aSLuca Tettamanti } 11082c03d07aSLuca Tettamanti data->read_handle = ret; 11092c03d07aSLuca Tettamanti 1110*9e6eba61SLuca Tettamanti /* De-multiplexer (write) */ 1111*9e6eba61SLuca Tettamanti status = acpi_get_handle(data->atk_handle, METHOD_WRITE, &ret); 1112*9e6eba61SLuca Tettamanti if (status != AE_OK) { 1113*9e6eba61SLuca Tettamanti dev_dbg(dev, "method " METHOD_READ " not found: %s\n", 1114*9e6eba61SLuca Tettamanti acpi_format_exception(status)); 1115*9e6eba61SLuca Tettamanti return -ENODEV; 1116*9e6eba61SLuca Tettamanti } 1117*9e6eba61SLuca Tettamanti data->write_handle = ret; 1118*9e6eba61SLuca Tettamanti 11192c03d07aSLuca Tettamanti return 0; 11202c03d07aSLuca Tettamanti } 11212c03d07aSLuca Tettamanti 11222c03d07aSLuca Tettamanti static int atk_add(struct acpi_device *device) 11232c03d07aSLuca Tettamanti { 11242c03d07aSLuca Tettamanti acpi_status ret; 11252c03d07aSLuca Tettamanti int err; 11262c03d07aSLuca Tettamanti struct acpi_buffer buf; 11272c03d07aSLuca Tettamanti union acpi_object *obj; 11282c03d07aSLuca Tettamanti struct atk_data *data; 11292c03d07aSLuca Tettamanti 11302c03d07aSLuca Tettamanti dev_dbg(&device->dev, "adding...\n"); 11312c03d07aSLuca Tettamanti 11322c03d07aSLuca Tettamanti data = kzalloc(sizeof(*data), GFP_KERNEL); 11332c03d07aSLuca Tettamanti if (!data) 11342c03d07aSLuca Tettamanti return -ENOMEM; 11352c03d07aSLuca Tettamanti 11362c03d07aSLuca Tettamanti data->acpi_dev = device; 11372c03d07aSLuca Tettamanti data->atk_handle = device->handle; 11382c03d07aSLuca Tettamanti INIT_LIST_HEAD(&data->sensor_list); 1139*9e6eba61SLuca Tettamanti data->disable_ec = false; 11402c03d07aSLuca Tettamanti 11412c03d07aSLuca Tettamanti buf.length = ACPI_ALLOCATE_BUFFER; 11422c03d07aSLuca Tettamanti ret = acpi_evaluate_object_typed(data->atk_handle, BOARD_ID, NULL, 11432c03d07aSLuca Tettamanti &buf, ACPI_TYPE_PACKAGE); 11442c03d07aSLuca Tettamanti if (ret != AE_OK) { 11452c03d07aSLuca Tettamanti dev_dbg(&device->dev, "atk: method MBIF not found\n"); 11462c03d07aSLuca Tettamanti err = -ENODEV; 11472c03d07aSLuca Tettamanti goto out; 11482c03d07aSLuca Tettamanti } 11492c03d07aSLuca Tettamanti 11502c03d07aSLuca Tettamanti obj = buf.pointer; 11512c03d07aSLuca Tettamanti if (obj->package.count >= 2 && 11522c03d07aSLuca Tettamanti obj->package.elements[1].type == ACPI_TYPE_STRING) { 11532c03d07aSLuca Tettamanti dev_dbg(&device->dev, "board ID = %s\n", 11542c03d07aSLuca Tettamanti obj->package.elements[1].string.pointer); 11552c03d07aSLuca Tettamanti } 11562c03d07aSLuca Tettamanti ACPI_FREE(buf.pointer); 11572c03d07aSLuca Tettamanti 11582c03d07aSLuca Tettamanti /* Check for hwmon methods: first check "old" style methods; note that 11592c03d07aSLuca Tettamanti * both may be present: in this case we stick to the old interface; 11602c03d07aSLuca Tettamanti * analysis of multiple DSDTs indicates that when both interfaces 11612c03d07aSLuca Tettamanti * are present the new one (GGRP/GITM) is not functional. 11622c03d07aSLuca Tettamanti */ 11632c03d07aSLuca Tettamanti err = atk_check_old_if(data); 11642c03d07aSLuca Tettamanti if (!err) { 11652c03d07aSLuca Tettamanti dev_dbg(&device->dev, "Using old hwmon interface\n"); 11662c03d07aSLuca Tettamanti data->old_interface = true; 11672c03d07aSLuca Tettamanti } else { 11682c03d07aSLuca Tettamanti err = atk_check_new_if(data); 11692c03d07aSLuca Tettamanti if (err) 11702c03d07aSLuca Tettamanti goto out; 11712c03d07aSLuca Tettamanti 11722c03d07aSLuca Tettamanti dev_dbg(&device->dev, "Using new hwmon interface\n"); 11732c03d07aSLuca Tettamanti data->old_interface = false; 11742c03d07aSLuca Tettamanti } 11752c03d07aSLuca Tettamanti 11762c03d07aSLuca Tettamanti if (data->old_interface) 11772c03d07aSLuca Tettamanti err = atk_enumerate_old_hwmon(data); 11782c03d07aSLuca Tettamanti else 11792c03d07aSLuca Tettamanti err = atk_enumerate_new_hwmon(data); 11802c03d07aSLuca Tettamanti if (err < 0) 11812c03d07aSLuca Tettamanti goto out; 11822c03d07aSLuca Tettamanti if (err == 0) { 11832c03d07aSLuca Tettamanti dev_info(&device->dev, 11842c03d07aSLuca Tettamanti "No usable sensor detected, bailing out\n"); 11852c03d07aSLuca Tettamanti err = -ENODEV; 11862c03d07aSLuca Tettamanti goto out; 11872c03d07aSLuca Tettamanti } 11882c03d07aSLuca Tettamanti 11892c03d07aSLuca Tettamanti err = atk_register_hwmon(data); 11902c03d07aSLuca Tettamanti if (err) 11912c03d07aSLuca Tettamanti goto cleanup; 11922c03d07aSLuca Tettamanti 11932c03d07aSLuca Tettamanti device->driver_data = data; 11942c03d07aSLuca Tettamanti return 0; 11952c03d07aSLuca Tettamanti cleanup: 11962c03d07aSLuca Tettamanti atk_free_sensors(data); 11972c03d07aSLuca Tettamanti out: 1198*9e6eba61SLuca Tettamanti if (data->disable_ec) 1199*9e6eba61SLuca Tettamanti atk_ec_ctl(data, 0); 12002c03d07aSLuca Tettamanti kfree(data); 12012c03d07aSLuca Tettamanti return err; 12022c03d07aSLuca Tettamanti } 12032c03d07aSLuca Tettamanti 12042c03d07aSLuca Tettamanti static int atk_remove(struct acpi_device *device, int type) 12052c03d07aSLuca Tettamanti { 12062c03d07aSLuca Tettamanti struct atk_data *data = device->driver_data; 12072c03d07aSLuca Tettamanti dev_dbg(&device->dev, "removing...\n"); 12082c03d07aSLuca Tettamanti 12092c03d07aSLuca Tettamanti device->driver_data = NULL; 12102c03d07aSLuca Tettamanti 12112c03d07aSLuca Tettamanti atk_remove_files(data); 12122c03d07aSLuca Tettamanti atk_free_sensors(data); 12132c03d07aSLuca Tettamanti hwmon_device_unregister(data->hwmon_dev); 12142c03d07aSLuca Tettamanti 1215*9e6eba61SLuca Tettamanti if (data->disable_ec) { 1216*9e6eba61SLuca Tettamanti if (atk_ec_ctl(data, 0)) 1217*9e6eba61SLuca Tettamanti dev_err(&device->dev, "Failed to disable EC\n"); 1218*9e6eba61SLuca Tettamanti } 1219*9e6eba61SLuca Tettamanti 12202c03d07aSLuca Tettamanti kfree(data); 12212c03d07aSLuca Tettamanti 12222c03d07aSLuca Tettamanti return 0; 12232c03d07aSLuca Tettamanti } 12242c03d07aSLuca Tettamanti 12252c03d07aSLuca Tettamanti static int __init atk0110_init(void) 12262c03d07aSLuca Tettamanti { 12272c03d07aSLuca Tettamanti int ret; 12282c03d07aSLuca Tettamanti 12292c03d07aSLuca Tettamanti ret = acpi_bus_register_driver(&atk_driver); 12302c03d07aSLuca Tettamanti if (ret) 12312c03d07aSLuca Tettamanti pr_info("atk: acpi_bus_register_driver failed: %d\n", ret); 12322c03d07aSLuca Tettamanti 12332c03d07aSLuca Tettamanti return ret; 12342c03d07aSLuca Tettamanti } 12352c03d07aSLuca Tettamanti 12362c03d07aSLuca Tettamanti static void __exit atk0110_exit(void) 12372c03d07aSLuca Tettamanti { 12382c03d07aSLuca Tettamanti acpi_bus_unregister_driver(&atk_driver); 12392c03d07aSLuca Tettamanti } 12402c03d07aSLuca Tettamanti 12412c03d07aSLuca Tettamanti module_init(atk0110_init); 12422c03d07aSLuca Tettamanti module_exit(atk0110_exit); 12432c03d07aSLuca Tettamanti 12442c03d07aSLuca Tettamanti MODULE_LICENSE("GPL"); 1245