brintos

brintos / linux-shallow public Read only

0
0
Text · 20.6 KiB · e75cd6e Raw
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