summaryrefslogtreecommitdiff
path: root/SOURCES/steam-deck.patch
diff options
context:
space:
mode:
authorJan200101 <sentrycraft123@gmail.com>2023-08-05 23:09:13 +0200
committerJan200101 <sentrycraft123@gmail.com>2023-08-05 23:09:13 +0200
commit5eceed518d26b9efa456b50e7b1bd9bfbb2010ac (patch)
tree5dbf336fdd470f83c8221b96e3037b310ff3f690 /SOURCES/steam-deck.patch
parent39e954e3a34034f13420b99661a66a99d02d1105 (diff)
downloadkernel-fsync-5eceed518d26b9efa456b50e7b1bd9bfbb2010ac.tar.gz
kernel-fsync-5eceed518d26b9efa456b50e7b1bd9bfbb2010ac.zip
kernel 6.4.8
Diffstat (limited to 'SOURCES/steam-deck.patch')
-rw-r--r--SOURCES/steam-deck.patch898
1 files changed, 627 insertions, 271 deletions
diff --git a/SOURCES/steam-deck.patch b/SOURCES/steam-deck.patch
index 1da2e78..e8570a0 100644
--- a/SOURCES/steam-deck.patch
+++ b/SOURCES/steam-deck.patch
@@ -1,263 +1,329 @@
-diff --git a/drivers/platform/x86/Kconfig b/drivers/platform/x86/Kconfig
-index 53abd553b842..5c42b99fe26d 100644
---- a/drivers/platform/x86/Kconfig
-+++ b/drivers/platform/x86/Kconfig
-@@ -1140,6 +1140,20 @@
- buttons below the display. This module adds an input device
- that delivers key events when these buttons are pressed.
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Andrey Smirnov <andrew.smirnov@gmail.com>
+Date: Sat, 19 Feb 2022 16:08:36 -0800
+Subject: [PATCH] mfd: Add MFD core driver for Steam Deck
+
+Add MFD core driver for Steam Deck. Doesn't really do much so far
+besides instantiating a number of MFD cells that implement all the
+interesting functionality.
+
+(cherry picked from commit 5f534c2d6ebdefccb9c024eb0f013bc1c0c622d9)
+Signed-off-by: Cristian Ciocaltea <cristian.ciocaltea@collabora.com>
+Signed-off-by: Jan200101 <sentrycraft123@gmail.com>
+---
+ drivers/mfd/Kconfig | 11 ++++
+ drivers/mfd/Makefile | 2 +
+ drivers/mfd/steamdeck.c | 127 ++++++++++++++++++++++++++++++++++++++++
+ 3 files changed, 140 insertions(+)
+ create mode 100644 drivers/mfd/steamdeck.c
+
+diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig
+index 8b93856de432..af335d9150e9 100644
+--- a/drivers/mfd/Kconfig
++++ b/drivers/mfd/Kconfig
+@@ -2260,5 +2260,16 @@ config MFD_RSMU_SPI
+ Additional drivers must be enabled in order to use the functionality
+ of the device.
-+config STEAMDECK
-+ tristate "Valve Steam Deck platform driver"
-+ depends on X86_64
++config MFD_STEAMDECK
++ tristate "Valve Steam Deck"
++ select MFD_CORE
++ depends on ACPI
++ depends on X86_64 || COMPILE_TEST
+ help
-+ Driver exposing various bits and pieces of functionality
-+ provided by Steam Deck specific VLV0100 device presented by
-+ EC firmware. This includes but not limited to:
-+ - CPU/device's fan control
-+ - Read-only access to DDIC registers
-+ - Battery tempreature measurements
-+ - Various display related control knobs
-+ - USB Type-C connector event notification
-+ Say N unless you are running on a Steam Deck.
-+
- endif # X86_PLATFORM_DEVICES
-
- config P2SB
-diff --git a/drivers/platform/x86/Makefile b/drivers/platform/x86/Makefile
-index c12a9b044fd8..c3cc86b27350 100644
---- a/drivers/platform/x86/Makefile
-+++ b/drivers/platform/x86/Makefile
-@@ -133,3 +133,6 @@
-
- # Winmate
- obj-$(CONFIG_WINMATE_FM07_KEYS) += winmate-fm07-keys.o
-+
-+# Steam Deck
-+obj-$(CONFIG_STEAMDECK) += steamdeck.o
-diff --git a/drivers/platform/x86/steamdeck.c b/drivers/platform/x86/steamdeck.c
++ This driver registers various MFD cells that expose aspects
++ of Steam Deck specific ACPI functionality.
++
++ Say N here, unless you are running on Steam Deck hardware.
++
+ endmenu
+ endif
+diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile
+index 7ed3ef4a698c..d01254ef0106 100644
+--- a/drivers/mfd/Makefile
++++ b/drivers/mfd/Makefile
+@@ -280,3 +280,5 @@ rsmu-i2c-objs := rsmu_core.o rsmu_i2c.o
+ rsmu-spi-objs := rsmu_core.o rsmu_spi.o
+ obj-$(CONFIG_MFD_RSMU_I2C) += rsmu-i2c.o
+ obj-$(CONFIG_MFD_RSMU_SPI) += rsmu-spi.o
++
++obj-$(CONFIG_MFD_STEAMDECK) += steamdeck.o
+diff --git a/drivers/mfd/steamdeck.c b/drivers/mfd/steamdeck.c
new file mode 100644
-index 000000000000..77a6677ec19e
+index 000000000000..0e504b3c2796
--- /dev/null
-+++ b/drivers/platform/x86/steamdeck.c
-@@ -0,0 +1,523 @@
++++ b/drivers/mfd/steamdeck.c
+@@ -0,0 +1,127 @@
+// SPDX-License-Identifier: GPL-2.0+
+
+/*
-+ * Steam Deck ACPI platform driver
++ * Steam Deck EC MFD core driver
+ *
+ * Copyright (C) 2021-2022 Valve Corporation
+ *
+ */
++
+#include <linux/acpi.h>
-+#include <linux/hwmon.h>
+#include <linux/platform_device.h>
-+#include <linux/regmap.h>
-+#include <linux/extcon-provider.h>
++#include <linux/mfd/core.h>
+
-+#define ACPI_STEAMDECK_NOTIFY_STATUS 0x80
-+
-+/* 0 - port connected, 1 -port disconnected */
-+#define ACPI_STEAMDECK_PORT_CONNECT BIT(0)
-+/* 0 - Upstream Facing Port, 1 - Downdstream Facing Port */
-+#define ACPI_STEAMDECK_CUR_DATA_ROLE BIT(3)
-+/*
-+ * Debouncing delay to allow negotiation process to settle. 2s value
-+ * was arrived at via trial and error.
-+ */
-+#define STEAMDECK_ROLE_SWITCH_DELAY (msecs_to_jiffies(2000))
++#define STEAMDECK_STA_OK \
++ (ACPI_STA_DEVICE_ENABLED | \
++ ACPI_STA_DEVICE_PRESENT | \
++ ACPI_STA_DEVICE_FUNCTIONING)
+
+struct steamdeck {
+ struct acpi_device *adev;
-+ struct device *hwmon;
-+ void *regmap;
-+ long fan_target;
-+ struct delayed_work role_work;
-+ struct extcon_dev *edev;
+ struct device *dev;
+};
+
-+static ssize_t
-+steamdeck_simple_store(struct device *dev, const char *buf, size_t count,
-+ const char *method,
-+ unsigned long upper_limit)
-+{
-+ struct steamdeck *fan = dev_get_drvdata(dev);
-+ unsigned long value;
-+
-+ if (kstrtoul(buf, 10, &value) || value >= upper_limit)
-+ return -EINVAL;
-+
-+ if (ACPI_FAILURE(acpi_execute_simple_method(fan->adev->handle,
-+ (char *)method, value)))
-+ return -EIO;
-+
-+ return count;
-+}
-+
-+#define STEAMDECK_ATTR_WO(_name, _method, _upper_limit) \
-+ static ssize_t _name##_store(struct device *dev, \
-+ struct device_attribute *attr, \
-+ const char *buf, size_t count) \
-+ { \
-+ return steamdeck_simple_store(dev, buf, count, \
-+ _method, \
-+ _upper_limit); \
-+ } \
-+ static DEVICE_ATTR_WO(_name)
-+
-+STEAMDECK_ATTR_WO(target_cpu_temp, "STCT", U8_MAX / 2);
-+STEAMDECK_ATTR_WO(gain, "SGAN", U16_MAX);
-+STEAMDECK_ATTR_WO(ramp_rate, "SFRR", U8_MAX);
-+STEAMDECK_ATTR_WO(hysteresis, "SHTS", U16_MAX);
-+STEAMDECK_ATTR_WO(maximum_battery_charge_rate, "CHGR", U16_MAX);
-+STEAMDECK_ATTR_WO(recalculate, "SCHG", U16_MAX);
-+
-+STEAMDECK_ATTR_WO(led_brightness, "CHBV", U8_MAX);
-+STEAMDECK_ATTR_WO(content_adaptive_brightness, "CABC", U8_MAX);
-+STEAMDECK_ATTR_WO(gamma_set, "GAMA", U8_MAX);
-+STEAMDECK_ATTR_WO(display_brightness, "WDBV", U8_MAX);
-+STEAMDECK_ATTR_WO(ctrl_display, "WCDV", U8_MAX);
-+STEAMDECK_ATTR_WO(cabc_minimum_brightness, "WCMB", U8_MAX);
-+STEAMDECK_ATTR_WO(memory_data_access_control, "MDAC", U8_MAX);
-+
-+#define STEAMDECK_ATTR_WO_NOARG(_name, _method) \
-+ static ssize_t _name##_store(struct device *dev, \
-+ struct device_attribute *attr, \
-+ const char *buf, size_t count) \
-+ { \
-+ struct steamdeck *fan = dev_get_drvdata(dev); \
-+ \
-+ if (ACPI_FAILURE(acpi_evaluate_object(fan->adev->handle, \
-+ _method, NULL, NULL))) \
-+ return -EIO; \
-+ \
-+ return count; \
-+ } \
-+ static DEVICE_ATTR_WO(_name)
-+
-+STEAMDECK_ATTR_WO_NOARG(power_cycle_display, "DPCY");
-+STEAMDECK_ATTR_WO_NOARG(display_normal_mode_on, "NORO");
-+STEAMDECK_ATTR_WO_NOARG(display_inversion_off, "INOF");
-+STEAMDECK_ATTR_WO_NOARG(display_inversion_on, "INON");
-+STEAMDECK_ATTR_WO_NOARG(idle_mode_on, "WRNE");
-+
+#define STEAMDECK_ATTR_RO(_name, _method) \
+ static ssize_t _name##_show(struct device *dev, \
+ struct device_attribute *attr, \
+ char *buf) \
+ { \
-+ struct steamdeck *jup = dev_get_drvdata(dev); \
++ struct steamdeck *sd = dev_get_drvdata(dev); \
+ unsigned long long val; \
+ \
+ if (ACPI_FAILURE(acpi_evaluate_integer( \
-+ jup->adev->handle, \
++ sd->adev->handle, \
+ _method, NULL, &val))) \
+ return -EIO; \
+ \
-+ return sprintf(buf, "%llu\n", val); \
++ return sysfs_emit(buf, "%llu\n", val); \
+ } \
+ static DEVICE_ATTR_RO(_name)
+
+STEAMDECK_ATTR_RO(firmware_version, "PDFW");
+STEAMDECK_ATTR_RO(board_id, "BOID");
-+STEAMDECK_ATTR_RO(pdcs, "PDCS");
+
-+static umode_t
-+steamdeck_is_visible(struct kobject *kobj, struct attribute *attr, int index)
++static struct attribute *steamdeck_attrs[] = {
++ &dev_attr_firmware_version.attr,
++ &dev_attr_board_id.attr,
++ NULL
++};
++
++ATTRIBUTE_GROUPS(steamdeck);
++
++static const struct mfd_cell steamdeck_cells[] = {
++ { .name = "steamdeck-hwmon" },
++ { .name = "steamdeck-leds" },
++ { .name = "steamdeck-extcon" },
++};
++
++static void steamdeck_remove_sysfs_groups(void *data)
+{
-+ return attr->mode;
++ struct steamdeck *sd = data;
++
++ sysfs_remove_groups(&sd->dev->kobj, steamdeck_groups);
+}
+
-+static struct attribute *steamdeck_attributes[] = {
-+ &dev_attr_target_cpu_temp.attr,
-+ &dev_attr_gain.attr,
-+ &dev_attr_ramp_rate.attr,
-+ &dev_attr_hysteresis.attr,
-+ &dev_attr_maximum_battery_charge_rate.attr,
-+ &dev_attr_recalculate.attr,
-+ &dev_attr_power_cycle_display.attr,
-+
-+ &dev_attr_led_brightness.attr,
-+ &dev_attr_content_adaptive_brightness.attr,
-+ &dev_attr_gamma_set.attr,
-+ &dev_attr_display_brightness.attr,
-+ &dev_attr_ctrl_display.attr,
-+ &dev_attr_cabc_minimum_brightness.attr,
-+ &dev_attr_memory_data_access_control.attr,
-+
-+ &dev_attr_display_normal_mode_on.attr,
-+ &dev_attr_display_inversion_off.attr,
-+ &dev_attr_display_inversion_on.attr,
-+ &dev_attr_idle_mode_on.attr,
++static int steamdeck_probe(struct platform_device *pdev)
++{
++ struct device *dev = &pdev->dev;
++ unsigned long long sta;
++ struct steamdeck *sd;
++ acpi_status status;
++ int ret;
+
-+ &dev_attr_firmware_version.attr,
-+ &dev_attr_board_id.attr,
-+ &dev_attr_pdcs.attr,
++ sd = devm_kzalloc(dev, sizeof(*sd), GFP_KERNEL);
++ if (!sd)
++ return -ENOMEM;
++ sd->adev = ACPI_COMPANION(dev);
++ sd->dev = dev;
++ platform_set_drvdata(pdev, sd);
+
-+ NULL
++ status = acpi_evaluate_integer(sd->adev->handle, "_STA",
++ NULL, &sta);
++ if (ACPI_FAILURE(status)) {
++ dev_err(dev, "Status check failed (0x%x)\n", status);
++ return -EINVAL;
++ }
++
++ if ((sta & STEAMDECK_STA_OK) != STEAMDECK_STA_OK) {
++ dev_err(dev, "Device is not ready\n");
++ return -EINVAL;
++ }
++
++ ret = sysfs_create_groups(&dev->kobj, steamdeck_groups);
++ if (ret) {
++ dev_err(dev, "Failed to create sysfs group\n");
++ return ret;
++ }
++
++ ret = devm_add_action_or_reset(dev, steamdeck_remove_sysfs_groups,
++ sd);
++ if (ret) {
++ dev_err(dev, "Failed to register devres action\n");
++ return ret;
++ }
++
++ return devm_mfd_add_devices(dev, PLATFORM_DEVID_NONE,
++ steamdeck_cells, ARRAY_SIZE(steamdeck_cells),
++ NULL, 0, NULL);
++}
++
++static const struct acpi_device_id steamdeck_device_ids[] = {
++ { "VLV0100", 0 },
++ { "", 0 },
+};
++MODULE_DEVICE_TABLE(acpi, steamdeck_device_ids);
+
-+static const struct attribute_group steamdeck_group = {
-+ .attrs = steamdeck_attributes,
-+ .is_visible = steamdeck_is_visible,
++static struct platform_driver steamdeck_driver = {
++ .probe = steamdeck_probe,
++ .driver = {
++ .name = "steamdeck",
++ .acpi_match_table = steamdeck_device_ids,
++ },
+};
++module_platform_driver(steamdeck_driver);
+
-+static const struct attribute_group *steamdeck_groups[] = {
-+ &steamdeck_group,
-+ NULL
++MODULE_AUTHOR("Andrey Smirnov <andrew.smirnov@gmail.com>");
++MODULE_DESCRIPTION("Steam Deck EC MFD core driver");
++MODULE_LICENSE("GPL");
+From 0000000000000000000000000000000000000000 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] 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>
+Signed-off-by: Jan200101 <sentrycraft123@gmail.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 7ac3daaf59ce..d784c78417cf 100644
+--- a/drivers/hwmon/Kconfig
++++ b/drivers/hwmon/Kconfig
+@@ -1900,6 +1900,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 11d076cad8a2..d03c1e1d339f 100644
+--- a/drivers/hwmon/Makefile
++++ b/drivers/hwmon/Makefile
+@@ -191,6 +191,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 int steamdeck_read_fan_speed(struct steamdeck *jup, long *speed)
++static long
++steamdeck_hwmon_get(struct steamdeck_hwmon *sd, const char *method)
+{
+ unsigned long long val;
-+
-+ if (ACPI_FAILURE(acpi_evaluate_integer(jup->adev->handle,
-+ "FANR", NULL, &val)))
++ if (ACPI_FAILURE(acpi_evaluate_integer(sd->adev->handle,
++ (char *)method, NULL, &val)))
+ return -EIO;
+
-+ *speed = val;
-+ return 0;
++ return val;
+}
+
+static int
+steamdeck_hwmon_read(struct device *dev, enum hwmon_sensor_types type,
+ u32 attr, int channel, long *out)
+{
-+ struct steamdeck *sd = dev_get_drvdata(dev);
-+ unsigned long long val;
++ 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;
+
-+ if (ACPI_FAILURE(acpi_evaluate_integer(sd->adev->handle,
-+ "BATT", NULL, &val)))
-+ return -EIO;
++ *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 = val * 1000;
++ *out *= 1000;
+ break;
+ case hwmon_fan:
+ switch (attr) {
+ case hwmon_fan_input:
-+ return steamdeck_read_fan_speed(sd, out);
++ *out = steamdeck_hwmon_get(sd, "FANR");
++ if (*out < 0)
++ return *out;
++ break;
+ case hwmon_fan_target:
-+ *out = sd->fan_target;
++ *out = steamdeck_hwmon_get(sd, "FSSR");
++ if (*out < 0)
++ return *out;
+ break;
+ case hwmon_fan_fault:
-+ if (ACPI_FAILURE(acpi_evaluate_integer(
-+ sd->adev->handle,
-+ "FANC", NULL, &val)))
-+ return -EIO;
++ *out = steamdeck_hwmon_get(sd, "FANC");
++ if (*out < 0)
++ return *out;
+ /*
+ * FANC (Fan check):
+ * 0: Abnormal
+ * 1: Normal
+ */
-+ *out = !val;
++ *out = !*out;
+ break;
+ default:
+ return -EOPNOTSUPP;
@@ -275,6 +341,17 @@ index 000000000000..77a6677ec19e
+ 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;
@@ -292,16 +369,13 @@ index 000000000000..77a6677ec19e
+steamdeck_hwmon_write(struct device *dev, enum hwmon_sensor_types type,
+ u32 attr, int channel, long val)
+{
-+ struct steamdeck *sd = dev_get_drvdata(dev);
++ struct steamdeck_hwmon *sd = dev_get_drvdata(dev);
+
+ if (type != hwmon_fan ||
+ attr != hwmon_fan_target)
+ return -EOPNOTSUPP;
+
-+ if (val > U16_MAX)
-+ return -EINVAL;
-+
-+ sd->fan_target = val;
++ val = clamp_val(val, 0, 7300);
+
+ if (ACPI_FAILURE(acpi_execute_simple_method(sd->adev->handle,
+ "FANS", val)))
@@ -321,7 +395,11 @@ index 000000000000..77a6677ec19e
+ return 0444;
+}
+
-+static const struct hwmon_channel_info *steamdeck_info[] = {
++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,
@@ -337,35 +415,249 @@ index 000000000000..77a6677ec19e
+ .write = steamdeck_hwmon_write,
+};
+
-+static const struct hwmon_chip_info steamdeck_chip_info = {
++static const struct hwmon_chip_info steamdeck_hwmon_chip_info = {
+ .ops = &steamdeck_hwmon_ops,
-+ .info = steamdeck_info,
++ .info = steamdeck_hwmon_info,
+};
+
-+#define STEAMDECK_STA_OK \
-+ (ACPI_STA_DEVICE_ENABLED | \
-+ ACPI_STA_DEVICE_PRESENT | \
-+ ACPI_STA_DEVICE_FUNCTIONING)
-+
-+static int
-+steamdeck_ddic_reg_read(void *context, unsigned int reg, unsigned int *val)
++static int steamdeck_hwmon_probe(struct platform_device *pdev)
+{
-+ union acpi_object obj = { .type = ACPI_TYPE_INTEGER };
-+ struct acpi_object_list arg_list = { .count = 1, .pointer = &obj, };
-+ struct steamdeck *sd = context;
-+ unsigned long long _val;
++ 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);
++ }
+
-+ obj.integer.value = reg;
++ return 0;
++}
+
-+ if (ACPI_FAILURE(acpi_evaluate_integer(sd->adev->handle,
-+ "RDDI", &arg_list, &_val)))
++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");
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Andrey Smirnov <andrew.smirnov@gmail.com>
+Date: Sun, 27 Feb 2022 12:58:05 -0800
+Subject: [PATCH] leds: steamdeck: Add support for Steam Deck LED
+
+(cherry picked from commit 85a86d19aa7022ff0555023d53aef78323a42d0c)
+Signed-off-by: Cristian Ciocaltea <cristian.ciocaltea@collabora.com>
+Signed-off-by: Jan200101 <sentrycraft123@gmail.com>
+---
+ drivers/leds/Kconfig | 7 ++++
+ drivers/leds/Makefile | 1 +
+ drivers/leds/leds-steamdeck.c | 74 +++++++++++++++++++++++++++++++++++
+ 3 files changed, 82 insertions(+)
+ create mode 100644 drivers/leds/leds-steamdeck.c
+
+diff --git a/drivers/leds/Kconfig b/drivers/leds/Kconfig
+index 499d0f215a8b..d1d761695cd6 100644
+--- a/drivers/leds/Kconfig
++++ b/drivers/leds/Kconfig
+@@ -864,6 +864,13 @@ config LEDS_ACER_A500
+ This option enables support for the Power Button LED of
+ Acer Iconia Tab A500.
+
++config LEDS_STEAMDECK
++ tristate "LED support for Steam Deck"
++ depends on LEDS_CLASS && MFD_STEAMDECK
++ help
++ This option enabled support for the status LED (next to the
++ power button) on Steam Deck
++
+ source "drivers/leds/blink/Kconfig"
+
+ comment "Flash and Torch LED drivers"
+diff --git a/drivers/leds/Makefile b/drivers/leds/Makefile
+index 4fd2f92cd198..130a1c175dde 100644
+--- a/drivers/leds/Makefile
++++ b/drivers/leds/Makefile
+@@ -75,6 +75,7 @@
+ obj-$(CONFIG_LEDS_PWM) += leds-pwm.o
+ obj-$(CONFIG_LEDS_REGULATOR) += leds-regulator.o
+ obj-$(CONFIG_LEDS_SC27XX_BLTC) += leds-sc27xx-bltc.o
++obj-$(CONFIG_LEDS_STEAMDECK) += leds-steamdeck.o
+ obj-$(CONFIG_LEDS_SUNFIRE) += leds-sunfire.o
+ obj-$(CONFIG_LEDS_SYSCON) += leds-syscon.o
+ obj-$(CONFIG_LEDS_TCA6507) += leds-tca6507.o
+diff --git a/drivers/leds/leds-steamdeck.c b/drivers/leds/leds-steamdeck.c
+new file mode 100644
+index 000000000000..686500b8de73
+--- /dev/null
++++ b/drivers/leds/leds-steamdeck.c
+@@ -0,0 +1,74 @@
++// SPDX-License-Identifier: GPL-2.0+
++
++/*
++ * Steam Deck EC MFD LED cell driver
++ *
++ * Copyright (C) 2021-2022 Valve Corporation
++ *
++ */
++
++#include <linux/acpi.h>
++#include <linux/leds.h>
++#include <linux/platform_device.h>
++
++struct steamdeck_led {
++ struct acpi_device *adev;
++ struct led_classdev cdev;
++};
++
++static int steamdeck_leds_brightness_set(struct led_classdev *cdev,
++ enum led_brightness value)
++{
++ struct steamdeck_led *sd = container_of(cdev, struct steamdeck_led,
++ cdev);
++
++ if (ACPI_FAILURE(acpi_execute_simple_method(sd->adev->handle,
++ "CHBV", value)))
+ return -EIO;
+
-+ *val = _val;
+ return 0;
+}
+
-+static int steamdeck_read_pdcs(struct steamdeck *sd, unsigned long long *pdcs)
++static int steamdeck_leds_probe(struct platform_device *pdev)
++{
++ struct device *dev = &pdev->dev;
++ struct steamdeck_led *sd;
++ int ret;
++
++ sd = devm_kzalloc(dev, sizeof(*sd), GFP_KERNEL);
++ if (!sd)
++ return -ENOMEM;
++
++ sd->adev = ACPI_COMPANION(dev->parent);
++
++ sd->cdev.name = "status:white";
++ sd->cdev.brightness_set_blocking = steamdeck_leds_brightness_set;
++ sd->cdev.max_brightness = 100;
++
++ ret = devm_led_classdev_register(dev, &sd->cdev);
++ if (ret) {
++ dev_err(dev, "Failed to register LEDs device: %d\n", ret);
++ return ret;
++ }
++
++ return 0;
++}
++
++static const struct platform_device_id steamdeck_leds_id_table[] = {
++ { .name = "steamdeck-leds" },
++ {}
++};
++MODULE_DEVICE_TABLE(platform, steamdeck_leds_id_table);
++
++static struct platform_driver steamdeck_leds_driver = {
++ .probe = steamdeck_leds_probe,
++ .driver = {
++ .name = "steamdeck-leds",
++ },
++ .id_table = steamdeck_leds_id_table,
++};
++module_platform_driver(steamdeck_leds_driver);
++
++MODULE_AUTHOR("Andrey Smirnov <andrew.smirnov@gmail.com>");
++MODULE_DESCRIPTION("Steam Deck LEDs driver");
++MODULE_LICENSE("GPL");
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Andrey Smirnov <andrew.smirnov@gmail.com>
+Date: Sun, 27 Feb 2022 14:46:08 -0800
+Subject: [PATCH] extcon: Add driver for Steam Deck
+
+(cherry picked from commit f9f2eddae582ae39d5f89c1218448fc259b90aa8)
+Signed-off-by: Cristian Ciocaltea <cristian.ciocaltea@collabora.com>
+Signed-off-by: Jan200101 <sentrycraft123@gmail.com>
+---
+ drivers/extcon/Kconfig | 7 ++
+ drivers/extcon/Makefile | 1 +
+ drivers/extcon/extcon-steamdeck.c | 180 ++++++++++++++++++++++++++++++
+ 3 files changed, 188 insertions(+)
+ create mode 100644 drivers/extcon/extcon-steamdeck.c
+
+diff --git a/drivers/extcon/Kconfig b/drivers/extcon/Kconfig
+index 290186e44e6b..4d444a9e2c1f 100644
+--- a/drivers/extcon/Kconfig
++++ b/drivers/extcon/Kconfig
+@@ -189,4 +189,11 @@ config EXTCON_USBC_TUSB320
+ Say Y here to enable support for USB Type C cable detection extcon
+ support using a TUSB320.
+
++config EXTCON_STEAMDECK
++ tristate "Steam Deck extcon support"
++ depends on MFD_STEAMDECK
++ help
++ Say Y here to enable support of USB Type C cable detection extcon
++ support on Steam Deck devices
++
+ endif
+diff --git a/drivers/extcon/Makefile b/drivers/extcon/Makefile
+index 1b390d934ca9..1c7e217f29e4 100644
+--- a/drivers/extcon/Makefile
++++ b/drivers/extcon/Makefile
+@@ -25,3 +25,4 @@ obj-$(CONFIG_EXTCON_SM5502) += extcon-sm5502.o
+ obj-$(CONFIG_EXTCON_USB_GPIO) += extcon-usb-gpio.o
+ obj-$(CONFIG_EXTCON_USBC_CROS_EC) += extcon-usbc-cros-ec.o
+ obj-$(CONFIG_EXTCON_USBC_TUSB320) += extcon-usbc-tusb320.o
++obj-$(CONFIG_EXTCON_STEAMDECK) += extcon-steamdeck.o
+diff --git a/drivers/extcon/extcon-steamdeck.c b/drivers/extcon/extcon-steamdeck.c
+new file mode 100644
+index 000000000000..74f190adc8ea
+--- /dev/null
++++ b/drivers/extcon/extcon-steamdeck.c
+@@ -0,0 +1,180 @@
++
++#include <linux/acpi.h>
++#include <linux/platform_device.h>
++#include <linux/extcon-provider.h>
++
++#define ACPI_STEAMDECK_NOTIFY_STATUS 0x80
++
++/* 0 - port connected, 1 -port disconnected */
++#define ACPI_STEAMDECK_PORT_CONNECT BIT(0)
++/* 0 - Upstream Facing Port, 1 - Downdstream Facing Port */
++#define ACPI_STEAMDECK_CUR_DATA_ROLE BIT(3)
++/*
++ * Debouncing delay to allow negotiation process to settle. 2s value
++ * was arrived at via trial and error.
++ */
++#define STEAMDECK_ROLE_SWITCH_DELAY (msecs_to_jiffies(2000))
++
++struct steamdeck_extcon {
++ struct acpi_device *adev;
++ struct delayed_work role_work;
++ struct extcon_dev *edev;
++ struct device *dev;
++};
++
++static int steamdeck_read_pdcs(struct steamdeck_extcon *sd, unsigned long long *pdcs)
+{
+ acpi_status status;
+
@@ -381,8 +673,8 @@ index 000000000000..77a6677ec19e
+
+static void steamdeck_usb_role_work(struct work_struct *work)
+{
-+ struct steamdeck *sd =
-+ container_of(work, struct steamdeck, role_work.work);
++ struct steamdeck_extcon *sd =
++ container_of(work, struct steamdeck_extcon, role_work.work);
+ unsigned long long pdcs;
+ bool usb_host;
+
@@ -404,15 +696,16 @@ index 000000000000..77a6677ec19e
+ usb_host = (pdcs & ACPI_STEAMDECK_PORT_CONNECT) ?
+ pdcs & ACPI_STEAMDECK_CUR_DATA_ROLE : false;
+
++ dev_dbg(sd->dev, "USB role is %s\n", usb_host ? "host" : "device");
+ WARN_ON(extcon_set_state_sync(sd->edev, EXTCON_USB_HOST,
+ usb_host));
-+ dev_dbg(sd->dev, "USB role is %s\n", usb_host ? "host" : "device");
++
+}
+
+static void steamdeck_notify(acpi_handle handle, u32 event, void *context)
+{
+ struct device *dev = context;
-+ struct steamdeck *sd = dev_get_drvdata(dev);
++ struct steamdeck_extcon *sd = dev_get_drvdata(dev);
+ unsigned long long pdcs;
+ unsigned long delay;
+
@@ -434,13 +727,13 @@ index 000000000000..77a6677ec19e
+ queue_delayed_work(system_long_wq, &sd->role_work, delay);
+ break;
+ default:
-+ dev_err(dev, "Unsupported event [0x%x]\n", event);
++ dev_warn(dev, "Unsupported event [0x%x]\n", event);
+ }
+}
+
+static void steamdeck_remove_notify_handler(void *data)
+{
-+ struct steamdeck *sd = data;
++ struct steamdeck_extcon *sd = data;
+
+ acpi_remove_notify_handler(sd->adev->handle, ACPI_DEVICE_NOTIFY,
+ steamdeck_notify);
@@ -457,67 +750,24 @@ index 000000000000..77a6677ec19e
+ EXTCON_NONE,
+};
+
-+static int steamdeck_probe(struct platform_device *pdev)
++static int steamdeck_extcon_probe(struct platform_device *pdev)
+{
-+ struct device *dev = &pdev->dev;
-+ struct steamdeck *sd;
++ struct device *dev = &pdev->dev;
++ struct steamdeck_extcon *sd;
+ acpi_status status;
-+ unsigned long long sta;
+ int ret;
+
-+ static const struct regmap_config regmap_config = {
-+ .reg_bits = 8,
-+ .val_bits = 8,
-+ .max_register = 255,
-+ .cache_type = REGCACHE_NONE,
-+ .reg_read = steamdeck_ddic_reg_read,
-+ };
-+
+ sd = devm_kzalloc(dev, sizeof(*sd), GFP_KERNEL);
+ if (!sd)
+ return -ENOMEM;
-+ sd->adev = ACPI_COMPANION(&pdev->dev);
-+ sd->dev = dev;
-+ platform_set_drvdata(pdev, sd);
-+ INIT_DELAYED_WORK(&sd->role_work, steamdeck_usb_role_work);
-+
-+ status = acpi_evaluate_integer(sd->adev->handle, "_STA",
-+ NULL, &sta);
-+ if (ACPI_FAILURE(status)) {
-+ dev_err(dev, "Status check failed (0x%x)\n", status);
-+ return -EINVAL;
-+ }
-+
-+ if ((sta & STEAMDECK_STA_OK) != STEAMDECK_STA_OK) {
-+ dev_err(dev, "Device is not ready\n");
-+ return -EINVAL;
-+ }
-+
-+ /*
-+ * Our ACPI interface doesn't expose a method to read current
-+ * fan target, so we use current fan speed as an
-+ * approximation.
-+ */
-+ if (steamdeck_read_fan_speed(sd, &sd->fan_target))
-+ dev_warn(dev, "Failed to read fan speed");
-+
-+ sd->hwmon = devm_hwmon_device_register_with_info(dev,
-+ "steamdeck",
-+ sd,
-+ &steamdeck_chip_info,
-+ steamdeck_groups);
-+ if (IS_ERR(sd->hwmon)) {
-+ dev_err(dev, "Failed to register HWMON device");
-+ return PTR_ERR(sd->hwmon);
-+ }
-+
-+ sd->regmap = devm_regmap_init(dev, NULL, sd, &regmap_config);
-+ if (IS_ERR(sd->regmap))
-+ dev_err(dev, "Failed to register REGMAP");
+
++ INIT_DELAYED_WORK(&sd->role_work, steamdeck_usb_role_work);
++ platform_set_drvdata(pdev, sd);
++ sd->adev = ACPI_COMPANION(dev->parent);
++ sd->dev = dev;
+ sd->edev = devm_extcon_dev_allocate(dev, steamdeck_extcon_cable);
+ if (IS_ERR(sd->edev))
-+ return -ENOMEM;
++ return PTR_ERR(sd->edev);
+
+ ret = devm_extcon_dev_register(dev, sd->edev);
+ if (ret < 0) {
@@ -545,21 +795,127 @@ index 000000000000..77a6677ec19e
+ return ret;
+}
+
-+static const struct acpi_device_id steamdeck_device_ids[] = {
-+ { "VLV0100", 0 },
-+ { "", 0 },
++static const struct platform_device_id steamdeck_extcon_id_table[] = {
++ { .name = "steamdeck-extcon" },
++ {}
+};
-+MODULE_DEVICE_TABLE(acpi, steamdeck_device_ids);
++MODULE_DEVICE_TABLE(platform, steamdeck_extcon_id_table);
+
-+static struct platform_driver steamdeck_driver = {
-+ .probe = steamdeck_probe,
++static struct platform_driver steamdeck_extcon_driver = {
++ .probe = steamdeck_extcon_probe,
+ .driver = {
-+ .name = "steamdeck",
-+ .acpi_match_table = steamdeck_device_ids,
++ .name = "steamdeck-extcon",
+ },
++ .id_table = steamdeck_extcon_id_table,
+};
-+module_platform_driver(steamdeck_driver);
++module_platform_driver(steamdeck_extcon_driver);
+
+MODULE_AUTHOR("Andrey Smirnov <andrew.smirnov@gmail.com>");
-+MODULE_DESCRIPTION("Steam Deck ACPI platform driver");
++MODULE_DESCRIPTION("Steam Deck extcon driver");
+MODULE_LICENSE("GPL");
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Andrey Smirnov <andrew.smirnov@gmail.com>
+Date: Sat, 15 Jul 2023 12:58:54 -0700
+Subject: [PATCH] hwmon: steamdeck-hwmon: Add support for max battery
+ level/rate
+
+Add support for max battery level/charge rate attributes.
+
+Signed-off-by: Andrey Smirnov <andrew.smirnov@gmail.com>
+(cherry picked from commit 50af83e8fd75dc52221edd3fb6fd7a7f70c4d8a4)
+Signed-off-by: Cristian Ciocaltea <cristian.ciocaltea@collabora.com>
+Signed-off-by: Jan200101 <sentrycraft123@gmail.com>
+---
+ drivers/hwmon/steamdeck-hwmon.c | 72 ++++++++++++++++++++++++++++++++-
+ 1 file changed, 71 insertions(+), 1 deletion(-)
+
+diff --git a/drivers/hwmon/steamdeck-hwmon.c b/drivers/hwmon/steamdeck-hwmon.c
+index fab9e9460bd4..9d0a5471b181 100644
+--- a/drivers/hwmon/steamdeck-hwmon.c
++++ b/drivers/hwmon/steamdeck-hwmon.c
+@@ -180,6 +180,76 @@ static const struct hwmon_chip_info steamdeck_hwmon_chip_info = {
+ .info = steamdeck_hwmon_info,
+ };
+
++
++static ssize_t
++steamdeck_hwmon_simple_store(struct device *dev, const char *buf, size_t count,
++ const char *method,
++ unsigned long upper_limit)
++{
++ struct steamdeck_hwmon *sd = dev_get_drvdata(dev);
++ unsigned long value;
++
++ if (kstrtoul(buf, 10, &value) || value >= upper_limit)
++ return -EINVAL;
++
++ if (ACPI_FAILURE(acpi_execute_simple_method(sd->adev->handle,
++ (char *)method, value)))
++ return -EIO;
++
++ return count;
++}
++
++static ssize_t
++steamdeck_hwmon_simple_show(struct device *dev, char *buf,
++ const char *method)
++{
++ struct steamdeck_hwmon *sd = dev_get_drvdata(dev);
++ unsigned long value;
++
++ value = steamdeck_hwmon_get(sd, method);
++ if (value < 0)
++ return value;
++
++ return sprintf(buf, "%ld\n", value);
++}
++
++#define STEAMDECK_HWMON_ATTR_RW(_name, _set_method, _get_method, \
++ _upper_limit) \
++ static ssize_t _name##_show(struct device *dev, \
++ struct device_attribute *attr, \
++ char *buf) \
++ { \
++ return steamdeck_hwmon_simple_show(dev, buf, \
++ _get_method); \
++ } \
++ static ssize_t _name##_store(struct device *dev, \
++ struct device_attribute *attr, \
++ const char *buf, size_t count) \
++ { \
++ return steamdeck_hwmon_simple_store(dev, buf, count, \
++ _set_method, \
++ _upper_limit); \
++ } \
++ static DEVICE_ATTR_RW(_name)
++
++STEAMDECK_HWMON_ATTR_RW(max_battery_charge_level, "FCBL", "SFBL", 101);
++STEAMDECK_HWMON_ATTR_RW(max_battery_charge_rate, "CHGR", "GCHR", 101);
++
++static struct attribute *steamdeck_hwmon_attributes[] = {
++ &dev_attr_max_battery_charge_level.attr,
++ &dev_attr_max_battery_charge_rate.attr,
++ NULL
++};
++
++static const struct attribute_group steamdeck_hwmon_group = {
++ .attrs = steamdeck_hwmon_attributes,
++};
++
++static const struct attribute_group *steamdeck_hwmon_groups[] = {
++ &steamdeck_hwmon_group,
++ NULL
++};
++
+ static int steamdeck_hwmon_probe(struct platform_device *pdev)
+ {
+ struct device *dev = &pdev->dev;
+@@ -195,7 +265,7 @@ static int steamdeck_hwmon_probe(struct platform_device *pdev)
+ "steamdeck_hwmon",
+ sd,
+ &steamdeck_hwmon_chip_info,
+- NULL);
++ steamdeck_hwmon_groups);
+ if (IS_ERR(hwmon)) {
+ dev_err(dev, "Failed to register HWMON device");
+ return PTR_ERR(hwmon);