892 lines · c
1// SPDX-License-Identifier: GPL-2.0-or-later2/*3 * Linux driver for WMI sensor information on Dell notebooks.4 *5 * Copyright (C) 2022 Armin Wolf <W_Armin@gmx.de>6 */7 8#define pr_format(fmt) KBUILD_MODNAME ": " fmt9 10#include <linux/acpi.h>11#include <linux/debugfs.h>12#include <linux/device.h>13#include <linux/device/driver.h>14#include <linux/dev_printk.h>15#include <linux/errno.h>16#include <linux/kconfig.h>17#include <linux/kernel.h>18#include <linux/hwmon.h>19#include <linux/kstrtox.h>20#include <linux/math64.h>21#include <linux/module.h>22#include <linux/mutex.h>23#include <linux/limits.h>24#include <linux/pm.h>25#include <linux/power_supply.h>26#include <linux/printk.h>27#include <linux/seq_file.h>28#include <linux/sysfs.h>29#include <linux/types.h>30#include <linux/wmi.h>31 32#include <acpi/battery.h>33 34#include <linux/unaligned.h>35 36#define DRIVER_NAME "dell-wmi-ddv"37 38#define DELL_DDV_SUPPORTED_VERSION_MIN 239#define DELL_DDV_SUPPORTED_VERSION_MAX 340#define DELL_DDV_GUID "8A42EA14-4F2A-FD45-6422-0087F7A7E608"41 42#define DELL_EPPID_LENGTH 2043#define DELL_EPPID_EXT_LENGTH 2344 45static bool force;46module_param_unsafe(force, bool, 0);47MODULE_PARM_DESC(force, "Force loading without checking for supported WMI interface versions");48 49enum dell_ddv_method {50 DELL_DDV_BATTERY_DESIGN_CAPACITY = 0x01,51 DELL_DDV_BATTERY_FULL_CHARGE_CAPACITY = 0x02,52 DELL_DDV_BATTERY_MANUFACTURE_NAME = 0x03,53 DELL_DDV_BATTERY_MANUFACTURE_DATE = 0x04,54 DELL_DDV_BATTERY_SERIAL_NUMBER = 0x05,55 DELL_DDV_BATTERY_CHEMISTRY_VALUE = 0x06,56 DELL_DDV_BATTERY_TEMPERATURE = 0x07,57 DELL_DDV_BATTERY_CURRENT = 0x08,58 DELL_DDV_BATTERY_VOLTAGE = 0x09,59 DELL_DDV_BATTERY_MANUFACTURER_ACCESS = 0x0A,60 DELL_DDV_BATTERY_RELATIVE_CHARGE_STATE = 0x0B,61 DELL_DDV_BATTERY_CYCLE_COUNT = 0x0C,62 DELL_DDV_BATTERY_EPPID = 0x0D,63 DELL_DDV_BATTERY_RAW_ANALYTICS_START = 0x0E,64 DELL_DDV_BATTERY_RAW_ANALYTICS = 0x0F,65 DELL_DDV_BATTERY_DESIGN_VOLTAGE = 0x10,66 DELL_DDV_BATTERY_RAW_ANALYTICS_A_BLOCK = 0x11, /* version 3 */67 68 DELL_DDV_INTERFACE_VERSION = 0x12,69 70 DELL_DDV_FAN_SENSOR_INFORMATION = 0x20,71 DELL_DDV_THERMAL_SENSOR_INFORMATION = 0x22,72};73 74struct fan_sensor_entry {75 u8 type;76 __le16 rpm;77} __packed;78 79struct thermal_sensor_entry {80 u8 type;81 s8 now;82 s8 min;83 s8 max;84 u8 unknown;85} __packed;86 87struct combined_channel_info {88 struct hwmon_channel_info info;89 u32 config[];90};91 92struct combined_chip_info {93 struct hwmon_chip_info chip;94 const struct hwmon_channel_info *info[];95};96 97struct dell_wmi_ddv_sensors {98 bool active;99 struct mutex lock; /* protect caching */100 unsigned long timestamp;101 union acpi_object *obj;102 u64 entries;103};104 105struct dell_wmi_ddv_data {106 struct acpi_battery_hook hook;107 struct device_attribute temp_attr;108 struct device_attribute eppid_attr;109 struct dell_wmi_ddv_sensors fans;110 struct dell_wmi_ddv_sensors temps;111 struct wmi_device *wdev;112};113 114static const char * const fan_labels[] = {115 "CPU Fan",116 "Chassis Motherboard Fan",117 "Video Fan",118 "Power Supply Fan",119 "Chipset Fan",120 "Memory Fan",121 "PCI Fan",122 "HDD Fan",123};124 125static const char * const fan_dock_labels[] = {126 "Docking Chassis/Motherboard Fan",127 "Docking Video Fan",128 "Docking Power Supply Fan",129 "Docking Chipset Fan",130};131 132static int dell_wmi_ddv_query_type(struct wmi_device *wdev, enum dell_ddv_method method, u32 arg,133 union acpi_object **result, acpi_object_type type)134{135 struct acpi_buffer out = { ACPI_ALLOCATE_BUFFER, NULL };136 const struct acpi_buffer in = {137 .length = sizeof(arg),138 .pointer = &arg,139 };140 union acpi_object *obj;141 acpi_status ret;142 143 ret = wmidev_evaluate_method(wdev, 0x0, method, &in, &out);144 if (ACPI_FAILURE(ret))145 return -EIO;146 147 obj = out.pointer;148 if (!obj)149 return -ENODATA;150 151 if (obj->type != type) {152 kfree(obj);153 return -ENOMSG;154 }155 156 *result = obj;157 158 return 0;159}160 161static int dell_wmi_ddv_query_integer(struct wmi_device *wdev, enum dell_ddv_method method,162 u32 arg, u32 *res)163{164 union acpi_object *obj;165 int ret;166 167 ret = dell_wmi_ddv_query_type(wdev, method, arg, &obj, ACPI_TYPE_INTEGER);168 if (ret < 0)169 return ret;170 171 if (obj->integer.value <= U32_MAX)172 *res = (u32)obj->integer.value;173 else174 ret = -ERANGE;175 176 kfree(obj);177 178 return ret;179}180 181static int dell_wmi_ddv_query_buffer(struct wmi_device *wdev, enum dell_ddv_method method,182 u32 arg, union acpi_object **result)183{184 union acpi_object *obj;185 u64 buffer_size;186 int ret;187 188 ret = dell_wmi_ddv_query_type(wdev, method, arg, &obj, ACPI_TYPE_PACKAGE);189 if (ret < 0)190 return ret;191 192 if (obj->package.count != 2 ||193 obj->package.elements[0].type != ACPI_TYPE_INTEGER ||194 obj->package.elements[1].type != ACPI_TYPE_BUFFER) {195 ret = -ENOMSG;196 197 goto err_free;198 }199 200 buffer_size = obj->package.elements[0].integer.value;201 202 if (!buffer_size) {203 ret = -ENODATA;204 205 goto err_free;206 }207 208 if (buffer_size > obj->package.elements[1].buffer.length) {209 dev_warn(&wdev->dev,210 FW_WARN "WMI buffer size (%llu) exceeds ACPI buffer size (%d)\n",211 buffer_size, obj->package.elements[1].buffer.length);212 ret = -EMSGSIZE;213 214 goto err_free;215 }216 217 *result = obj;218 219 return 0;220 221err_free:222 kfree(obj);223 224 return ret;225}226 227static int dell_wmi_ddv_query_string(struct wmi_device *wdev, enum dell_ddv_method method,228 u32 arg, union acpi_object **result)229{230 return dell_wmi_ddv_query_type(wdev, method, arg, result, ACPI_TYPE_STRING);231}232 233/*234 * Needs to be called with lock held, except during initialization.235 */236static int dell_wmi_ddv_update_sensors(struct wmi_device *wdev, enum dell_ddv_method method,237 struct dell_wmi_ddv_sensors *sensors, size_t entry_size)238{239 u64 buffer_size, rem, entries;240 union acpi_object *obj;241 u8 *buffer;242 int ret;243 244 if (sensors->obj) {245 if (time_before(jiffies, sensors->timestamp + HZ))246 return 0;247 248 kfree(sensors->obj);249 sensors->obj = NULL;250 }251 252 ret = dell_wmi_ddv_query_buffer(wdev, method, 0, &obj);253 if (ret < 0)254 return ret;255 256 /* buffer format sanity check */257 buffer_size = obj->package.elements[0].integer.value;258 buffer = obj->package.elements[1].buffer.pointer;259 entries = div64_u64_rem(buffer_size, entry_size, &rem);260 if (rem != 1 || buffer[buffer_size - 1] != 0xff) {261 ret = -ENOMSG;262 goto err_free;263 }264 265 if (!entries) {266 ret = -ENODATA;267 goto err_free;268 }269 270 sensors->obj = obj;271 sensors->entries = entries;272 sensors->timestamp = jiffies;273 274 return 0;275 276err_free:277 kfree(obj);278 279 return ret;280}281 282static umode_t dell_wmi_ddv_is_visible(const void *drvdata, enum hwmon_sensor_types type, u32 attr,283 int channel)284{285 return 0444;286}287 288static int dell_wmi_ddv_fan_read_channel(struct dell_wmi_ddv_data *data, u32 attr, int channel,289 long *val)290{291 struct fan_sensor_entry *entry;292 int ret;293 294 ret = dell_wmi_ddv_update_sensors(data->wdev, DELL_DDV_FAN_SENSOR_INFORMATION,295 &data->fans, sizeof(*entry));296 if (ret < 0)297 return ret;298 299 if (channel >= data->fans.entries)300 return -ENXIO;301 302 entry = (struct fan_sensor_entry *)data->fans.obj->package.elements[1].buffer.pointer;303 switch (attr) {304 case hwmon_fan_input:305 *val = get_unaligned_le16(&entry[channel].rpm);306 return 0;307 default:308 break;309 }310 311 return -EOPNOTSUPP;312}313 314static int dell_wmi_ddv_temp_read_channel(struct dell_wmi_ddv_data *data, u32 attr, int channel,315 long *val)316{317 struct thermal_sensor_entry *entry;318 int ret;319 320 ret = dell_wmi_ddv_update_sensors(data->wdev, DELL_DDV_THERMAL_SENSOR_INFORMATION,321 &data->temps, sizeof(*entry));322 if (ret < 0)323 return ret;324 325 if (channel >= data->temps.entries)326 return -ENXIO;327 328 entry = (struct thermal_sensor_entry *)data->temps.obj->package.elements[1].buffer.pointer;329 switch (attr) {330 case hwmon_temp_input:331 *val = entry[channel].now * 1000;332 return 0;333 case hwmon_temp_min:334 *val = entry[channel].min * 1000;335 return 0;336 case hwmon_temp_max:337 *val = entry[channel].max * 1000;338 return 0;339 default:340 break;341 }342 343 return -EOPNOTSUPP;344}345 346static int dell_wmi_ddv_read(struct device *dev, enum hwmon_sensor_types type, u32 attr,347 int channel, long *val)348{349 struct dell_wmi_ddv_data *data = dev_get_drvdata(dev);350 int ret;351 352 switch (type) {353 case hwmon_fan:354 mutex_lock(&data->fans.lock);355 ret = dell_wmi_ddv_fan_read_channel(data, attr, channel, val);356 mutex_unlock(&data->fans.lock);357 return ret;358 case hwmon_temp:359 mutex_lock(&data->temps.lock);360 ret = dell_wmi_ddv_temp_read_channel(data, attr, channel, val);361 mutex_unlock(&data->temps.lock);362 return ret;363 default:364 break;365 }366 367 return -EOPNOTSUPP;368}369 370static int dell_wmi_ddv_fan_read_string(struct dell_wmi_ddv_data *data, int channel,371 const char **str)372{373 struct fan_sensor_entry *entry;374 int ret;375 u8 type;376 377 ret = dell_wmi_ddv_update_sensors(data->wdev, DELL_DDV_FAN_SENSOR_INFORMATION,378 &data->fans, sizeof(*entry));379 if (ret < 0)380 return ret;381 382 if (channel >= data->fans.entries)383 return -ENXIO;384 385 entry = (struct fan_sensor_entry *)data->fans.obj->package.elements[1].buffer.pointer;386 type = entry[channel].type;387 switch (type) {388 case 0x00 ... 0x07:389 *str = fan_labels[type];390 break;391 case 0x11 ... 0x14:392 *str = fan_dock_labels[type - 0x11];393 break;394 default:395 *str = "Unknown Fan";396 break;397 }398 399 return 0;400}401 402static int dell_wmi_ddv_temp_read_string(struct dell_wmi_ddv_data *data, int channel,403 const char **str)404{405 struct thermal_sensor_entry *entry;406 int ret;407 408 ret = dell_wmi_ddv_update_sensors(data->wdev, DELL_DDV_THERMAL_SENSOR_INFORMATION,409 &data->temps, sizeof(*entry));410 if (ret < 0)411 return ret;412 413 if (channel >= data->temps.entries)414 return -ENXIO;415 416 entry = (struct thermal_sensor_entry *)data->temps.obj->package.elements[1].buffer.pointer;417 switch (entry[channel].type) {418 case 0x00:419 *str = "CPU";420 break;421 case 0x11:422 *str = "Video";423 break;424 case 0x22:425 *str = "Memory"; /* sometimes called DIMM */426 break;427 case 0x33:428 *str = "Other";429 break;430 case 0x44:431 *str = "Ambient"; /* sometimes called SKIN */432 break;433 case 0x52:434 *str = "SODIMM";435 break;436 case 0x55:437 *str = "HDD";438 break;439 case 0x62:440 *str = "SODIMM 2";441 break;442 case 0x73:443 *str = "NB";444 break;445 case 0x83:446 *str = "Charger";447 break;448 case 0xbb:449 *str = "Memory 3";450 break;451 default:452 *str = "Unknown";453 break;454 }455 456 return 0;457}458 459static int dell_wmi_ddv_read_string(struct device *dev, enum hwmon_sensor_types type, u32 attr,460 int channel, const char **str)461{462 struct dell_wmi_ddv_data *data = dev_get_drvdata(dev);463 int ret;464 465 switch (type) {466 case hwmon_fan:467 switch (attr) {468 case hwmon_fan_label:469 mutex_lock(&data->fans.lock);470 ret = dell_wmi_ddv_fan_read_string(data, channel, str);471 mutex_unlock(&data->fans.lock);472 return ret;473 default:474 break;475 }476 break;477 case hwmon_temp:478 switch (attr) {479 case hwmon_temp_label:480 mutex_lock(&data->temps.lock);481 ret = dell_wmi_ddv_temp_read_string(data, channel, str);482 mutex_unlock(&data->temps.lock);483 return ret;484 default:485 break;486 }487 break;488 default:489 break;490 }491 492 return -EOPNOTSUPP;493}494 495static const struct hwmon_ops dell_wmi_ddv_ops = {496 .is_visible = dell_wmi_ddv_is_visible,497 .read = dell_wmi_ddv_read,498 .read_string = dell_wmi_ddv_read_string,499};500 501static struct hwmon_channel_info *dell_wmi_ddv_channel_create(struct device *dev, u64 count,502 enum hwmon_sensor_types type,503 u32 config)504{505 struct combined_channel_info *cinfo;506 int i;507 508 cinfo = devm_kzalloc(dev, struct_size(cinfo, config, count + 1), GFP_KERNEL);509 if (!cinfo)510 return ERR_PTR(-ENOMEM);511 512 cinfo->info.type = type;513 cinfo->info.config = cinfo->config;514 515 for (i = 0; i < count; i++)516 cinfo->config[i] = config;517 518 return &cinfo->info;519}520 521static void dell_wmi_ddv_hwmon_cache_invalidate(struct dell_wmi_ddv_sensors *sensors)522{523 if (!sensors->active)524 return;525 526 mutex_lock(&sensors->lock);527 kfree(sensors->obj);528 sensors->obj = NULL;529 mutex_unlock(&sensors->lock);530}531 532static void dell_wmi_ddv_hwmon_cache_destroy(void *data)533{534 struct dell_wmi_ddv_sensors *sensors = data;535 536 sensors->active = false;537 mutex_destroy(&sensors->lock);538 kfree(sensors->obj);539}540 541static struct hwmon_channel_info *dell_wmi_ddv_channel_init(struct wmi_device *wdev,542 enum dell_ddv_method method,543 struct dell_wmi_ddv_sensors *sensors,544 size_t entry_size,545 enum hwmon_sensor_types type,546 u32 config)547{548 struct hwmon_channel_info *info;549 int ret;550 551 ret = dell_wmi_ddv_update_sensors(wdev, method, sensors, entry_size);552 if (ret < 0)553 return ERR_PTR(ret);554 555 mutex_init(&sensors->lock);556 sensors->active = true;557 558 ret = devm_add_action_or_reset(&wdev->dev, dell_wmi_ddv_hwmon_cache_destroy, sensors);559 if (ret < 0)560 return ERR_PTR(ret);561 562 info = dell_wmi_ddv_channel_create(&wdev->dev, sensors->entries, type, config);563 if (IS_ERR(info))564 devm_release_action(&wdev->dev, dell_wmi_ddv_hwmon_cache_destroy, sensors);565 566 return info;567}568 569static int dell_wmi_ddv_hwmon_add(struct dell_wmi_ddv_data *data)570{571 struct wmi_device *wdev = data->wdev;572 struct combined_chip_info *cinfo;573 struct hwmon_channel_info *info;574 struct device *hdev;575 int index = 0;576 int ret;577 578 if (!devres_open_group(&wdev->dev, dell_wmi_ddv_hwmon_add, GFP_KERNEL))579 return -ENOMEM;580 581 cinfo = devm_kzalloc(&wdev->dev, struct_size(cinfo, info, 4), GFP_KERNEL);582 if (!cinfo) {583 ret = -ENOMEM;584 585 goto err_release;586 }587 588 cinfo->chip.ops = &dell_wmi_ddv_ops;589 cinfo->chip.info = cinfo->info;590 591 info = dell_wmi_ddv_channel_create(&wdev->dev, 1, hwmon_chip, HWMON_C_REGISTER_TZ);592 if (IS_ERR(info)) {593 ret = PTR_ERR(info);594 595 goto err_release;596 }597 598 cinfo->info[index] = info;599 index++;600 601 info = dell_wmi_ddv_channel_init(wdev, DELL_DDV_FAN_SENSOR_INFORMATION, &data->fans,602 sizeof(struct fan_sensor_entry), hwmon_fan,603 (HWMON_F_INPUT | HWMON_F_LABEL));604 if (!IS_ERR(info)) {605 cinfo->info[index] = info;606 index++;607 }608 609 info = dell_wmi_ddv_channel_init(wdev, DELL_DDV_THERMAL_SENSOR_INFORMATION, &data->temps,610 sizeof(struct thermal_sensor_entry), hwmon_temp,611 (HWMON_T_INPUT | HWMON_T_MIN | HWMON_T_MAX |612 HWMON_T_LABEL));613 if (!IS_ERR(info)) {614 cinfo->info[index] = info;615 index++;616 }617 618 if (index < 2) {619 /* Finding no available sensors is not an error */620 ret = 0;621 622 goto err_release;623 }624 625 hdev = devm_hwmon_device_register_with_info(&wdev->dev, "dell_ddv", data, &cinfo->chip,626 NULL);627 if (IS_ERR(hdev)) {628 ret = PTR_ERR(hdev);629 630 goto err_release;631 }632 633 devres_close_group(&wdev->dev, dell_wmi_ddv_hwmon_add);634 635 return 0;636 637err_release:638 devres_release_group(&wdev->dev, dell_wmi_ddv_hwmon_add);639 640 return ret;641}642 643static int dell_wmi_ddv_battery_index(struct acpi_device *acpi_dev, u32 *index)644{645 const char *uid_str;646 647 uid_str = acpi_device_uid(acpi_dev);648 if (!uid_str)649 return -ENODEV;650 651 return kstrtou32(uid_str, 10, index);652}653 654static ssize_t temp_show(struct device *dev, struct device_attribute *attr, char *buf)655{656 struct dell_wmi_ddv_data *data = container_of(attr, struct dell_wmi_ddv_data, temp_attr);657 u32 index, value;658 int ret;659 660 ret = dell_wmi_ddv_battery_index(to_acpi_device(dev->parent), &index);661 if (ret < 0)662 return ret;663 664 ret = dell_wmi_ddv_query_integer(data->wdev, DELL_DDV_BATTERY_TEMPERATURE, index, &value);665 if (ret < 0)666 return ret;667 668 /* Use 2731 instead of 2731.5 to avoid unnecessary rounding */669 return sysfs_emit(buf, "%d\n", value - 2731);670}671 672static ssize_t eppid_show(struct device *dev, struct device_attribute *attr, char *buf)673{674 struct dell_wmi_ddv_data *data = container_of(attr, struct dell_wmi_ddv_data, eppid_attr);675 union acpi_object *obj;676 u32 index;677 int ret;678 679 ret = dell_wmi_ddv_battery_index(to_acpi_device(dev->parent), &index);680 if (ret < 0)681 return ret;682 683 ret = dell_wmi_ddv_query_string(data->wdev, DELL_DDV_BATTERY_EPPID, index, &obj);684 if (ret < 0)685 return ret;686 687 if (obj->string.length != DELL_EPPID_LENGTH && obj->string.length != DELL_EPPID_EXT_LENGTH)688 dev_info_once(&data->wdev->dev, FW_INFO "Suspicious ePPID length (%d)\n",689 obj->string.length);690 691 ret = sysfs_emit(buf, "%s\n", obj->string.pointer);692 693 kfree(obj);694 695 return ret;696}697 698static int dell_wmi_ddv_add_battery(struct power_supply *battery, struct acpi_battery_hook *hook)699{700 struct dell_wmi_ddv_data *data = container_of(hook, struct dell_wmi_ddv_data, hook);701 u32 index;702 int ret;703 704 /* Return 0 instead of error to avoid being unloaded */705 ret = dell_wmi_ddv_battery_index(to_acpi_device(battery->dev.parent), &index);706 if (ret < 0)707 return 0;708 709 ret = device_create_file(&battery->dev, &data->temp_attr);710 if (ret < 0)711 return ret;712 713 ret = device_create_file(&battery->dev, &data->eppid_attr);714 if (ret < 0) {715 device_remove_file(&battery->dev, &data->temp_attr);716 717 return ret;718 }719 720 return 0;721}722 723static int dell_wmi_ddv_remove_battery(struct power_supply *battery, struct acpi_battery_hook *hook)724{725 struct dell_wmi_ddv_data *data = container_of(hook, struct dell_wmi_ddv_data, hook);726 727 device_remove_file(&battery->dev, &data->temp_attr);728 device_remove_file(&battery->dev, &data->eppid_attr);729 730 return 0;731}732 733static void dell_wmi_ddv_battery_remove(void *data)734{735 struct acpi_battery_hook *hook = data;736 737 battery_hook_unregister(hook);738}739 740static int dell_wmi_ddv_battery_add(struct dell_wmi_ddv_data *data)741{742 data->hook.name = "Dell DDV Battery Extension";743 data->hook.add_battery = dell_wmi_ddv_add_battery;744 data->hook.remove_battery = dell_wmi_ddv_remove_battery;745 746 sysfs_attr_init(&data->temp_attr.attr);747 data->temp_attr.attr.name = "temp";748 data->temp_attr.attr.mode = 0444;749 data->temp_attr.show = temp_show;750 751 sysfs_attr_init(&data->eppid_attr.attr);752 data->eppid_attr.attr.name = "eppid";753 data->eppid_attr.attr.mode = 0444;754 data->eppid_attr.show = eppid_show;755 756 battery_hook_register(&data->hook);757 758 return devm_add_action_or_reset(&data->wdev->dev, dell_wmi_ddv_battery_remove, &data->hook);759}760 761static int dell_wmi_ddv_buffer_read(struct seq_file *seq, enum dell_ddv_method method)762{763 struct device *dev = seq->private;764 struct dell_wmi_ddv_data *data = dev_get_drvdata(dev);765 union acpi_object *obj;766 u64 size;767 u8 *buf;768 int ret;769 770 ret = dell_wmi_ddv_query_buffer(data->wdev, method, 0, &obj);771 if (ret < 0)772 return ret;773 774 size = obj->package.elements[0].integer.value;775 buf = obj->package.elements[1].buffer.pointer;776 ret = seq_write(seq, buf, size);777 kfree(obj);778 779 return ret;780}781 782static int dell_wmi_ddv_fan_read(struct seq_file *seq, void *offset)783{784 return dell_wmi_ddv_buffer_read(seq, DELL_DDV_FAN_SENSOR_INFORMATION);785}786 787static int dell_wmi_ddv_temp_read(struct seq_file *seq, void *offset)788{789 return dell_wmi_ddv_buffer_read(seq, DELL_DDV_THERMAL_SENSOR_INFORMATION);790}791 792static void dell_wmi_ddv_debugfs_remove(void *data)793{794 struct dentry *entry = data;795 796 debugfs_remove(entry);797}798 799static void dell_wmi_ddv_debugfs_init(struct wmi_device *wdev)800{801 struct dentry *entry;802 char name[64];803 804 scnprintf(name, ARRAY_SIZE(name), "%s-%s", DRIVER_NAME, dev_name(&wdev->dev));805 entry = debugfs_create_dir(name, NULL);806 807 debugfs_create_devm_seqfile(&wdev->dev, "fan_sensor_information", entry,808 dell_wmi_ddv_fan_read);809 debugfs_create_devm_seqfile(&wdev->dev, "thermal_sensor_information", entry,810 dell_wmi_ddv_temp_read);811 812 devm_add_action_or_reset(&wdev->dev, dell_wmi_ddv_debugfs_remove, entry);813}814 815static int dell_wmi_ddv_probe(struct wmi_device *wdev, const void *context)816{817 struct dell_wmi_ddv_data *data;818 u32 version;819 int ret;820 821 ret = dell_wmi_ddv_query_integer(wdev, DELL_DDV_INTERFACE_VERSION, 0, &version);822 if (ret < 0)823 return ret;824 825 dev_dbg(&wdev->dev, "WMI interface version: %d\n", version);826 if (version < DELL_DDV_SUPPORTED_VERSION_MIN || version > DELL_DDV_SUPPORTED_VERSION_MAX) {827 if (!force)828 return -ENODEV;829 830 dev_warn(&wdev->dev, "Loading despite unsupported WMI interface version (%u)\n",831 version);832 }833 834 data = devm_kzalloc(&wdev->dev, sizeof(*data), GFP_KERNEL);835 if (!data)836 return -ENOMEM;837 838 dev_set_drvdata(&wdev->dev, data);839 data->wdev = wdev;840 841 dell_wmi_ddv_debugfs_init(wdev);842 843 if (IS_REACHABLE(CONFIG_ACPI_BATTERY)) {844 ret = dell_wmi_ddv_battery_add(data);845 if (ret < 0)846 dev_warn(&wdev->dev, "Unable to register ACPI battery hook: %d\n", ret);847 }848 849 if (IS_REACHABLE(CONFIG_HWMON)) {850 ret = dell_wmi_ddv_hwmon_add(data);851 if (ret < 0)852 dev_warn(&wdev->dev, "Unable to register hwmon interface: %d\n", ret);853 }854 855 return 0;856}857 858static int dell_wmi_ddv_resume(struct device *dev)859{860 struct dell_wmi_ddv_data *data = dev_get_drvdata(dev);861 862 /* Force re-reading of all active sensors */863 dell_wmi_ddv_hwmon_cache_invalidate(&data->fans);864 dell_wmi_ddv_hwmon_cache_invalidate(&data->temps);865 866 return 0;867}868 869static DEFINE_SIMPLE_DEV_PM_OPS(dell_wmi_ddv_dev_pm_ops, NULL, dell_wmi_ddv_resume);870 871static const struct wmi_device_id dell_wmi_ddv_id_table[] = {872 { DELL_DDV_GUID, NULL },873 { }874};875MODULE_DEVICE_TABLE(wmi, dell_wmi_ddv_id_table);876 877static struct wmi_driver dell_wmi_ddv_driver = {878 .driver = {879 .name = DRIVER_NAME,880 .probe_type = PROBE_PREFER_ASYNCHRONOUS,881 .pm = pm_sleep_ptr(&dell_wmi_ddv_dev_pm_ops),882 },883 .id_table = dell_wmi_ddv_id_table,884 .probe = dell_wmi_ddv_probe,885 .no_singleton = true,886};887module_wmi_driver(dell_wmi_ddv_driver);888 889MODULE_AUTHOR("Armin Wolf <W_Armin@gmx.de>");890MODULE_DESCRIPTION("Dell WMI sensor driver");891MODULE_LICENSE("GPL");892