diff options
author | Jan200101 <sentrycraft123@gmail.com> | 2023-08-05 23:09:13 +0200 |
---|---|---|
committer | Jan200101 <sentrycraft123@gmail.com> | 2023-08-05 23:09:13 +0200 |
commit | 5eceed518d26b9efa456b50e7b1bd9bfbb2010ac (patch) | |
tree | 5dbf336fdd470f83c8221b96e3037b310ff3f690 /SOURCES/steam-deck.patch | |
parent | 39e954e3a34034f13420b99661a66a99d02d1105 (diff) | |
download | kernel-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.patch | 898 |
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, ®map_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); |