1*2c03d07aSLuca Tettamanti /* 2*2c03d07aSLuca Tettamanti * Copyright (C) 2007-2009 Luca Tettamanti <kronos.it@gmail.com> 3*2c03d07aSLuca Tettamanti * 4*2c03d07aSLuca Tettamanti * This file is released under the GPLv2 5*2c03d07aSLuca Tettamanti * See COPYING in the top level directory of the kernel tree. 6*2c03d07aSLuca Tettamanti */ 7*2c03d07aSLuca Tettamanti 8*2c03d07aSLuca Tettamanti #include <linux/kernel.h> 9*2c03d07aSLuca Tettamanti #include <linux/hwmon.h> 10*2c03d07aSLuca Tettamanti #include <linux/list.h> 11*2c03d07aSLuca Tettamanti #include <linux/module.h> 12*2c03d07aSLuca Tettamanti 13*2c03d07aSLuca Tettamanti #include <acpi/acpi.h> 14*2c03d07aSLuca Tettamanti #include <acpi/acpixf.h> 15*2c03d07aSLuca Tettamanti #include <acpi/acpi_drivers.h> 16*2c03d07aSLuca Tettamanti #include <acpi/acpi_bus.h> 17*2c03d07aSLuca Tettamanti 18*2c03d07aSLuca Tettamanti 19*2c03d07aSLuca Tettamanti #define ATK_HID "ATK0110" 20*2c03d07aSLuca Tettamanti 21*2c03d07aSLuca Tettamanti /* Minimum time between readings, enforced in order to avoid 22*2c03d07aSLuca Tettamanti * hogging the CPU. 23*2c03d07aSLuca Tettamanti */ 24*2c03d07aSLuca Tettamanti #define CACHE_TIME HZ 25*2c03d07aSLuca Tettamanti 26*2c03d07aSLuca Tettamanti #define BOARD_ID "MBIF" 27*2c03d07aSLuca Tettamanti #define METHOD_ENUMERATE "GGRP" 28*2c03d07aSLuca Tettamanti #define METHOD_READ "GITM" 29*2c03d07aSLuca Tettamanti #define METHOD_WRITE "SITM" 30*2c03d07aSLuca Tettamanti #define METHOD_OLD_READ_TMP "RTMP" 31*2c03d07aSLuca Tettamanti #define METHOD_OLD_READ_VLT "RVLT" 32*2c03d07aSLuca Tettamanti #define METHOD_OLD_READ_FAN "RFAN" 33*2c03d07aSLuca Tettamanti #define METHOD_OLD_ENUM_TMP "TSIF" 34*2c03d07aSLuca Tettamanti #define METHOD_OLD_ENUM_VLT "VSIF" 35*2c03d07aSLuca Tettamanti #define METHOD_OLD_ENUM_FAN "FSIF" 36*2c03d07aSLuca Tettamanti 37*2c03d07aSLuca Tettamanti #define ATK_MUX_HWMON 0x00000006ULL 38*2c03d07aSLuca Tettamanti 39*2c03d07aSLuca Tettamanti #define ATK_CLASS_MASK 0xff000000ULL 40*2c03d07aSLuca Tettamanti #define ATK_CLASS_FREQ_CTL 0x03000000ULL 41*2c03d07aSLuca Tettamanti #define ATK_CLASS_FAN_CTL 0x04000000ULL 42*2c03d07aSLuca Tettamanti #define ATK_CLASS_HWMON 0x06000000ULL 43*2c03d07aSLuca Tettamanti 44*2c03d07aSLuca Tettamanti #define ATK_TYPE_MASK 0x00ff0000ULL 45*2c03d07aSLuca Tettamanti #define HWMON_TYPE_VOLT 0x00020000ULL 46*2c03d07aSLuca Tettamanti #define HWMON_TYPE_TEMP 0x00030000ULL 47*2c03d07aSLuca Tettamanti #define HWMON_TYPE_FAN 0x00040000ULL 48*2c03d07aSLuca Tettamanti 49*2c03d07aSLuca Tettamanti #define HWMON_SENSOR_ID_MASK 0x0000ffffULL 50*2c03d07aSLuca Tettamanti 51*2c03d07aSLuca Tettamanti enum atk_pack_member { 52*2c03d07aSLuca Tettamanti HWMON_PACK_FLAGS, 53*2c03d07aSLuca Tettamanti HWMON_PACK_NAME, 54*2c03d07aSLuca Tettamanti HWMON_PACK_LIMIT1, 55*2c03d07aSLuca Tettamanti HWMON_PACK_LIMIT2, 56*2c03d07aSLuca Tettamanti HWMON_PACK_ENABLE 57*2c03d07aSLuca Tettamanti }; 58*2c03d07aSLuca Tettamanti 59*2c03d07aSLuca Tettamanti /* New package format */ 60*2c03d07aSLuca Tettamanti #define _HWMON_NEW_PACK_SIZE 7 61*2c03d07aSLuca Tettamanti #define _HWMON_NEW_PACK_FLAGS 0 62*2c03d07aSLuca Tettamanti #define _HWMON_NEW_PACK_NAME 1 63*2c03d07aSLuca Tettamanti #define _HWMON_NEW_PACK_UNK1 2 64*2c03d07aSLuca Tettamanti #define _HWMON_NEW_PACK_UNK2 3 65*2c03d07aSLuca Tettamanti #define _HWMON_NEW_PACK_LIMIT1 4 66*2c03d07aSLuca Tettamanti #define _HWMON_NEW_PACK_LIMIT2 5 67*2c03d07aSLuca Tettamanti #define _HWMON_NEW_PACK_ENABLE 6 68*2c03d07aSLuca Tettamanti 69*2c03d07aSLuca Tettamanti /* Old package format */ 70*2c03d07aSLuca Tettamanti #define _HWMON_OLD_PACK_SIZE 5 71*2c03d07aSLuca Tettamanti #define _HWMON_OLD_PACK_FLAGS 0 72*2c03d07aSLuca Tettamanti #define _HWMON_OLD_PACK_NAME 1 73*2c03d07aSLuca Tettamanti #define _HWMON_OLD_PACK_LIMIT1 2 74*2c03d07aSLuca Tettamanti #define _HWMON_OLD_PACK_LIMIT2 3 75*2c03d07aSLuca Tettamanti #define _HWMON_OLD_PACK_ENABLE 4 76*2c03d07aSLuca Tettamanti 77*2c03d07aSLuca Tettamanti 78*2c03d07aSLuca Tettamanti struct atk_data { 79*2c03d07aSLuca Tettamanti struct device *hwmon_dev; 80*2c03d07aSLuca Tettamanti acpi_handle atk_handle; 81*2c03d07aSLuca Tettamanti struct acpi_device *acpi_dev; 82*2c03d07aSLuca Tettamanti 83*2c03d07aSLuca Tettamanti bool old_interface; 84*2c03d07aSLuca Tettamanti 85*2c03d07aSLuca Tettamanti /* old interface */ 86*2c03d07aSLuca Tettamanti acpi_handle rtmp_handle; 87*2c03d07aSLuca Tettamanti acpi_handle rvlt_handle; 88*2c03d07aSLuca Tettamanti acpi_handle rfan_handle; 89*2c03d07aSLuca Tettamanti /* new inteface */ 90*2c03d07aSLuca Tettamanti acpi_handle enumerate_handle; 91*2c03d07aSLuca Tettamanti acpi_handle read_handle; 92*2c03d07aSLuca Tettamanti 93*2c03d07aSLuca Tettamanti int voltage_count; 94*2c03d07aSLuca Tettamanti int temperature_count; 95*2c03d07aSLuca Tettamanti int fan_count; 96*2c03d07aSLuca Tettamanti struct list_head sensor_list; 97*2c03d07aSLuca Tettamanti }; 98*2c03d07aSLuca Tettamanti 99*2c03d07aSLuca Tettamanti 100*2c03d07aSLuca Tettamanti typedef ssize_t (*sysfs_show_func)(struct device *dev, 101*2c03d07aSLuca Tettamanti struct device_attribute *attr, char *buf); 102*2c03d07aSLuca Tettamanti 103*2c03d07aSLuca Tettamanti static const struct acpi_device_id atk_ids[] = { 104*2c03d07aSLuca Tettamanti {ATK_HID, 0}, 105*2c03d07aSLuca Tettamanti {"", 0}, 106*2c03d07aSLuca Tettamanti }; 107*2c03d07aSLuca Tettamanti MODULE_DEVICE_TABLE(acpi, atk_ids); 108*2c03d07aSLuca Tettamanti 109*2c03d07aSLuca Tettamanti #define ATTR_NAME_SIZE 16 /* Worst case is "tempN_input" */ 110*2c03d07aSLuca Tettamanti 111*2c03d07aSLuca Tettamanti struct atk_sensor_data { 112*2c03d07aSLuca Tettamanti struct list_head list; 113*2c03d07aSLuca Tettamanti struct atk_data *data; 114*2c03d07aSLuca Tettamanti struct device_attribute label_attr; 115*2c03d07aSLuca Tettamanti struct device_attribute input_attr; 116*2c03d07aSLuca Tettamanti struct device_attribute limit1_attr; 117*2c03d07aSLuca Tettamanti struct device_attribute limit2_attr; 118*2c03d07aSLuca Tettamanti char label_attr_name[ATTR_NAME_SIZE]; 119*2c03d07aSLuca Tettamanti char input_attr_name[ATTR_NAME_SIZE]; 120*2c03d07aSLuca Tettamanti char limit1_attr_name[ATTR_NAME_SIZE]; 121*2c03d07aSLuca Tettamanti char limit2_attr_name[ATTR_NAME_SIZE]; 122*2c03d07aSLuca Tettamanti u64 id; 123*2c03d07aSLuca Tettamanti u64 type; 124*2c03d07aSLuca Tettamanti u64 limit1; 125*2c03d07aSLuca Tettamanti u64 limit2; 126*2c03d07aSLuca Tettamanti u64 cached_value; 127*2c03d07aSLuca Tettamanti unsigned long last_updated; /* in jiffies */ 128*2c03d07aSLuca Tettamanti bool is_valid; 129*2c03d07aSLuca Tettamanti char const *acpi_name; 130*2c03d07aSLuca Tettamanti }; 131*2c03d07aSLuca Tettamanti 132*2c03d07aSLuca Tettamanti struct atk_acpi_buffer_u64 { 133*2c03d07aSLuca Tettamanti union acpi_object buf; 134*2c03d07aSLuca Tettamanti u64 value; 135*2c03d07aSLuca Tettamanti }; 136*2c03d07aSLuca Tettamanti 137*2c03d07aSLuca Tettamanti static int atk_add(struct acpi_device *device); 138*2c03d07aSLuca Tettamanti static int atk_remove(struct acpi_device *device, int type); 139*2c03d07aSLuca Tettamanti static void atk_print_sensor(struct atk_data *data, union acpi_object *obj); 140*2c03d07aSLuca Tettamanti static int atk_read_value(struct atk_sensor_data *sensor, u64 *value); 141*2c03d07aSLuca Tettamanti static void atk_free_sensors(struct atk_data *data); 142*2c03d07aSLuca Tettamanti 143*2c03d07aSLuca Tettamanti static struct acpi_driver atk_driver = { 144*2c03d07aSLuca Tettamanti .name = ATK_HID, 145*2c03d07aSLuca Tettamanti .class = "hwmon", 146*2c03d07aSLuca Tettamanti .ids = atk_ids, 147*2c03d07aSLuca Tettamanti .ops = { 148*2c03d07aSLuca Tettamanti .add = atk_add, 149*2c03d07aSLuca Tettamanti .remove = atk_remove, 150*2c03d07aSLuca Tettamanti }, 151*2c03d07aSLuca Tettamanti }; 152*2c03d07aSLuca Tettamanti 153*2c03d07aSLuca Tettamanti #define input_to_atk_sensor(attr) \ 154*2c03d07aSLuca Tettamanti container_of(attr, struct atk_sensor_data, input_attr) 155*2c03d07aSLuca Tettamanti 156*2c03d07aSLuca Tettamanti #define label_to_atk_sensor(attr) \ 157*2c03d07aSLuca Tettamanti container_of(attr, struct atk_sensor_data, label_attr) 158*2c03d07aSLuca Tettamanti 159*2c03d07aSLuca Tettamanti #define limit1_to_atk_sensor(attr) \ 160*2c03d07aSLuca Tettamanti container_of(attr, struct atk_sensor_data, limit1_attr) 161*2c03d07aSLuca Tettamanti 162*2c03d07aSLuca Tettamanti #define limit2_to_atk_sensor(attr) \ 163*2c03d07aSLuca Tettamanti container_of(attr, struct atk_sensor_data, limit2_attr) 164*2c03d07aSLuca Tettamanti 165*2c03d07aSLuca Tettamanti static ssize_t atk_input_show(struct device *dev, 166*2c03d07aSLuca Tettamanti struct device_attribute *attr, char *buf) 167*2c03d07aSLuca Tettamanti { 168*2c03d07aSLuca Tettamanti struct atk_sensor_data *s = input_to_atk_sensor(attr); 169*2c03d07aSLuca Tettamanti u64 value; 170*2c03d07aSLuca Tettamanti int err; 171*2c03d07aSLuca Tettamanti 172*2c03d07aSLuca Tettamanti err = atk_read_value(s, &value); 173*2c03d07aSLuca Tettamanti if (err) 174*2c03d07aSLuca Tettamanti return err; 175*2c03d07aSLuca Tettamanti 176*2c03d07aSLuca Tettamanti if (s->type == HWMON_TYPE_TEMP) 177*2c03d07aSLuca Tettamanti /* ACPI returns decidegree */ 178*2c03d07aSLuca Tettamanti value *= 100; 179*2c03d07aSLuca Tettamanti 180*2c03d07aSLuca Tettamanti return sprintf(buf, "%llu\n", value); 181*2c03d07aSLuca Tettamanti } 182*2c03d07aSLuca Tettamanti 183*2c03d07aSLuca Tettamanti static ssize_t atk_label_show(struct device *dev, 184*2c03d07aSLuca Tettamanti struct device_attribute *attr, char *buf) 185*2c03d07aSLuca Tettamanti { 186*2c03d07aSLuca Tettamanti struct atk_sensor_data *s = label_to_atk_sensor(attr); 187*2c03d07aSLuca Tettamanti 188*2c03d07aSLuca Tettamanti return sprintf(buf, "%s\n", s->acpi_name); 189*2c03d07aSLuca Tettamanti } 190*2c03d07aSLuca Tettamanti 191*2c03d07aSLuca Tettamanti static ssize_t atk_limit1_show(struct device *dev, 192*2c03d07aSLuca Tettamanti struct device_attribute *attr, char *buf) 193*2c03d07aSLuca Tettamanti { 194*2c03d07aSLuca Tettamanti struct atk_sensor_data *s = limit1_to_atk_sensor(attr); 195*2c03d07aSLuca Tettamanti u64 value = s->limit1; 196*2c03d07aSLuca Tettamanti 197*2c03d07aSLuca Tettamanti if (s->type == HWMON_TYPE_TEMP) 198*2c03d07aSLuca Tettamanti value *= 100; 199*2c03d07aSLuca Tettamanti 200*2c03d07aSLuca Tettamanti return sprintf(buf, "%lld\n", value); 201*2c03d07aSLuca Tettamanti } 202*2c03d07aSLuca Tettamanti 203*2c03d07aSLuca Tettamanti static ssize_t atk_limit2_show(struct device *dev, 204*2c03d07aSLuca Tettamanti struct device_attribute *attr, char *buf) 205*2c03d07aSLuca Tettamanti { 206*2c03d07aSLuca Tettamanti struct atk_sensor_data *s = limit2_to_atk_sensor(attr); 207*2c03d07aSLuca Tettamanti u64 value = s->limit2; 208*2c03d07aSLuca Tettamanti 209*2c03d07aSLuca Tettamanti if (s->type == HWMON_TYPE_TEMP) 210*2c03d07aSLuca Tettamanti value *= 100; 211*2c03d07aSLuca Tettamanti 212*2c03d07aSLuca Tettamanti return sprintf(buf, "%lld\n", value); 213*2c03d07aSLuca Tettamanti } 214*2c03d07aSLuca Tettamanti 215*2c03d07aSLuca Tettamanti static ssize_t atk_name_show(struct device *dev, 216*2c03d07aSLuca Tettamanti struct device_attribute *attr, char *buf) 217*2c03d07aSLuca Tettamanti { 218*2c03d07aSLuca Tettamanti return sprintf(buf, "atk0110\n"); 219*2c03d07aSLuca Tettamanti } 220*2c03d07aSLuca Tettamanti static struct device_attribute atk_name_attr = 221*2c03d07aSLuca Tettamanti __ATTR(name, 0444, atk_name_show, NULL); 222*2c03d07aSLuca Tettamanti 223*2c03d07aSLuca Tettamanti static void atk_init_attribute(struct device_attribute *attr, char *name, 224*2c03d07aSLuca Tettamanti sysfs_show_func show) 225*2c03d07aSLuca Tettamanti { 226*2c03d07aSLuca Tettamanti attr->attr.name = name; 227*2c03d07aSLuca Tettamanti attr->attr.mode = 0444; 228*2c03d07aSLuca Tettamanti attr->show = show; 229*2c03d07aSLuca Tettamanti attr->store = NULL; 230*2c03d07aSLuca Tettamanti } 231*2c03d07aSLuca Tettamanti 232*2c03d07aSLuca Tettamanti 233*2c03d07aSLuca Tettamanti static union acpi_object *atk_get_pack_member(struct atk_data *data, 234*2c03d07aSLuca Tettamanti union acpi_object *pack, 235*2c03d07aSLuca Tettamanti enum atk_pack_member m) 236*2c03d07aSLuca Tettamanti { 237*2c03d07aSLuca Tettamanti bool old_if = data->old_interface; 238*2c03d07aSLuca Tettamanti int offset; 239*2c03d07aSLuca Tettamanti 240*2c03d07aSLuca Tettamanti switch (m) { 241*2c03d07aSLuca Tettamanti case HWMON_PACK_FLAGS: 242*2c03d07aSLuca Tettamanti offset = old_if ? _HWMON_OLD_PACK_FLAGS : _HWMON_NEW_PACK_FLAGS; 243*2c03d07aSLuca Tettamanti break; 244*2c03d07aSLuca Tettamanti case HWMON_PACK_NAME: 245*2c03d07aSLuca Tettamanti offset = old_if ? _HWMON_OLD_PACK_NAME : _HWMON_NEW_PACK_NAME; 246*2c03d07aSLuca Tettamanti break; 247*2c03d07aSLuca Tettamanti case HWMON_PACK_LIMIT1: 248*2c03d07aSLuca Tettamanti offset = old_if ? _HWMON_OLD_PACK_LIMIT1 : 249*2c03d07aSLuca Tettamanti _HWMON_NEW_PACK_LIMIT1; 250*2c03d07aSLuca Tettamanti break; 251*2c03d07aSLuca Tettamanti case HWMON_PACK_LIMIT2: 252*2c03d07aSLuca Tettamanti offset = old_if ? _HWMON_OLD_PACK_LIMIT2 : 253*2c03d07aSLuca Tettamanti _HWMON_NEW_PACK_LIMIT2; 254*2c03d07aSLuca Tettamanti break; 255*2c03d07aSLuca Tettamanti case HWMON_PACK_ENABLE: 256*2c03d07aSLuca Tettamanti offset = old_if ? _HWMON_OLD_PACK_ENABLE : 257*2c03d07aSLuca Tettamanti _HWMON_NEW_PACK_ENABLE; 258*2c03d07aSLuca Tettamanti break; 259*2c03d07aSLuca Tettamanti default: 260*2c03d07aSLuca Tettamanti return NULL; 261*2c03d07aSLuca Tettamanti } 262*2c03d07aSLuca Tettamanti 263*2c03d07aSLuca Tettamanti return &pack->package.elements[offset]; 264*2c03d07aSLuca Tettamanti } 265*2c03d07aSLuca Tettamanti 266*2c03d07aSLuca Tettamanti 267*2c03d07aSLuca Tettamanti /* New package format is: 268*2c03d07aSLuca Tettamanti * - flag (int) 269*2c03d07aSLuca Tettamanti * class - used for de-muxing the request to the correct GITn 270*2c03d07aSLuca Tettamanti * type (volt, temp, fan) 271*2c03d07aSLuca Tettamanti * sensor id | 272*2c03d07aSLuca Tettamanti * sensor id - used for de-muxing the request _inside_ the GITn 273*2c03d07aSLuca Tettamanti * - name (str) 274*2c03d07aSLuca Tettamanti * - unknown (int) 275*2c03d07aSLuca Tettamanti * - unknown (int) 276*2c03d07aSLuca Tettamanti * - limit1 (int) 277*2c03d07aSLuca Tettamanti * - limit2 (int) 278*2c03d07aSLuca Tettamanti * - enable (int) 279*2c03d07aSLuca Tettamanti * 280*2c03d07aSLuca Tettamanti * The old package has the same format but it's missing the two unknown fields. 281*2c03d07aSLuca Tettamanti */ 282*2c03d07aSLuca Tettamanti static int validate_hwmon_pack(struct atk_data *data, union acpi_object *obj) 283*2c03d07aSLuca Tettamanti { 284*2c03d07aSLuca Tettamanti struct device *dev = &data->acpi_dev->dev; 285*2c03d07aSLuca Tettamanti union acpi_object *tmp; 286*2c03d07aSLuca Tettamanti bool old_if = data->old_interface; 287*2c03d07aSLuca Tettamanti int const expected_size = old_if ? _HWMON_OLD_PACK_SIZE : 288*2c03d07aSLuca Tettamanti _HWMON_NEW_PACK_SIZE; 289*2c03d07aSLuca Tettamanti 290*2c03d07aSLuca Tettamanti if (obj->type != ACPI_TYPE_PACKAGE) { 291*2c03d07aSLuca Tettamanti dev_warn(dev, "Invalid type: %d\n", obj->type); 292*2c03d07aSLuca Tettamanti return -EINVAL; 293*2c03d07aSLuca Tettamanti } 294*2c03d07aSLuca Tettamanti 295*2c03d07aSLuca Tettamanti if (obj->package.count != expected_size) { 296*2c03d07aSLuca Tettamanti dev_warn(dev, "Invalid package size: %d, expected: %d\n", 297*2c03d07aSLuca Tettamanti obj->package.count, expected_size); 298*2c03d07aSLuca Tettamanti return -EINVAL; 299*2c03d07aSLuca Tettamanti } 300*2c03d07aSLuca Tettamanti 301*2c03d07aSLuca Tettamanti tmp = atk_get_pack_member(data, obj, HWMON_PACK_FLAGS); 302*2c03d07aSLuca Tettamanti if (tmp->type != ACPI_TYPE_INTEGER) { 303*2c03d07aSLuca Tettamanti dev_warn(dev, "Invalid type (flag): %d\n", tmp->type); 304*2c03d07aSLuca Tettamanti return -EINVAL; 305*2c03d07aSLuca Tettamanti } 306*2c03d07aSLuca Tettamanti 307*2c03d07aSLuca Tettamanti tmp = atk_get_pack_member(data, obj, HWMON_PACK_NAME); 308*2c03d07aSLuca Tettamanti if (tmp->type != ACPI_TYPE_STRING) { 309*2c03d07aSLuca Tettamanti dev_warn(dev, "Invalid type (name): %d\n", tmp->type); 310*2c03d07aSLuca Tettamanti return -EINVAL; 311*2c03d07aSLuca Tettamanti } 312*2c03d07aSLuca Tettamanti 313*2c03d07aSLuca Tettamanti /* Don't check... we don't know what they're useful for anyway */ 314*2c03d07aSLuca Tettamanti #if 0 315*2c03d07aSLuca Tettamanti tmp = &obj->package.elements[HWMON_PACK_UNK1]; 316*2c03d07aSLuca Tettamanti if (tmp->type != ACPI_TYPE_INTEGER) { 317*2c03d07aSLuca Tettamanti dev_warn(dev, "Invalid type (unk1): %d\n", tmp->type); 318*2c03d07aSLuca Tettamanti return -EINVAL; 319*2c03d07aSLuca Tettamanti } 320*2c03d07aSLuca Tettamanti 321*2c03d07aSLuca Tettamanti tmp = &obj->package.elements[HWMON_PACK_UNK2]; 322*2c03d07aSLuca Tettamanti if (tmp->type != ACPI_TYPE_INTEGER) { 323*2c03d07aSLuca Tettamanti dev_warn(dev, "Invalid type (unk2): %d\n", tmp->type); 324*2c03d07aSLuca Tettamanti return -EINVAL; 325*2c03d07aSLuca Tettamanti } 326*2c03d07aSLuca Tettamanti #endif 327*2c03d07aSLuca Tettamanti 328*2c03d07aSLuca Tettamanti tmp = atk_get_pack_member(data, obj, HWMON_PACK_LIMIT1); 329*2c03d07aSLuca Tettamanti if (tmp->type != ACPI_TYPE_INTEGER) { 330*2c03d07aSLuca Tettamanti dev_warn(dev, "Invalid type (limit1): %d\n", tmp->type); 331*2c03d07aSLuca Tettamanti return -EINVAL; 332*2c03d07aSLuca Tettamanti } 333*2c03d07aSLuca Tettamanti 334*2c03d07aSLuca Tettamanti tmp = atk_get_pack_member(data, obj, HWMON_PACK_LIMIT2); 335*2c03d07aSLuca Tettamanti if (tmp->type != ACPI_TYPE_INTEGER) { 336*2c03d07aSLuca Tettamanti dev_warn(dev, "Invalid type (limit2): %d\n", tmp->type); 337*2c03d07aSLuca Tettamanti return -EINVAL; 338*2c03d07aSLuca Tettamanti } 339*2c03d07aSLuca Tettamanti 340*2c03d07aSLuca Tettamanti tmp = atk_get_pack_member(data, obj, HWMON_PACK_ENABLE); 341*2c03d07aSLuca Tettamanti if (tmp->type != ACPI_TYPE_INTEGER) { 342*2c03d07aSLuca Tettamanti dev_warn(dev, "Invalid type (enable): %d\n", tmp->type); 343*2c03d07aSLuca Tettamanti return -EINVAL; 344*2c03d07aSLuca Tettamanti } 345*2c03d07aSLuca Tettamanti 346*2c03d07aSLuca Tettamanti atk_print_sensor(data, obj); 347*2c03d07aSLuca Tettamanti 348*2c03d07aSLuca Tettamanti return 0; 349*2c03d07aSLuca Tettamanti } 350*2c03d07aSLuca Tettamanti 351*2c03d07aSLuca Tettamanti static char const *atk_sensor_type(union acpi_object *flags) 352*2c03d07aSLuca Tettamanti { 353*2c03d07aSLuca Tettamanti u64 type = flags->integer.value & ATK_TYPE_MASK; 354*2c03d07aSLuca Tettamanti char const *what; 355*2c03d07aSLuca Tettamanti 356*2c03d07aSLuca Tettamanti switch (type) { 357*2c03d07aSLuca Tettamanti case HWMON_TYPE_VOLT: 358*2c03d07aSLuca Tettamanti what = "voltage"; 359*2c03d07aSLuca Tettamanti break; 360*2c03d07aSLuca Tettamanti case HWMON_TYPE_TEMP: 361*2c03d07aSLuca Tettamanti what = "temperature"; 362*2c03d07aSLuca Tettamanti break; 363*2c03d07aSLuca Tettamanti case HWMON_TYPE_FAN: 364*2c03d07aSLuca Tettamanti what = "fan"; 365*2c03d07aSLuca Tettamanti break; 366*2c03d07aSLuca Tettamanti default: 367*2c03d07aSLuca Tettamanti what = "unknown"; 368*2c03d07aSLuca Tettamanti break; 369*2c03d07aSLuca Tettamanti } 370*2c03d07aSLuca Tettamanti 371*2c03d07aSLuca Tettamanti return what; 372*2c03d07aSLuca Tettamanti } 373*2c03d07aSLuca Tettamanti 374*2c03d07aSLuca Tettamanti static void atk_print_sensor(struct atk_data *data, union acpi_object *obj) 375*2c03d07aSLuca Tettamanti { 376*2c03d07aSLuca Tettamanti #ifdef DEBUG 377*2c03d07aSLuca Tettamanti struct device *dev = &data->acpi_dev->dev; 378*2c03d07aSLuca Tettamanti union acpi_object *flags; 379*2c03d07aSLuca Tettamanti union acpi_object *name; 380*2c03d07aSLuca Tettamanti union acpi_object *limit1; 381*2c03d07aSLuca Tettamanti union acpi_object *limit2; 382*2c03d07aSLuca Tettamanti union acpi_object *enable; 383*2c03d07aSLuca Tettamanti char const *what; 384*2c03d07aSLuca Tettamanti 385*2c03d07aSLuca Tettamanti flags = atk_get_pack_member(data, obj, HWMON_PACK_FLAGS); 386*2c03d07aSLuca Tettamanti name = atk_get_pack_member(data, obj, HWMON_PACK_NAME); 387*2c03d07aSLuca Tettamanti limit1 = atk_get_pack_member(data, obj, HWMON_PACK_LIMIT1); 388*2c03d07aSLuca Tettamanti limit2 = atk_get_pack_member(data, obj, HWMON_PACK_LIMIT2); 389*2c03d07aSLuca Tettamanti enable = atk_get_pack_member(data, obj, HWMON_PACK_ENABLE); 390*2c03d07aSLuca Tettamanti 391*2c03d07aSLuca Tettamanti what = atk_sensor_type(flags); 392*2c03d07aSLuca Tettamanti 393*2c03d07aSLuca Tettamanti dev_dbg(dev, "%s: %#llx %s [%llu-%llu] %s\n", what, 394*2c03d07aSLuca Tettamanti flags->integer.value, 395*2c03d07aSLuca Tettamanti name->string.pointer, 396*2c03d07aSLuca Tettamanti limit1->integer.value, limit2->integer.value, 397*2c03d07aSLuca Tettamanti enable->integer.value ? "enabled" : "disabled"); 398*2c03d07aSLuca Tettamanti #endif 399*2c03d07aSLuca Tettamanti } 400*2c03d07aSLuca Tettamanti 401*2c03d07aSLuca Tettamanti static int atk_read_value_old(struct atk_sensor_data *sensor, u64 *value) 402*2c03d07aSLuca Tettamanti { 403*2c03d07aSLuca Tettamanti struct atk_data *data = sensor->data; 404*2c03d07aSLuca Tettamanti struct device *dev = &data->acpi_dev->dev; 405*2c03d07aSLuca Tettamanti struct acpi_object_list params; 406*2c03d07aSLuca Tettamanti union acpi_object id; 407*2c03d07aSLuca Tettamanti acpi_status status; 408*2c03d07aSLuca Tettamanti acpi_handle method; 409*2c03d07aSLuca Tettamanti 410*2c03d07aSLuca Tettamanti switch (sensor->type) { 411*2c03d07aSLuca Tettamanti case HWMON_TYPE_VOLT: 412*2c03d07aSLuca Tettamanti method = data->rvlt_handle; 413*2c03d07aSLuca Tettamanti break; 414*2c03d07aSLuca Tettamanti case HWMON_TYPE_TEMP: 415*2c03d07aSLuca Tettamanti method = data->rtmp_handle; 416*2c03d07aSLuca Tettamanti break; 417*2c03d07aSLuca Tettamanti case HWMON_TYPE_FAN: 418*2c03d07aSLuca Tettamanti method = data->rfan_handle; 419*2c03d07aSLuca Tettamanti break; 420*2c03d07aSLuca Tettamanti default: 421*2c03d07aSLuca Tettamanti return -EINVAL; 422*2c03d07aSLuca Tettamanti } 423*2c03d07aSLuca Tettamanti 424*2c03d07aSLuca Tettamanti id.type = ACPI_TYPE_INTEGER; 425*2c03d07aSLuca Tettamanti id.integer.value = sensor->id; 426*2c03d07aSLuca Tettamanti 427*2c03d07aSLuca Tettamanti params.count = 1; 428*2c03d07aSLuca Tettamanti params.pointer = &id; 429*2c03d07aSLuca Tettamanti 430*2c03d07aSLuca Tettamanti status = acpi_evaluate_integer(method, NULL, ¶ms, value); 431*2c03d07aSLuca Tettamanti if (status != AE_OK) { 432*2c03d07aSLuca Tettamanti dev_warn(dev, "%s: ACPI exception: %s\n", __func__, 433*2c03d07aSLuca Tettamanti acpi_format_exception(status)); 434*2c03d07aSLuca Tettamanti return -EIO; 435*2c03d07aSLuca Tettamanti } 436*2c03d07aSLuca Tettamanti 437*2c03d07aSLuca Tettamanti return 0; 438*2c03d07aSLuca Tettamanti } 439*2c03d07aSLuca Tettamanti 440*2c03d07aSLuca Tettamanti static int atk_read_value_new(struct atk_sensor_data *sensor, u64 *value) 441*2c03d07aSLuca Tettamanti { 442*2c03d07aSLuca Tettamanti struct atk_data *data = sensor->data; 443*2c03d07aSLuca Tettamanti struct device *dev = &data->acpi_dev->dev; 444*2c03d07aSLuca Tettamanti struct acpi_object_list params; 445*2c03d07aSLuca Tettamanti struct acpi_buffer ret; 446*2c03d07aSLuca Tettamanti union acpi_object id; 447*2c03d07aSLuca Tettamanti struct atk_acpi_buffer_u64 tmp; 448*2c03d07aSLuca Tettamanti acpi_status status; 449*2c03d07aSLuca Tettamanti 450*2c03d07aSLuca Tettamanti id.type = ACPI_TYPE_INTEGER; 451*2c03d07aSLuca Tettamanti id.integer.value = sensor->id; 452*2c03d07aSLuca Tettamanti 453*2c03d07aSLuca Tettamanti params.count = 1; 454*2c03d07aSLuca Tettamanti params.pointer = &id; 455*2c03d07aSLuca Tettamanti 456*2c03d07aSLuca Tettamanti tmp.buf.type = ACPI_TYPE_BUFFER; 457*2c03d07aSLuca Tettamanti tmp.buf.buffer.pointer = (u8 *)&tmp.value; 458*2c03d07aSLuca Tettamanti tmp.buf.buffer.length = sizeof(u64); 459*2c03d07aSLuca Tettamanti ret.length = sizeof(tmp); 460*2c03d07aSLuca Tettamanti ret.pointer = &tmp; 461*2c03d07aSLuca Tettamanti 462*2c03d07aSLuca Tettamanti status = acpi_evaluate_object_typed(data->read_handle, NULL, ¶ms, 463*2c03d07aSLuca Tettamanti &ret, ACPI_TYPE_BUFFER); 464*2c03d07aSLuca Tettamanti if (status != AE_OK) { 465*2c03d07aSLuca Tettamanti dev_warn(dev, "%s: ACPI exception: %s\n", __func__, 466*2c03d07aSLuca Tettamanti acpi_format_exception(status)); 467*2c03d07aSLuca Tettamanti return -EIO; 468*2c03d07aSLuca Tettamanti } 469*2c03d07aSLuca Tettamanti 470*2c03d07aSLuca Tettamanti /* Return buffer format: 471*2c03d07aSLuca Tettamanti * [0-3] "value" is valid flag 472*2c03d07aSLuca Tettamanti * [4-7] value 473*2c03d07aSLuca Tettamanti */ 474*2c03d07aSLuca Tettamanti if (!(tmp.value & 0xffffffff)) { 475*2c03d07aSLuca Tettamanti /* The reading is not valid, possible causes: 476*2c03d07aSLuca Tettamanti * - sensor failure 477*2c03d07aSLuca Tettamanti * - enumeration was FUBAR (and we didn't notice) 478*2c03d07aSLuca Tettamanti */ 479*2c03d07aSLuca Tettamanti dev_info(dev, "Failure: %#llx\n", tmp.value); 480*2c03d07aSLuca Tettamanti return -EIO; 481*2c03d07aSLuca Tettamanti } 482*2c03d07aSLuca Tettamanti 483*2c03d07aSLuca Tettamanti *value = (tmp.value & 0xffffffff00000000ULL) >> 32; 484*2c03d07aSLuca Tettamanti 485*2c03d07aSLuca Tettamanti return 0; 486*2c03d07aSLuca Tettamanti } 487*2c03d07aSLuca Tettamanti 488*2c03d07aSLuca Tettamanti static int atk_read_value(struct atk_sensor_data *sensor, u64 *value) 489*2c03d07aSLuca Tettamanti { 490*2c03d07aSLuca Tettamanti int err; 491*2c03d07aSLuca Tettamanti 492*2c03d07aSLuca Tettamanti if (!sensor->is_valid || 493*2c03d07aSLuca Tettamanti time_after(jiffies, sensor->last_updated + CACHE_TIME)) { 494*2c03d07aSLuca Tettamanti if (sensor->data->old_interface) 495*2c03d07aSLuca Tettamanti err = atk_read_value_old(sensor, value); 496*2c03d07aSLuca Tettamanti else 497*2c03d07aSLuca Tettamanti err = atk_read_value_new(sensor, value); 498*2c03d07aSLuca Tettamanti 499*2c03d07aSLuca Tettamanti sensor->is_valid = true; 500*2c03d07aSLuca Tettamanti sensor->last_updated = jiffies; 501*2c03d07aSLuca Tettamanti sensor->cached_value = *value; 502*2c03d07aSLuca Tettamanti } else { 503*2c03d07aSLuca Tettamanti *value = sensor->cached_value; 504*2c03d07aSLuca Tettamanti err = 0; 505*2c03d07aSLuca Tettamanti } 506*2c03d07aSLuca Tettamanti 507*2c03d07aSLuca Tettamanti return err; 508*2c03d07aSLuca Tettamanti } 509*2c03d07aSLuca Tettamanti 510*2c03d07aSLuca Tettamanti static int atk_add_sensor(struct atk_data *data, union acpi_object *obj) 511*2c03d07aSLuca Tettamanti { 512*2c03d07aSLuca Tettamanti struct device *dev = &data->acpi_dev->dev; 513*2c03d07aSLuca Tettamanti union acpi_object *flags; 514*2c03d07aSLuca Tettamanti union acpi_object *name; 515*2c03d07aSLuca Tettamanti union acpi_object *limit1; 516*2c03d07aSLuca Tettamanti union acpi_object *limit2; 517*2c03d07aSLuca Tettamanti union acpi_object *enable; 518*2c03d07aSLuca Tettamanti struct atk_sensor_data *sensor; 519*2c03d07aSLuca Tettamanti char const *base_name; 520*2c03d07aSLuca Tettamanti char const *limit1_name; 521*2c03d07aSLuca Tettamanti char const *limit2_name; 522*2c03d07aSLuca Tettamanti u64 type; 523*2c03d07aSLuca Tettamanti int err; 524*2c03d07aSLuca Tettamanti int *num; 525*2c03d07aSLuca Tettamanti int start; 526*2c03d07aSLuca Tettamanti 527*2c03d07aSLuca Tettamanti if (obj->type != ACPI_TYPE_PACKAGE) { 528*2c03d07aSLuca Tettamanti /* wft is this? */ 529*2c03d07aSLuca Tettamanti dev_warn(dev, "Unknown type for ACPI object: (%d)\n", 530*2c03d07aSLuca Tettamanti obj->type); 531*2c03d07aSLuca Tettamanti return -EINVAL; 532*2c03d07aSLuca Tettamanti } 533*2c03d07aSLuca Tettamanti 534*2c03d07aSLuca Tettamanti err = validate_hwmon_pack(data, obj); 535*2c03d07aSLuca Tettamanti if (err) 536*2c03d07aSLuca Tettamanti return err; 537*2c03d07aSLuca Tettamanti 538*2c03d07aSLuca Tettamanti /* Ok, we have a valid hwmon package */ 539*2c03d07aSLuca Tettamanti type = atk_get_pack_member(data, obj, HWMON_PACK_FLAGS)->integer.value 540*2c03d07aSLuca Tettamanti & ATK_TYPE_MASK; 541*2c03d07aSLuca Tettamanti 542*2c03d07aSLuca Tettamanti switch (type) { 543*2c03d07aSLuca Tettamanti case HWMON_TYPE_VOLT: 544*2c03d07aSLuca Tettamanti base_name = "in"; 545*2c03d07aSLuca Tettamanti limit1_name = "min"; 546*2c03d07aSLuca Tettamanti limit2_name = "max"; 547*2c03d07aSLuca Tettamanti num = &data->voltage_count; 548*2c03d07aSLuca Tettamanti start = 0; 549*2c03d07aSLuca Tettamanti break; 550*2c03d07aSLuca Tettamanti case HWMON_TYPE_TEMP: 551*2c03d07aSLuca Tettamanti base_name = "temp"; 552*2c03d07aSLuca Tettamanti limit1_name = "max"; 553*2c03d07aSLuca Tettamanti limit2_name = "crit"; 554*2c03d07aSLuca Tettamanti num = &data->temperature_count; 555*2c03d07aSLuca Tettamanti start = 1; 556*2c03d07aSLuca Tettamanti break; 557*2c03d07aSLuca Tettamanti case HWMON_TYPE_FAN: 558*2c03d07aSLuca Tettamanti base_name = "fan"; 559*2c03d07aSLuca Tettamanti limit1_name = "min"; 560*2c03d07aSLuca Tettamanti limit2_name = "max"; 561*2c03d07aSLuca Tettamanti num = &data->fan_count; 562*2c03d07aSLuca Tettamanti start = 1; 563*2c03d07aSLuca Tettamanti break; 564*2c03d07aSLuca Tettamanti default: 565*2c03d07aSLuca Tettamanti dev_warn(dev, "Unknown sensor type: %#llx\n", type); 566*2c03d07aSLuca Tettamanti return -EINVAL; 567*2c03d07aSLuca Tettamanti } 568*2c03d07aSLuca Tettamanti 569*2c03d07aSLuca Tettamanti enable = atk_get_pack_member(data, obj, HWMON_PACK_ENABLE); 570*2c03d07aSLuca Tettamanti if (!enable->integer.value) 571*2c03d07aSLuca Tettamanti /* sensor is disabled */ 572*2c03d07aSLuca Tettamanti return 0; 573*2c03d07aSLuca Tettamanti 574*2c03d07aSLuca Tettamanti flags = atk_get_pack_member(data, obj, HWMON_PACK_FLAGS); 575*2c03d07aSLuca Tettamanti name = atk_get_pack_member(data, obj, HWMON_PACK_NAME); 576*2c03d07aSLuca Tettamanti limit1 = atk_get_pack_member(data, obj, HWMON_PACK_LIMIT1); 577*2c03d07aSLuca Tettamanti limit2 = atk_get_pack_member(data, obj, HWMON_PACK_LIMIT2); 578*2c03d07aSLuca Tettamanti 579*2c03d07aSLuca Tettamanti sensor = kzalloc(sizeof(*sensor), GFP_KERNEL); 580*2c03d07aSLuca Tettamanti if (!sensor) 581*2c03d07aSLuca Tettamanti return -ENOMEM; 582*2c03d07aSLuca Tettamanti 583*2c03d07aSLuca Tettamanti sensor->acpi_name = kstrdup(name->string.pointer, GFP_KERNEL); 584*2c03d07aSLuca Tettamanti if (!sensor->acpi_name) { 585*2c03d07aSLuca Tettamanti err = -ENOMEM; 586*2c03d07aSLuca Tettamanti goto out; 587*2c03d07aSLuca Tettamanti } 588*2c03d07aSLuca Tettamanti 589*2c03d07aSLuca Tettamanti INIT_LIST_HEAD(&sensor->list); 590*2c03d07aSLuca Tettamanti sensor->type = type; 591*2c03d07aSLuca Tettamanti sensor->data = data; 592*2c03d07aSLuca Tettamanti sensor->id = flags->integer.value; 593*2c03d07aSLuca Tettamanti sensor->limit1 = limit1->integer.value; 594*2c03d07aSLuca Tettamanti sensor->limit2 = limit2->integer.value; 595*2c03d07aSLuca Tettamanti 596*2c03d07aSLuca Tettamanti snprintf(sensor->input_attr_name, ATTR_NAME_SIZE, 597*2c03d07aSLuca Tettamanti "%s%d_input", base_name, start + *num); 598*2c03d07aSLuca Tettamanti atk_init_attribute(&sensor->input_attr, 599*2c03d07aSLuca Tettamanti sensor->input_attr_name, 600*2c03d07aSLuca Tettamanti atk_input_show); 601*2c03d07aSLuca Tettamanti 602*2c03d07aSLuca Tettamanti snprintf(sensor->label_attr_name, ATTR_NAME_SIZE, 603*2c03d07aSLuca Tettamanti "%s%d_label", base_name, start + *num); 604*2c03d07aSLuca Tettamanti atk_init_attribute(&sensor->label_attr, 605*2c03d07aSLuca Tettamanti sensor->label_attr_name, 606*2c03d07aSLuca Tettamanti atk_label_show); 607*2c03d07aSLuca Tettamanti 608*2c03d07aSLuca Tettamanti snprintf(sensor->limit1_attr_name, ATTR_NAME_SIZE, 609*2c03d07aSLuca Tettamanti "%s%d_%s", base_name, start + *num, limit1_name); 610*2c03d07aSLuca Tettamanti atk_init_attribute(&sensor->limit1_attr, 611*2c03d07aSLuca Tettamanti sensor->limit1_attr_name, 612*2c03d07aSLuca Tettamanti atk_limit1_show); 613*2c03d07aSLuca Tettamanti 614*2c03d07aSLuca Tettamanti snprintf(sensor->limit2_attr_name, ATTR_NAME_SIZE, 615*2c03d07aSLuca Tettamanti "%s%d_%s", base_name, start + *num, limit2_name); 616*2c03d07aSLuca Tettamanti atk_init_attribute(&sensor->limit2_attr, 617*2c03d07aSLuca Tettamanti sensor->limit2_attr_name, 618*2c03d07aSLuca Tettamanti atk_limit2_show); 619*2c03d07aSLuca Tettamanti 620*2c03d07aSLuca Tettamanti list_add(&sensor->list, &data->sensor_list); 621*2c03d07aSLuca Tettamanti (*num)++; 622*2c03d07aSLuca Tettamanti 623*2c03d07aSLuca Tettamanti return 1; 624*2c03d07aSLuca Tettamanti out: 625*2c03d07aSLuca Tettamanti kfree(sensor->acpi_name); 626*2c03d07aSLuca Tettamanti kfree(sensor); 627*2c03d07aSLuca Tettamanti return err; 628*2c03d07aSLuca Tettamanti } 629*2c03d07aSLuca Tettamanti 630*2c03d07aSLuca Tettamanti static int atk_enumerate_old_hwmon(struct atk_data *data) 631*2c03d07aSLuca Tettamanti { 632*2c03d07aSLuca Tettamanti struct device *dev = &data->acpi_dev->dev; 633*2c03d07aSLuca Tettamanti struct acpi_buffer buf; 634*2c03d07aSLuca Tettamanti union acpi_object *pack; 635*2c03d07aSLuca Tettamanti acpi_status status; 636*2c03d07aSLuca Tettamanti int i, ret; 637*2c03d07aSLuca Tettamanti int count = 0; 638*2c03d07aSLuca Tettamanti 639*2c03d07aSLuca Tettamanti /* Voltages */ 640*2c03d07aSLuca Tettamanti buf.length = ACPI_ALLOCATE_BUFFER; 641*2c03d07aSLuca Tettamanti status = acpi_evaluate_object_typed(data->atk_handle, 642*2c03d07aSLuca Tettamanti METHOD_OLD_ENUM_VLT, NULL, &buf, ACPI_TYPE_PACKAGE); 643*2c03d07aSLuca Tettamanti if (status != AE_OK) { 644*2c03d07aSLuca Tettamanti dev_warn(dev, METHOD_OLD_ENUM_VLT ": ACPI exception: %s\n", 645*2c03d07aSLuca Tettamanti acpi_format_exception(status)); 646*2c03d07aSLuca Tettamanti 647*2c03d07aSLuca Tettamanti return -ENODEV; 648*2c03d07aSLuca Tettamanti } 649*2c03d07aSLuca Tettamanti 650*2c03d07aSLuca Tettamanti pack = buf.pointer; 651*2c03d07aSLuca Tettamanti for (i = 1; i < pack->package.count; i++) { 652*2c03d07aSLuca Tettamanti union acpi_object *obj = &pack->package.elements[i]; 653*2c03d07aSLuca Tettamanti 654*2c03d07aSLuca Tettamanti ret = atk_add_sensor(data, obj); 655*2c03d07aSLuca Tettamanti if (ret > 0) 656*2c03d07aSLuca Tettamanti count++; 657*2c03d07aSLuca Tettamanti } 658*2c03d07aSLuca Tettamanti ACPI_FREE(buf.pointer); 659*2c03d07aSLuca Tettamanti 660*2c03d07aSLuca Tettamanti /* Temperatures */ 661*2c03d07aSLuca Tettamanti buf.length = ACPI_ALLOCATE_BUFFER; 662*2c03d07aSLuca Tettamanti status = acpi_evaluate_object_typed(data->atk_handle, 663*2c03d07aSLuca Tettamanti METHOD_OLD_ENUM_TMP, NULL, &buf, ACPI_TYPE_PACKAGE); 664*2c03d07aSLuca Tettamanti if (status != AE_OK) { 665*2c03d07aSLuca Tettamanti dev_warn(dev, METHOD_OLD_ENUM_TMP ": ACPI exception: %s\n", 666*2c03d07aSLuca Tettamanti acpi_format_exception(status)); 667*2c03d07aSLuca Tettamanti 668*2c03d07aSLuca Tettamanti ret = -ENODEV; 669*2c03d07aSLuca Tettamanti goto cleanup; 670*2c03d07aSLuca Tettamanti } 671*2c03d07aSLuca Tettamanti 672*2c03d07aSLuca Tettamanti pack = buf.pointer; 673*2c03d07aSLuca Tettamanti for (i = 1; i < pack->package.count; i++) { 674*2c03d07aSLuca Tettamanti union acpi_object *obj = &pack->package.elements[i]; 675*2c03d07aSLuca Tettamanti 676*2c03d07aSLuca Tettamanti ret = atk_add_sensor(data, obj); 677*2c03d07aSLuca Tettamanti if (ret > 0) 678*2c03d07aSLuca Tettamanti count++; 679*2c03d07aSLuca Tettamanti } 680*2c03d07aSLuca Tettamanti ACPI_FREE(buf.pointer); 681*2c03d07aSLuca Tettamanti 682*2c03d07aSLuca Tettamanti /* Fans */ 683*2c03d07aSLuca Tettamanti buf.length = ACPI_ALLOCATE_BUFFER; 684*2c03d07aSLuca Tettamanti status = acpi_evaluate_object_typed(data->atk_handle, 685*2c03d07aSLuca Tettamanti METHOD_OLD_ENUM_FAN, NULL, &buf, ACPI_TYPE_PACKAGE); 686*2c03d07aSLuca Tettamanti if (status != AE_OK) { 687*2c03d07aSLuca Tettamanti dev_warn(dev, METHOD_OLD_ENUM_FAN ": ACPI exception: %s\n", 688*2c03d07aSLuca Tettamanti acpi_format_exception(status)); 689*2c03d07aSLuca Tettamanti 690*2c03d07aSLuca Tettamanti ret = -ENODEV; 691*2c03d07aSLuca Tettamanti goto cleanup; 692*2c03d07aSLuca Tettamanti } 693*2c03d07aSLuca Tettamanti 694*2c03d07aSLuca Tettamanti pack = buf.pointer; 695*2c03d07aSLuca Tettamanti for (i = 1; i < pack->package.count; i++) { 696*2c03d07aSLuca Tettamanti union acpi_object *obj = &pack->package.elements[i]; 697*2c03d07aSLuca Tettamanti 698*2c03d07aSLuca Tettamanti ret = atk_add_sensor(data, obj); 699*2c03d07aSLuca Tettamanti if (ret > 0) 700*2c03d07aSLuca Tettamanti count++; 701*2c03d07aSLuca Tettamanti } 702*2c03d07aSLuca Tettamanti ACPI_FREE(buf.pointer); 703*2c03d07aSLuca Tettamanti 704*2c03d07aSLuca Tettamanti return count; 705*2c03d07aSLuca Tettamanti cleanup: 706*2c03d07aSLuca Tettamanti atk_free_sensors(data); 707*2c03d07aSLuca Tettamanti return ret; 708*2c03d07aSLuca Tettamanti } 709*2c03d07aSLuca Tettamanti 710*2c03d07aSLuca Tettamanti static int atk_enumerate_new_hwmon(struct atk_data *data) 711*2c03d07aSLuca Tettamanti { 712*2c03d07aSLuca Tettamanti struct device *dev = &data->acpi_dev->dev; 713*2c03d07aSLuca Tettamanti struct acpi_buffer buf; 714*2c03d07aSLuca Tettamanti acpi_status ret; 715*2c03d07aSLuca Tettamanti struct acpi_object_list params; 716*2c03d07aSLuca Tettamanti union acpi_object id; 717*2c03d07aSLuca Tettamanti union acpi_object *pack; 718*2c03d07aSLuca Tettamanti int err; 719*2c03d07aSLuca Tettamanti int i; 720*2c03d07aSLuca Tettamanti 721*2c03d07aSLuca Tettamanti dev_dbg(dev, "Enumerating hwmon sensors\n"); 722*2c03d07aSLuca Tettamanti 723*2c03d07aSLuca Tettamanti id.type = ACPI_TYPE_INTEGER; 724*2c03d07aSLuca Tettamanti id.integer.value = ATK_MUX_HWMON; 725*2c03d07aSLuca Tettamanti params.count = 1; 726*2c03d07aSLuca Tettamanti params.pointer = &id; 727*2c03d07aSLuca Tettamanti 728*2c03d07aSLuca Tettamanti buf.length = ACPI_ALLOCATE_BUFFER; 729*2c03d07aSLuca Tettamanti ret = acpi_evaluate_object_typed(data->enumerate_handle, NULL, ¶ms, 730*2c03d07aSLuca Tettamanti &buf, ACPI_TYPE_PACKAGE); 731*2c03d07aSLuca Tettamanti if (ret != AE_OK) { 732*2c03d07aSLuca Tettamanti dev_warn(dev, METHOD_ENUMERATE ": ACPI exception: %s\n", 733*2c03d07aSLuca Tettamanti acpi_format_exception(ret)); 734*2c03d07aSLuca Tettamanti return -ENODEV; 735*2c03d07aSLuca Tettamanti } 736*2c03d07aSLuca Tettamanti 737*2c03d07aSLuca Tettamanti /* Result must be a package */ 738*2c03d07aSLuca Tettamanti pack = buf.pointer; 739*2c03d07aSLuca Tettamanti 740*2c03d07aSLuca Tettamanti if (pack->package.count < 1) { 741*2c03d07aSLuca Tettamanti dev_dbg(dev, "%s: hwmon package is too small: %d\n", __func__, 742*2c03d07aSLuca Tettamanti pack->package.count); 743*2c03d07aSLuca Tettamanti err = -EINVAL; 744*2c03d07aSLuca Tettamanti goto out; 745*2c03d07aSLuca Tettamanti } 746*2c03d07aSLuca Tettamanti 747*2c03d07aSLuca Tettamanti for (i = 0; i < pack->package.count; i++) { 748*2c03d07aSLuca Tettamanti union acpi_object *obj = &pack->package.elements[i]; 749*2c03d07aSLuca Tettamanti 750*2c03d07aSLuca Tettamanti atk_add_sensor(data, obj); 751*2c03d07aSLuca Tettamanti } 752*2c03d07aSLuca Tettamanti 753*2c03d07aSLuca Tettamanti err = data->voltage_count + data->temperature_count + data->fan_count; 754*2c03d07aSLuca Tettamanti 755*2c03d07aSLuca Tettamanti out: 756*2c03d07aSLuca Tettamanti ACPI_FREE(buf.pointer); 757*2c03d07aSLuca Tettamanti return err; 758*2c03d07aSLuca Tettamanti } 759*2c03d07aSLuca Tettamanti 760*2c03d07aSLuca Tettamanti static int atk_create_files(struct atk_data *data) 761*2c03d07aSLuca Tettamanti { 762*2c03d07aSLuca Tettamanti struct atk_sensor_data *s; 763*2c03d07aSLuca Tettamanti int err; 764*2c03d07aSLuca Tettamanti 765*2c03d07aSLuca Tettamanti list_for_each_entry(s, &data->sensor_list, list) { 766*2c03d07aSLuca Tettamanti err = device_create_file(data->hwmon_dev, &s->input_attr); 767*2c03d07aSLuca Tettamanti if (err) 768*2c03d07aSLuca Tettamanti return err; 769*2c03d07aSLuca Tettamanti err = device_create_file(data->hwmon_dev, &s->label_attr); 770*2c03d07aSLuca Tettamanti if (err) 771*2c03d07aSLuca Tettamanti return err; 772*2c03d07aSLuca Tettamanti err = device_create_file(data->hwmon_dev, &s->limit1_attr); 773*2c03d07aSLuca Tettamanti if (err) 774*2c03d07aSLuca Tettamanti return err; 775*2c03d07aSLuca Tettamanti err = device_create_file(data->hwmon_dev, &s->limit2_attr); 776*2c03d07aSLuca Tettamanti if (err) 777*2c03d07aSLuca Tettamanti return err; 778*2c03d07aSLuca Tettamanti } 779*2c03d07aSLuca Tettamanti 780*2c03d07aSLuca Tettamanti err = device_create_file(data->hwmon_dev, &atk_name_attr); 781*2c03d07aSLuca Tettamanti 782*2c03d07aSLuca Tettamanti return err; 783*2c03d07aSLuca Tettamanti } 784*2c03d07aSLuca Tettamanti 785*2c03d07aSLuca Tettamanti static void atk_remove_files(struct atk_data *data) 786*2c03d07aSLuca Tettamanti { 787*2c03d07aSLuca Tettamanti struct atk_sensor_data *s; 788*2c03d07aSLuca Tettamanti 789*2c03d07aSLuca Tettamanti list_for_each_entry(s, &data->sensor_list, list) { 790*2c03d07aSLuca Tettamanti device_remove_file(data->hwmon_dev, &s->input_attr); 791*2c03d07aSLuca Tettamanti device_remove_file(data->hwmon_dev, &s->label_attr); 792*2c03d07aSLuca Tettamanti device_remove_file(data->hwmon_dev, &s->limit1_attr); 793*2c03d07aSLuca Tettamanti device_remove_file(data->hwmon_dev, &s->limit2_attr); 794*2c03d07aSLuca Tettamanti } 795*2c03d07aSLuca Tettamanti device_remove_file(data->hwmon_dev, &atk_name_attr); 796*2c03d07aSLuca Tettamanti } 797*2c03d07aSLuca Tettamanti 798*2c03d07aSLuca Tettamanti static void atk_free_sensors(struct atk_data *data) 799*2c03d07aSLuca Tettamanti { 800*2c03d07aSLuca Tettamanti struct list_head *head = &data->sensor_list; 801*2c03d07aSLuca Tettamanti struct atk_sensor_data *s, *tmp; 802*2c03d07aSLuca Tettamanti 803*2c03d07aSLuca Tettamanti list_for_each_entry_safe(s, tmp, head, list) { 804*2c03d07aSLuca Tettamanti kfree(s->acpi_name); 805*2c03d07aSLuca Tettamanti kfree(s); 806*2c03d07aSLuca Tettamanti } 807*2c03d07aSLuca Tettamanti } 808*2c03d07aSLuca Tettamanti 809*2c03d07aSLuca Tettamanti static int atk_register_hwmon(struct atk_data *data) 810*2c03d07aSLuca Tettamanti { 811*2c03d07aSLuca Tettamanti struct device *dev = &data->acpi_dev->dev; 812*2c03d07aSLuca Tettamanti int err; 813*2c03d07aSLuca Tettamanti 814*2c03d07aSLuca Tettamanti dev_dbg(dev, "registering hwmon device\n"); 815*2c03d07aSLuca Tettamanti data->hwmon_dev = hwmon_device_register(dev); 816*2c03d07aSLuca Tettamanti if (IS_ERR(data->hwmon_dev)) 817*2c03d07aSLuca Tettamanti return PTR_ERR(data->hwmon_dev); 818*2c03d07aSLuca Tettamanti 819*2c03d07aSLuca Tettamanti dev_dbg(dev, "populating sysfs directory\n"); 820*2c03d07aSLuca Tettamanti err = atk_create_files(data); 821*2c03d07aSLuca Tettamanti if (err) 822*2c03d07aSLuca Tettamanti goto remove; 823*2c03d07aSLuca Tettamanti 824*2c03d07aSLuca Tettamanti return 0; 825*2c03d07aSLuca Tettamanti remove: 826*2c03d07aSLuca Tettamanti /* Cleanup the registered files */ 827*2c03d07aSLuca Tettamanti atk_remove_files(data); 828*2c03d07aSLuca Tettamanti hwmon_device_unregister(data->hwmon_dev); 829*2c03d07aSLuca Tettamanti return err; 830*2c03d07aSLuca Tettamanti } 831*2c03d07aSLuca Tettamanti 832*2c03d07aSLuca Tettamanti static int atk_check_old_if(struct atk_data *data) 833*2c03d07aSLuca Tettamanti { 834*2c03d07aSLuca Tettamanti struct device *dev = &data->acpi_dev->dev; 835*2c03d07aSLuca Tettamanti acpi_handle ret; 836*2c03d07aSLuca Tettamanti acpi_status status; 837*2c03d07aSLuca Tettamanti 838*2c03d07aSLuca Tettamanti /* RTMP: read temperature */ 839*2c03d07aSLuca Tettamanti status = acpi_get_handle(data->atk_handle, METHOD_OLD_READ_TMP, &ret); 840*2c03d07aSLuca Tettamanti if (status != AE_OK) { 841*2c03d07aSLuca Tettamanti dev_dbg(dev, "method " METHOD_OLD_READ_TMP " not found: %s\n", 842*2c03d07aSLuca Tettamanti acpi_format_exception(status)); 843*2c03d07aSLuca Tettamanti return -ENODEV; 844*2c03d07aSLuca Tettamanti } 845*2c03d07aSLuca Tettamanti data->rtmp_handle = ret; 846*2c03d07aSLuca Tettamanti 847*2c03d07aSLuca Tettamanti /* RVLT: read voltage */ 848*2c03d07aSLuca Tettamanti status = acpi_get_handle(data->atk_handle, METHOD_OLD_READ_VLT, &ret); 849*2c03d07aSLuca Tettamanti if (status != AE_OK) { 850*2c03d07aSLuca Tettamanti dev_dbg(dev, "method " METHOD_OLD_READ_VLT " not found: %s\n", 851*2c03d07aSLuca Tettamanti acpi_format_exception(status)); 852*2c03d07aSLuca Tettamanti return -ENODEV; 853*2c03d07aSLuca Tettamanti } 854*2c03d07aSLuca Tettamanti data->rvlt_handle = ret; 855*2c03d07aSLuca Tettamanti 856*2c03d07aSLuca Tettamanti /* RFAN: read fan status */ 857*2c03d07aSLuca Tettamanti status = acpi_get_handle(data->atk_handle, METHOD_OLD_READ_FAN, &ret); 858*2c03d07aSLuca Tettamanti if (status != AE_OK) { 859*2c03d07aSLuca Tettamanti dev_dbg(dev, "method " METHOD_OLD_READ_FAN " not found: %s\n", 860*2c03d07aSLuca Tettamanti acpi_format_exception(status)); 861*2c03d07aSLuca Tettamanti return -ENODEV; 862*2c03d07aSLuca Tettamanti } 863*2c03d07aSLuca Tettamanti data->rfan_handle = ret; 864*2c03d07aSLuca Tettamanti 865*2c03d07aSLuca Tettamanti return 0; 866*2c03d07aSLuca Tettamanti } 867*2c03d07aSLuca Tettamanti 868*2c03d07aSLuca Tettamanti static int atk_check_new_if(struct atk_data *data) 869*2c03d07aSLuca Tettamanti { 870*2c03d07aSLuca Tettamanti struct device *dev = &data->acpi_dev->dev; 871*2c03d07aSLuca Tettamanti acpi_handle ret; 872*2c03d07aSLuca Tettamanti acpi_status status; 873*2c03d07aSLuca Tettamanti 874*2c03d07aSLuca Tettamanti /* Enumeration */ 875*2c03d07aSLuca Tettamanti status = acpi_get_handle(data->atk_handle, METHOD_ENUMERATE, &ret); 876*2c03d07aSLuca Tettamanti if (status != AE_OK) { 877*2c03d07aSLuca Tettamanti dev_dbg(dev, "method " METHOD_ENUMERATE " not found: %s\n", 878*2c03d07aSLuca Tettamanti acpi_format_exception(status)); 879*2c03d07aSLuca Tettamanti return -ENODEV; 880*2c03d07aSLuca Tettamanti } 881*2c03d07aSLuca Tettamanti data->enumerate_handle = ret; 882*2c03d07aSLuca Tettamanti 883*2c03d07aSLuca Tettamanti /* De-multiplexer (read) */ 884*2c03d07aSLuca Tettamanti status = acpi_get_handle(data->atk_handle, METHOD_READ, &ret); 885*2c03d07aSLuca Tettamanti if (status != AE_OK) { 886*2c03d07aSLuca Tettamanti dev_dbg(dev, "method " METHOD_READ " not found: %s\n", 887*2c03d07aSLuca Tettamanti acpi_format_exception(status)); 888*2c03d07aSLuca Tettamanti return -ENODEV; 889*2c03d07aSLuca Tettamanti } 890*2c03d07aSLuca Tettamanti data->read_handle = ret; 891*2c03d07aSLuca Tettamanti 892*2c03d07aSLuca Tettamanti return 0; 893*2c03d07aSLuca Tettamanti } 894*2c03d07aSLuca Tettamanti 895*2c03d07aSLuca Tettamanti static int atk_add(struct acpi_device *device) 896*2c03d07aSLuca Tettamanti { 897*2c03d07aSLuca Tettamanti acpi_status ret; 898*2c03d07aSLuca Tettamanti int err; 899*2c03d07aSLuca Tettamanti struct acpi_buffer buf; 900*2c03d07aSLuca Tettamanti union acpi_object *obj; 901*2c03d07aSLuca Tettamanti struct atk_data *data; 902*2c03d07aSLuca Tettamanti 903*2c03d07aSLuca Tettamanti dev_dbg(&device->dev, "adding...\n"); 904*2c03d07aSLuca Tettamanti 905*2c03d07aSLuca Tettamanti data = kzalloc(sizeof(*data), GFP_KERNEL); 906*2c03d07aSLuca Tettamanti if (!data) 907*2c03d07aSLuca Tettamanti return -ENOMEM; 908*2c03d07aSLuca Tettamanti 909*2c03d07aSLuca Tettamanti data->acpi_dev = device; 910*2c03d07aSLuca Tettamanti data->atk_handle = device->handle; 911*2c03d07aSLuca Tettamanti INIT_LIST_HEAD(&data->sensor_list); 912*2c03d07aSLuca Tettamanti 913*2c03d07aSLuca Tettamanti buf.length = ACPI_ALLOCATE_BUFFER; 914*2c03d07aSLuca Tettamanti ret = acpi_evaluate_object_typed(data->atk_handle, BOARD_ID, NULL, 915*2c03d07aSLuca Tettamanti &buf, ACPI_TYPE_PACKAGE); 916*2c03d07aSLuca Tettamanti if (ret != AE_OK) { 917*2c03d07aSLuca Tettamanti dev_dbg(&device->dev, "atk: method MBIF not found\n"); 918*2c03d07aSLuca Tettamanti err = -ENODEV; 919*2c03d07aSLuca Tettamanti goto out; 920*2c03d07aSLuca Tettamanti } 921*2c03d07aSLuca Tettamanti 922*2c03d07aSLuca Tettamanti obj = buf.pointer; 923*2c03d07aSLuca Tettamanti if (obj->package.count >= 2 && 924*2c03d07aSLuca Tettamanti obj->package.elements[1].type == ACPI_TYPE_STRING) { 925*2c03d07aSLuca Tettamanti dev_dbg(&device->dev, "board ID = %s\n", 926*2c03d07aSLuca Tettamanti obj->package.elements[1].string.pointer); 927*2c03d07aSLuca Tettamanti } 928*2c03d07aSLuca Tettamanti ACPI_FREE(buf.pointer); 929*2c03d07aSLuca Tettamanti 930*2c03d07aSLuca Tettamanti /* Check for hwmon methods: first check "old" style methods; note that 931*2c03d07aSLuca Tettamanti * both may be present: in this case we stick to the old interface; 932*2c03d07aSLuca Tettamanti * analysis of multiple DSDTs indicates that when both interfaces 933*2c03d07aSLuca Tettamanti * are present the new one (GGRP/GITM) is not functional. 934*2c03d07aSLuca Tettamanti */ 935*2c03d07aSLuca Tettamanti err = atk_check_old_if(data); 936*2c03d07aSLuca Tettamanti if (!err) { 937*2c03d07aSLuca Tettamanti dev_dbg(&device->dev, "Using old hwmon interface\n"); 938*2c03d07aSLuca Tettamanti data->old_interface = true; 939*2c03d07aSLuca Tettamanti } else { 940*2c03d07aSLuca Tettamanti err = atk_check_new_if(data); 941*2c03d07aSLuca Tettamanti if (err) 942*2c03d07aSLuca Tettamanti goto out; 943*2c03d07aSLuca Tettamanti 944*2c03d07aSLuca Tettamanti dev_dbg(&device->dev, "Using new hwmon interface\n"); 945*2c03d07aSLuca Tettamanti data->old_interface = false; 946*2c03d07aSLuca Tettamanti } 947*2c03d07aSLuca Tettamanti 948*2c03d07aSLuca Tettamanti if (data->old_interface) 949*2c03d07aSLuca Tettamanti err = atk_enumerate_old_hwmon(data); 950*2c03d07aSLuca Tettamanti else 951*2c03d07aSLuca Tettamanti err = atk_enumerate_new_hwmon(data); 952*2c03d07aSLuca Tettamanti if (err < 0) 953*2c03d07aSLuca Tettamanti goto out; 954*2c03d07aSLuca Tettamanti if (err == 0) { 955*2c03d07aSLuca Tettamanti dev_info(&device->dev, 956*2c03d07aSLuca Tettamanti "No usable sensor detected, bailing out\n"); 957*2c03d07aSLuca Tettamanti err = -ENODEV; 958*2c03d07aSLuca Tettamanti goto out; 959*2c03d07aSLuca Tettamanti } 960*2c03d07aSLuca Tettamanti 961*2c03d07aSLuca Tettamanti err = atk_register_hwmon(data); 962*2c03d07aSLuca Tettamanti if (err) 963*2c03d07aSLuca Tettamanti goto cleanup; 964*2c03d07aSLuca Tettamanti 965*2c03d07aSLuca Tettamanti device->driver_data = data; 966*2c03d07aSLuca Tettamanti return 0; 967*2c03d07aSLuca Tettamanti cleanup: 968*2c03d07aSLuca Tettamanti atk_free_sensors(data); 969*2c03d07aSLuca Tettamanti out: 970*2c03d07aSLuca Tettamanti kfree(data); 971*2c03d07aSLuca Tettamanti return err; 972*2c03d07aSLuca Tettamanti } 973*2c03d07aSLuca Tettamanti 974*2c03d07aSLuca Tettamanti static int atk_remove(struct acpi_device *device, int type) 975*2c03d07aSLuca Tettamanti { 976*2c03d07aSLuca Tettamanti struct atk_data *data = device->driver_data; 977*2c03d07aSLuca Tettamanti dev_dbg(&device->dev, "removing...\n"); 978*2c03d07aSLuca Tettamanti 979*2c03d07aSLuca Tettamanti device->driver_data = NULL; 980*2c03d07aSLuca Tettamanti 981*2c03d07aSLuca Tettamanti atk_remove_files(data); 982*2c03d07aSLuca Tettamanti atk_free_sensors(data); 983*2c03d07aSLuca Tettamanti hwmon_device_unregister(data->hwmon_dev); 984*2c03d07aSLuca Tettamanti 985*2c03d07aSLuca Tettamanti kfree(data); 986*2c03d07aSLuca Tettamanti 987*2c03d07aSLuca Tettamanti return 0; 988*2c03d07aSLuca Tettamanti } 989*2c03d07aSLuca Tettamanti 990*2c03d07aSLuca Tettamanti static int __init atk0110_init(void) 991*2c03d07aSLuca Tettamanti { 992*2c03d07aSLuca Tettamanti int ret; 993*2c03d07aSLuca Tettamanti 994*2c03d07aSLuca Tettamanti ret = acpi_bus_register_driver(&atk_driver); 995*2c03d07aSLuca Tettamanti if (ret) 996*2c03d07aSLuca Tettamanti pr_info("atk: acpi_bus_register_driver failed: %d\n", ret); 997*2c03d07aSLuca Tettamanti 998*2c03d07aSLuca Tettamanti return ret; 999*2c03d07aSLuca Tettamanti } 1000*2c03d07aSLuca Tettamanti 1001*2c03d07aSLuca Tettamanti static void __exit atk0110_exit(void) 1002*2c03d07aSLuca Tettamanti { 1003*2c03d07aSLuca Tettamanti acpi_bus_unregister_driver(&atk_driver); 1004*2c03d07aSLuca Tettamanti } 1005*2c03d07aSLuca Tettamanti 1006*2c03d07aSLuca Tettamanti module_init(atk0110_init); 1007*2c03d07aSLuca Tettamanti module_exit(atk0110_exit); 1008*2c03d07aSLuca Tettamanti 1009*2c03d07aSLuca Tettamanti MODULE_LICENSE("GPL"); 1010