1a77272c1SArmin Wolf // SPDX-License-Identifier: GPL-2.0-or-later
2a77272c1SArmin Wolf /*
3a77272c1SArmin Wolf * Linux driver for WMI sensor information on Dell notebooks.
4a77272c1SArmin Wolf *
5a77272c1SArmin Wolf * Copyright (C) 2022 Armin Wolf <W_Armin@gmx.de>
6a77272c1SArmin Wolf */
7a77272c1SArmin Wolf
8a77272c1SArmin Wolf #define pr_format(fmt) KBUILD_MODNAME ": " fmt
9a77272c1SArmin Wolf
10a77272c1SArmin Wolf #include <linux/acpi.h>
11a77272c1SArmin Wolf #include <linux/debugfs.h>
12a77272c1SArmin Wolf #include <linux/device.h>
136113bd52SArmin Wolf #include <linux/device/driver.h>
14c7891884SArmin Wolf #include <linux/dev_printk.h>
1536d44825SArmin Wolf #include <linux/errno.h>
163b7eeff9SArmin Wolf #include <linux/kconfig.h>
17a77272c1SArmin Wolf #include <linux/kernel.h>
183b7eeff9SArmin Wolf #include <linux/hwmon.h>
19a77272c1SArmin Wolf #include <linux/kstrtox.h>
203b7eeff9SArmin Wolf #include <linux/math64.h>
21a77272c1SArmin Wolf #include <linux/module.h>
223b7eeff9SArmin Wolf #include <linux/mutex.h>
23a77272c1SArmin Wolf #include <linux/limits.h>
243b7eeff9SArmin Wolf #include <linux/pm.h>
25a77272c1SArmin Wolf #include <linux/power_supply.h>
26c7891884SArmin Wolf #include <linux/printk.h>
27a77272c1SArmin Wolf #include <linux/seq_file.h>
28a77272c1SArmin Wolf #include <linux/sysfs.h>
293b7eeff9SArmin Wolf #include <linux/types.h>
30a77272c1SArmin Wolf #include <linux/wmi.h>
31a77272c1SArmin Wolf
32a77272c1SArmin Wolf #include <acpi/battery.h>
33a77272c1SArmin Wolf
343b7eeff9SArmin Wolf #include <asm/unaligned.h>
353b7eeff9SArmin Wolf
36a77272c1SArmin Wolf #define DRIVER_NAME "dell-wmi-ddv"
37a77272c1SArmin Wolf
383e899fecSArmin Wolf #define DELL_DDV_SUPPORTED_VERSION_MIN 2
393e899fecSArmin Wolf #define DELL_DDV_SUPPORTED_VERSION_MAX 3
40a77272c1SArmin Wolf #define DELL_DDV_GUID "8A42EA14-4F2A-FD45-6422-0087F7A7E608"
41a77272c1SArmin Wolf
42c7891884SArmin Wolf #define DELL_EPPID_LENGTH 20
43c7891884SArmin Wolf #define DELL_EPPID_EXT_LENGTH 23
44c7891884SArmin Wolf
45cf2cc541SArmin Wolf static bool force;
46cf2cc541SArmin Wolf module_param_unsafe(force, bool, 0);
47cf2cc541SArmin Wolf MODULE_PARM_DESC(force, "Force loading without checking for supported WMI interface versions");
48cf2cc541SArmin Wolf
49a77272c1SArmin Wolf enum dell_ddv_method {
50a77272c1SArmin Wolf DELL_DDV_BATTERY_DESIGN_CAPACITY = 0x01,
51a77272c1SArmin Wolf DELL_DDV_BATTERY_FULL_CHARGE_CAPACITY = 0x02,
52a77272c1SArmin Wolf DELL_DDV_BATTERY_MANUFACTURE_NAME = 0x03,
53a77272c1SArmin Wolf DELL_DDV_BATTERY_MANUFACTURE_DATE = 0x04,
54a77272c1SArmin Wolf DELL_DDV_BATTERY_SERIAL_NUMBER = 0x05,
55a77272c1SArmin Wolf DELL_DDV_BATTERY_CHEMISTRY_VALUE = 0x06,
56a77272c1SArmin Wolf DELL_DDV_BATTERY_TEMPERATURE = 0x07,
57a77272c1SArmin Wolf DELL_DDV_BATTERY_CURRENT = 0x08,
58a77272c1SArmin Wolf DELL_DDV_BATTERY_VOLTAGE = 0x09,
59a77272c1SArmin Wolf DELL_DDV_BATTERY_MANUFACTURER_ACCESS = 0x0A,
60a77272c1SArmin Wolf DELL_DDV_BATTERY_RELATIVE_CHARGE_STATE = 0x0B,
61a77272c1SArmin Wolf DELL_DDV_BATTERY_CYCLE_COUNT = 0x0C,
62a77272c1SArmin Wolf DELL_DDV_BATTERY_EPPID = 0x0D,
63a77272c1SArmin Wolf DELL_DDV_BATTERY_RAW_ANALYTICS_START = 0x0E,
64a77272c1SArmin Wolf DELL_DDV_BATTERY_RAW_ANALYTICS = 0x0F,
65a77272c1SArmin Wolf DELL_DDV_BATTERY_DESIGN_VOLTAGE = 0x10,
663e899fecSArmin Wolf DELL_DDV_BATTERY_RAW_ANALYTICS_A_BLOCK = 0x11, /* version 3 */
67a77272c1SArmin Wolf
68a77272c1SArmin Wolf DELL_DDV_INTERFACE_VERSION = 0x12,
69a77272c1SArmin Wolf
70a77272c1SArmin Wolf DELL_DDV_FAN_SENSOR_INFORMATION = 0x20,
71a77272c1SArmin Wolf DELL_DDV_THERMAL_SENSOR_INFORMATION = 0x22,
72a77272c1SArmin Wolf };
73a77272c1SArmin Wolf
743b7eeff9SArmin Wolf struct fan_sensor_entry {
753b7eeff9SArmin Wolf u8 type;
763b7eeff9SArmin Wolf __le16 rpm;
773b7eeff9SArmin Wolf } __packed;
783b7eeff9SArmin Wolf
793b7eeff9SArmin Wolf struct thermal_sensor_entry {
803b7eeff9SArmin Wolf u8 type;
813b7eeff9SArmin Wolf s8 now;
823b7eeff9SArmin Wolf s8 min;
833b7eeff9SArmin Wolf s8 max;
843b7eeff9SArmin Wolf u8 unknown;
853b7eeff9SArmin Wolf } __packed;
863b7eeff9SArmin Wolf
873b7eeff9SArmin Wolf struct combined_channel_info {
883b7eeff9SArmin Wolf struct hwmon_channel_info info;
893b7eeff9SArmin Wolf u32 config[];
903b7eeff9SArmin Wolf };
913b7eeff9SArmin Wolf
923b7eeff9SArmin Wolf struct combined_chip_info {
933b7eeff9SArmin Wolf struct hwmon_chip_info chip;
943b7eeff9SArmin Wolf const struct hwmon_channel_info *info[];
953b7eeff9SArmin Wolf };
963b7eeff9SArmin Wolf
973b7eeff9SArmin Wolf struct dell_wmi_ddv_sensors {
98001f61c4SArmin Wolf bool active;
993b7eeff9SArmin Wolf struct mutex lock; /* protect caching */
1003b7eeff9SArmin Wolf unsigned long timestamp;
1013b7eeff9SArmin Wolf union acpi_object *obj;
1023b7eeff9SArmin Wolf u64 entries;
1033b7eeff9SArmin Wolf };
1043b7eeff9SArmin Wolf
105a77272c1SArmin Wolf struct dell_wmi_ddv_data {
106a77272c1SArmin Wolf struct acpi_battery_hook hook;
107a77272c1SArmin Wolf struct device_attribute temp_attr;
108a77272c1SArmin Wolf struct device_attribute eppid_attr;
1093b7eeff9SArmin Wolf struct dell_wmi_ddv_sensors fans;
1103b7eeff9SArmin Wolf struct dell_wmi_ddv_sensors temps;
111a77272c1SArmin Wolf struct wmi_device *wdev;
112a77272c1SArmin Wolf };
113a77272c1SArmin Wolf
1143b7eeff9SArmin Wolf static const char * const fan_labels[] = {
1153b7eeff9SArmin Wolf "CPU Fan",
1163b7eeff9SArmin Wolf "Chassis Motherboard Fan",
1173b7eeff9SArmin Wolf "Video Fan",
1183b7eeff9SArmin Wolf "Power Supply Fan",
1193b7eeff9SArmin Wolf "Chipset Fan",
1203b7eeff9SArmin Wolf "Memory Fan",
1213b7eeff9SArmin Wolf "PCI Fan",
1223b7eeff9SArmin Wolf "HDD Fan",
1233b7eeff9SArmin Wolf };
1243b7eeff9SArmin Wolf
1253b7eeff9SArmin Wolf static const char * const fan_dock_labels[] = {
1263b7eeff9SArmin Wolf "Docking Chassis/Motherboard Fan",
1273b7eeff9SArmin Wolf "Docking Video Fan",
1283b7eeff9SArmin Wolf "Docking Power Supply Fan",
1293b7eeff9SArmin Wolf "Docking Chipset Fan",
1303b7eeff9SArmin Wolf };
1313b7eeff9SArmin Wolf
dell_wmi_ddv_query_type(struct wmi_device * wdev,enum dell_ddv_method method,u32 arg,union acpi_object ** result,acpi_object_type type)132a77272c1SArmin Wolf static int dell_wmi_ddv_query_type(struct wmi_device *wdev, enum dell_ddv_method method, u32 arg,
133a77272c1SArmin Wolf union acpi_object **result, acpi_object_type type)
134a77272c1SArmin Wolf {
135a77272c1SArmin Wolf struct acpi_buffer out = { ACPI_ALLOCATE_BUFFER, NULL };
136a77272c1SArmin Wolf const struct acpi_buffer in = {
137a77272c1SArmin Wolf .length = sizeof(arg),
138a77272c1SArmin Wolf .pointer = &arg,
139a77272c1SArmin Wolf };
140a77272c1SArmin Wolf union acpi_object *obj;
141a77272c1SArmin Wolf acpi_status ret;
142a77272c1SArmin Wolf
143a77272c1SArmin Wolf ret = wmidev_evaluate_method(wdev, 0x0, method, &in, &out);
144a77272c1SArmin Wolf if (ACPI_FAILURE(ret))
145a77272c1SArmin Wolf return -EIO;
146a77272c1SArmin Wolf
147a77272c1SArmin Wolf obj = out.pointer;
148a77272c1SArmin Wolf if (!obj)
149a77272c1SArmin Wolf return -ENODATA;
150a77272c1SArmin Wolf
151a77272c1SArmin Wolf if (obj->type != type) {
152a77272c1SArmin Wolf kfree(obj);
1538b52501cSArmin Wolf return -ENOMSG;
154a77272c1SArmin Wolf }
155a77272c1SArmin Wolf
156a77272c1SArmin Wolf *result = obj;
157a77272c1SArmin Wolf
158a77272c1SArmin Wolf return 0;
159a77272c1SArmin Wolf }
160a77272c1SArmin Wolf
dell_wmi_ddv_query_integer(struct wmi_device * wdev,enum dell_ddv_method method,u32 arg,u32 * res)161a77272c1SArmin Wolf static int dell_wmi_ddv_query_integer(struct wmi_device *wdev, enum dell_ddv_method method,
162a77272c1SArmin Wolf u32 arg, u32 *res)
163a77272c1SArmin Wolf {
164a77272c1SArmin Wolf union acpi_object *obj;
165a77272c1SArmin Wolf int ret;
166a77272c1SArmin Wolf
167a77272c1SArmin Wolf ret = dell_wmi_ddv_query_type(wdev, method, arg, &obj, ACPI_TYPE_INTEGER);
168a77272c1SArmin Wolf if (ret < 0)
169a77272c1SArmin Wolf return ret;
170a77272c1SArmin Wolf
171a77272c1SArmin Wolf if (obj->integer.value <= U32_MAX)
172a77272c1SArmin Wolf *res = (u32)obj->integer.value;
173a77272c1SArmin Wolf else
174a77272c1SArmin Wolf ret = -ERANGE;
175a77272c1SArmin Wolf
176a77272c1SArmin Wolf kfree(obj);
177a77272c1SArmin Wolf
178a77272c1SArmin Wolf return ret;
179a77272c1SArmin Wolf }
180a77272c1SArmin Wolf
dell_wmi_ddv_query_buffer(struct wmi_device * wdev,enum dell_ddv_method method,u32 arg,union acpi_object ** result)181a77272c1SArmin Wolf static int dell_wmi_ddv_query_buffer(struct wmi_device *wdev, enum dell_ddv_method method,
182a77272c1SArmin Wolf u32 arg, union acpi_object **result)
183a77272c1SArmin Wolf {
184a77272c1SArmin Wolf union acpi_object *obj;
185a77272c1SArmin Wolf u64 buffer_size;
186a77272c1SArmin Wolf int ret;
187a77272c1SArmin Wolf
188a77272c1SArmin Wolf ret = dell_wmi_ddv_query_type(wdev, method, arg, &obj, ACPI_TYPE_PACKAGE);
189a77272c1SArmin Wolf if (ret < 0)
190a77272c1SArmin Wolf return ret;
191a77272c1SArmin Wolf
19236d44825SArmin Wolf if (obj->package.count != 2 ||
19336d44825SArmin Wolf obj->package.elements[0].type != ACPI_TYPE_INTEGER ||
19436d44825SArmin Wolf obj->package.elements[1].type != ACPI_TYPE_BUFFER) {
19536d44825SArmin Wolf ret = -ENOMSG;
196a77272c1SArmin Wolf
197a77272c1SArmin Wolf goto err_free;
19836d44825SArmin Wolf }
199a77272c1SArmin Wolf
200a77272c1SArmin Wolf buffer_size = obj->package.elements[0].integer.value;
201a77272c1SArmin Wolf
20236d44825SArmin Wolf if (!buffer_size) {
20336d44825SArmin Wolf ret = -ENODATA;
20436d44825SArmin Wolf
205a77272c1SArmin Wolf goto err_free;
20636d44825SArmin Wolf }
207a77272c1SArmin Wolf
20884fa20c2SArmin Wolf if (buffer_size > obj->package.elements[1].buffer.length) {
209a77272c1SArmin Wolf dev_warn(&wdev->dev,
21084fa20c2SArmin Wolf FW_WARN "WMI buffer size (%llu) exceeds ACPI buffer size (%d)\n",
211a77272c1SArmin Wolf buffer_size, obj->package.elements[1].buffer.length);
21236d44825SArmin Wolf ret = -EMSGSIZE;
213a77272c1SArmin Wolf
214a77272c1SArmin Wolf goto err_free;
215a77272c1SArmin Wolf }
216a77272c1SArmin Wolf
217a77272c1SArmin Wolf *result = obj;
218a77272c1SArmin Wolf
219a77272c1SArmin Wolf return 0;
220a77272c1SArmin Wolf
221a77272c1SArmin Wolf err_free:
222a77272c1SArmin Wolf kfree(obj);
223a77272c1SArmin Wolf
22436d44825SArmin Wolf return ret;
225a77272c1SArmin Wolf }
226a77272c1SArmin Wolf
dell_wmi_ddv_query_string(struct wmi_device * wdev,enum dell_ddv_method method,u32 arg,union acpi_object ** result)227a77272c1SArmin Wolf static int dell_wmi_ddv_query_string(struct wmi_device *wdev, enum dell_ddv_method method,
228a77272c1SArmin Wolf u32 arg, union acpi_object **result)
229a77272c1SArmin Wolf {
230a77272c1SArmin Wolf return dell_wmi_ddv_query_type(wdev, method, arg, result, ACPI_TYPE_STRING);
231a77272c1SArmin Wolf }
232a77272c1SArmin Wolf
2333b7eeff9SArmin Wolf /*
2343b7eeff9SArmin Wolf * Needs to be called with lock held, except during initialization.
2353b7eeff9SArmin Wolf */
dell_wmi_ddv_update_sensors(struct wmi_device * wdev,enum dell_ddv_method method,struct dell_wmi_ddv_sensors * sensors,size_t entry_size)2363b7eeff9SArmin Wolf static int dell_wmi_ddv_update_sensors(struct wmi_device *wdev, enum dell_ddv_method method,
2373b7eeff9SArmin Wolf struct dell_wmi_ddv_sensors *sensors, size_t entry_size)
2383b7eeff9SArmin Wolf {
2393b7eeff9SArmin Wolf u64 buffer_size, rem, entries;
2403b7eeff9SArmin Wolf union acpi_object *obj;
2413b7eeff9SArmin Wolf u8 *buffer;
2423b7eeff9SArmin Wolf int ret;
2433b7eeff9SArmin Wolf
2443b7eeff9SArmin Wolf if (sensors->obj) {
2453b7eeff9SArmin Wolf if (time_before(jiffies, sensors->timestamp + HZ))
2463b7eeff9SArmin Wolf return 0;
2473b7eeff9SArmin Wolf
2483b7eeff9SArmin Wolf kfree(sensors->obj);
2493b7eeff9SArmin Wolf sensors->obj = NULL;
2503b7eeff9SArmin Wolf }
2513b7eeff9SArmin Wolf
2523b7eeff9SArmin Wolf ret = dell_wmi_ddv_query_buffer(wdev, method, 0, &obj);
2533b7eeff9SArmin Wolf if (ret < 0)
2543b7eeff9SArmin Wolf return ret;
2553b7eeff9SArmin Wolf
2563b7eeff9SArmin Wolf /* buffer format sanity check */
2573b7eeff9SArmin Wolf buffer_size = obj->package.elements[0].integer.value;
2583b7eeff9SArmin Wolf buffer = obj->package.elements[1].buffer.pointer;
2593b7eeff9SArmin Wolf entries = div64_u64_rem(buffer_size, entry_size, &rem);
2603b7eeff9SArmin Wolf if (rem != 1 || buffer[buffer_size - 1] != 0xff) {
2613b7eeff9SArmin Wolf ret = -ENOMSG;
2623b7eeff9SArmin Wolf goto err_free;
2633b7eeff9SArmin Wolf }
2643b7eeff9SArmin Wolf
2653b7eeff9SArmin Wolf if (!entries) {
2663b7eeff9SArmin Wolf ret = -ENODATA;
2673b7eeff9SArmin Wolf goto err_free;
2683b7eeff9SArmin Wolf }
2693b7eeff9SArmin Wolf
2703b7eeff9SArmin Wolf sensors->obj = obj;
2713b7eeff9SArmin Wolf sensors->entries = entries;
2723b7eeff9SArmin Wolf sensors->timestamp = jiffies;
2733b7eeff9SArmin Wolf
2743b7eeff9SArmin Wolf return 0;
2753b7eeff9SArmin Wolf
2763b7eeff9SArmin Wolf err_free:
2773b7eeff9SArmin Wolf kfree(obj);
2783b7eeff9SArmin Wolf
2793b7eeff9SArmin Wolf return ret;
2803b7eeff9SArmin Wolf }
2813b7eeff9SArmin Wolf
dell_wmi_ddv_is_visible(const void * drvdata,enum hwmon_sensor_types type,u32 attr,int channel)2823b7eeff9SArmin Wolf static umode_t dell_wmi_ddv_is_visible(const void *drvdata, enum hwmon_sensor_types type, u32 attr,
2833b7eeff9SArmin Wolf int channel)
2843b7eeff9SArmin Wolf {
2853b7eeff9SArmin Wolf return 0444;
2863b7eeff9SArmin Wolf }
2873b7eeff9SArmin Wolf
dell_wmi_ddv_fan_read_channel(struct dell_wmi_ddv_data * data,u32 attr,int channel,long * val)2883b7eeff9SArmin Wolf static int dell_wmi_ddv_fan_read_channel(struct dell_wmi_ddv_data *data, u32 attr, int channel,
2893b7eeff9SArmin Wolf long *val)
2903b7eeff9SArmin Wolf {
2913b7eeff9SArmin Wolf struct fan_sensor_entry *entry;
2923b7eeff9SArmin Wolf int ret;
2933b7eeff9SArmin Wolf
2943b7eeff9SArmin Wolf ret = dell_wmi_ddv_update_sensors(data->wdev, DELL_DDV_FAN_SENSOR_INFORMATION,
2953b7eeff9SArmin Wolf &data->fans, sizeof(*entry));
2963b7eeff9SArmin Wolf if (ret < 0)
2973b7eeff9SArmin Wolf return ret;
2983b7eeff9SArmin Wolf
2993b7eeff9SArmin Wolf if (channel >= data->fans.entries)
3003b7eeff9SArmin Wolf return -ENXIO;
3013b7eeff9SArmin Wolf
3023b7eeff9SArmin Wolf entry = (struct fan_sensor_entry *)data->fans.obj->package.elements[1].buffer.pointer;
3033b7eeff9SArmin Wolf switch (attr) {
3043b7eeff9SArmin Wolf case hwmon_fan_input:
3053b7eeff9SArmin Wolf *val = get_unaligned_le16(&entry[channel].rpm);
3063b7eeff9SArmin Wolf return 0;
3073b7eeff9SArmin Wolf default:
3083b7eeff9SArmin Wolf break;
3093b7eeff9SArmin Wolf }
3103b7eeff9SArmin Wolf
3113b7eeff9SArmin Wolf return -EOPNOTSUPP;
3123b7eeff9SArmin Wolf }
3133b7eeff9SArmin Wolf
dell_wmi_ddv_temp_read_channel(struct dell_wmi_ddv_data * data,u32 attr,int channel,long * val)3143b7eeff9SArmin Wolf static int dell_wmi_ddv_temp_read_channel(struct dell_wmi_ddv_data *data, u32 attr, int channel,
3153b7eeff9SArmin Wolf long *val)
3163b7eeff9SArmin Wolf {
3173b7eeff9SArmin Wolf struct thermal_sensor_entry *entry;
3183b7eeff9SArmin Wolf int ret;
3193b7eeff9SArmin Wolf
3203b7eeff9SArmin Wolf ret = dell_wmi_ddv_update_sensors(data->wdev, DELL_DDV_THERMAL_SENSOR_INFORMATION,
3213b7eeff9SArmin Wolf &data->temps, sizeof(*entry));
3223b7eeff9SArmin Wolf if (ret < 0)
3233b7eeff9SArmin Wolf return ret;
3243b7eeff9SArmin Wolf
3253b7eeff9SArmin Wolf if (channel >= data->temps.entries)
3263b7eeff9SArmin Wolf return -ENXIO;
3273b7eeff9SArmin Wolf
3283b7eeff9SArmin Wolf entry = (struct thermal_sensor_entry *)data->temps.obj->package.elements[1].buffer.pointer;
3293b7eeff9SArmin Wolf switch (attr) {
3303b7eeff9SArmin Wolf case hwmon_temp_input:
3313b7eeff9SArmin Wolf *val = entry[channel].now * 1000;
3323b7eeff9SArmin Wolf return 0;
3333b7eeff9SArmin Wolf case hwmon_temp_min:
3343b7eeff9SArmin Wolf *val = entry[channel].min * 1000;
3353b7eeff9SArmin Wolf return 0;
3363b7eeff9SArmin Wolf case hwmon_temp_max:
3373b7eeff9SArmin Wolf *val = entry[channel].max * 1000;
3383b7eeff9SArmin Wolf return 0;
3393b7eeff9SArmin Wolf default:
3403b7eeff9SArmin Wolf break;
3413b7eeff9SArmin Wolf }
3423b7eeff9SArmin Wolf
3433b7eeff9SArmin Wolf return -EOPNOTSUPP;
3443b7eeff9SArmin Wolf }
3453b7eeff9SArmin Wolf
dell_wmi_ddv_read(struct device * dev,enum hwmon_sensor_types type,u32 attr,int channel,long * val)3463b7eeff9SArmin Wolf static int dell_wmi_ddv_read(struct device *dev, enum hwmon_sensor_types type, u32 attr,
3473b7eeff9SArmin Wolf int channel, long *val)
3483b7eeff9SArmin Wolf {
3493b7eeff9SArmin Wolf struct dell_wmi_ddv_data *data = dev_get_drvdata(dev);
3503b7eeff9SArmin Wolf int ret;
3513b7eeff9SArmin Wolf
3523b7eeff9SArmin Wolf switch (type) {
3533b7eeff9SArmin Wolf case hwmon_fan:
3543b7eeff9SArmin Wolf mutex_lock(&data->fans.lock);
3553b7eeff9SArmin Wolf ret = dell_wmi_ddv_fan_read_channel(data, attr, channel, val);
3563b7eeff9SArmin Wolf mutex_unlock(&data->fans.lock);
3573b7eeff9SArmin Wolf return ret;
3583b7eeff9SArmin Wolf case hwmon_temp:
3593b7eeff9SArmin Wolf mutex_lock(&data->temps.lock);
3603b7eeff9SArmin Wolf ret = dell_wmi_ddv_temp_read_channel(data, attr, channel, val);
3613b7eeff9SArmin Wolf mutex_unlock(&data->temps.lock);
3623b7eeff9SArmin Wolf return ret;
3633b7eeff9SArmin Wolf default:
3643b7eeff9SArmin Wolf break;
3653b7eeff9SArmin Wolf }
3663b7eeff9SArmin Wolf
3673b7eeff9SArmin Wolf return -EOPNOTSUPP;
3683b7eeff9SArmin Wolf }
3693b7eeff9SArmin Wolf
dell_wmi_ddv_fan_read_string(struct dell_wmi_ddv_data * data,int channel,const char ** str)3703b7eeff9SArmin Wolf static int dell_wmi_ddv_fan_read_string(struct dell_wmi_ddv_data *data, int channel,
3713b7eeff9SArmin Wolf const char **str)
3723b7eeff9SArmin Wolf {
3733b7eeff9SArmin Wolf struct fan_sensor_entry *entry;
3743b7eeff9SArmin Wolf int ret;
3753b7eeff9SArmin Wolf u8 type;
3763b7eeff9SArmin Wolf
3773b7eeff9SArmin Wolf ret = dell_wmi_ddv_update_sensors(data->wdev, DELL_DDV_FAN_SENSOR_INFORMATION,
3783b7eeff9SArmin Wolf &data->fans, sizeof(*entry));
3793b7eeff9SArmin Wolf if (ret < 0)
3803b7eeff9SArmin Wolf return ret;
3813b7eeff9SArmin Wolf
3823b7eeff9SArmin Wolf if (channel >= data->fans.entries)
3833b7eeff9SArmin Wolf return -ENXIO;
3843b7eeff9SArmin Wolf
3853b7eeff9SArmin Wolf entry = (struct fan_sensor_entry *)data->fans.obj->package.elements[1].buffer.pointer;
3863b7eeff9SArmin Wolf type = entry[channel].type;
3873b7eeff9SArmin Wolf switch (type) {
3883b7eeff9SArmin Wolf case 0x00 ... 0x07:
3893b7eeff9SArmin Wolf *str = fan_labels[type];
3903b7eeff9SArmin Wolf break;
3913b7eeff9SArmin Wolf case 0x11 ... 0x14:
3923b7eeff9SArmin Wolf *str = fan_dock_labels[type - 0x11];
3933b7eeff9SArmin Wolf break;
3943b7eeff9SArmin Wolf default:
3953b7eeff9SArmin Wolf *str = "Unknown Fan";
3963b7eeff9SArmin Wolf break;
3973b7eeff9SArmin Wolf }
3983b7eeff9SArmin Wolf
3993b7eeff9SArmin Wolf return 0;
4003b7eeff9SArmin Wolf }
4013b7eeff9SArmin Wolf
dell_wmi_ddv_temp_read_string(struct dell_wmi_ddv_data * data,int channel,const char ** str)4023b7eeff9SArmin Wolf static int dell_wmi_ddv_temp_read_string(struct dell_wmi_ddv_data *data, int channel,
4033b7eeff9SArmin Wolf const char **str)
4043b7eeff9SArmin Wolf {
4053b7eeff9SArmin Wolf struct thermal_sensor_entry *entry;
4063b7eeff9SArmin Wolf int ret;
4073b7eeff9SArmin Wolf
4083b7eeff9SArmin Wolf ret = dell_wmi_ddv_update_sensors(data->wdev, DELL_DDV_THERMAL_SENSOR_INFORMATION,
4093b7eeff9SArmin Wolf &data->temps, sizeof(*entry));
4103b7eeff9SArmin Wolf if (ret < 0)
4113b7eeff9SArmin Wolf return ret;
4123b7eeff9SArmin Wolf
4133b7eeff9SArmin Wolf if (channel >= data->temps.entries)
4143b7eeff9SArmin Wolf return -ENXIO;
4153b7eeff9SArmin Wolf
4163b7eeff9SArmin Wolf entry = (struct thermal_sensor_entry *)data->temps.obj->package.elements[1].buffer.pointer;
4173b7eeff9SArmin Wolf switch (entry[channel].type) {
4183b7eeff9SArmin Wolf case 0x00:
4193b7eeff9SArmin Wolf *str = "CPU";
4203b7eeff9SArmin Wolf break;
4213b7eeff9SArmin Wolf case 0x11:
4223b7eeff9SArmin Wolf *str = "Video";
4233b7eeff9SArmin Wolf break;
4243b7eeff9SArmin Wolf case 0x22:
4253b7eeff9SArmin Wolf *str = "Memory"; /* sometimes called DIMM */
4263b7eeff9SArmin Wolf break;
4273b7eeff9SArmin Wolf case 0x33:
4283b7eeff9SArmin Wolf *str = "Other";
4293b7eeff9SArmin Wolf break;
4303b7eeff9SArmin Wolf case 0x44:
4313b7eeff9SArmin Wolf *str = "Ambient"; /* sometimes called SKIN */
4323b7eeff9SArmin Wolf break;
4333b7eeff9SArmin Wolf case 0x52:
4343b7eeff9SArmin Wolf *str = "SODIMM";
4353b7eeff9SArmin Wolf break;
4363b7eeff9SArmin Wolf case 0x55:
4373b7eeff9SArmin Wolf *str = "HDD";
4383b7eeff9SArmin Wolf break;
4393b7eeff9SArmin Wolf case 0x62:
4403b7eeff9SArmin Wolf *str = "SODIMM 2";
4413b7eeff9SArmin Wolf break;
4423b7eeff9SArmin Wolf case 0x73:
4433b7eeff9SArmin Wolf *str = "NB";
4443b7eeff9SArmin Wolf break;
4453b7eeff9SArmin Wolf case 0x83:
4463b7eeff9SArmin Wolf *str = "Charger";
4473b7eeff9SArmin Wolf break;
4483b7eeff9SArmin Wolf case 0xbb:
4493b7eeff9SArmin Wolf *str = "Memory 3";
4503b7eeff9SArmin Wolf break;
4513b7eeff9SArmin Wolf default:
4523b7eeff9SArmin Wolf *str = "Unknown";
4533b7eeff9SArmin Wolf break;
4543b7eeff9SArmin Wolf }
4553b7eeff9SArmin Wolf
4563b7eeff9SArmin Wolf return 0;
4573b7eeff9SArmin Wolf }
4583b7eeff9SArmin Wolf
dell_wmi_ddv_read_string(struct device * dev,enum hwmon_sensor_types type,u32 attr,int channel,const char ** str)4593b7eeff9SArmin Wolf static int dell_wmi_ddv_read_string(struct device *dev, enum hwmon_sensor_types type, u32 attr,
4603b7eeff9SArmin Wolf int channel, const char **str)
4613b7eeff9SArmin Wolf {
4623b7eeff9SArmin Wolf struct dell_wmi_ddv_data *data = dev_get_drvdata(dev);
4633b7eeff9SArmin Wolf int ret;
4643b7eeff9SArmin Wolf
4653b7eeff9SArmin Wolf switch (type) {
4663b7eeff9SArmin Wolf case hwmon_fan:
4673b7eeff9SArmin Wolf switch (attr) {
4683b7eeff9SArmin Wolf case hwmon_fan_label:
4693b7eeff9SArmin Wolf mutex_lock(&data->fans.lock);
4703b7eeff9SArmin Wolf ret = dell_wmi_ddv_fan_read_string(data, channel, str);
4713b7eeff9SArmin Wolf mutex_unlock(&data->fans.lock);
4723b7eeff9SArmin Wolf return ret;
4733b7eeff9SArmin Wolf default:
4743b7eeff9SArmin Wolf break;
4753b7eeff9SArmin Wolf }
4763b7eeff9SArmin Wolf break;
4773b7eeff9SArmin Wolf case hwmon_temp:
4783b7eeff9SArmin Wolf switch (attr) {
4793b7eeff9SArmin Wolf case hwmon_temp_label:
4803b7eeff9SArmin Wolf mutex_lock(&data->temps.lock);
4813b7eeff9SArmin Wolf ret = dell_wmi_ddv_temp_read_string(data, channel, str);
4823b7eeff9SArmin Wolf mutex_unlock(&data->temps.lock);
4833b7eeff9SArmin Wolf return ret;
4843b7eeff9SArmin Wolf default:
4853b7eeff9SArmin Wolf break;
4863b7eeff9SArmin Wolf }
4873b7eeff9SArmin Wolf break;
4883b7eeff9SArmin Wolf default:
4893b7eeff9SArmin Wolf break;
4903b7eeff9SArmin Wolf }
4913b7eeff9SArmin Wolf
4923b7eeff9SArmin Wolf return -EOPNOTSUPP;
4933b7eeff9SArmin Wolf }
4943b7eeff9SArmin Wolf
4953b7eeff9SArmin Wolf static const struct hwmon_ops dell_wmi_ddv_ops = {
4963b7eeff9SArmin Wolf .is_visible = dell_wmi_ddv_is_visible,
4973b7eeff9SArmin Wolf .read = dell_wmi_ddv_read,
4983b7eeff9SArmin Wolf .read_string = dell_wmi_ddv_read_string,
4993b7eeff9SArmin Wolf };
5003b7eeff9SArmin Wolf
dell_wmi_ddv_channel_create(struct device * dev,u64 count,enum hwmon_sensor_types type,u32 config)5013b7eeff9SArmin Wolf static struct hwmon_channel_info *dell_wmi_ddv_channel_create(struct device *dev, u64 count,
5023b7eeff9SArmin Wolf enum hwmon_sensor_types type,
5033b7eeff9SArmin Wolf u32 config)
5043b7eeff9SArmin Wolf {
5053b7eeff9SArmin Wolf struct combined_channel_info *cinfo;
5063b7eeff9SArmin Wolf int i;
5073b7eeff9SArmin Wolf
5083b7eeff9SArmin Wolf cinfo = devm_kzalloc(dev, struct_size(cinfo, config, count + 1), GFP_KERNEL);
5093b7eeff9SArmin Wolf if (!cinfo)
5103b7eeff9SArmin Wolf return ERR_PTR(-ENOMEM);
5113b7eeff9SArmin Wolf
5123b7eeff9SArmin Wolf cinfo->info.type = type;
5133b7eeff9SArmin Wolf cinfo->info.config = cinfo->config;
5143b7eeff9SArmin Wolf
5153b7eeff9SArmin Wolf for (i = 0; i < count; i++)
5163b7eeff9SArmin Wolf cinfo->config[i] = config;
5173b7eeff9SArmin Wolf
5183b7eeff9SArmin Wolf return &cinfo->info;
5193b7eeff9SArmin Wolf }
5203b7eeff9SArmin Wolf
dell_wmi_ddv_hwmon_cache_invalidate(struct dell_wmi_ddv_sensors * sensors)5213b7eeff9SArmin Wolf static void dell_wmi_ddv_hwmon_cache_invalidate(struct dell_wmi_ddv_sensors *sensors)
5223b7eeff9SArmin Wolf {
523001f61c4SArmin Wolf if (!sensors->active)
524001f61c4SArmin Wolf return;
525001f61c4SArmin Wolf
5263b7eeff9SArmin Wolf mutex_lock(&sensors->lock);
5273b7eeff9SArmin Wolf kfree(sensors->obj);
5283b7eeff9SArmin Wolf sensors->obj = NULL;
5293b7eeff9SArmin Wolf mutex_unlock(&sensors->lock);
5303b7eeff9SArmin Wolf }
5313b7eeff9SArmin Wolf
dell_wmi_ddv_hwmon_cache_destroy(void * data)5323b7eeff9SArmin Wolf static void dell_wmi_ddv_hwmon_cache_destroy(void *data)
5333b7eeff9SArmin Wolf {
5343b7eeff9SArmin Wolf struct dell_wmi_ddv_sensors *sensors = data;
5353b7eeff9SArmin Wolf
536001f61c4SArmin Wolf sensors->active = false;
5373b7eeff9SArmin Wolf mutex_destroy(&sensors->lock);
5383b7eeff9SArmin Wolf kfree(sensors->obj);
5393b7eeff9SArmin Wolf }
5403b7eeff9SArmin Wolf
dell_wmi_ddv_channel_init(struct wmi_device * wdev,enum dell_ddv_method method,struct dell_wmi_ddv_sensors * sensors,size_t entry_size,enum hwmon_sensor_types type,u32 config)5413b7eeff9SArmin Wolf static struct hwmon_channel_info *dell_wmi_ddv_channel_init(struct wmi_device *wdev,
5423b7eeff9SArmin Wolf enum dell_ddv_method method,
5433b7eeff9SArmin Wolf struct dell_wmi_ddv_sensors *sensors,
5443b7eeff9SArmin Wolf size_t entry_size,
5453b7eeff9SArmin Wolf enum hwmon_sensor_types type,
5463b7eeff9SArmin Wolf u32 config)
5473b7eeff9SArmin Wolf {
5483b7eeff9SArmin Wolf struct hwmon_channel_info *info;
5493b7eeff9SArmin Wolf int ret;
5503b7eeff9SArmin Wolf
5513b7eeff9SArmin Wolf ret = dell_wmi_ddv_update_sensors(wdev, method, sensors, entry_size);
5523b7eeff9SArmin Wolf if (ret < 0)
5533b7eeff9SArmin Wolf return ERR_PTR(ret);
5543b7eeff9SArmin Wolf
5553b7eeff9SArmin Wolf mutex_init(&sensors->lock);
556001f61c4SArmin Wolf sensors->active = true;
5573b7eeff9SArmin Wolf
5583b7eeff9SArmin Wolf ret = devm_add_action_or_reset(&wdev->dev, dell_wmi_ddv_hwmon_cache_destroy, sensors);
5593b7eeff9SArmin Wolf if (ret < 0)
5603b7eeff9SArmin Wolf return ERR_PTR(ret);
5613b7eeff9SArmin Wolf
5623b7eeff9SArmin Wolf info = dell_wmi_ddv_channel_create(&wdev->dev, sensors->entries, type, config);
5633b7eeff9SArmin Wolf if (IS_ERR(info))
5643b7eeff9SArmin Wolf devm_release_action(&wdev->dev, dell_wmi_ddv_hwmon_cache_destroy, sensors);
5653b7eeff9SArmin Wolf
5663b7eeff9SArmin Wolf return info;
5673b7eeff9SArmin Wolf }
5683b7eeff9SArmin Wolf
dell_wmi_ddv_hwmon_add(struct dell_wmi_ddv_data * data)5693b7eeff9SArmin Wolf static int dell_wmi_ddv_hwmon_add(struct dell_wmi_ddv_data *data)
5703b7eeff9SArmin Wolf {
5713b7eeff9SArmin Wolf struct wmi_device *wdev = data->wdev;
5723b7eeff9SArmin Wolf struct combined_chip_info *cinfo;
5733b7eeff9SArmin Wolf struct hwmon_channel_info *info;
5743b7eeff9SArmin Wolf struct device *hdev;
5753b7eeff9SArmin Wolf int index = 0;
5763b7eeff9SArmin Wolf int ret;
5773b7eeff9SArmin Wolf
5783b7eeff9SArmin Wolf if (!devres_open_group(&wdev->dev, dell_wmi_ddv_hwmon_add, GFP_KERNEL))
5793b7eeff9SArmin Wolf return -ENOMEM;
5803b7eeff9SArmin Wolf
5813b7eeff9SArmin Wolf cinfo = devm_kzalloc(&wdev->dev, struct_size(cinfo, info, 4), GFP_KERNEL);
5823b7eeff9SArmin Wolf if (!cinfo) {
5833b7eeff9SArmin Wolf ret = -ENOMEM;
5843b7eeff9SArmin Wolf
5853b7eeff9SArmin Wolf goto err_release;
5863b7eeff9SArmin Wolf }
5873b7eeff9SArmin Wolf
5883b7eeff9SArmin Wolf cinfo->chip.ops = &dell_wmi_ddv_ops;
5893b7eeff9SArmin Wolf cinfo->chip.info = cinfo->info;
5903b7eeff9SArmin Wolf
5913b7eeff9SArmin Wolf info = dell_wmi_ddv_channel_create(&wdev->dev, 1, hwmon_chip, HWMON_C_REGISTER_TZ);
5923b7eeff9SArmin Wolf if (IS_ERR(info)) {
5933b7eeff9SArmin Wolf ret = PTR_ERR(info);
5943b7eeff9SArmin Wolf
5953b7eeff9SArmin Wolf goto err_release;
5963b7eeff9SArmin Wolf }
5973b7eeff9SArmin Wolf
5983b7eeff9SArmin Wolf cinfo->info[index] = info;
5993b7eeff9SArmin Wolf index++;
6003b7eeff9SArmin Wolf
6013b7eeff9SArmin Wolf info = dell_wmi_ddv_channel_init(wdev, DELL_DDV_FAN_SENSOR_INFORMATION, &data->fans,
6023b7eeff9SArmin Wolf sizeof(struct fan_sensor_entry), hwmon_fan,
6033b7eeff9SArmin Wolf (HWMON_F_INPUT | HWMON_F_LABEL));
6043b7eeff9SArmin Wolf if (!IS_ERR(info)) {
6053b7eeff9SArmin Wolf cinfo->info[index] = info;
6063b7eeff9SArmin Wolf index++;
6073b7eeff9SArmin Wolf }
6083b7eeff9SArmin Wolf
6093b7eeff9SArmin Wolf info = dell_wmi_ddv_channel_init(wdev, DELL_DDV_THERMAL_SENSOR_INFORMATION, &data->temps,
6103b7eeff9SArmin Wolf sizeof(struct thermal_sensor_entry), hwmon_temp,
6113b7eeff9SArmin Wolf (HWMON_T_INPUT | HWMON_T_MIN | HWMON_T_MAX |
6123b7eeff9SArmin Wolf HWMON_T_LABEL));
6133b7eeff9SArmin Wolf if (!IS_ERR(info)) {
6143b7eeff9SArmin Wolf cinfo->info[index] = info;
6153b7eeff9SArmin Wolf index++;
6163b7eeff9SArmin Wolf }
6173b7eeff9SArmin Wolf
6183b7eeff9SArmin Wolf if (index < 2) {
619*8c489383SArmin Wolf /* Finding no available sensors is not an error */
620*8c489383SArmin Wolf ret = 0;
6213b7eeff9SArmin Wolf
6223b7eeff9SArmin Wolf goto err_release;
6233b7eeff9SArmin Wolf }
6243b7eeff9SArmin Wolf
6253b7eeff9SArmin Wolf hdev = devm_hwmon_device_register_with_info(&wdev->dev, "dell_ddv", data, &cinfo->chip,
6263b7eeff9SArmin Wolf NULL);
6273b7eeff9SArmin Wolf if (IS_ERR(hdev)) {
6283b7eeff9SArmin Wolf ret = PTR_ERR(hdev);
6293b7eeff9SArmin Wolf
6303b7eeff9SArmin Wolf goto err_release;
6313b7eeff9SArmin Wolf }
6323b7eeff9SArmin Wolf
6333b7eeff9SArmin Wolf devres_close_group(&wdev->dev, dell_wmi_ddv_hwmon_add);
6343b7eeff9SArmin Wolf
6353b7eeff9SArmin Wolf return 0;
6363b7eeff9SArmin Wolf
6373b7eeff9SArmin Wolf err_release:
6383b7eeff9SArmin Wolf devres_release_group(&wdev->dev, dell_wmi_ddv_hwmon_add);
6393b7eeff9SArmin Wolf
6403b7eeff9SArmin Wolf return ret;
6413b7eeff9SArmin Wolf }
6423b7eeff9SArmin Wolf
dell_wmi_ddv_battery_index(struct acpi_device * acpi_dev,u32 * index)643a77272c1SArmin Wolf static int dell_wmi_ddv_battery_index(struct acpi_device *acpi_dev, u32 *index)
644a77272c1SArmin Wolf {
645a77272c1SArmin Wolf const char *uid_str;
646a77272c1SArmin Wolf
647a77272c1SArmin Wolf uid_str = acpi_device_uid(acpi_dev);
648a77272c1SArmin Wolf if (!uid_str)
649a77272c1SArmin Wolf return -ENODEV;
650a77272c1SArmin Wolf
651a77272c1SArmin Wolf return kstrtou32(uid_str, 10, index);
652a77272c1SArmin Wolf }
653a77272c1SArmin Wolf
temp_show(struct device * dev,struct device_attribute * attr,char * buf)654a77272c1SArmin Wolf static ssize_t temp_show(struct device *dev, struct device_attribute *attr, char *buf)
655a77272c1SArmin Wolf {
656a77272c1SArmin Wolf struct dell_wmi_ddv_data *data = container_of(attr, struct dell_wmi_ddv_data, temp_attr);
657a77272c1SArmin Wolf u32 index, value;
658a77272c1SArmin Wolf int ret;
659a77272c1SArmin Wolf
660a77272c1SArmin Wolf ret = dell_wmi_ddv_battery_index(to_acpi_device(dev->parent), &index);
661a77272c1SArmin Wolf if (ret < 0)
662a77272c1SArmin Wolf return ret;
663a77272c1SArmin Wolf
664a77272c1SArmin Wolf ret = dell_wmi_ddv_query_integer(data->wdev, DELL_DDV_BATTERY_TEMPERATURE, index, &value);
665a77272c1SArmin Wolf if (ret < 0)
666a77272c1SArmin Wolf return ret;
667a77272c1SArmin Wolf
6680331b1b0SArmin Wolf /* Use 2731 instead of 2731.5 to avoid unnecessary rounding */
6690331b1b0SArmin Wolf return sysfs_emit(buf, "%d\n", value - 2731);
670a77272c1SArmin Wolf }
671a77272c1SArmin Wolf
eppid_show(struct device * dev,struct device_attribute * attr,char * buf)672a77272c1SArmin Wolf static ssize_t eppid_show(struct device *dev, struct device_attribute *attr, char *buf)
673a77272c1SArmin Wolf {
674a77272c1SArmin Wolf struct dell_wmi_ddv_data *data = container_of(attr, struct dell_wmi_ddv_data, eppid_attr);
675a77272c1SArmin Wolf union acpi_object *obj;
676a77272c1SArmin Wolf u32 index;
677a77272c1SArmin Wolf int ret;
678a77272c1SArmin Wolf
679a77272c1SArmin Wolf ret = dell_wmi_ddv_battery_index(to_acpi_device(dev->parent), &index);
680a77272c1SArmin Wolf if (ret < 0)
681a77272c1SArmin Wolf return ret;
682a77272c1SArmin Wolf
683a77272c1SArmin Wolf ret = dell_wmi_ddv_query_string(data->wdev, DELL_DDV_BATTERY_EPPID, index, &obj);
684a77272c1SArmin Wolf if (ret < 0)
685a77272c1SArmin Wolf return ret;
686a77272c1SArmin Wolf
687c7891884SArmin Wolf if (obj->string.length != DELL_EPPID_LENGTH && obj->string.length != DELL_EPPID_EXT_LENGTH)
688c7891884SArmin Wolf dev_info_once(&data->wdev->dev, FW_INFO "Suspicious ePPID length (%d)\n",
689c7891884SArmin Wolf obj->string.length);
690c7891884SArmin Wolf
691a77272c1SArmin Wolf ret = sysfs_emit(buf, "%s\n", obj->string.pointer);
692a77272c1SArmin Wolf
693a77272c1SArmin Wolf kfree(obj);
694a77272c1SArmin Wolf
695a77272c1SArmin Wolf return ret;
696a77272c1SArmin Wolf }
697a77272c1SArmin Wolf
dell_wmi_ddv_add_battery(struct power_supply * battery,struct acpi_battery_hook * hook)698a77272c1SArmin Wolf static int dell_wmi_ddv_add_battery(struct power_supply *battery, struct acpi_battery_hook *hook)
699a77272c1SArmin Wolf {
700a77272c1SArmin Wolf struct dell_wmi_ddv_data *data = container_of(hook, struct dell_wmi_ddv_data, hook);
701a77272c1SArmin Wolf u32 index;
702a77272c1SArmin Wolf int ret;
703a77272c1SArmin Wolf
704a77272c1SArmin Wolf /* Return 0 instead of error to avoid being unloaded */
705a77272c1SArmin Wolf ret = dell_wmi_ddv_battery_index(to_acpi_device(battery->dev.parent), &index);
706a77272c1SArmin Wolf if (ret < 0)
707a77272c1SArmin Wolf return 0;
708a77272c1SArmin Wolf
709a77272c1SArmin Wolf ret = device_create_file(&battery->dev, &data->temp_attr);
710a77272c1SArmin Wolf if (ret < 0)
711a77272c1SArmin Wolf return ret;
712a77272c1SArmin Wolf
713a77272c1SArmin Wolf ret = device_create_file(&battery->dev, &data->eppid_attr);
714a77272c1SArmin Wolf if (ret < 0) {
715a77272c1SArmin Wolf device_remove_file(&battery->dev, &data->temp_attr);
716a77272c1SArmin Wolf
717a77272c1SArmin Wolf return ret;
718a77272c1SArmin Wolf }
719a77272c1SArmin Wolf
720a77272c1SArmin Wolf return 0;
721a77272c1SArmin Wolf }
722a77272c1SArmin Wolf
dell_wmi_ddv_remove_battery(struct power_supply * battery,struct acpi_battery_hook * hook)723a77272c1SArmin Wolf static int dell_wmi_ddv_remove_battery(struct power_supply *battery, struct acpi_battery_hook *hook)
724a77272c1SArmin Wolf {
725a77272c1SArmin Wolf struct dell_wmi_ddv_data *data = container_of(hook, struct dell_wmi_ddv_data, hook);
726a77272c1SArmin Wolf
727a77272c1SArmin Wolf device_remove_file(&battery->dev, &data->temp_attr);
728a77272c1SArmin Wolf device_remove_file(&battery->dev, &data->eppid_attr);
729a77272c1SArmin Wolf
730a77272c1SArmin Wolf return 0;
731a77272c1SArmin Wolf }
732a77272c1SArmin Wolf
dell_wmi_ddv_battery_remove(void * data)733a77272c1SArmin Wolf static void dell_wmi_ddv_battery_remove(void *data)
734a77272c1SArmin Wolf {
735a77272c1SArmin Wolf struct acpi_battery_hook *hook = data;
736a77272c1SArmin Wolf
737a77272c1SArmin Wolf battery_hook_unregister(hook);
738a77272c1SArmin Wolf }
739a77272c1SArmin Wolf
dell_wmi_ddv_battery_add(struct dell_wmi_ddv_data * data)740a77272c1SArmin Wolf static int dell_wmi_ddv_battery_add(struct dell_wmi_ddv_data *data)
741a77272c1SArmin Wolf {
742a77272c1SArmin Wolf data->hook.name = "Dell DDV Battery Extension";
743a77272c1SArmin Wolf data->hook.add_battery = dell_wmi_ddv_add_battery;
744a77272c1SArmin Wolf data->hook.remove_battery = dell_wmi_ddv_remove_battery;
745a77272c1SArmin Wolf
746a77272c1SArmin Wolf sysfs_attr_init(&data->temp_attr.attr);
747a77272c1SArmin Wolf data->temp_attr.attr.name = "temp";
748a77272c1SArmin Wolf data->temp_attr.attr.mode = 0444;
749a77272c1SArmin Wolf data->temp_attr.show = temp_show;
750a77272c1SArmin Wolf
751a77272c1SArmin Wolf sysfs_attr_init(&data->eppid_attr.attr);
752a77272c1SArmin Wolf data->eppid_attr.attr.name = "eppid";
753a77272c1SArmin Wolf data->eppid_attr.attr.mode = 0444;
754a77272c1SArmin Wolf data->eppid_attr.show = eppid_show;
755a77272c1SArmin Wolf
756a77272c1SArmin Wolf battery_hook_register(&data->hook);
757a77272c1SArmin Wolf
758a77272c1SArmin Wolf return devm_add_action_or_reset(&data->wdev->dev, dell_wmi_ddv_battery_remove, &data->hook);
759a77272c1SArmin Wolf }
760a77272c1SArmin Wolf
dell_wmi_ddv_buffer_read(struct seq_file * seq,enum dell_ddv_method method)761a77272c1SArmin Wolf static int dell_wmi_ddv_buffer_read(struct seq_file *seq, enum dell_ddv_method method)
762a77272c1SArmin Wolf {
763a77272c1SArmin Wolf struct device *dev = seq->private;
764a77272c1SArmin Wolf struct dell_wmi_ddv_data *data = dev_get_drvdata(dev);
765a77272c1SArmin Wolf union acpi_object *obj;
76684fa20c2SArmin Wolf u64 size;
76784fa20c2SArmin Wolf u8 *buf;
768a77272c1SArmin Wolf int ret;
769a77272c1SArmin Wolf
770a77272c1SArmin Wolf ret = dell_wmi_ddv_query_buffer(data->wdev, method, 0, &obj);
771a77272c1SArmin Wolf if (ret < 0)
772a77272c1SArmin Wolf return ret;
773a77272c1SArmin Wolf
77484fa20c2SArmin Wolf size = obj->package.elements[0].integer.value;
77584fa20c2SArmin Wolf buf = obj->package.elements[1].buffer.pointer;
77684fa20c2SArmin Wolf ret = seq_write(seq, buf, size);
777a77272c1SArmin Wolf kfree(obj);
778a77272c1SArmin Wolf
779a77272c1SArmin Wolf return ret;
780a77272c1SArmin Wolf }
781a77272c1SArmin Wolf
dell_wmi_ddv_fan_read(struct seq_file * seq,void * offset)782a77272c1SArmin Wolf static int dell_wmi_ddv_fan_read(struct seq_file *seq, void *offset)
783a77272c1SArmin Wolf {
784a77272c1SArmin Wolf return dell_wmi_ddv_buffer_read(seq, DELL_DDV_FAN_SENSOR_INFORMATION);
785a77272c1SArmin Wolf }
786a77272c1SArmin Wolf
dell_wmi_ddv_temp_read(struct seq_file * seq,void * offset)787a77272c1SArmin Wolf static int dell_wmi_ddv_temp_read(struct seq_file *seq, void *offset)
788a77272c1SArmin Wolf {
789a77272c1SArmin Wolf return dell_wmi_ddv_buffer_read(seq, DELL_DDV_THERMAL_SENSOR_INFORMATION);
790a77272c1SArmin Wolf }
791a77272c1SArmin Wolf
dell_wmi_ddv_debugfs_remove(void * data)792a77272c1SArmin Wolf static void dell_wmi_ddv_debugfs_remove(void *data)
793a77272c1SArmin Wolf {
794a77272c1SArmin Wolf struct dentry *entry = data;
795a77272c1SArmin Wolf
796a77272c1SArmin Wolf debugfs_remove(entry);
797a77272c1SArmin Wolf }
798a77272c1SArmin Wolf
dell_wmi_ddv_debugfs_init(struct wmi_device * wdev)799a77272c1SArmin Wolf static void dell_wmi_ddv_debugfs_init(struct wmi_device *wdev)
800a77272c1SArmin Wolf {
801a77272c1SArmin Wolf struct dentry *entry;
802a77272c1SArmin Wolf char name[64];
803a77272c1SArmin Wolf
804a77272c1SArmin Wolf scnprintf(name, ARRAY_SIZE(name), "%s-%s", DRIVER_NAME, dev_name(&wdev->dev));
805a77272c1SArmin Wolf entry = debugfs_create_dir(name, NULL);
806a77272c1SArmin Wolf
807a77272c1SArmin Wolf debugfs_create_devm_seqfile(&wdev->dev, "fan_sensor_information", entry,
808a77272c1SArmin Wolf dell_wmi_ddv_fan_read);
809a77272c1SArmin Wolf debugfs_create_devm_seqfile(&wdev->dev, "thermal_sensor_information", entry,
810a77272c1SArmin Wolf dell_wmi_ddv_temp_read);
811a77272c1SArmin Wolf
812a77272c1SArmin Wolf devm_add_action_or_reset(&wdev->dev, dell_wmi_ddv_debugfs_remove, entry);
813a77272c1SArmin Wolf }
814a77272c1SArmin Wolf
dell_wmi_ddv_probe(struct wmi_device * wdev,const void * context)815a77272c1SArmin Wolf static int dell_wmi_ddv_probe(struct wmi_device *wdev, const void *context)
816a77272c1SArmin Wolf {
817a77272c1SArmin Wolf struct dell_wmi_ddv_data *data;
818a77272c1SArmin Wolf u32 version;
819a77272c1SArmin Wolf int ret;
820a77272c1SArmin Wolf
821a77272c1SArmin Wolf ret = dell_wmi_ddv_query_integer(wdev, DELL_DDV_INTERFACE_VERSION, 0, &version);
822a77272c1SArmin Wolf if (ret < 0)
823a77272c1SArmin Wolf return ret;
824a77272c1SArmin Wolf
825a77272c1SArmin Wolf dev_dbg(&wdev->dev, "WMI interface version: %d\n", version);
826cf2cc541SArmin Wolf if (version < DELL_DDV_SUPPORTED_VERSION_MIN || version > DELL_DDV_SUPPORTED_VERSION_MAX) {
827cf2cc541SArmin Wolf if (!force)
828a77272c1SArmin Wolf return -ENODEV;
829a77272c1SArmin Wolf
830cf2cc541SArmin Wolf dev_warn(&wdev->dev, "Loading despite unsupported WMI interface version (%u)\n",
831cf2cc541SArmin Wolf version);
832cf2cc541SArmin Wolf }
833cf2cc541SArmin Wolf
834a77272c1SArmin Wolf data = devm_kzalloc(&wdev->dev, sizeof(*data), GFP_KERNEL);
835a77272c1SArmin Wolf if (!data)
836a77272c1SArmin Wolf return -ENOMEM;
837a77272c1SArmin Wolf
838a77272c1SArmin Wolf dev_set_drvdata(&wdev->dev, data);
839a77272c1SArmin Wolf data->wdev = wdev;
840a77272c1SArmin Wolf
841a77272c1SArmin Wolf dell_wmi_ddv_debugfs_init(wdev);
842a77272c1SArmin Wolf
8433b7eeff9SArmin Wolf if (IS_REACHABLE(CONFIG_ACPI_BATTERY)) {
8443b7eeff9SArmin Wolf ret = dell_wmi_ddv_battery_add(data);
845*8c489383SArmin Wolf if (ret < 0)
8463b7eeff9SArmin Wolf dev_warn(&wdev->dev, "Unable to register ACPI battery hook: %d\n", ret);
847a77272c1SArmin Wolf }
848a77272c1SArmin Wolf
8493b7eeff9SArmin Wolf if (IS_REACHABLE(CONFIG_HWMON)) {
8503b7eeff9SArmin Wolf ret = dell_wmi_ddv_hwmon_add(data);
851*8c489383SArmin Wolf if (ret < 0)
8523b7eeff9SArmin Wolf dev_warn(&wdev->dev, "Unable to register hwmon interface: %d\n", ret);
8533b7eeff9SArmin Wolf }
8543b7eeff9SArmin Wolf
8553b7eeff9SArmin Wolf return 0;
8563b7eeff9SArmin Wolf }
8573b7eeff9SArmin Wolf
dell_wmi_ddv_resume(struct device * dev)8583b7eeff9SArmin Wolf static int dell_wmi_ddv_resume(struct device *dev)
8593b7eeff9SArmin Wolf {
8603b7eeff9SArmin Wolf struct dell_wmi_ddv_data *data = dev_get_drvdata(dev);
8613b7eeff9SArmin Wolf
862001f61c4SArmin Wolf /* Force re-reading of all active sensors */
8633b7eeff9SArmin Wolf dell_wmi_ddv_hwmon_cache_invalidate(&data->fans);
8643b7eeff9SArmin Wolf dell_wmi_ddv_hwmon_cache_invalidate(&data->temps);
8653b7eeff9SArmin Wolf
8663b7eeff9SArmin Wolf return 0;
8673b7eeff9SArmin Wolf }
8683b7eeff9SArmin Wolf
8693b7eeff9SArmin Wolf static DEFINE_SIMPLE_DEV_PM_OPS(dell_wmi_ddv_dev_pm_ops, NULL, dell_wmi_ddv_resume);
8703b7eeff9SArmin Wolf
871a77272c1SArmin Wolf static const struct wmi_device_id dell_wmi_ddv_id_table[] = {
872a77272c1SArmin Wolf { DELL_DDV_GUID, NULL },
873a77272c1SArmin Wolf { }
874a77272c1SArmin Wolf };
875a77272c1SArmin Wolf MODULE_DEVICE_TABLE(wmi, dell_wmi_ddv_id_table);
876a77272c1SArmin Wolf
877a77272c1SArmin Wolf static struct wmi_driver dell_wmi_ddv_driver = {
878a77272c1SArmin Wolf .driver = {
879a77272c1SArmin Wolf .name = DRIVER_NAME,
8806113bd52SArmin Wolf .probe_type = PROBE_PREFER_ASYNCHRONOUS,
8813b7eeff9SArmin Wolf .pm = pm_sleep_ptr(&dell_wmi_ddv_dev_pm_ops),
882a77272c1SArmin Wolf },
883a77272c1SArmin Wolf .id_table = dell_wmi_ddv_id_table,
884a77272c1SArmin Wolf .probe = dell_wmi_ddv_probe,
885a77272c1SArmin Wolf };
886a77272c1SArmin Wolf module_wmi_driver(dell_wmi_ddv_driver);
887a77272c1SArmin Wolf
888a77272c1SArmin Wolf MODULE_AUTHOR("Armin Wolf <W_Armin@gmx.de>");
889a77272c1SArmin Wolf MODULE_DESCRIPTION("Dell WMI sensor driver");
890a77272c1SArmin Wolf MODULE_LICENSE("GPL");
891