46bf4695d7
There are some important platform drivers that Valve has not upstreamed, that are basically required for this device to operate well. I picked those patches from the kernel tree they released for 6.5, and rebased them onto 6.8.
283 lines
7.1 KiB
Diff
283 lines
7.1 KiB
Diff
From 498c8379bae238aca5707308652e0834e1f6de7a Mon Sep 17 00:00:00 2001
|
|
From: Andrey Smirnov <andrew.smirnov@gmail.com>
|
|
Date: Sat, 19 Feb 2022 16:09:45 -0800
|
|
Subject: [PATCH 05/21] hwmon: Add driver for Steam Deck's EC sensors
|
|
|
|
Add driver for sensors exposed by EC firmware on Steam Deck hardware.
|
|
|
|
(cherry picked from commit 6917aac77bee6185ae3920b936cdbe7876118c0b)
|
|
Signed-off-by: Cristian Ciocaltea <cristian.ciocaltea@collabora.com>
|
|
---
|
|
drivers/hwmon/Kconfig | 11 ++
|
|
drivers/hwmon/Makefile | 1 +
|
|
drivers/hwmon/steamdeck-hwmon.c | 224 ++++++++++++++++++++++++++++++++
|
|
3 files changed, 236 insertions(+)
|
|
create mode 100644 drivers/hwmon/steamdeck-hwmon.c
|
|
|
|
diff --git a/drivers/hwmon/Kconfig b/drivers/hwmon/Kconfig
|
|
index a608264da87d..cf0fc2ce1017 100644
|
|
--- a/drivers/hwmon/Kconfig
|
|
+++ b/drivers/hwmon/Kconfig
|
|
@@ -1974,6 +1974,17 @@ config SENSORS_SCH5636
|
|
This driver can also be built as a module. If so, the module
|
|
will be called sch5636.
|
|
|
|
+config SENSORS_STEAMDECK
|
|
+ tristate "Steam Deck EC sensors"
|
|
+ depends on MFD_STEAMDECK
|
|
+ help
|
|
+ If you say yes here you get support for the hardware
|
|
+ monitoring features exposed by EC firmware on Steam Deck
|
|
+ devices
|
|
+
|
|
+ This driver can also be built as a module. If so, the module
|
|
+ will be called steamdeck-hwmon.
|
|
+
|
|
config SENSORS_STTS751
|
|
tristate "ST Microelectronics STTS751"
|
|
depends on I2C
|
|
diff --git a/drivers/hwmon/Makefile b/drivers/hwmon/Makefile
|
|
index 47be39af5c03..b1cc9112a0a6 100644
|
|
--- a/drivers/hwmon/Makefile
|
|
+++ b/drivers/hwmon/Makefile
|
|
@@ -200,6 +200,7 @@ obj-$(CONFIG_SENSORS_SMSC47B397)+= smsc47b397.o
|
|
obj-$(CONFIG_SENSORS_SMSC47M1) += smsc47m1.o
|
|
obj-$(CONFIG_SENSORS_SMSC47M192)+= smsc47m192.o
|
|
obj-$(CONFIG_SENSORS_SPARX5) += sparx5-temp.o
|
|
+obj-$(CONFIG_SENSORS_STEAMDECK) += steamdeck-hwmon.o
|
|
obj-$(CONFIG_SENSORS_STTS751) += stts751.o
|
|
obj-$(CONFIG_SENSORS_SY7636A) += sy7636a-hwmon.o
|
|
obj-$(CONFIG_SENSORS_AMC6821) += amc6821.o
|
|
diff --git a/drivers/hwmon/steamdeck-hwmon.c b/drivers/hwmon/steamdeck-hwmon.c
|
|
new file mode 100644
|
|
index 000000000000..fab9e9460bd4
|
|
--- /dev/null
|
|
+++ b/drivers/hwmon/steamdeck-hwmon.c
|
|
@@ -0,0 +1,224 @@
|
|
+// SPDX-License-Identifier: GPL-2.0+
|
|
+/*
|
|
+ * Steam Deck EC sensors driver
|
|
+ *
|
|
+ * Copyright (C) 2021-2022 Valve Corporation
|
|
+ */
|
|
+
|
|
+#include <linux/acpi.h>
|
|
+#include <linux/hwmon.h>
|
|
+#include <linux/platform_device.h>
|
|
+
|
|
+#define STEAMDECK_HWMON_NAME "steamdeck-hwmon"
|
|
+
|
|
+struct steamdeck_hwmon {
|
|
+ struct acpi_device *adev;
|
|
+};
|
|
+
|
|
+static long
|
|
+steamdeck_hwmon_get(struct steamdeck_hwmon *sd, const char *method)
|
|
+{
|
|
+ unsigned long long val;
|
|
+ if (ACPI_FAILURE(acpi_evaluate_integer(sd->adev->handle,
|
|
+ (char *)method, NULL, &val)))
|
|
+ return -EIO;
|
|
+
|
|
+ return val;
|
|
+}
|
|
+
|
|
+static int
|
|
+steamdeck_hwmon_read(struct device *dev, enum hwmon_sensor_types type,
|
|
+ u32 attr, int channel, long *out)
|
|
+{
|
|
+ struct steamdeck_hwmon *sd = dev_get_drvdata(dev);
|
|
+
|
|
+ switch (type) {
|
|
+ case hwmon_curr:
|
|
+ if (attr != hwmon_curr_input)
|
|
+ return -EOPNOTSUPP;
|
|
+
|
|
+ *out = steamdeck_hwmon_get(sd, "PDAM");
|
|
+ if (*out < 0)
|
|
+ return *out;
|
|
+ break;
|
|
+ case hwmon_in:
|
|
+ if (attr != hwmon_in_input)
|
|
+ return -EOPNOTSUPP;
|
|
+
|
|
+ *out = steamdeck_hwmon_get(sd, "PDVL");
|
|
+ if (*out < 0)
|
|
+ return *out;
|
|
+ break;
|
|
+ case hwmon_temp:
|
|
+ if (attr != hwmon_temp_input)
|
|
+ return -EOPNOTSUPP;
|
|
+
|
|
+ *out = steamdeck_hwmon_get(sd, "BATT");
|
|
+ if (*out < 0)
|
|
+ return *out;
|
|
+ /*
|
|
+ * Assuming BATT returns deg C we need to mutiply it
|
|
+ * by 1000 to convert to mC
|
|
+ */
|
|
+ *out *= 1000;
|
|
+ break;
|
|
+ case hwmon_fan:
|
|
+ switch (attr) {
|
|
+ case hwmon_fan_input:
|
|
+ *out = steamdeck_hwmon_get(sd, "FANR");
|
|
+ if (*out < 0)
|
|
+ return *out;
|
|
+ break;
|
|
+ case hwmon_fan_target:
|
|
+ *out = steamdeck_hwmon_get(sd, "FSSR");
|
|
+ if (*out < 0)
|
|
+ return *out;
|
|
+ break;
|
|
+ case hwmon_fan_fault:
|
|
+ *out = steamdeck_hwmon_get(sd, "FANC");
|
|
+ if (*out < 0)
|
|
+ return *out;
|
|
+ /*
|
|
+ * FANC (Fan check):
|
|
+ * 0: Abnormal
|
|
+ * 1: Normal
|
|
+ */
|
|
+ *out = !*out;
|
|
+ break;
|
|
+ default:
|
|
+ return -EOPNOTSUPP;
|
|
+ }
|
|
+ break;
|
|
+ default:
|
|
+ return -EOPNOTSUPP;
|
|
+ }
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static int
|
|
+steamdeck_hwmon_read_string(struct device *dev, enum hwmon_sensor_types type,
|
|
+ u32 attr, int channel, const char **str)
|
|
+{
|
|
+ switch (type) {
|
|
+ /*
|
|
+ * These two aren't, strictly speaking, measured. EC
|
|
+ * firmware just reports what PD negotiation resulted
|
|
+ * in.
|
|
+ */
|
|
+ case hwmon_curr:
|
|
+ *str = "PD Contract Current";
|
|
+ break;
|
|
+ case hwmon_in:
|
|
+ *str = "PD Contract Voltage";
|
|
+ break;
|
|
+ case hwmon_temp:
|
|
+ *str = "Battery Temp";
|
|
+ break;
|
|
+ case hwmon_fan:
|
|
+ *str = "System Fan";
|
|
+ break;
|
|
+ default:
|
|
+ return -EOPNOTSUPP;
|
|
+ }
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static int
|
|
+steamdeck_hwmon_write(struct device *dev, enum hwmon_sensor_types type,
|
|
+ u32 attr, int channel, long val)
|
|
+{
|
|
+ struct steamdeck_hwmon *sd = dev_get_drvdata(dev);
|
|
+
|
|
+ if (type != hwmon_fan ||
|
|
+ attr != hwmon_fan_target)
|
|
+ return -EOPNOTSUPP;
|
|
+
|
|
+ val = clamp_val(val, 0, 7300);
|
|
+
|
|
+ if (ACPI_FAILURE(acpi_execute_simple_method(sd->adev->handle,
|
|
+ "FANS", val)))
|
|
+ return -EIO;
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static umode_t
|
|
+steamdeck_hwmon_is_visible(const void *data, enum hwmon_sensor_types type,
|
|
+ u32 attr, int channel)
|
|
+{
|
|
+ if (type == hwmon_fan &&
|
|
+ attr == hwmon_fan_target)
|
|
+ return 0644;
|
|
+
|
|
+ return 0444;
|
|
+}
|
|
+
|
|
+static const struct hwmon_channel_info *steamdeck_hwmon_info[] = {
|
|
+ HWMON_CHANNEL_INFO(in,
|
|
+ HWMON_I_INPUT | HWMON_I_LABEL),
|
|
+ HWMON_CHANNEL_INFO(curr,
|
|
+ HWMON_C_INPUT | HWMON_C_LABEL),
|
|
+ HWMON_CHANNEL_INFO(temp,
|
|
+ HWMON_T_INPUT | HWMON_T_LABEL),
|
|
+ HWMON_CHANNEL_INFO(fan,
|
|
+ HWMON_F_INPUT | HWMON_F_LABEL |
|
|
+ HWMON_F_TARGET | HWMON_F_FAULT),
|
|
+ NULL
|
|
+};
|
|
+
|
|
+static const struct hwmon_ops steamdeck_hwmon_ops = {
|
|
+ .is_visible = steamdeck_hwmon_is_visible,
|
|
+ .read = steamdeck_hwmon_read,
|
|
+ .read_string = steamdeck_hwmon_read_string,
|
|
+ .write = steamdeck_hwmon_write,
|
|
+};
|
|
+
|
|
+static const struct hwmon_chip_info steamdeck_hwmon_chip_info = {
|
|
+ .ops = &steamdeck_hwmon_ops,
|
|
+ .info = steamdeck_hwmon_info,
|
|
+};
|
|
+
|
|
+static int steamdeck_hwmon_probe(struct platform_device *pdev)
|
|
+{
|
|
+ struct device *dev = &pdev->dev;
|
|
+ struct steamdeck_hwmon *sd;
|
|
+ struct device *hwmon;
|
|
+
|
|
+ sd = devm_kzalloc(dev, sizeof(*sd), GFP_KERNEL);
|
|
+ if (!sd)
|
|
+ return -ENOMEM;
|
|
+
|
|
+ sd->adev = ACPI_COMPANION(dev->parent);
|
|
+ hwmon = devm_hwmon_device_register_with_info(dev,
|
|
+ "steamdeck_hwmon",
|
|
+ sd,
|
|
+ &steamdeck_hwmon_chip_info,
|
|
+ NULL);
|
|
+ if (IS_ERR(hwmon)) {
|
|
+ dev_err(dev, "Failed to register HWMON device");
|
|
+ return PTR_ERR(hwmon);
|
|
+ }
|
|
+
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+static const struct platform_device_id steamdeck_hwmon_id_table[] = {
|
|
+ { .name = STEAMDECK_HWMON_NAME },
|
|
+ {}
|
|
+};
|
|
+MODULE_DEVICE_TABLE(platform, steamdeck_hwmon_id_table);
|
|
+
|
|
+static struct platform_driver steamdeck_hwmon_driver = {
|
|
+ .probe = steamdeck_hwmon_probe,
|
|
+ .driver = {
|
|
+ .name = STEAMDECK_HWMON_NAME,
|
|
+ },
|
|
+ .id_table = steamdeck_hwmon_id_table,
|
|
+};
|
|
+module_platform_driver(steamdeck_hwmon_driver);
|
|
+
|
|
+MODULE_AUTHOR("Andrey Smirnov <andrew.smirnov@gmail.com>");
|
|
+MODULE_DESCRIPTION("Steam Deck EC sensors driver");
|
|
+MODULE_LICENSE("GPL");
|
|
--
|
|
2.44.0
|
|
|