platform/x86: Add driver to force WMI Thunderbolt controller power status
Current implementations of Intel Thunderbolt controllers will go into a low power mode when not in use. Many machines containing these controllers also have a GPIO wired up that can force the controller awake. This is offered via a ACPI-WMI interface intended to be manipulated by a userspace utility. This mechanism is provided by Intel to OEMs to include in BIOS. It uses an industry wide GUID that is populated in a separate _WDG entry with no binary MOF. This interface allows software such as fwupd to wake up thunderbolt controllers to query the firmware version or flash new firmware. Signed-off-by: Mario Limonciello <mario.limonciello@dell.com> Reviewed-by: Mika Westerberg <mika.westerberg@linux.intel.com> Reviewed-by: Yehezkel Bernat <yehezkel.bernat@intel.com> Signed-off-by: Darren Hart (VMware) <dvhart@infradead.org> [andy fixed merge conflicts and bump kernel version for ABI] Signed-off-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
This commit is contained in:

committed by
Andy Shevchenko

parent
2bd6bf03f4
commit
ce6a90027c
101
drivers/platform/x86/intel-wmi-thunderbolt.c
Normal file
101
drivers/platform/x86/intel-wmi-thunderbolt.c
Normal file
@@ -0,0 +1,101 @@
|
||||
/*
|
||||
* WMI Thunderbolt driver
|
||||
*
|
||||
* Copyright (C) 2017 Dell Inc. All Rights Reserved.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 as published
|
||||
* by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
|
||||
|
||||
#include <linux/acpi.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/fs.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/string.h>
|
||||
#include <linux/sysfs.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/wmi.h>
|
||||
|
||||
#define INTEL_WMI_THUNDERBOLT_GUID "86CCFD48-205E-4A77-9C48-2021CBEDE341"
|
||||
|
||||
static ssize_t force_power_store(struct device *dev,
|
||||
struct device_attribute *attr,
|
||||
const char *buf, size_t count)
|
||||
{
|
||||
struct acpi_buffer input;
|
||||
acpi_status status;
|
||||
u8 mode;
|
||||
|
||||
input.length = sizeof(u8);
|
||||
input.pointer = &mode;
|
||||
mode = hex_to_bin(buf[0]);
|
||||
if (mode == 0 || mode == 1) {
|
||||
status = wmi_evaluate_method(INTEL_WMI_THUNDERBOLT_GUID, 0, 1,
|
||||
&input, NULL);
|
||||
if (ACPI_FAILURE(status)) {
|
||||
pr_err("intel-wmi-thunderbolt: failed setting %s\n",
|
||||
buf);
|
||||
return -ENODEV;
|
||||
}
|
||||
} else {
|
||||
pr_err("intel-wmi-thunderbolt: unsupported mode: %d", mode);
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
static DEVICE_ATTR_WO(force_power);
|
||||
|
||||
static struct attribute *tbt_attrs[] = {
|
||||
&dev_attr_force_power.attr,
|
||||
NULL
|
||||
};
|
||||
|
||||
static const struct attribute_group tbt_attribute_group = {
|
||||
.attrs = tbt_attrs,
|
||||
};
|
||||
|
||||
static int intel_wmi_thunderbolt_probe(struct wmi_device *wdev)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = sysfs_create_group(&wdev->dev.kobj, &tbt_attribute_group);
|
||||
kobject_uevent(&wdev->dev.kobj, KOBJ_CHANGE);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int intel_wmi_thunderbolt_remove(struct wmi_device *wdev)
|
||||
{
|
||||
sysfs_remove_group(&wdev->dev.kobj, &tbt_attribute_group);
|
||||
kobject_uevent(&wdev->dev.kobj, KOBJ_CHANGE);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct wmi_device_id intel_wmi_thunderbolt_id_table[] = {
|
||||
{ .guid_string = INTEL_WMI_THUNDERBOLT_GUID },
|
||||
{ },
|
||||
};
|
||||
|
||||
static struct wmi_driver intel_wmi_thunderbolt_driver = {
|
||||
.driver = {
|
||||
.name = "intel-wmi-thunderbolt",
|
||||
},
|
||||
.probe = intel_wmi_thunderbolt_probe,
|
||||
.remove = intel_wmi_thunderbolt_remove,
|
||||
.id_table = intel_wmi_thunderbolt_id_table,
|
||||
};
|
||||
|
||||
module_wmi_driver(intel_wmi_thunderbolt_driver);
|
||||
|
||||
MODULE_ALIAS("wmi:" INTEL_WMI_THUNDERBOLT_GUID);
|
||||
MODULE_AUTHOR("Mario Limonciello <mario.limonciello@dell.com>");
|
||||
MODULE_DESCRIPTION("Intel WMI Thunderbolt force power driver");
|
||||
MODULE_LICENSE("GPL");
|
Reference in New Issue
Block a user