|
@@ -1,20 +1,20 @@
|
|
|
-From 06454d6870b688c2981c4121d70db69fdf9845c7 Mon Sep 17 00:00:00 2001
|
|
|
+From fdd0f9532af763dbdbab7c6749f2e9d39af11db0 Mon Sep 17 00:00:00 2001
|
|
|
From: qzed <qzed@users.noreply.github.com>
|
|
|
-Date: Thu, 4 Apr 2019 22:47:12 +0200
|
|
|
+Date: Sun, 21 Apr 2019 14:59:22 +0200
|
|
|
Subject: [PATCH 01/11] surface-acpi
|
|
|
|
|
|
---
|
|
|
drivers/acpi/acpica/dsopcode.c | 2 +-
|
|
|
drivers/acpi/acpica/exfield.c | 26 +-
|
|
|
- drivers/platform/x86/Kconfig | 84 +
|
|
|
+ drivers/platform/x86/Kconfig | 97 +
|
|
|
drivers/platform/x86/Makefile | 1 +
|
|
|
- drivers/platform/x86/surface_acpi.c | 3536 +++++++++++++++++++++++++++
|
|
|
+ drivers/platform/x86/surface_acpi.c | 3828 +++++++++++++++++++++++++++
|
|
|
drivers/tty/serdev/core.c | 90 +-
|
|
|
- 6 files changed, 3720 insertions(+), 19 deletions(-)
|
|
|
+ 6 files changed, 4025 insertions(+), 19 deletions(-)
|
|
|
create mode 100644 drivers/platform/x86/surface_acpi.c
|
|
|
|
|
|
diff --git a/drivers/acpi/acpica/dsopcode.c b/drivers/acpi/acpica/dsopcode.c
|
|
|
-index 78f9de260d5f..0cd858520f5b 100644
|
|
|
+index 2f4641e5ecde..beb22d7e245e 100644
|
|
|
--- a/drivers/acpi/acpica/dsopcode.c
|
|
|
+++ b/drivers/acpi/acpica/dsopcode.c
|
|
|
@@ -123,7 +123,7 @@ acpi_ds_init_buffer_field(u16 aml_opcode,
|
|
@@ -80,10 +80,10 @@ index b272c329d45d..cf547883a993 100644
|
|
|
} else { /* IPMI */
|
|
|
|
|
|
diff --git a/drivers/platform/x86/Kconfig b/drivers/platform/x86/Kconfig
|
|
|
-index 7563c07e14e4..4c4b138170c4 100644
|
|
|
+index 1e2524de6a63..9a47363a0c30 100644
|
|
|
--- a/drivers/platform/x86/Kconfig
|
|
|
+++ b/drivers/platform/x86/Kconfig
|
|
|
-@@ -573,6 +573,90 @@ config THINKPAD_ACPI_HOTKEY_POLL
|
|
|
+@@ -573,6 +573,103 @@ config THINKPAD_ACPI_HOTKEY_POLL
|
|
|
If you are not sure, say Y here. The driver enables polling only if
|
|
|
it is strictly necessary to do so.
|
|
|
|
|
@@ -170,12 +170,25 @@ index 7563c07e14e4..4c4b138170c4 100644
|
|
|
+ upon device mode change.
|
|
|
+
|
|
|
+ If you are not sure, say Y here.
|
|
|
++
|
|
|
++config SURFACE_ACPI_SID
|
|
|
++ bool "Surface Platform Integration Driver"
|
|
|
++ depends on SURFACE_ACPI_SSH
|
|
|
++ default y
|
|
|
++ ---help---
|
|
|
++ Surface Platform Integration Driver for the Microsoft Surface Devices.
|
|
|
++ Currently only supports the Surface Book 2. This driver provides suport
|
|
|
++ for setting performance-modes via the perf_mode sysfs attribute.
|
|
|
++ Performance-modes directly influence the fan-profile of the device,
|
|
|
++ allowing to choose between higher performance or quieter operation.
|
|
|
++
|
|
|
++ If you are not sure, say Y here.
|
|
|
+
|
|
|
config SENSORS_HDAPS
|
|
|
tristate "Thinkpad Hard Drive Active Protection System (hdaps)"
|
|
|
depends on INPUT
|
|
|
diff --git a/drivers/platform/x86/Makefile b/drivers/platform/x86/Makefile
|
|
|
-index e6d1becf81ce..ab8be80b6596 100644
|
|
|
+index dc29af4d8e2f..2250a32a5527 100644
|
|
|
--- a/drivers/platform/x86/Makefile
|
|
|
+++ b/drivers/platform/x86/Makefile
|
|
|
@@ -35,6 +35,7 @@ obj-$(CONFIG_TC1100_WMI) += tc1100-wmi.o
|
|
@@ -188,10 +201,10 @@ index e6d1becf81ce..ab8be80b6596 100644
|
|
|
obj-$(CONFIG_FUJITSU_TABLET) += fujitsu-tablet.o
|
|
|
diff --git a/drivers/platform/x86/surface_acpi.c b/drivers/platform/x86/surface_acpi.c
|
|
|
new file mode 100644
|
|
|
-index 000000000000..9d11028562c9
|
|
|
+index 000000000000..ab793f6774a0
|
|
|
--- /dev/null
|
|
|
+++ b/drivers/platform/x86/surface_acpi.c
|
|
|
-@@ -0,0 +1,3536 @@
|
|
|
+@@ -0,0 +1,3828 @@
|
|
|
+#include <asm/unaligned.h>
|
|
|
+#include <linux/acpi.h>
|
|
|
+#include <linux/completion.h>
|
|
@@ -207,6 +220,8 @@ index 000000000000..9d11028562c9
|
|
|
+#include <linux/kernel.h>
|
|
|
+#include <linux/kfifo.h>
|
|
|
+#include <linux/miscdevice.h>
|
|
|
++#include <linux/module.h>
|
|
|
++#include <linux/moduleparam.h>
|
|
|
+#include <linux/mutex.h>
|
|
|
+#include <linux/platform_device.h>
|
|
|
+#include <linux/pm.h>
|
|
@@ -224,6 +239,8 @@ index 000000000000..9d11028562c9
|
|
|
+#define USB_DEVICE_ID_MS_VHF 0xf001
|
|
|
+#define USB_DEVICE_ID_MS_SURFACE_BASE_2_INTEGRATION 0x0922
|
|
|
+
|
|
|
++#define SG5_PARAM_PERM (S_IRUGO | S_IWUSR)
|
|
|
++
|
|
|
+
|
|
|
+/*************************************************************************
|
|
|
+ * Surface Serial Hub driver (cross-driver interface)
|
|
@@ -3675,6 +3692,286 @@ index 000000000000..9d11028562c9
|
|
|
+
|
|
|
+
|
|
|
+/*************************************************************************
|
|
|
++ * Surface Platform Integration Driver
|
|
|
++ */
|
|
|
++
|
|
|
++#ifdef CONFIG_SURFACE_ACPI_SID
|
|
|
++
|
|
|
++enum sg5_perf_mode {
|
|
|
++ SG5_PERF_MODE_NORMAL = 1,
|
|
|
++ SG5_PERF_MODE_BATTERY = 2,
|
|
|
++ SG5_PERF_MODE_PERF1 = 3,
|
|
|
++ SG5_PERF_MODE_PERF2 = 4,
|
|
|
++
|
|
|
++ __SG5_PERF_MODE__START = 1,
|
|
|
++ __SG5_PERF_MODE__END = 4,
|
|
|
++};
|
|
|
++
|
|
|
++enum sg5_param_perf_mode {
|
|
|
++ SG5_PARAM_PERF_MODE_AS_IS = 0,
|
|
|
++ SG5_PARAM_PERF_MODE_NORMAL = SG5_PERF_MODE_NORMAL,
|
|
|
++ SG5_PARAM_PERF_MODE_BATTERY = SG5_PERF_MODE_BATTERY,
|
|
|
++ SG5_PARAM_PERF_MODE_PERF1 = SG5_PERF_MODE_PERF1,
|
|
|
++ SG5_PARAM_PERF_MODE_PERF2 = SG5_PERF_MODE_PERF2,
|
|
|
++
|
|
|
++ __SG5_PARAM_PERF_MODE__START = 0,
|
|
|
++ __SG5_PARAM_PERF_MODE__END = 4,
|
|
|
++};
|
|
|
++
|
|
|
++struct surface_sid_drvdata {
|
|
|
++ struct device_link *ec_link;
|
|
|
++};
|
|
|
++
|
|
|
++
|
|
|
++static int sg5_ec_perf_mode_get(void)
|
|
|
++{
|
|
|
++ u8 result_buf[8] = { 0 };
|
|
|
++ int status;
|
|
|
++
|
|
|
++ struct surfacegen5_rqst rqst = {
|
|
|
++ .tc = 0x03,
|
|
|
++ .iid = 0x00,
|
|
|
++ .cid = 0x02,
|
|
|
++ .snc = 0x01,
|
|
|
++ .cdl = 0x00,
|
|
|
++ .pld = NULL,
|
|
|
++ };
|
|
|
++
|
|
|
++ struct surfacegen5_buf result = {
|
|
|
++ .cap = ARRAY_SIZE(result_buf),
|
|
|
++ .len = 0,
|
|
|
++ .data = result_buf,
|
|
|
++ };
|
|
|
++
|
|
|
++ status = surfacegen5_ec_rqst(&rqst, &result);
|
|
|
++ if (status) {
|
|
|
++ return status;
|
|
|
++ }
|
|
|
++
|
|
|
++ if (result.len != 8) {
|
|
|
++ return -EFAULT;
|
|
|
++ }
|
|
|
++
|
|
|
++ return get_unaligned_le32(&result.data[0]);
|
|
|
++}
|
|
|
++
|
|
|
++static int sg5_ec_perf_mode_set(int perf_mode)
|
|
|
++{
|
|
|
++ u8 payload[4] = { 0 };
|
|
|
++
|
|
|
++ struct surfacegen5_rqst rqst = {
|
|
|
++ .tc = 0x03,
|
|
|
++ .iid = 0x00,
|
|
|
++ .cid = 0x03,
|
|
|
++ .snc = 0x00,
|
|
|
++ .cdl = ARRAY_SIZE(payload),
|
|
|
++ .pld = payload,
|
|
|
++ };
|
|
|
++
|
|
|
++ if (perf_mode < __SG5_PERF_MODE__START || perf_mode > __SG5_PERF_MODE__END) {
|
|
|
++ return -EINVAL;
|
|
|
++ }
|
|
|
++
|
|
|
++ put_unaligned_le32(perf_mode, &rqst.pld[0]);
|
|
|
++ return surfacegen5_ec_rqst(&rqst, NULL);
|
|
|
++}
|
|
|
++
|
|
|
++
|
|
|
++static int param_perf_mode_set(const char *val, const struct kernel_param *kp)
|
|
|
++{
|
|
|
++ int perf_mode;
|
|
|
++ int status;
|
|
|
++
|
|
|
++ status = kstrtoint(val, 0, &perf_mode);
|
|
|
++ if (status) {
|
|
|
++ return status;
|
|
|
++ }
|
|
|
++
|
|
|
++ if (perf_mode < __SG5_PARAM_PERF_MODE__START || perf_mode > __SG5_PARAM_PERF_MODE__END) {
|
|
|
++ return -EINVAL;
|
|
|
++ }
|
|
|
++
|
|
|
++ return param_set_int(val, kp);
|
|
|
++}
|
|
|
++
|
|
|
++static const struct kernel_param_ops param_perf_mode_ops = {
|
|
|
++ .set = param_perf_mode_set,
|
|
|
++ .get = param_get_int,
|
|
|
++};
|
|
|
++
|
|
|
++static int param_perf_mode_init = SG5_PARAM_PERF_MODE_AS_IS;
|
|
|
++static int param_perf_mode_exit = SG5_PARAM_PERF_MODE_AS_IS;
|
|
|
++
|
|
|
++module_param_cb(perf_mode_init, ¶m_perf_mode_ops, ¶m_perf_mode_init, SG5_PARAM_PERM);
|
|
|
++module_param_cb(perf_mode_exit, ¶m_perf_mode_ops, ¶m_perf_mode_exit, SG5_PARAM_PERM);
|
|
|
++
|
|
|
++MODULE_PARM_DESC(perf_mode_init, "Performance-mode to be set on module initialization");
|
|
|
++MODULE_PARM_DESC(perf_mode_exit, "Performance-mode to be set on module exit");
|
|
|
++
|
|
|
++
|
|
|
++static ssize_t perf_mode_show(struct device *dev, struct device_attribute *attr, char *data)
|
|
|
++{
|
|
|
++ int perf_mode;
|
|
|
++
|
|
|
++ perf_mode = sg5_ec_perf_mode_get();
|
|
|
++ if (perf_mode < 0) {
|
|
|
++ dev_err(dev, "failed to get current performance mode: %d", perf_mode);
|
|
|
++ return -EIO;
|
|
|
++ }
|
|
|
++
|
|
|
++ return sprintf(data, "%d\n", perf_mode);
|
|
|
++}
|
|
|
++
|
|
|
++static ssize_t perf_mode_store(struct device *dev, struct device_attribute *attr,
|
|
|
++ const char *data, size_t count)
|
|
|
++{
|
|
|
++ int perf_mode;
|
|
|
++ int status;
|
|
|
++
|
|
|
++ status = kstrtoint(data, 0, &perf_mode);
|
|
|
++ if (status) {
|
|
|
++ return status;
|
|
|
++ }
|
|
|
++
|
|
|
++ status = sg5_ec_perf_mode_set(perf_mode);
|
|
|
++ if (status) {
|
|
|
++ return status;
|
|
|
++ }
|
|
|
++
|
|
|
++ // TODO: Should we notify ACPI here?
|
|
|
++ //
|
|
|
++ // There is a _DSM call described as
|
|
|
++ // WSID._DSM: Notify DPTF on Slider State change
|
|
|
++ // which calls
|
|
|
++ // ODV3 = ToInteger (Arg3)
|
|
|
++ // Notify(IETM, 0x88)
|
|
|
++ // IETM is an INT3400 Intel Dynamic Power Performance Management
|
|
|
++ // device, part of the DPTF framework. From the corresponding
|
|
|
++ // kernel driver, it looks like event 0x88 is being ignored. Also
|
|
|
++ // it is currently unknown what the consequecnes of setting ODV3
|
|
|
++ // are.
|
|
|
++
|
|
|
++ return count;
|
|
|
++}
|
|
|
++
|
|
|
++const static DEVICE_ATTR_RW(perf_mode);
|
|
|
++
|
|
|
++
|
|
|
++static int surfacegen5_acpi_sid_probe(struct platform_device *pdev)
|
|
|
++{
|
|
|
++ struct surface_sid_drvdata *drvdata;
|
|
|
++ struct device_link *ec_link;
|
|
|
++ int status;
|
|
|
++
|
|
|
++ // link to ec
|
|
|
++ ec_link = surfacegen5_ec_consumer_add(&pdev->dev, DL_FLAG_PM_RUNTIME);
|
|
|
++ if (IS_ERR_OR_NULL(ec_link)) {
|
|
|
++ if (PTR_ERR(ec_link) == -ENXIO) {
|
|
|
++ // Defer probe if the _SSH driver has not set up the controller yet.
|
|
|
++ status = -EPROBE_DEFER;
|
|
|
++ } else {
|
|
|
++ status = -EFAULT;
|
|
|
++ }
|
|
|
++
|
|
|
++ goto err_probe_ec_link;
|
|
|
++ }
|
|
|
++
|
|
|
++ // set up driver data
|
|
|
++ drvdata = kzalloc(sizeof(struct surface_sid_drvdata), GFP_KERNEL);
|
|
|
++ if (!drvdata) {
|
|
|
++ status = -ENOMEM;
|
|
|
++ goto err_drvdata;
|
|
|
++ }
|
|
|
++ drvdata->ec_link = ec_link;
|
|
|
++ platform_set_drvdata(pdev, drvdata);
|
|
|
++
|
|
|
++ // set initial perf_mode
|
|
|
++ if (param_perf_mode_init != SG5_PARAM_PERF_MODE_AS_IS) {
|
|
|
++ status = sg5_ec_perf_mode_set(param_perf_mode_init);
|
|
|
++ if (status) {
|
|
|
++ goto err_set_perf;
|
|
|
++ }
|
|
|
++ }
|
|
|
++
|
|
|
++ // register perf_mode attribute
|
|
|
++ status = sysfs_create_file(&pdev->dev.kobj, &dev_attr_perf_mode.attr);
|
|
|
++ if (status) {
|
|
|
++ goto err_sysfs;
|
|
|
++ }
|
|
|
++
|
|
|
++ return 0;
|
|
|
++
|
|
|
++err_sysfs:
|
|
|
++ sg5_ec_perf_mode_set(param_perf_mode_exit);
|
|
|
++err_set_perf:
|
|
|
++ platform_set_drvdata(pdev, NULL);
|
|
|
++ kfree(drvdata);
|
|
|
++err_drvdata:
|
|
|
++ surfacegen5_ec_consumer_remove(ec_link);
|
|
|
++err_probe_ec_link:
|
|
|
++ return status;
|
|
|
++}
|
|
|
++
|
|
|
++static int surfacegen5_acpi_sid_remove(struct platform_device *pdev)
|
|
|
++{
|
|
|
++ struct surface_sid_drvdata *drvdata = platform_get_drvdata(pdev);
|
|
|
++
|
|
|
++ // remove perf_mode attribute
|
|
|
++ sysfs_remove_file(&pdev->dev.kobj, &dev_attr_perf_mode.attr);
|
|
|
++
|
|
|
++ // set exit perf_mode
|
|
|
++ sg5_ec_perf_mode_set(param_perf_mode_exit);
|
|
|
++
|
|
|
++ // remove consumer and clean up
|
|
|
++ surfacegen5_ec_consumer_remove(drvdata->ec_link);
|
|
|
++ platform_set_drvdata(pdev, NULL);
|
|
|
++ kfree(drvdata);
|
|
|
++
|
|
|
++ return 0;
|
|
|
++}
|
|
|
++
|
|
|
++
|
|
|
++static const struct acpi_device_id surfacegen5_acpi_sid_match[] = {
|
|
|
++ { "MSHW0107", 0 }, /* Surface Book 2 */
|
|
|
++ { },
|
|
|
++};
|
|
|
++MODULE_DEVICE_TABLE(acpi, surfacegen5_acpi_sid_match);
|
|
|
++
|
|
|
++struct platform_driver surfacegen5_acpi_sid = {
|
|
|
++ .probe = surfacegen5_acpi_sid_probe,
|
|
|
++ .remove = surfacegen5_acpi_sid_remove,
|
|
|
++ .driver = {
|
|
|
++ .name = "surfacegen5_acpi_sid",
|
|
|
++ .acpi_match_table = ACPI_PTR(surfacegen5_acpi_sid_match),
|
|
|
++ },
|
|
|
++};
|
|
|
++
|
|
|
++
|
|
|
++inline int surfacegen5_acpi_sid_register(void)
|
|
|
++{
|
|
|
++ return platform_driver_register(&surfacegen5_acpi_sid);
|
|
|
++}
|
|
|
++
|
|
|
++inline void surfacegen5_acpi_sid_unregister(void)
|
|
|
++{
|
|
|
++ platform_driver_unregister(&surfacegen5_acpi_sid);
|
|
|
++}
|
|
|
++
|
|
|
++#else /* CONFIG_SURFACE_ACPI_SID */
|
|
|
++
|
|
|
++inline int surfacegen5_acpi_sid_register(void)
|
|
|
++{
|
|
|
++ return 0;
|
|
|
++}
|
|
|
++
|
|
|
++inline void surfacegen5_acpi_sid_unregister(void)
|
|
|
++{
|
|
|
++}
|
|
|
++
|
|
|
++#endif /* CONFIG_SURFACE_ACPI_SID */
|
|
|
++
|
|
|
++
|
|
|
++/*************************************************************************
|
|
|
+ * Module initialization
|
|
|
+ */
|
|
|
+
|
|
@@ -3702,8 +3999,15 @@ index 000000000000..9d11028562c9
|
|
|
+ goto err_dtx;
|
|
|
+ }
|
|
|
+
|
|
|
++ status = surfacegen5_acpi_sid_register();
|
|
|
++ if (status) {
|
|
|
++ goto err_sid;
|
|
|
++ }
|
|
|
++
|
|
|
+ return 0;
|
|
|
+
|
|
|
++err_sid:
|
|
|
++ surfacegen5_acpi_sid_unregister();
|
|
|
+err_dtx:
|
|
|
+ surfacegen5_acpi_vhf_unregister();
|
|
|
+err_vhf:
|
|
@@ -3716,6 +4020,7 @@ index 000000000000..9d11028562c9
|
|
|
+
|
|
|
+void __exit surface_acpi_exit(void)
|
|
|
+{
|
|
|
++ surfacegen5_acpi_sid_unregister();
|
|
|
+ surfacegen5_acpi_dtx_unregister();
|
|
|
+ surfacegen5_acpi_vhf_unregister();
|
|
|
+ surfacegen5_acpi_san_unregister();
|