155716d26SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
22c03d07aSLuca Tettamanti /*
32c03d07aSLuca Tettamanti * Copyright (C) 2007-2009 Luca Tettamanti <kronos.it@gmail.com>
42c03d07aSLuca Tettamanti *
52c03d07aSLuca Tettamanti * See COPYING in the top level directory of the kernel tree.
62c03d07aSLuca Tettamanti */
72c03d07aSLuca Tettamanti
8ac561494SJoe Perches #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
9ac561494SJoe Perches
107e5eab11SLuca Tettamanti #include <linux/debugfs.h>
112c03d07aSLuca Tettamanti #include <linux/kernel.h>
122c03d07aSLuca Tettamanti #include <linux/hwmon.h>
132c03d07aSLuca Tettamanti #include <linux/list.h>
142c03d07aSLuca Tettamanti #include <linux/module.h>
155a0e3ad6STejun Heo #include <linux/slab.h>
1686ca33e8SLuca Tettamanti #include <linux/dmi.h>
17dcd8f392SJean Delvare #include <linux/jiffies.h>
18fa845740SJean Delvare #include <linux/err.h>
198b48463fSLv Zheng #include <linux/acpi.h>
202c03d07aSLuca Tettamanti
212c03d07aSLuca Tettamanti #define ATK_HID "ATK0110"
222c03d07aSLuca Tettamanti
2386ca33e8SLuca Tettamanti static bool new_if;
2486ca33e8SLuca Tettamanti module_param(new_if, bool, 0);
2586ca33e8SLuca Tettamanti MODULE_PARM_DESC(new_if, "Override detection heuristic and force the use of the new ATK0110 interface");
2686ca33e8SLuca Tettamanti
2786ca33e8SLuca Tettamanti static const struct dmi_system_id __initconst atk_force_new_if[] = {
2886ca33e8SLuca Tettamanti {
2986ca33e8SLuca Tettamanti /* Old interface has broken MCH temp monitoring */
3086ca33e8SLuca Tettamanti .ident = "Asus Sabertooth X58",
3186ca33e8SLuca Tettamanti .matches = {
3286ca33e8SLuca Tettamanti DMI_MATCH(DMI_BOARD_NAME, "SABERTOOTH X58")
3386ca33e8SLuca Tettamanti }
3443ca6cb2SLuca Tettamanti }, {
3543ca6cb2SLuca Tettamanti /* Old interface reads the same sensor for fan0 and fan1 */
3643ca6cb2SLuca Tettamanti .ident = "Asus M5A78L",
3743ca6cb2SLuca Tettamanti .matches = {
3843ca6cb2SLuca Tettamanti DMI_MATCH(DMI_BOARD_NAME, "M5A78L")
3943ca6cb2SLuca Tettamanti }
4086ca33e8SLuca Tettamanti },
4186ca33e8SLuca Tettamanti { }
4286ca33e8SLuca Tettamanti };
4386ca33e8SLuca Tettamanti
4475bdc936SGuenter Roeck /*
4575bdc936SGuenter Roeck * Minimum time between readings, enforced in order to avoid
462c03d07aSLuca Tettamanti * hogging the CPU.
472c03d07aSLuca Tettamanti */
482c03d07aSLuca Tettamanti #define CACHE_TIME HZ
492c03d07aSLuca Tettamanti
502c03d07aSLuca Tettamanti #define BOARD_ID "MBIF"
512c03d07aSLuca Tettamanti #define METHOD_ENUMERATE "GGRP"
522c03d07aSLuca Tettamanti #define METHOD_READ "GITM"
532c03d07aSLuca Tettamanti #define METHOD_WRITE "SITM"
542c03d07aSLuca Tettamanti #define METHOD_OLD_READ_TMP "RTMP"
552c03d07aSLuca Tettamanti #define METHOD_OLD_READ_VLT "RVLT"
562c03d07aSLuca Tettamanti #define METHOD_OLD_READ_FAN "RFAN"
572c03d07aSLuca Tettamanti #define METHOD_OLD_ENUM_TMP "TSIF"
582c03d07aSLuca Tettamanti #define METHOD_OLD_ENUM_VLT "VSIF"
592c03d07aSLuca Tettamanti #define METHOD_OLD_ENUM_FAN "FSIF"
602c03d07aSLuca Tettamanti
612c03d07aSLuca Tettamanti #define ATK_MUX_HWMON 0x00000006ULL
629e6eba61SLuca Tettamanti #define ATK_MUX_MGMT 0x00000011ULL
632c03d07aSLuca Tettamanti
642c03d07aSLuca Tettamanti #define ATK_CLASS_MASK 0xff000000ULL
652c03d07aSLuca Tettamanti #define ATK_CLASS_FREQ_CTL 0x03000000ULL
662c03d07aSLuca Tettamanti #define ATK_CLASS_FAN_CTL 0x04000000ULL
672c03d07aSLuca Tettamanti #define ATK_CLASS_HWMON 0x06000000ULL
689e6eba61SLuca Tettamanti #define ATK_CLASS_MGMT 0x11000000ULL
692c03d07aSLuca Tettamanti
702c03d07aSLuca Tettamanti #define ATK_TYPE_MASK 0x00ff0000ULL
712c03d07aSLuca Tettamanti #define HWMON_TYPE_VOLT 0x00020000ULL
722c03d07aSLuca Tettamanti #define HWMON_TYPE_TEMP 0x00030000ULL
732c03d07aSLuca Tettamanti #define HWMON_TYPE_FAN 0x00040000ULL
742c03d07aSLuca Tettamanti
759e6eba61SLuca Tettamanti #define ATK_ELEMENT_ID_MASK 0x0000ffffULL
769e6eba61SLuca Tettamanti
779e6eba61SLuca Tettamanti #define ATK_EC_ID 0x11060004ULL
782c03d07aSLuca Tettamanti
792c03d07aSLuca Tettamanti enum atk_pack_member {
802c03d07aSLuca Tettamanti HWMON_PACK_FLAGS,
812c03d07aSLuca Tettamanti HWMON_PACK_NAME,
822c03d07aSLuca Tettamanti HWMON_PACK_LIMIT1,
832c03d07aSLuca Tettamanti HWMON_PACK_LIMIT2,
842c03d07aSLuca Tettamanti HWMON_PACK_ENABLE
852c03d07aSLuca Tettamanti };
862c03d07aSLuca Tettamanti
872c03d07aSLuca Tettamanti /* New package format */
882c03d07aSLuca Tettamanti #define _HWMON_NEW_PACK_SIZE 7
892c03d07aSLuca Tettamanti #define _HWMON_NEW_PACK_FLAGS 0
902c03d07aSLuca Tettamanti #define _HWMON_NEW_PACK_NAME 1
912c03d07aSLuca Tettamanti #define _HWMON_NEW_PACK_UNK1 2
922c03d07aSLuca Tettamanti #define _HWMON_NEW_PACK_UNK2 3
932c03d07aSLuca Tettamanti #define _HWMON_NEW_PACK_LIMIT1 4
942c03d07aSLuca Tettamanti #define _HWMON_NEW_PACK_LIMIT2 5
952c03d07aSLuca Tettamanti #define _HWMON_NEW_PACK_ENABLE 6
962c03d07aSLuca Tettamanti
972c03d07aSLuca Tettamanti /* Old package format */
982c03d07aSLuca Tettamanti #define _HWMON_OLD_PACK_SIZE 5
992c03d07aSLuca Tettamanti #define _HWMON_OLD_PACK_FLAGS 0
1002c03d07aSLuca Tettamanti #define _HWMON_OLD_PACK_NAME 1
1012c03d07aSLuca Tettamanti #define _HWMON_OLD_PACK_LIMIT1 2
1022c03d07aSLuca Tettamanti #define _HWMON_OLD_PACK_LIMIT2 3
1032c03d07aSLuca Tettamanti #define _HWMON_OLD_PACK_ENABLE 4
1042c03d07aSLuca Tettamanti
1052c03d07aSLuca Tettamanti
1062c03d07aSLuca Tettamanti struct atk_data {
1072c03d07aSLuca Tettamanti struct device *hwmon_dev;
1082c03d07aSLuca Tettamanti acpi_handle atk_handle;
1092c03d07aSLuca Tettamanti struct acpi_device *acpi_dev;
1102c03d07aSLuca Tettamanti
1112c03d07aSLuca Tettamanti bool old_interface;
1122c03d07aSLuca Tettamanti
1132c03d07aSLuca Tettamanti /* old interface */
1142c03d07aSLuca Tettamanti acpi_handle rtmp_handle;
1152c03d07aSLuca Tettamanti acpi_handle rvlt_handle;
1162c03d07aSLuca Tettamanti acpi_handle rfan_handle;
11784fb029fSLABBE Corentin /* new interface */
1182c03d07aSLuca Tettamanti acpi_handle enumerate_handle;
1192c03d07aSLuca Tettamanti acpi_handle read_handle;
1209e6eba61SLuca Tettamanti acpi_handle write_handle;
1219e6eba61SLuca Tettamanti
1229e6eba61SLuca Tettamanti bool disable_ec;
1232c03d07aSLuca Tettamanti
1242c03d07aSLuca Tettamanti int voltage_count;
1252c03d07aSLuca Tettamanti int temperature_count;
1262c03d07aSLuca Tettamanti int fan_count;
1272c03d07aSLuca Tettamanti struct list_head sensor_list;
1283c60726dSBastian Germann struct attribute_group attr_group;
1293c60726dSBastian Germann const struct attribute_group *attr_groups[2];
1307e5eab11SLuca Tettamanti
1317e5eab11SLuca Tettamanti struct {
1327e5eab11SLuca Tettamanti struct dentry *root;
1337e5eab11SLuca Tettamanti u32 id;
1347e5eab11SLuca Tettamanti } debugfs;
1352c03d07aSLuca Tettamanti };
1362c03d07aSLuca Tettamanti
1372c03d07aSLuca Tettamanti
1382c03d07aSLuca Tettamanti typedef ssize_t (*sysfs_show_func)(struct device *dev,
1392c03d07aSLuca Tettamanti struct device_attribute *attr, char *buf);
1402c03d07aSLuca Tettamanti
1412c03d07aSLuca Tettamanti static const struct acpi_device_id atk_ids[] = {
1422c03d07aSLuca Tettamanti {ATK_HID, 0},
1432c03d07aSLuca Tettamanti {"", 0},
1442c03d07aSLuca Tettamanti };
1452c03d07aSLuca Tettamanti MODULE_DEVICE_TABLE(acpi, atk_ids);
1462c03d07aSLuca Tettamanti
1472c03d07aSLuca Tettamanti #define ATTR_NAME_SIZE 16 /* Worst case is "tempN_input" */
1482c03d07aSLuca Tettamanti
1492c03d07aSLuca Tettamanti struct atk_sensor_data {
1502c03d07aSLuca Tettamanti struct list_head list;
1512c03d07aSLuca Tettamanti struct atk_data *data;
1522c03d07aSLuca Tettamanti struct device_attribute label_attr;
1532c03d07aSLuca Tettamanti struct device_attribute input_attr;
1542c03d07aSLuca Tettamanti struct device_attribute limit1_attr;
1552c03d07aSLuca Tettamanti struct device_attribute limit2_attr;
1562c03d07aSLuca Tettamanti char label_attr_name[ATTR_NAME_SIZE];
1572c03d07aSLuca Tettamanti char input_attr_name[ATTR_NAME_SIZE];
1582c03d07aSLuca Tettamanti char limit1_attr_name[ATTR_NAME_SIZE];
1592c03d07aSLuca Tettamanti char limit2_attr_name[ATTR_NAME_SIZE];
1602c03d07aSLuca Tettamanti u64 id;
1612c03d07aSLuca Tettamanti u64 type;
1622c03d07aSLuca Tettamanti u64 limit1;
1632c03d07aSLuca Tettamanti u64 limit2;
1642c03d07aSLuca Tettamanti u64 cached_value;
1652c03d07aSLuca Tettamanti unsigned long last_updated; /* in jiffies */
1662c03d07aSLuca Tettamanti bool is_valid;
1672c03d07aSLuca Tettamanti char const *acpi_name;
1682c03d07aSLuca Tettamanti };
1692c03d07aSLuca Tettamanti
17075bdc936SGuenter Roeck /*
17175bdc936SGuenter Roeck * Return buffer format:
17218e25555SLuca Tettamanti * [0-3] "value" is valid flag
17318e25555SLuca Tettamanti * [4-7] value
17418e25555SLuca Tettamanti * [8- ] unknown stuff on newer mobos
17518e25555SLuca Tettamanti */
17618e25555SLuca Tettamanti struct atk_acpi_ret_buffer {
17718e25555SLuca Tettamanti u32 flags;
17818e25555SLuca Tettamanti u32 value;
17918e25555SLuca Tettamanti u8 data[];
18018e25555SLuca Tettamanti };
18118e25555SLuca Tettamanti
18218e25555SLuca Tettamanti /* Input buffer used for GITM and SITM methods */
18318e25555SLuca Tettamanti struct atk_acpi_input_buf {
18418e25555SLuca Tettamanti u32 id;
18518e25555SLuca Tettamanti u32 param1;
18618e25555SLuca Tettamanti u32 param2;
1872c03d07aSLuca Tettamanti };
1882c03d07aSLuca Tettamanti
1892c03d07aSLuca Tettamanti static int atk_add(struct acpi_device *device);
190*6c0eb5baSDawei Li static void atk_remove(struct acpi_device *device);
1912c03d07aSLuca Tettamanti static void atk_print_sensor(struct atk_data *data, union acpi_object *obj);
1922c03d07aSLuca Tettamanti static int atk_read_value(struct atk_sensor_data *sensor, u64 *value);
1932c03d07aSLuca Tettamanti
1942c03d07aSLuca Tettamanti static struct acpi_driver atk_driver = {
1952c03d07aSLuca Tettamanti .name = ATK_HID,
1962c03d07aSLuca Tettamanti .class = "hwmon",
1972c03d07aSLuca Tettamanti .ids = atk_ids,
1982c03d07aSLuca Tettamanti .ops = {
1992c03d07aSLuca Tettamanti .add = atk_add,
2002c03d07aSLuca Tettamanti .remove = atk_remove,
2012c03d07aSLuca Tettamanti },
2022c03d07aSLuca Tettamanti };
2032c03d07aSLuca Tettamanti
2042c03d07aSLuca Tettamanti #define input_to_atk_sensor(attr) \
2052c03d07aSLuca Tettamanti container_of(attr, struct atk_sensor_data, input_attr)
2062c03d07aSLuca Tettamanti
2072c03d07aSLuca Tettamanti #define label_to_atk_sensor(attr) \
2082c03d07aSLuca Tettamanti container_of(attr, struct atk_sensor_data, label_attr)
2092c03d07aSLuca Tettamanti
2102c03d07aSLuca Tettamanti #define limit1_to_atk_sensor(attr) \
2112c03d07aSLuca Tettamanti container_of(attr, struct atk_sensor_data, limit1_attr)
2122c03d07aSLuca Tettamanti
2132c03d07aSLuca Tettamanti #define limit2_to_atk_sensor(attr) \
2142c03d07aSLuca Tettamanti container_of(attr, struct atk_sensor_data, limit2_attr)
2152c03d07aSLuca Tettamanti
atk_input_show(struct device * dev,struct device_attribute * attr,char * buf)2162c03d07aSLuca Tettamanti static ssize_t atk_input_show(struct device *dev,
2172c03d07aSLuca Tettamanti struct device_attribute *attr, char *buf)
2182c03d07aSLuca Tettamanti {
2192c03d07aSLuca Tettamanti struct atk_sensor_data *s = input_to_atk_sensor(attr);
2202c03d07aSLuca Tettamanti u64 value;
2212c03d07aSLuca Tettamanti int err;
2222c03d07aSLuca Tettamanti
2232c03d07aSLuca Tettamanti err = atk_read_value(s, &value);
2242c03d07aSLuca Tettamanti if (err)
2252c03d07aSLuca Tettamanti return err;
2262c03d07aSLuca Tettamanti
2272c03d07aSLuca Tettamanti if (s->type == HWMON_TYPE_TEMP)
2282c03d07aSLuca Tettamanti /* ACPI returns decidegree */
2292c03d07aSLuca Tettamanti value *= 100;
2302c03d07aSLuca Tettamanti
2312c03d07aSLuca Tettamanti return sprintf(buf, "%llu\n", value);
2322c03d07aSLuca Tettamanti }
2332c03d07aSLuca Tettamanti
atk_label_show(struct device * dev,struct device_attribute * attr,char * buf)2342c03d07aSLuca Tettamanti static ssize_t atk_label_show(struct device *dev,
2352c03d07aSLuca Tettamanti struct device_attribute *attr, char *buf)
2362c03d07aSLuca Tettamanti {
2372c03d07aSLuca Tettamanti struct atk_sensor_data *s = label_to_atk_sensor(attr);
2382c03d07aSLuca Tettamanti
2392c03d07aSLuca Tettamanti return sprintf(buf, "%s\n", s->acpi_name);
2402c03d07aSLuca Tettamanti }
2412c03d07aSLuca Tettamanti
atk_limit1_show(struct device * dev,struct device_attribute * attr,char * buf)2422c03d07aSLuca Tettamanti static ssize_t atk_limit1_show(struct device *dev,
2432c03d07aSLuca Tettamanti struct device_attribute *attr, char *buf)
2442c03d07aSLuca Tettamanti {
2452c03d07aSLuca Tettamanti struct atk_sensor_data *s = limit1_to_atk_sensor(attr);
2462c03d07aSLuca Tettamanti u64 value = s->limit1;
2472c03d07aSLuca Tettamanti
2482c03d07aSLuca Tettamanti if (s->type == HWMON_TYPE_TEMP)
2492c03d07aSLuca Tettamanti value *= 100;
2502c03d07aSLuca Tettamanti
2512c03d07aSLuca Tettamanti return sprintf(buf, "%lld\n", value);
2522c03d07aSLuca Tettamanti }
2532c03d07aSLuca Tettamanti
atk_limit2_show(struct device * dev,struct device_attribute * attr,char * buf)2542c03d07aSLuca Tettamanti static ssize_t atk_limit2_show(struct device *dev,
2552c03d07aSLuca Tettamanti struct device_attribute *attr, char *buf)
2562c03d07aSLuca Tettamanti {
2572c03d07aSLuca Tettamanti struct atk_sensor_data *s = limit2_to_atk_sensor(attr);
2582c03d07aSLuca Tettamanti u64 value = s->limit2;
2592c03d07aSLuca Tettamanti
2602c03d07aSLuca Tettamanti if (s->type == HWMON_TYPE_TEMP)
2612c03d07aSLuca Tettamanti value *= 100;
2622c03d07aSLuca Tettamanti
2632c03d07aSLuca Tettamanti return sprintf(buf, "%lld\n", value);
2642c03d07aSLuca Tettamanti }
2652c03d07aSLuca Tettamanti
atk_init_attribute(struct device_attribute * attr,char * name,sysfs_show_func show)2662c03d07aSLuca Tettamanti static void atk_init_attribute(struct device_attribute *attr, char *name,
2672c03d07aSLuca Tettamanti sysfs_show_func show)
2682c03d07aSLuca Tettamanti {
2699a2d55beSGuenter Roeck sysfs_attr_init(&attr->attr);
2702c03d07aSLuca Tettamanti attr->attr.name = name;
2712c03d07aSLuca Tettamanti attr->attr.mode = 0444;
2722c03d07aSLuca Tettamanti attr->show = show;
2732c03d07aSLuca Tettamanti attr->store = NULL;
2742c03d07aSLuca Tettamanti }
2752c03d07aSLuca Tettamanti
2762c03d07aSLuca Tettamanti
atk_get_pack_member(struct atk_data * data,union acpi_object * pack,enum atk_pack_member m)2772c03d07aSLuca Tettamanti static union acpi_object *atk_get_pack_member(struct atk_data *data,
2782c03d07aSLuca Tettamanti union acpi_object *pack,
2792c03d07aSLuca Tettamanti enum atk_pack_member m)
2802c03d07aSLuca Tettamanti {
2812c03d07aSLuca Tettamanti bool old_if = data->old_interface;
2822c03d07aSLuca Tettamanti int offset;
2832c03d07aSLuca Tettamanti
2842c03d07aSLuca Tettamanti switch (m) {
2852c03d07aSLuca Tettamanti case HWMON_PACK_FLAGS:
2862c03d07aSLuca Tettamanti offset = old_if ? _HWMON_OLD_PACK_FLAGS : _HWMON_NEW_PACK_FLAGS;
2872c03d07aSLuca Tettamanti break;
2882c03d07aSLuca Tettamanti case HWMON_PACK_NAME:
2892c03d07aSLuca Tettamanti offset = old_if ? _HWMON_OLD_PACK_NAME : _HWMON_NEW_PACK_NAME;
2902c03d07aSLuca Tettamanti break;
2912c03d07aSLuca Tettamanti case HWMON_PACK_LIMIT1:
2922c03d07aSLuca Tettamanti offset = old_if ? _HWMON_OLD_PACK_LIMIT1 :
2932c03d07aSLuca Tettamanti _HWMON_NEW_PACK_LIMIT1;
2942c03d07aSLuca Tettamanti break;
2952c03d07aSLuca Tettamanti case HWMON_PACK_LIMIT2:
2962c03d07aSLuca Tettamanti offset = old_if ? _HWMON_OLD_PACK_LIMIT2 :
2972c03d07aSLuca Tettamanti _HWMON_NEW_PACK_LIMIT2;
2982c03d07aSLuca Tettamanti break;
2992c03d07aSLuca Tettamanti case HWMON_PACK_ENABLE:
3002c03d07aSLuca Tettamanti offset = old_if ? _HWMON_OLD_PACK_ENABLE :
3012c03d07aSLuca Tettamanti _HWMON_NEW_PACK_ENABLE;
3022c03d07aSLuca Tettamanti break;
3032c03d07aSLuca Tettamanti default:
3042c03d07aSLuca Tettamanti return NULL;
3052c03d07aSLuca Tettamanti }
3062c03d07aSLuca Tettamanti
3072c03d07aSLuca Tettamanti return &pack->package.elements[offset];
3082c03d07aSLuca Tettamanti }
3092c03d07aSLuca Tettamanti
3102c03d07aSLuca Tettamanti
31175bdc936SGuenter Roeck /*
31275bdc936SGuenter Roeck * New package format is:
3132c03d07aSLuca Tettamanti * - flag (int)
3142c03d07aSLuca Tettamanti * class - used for de-muxing the request to the correct GITn
3152c03d07aSLuca Tettamanti * type (volt, temp, fan)
3162c03d07aSLuca Tettamanti * sensor id |
3172c03d07aSLuca Tettamanti * sensor id - used for de-muxing the request _inside_ the GITn
3182c03d07aSLuca Tettamanti * - name (str)
3192c03d07aSLuca Tettamanti * - unknown (int)
3202c03d07aSLuca Tettamanti * - unknown (int)
3212c03d07aSLuca Tettamanti * - limit1 (int)
3222c03d07aSLuca Tettamanti * - limit2 (int)
3232c03d07aSLuca Tettamanti * - enable (int)
3242c03d07aSLuca Tettamanti *
3252c03d07aSLuca Tettamanti * The old package has the same format but it's missing the two unknown fields.
3262c03d07aSLuca Tettamanti */
validate_hwmon_pack(struct atk_data * data,union acpi_object * obj)3272c03d07aSLuca Tettamanti static int validate_hwmon_pack(struct atk_data *data, union acpi_object *obj)
3282c03d07aSLuca Tettamanti {
3292c03d07aSLuca Tettamanti struct device *dev = &data->acpi_dev->dev;
3302c03d07aSLuca Tettamanti union acpi_object *tmp;
3312c03d07aSLuca Tettamanti bool old_if = data->old_interface;
3322c03d07aSLuca Tettamanti int const expected_size = old_if ? _HWMON_OLD_PACK_SIZE :
3332c03d07aSLuca Tettamanti _HWMON_NEW_PACK_SIZE;
3342c03d07aSLuca Tettamanti
3352c03d07aSLuca Tettamanti if (obj->type != ACPI_TYPE_PACKAGE) {
3362c03d07aSLuca Tettamanti dev_warn(dev, "Invalid type: %d\n", obj->type);
3372c03d07aSLuca Tettamanti return -EINVAL;
3382c03d07aSLuca Tettamanti }
3392c03d07aSLuca Tettamanti
3402c03d07aSLuca Tettamanti if (obj->package.count != expected_size) {
3412c03d07aSLuca Tettamanti dev_warn(dev, "Invalid package size: %d, expected: %d\n",
3422c03d07aSLuca Tettamanti obj->package.count, expected_size);
3432c03d07aSLuca Tettamanti return -EINVAL;
3442c03d07aSLuca Tettamanti }
3452c03d07aSLuca Tettamanti
3462c03d07aSLuca Tettamanti tmp = atk_get_pack_member(data, obj, HWMON_PACK_FLAGS);
3472c03d07aSLuca Tettamanti if (tmp->type != ACPI_TYPE_INTEGER) {
3482c03d07aSLuca Tettamanti dev_warn(dev, "Invalid type (flag): %d\n", tmp->type);
3492c03d07aSLuca Tettamanti return -EINVAL;
3502c03d07aSLuca Tettamanti }
3512c03d07aSLuca Tettamanti
3522c03d07aSLuca Tettamanti tmp = atk_get_pack_member(data, obj, HWMON_PACK_NAME);
3532c03d07aSLuca Tettamanti if (tmp->type != ACPI_TYPE_STRING) {
3542c03d07aSLuca Tettamanti dev_warn(dev, "Invalid type (name): %d\n", tmp->type);
3552c03d07aSLuca Tettamanti return -EINVAL;
3562c03d07aSLuca Tettamanti }
3572c03d07aSLuca Tettamanti
3582c03d07aSLuca Tettamanti /* Don't check... we don't know what they're useful for anyway */
3592c03d07aSLuca Tettamanti #if 0
3602c03d07aSLuca Tettamanti tmp = &obj->package.elements[HWMON_PACK_UNK1];
3612c03d07aSLuca Tettamanti if (tmp->type != ACPI_TYPE_INTEGER) {
3622c03d07aSLuca Tettamanti dev_warn(dev, "Invalid type (unk1): %d\n", tmp->type);
3632c03d07aSLuca Tettamanti return -EINVAL;
3642c03d07aSLuca Tettamanti }
3652c03d07aSLuca Tettamanti
3662c03d07aSLuca Tettamanti tmp = &obj->package.elements[HWMON_PACK_UNK2];
3672c03d07aSLuca Tettamanti if (tmp->type != ACPI_TYPE_INTEGER) {
3682c03d07aSLuca Tettamanti dev_warn(dev, "Invalid type (unk2): %d\n", tmp->type);
3692c03d07aSLuca Tettamanti return -EINVAL;
3702c03d07aSLuca Tettamanti }
3712c03d07aSLuca Tettamanti #endif
3722c03d07aSLuca Tettamanti
3732c03d07aSLuca Tettamanti tmp = atk_get_pack_member(data, obj, HWMON_PACK_LIMIT1);
3742c03d07aSLuca Tettamanti if (tmp->type != ACPI_TYPE_INTEGER) {
3752c03d07aSLuca Tettamanti dev_warn(dev, "Invalid type (limit1): %d\n", tmp->type);
3762c03d07aSLuca Tettamanti return -EINVAL;
3772c03d07aSLuca Tettamanti }
3782c03d07aSLuca Tettamanti
3792c03d07aSLuca Tettamanti tmp = atk_get_pack_member(data, obj, HWMON_PACK_LIMIT2);
3802c03d07aSLuca Tettamanti if (tmp->type != ACPI_TYPE_INTEGER) {
3812c03d07aSLuca Tettamanti dev_warn(dev, "Invalid type (limit2): %d\n", tmp->type);
3822c03d07aSLuca Tettamanti return -EINVAL;
3832c03d07aSLuca Tettamanti }
3842c03d07aSLuca Tettamanti
3852c03d07aSLuca Tettamanti tmp = atk_get_pack_member(data, obj, HWMON_PACK_ENABLE);
3862c03d07aSLuca Tettamanti if (tmp->type != ACPI_TYPE_INTEGER) {
3872c03d07aSLuca Tettamanti dev_warn(dev, "Invalid type (enable): %d\n", tmp->type);
3882c03d07aSLuca Tettamanti return -EINVAL;
3892c03d07aSLuca Tettamanti }
3902c03d07aSLuca Tettamanti
3912c03d07aSLuca Tettamanti atk_print_sensor(data, obj);
3922c03d07aSLuca Tettamanti
3932c03d07aSLuca Tettamanti return 0;
3942c03d07aSLuca Tettamanti }
3952c03d07aSLuca Tettamanti
396b9008708SLuca Tettamanti #ifdef DEBUG
atk_sensor_type(union acpi_object * flags)3972c03d07aSLuca Tettamanti static char const *atk_sensor_type(union acpi_object *flags)
3982c03d07aSLuca Tettamanti {
3992c03d07aSLuca Tettamanti u64 type = flags->integer.value & ATK_TYPE_MASK;
4002c03d07aSLuca Tettamanti char const *what;
4012c03d07aSLuca Tettamanti
4022c03d07aSLuca Tettamanti switch (type) {
4032c03d07aSLuca Tettamanti case HWMON_TYPE_VOLT:
4042c03d07aSLuca Tettamanti what = "voltage";
4052c03d07aSLuca Tettamanti break;
4062c03d07aSLuca Tettamanti case HWMON_TYPE_TEMP:
4072c03d07aSLuca Tettamanti what = "temperature";
4082c03d07aSLuca Tettamanti break;
4092c03d07aSLuca Tettamanti case HWMON_TYPE_FAN:
4102c03d07aSLuca Tettamanti what = "fan";
4112c03d07aSLuca Tettamanti break;
4122c03d07aSLuca Tettamanti default:
4132c03d07aSLuca Tettamanti what = "unknown";
4142c03d07aSLuca Tettamanti break;
4152c03d07aSLuca Tettamanti }
4162c03d07aSLuca Tettamanti
4172c03d07aSLuca Tettamanti return what;
4182c03d07aSLuca Tettamanti }
419b9008708SLuca Tettamanti #endif
4202c03d07aSLuca Tettamanti
atk_print_sensor(struct atk_data * data,union acpi_object * obj)4212c03d07aSLuca Tettamanti static void atk_print_sensor(struct atk_data *data, union acpi_object *obj)
4222c03d07aSLuca Tettamanti {
4232c03d07aSLuca Tettamanti #ifdef DEBUG
4242c03d07aSLuca Tettamanti struct device *dev = &data->acpi_dev->dev;
4252c03d07aSLuca Tettamanti union acpi_object *flags;
4262c03d07aSLuca Tettamanti union acpi_object *name;
4272c03d07aSLuca Tettamanti union acpi_object *limit1;
4282c03d07aSLuca Tettamanti union acpi_object *limit2;
4292c03d07aSLuca Tettamanti union acpi_object *enable;
4302c03d07aSLuca Tettamanti char const *what;
4312c03d07aSLuca Tettamanti
4322c03d07aSLuca Tettamanti flags = atk_get_pack_member(data, obj, HWMON_PACK_FLAGS);
4332c03d07aSLuca Tettamanti name = atk_get_pack_member(data, obj, HWMON_PACK_NAME);
4342c03d07aSLuca Tettamanti limit1 = atk_get_pack_member(data, obj, HWMON_PACK_LIMIT1);
4352c03d07aSLuca Tettamanti limit2 = atk_get_pack_member(data, obj, HWMON_PACK_LIMIT2);
4362c03d07aSLuca Tettamanti enable = atk_get_pack_member(data, obj, HWMON_PACK_ENABLE);
4372c03d07aSLuca Tettamanti
4382c03d07aSLuca Tettamanti what = atk_sensor_type(flags);
4392c03d07aSLuca Tettamanti
4402c03d07aSLuca Tettamanti dev_dbg(dev, "%s: %#llx %s [%llu-%llu] %s\n", what,
4412c03d07aSLuca Tettamanti flags->integer.value,
4422c03d07aSLuca Tettamanti name->string.pointer,
4432c03d07aSLuca Tettamanti limit1->integer.value, limit2->integer.value,
4442c03d07aSLuca Tettamanti enable->integer.value ? "enabled" : "disabled");
4452c03d07aSLuca Tettamanti #endif
4462c03d07aSLuca Tettamanti }
4472c03d07aSLuca Tettamanti
atk_read_value_old(struct atk_sensor_data * sensor,u64 * value)4482c03d07aSLuca Tettamanti static int atk_read_value_old(struct atk_sensor_data *sensor, u64 *value)
4492c03d07aSLuca Tettamanti {
4502c03d07aSLuca Tettamanti struct atk_data *data = sensor->data;
4512c03d07aSLuca Tettamanti struct device *dev = &data->acpi_dev->dev;
4522c03d07aSLuca Tettamanti struct acpi_object_list params;
4532c03d07aSLuca Tettamanti union acpi_object id;
4542c03d07aSLuca Tettamanti acpi_status status;
4552c03d07aSLuca Tettamanti acpi_handle method;
4562c03d07aSLuca Tettamanti
4572c03d07aSLuca Tettamanti switch (sensor->type) {
4582c03d07aSLuca Tettamanti case HWMON_TYPE_VOLT:
4592c03d07aSLuca Tettamanti method = data->rvlt_handle;
4602c03d07aSLuca Tettamanti break;
4612c03d07aSLuca Tettamanti case HWMON_TYPE_TEMP:
4622c03d07aSLuca Tettamanti method = data->rtmp_handle;
4632c03d07aSLuca Tettamanti break;
4642c03d07aSLuca Tettamanti case HWMON_TYPE_FAN:
4652c03d07aSLuca Tettamanti method = data->rfan_handle;
4662c03d07aSLuca Tettamanti break;
4672c03d07aSLuca Tettamanti default:
4682c03d07aSLuca Tettamanti return -EINVAL;
4692c03d07aSLuca Tettamanti }
4702c03d07aSLuca Tettamanti
4712c03d07aSLuca Tettamanti id.type = ACPI_TYPE_INTEGER;
4722c03d07aSLuca Tettamanti id.integer.value = sensor->id;
4732c03d07aSLuca Tettamanti
4742c03d07aSLuca Tettamanti params.count = 1;
4752c03d07aSLuca Tettamanti params.pointer = &id;
4762c03d07aSLuca Tettamanti
4772c03d07aSLuca Tettamanti status = acpi_evaluate_integer(method, NULL, ¶ms, value);
4782c03d07aSLuca Tettamanti if (status != AE_OK) {
4792c03d07aSLuca Tettamanti dev_warn(dev, "%s: ACPI exception: %s\n", __func__,
4802c03d07aSLuca Tettamanti acpi_format_exception(status));
4812c03d07aSLuca Tettamanti return -EIO;
4822c03d07aSLuca Tettamanti }
4832c03d07aSLuca Tettamanti
4842c03d07aSLuca Tettamanti return 0;
4852c03d07aSLuca Tettamanti }
4862c03d07aSLuca Tettamanti
atk_ggrp(struct atk_data * data,u16 mux)48718e25555SLuca Tettamanti static union acpi_object *atk_ggrp(struct atk_data *data, u16 mux)
48818e25555SLuca Tettamanti {
48918e25555SLuca Tettamanti struct device *dev = &data->acpi_dev->dev;
49018e25555SLuca Tettamanti struct acpi_buffer buf;
49118e25555SLuca Tettamanti acpi_status ret;
49218e25555SLuca Tettamanti struct acpi_object_list params;
49318e25555SLuca Tettamanti union acpi_object id;
49418e25555SLuca Tettamanti union acpi_object *pack;
49518e25555SLuca Tettamanti
49618e25555SLuca Tettamanti id.type = ACPI_TYPE_INTEGER;
49718e25555SLuca Tettamanti id.integer.value = mux;
49818e25555SLuca Tettamanti params.count = 1;
49918e25555SLuca Tettamanti params.pointer = &id;
50018e25555SLuca Tettamanti
50118e25555SLuca Tettamanti buf.length = ACPI_ALLOCATE_BUFFER;
50218e25555SLuca Tettamanti ret = acpi_evaluate_object(data->enumerate_handle, NULL, ¶ms, &buf);
50318e25555SLuca Tettamanti if (ret != AE_OK) {
50418e25555SLuca Tettamanti dev_err(dev, "GGRP[%#x] ACPI exception: %s\n", mux,
50518e25555SLuca Tettamanti acpi_format_exception(ret));
50618e25555SLuca Tettamanti return ERR_PTR(-EIO);
50718e25555SLuca Tettamanti }
50818e25555SLuca Tettamanti pack = buf.pointer;
50918e25555SLuca Tettamanti if (pack->type != ACPI_TYPE_PACKAGE) {
51018e25555SLuca Tettamanti /* Execution was successful, but the id was not found */
51118e25555SLuca Tettamanti ACPI_FREE(pack);
51218e25555SLuca Tettamanti return ERR_PTR(-ENOENT);
51318e25555SLuca Tettamanti }
51418e25555SLuca Tettamanti
51518e25555SLuca Tettamanti if (pack->package.count < 1) {
51618e25555SLuca Tettamanti dev_err(dev, "GGRP[%#x] package is too small\n", mux);
51718e25555SLuca Tettamanti ACPI_FREE(pack);
51818e25555SLuca Tettamanti return ERR_PTR(-EIO);
51918e25555SLuca Tettamanti }
52018e25555SLuca Tettamanti return pack;
52118e25555SLuca Tettamanti }
52218e25555SLuca Tettamanti
atk_gitm(struct atk_data * data,u64 id)52318e25555SLuca Tettamanti static union acpi_object *atk_gitm(struct atk_data *data, u64 id)
52418e25555SLuca Tettamanti {
52518e25555SLuca Tettamanti struct device *dev = &data->acpi_dev->dev;
52618e25555SLuca Tettamanti struct atk_acpi_input_buf buf;
52718e25555SLuca Tettamanti union acpi_object tmp;
52818e25555SLuca Tettamanti struct acpi_object_list params;
52918e25555SLuca Tettamanti struct acpi_buffer ret;
53018e25555SLuca Tettamanti union acpi_object *obj;
53118e25555SLuca Tettamanti acpi_status status;
53218e25555SLuca Tettamanti
53318e25555SLuca Tettamanti buf.id = id;
53418e25555SLuca Tettamanti buf.param1 = 0;
53518e25555SLuca Tettamanti buf.param2 = 0;
53618e25555SLuca Tettamanti
53718e25555SLuca Tettamanti tmp.type = ACPI_TYPE_BUFFER;
53818e25555SLuca Tettamanti tmp.buffer.pointer = (u8 *)&buf;
53918e25555SLuca Tettamanti tmp.buffer.length = sizeof(buf);
54018e25555SLuca Tettamanti
54118e25555SLuca Tettamanti params.count = 1;
54218e25555SLuca Tettamanti params.pointer = (void *)&tmp;
54318e25555SLuca Tettamanti
54418e25555SLuca Tettamanti ret.length = ACPI_ALLOCATE_BUFFER;
54518e25555SLuca Tettamanti status = acpi_evaluate_object_typed(data->read_handle, NULL, ¶ms,
54618e25555SLuca Tettamanti &ret, ACPI_TYPE_BUFFER);
54718e25555SLuca Tettamanti if (status != AE_OK) {
54818e25555SLuca Tettamanti dev_warn(dev, "GITM[%#llx] ACPI exception: %s\n", id,
54918e25555SLuca Tettamanti acpi_format_exception(status));
55018e25555SLuca Tettamanti return ERR_PTR(-EIO);
55118e25555SLuca Tettamanti }
55218e25555SLuca Tettamanti obj = ret.pointer;
55318e25555SLuca Tettamanti
55418e25555SLuca Tettamanti /* Sanity check */
55518e25555SLuca Tettamanti if (obj->buffer.length < 8) {
55618e25555SLuca Tettamanti dev_warn(dev, "Unexpected ASBF length: %u\n",
55718e25555SLuca Tettamanti obj->buffer.length);
55818e25555SLuca Tettamanti ACPI_FREE(obj);
55918e25555SLuca Tettamanti return ERR_PTR(-EIO);
56018e25555SLuca Tettamanti }
56118e25555SLuca Tettamanti return obj;
56218e25555SLuca Tettamanti }
56318e25555SLuca Tettamanti
atk_sitm(struct atk_data * data,struct atk_acpi_input_buf * buf)5649e6eba61SLuca Tettamanti static union acpi_object *atk_sitm(struct atk_data *data,
5659e6eba61SLuca Tettamanti struct atk_acpi_input_buf *buf)
5669e6eba61SLuca Tettamanti {
5679e6eba61SLuca Tettamanti struct device *dev = &data->acpi_dev->dev;
5689e6eba61SLuca Tettamanti struct acpi_object_list params;
5699e6eba61SLuca Tettamanti union acpi_object tmp;
5709e6eba61SLuca Tettamanti struct acpi_buffer ret;
5719e6eba61SLuca Tettamanti union acpi_object *obj;
5729e6eba61SLuca Tettamanti acpi_status status;
5739e6eba61SLuca Tettamanti
5749e6eba61SLuca Tettamanti tmp.type = ACPI_TYPE_BUFFER;
5759e6eba61SLuca Tettamanti tmp.buffer.pointer = (u8 *)buf;
5769e6eba61SLuca Tettamanti tmp.buffer.length = sizeof(*buf);
5779e6eba61SLuca Tettamanti
5789e6eba61SLuca Tettamanti params.count = 1;
5799e6eba61SLuca Tettamanti params.pointer = &tmp;
5809e6eba61SLuca Tettamanti
5819e6eba61SLuca Tettamanti ret.length = ACPI_ALLOCATE_BUFFER;
5829e6eba61SLuca Tettamanti status = acpi_evaluate_object_typed(data->write_handle, NULL, ¶ms,
5839e6eba61SLuca Tettamanti &ret, ACPI_TYPE_BUFFER);
5849e6eba61SLuca Tettamanti if (status != AE_OK) {
5859e6eba61SLuca Tettamanti dev_warn(dev, "SITM[%#x] ACPI exception: %s\n", buf->id,
5869e6eba61SLuca Tettamanti acpi_format_exception(status));
5879e6eba61SLuca Tettamanti return ERR_PTR(-EIO);
5889e6eba61SLuca Tettamanti }
5899e6eba61SLuca Tettamanti obj = ret.pointer;
5909e6eba61SLuca Tettamanti
5919e6eba61SLuca Tettamanti /* Sanity check */
5929e6eba61SLuca Tettamanti if (obj->buffer.length < 8) {
5939e6eba61SLuca Tettamanti dev_warn(dev, "Unexpected ASBF length: %u\n",
5949e6eba61SLuca Tettamanti obj->buffer.length);
5959e6eba61SLuca Tettamanti ACPI_FREE(obj);
5969e6eba61SLuca Tettamanti return ERR_PTR(-EIO);
5979e6eba61SLuca Tettamanti }
5989e6eba61SLuca Tettamanti return obj;
5999e6eba61SLuca Tettamanti }
6009e6eba61SLuca Tettamanti
atk_read_value_new(struct atk_sensor_data * sensor,u64 * value)6012c03d07aSLuca Tettamanti static int atk_read_value_new(struct atk_sensor_data *sensor, u64 *value)
6022c03d07aSLuca Tettamanti {
6032c03d07aSLuca Tettamanti struct atk_data *data = sensor->data;
6042c03d07aSLuca Tettamanti struct device *dev = &data->acpi_dev->dev;
60518e25555SLuca Tettamanti union acpi_object *obj;
60618e25555SLuca Tettamanti struct atk_acpi_ret_buffer *buf;
60718e25555SLuca Tettamanti int err = 0;
6082c03d07aSLuca Tettamanti
60918e25555SLuca Tettamanti obj = atk_gitm(data, sensor->id);
61018e25555SLuca Tettamanti if (IS_ERR(obj))
61118e25555SLuca Tettamanti return PTR_ERR(obj);
6122c03d07aSLuca Tettamanti
61318e25555SLuca Tettamanti buf = (struct atk_acpi_ret_buffer *)obj->buffer.pointer;
61418e25555SLuca Tettamanti if (buf->flags == 0) {
61575bdc936SGuenter Roeck /*
61675bdc936SGuenter Roeck * The reading is not valid, possible causes:
6172c03d07aSLuca Tettamanti * - sensor failure
6182c03d07aSLuca Tettamanti * - enumeration was FUBAR (and we didn't notice)
6192c03d07aSLuca Tettamanti */
62018e25555SLuca Tettamanti dev_warn(dev, "Read failed, sensor = %#llx\n", sensor->id);
62118e25555SLuca Tettamanti err = -EIO;
62218e25555SLuca Tettamanti goto out;
6232c03d07aSLuca Tettamanti }
6242c03d07aSLuca Tettamanti
62518e25555SLuca Tettamanti *value = buf->value;
62618e25555SLuca Tettamanti out:
62718e25555SLuca Tettamanti ACPI_FREE(obj);
62818e25555SLuca Tettamanti return err;
6292c03d07aSLuca Tettamanti }
6302c03d07aSLuca Tettamanti
atk_read_value(struct atk_sensor_data * sensor,u64 * value)6312c03d07aSLuca Tettamanti static int atk_read_value(struct atk_sensor_data *sensor, u64 *value)
6322c03d07aSLuca Tettamanti {
6332c03d07aSLuca Tettamanti int err;
6342c03d07aSLuca Tettamanti
6352c03d07aSLuca Tettamanti if (!sensor->is_valid ||
6362c03d07aSLuca Tettamanti time_after(jiffies, sensor->last_updated + CACHE_TIME)) {
6372c03d07aSLuca Tettamanti if (sensor->data->old_interface)
6382c03d07aSLuca Tettamanti err = atk_read_value_old(sensor, value);
6392c03d07aSLuca Tettamanti else
6402c03d07aSLuca Tettamanti err = atk_read_value_new(sensor, value);
6412c03d07aSLuca Tettamanti
642a2125d02SArnd Bergmann if (err)
643a2125d02SArnd Bergmann return err;
644a2125d02SArnd Bergmann
6452c03d07aSLuca Tettamanti sensor->is_valid = true;
6462c03d07aSLuca Tettamanti sensor->last_updated = jiffies;
6472c03d07aSLuca Tettamanti sensor->cached_value = *value;
6482c03d07aSLuca Tettamanti } else {
6492c03d07aSLuca Tettamanti *value = sensor->cached_value;
6502c03d07aSLuca Tettamanti err = 0;
6512c03d07aSLuca Tettamanti }
6522c03d07aSLuca Tettamanti
6532c03d07aSLuca Tettamanti return err;
6542c03d07aSLuca Tettamanti }
6552c03d07aSLuca Tettamanti
6567e5eab11SLuca Tettamanti #ifdef CONFIG_DEBUG_FS
atk_debugfs_gitm_get(void * p,u64 * val)6577e5eab11SLuca Tettamanti static int atk_debugfs_gitm_get(void *p, u64 *val)
6587e5eab11SLuca Tettamanti {
6597e5eab11SLuca Tettamanti struct atk_data *data = p;
6607e5eab11SLuca Tettamanti union acpi_object *ret;
6617e5eab11SLuca Tettamanti struct atk_acpi_ret_buffer *buf;
6627e5eab11SLuca Tettamanti int err = 0;
6637e5eab11SLuca Tettamanti
6647e5eab11SLuca Tettamanti if (!data->read_handle)
6657e5eab11SLuca Tettamanti return -ENODEV;
6667e5eab11SLuca Tettamanti
6677e5eab11SLuca Tettamanti if (!data->debugfs.id)
6687e5eab11SLuca Tettamanti return -EINVAL;
6697e5eab11SLuca Tettamanti
6707e5eab11SLuca Tettamanti ret = atk_gitm(data, data->debugfs.id);
6717e5eab11SLuca Tettamanti if (IS_ERR(ret))
6727e5eab11SLuca Tettamanti return PTR_ERR(ret);
6737e5eab11SLuca Tettamanti
6747e5eab11SLuca Tettamanti buf = (struct atk_acpi_ret_buffer *)ret->buffer.pointer;
6757e5eab11SLuca Tettamanti if (buf->flags)
6767e5eab11SLuca Tettamanti *val = buf->value;
6777e5eab11SLuca Tettamanti else
6787e5eab11SLuca Tettamanti err = -EIO;
6797e5eab11SLuca Tettamanti
6800b8e77f1SLuca Tettamanti ACPI_FREE(ret);
6817e5eab11SLuca Tettamanti return err;
6827e5eab11SLuca Tettamanti }
6837e5eab11SLuca Tettamanti
684f9facc24SYueHaibing DEFINE_DEBUGFS_ATTRIBUTE(atk_debugfs_gitm, atk_debugfs_gitm_get, NULL,
68568be3029SJoe Perches "0x%08llx\n");
6867e5eab11SLuca Tettamanti
atk_acpi_print(char * buf,size_t sz,union acpi_object * obj)6877e5eab11SLuca Tettamanti static int atk_acpi_print(char *buf, size_t sz, union acpi_object *obj)
6887e5eab11SLuca Tettamanti {
6897e5eab11SLuca Tettamanti int ret = 0;
6907e5eab11SLuca Tettamanti
6917e5eab11SLuca Tettamanti switch (obj->type) {
6927e5eab11SLuca Tettamanti case ACPI_TYPE_INTEGER:
6937e5eab11SLuca Tettamanti ret = snprintf(buf, sz, "0x%08llx\n", obj->integer.value);
6947e5eab11SLuca Tettamanti break;
6957e5eab11SLuca Tettamanti case ACPI_TYPE_STRING:
6967e5eab11SLuca Tettamanti ret = snprintf(buf, sz, "%s\n", obj->string.pointer);
6977e5eab11SLuca Tettamanti break;
6987e5eab11SLuca Tettamanti }
6997e5eab11SLuca Tettamanti
7007e5eab11SLuca Tettamanti return ret;
7017e5eab11SLuca Tettamanti }
7027e5eab11SLuca Tettamanti
atk_pack_print(char * buf,size_t sz,union acpi_object * pack)7037e5eab11SLuca Tettamanti static void atk_pack_print(char *buf, size_t sz, union acpi_object *pack)
7047e5eab11SLuca Tettamanti {
7057e5eab11SLuca Tettamanti int ret;
7067e5eab11SLuca Tettamanti int i;
7077e5eab11SLuca Tettamanti
7087e5eab11SLuca Tettamanti for (i = 0; i < pack->package.count; i++) {
7097e5eab11SLuca Tettamanti union acpi_object *obj = &pack->package.elements[i];
7107e5eab11SLuca Tettamanti
7117e5eab11SLuca Tettamanti ret = atk_acpi_print(buf, sz, obj);
7127e5eab11SLuca Tettamanti if (ret >= sz)
7137e5eab11SLuca Tettamanti break;
7147e5eab11SLuca Tettamanti buf += ret;
7157e5eab11SLuca Tettamanti sz -= ret;
7167e5eab11SLuca Tettamanti }
7177e5eab11SLuca Tettamanti }
7187e5eab11SLuca Tettamanti
atk_debugfs_ggrp_open(struct inode * inode,struct file * file)7197e5eab11SLuca Tettamanti static int atk_debugfs_ggrp_open(struct inode *inode, struct file *file)
7207e5eab11SLuca Tettamanti {
7217e5eab11SLuca Tettamanti struct atk_data *data = inode->i_private;
7227e5eab11SLuca Tettamanti char *buf = NULL;
7237e5eab11SLuca Tettamanti union acpi_object *ret;
7247e5eab11SLuca Tettamanti u8 cls;
7257e5eab11SLuca Tettamanti int i;
7267e5eab11SLuca Tettamanti
7277e5eab11SLuca Tettamanti if (!data->enumerate_handle)
7287e5eab11SLuca Tettamanti return -ENODEV;
7297e5eab11SLuca Tettamanti if (!data->debugfs.id)
7307e5eab11SLuca Tettamanti return -EINVAL;
7317e5eab11SLuca Tettamanti
7327e5eab11SLuca Tettamanti cls = (data->debugfs.id & 0xff000000) >> 24;
7337e5eab11SLuca Tettamanti ret = atk_ggrp(data, cls);
7347e5eab11SLuca Tettamanti if (IS_ERR(ret))
7357e5eab11SLuca Tettamanti return PTR_ERR(ret);
7367e5eab11SLuca Tettamanti
7377e5eab11SLuca Tettamanti for (i = 0; i < ret->package.count; i++) {
7387e5eab11SLuca Tettamanti union acpi_object *pack = &ret->package.elements[i];
7397e5eab11SLuca Tettamanti union acpi_object *id;
7407e5eab11SLuca Tettamanti
7417e5eab11SLuca Tettamanti if (pack->type != ACPI_TYPE_PACKAGE)
7427e5eab11SLuca Tettamanti continue;
7437e5eab11SLuca Tettamanti if (!pack->package.count)
7447e5eab11SLuca Tettamanti continue;
7457e5eab11SLuca Tettamanti id = &pack->package.elements[0];
7467e5eab11SLuca Tettamanti if (id->integer.value == data->debugfs.id) {
7477e5eab11SLuca Tettamanti /* Print the package */
7487e5eab11SLuca Tettamanti buf = kzalloc(512, GFP_KERNEL);
7497e5eab11SLuca Tettamanti if (!buf) {
7507e5eab11SLuca Tettamanti ACPI_FREE(ret);
7517e5eab11SLuca Tettamanti return -ENOMEM;
7527e5eab11SLuca Tettamanti }
7537e5eab11SLuca Tettamanti atk_pack_print(buf, 512, pack);
7547e5eab11SLuca Tettamanti break;
7557e5eab11SLuca Tettamanti }
7567e5eab11SLuca Tettamanti }
7577e5eab11SLuca Tettamanti ACPI_FREE(ret);
7587e5eab11SLuca Tettamanti
7597e5eab11SLuca Tettamanti if (!buf)
7607e5eab11SLuca Tettamanti return -EINVAL;
7617e5eab11SLuca Tettamanti
7627e5eab11SLuca Tettamanti file->private_data = buf;
7637e5eab11SLuca Tettamanti
7647e5eab11SLuca Tettamanti return nonseekable_open(inode, file);
7657e5eab11SLuca Tettamanti }
7667e5eab11SLuca Tettamanti
atk_debugfs_ggrp_read(struct file * file,char __user * buf,size_t count,loff_t * pos)7677e5eab11SLuca Tettamanti static ssize_t atk_debugfs_ggrp_read(struct file *file, char __user *buf,
7687e5eab11SLuca Tettamanti size_t count, loff_t *pos)
7697e5eab11SLuca Tettamanti {
7707e5eab11SLuca Tettamanti char *str = file->private_data;
7717e5eab11SLuca Tettamanti size_t len = strlen(str);
7727e5eab11SLuca Tettamanti
7737e5eab11SLuca Tettamanti return simple_read_from_buffer(buf, count, pos, str, len);
7747e5eab11SLuca Tettamanti }
7757e5eab11SLuca Tettamanti
atk_debugfs_ggrp_release(struct inode * inode,struct file * file)7767e5eab11SLuca Tettamanti static int atk_debugfs_ggrp_release(struct inode *inode, struct file *file)
7777e5eab11SLuca Tettamanti {
7787e5eab11SLuca Tettamanti kfree(file->private_data);
7797e5eab11SLuca Tettamanti return 0;
7807e5eab11SLuca Tettamanti }
7817e5eab11SLuca Tettamanti
7827e5eab11SLuca Tettamanti static const struct file_operations atk_debugfs_ggrp_fops = {
7837e5eab11SLuca Tettamanti .read = atk_debugfs_ggrp_read,
7847e5eab11SLuca Tettamanti .open = atk_debugfs_ggrp_open,
7857e5eab11SLuca Tettamanti .release = atk_debugfs_ggrp_release,
7866038f373SArnd Bergmann .llseek = no_llseek,
7877e5eab11SLuca Tettamanti };
7887e5eab11SLuca Tettamanti
atk_debugfs_init(struct atk_data * data)7897e5eab11SLuca Tettamanti static void atk_debugfs_init(struct atk_data *data)
7907e5eab11SLuca Tettamanti {
7917e5eab11SLuca Tettamanti struct dentry *d;
7927e5eab11SLuca Tettamanti
7937e5eab11SLuca Tettamanti data->debugfs.id = 0;
7947e5eab11SLuca Tettamanti
7957e5eab11SLuca Tettamanti d = debugfs_create_dir("asus_atk0110", NULL);
7967e5eab11SLuca Tettamanti
79708d09d80SGreg Kroah-Hartman debugfs_create_x32("id", 0600, d, &data->debugfs.id);
79808d09d80SGreg Kroah-Hartman debugfs_create_file_unsafe("gitm", 0400, d, data, &atk_debugfs_gitm);
79908d09d80SGreg Kroah-Hartman debugfs_create_file("ggrp", 0400, d, data, &atk_debugfs_ggrp_fops);
8007e5eab11SLuca Tettamanti
8017e5eab11SLuca Tettamanti data->debugfs.root = d;
8027e5eab11SLuca Tettamanti }
8037e5eab11SLuca Tettamanti
atk_debugfs_cleanup(struct atk_data * data)8047e5eab11SLuca Tettamanti static void atk_debugfs_cleanup(struct atk_data *data)
8057e5eab11SLuca Tettamanti {
8067e5eab11SLuca Tettamanti debugfs_remove_recursive(data->debugfs.root);
8077e5eab11SLuca Tettamanti }
8087e5eab11SLuca Tettamanti
8097e5eab11SLuca Tettamanti #else /* CONFIG_DEBUG_FS */
8107e5eab11SLuca Tettamanti
atk_debugfs_init(struct atk_data * data)8117e5eab11SLuca Tettamanti static void atk_debugfs_init(struct atk_data *data)
8127e5eab11SLuca Tettamanti {
8137e5eab11SLuca Tettamanti }
8147e5eab11SLuca Tettamanti
atk_debugfs_cleanup(struct atk_data * data)8157e5eab11SLuca Tettamanti static void atk_debugfs_cleanup(struct atk_data *data)
8167e5eab11SLuca Tettamanti {
8177e5eab11SLuca Tettamanti }
8187e5eab11SLuca Tettamanti #endif
8197e5eab11SLuca Tettamanti
atk_add_sensor(struct atk_data * data,union acpi_object * obj)8202c03d07aSLuca Tettamanti static int atk_add_sensor(struct atk_data *data, union acpi_object *obj)
8212c03d07aSLuca Tettamanti {
8222c03d07aSLuca Tettamanti struct device *dev = &data->acpi_dev->dev;
8232c03d07aSLuca Tettamanti union acpi_object *flags;
8242c03d07aSLuca Tettamanti union acpi_object *name;
8252c03d07aSLuca Tettamanti union acpi_object *limit1;
8262c03d07aSLuca Tettamanti union acpi_object *limit2;
8272c03d07aSLuca Tettamanti union acpi_object *enable;
8282c03d07aSLuca Tettamanti struct atk_sensor_data *sensor;
8292c03d07aSLuca Tettamanti char const *base_name;
8302c03d07aSLuca Tettamanti char const *limit1_name;
8312c03d07aSLuca Tettamanti char const *limit2_name;
8322c03d07aSLuca Tettamanti u64 type;
8332c03d07aSLuca Tettamanti int err;
8342c03d07aSLuca Tettamanti int *num;
8352c03d07aSLuca Tettamanti int start;
8362c03d07aSLuca Tettamanti
8372c03d07aSLuca Tettamanti if (obj->type != ACPI_TYPE_PACKAGE) {
8382c03d07aSLuca Tettamanti /* wft is this? */
8392c03d07aSLuca Tettamanti dev_warn(dev, "Unknown type for ACPI object: (%d)\n",
8402c03d07aSLuca Tettamanti obj->type);
8412c03d07aSLuca Tettamanti return -EINVAL;
8422c03d07aSLuca Tettamanti }
8432c03d07aSLuca Tettamanti
8442c03d07aSLuca Tettamanti err = validate_hwmon_pack(data, obj);
8452c03d07aSLuca Tettamanti if (err)
8462c03d07aSLuca Tettamanti return err;
8472c03d07aSLuca Tettamanti
8482c03d07aSLuca Tettamanti /* Ok, we have a valid hwmon package */
8492c03d07aSLuca Tettamanti type = atk_get_pack_member(data, obj, HWMON_PACK_FLAGS)->integer.value
8502c03d07aSLuca Tettamanti & ATK_TYPE_MASK;
8512c03d07aSLuca Tettamanti
8522c03d07aSLuca Tettamanti switch (type) {
8532c03d07aSLuca Tettamanti case HWMON_TYPE_VOLT:
8542c03d07aSLuca Tettamanti base_name = "in";
8552c03d07aSLuca Tettamanti limit1_name = "min";
8562c03d07aSLuca Tettamanti limit2_name = "max";
8572c03d07aSLuca Tettamanti num = &data->voltage_count;
8582c03d07aSLuca Tettamanti start = 0;
8592c03d07aSLuca Tettamanti break;
8602c03d07aSLuca Tettamanti case HWMON_TYPE_TEMP:
8612c03d07aSLuca Tettamanti base_name = "temp";
8622c03d07aSLuca Tettamanti limit1_name = "max";
8632c03d07aSLuca Tettamanti limit2_name = "crit";
8642c03d07aSLuca Tettamanti num = &data->temperature_count;
8652c03d07aSLuca Tettamanti start = 1;
8662c03d07aSLuca Tettamanti break;
8672c03d07aSLuca Tettamanti case HWMON_TYPE_FAN:
8682c03d07aSLuca Tettamanti base_name = "fan";
8692c03d07aSLuca Tettamanti limit1_name = "min";
8702c03d07aSLuca Tettamanti limit2_name = "max";
8712c03d07aSLuca Tettamanti num = &data->fan_count;
8722c03d07aSLuca Tettamanti start = 1;
8732c03d07aSLuca Tettamanti break;
8742c03d07aSLuca Tettamanti default:
8752c03d07aSLuca Tettamanti dev_warn(dev, "Unknown sensor type: %#llx\n", type);
8762c03d07aSLuca Tettamanti return -EINVAL;
8772c03d07aSLuca Tettamanti }
8782c03d07aSLuca Tettamanti
8792c03d07aSLuca Tettamanti enable = atk_get_pack_member(data, obj, HWMON_PACK_ENABLE);
8802c03d07aSLuca Tettamanti if (!enable->integer.value)
8812c03d07aSLuca Tettamanti /* sensor is disabled */
8822c03d07aSLuca Tettamanti return 0;
8832c03d07aSLuca Tettamanti
8842c03d07aSLuca Tettamanti flags = atk_get_pack_member(data, obj, HWMON_PACK_FLAGS);
8852c03d07aSLuca Tettamanti name = atk_get_pack_member(data, obj, HWMON_PACK_NAME);
8862c03d07aSLuca Tettamanti limit1 = atk_get_pack_member(data, obj, HWMON_PACK_LIMIT1);
8872c03d07aSLuca Tettamanti limit2 = atk_get_pack_member(data, obj, HWMON_PACK_LIMIT2);
8882c03d07aSLuca Tettamanti
889c9bdf291SBastian Germann sensor = devm_kzalloc(dev, sizeof(*sensor), GFP_KERNEL);
8902c03d07aSLuca Tettamanti if (!sensor)
8912c03d07aSLuca Tettamanti return -ENOMEM;
8922c03d07aSLuca Tettamanti
893c9bdf291SBastian Germann sensor->acpi_name = devm_kstrdup(dev, name->string.pointer, GFP_KERNEL);
894c9bdf291SBastian Germann if (!sensor->acpi_name)
895c9bdf291SBastian Germann return -ENOMEM;
8962c03d07aSLuca Tettamanti
8972c03d07aSLuca Tettamanti INIT_LIST_HEAD(&sensor->list);
8982c03d07aSLuca Tettamanti sensor->type = type;
8992c03d07aSLuca Tettamanti sensor->data = data;
9002c03d07aSLuca Tettamanti sensor->id = flags->integer.value;
9012c03d07aSLuca Tettamanti sensor->limit1 = limit1->integer.value;
9028d282497SLuca Tettamanti if (data->old_interface)
9032c03d07aSLuca Tettamanti sensor->limit2 = limit2->integer.value;
9048d282497SLuca Tettamanti else
9058d282497SLuca Tettamanti /* The upper limit is expressed as delta from lower limit */
9068d282497SLuca Tettamanti sensor->limit2 = sensor->limit1 + limit2->integer.value;
9072c03d07aSLuca Tettamanti
9082c03d07aSLuca Tettamanti snprintf(sensor->input_attr_name, ATTR_NAME_SIZE,
9092c03d07aSLuca Tettamanti "%s%d_input", base_name, start + *num);
9102c03d07aSLuca Tettamanti atk_init_attribute(&sensor->input_attr,
9112c03d07aSLuca Tettamanti sensor->input_attr_name,
9122c03d07aSLuca Tettamanti atk_input_show);
9132c03d07aSLuca Tettamanti
9142c03d07aSLuca Tettamanti snprintf(sensor->label_attr_name, ATTR_NAME_SIZE,
9152c03d07aSLuca Tettamanti "%s%d_label", base_name, start + *num);
9162c03d07aSLuca Tettamanti atk_init_attribute(&sensor->label_attr,
9172c03d07aSLuca Tettamanti sensor->label_attr_name,
9182c03d07aSLuca Tettamanti atk_label_show);
9192c03d07aSLuca Tettamanti
9202c03d07aSLuca Tettamanti snprintf(sensor->limit1_attr_name, ATTR_NAME_SIZE,
9212c03d07aSLuca Tettamanti "%s%d_%s", base_name, start + *num, limit1_name);
9222c03d07aSLuca Tettamanti atk_init_attribute(&sensor->limit1_attr,
9232c03d07aSLuca Tettamanti sensor->limit1_attr_name,
9242c03d07aSLuca Tettamanti atk_limit1_show);
9252c03d07aSLuca Tettamanti
9262c03d07aSLuca Tettamanti snprintf(sensor->limit2_attr_name, ATTR_NAME_SIZE,
9272c03d07aSLuca Tettamanti "%s%d_%s", base_name, start + *num, limit2_name);
9282c03d07aSLuca Tettamanti atk_init_attribute(&sensor->limit2_attr,
9292c03d07aSLuca Tettamanti sensor->limit2_attr_name,
9302c03d07aSLuca Tettamanti atk_limit2_show);
9312c03d07aSLuca Tettamanti
9322c03d07aSLuca Tettamanti list_add(&sensor->list, &data->sensor_list);
9332c03d07aSLuca Tettamanti (*num)++;
9342c03d07aSLuca Tettamanti
9352c03d07aSLuca Tettamanti return 1;
9362c03d07aSLuca Tettamanti }
9372c03d07aSLuca Tettamanti
atk_enumerate_old_hwmon(struct atk_data * data)9382c03d07aSLuca Tettamanti static int atk_enumerate_old_hwmon(struct atk_data *data)
9392c03d07aSLuca Tettamanti {
9402c03d07aSLuca Tettamanti struct device *dev = &data->acpi_dev->dev;
9412c03d07aSLuca Tettamanti struct acpi_buffer buf;
9422c03d07aSLuca Tettamanti union acpi_object *pack;
9432c03d07aSLuca Tettamanti acpi_status status;
9442c03d07aSLuca Tettamanti int i, ret;
9452c03d07aSLuca Tettamanti int count = 0;
9462c03d07aSLuca Tettamanti
9472c03d07aSLuca Tettamanti /* Voltages */
9482c03d07aSLuca Tettamanti buf.length = ACPI_ALLOCATE_BUFFER;
9492c03d07aSLuca Tettamanti status = acpi_evaluate_object_typed(data->atk_handle,
9502c03d07aSLuca Tettamanti METHOD_OLD_ENUM_VLT, NULL, &buf, ACPI_TYPE_PACKAGE);
9512c03d07aSLuca Tettamanti if (status != AE_OK) {
9522c03d07aSLuca Tettamanti dev_warn(dev, METHOD_OLD_ENUM_VLT ": ACPI exception: %s\n",
9532c03d07aSLuca Tettamanti acpi_format_exception(status));
9542c03d07aSLuca Tettamanti
9552c03d07aSLuca Tettamanti return -ENODEV;
9562c03d07aSLuca Tettamanti }
9572c03d07aSLuca Tettamanti
9582c03d07aSLuca Tettamanti pack = buf.pointer;
9592c03d07aSLuca Tettamanti for (i = 1; i < pack->package.count; i++) {
9602c03d07aSLuca Tettamanti union acpi_object *obj = &pack->package.elements[i];
9612c03d07aSLuca Tettamanti
9622c03d07aSLuca Tettamanti ret = atk_add_sensor(data, obj);
9632c03d07aSLuca Tettamanti if (ret > 0)
9642c03d07aSLuca Tettamanti count++;
9652c03d07aSLuca Tettamanti }
9662c03d07aSLuca Tettamanti ACPI_FREE(buf.pointer);
9672c03d07aSLuca Tettamanti
9682c03d07aSLuca Tettamanti /* Temperatures */
9692c03d07aSLuca Tettamanti buf.length = ACPI_ALLOCATE_BUFFER;
9702c03d07aSLuca Tettamanti status = acpi_evaluate_object_typed(data->atk_handle,
9712c03d07aSLuca Tettamanti METHOD_OLD_ENUM_TMP, NULL, &buf, ACPI_TYPE_PACKAGE);
9722c03d07aSLuca Tettamanti if (status != AE_OK) {
9732c03d07aSLuca Tettamanti dev_warn(dev, METHOD_OLD_ENUM_TMP ": ACPI exception: %s\n",
9742c03d07aSLuca Tettamanti acpi_format_exception(status));
9752c03d07aSLuca Tettamanti
976c9bdf291SBastian Germann return -ENODEV;
9772c03d07aSLuca Tettamanti }
9782c03d07aSLuca Tettamanti
9792c03d07aSLuca Tettamanti pack = buf.pointer;
9802c03d07aSLuca Tettamanti for (i = 1; i < pack->package.count; i++) {
9812c03d07aSLuca Tettamanti union acpi_object *obj = &pack->package.elements[i];
9822c03d07aSLuca Tettamanti
9832c03d07aSLuca Tettamanti ret = atk_add_sensor(data, obj);
9842c03d07aSLuca Tettamanti if (ret > 0)
9852c03d07aSLuca Tettamanti count++;
9862c03d07aSLuca Tettamanti }
9872c03d07aSLuca Tettamanti ACPI_FREE(buf.pointer);
9882c03d07aSLuca Tettamanti
9892c03d07aSLuca Tettamanti /* Fans */
9902c03d07aSLuca Tettamanti buf.length = ACPI_ALLOCATE_BUFFER;
9912c03d07aSLuca Tettamanti status = acpi_evaluate_object_typed(data->atk_handle,
9922c03d07aSLuca Tettamanti METHOD_OLD_ENUM_FAN, NULL, &buf, ACPI_TYPE_PACKAGE);
9932c03d07aSLuca Tettamanti if (status != AE_OK) {
9942c03d07aSLuca Tettamanti dev_warn(dev, METHOD_OLD_ENUM_FAN ": ACPI exception: %s\n",
9952c03d07aSLuca Tettamanti acpi_format_exception(status));
9962c03d07aSLuca Tettamanti
997c9bdf291SBastian Germann return -ENODEV;
9982c03d07aSLuca Tettamanti }
9992c03d07aSLuca Tettamanti
10002c03d07aSLuca Tettamanti pack = buf.pointer;
10012c03d07aSLuca Tettamanti for (i = 1; i < pack->package.count; i++) {
10022c03d07aSLuca Tettamanti union acpi_object *obj = &pack->package.elements[i];
10032c03d07aSLuca Tettamanti
10042c03d07aSLuca Tettamanti ret = atk_add_sensor(data, obj);
10052c03d07aSLuca Tettamanti if (ret > 0)
10062c03d07aSLuca Tettamanti count++;
10072c03d07aSLuca Tettamanti }
10082c03d07aSLuca Tettamanti ACPI_FREE(buf.pointer);
10092c03d07aSLuca Tettamanti
10102c03d07aSLuca Tettamanti return count;
10112c03d07aSLuca Tettamanti }
10122c03d07aSLuca Tettamanti
atk_ec_present(struct atk_data * data)10139e6eba61SLuca Tettamanti static int atk_ec_present(struct atk_data *data)
10149e6eba61SLuca Tettamanti {
10159e6eba61SLuca Tettamanti struct device *dev = &data->acpi_dev->dev;
10169e6eba61SLuca Tettamanti union acpi_object *pack;
10179e6eba61SLuca Tettamanti union acpi_object *ec;
10189e6eba61SLuca Tettamanti int ret;
10199e6eba61SLuca Tettamanti int i;
10209e6eba61SLuca Tettamanti
10219e6eba61SLuca Tettamanti pack = atk_ggrp(data, ATK_MUX_MGMT);
10229e6eba61SLuca Tettamanti if (IS_ERR(pack)) {
10239e6eba61SLuca Tettamanti if (PTR_ERR(pack) == -ENOENT) {
10249e6eba61SLuca Tettamanti /* The MGMT class does not exists - that's ok */
10259e6eba61SLuca Tettamanti dev_dbg(dev, "Class %#llx not found\n", ATK_MUX_MGMT);
10269e6eba61SLuca Tettamanti return 0;
10279e6eba61SLuca Tettamanti }
10289e6eba61SLuca Tettamanti return PTR_ERR(pack);
10299e6eba61SLuca Tettamanti }
10309e6eba61SLuca Tettamanti
10319e6eba61SLuca Tettamanti /* Search the EC */
10329e6eba61SLuca Tettamanti ec = NULL;
10339e6eba61SLuca Tettamanti for (i = 0; i < pack->package.count; i++) {
10349e6eba61SLuca Tettamanti union acpi_object *obj = &pack->package.elements[i];
10359e6eba61SLuca Tettamanti union acpi_object *id;
10369e6eba61SLuca Tettamanti
10379e6eba61SLuca Tettamanti if (obj->type != ACPI_TYPE_PACKAGE)
10389e6eba61SLuca Tettamanti continue;
10399e6eba61SLuca Tettamanti
10409e6eba61SLuca Tettamanti id = &obj->package.elements[0];
10419e6eba61SLuca Tettamanti if (id->type != ACPI_TYPE_INTEGER)
10429e6eba61SLuca Tettamanti continue;
10439e6eba61SLuca Tettamanti
10449e6eba61SLuca Tettamanti if (id->integer.value == ATK_EC_ID) {
10459e6eba61SLuca Tettamanti ec = obj;
10469e6eba61SLuca Tettamanti break;
10479e6eba61SLuca Tettamanti }
10489e6eba61SLuca Tettamanti }
10499e6eba61SLuca Tettamanti
10509e6eba61SLuca Tettamanti ret = (ec != NULL);
10519e6eba61SLuca Tettamanti if (!ret)
10529e6eba61SLuca Tettamanti /* The system has no EC */
10539e6eba61SLuca Tettamanti dev_dbg(dev, "EC not found\n");
10549e6eba61SLuca Tettamanti
10559e6eba61SLuca Tettamanti ACPI_FREE(pack);
10569e6eba61SLuca Tettamanti return ret;
10579e6eba61SLuca Tettamanti }
10589e6eba61SLuca Tettamanti
atk_ec_enabled(struct atk_data * data)10599e6eba61SLuca Tettamanti static int atk_ec_enabled(struct atk_data *data)
10609e6eba61SLuca Tettamanti {
10619e6eba61SLuca Tettamanti struct device *dev = &data->acpi_dev->dev;
10629e6eba61SLuca Tettamanti union acpi_object *obj;
10639e6eba61SLuca Tettamanti struct atk_acpi_ret_buffer *buf;
10649e6eba61SLuca Tettamanti int err;
10659e6eba61SLuca Tettamanti
10669e6eba61SLuca Tettamanti obj = atk_gitm(data, ATK_EC_ID);
10679e6eba61SLuca Tettamanti if (IS_ERR(obj)) {
10689e6eba61SLuca Tettamanti dev_err(dev, "Unable to query EC status\n");
10699e6eba61SLuca Tettamanti return PTR_ERR(obj);
10709e6eba61SLuca Tettamanti }
10719e6eba61SLuca Tettamanti buf = (struct atk_acpi_ret_buffer *)obj->buffer.pointer;
10729e6eba61SLuca Tettamanti
10739e6eba61SLuca Tettamanti if (buf->flags == 0) {
10749e6eba61SLuca Tettamanti dev_err(dev, "Unable to query EC status\n");
10759e6eba61SLuca Tettamanti err = -EIO;
10769e6eba61SLuca Tettamanti } else {
10779e6eba61SLuca Tettamanti err = (buf->value != 0);
10789e6eba61SLuca Tettamanti dev_dbg(dev, "EC is %sabled\n",
10799e6eba61SLuca Tettamanti err ? "en" : "dis");
10809e6eba61SLuca Tettamanti }
10819e6eba61SLuca Tettamanti
10829e6eba61SLuca Tettamanti ACPI_FREE(obj);
10839e6eba61SLuca Tettamanti return err;
10849e6eba61SLuca Tettamanti }
10859e6eba61SLuca Tettamanti
atk_ec_ctl(struct atk_data * data,int enable)10869e6eba61SLuca Tettamanti static int atk_ec_ctl(struct atk_data *data, int enable)
10879e6eba61SLuca Tettamanti {
10889e6eba61SLuca Tettamanti struct device *dev = &data->acpi_dev->dev;
10899e6eba61SLuca Tettamanti union acpi_object *obj;
10909e6eba61SLuca Tettamanti struct atk_acpi_input_buf sitm;
10919e6eba61SLuca Tettamanti struct atk_acpi_ret_buffer *ec_ret;
10929e6eba61SLuca Tettamanti int err = 0;
10939e6eba61SLuca Tettamanti
10949e6eba61SLuca Tettamanti sitm.id = ATK_EC_ID;
10959e6eba61SLuca Tettamanti sitm.param1 = enable;
10969e6eba61SLuca Tettamanti sitm.param2 = 0;
10979e6eba61SLuca Tettamanti
10989e6eba61SLuca Tettamanti obj = atk_sitm(data, &sitm);
10999e6eba61SLuca Tettamanti if (IS_ERR(obj)) {
11009e6eba61SLuca Tettamanti dev_err(dev, "Failed to %sable the EC\n",
11019e6eba61SLuca Tettamanti enable ? "en" : "dis");
11029e6eba61SLuca Tettamanti return PTR_ERR(obj);
11039e6eba61SLuca Tettamanti }
11049e6eba61SLuca Tettamanti ec_ret = (struct atk_acpi_ret_buffer *)obj->buffer.pointer;
11059e6eba61SLuca Tettamanti if (ec_ret->flags == 0) {
11069e6eba61SLuca Tettamanti dev_err(dev, "Failed to %sable the EC\n",
11079e6eba61SLuca Tettamanti enable ? "en" : "dis");
11089e6eba61SLuca Tettamanti err = -EIO;
11099e6eba61SLuca Tettamanti } else {
11109e6eba61SLuca Tettamanti dev_info(dev, "EC %sabled\n",
11119e6eba61SLuca Tettamanti enable ? "en" : "dis");
11129e6eba61SLuca Tettamanti }
11139e6eba61SLuca Tettamanti
11149e6eba61SLuca Tettamanti ACPI_FREE(obj);
11159e6eba61SLuca Tettamanti return err;
11169e6eba61SLuca Tettamanti }
11179e6eba61SLuca Tettamanti
atk_enumerate_new_hwmon(struct atk_data * data)11182c03d07aSLuca Tettamanti static int atk_enumerate_new_hwmon(struct atk_data *data)
11192c03d07aSLuca Tettamanti {
11202c03d07aSLuca Tettamanti struct device *dev = &data->acpi_dev->dev;
11212c03d07aSLuca Tettamanti union acpi_object *pack;
11222c03d07aSLuca Tettamanti int err;
11232c03d07aSLuca Tettamanti int i;
11242c03d07aSLuca Tettamanti
11259e6eba61SLuca Tettamanti err = atk_ec_present(data);
11269e6eba61SLuca Tettamanti if (err < 0)
11279e6eba61SLuca Tettamanti return err;
11289e6eba61SLuca Tettamanti if (err) {
11299e6eba61SLuca Tettamanti err = atk_ec_enabled(data);
11309e6eba61SLuca Tettamanti if (err < 0)
11319e6eba61SLuca Tettamanti return err;
11329e6eba61SLuca Tettamanti /* If the EC was disabled we will disable it again on unload */
11339e6eba61SLuca Tettamanti data->disable_ec = err;
11349e6eba61SLuca Tettamanti
11359e6eba61SLuca Tettamanti err = atk_ec_ctl(data, 1);
11369e6eba61SLuca Tettamanti if (err) {
11379e6eba61SLuca Tettamanti data->disable_ec = false;
11389e6eba61SLuca Tettamanti return err;
11399e6eba61SLuca Tettamanti }
11409e6eba61SLuca Tettamanti }
11419e6eba61SLuca Tettamanti
11422c03d07aSLuca Tettamanti dev_dbg(dev, "Enumerating hwmon sensors\n");
11432c03d07aSLuca Tettamanti
114418e25555SLuca Tettamanti pack = atk_ggrp(data, ATK_MUX_HWMON);
114518e25555SLuca Tettamanti if (IS_ERR(pack))
114618e25555SLuca Tettamanti return PTR_ERR(pack);
11472c03d07aSLuca Tettamanti
11482c03d07aSLuca Tettamanti for (i = 0; i < pack->package.count; i++) {
11492c03d07aSLuca Tettamanti union acpi_object *obj = &pack->package.elements[i];
11502c03d07aSLuca Tettamanti
11512c03d07aSLuca Tettamanti atk_add_sensor(data, obj);
11522c03d07aSLuca Tettamanti }
11532c03d07aSLuca Tettamanti
11542c03d07aSLuca Tettamanti err = data->voltage_count + data->temperature_count + data->fan_count;
11552c03d07aSLuca Tettamanti
115618e25555SLuca Tettamanti ACPI_FREE(pack);
11572c03d07aSLuca Tettamanti return err;
11582c03d07aSLuca Tettamanti }
11592c03d07aSLuca Tettamanti
atk_init_attribute_groups(struct atk_data * data)11603c60726dSBastian Germann static int atk_init_attribute_groups(struct atk_data *data)
11612c03d07aSLuca Tettamanti {
11623c60726dSBastian Germann struct device *dev = &data->acpi_dev->dev;
11632c03d07aSLuca Tettamanti struct atk_sensor_data *s;
11643c60726dSBastian Germann struct attribute **attrs;
11653c60726dSBastian Germann int i = 0;
11663c60726dSBastian Germann int len = (data->voltage_count + data->temperature_count
11673c60726dSBastian Germann + data->fan_count) * 4 + 1;
11683c60726dSBastian Germann
11693c60726dSBastian Germann attrs = devm_kcalloc(dev, len, sizeof(struct attribute *), GFP_KERNEL);
11703c60726dSBastian Germann if (!attrs)
11713c60726dSBastian Germann return -ENOMEM;
11722c03d07aSLuca Tettamanti
11732c03d07aSLuca Tettamanti list_for_each_entry(s, &data->sensor_list, list) {
11743c60726dSBastian Germann attrs[i++] = &s->input_attr.attr;
11753c60726dSBastian Germann attrs[i++] = &s->label_attr.attr;
11763c60726dSBastian Germann attrs[i++] = &s->limit1_attr.attr;
11773c60726dSBastian Germann attrs[i++] = &s->limit2_attr.attr;
11782c03d07aSLuca Tettamanti }
11792c03d07aSLuca Tettamanti
11803c60726dSBastian Germann data->attr_group.attrs = attrs;
11813c60726dSBastian Germann data->attr_groups[0] = &data->attr_group;
11822c03d07aSLuca Tettamanti
11833c60726dSBastian Germann return 0;
11842c03d07aSLuca Tettamanti }
11852c03d07aSLuca Tettamanti
atk_register_hwmon(struct atk_data * data)11862c03d07aSLuca Tettamanti static int atk_register_hwmon(struct atk_data *data)
11872c03d07aSLuca Tettamanti {
11882c03d07aSLuca Tettamanti struct device *dev = &data->acpi_dev->dev;
11892c03d07aSLuca Tettamanti
11902c03d07aSLuca Tettamanti dev_dbg(dev, "registering hwmon device\n");
11913c60726dSBastian Germann data->hwmon_dev = hwmon_device_register_with_groups(dev, "atk0110",
11923c60726dSBastian Germann data,
11933c60726dSBastian Germann data->attr_groups);
11942c03d07aSLuca Tettamanti
11952738b767Szhong jiang return PTR_ERR_OR_ZERO(data->hwmon_dev);
11962c03d07aSLuca Tettamanti }
11972c03d07aSLuca Tettamanti
atk_probe_if(struct atk_data * data)11988ba406beSLuca Tettamanti static int atk_probe_if(struct atk_data *data)
11992c03d07aSLuca Tettamanti {
12002c03d07aSLuca Tettamanti struct device *dev = &data->acpi_dev->dev;
12012c03d07aSLuca Tettamanti acpi_handle ret;
12022c03d07aSLuca Tettamanti acpi_status status;
12038ba406beSLuca Tettamanti int err = 0;
12042c03d07aSLuca Tettamanti
12052c03d07aSLuca Tettamanti /* RTMP: read temperature */
12062c03d07aSLuca Tettamanti status = acpi_get_handle(data->atk_handle, METHOD_OLD_READ_TMP, &ret);
12078ba406beSLuca Tettamanti if (ACPI_SUCCESS(status))
12088ba406beSLuca Tettamanti data->rtmp_handle = ret;
12098ba406beSLuca Tettamanti else
12102c03d07aSLuca Tettamanti dev_dbg(dev, "method " METHOD_OLD_READ_TMP " not found: %s\n",
12112c03d07aSLuca Tettamanti acpi_format_exception(status));
12122c03d07aSLuca Tettamanti
12132c03d07aSLuca Tettamanti /* RVLT: read voltage */
12142c03d07aSLuca Tettamanti status = acpi_get_handle(data->atk_handle, METHOD_OLD_READ_VLT, &ret);
12158ba406beSLuca Tettamanti if (ACPI_SUCCESS(status))
12168ba406beSLuca Tettamanti data->rvlt_handle = ret;
12178ba406beSLuca Tettamanti else
12182c03d07aSLuca Tettamanti dev_dbg(dev, "method " METHOD_OLD_READ_VLT " not found: %s\n",
12192c03d07aSLuca Tettamanti acpi_format_exception(status));
12202c03d07aSLuca Tettamanti
12212c03d07aSLuca Tettamanti /* RFAN: read fan status */
12222c03d07aSLuca Tettamanti status = acpi_get_handle(data->atk_handle, METHOD_OLD_READ_FAN, &ret);
12238ba406beSLuca Tettamanti if (ACPI_SUCCESS(status))
12248ba406beSLuca Tettamanti data->rfan_handle = ret;
12258ba406beSLuca Tettamanti else
12262c03d07aSLuca Tettamanti dev_dbg(dev, "method " METHOD_OLD_READ_FAN " not found: %s\n",
12272c03d07aSLuca Tettamanti acpi_format_exception(status));
12282c03d07aSLuca Tettamanti
12292c03d07aSLuca Tettamanti /* Enumeration */
12302c03d07aSLuca Tettamanti status = acpi_get_handle(data->atk_handle, METHOD_ENUMERATE, &ret);
12318ba406beSLuca Tettamanti if (ACPI_SUCCESS(status))
12328ba406beSLuca Tettamanti data->enumerate_handle = ret;
12338ba406beSLuca Tettamanti else
12342c03d07aSLuca Tettamanti dev_dbg(dev, "method " METHOD_ENUMERATE " not found: %s\n",
12352c03d07aSLuca Tettamanti acpi_format_exception(status));
12362c03d07aSLuca Tettamanti
12372c03d07aSLuca Tettamanti /* De-multiplexer (read) */
12382c03d07aSLuca Tettamanti status = acpi_get_handle(data->atk_handle, METHOD_READ, &ret);
12398ba406beSLuca Tettamanti if (ACPI_SUCCESS(status))
12408ba406beSLuca Tettamanti data->read_handle = ret;
12418ba406beSLuca Tettamanti else
12422c03d07aSLuca Tettamanti dev_dbg(dev, "method " METHOD_READ " not found: %s\n",
12432c03d07aSLuca Tettamanti acpi_format_exception(status));
12442c03d07aSLuca Tettamanti
12459e6eba61SLuca Tettamanti /* De-multiplexer (write) */
12469e6eba61SLuca Tettamanti status = acpi_get_handle(data->atk_handle, METHOD_WRITE, &ret);
12478ba406beSLuca Tettamanti if (ACPI_SUCCESS(status))
12489e6eba61SLuca Tettamanti data->write_handle = ret;
12498ba406beSLuca Tettamanti else
12508ba406beSLuca Tettamanti dev_dbg(dev, "method " METHOD_WRITE " not found: %s\n",
12518ba406beSLuca Tettamanti acpi_format_exception(status));
12529e6eba61SLuca Tettamanti
125375bdc936SGuenter Roeck /*
125475bdc936SGuenter Roeck * Check for hwmon methods: first check "old" style methods; note that
12558ba406beSLuca Tettamanti * both may be present: in this case we stick to the old interface;
12568ba406beSLuca Tettamanti * analysis of multiple DSDTs indicates that when both interfaces
12578ba406beSLuca Tettamanti * are present the new one (GGRP/GITM) is not functional.
12588ba406beSLuca Tettamanti */
125986ca33e8SLuca Tettamanti if (new_if)
126086ca33e8SLuca Tettamanti dev_info(dev, "Overriding interface detection\n");
1261c6e8ac04SFrans Meulenbroeks if (data->rtmp_handle &&
1262c6e8ac04SFrans Meulenbroeks data->rvlt_handle && data->rfan_handle && !new_if)
12638ba406beSLuca Tettamanti data->old_interface = true;
12648ba406beSLuca Tettamanti else if (data->enumerate_handle && data->read_handle &&
12658ba406beSLuca Tettamanti data->write_handle)
12668ba406beSLuca Tettamanti data->old_interface = false;
12678ba406beSLuca Tettamanti else
12688ba406beSLuca Tettamanti err = -ENODEV;
12698ba406beSLuca Tettamanti
12708ba406beSLuca Tettamanti return err;
12712c03d07aSLuca Tettamanti }
12722c03d07aSLuca Tettamanti
atk_add(struct acpi_device * device)12732c03d07aSLuca Tettamanti static int atk_add(struct acpi_device *device)
12742c03d07aSLuca Tettamanti {
12752c03d07aSLuca Tettamanti acpi_status ret;
12762c03d07aSLuca Tettamanti int err;
12772c03d07aSLuca Tettamanti struct acpi_buffer buf;
12782c03d07aSLuca Tettamanti union acpi_object *obj;
12792c03d07aSLuca Tettamanti struct atk_data *data;
12802c03d07aSLuca Tettamanti
12812c03d07aSLuca Tettamanti dev_dbg(&device->dev, "adding...\n");
12822c03d07aSLuca Tettamanti
1283c9bdf291SBastian Germann data = devm_kzalloc(&device->dev, sizeof(*data), GFP_KERNEL);
12842c03d07aSLuca Tettamanti if (!data)
12852c03d07aSLuca Tettamanti return -ENOMEM;
12862c03d07aSLuca Tettamanti
12872c03d07aSLuca Tettamanti data->acpi_dev = device;
12882c03d07aSLuca Tettamanti data->atk_handle = device->handle;
12892c03d07aSLuca Tettamanti INIT_LIST_HEAD(&data->sensor_list);
12909e6eba61SLuca Tettamanti data->disable_ec = false;
12912c03d07aSLuca Tettamanti
12922c03d07aSLuca Tettamanti buf.length = ACPI_ALLOCATE_BUFFER;
12932c03d07aSLuca Tettamanti ret = acpi_evaluate_object_typed(data->atk_handle, BOARD_ID, NULL,
12942c03d07aSLuca Tettamanti &buf, ACPI_TYPE_PACKAGE);
12952c03d07aSLuca Tettamanti if (ret != AE_OK) {
12962c03d07aSLuca Tettamanti dev_dbg(&device->dev, "atk: method MBIF not found\n");
12975542482bSLuca Tettamanti } else {
12982c03d07aSLuca Tettamanti obj = buf.pointer;
12995542482bSLuca Tettamanti if (obj->package.count >= 2) {
13005542482bSLuca Tettamanti union acpi_object *id = &obj->package.elements[1];
13015542482bSLuca Tettamanti if (id->type == ACPI_TYPE_STRING)
13022c03d07aSLuca Tettamanti dev_dbg(&device->dev, "board ID = %s\n",
13035542482bSLuca Tettamanti id->string.pointer);
13042c03d07aSLuca Tettamanti }
13052c03d07aSLuca Tettamanti ACPI_FREE(buf.pointer);
13065542482bSLuca Tettamanti }
13072c03d07aSLuca Tettamanti
13088ba406beSLuca Tettamanti err = atk_probe_if(data);
13098ba406beSLuca Tettamanti if (err) {
13108ba406beSLuca Tettamanti dev_err(&device->dev, "No usable hwmon interface detected\n");
13112c03d07aSLuca Tettamanti goto out;
13122c03d07aSLuca Tettamanti }
13132c03d07aSLuca Tettamanti
13148ba406beSLuca Tettamanti if (data->old_interface) {
13158ba406beSLuca Tettamanti dev_dbg(&device->dev, "Using old hwmon interface\n");
13162c03d07aSLuca Tettamanti err = atk_enumerate_old_hwmon(data);
13178ba406beSLuca Tettamanti } else {
13188ba406beSLuca Tettamanti dev_dbg(&device->dev, "Using new hwmon interface\n");
13192c03d07aSLuca Tettamanti err = atk_enumerate_new_hwmon(data);
13208ba406beSLuca Tettamanti }
13212c03d07aSLuca Tettamanti if (err < 0)
13222c03d07aSLuca Tettamanti goto out;
13232c03d07aSLuca Tettamanti if (err == 0) {
13242c03d07aSLuca Tettamanti dev_info(&device->dev,
13252c03d07aSLuca Tettamanti "No usable sensor detected, bailing out\n");
13262c03d07aSLuca Tettamanti err = -ENODEV;
13272c03d07aSLuca Tettamanti goto out;
13282c03d07aSLuca Tettamanti }
13292c03d07aSLuca Tettamanti
13303c60726dSBastian Germann err = atk_init_attribute_groups(data);
13313c60726dSBastian Germann if (err)
13323c60726dSBastian Germann goto out;
13332c03d07aSLuca Tettamanti err = atk_register_hwmon(data);
13342c03d07aSLuca Tettamanti if (err)
1335c9bdf291SBastian Germann goto out;
13362c03d07aSLuca Tettamanti
13377e5eab11SLuca Tettamanti atk_debugfs_init(data);
13387e5eab11SLuca Tettamanti
13392c03d07aSLuca Tettamanti device->driver_data = data;
13402c03d07aSLuca Tettamanti return 0;
13412c03d07aSLuca Tettamanti out:
13429e6eba61SLuca Tettamanti if (data->disable_ec)
13439e6eba61SLuca Tettamanti atk_ec_ctl(data, 0);
13442c03d07aSLuca Tettamanti return err;
13452c03d07aSLuca Tettamanti }
13462c03d07aSLuca Tettamanti
atk_remove(struct acpi_device * device)1347*6c0eb5baSDawei Li static void atk_remove(struct acpi_device *device)
13482c03d07aSLuca Tettamanti {
13492c03d07aSLuca Tettamanti struct atk_data *data = device->driver_data;
13502c03d07aSLuca Tettamanti dev_dbg(&device->dev, "removing...\n");
13512c03d07aSLuca Tettamanti
13522c03d07aSLuca Tettamanti device->driver_data = NULL;
13532c03d07aSLuca Tettamanti
13547e5eab11SLuca Tettamanti atk_debugfs_cleanup(data);
13557e5eab11SLuca Tettamanti
13562c03d07aSLuca Tettamanti hwmon_device_unregister(data->hwmon_dev);
13572c03d07aSLuca Tettamanti
13589e6eba61SLuca Tettamanti if (data->disable_ec) {
13599e6eba61SLuca Tettamanti if (atk_ec_ctl(data, 0))
13609e6eba61SLuca Tettamanti dev_err(&device->dev, "Failed to disable EC\n");
13619e6eba61SLuca Tettamanti }
13622c03d07aSLuca Tettamanti }
13632c03d07aSLuca Tettamanti
atk0110_init(void)13642c03d07aSLuca Tettamanti static int __init atk0110_init(void)
13652c03d07aSLuca Tettamanti {
13662c03d07aSLuca Tettamanti int ret;
13672c03d07aSLuca Tettamanti
136870dd6beaSJean Delvare /* Make sure it's safe to access the device through ACPI */
136970dd6beaSJean Delvare if (!acpi_resources_are_enforced()) {
1370ac561494SJoe Perches pr_err("Resources not safely usable due to acpi_enforce_resources kernel parameter\n");
137170dd6beaSJean Delvare return -EBUSY;
137270dd6beaSJean Delvare }
137370dd6beaSJean Delvare
137486ca33e8SLuca Tettamanti if (dmi_check_system(atk_force_new_if))
137586ca33e8SLuca Tettamanti new_if = true;
137686ca33e8SLuca Tettamanti
13772c03d07aSLuca Tettamanti ret = acpi_bus_register_driver(&atk_driver);
13782c03d07aSLuca Tettamanti if (ret)
1379ac561494SJoe Perches pr_info("acpi_bus_register_driver failed: %d\n", ret);
13802c03d07aSLuca Tettamanti
13812c03d07aSLuca Tettamanti return ret;
13822c03d07aSLuca Tettamanti }
13832c03d07aSLuca Tettamanti
atk0110_exit(void)13842c03d07aSLuca Tettamanti static void __exit atk0110_exit(void)
13852c03d07aSLuca Tettamanti {
13862c03d07aSLuca Tettamanti acpi_bus_unregister_driver(&atk_driver);
13872c03d07aSLuca Tettamanti }
13882c03d07aSLuca Tettamanti
13892c03d07aSLuca Tettamanti module_init(atk0110_init);
13902c03d07aSLuca Tettamanti module_exit(atk0110_exit);
13912c03d07aSLuca Tettamanti
13922c03d07aSLuca Tettamanti MODULE_LICENSE("GPL");
1393