commit
5f23ce5ee5
10 changed files with 1192 additions and 283 deletions
|
@ -1,6 +1,6 @@
|
|||
diff -rupN alsa-ucm-conf.orig/ucm2/AMD/acp5x/acp5x.conf alsa-ucm-conf/ucm2/AMD/acp5x/acp5x.conf
|
||||
--- alsa-ucm-conf.orig/ucm2/AMD/acp5x/acp5x.conf 1969-12-31 19:00:00.000000000 -0500
|
||||
+++ alsa-ucm-conf/ucm2/AMD/acp5x/acp5x.conf 2023-01-12 18:33:34.943769783 -0500
|
||||
+++ alsa-ucm-conf/ucm2/AMD/acp5x/acp5x.conf 2023-01-14 09:14:14.639236230 -0500
|
||||
@@ -0,0 +1,53 @@
|
||||
+Syntax 6
|
||||
+
|
||||
|
@ -57,7 +57,7 @@ diff -rupN alsa-ucm-conf.orig/ucm2/AMD/acp5x/acp5x.conf alsa-ucm-conf/ucm2/AMD/a
|
|||
+}
|
||||
diff -rupN alsa-ucm-conf.orig/ucm2/AMD/acp5x/HiFi.conf alsa-ucm-conf/ucm2/AMD/acp5x/HiFi.conf
|
||||
--- alsa-ucm-conf.orig/ucm2/AMD/acp5x/HiFi.conf 1969-12-31 19:00:00.000000000 -0500
|
||||
+++ alsa-ucm-conf/ucm2/AMD/acp5x/HiFi.conf 2023-01-12 18:33:34.943769783 -0500
|
||||
+++ alsa-ucm-conf/ucm2/AMD/acp5x/HiFi.conf 2023-01-14 09:14:38.723138315 -0500
|
||||
@@ -0,0 +1,146 @@
|
||||
+Macro.apcmremap.CtlRemapMonoToStereoVolSw {
|
||||
+ Type Volume
|
||||
|
@ -205,9 +205,9 @@ diff -rupN alsa-ucm-conf.orig/ucm2/AMD/acp5x/HiFi.conf alsa-ucm-conf/ucm2/AMD/ac
|
|||
+ JackControl "Headset Mic Jack"
|
||||
+ }
|
||||
+}
|
||||
diff -rupN alsa-ucm-conf.orig/ucm2/conf.d/acp5x/acp5x.conf alsa-ucm-conf/ucm2/conf.d/acp5x/acp5x.conf
|
||||
--- alsa-ucm-conf.orig/ucm2/conf.d/acp5x/acp5x.conf 1969-12-31 19:00:00.000000000 -0500
|
||||
+++ alsa-ucm-conf/ucm2/conf.d/acp5x/acp5x.conf 2023-01-12 18:34:26.387634234 -0500
|
||||
diff -rupN alsa-ucm-conf.orig/ucm2/conf.d/acp5x/Valve-Jupiter-1.conf alsa-ucm-conf/ucm2/conf.d/acp5x/Valve-Jupiter-1.conf
|
||||
--- alsa-ucm-conf.orig/ucm2/conf.d/acp5x/Valve-Jupiter-1.conf 1969-12-31 19:00:00.000000000 -0500
|
||||
+++ alsa-ucm-conf/ucm2/conf.d/acp5x/Valve-Jupiter-1.conf 2023-01-14 09:14:14.639236230 -0500
|
||||
@@ -0,0 +1,53 @@
|
||||
+Syntax 6
|
||||
+
|
||||
|
|
|
@ -2,11 +2,11 @@
|
|||
# Copyright (C) 2021-present Fewtarius (https://github.com/fewtarius)
|
||||
|
||||
PKG_NAME="gamecontrollerdb"
|
||||
PKG_VERSION="b681748d6dbf2f735f94bd798b8e42042f211f56"
|
||||
PKG_VERSION="e3f82eb"
|
||||
PKG_ARCH="any"
|
||||
PKG_LICENSE="GPL"
|
||||
PKG_DEPENDS_TARGET="toolchain SDL2"
|
||||
PKG_SITE="https://github.com/JustEnoughLinuxOS/SDL_GameControllerDB"
|
||||
PKG_SITE="https://github.com/gabomdq/SDL_GameControllerDB.git"
|
||||
PKG_URL="${PKG_SITE}.git"
|
||||
PKG_SECTION="tools"
|
||||
PKG_SHORTDESC="SDL Game Controller DB"
|
||||
|
|
|
@ -0,0 +1,32 @@
|
|||
input_driver = "udev"
|
||||
input_device = "Steam Controller"
|
||||
input_vendor_id = "10462"
|
||||
input_product_id = "4613"
|
||||
input_b_btn = "5"
|
||||
input_y_btn = "7"
|
||||
input_select_btn = "13"
|
||||
input_start_btn = "14"
|
||||
input_up_btn = "20"
|
||||
input_down_btn = "21"
|
||||
input_left_btn = "22"
|
||||
input_right_btn = "23"
|
||||
input_a_btn = "6"
|
||||
input_x_btn = "8"
|
||||
input_l_btn = "9"
|
||||
input_r_btn = "10"
|
||||
input_l2_btn = "11"
|
||||
input_r2_btn = "2"
|
||||
input_l3_btn = "16"
|
||||
input_r3_axis = "-1"
|
||||
input_l_x_plus_axis = "+0"
|
||||
input_l_x_minus_axis = "-0"
|
||||
input_l_y_plus_axis = "+1"
|
||||
input_l_y_minus_axis = "-1"
|
||||
input_r_x_plus_axis = "+3"
|
||||
input_r_x_minus_axis = "-3"
|
||||
input_r_y_plus_axis = "+4"
|
||||
input_r_y_minus_axis = "-4"
|
||||
input_l2_axis = "+4"
|
||||
input_r2_axis = "+2"
|
||||
input_r3_btn = "17"
|
||||
input_gun_trigger_mbtn = "1"
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
539
packages/kernel/linux/patches/X86_64/006-steamdeck-acpi.patch
Normal file
539
packages/kernel/linux/patches/X86_64/006-steamdeck-acpi.patch
Normal file
|
@ -0,0 +1,539 @@
|
|||
diff --git a/drivers/platform/x86/Kconfig b/drivers/platform/x86/Kconfig
|
||||
index f022c220b75416d79aeddd6177c90e1e8b54457e..340ee875ebeec82d9a73301923b63fab391c79b6 100644
|
||||
--- a/drivers/platform/x86/Kconfig
|
||||
+++ b/drivers/platform/x86/Kconfig
|
||||
@@ -1320,6 +1320,13 @@ config JUPITER
|
||||
This driver exposes various bits of Jupiter platform specific
|
||||
ACPI functionality.
|
||||
|
||||
+config STEAMDECK
|
||||
+ tristate "Valve Steam Deck platform driver"
|
||||
+ depends on X86_64
|
||||
+ help
|
||||
+ This driver exposes various bits of Steam Deck specific ACPI
|
||||
+ functionality.
|
||||
+
|
||||
endif # X86_PLATFORM_DEVICES
|
||||
|
||||
config PMC_ATOM
|
||||
diff --git a/drivers/platform/x86/Makefile b/drivers/platform/x86/Makefile
|
||||
index ea069a8853958ff1b62ffb5361be443fb386b30d..483d755d4a4285f0abdc2d27dc2835ae76f4c211 100644
|
||||
--- a/drivers/platform/x86/Makefile
|
||||
+++ b/drivers/platform/x86/Makefile
|
||||
@@ -145,1 +145,3 @@
|
||||
obj-$(CONFIG_X86_INTEL_LPSS) += pmc_atom.o
|
||||
+
|
||||
+obj-$(CONFIG_STEAMDECK) += steamdeck.o
|
||||
diff --git a/drivers/platform/x86/steamdeck.c b/drivers/platform/x86/steamdeck.c
|
||||
new file mode 100644
|
||||
index 0000000000000000000000000000000000000000..c6b0b4257a213c2528ee158ba20df3ee012955af
|
||||
--- /dev/null
|
||||
+++ b/drivers/platform/x86/steamdeck.c
|
||||
@@ -0,0 +1,507 @@
|
||||
+// SPDX-License-Identifier: GPL-2.0+
|
||||
+
|
||||
+/*
|
||||
+ * Steam Deck ACPI platform 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>
|
||||
+
|
||||
+#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 {
|
||||
+ 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 *sd = dev_get_drvdata(dev); \
|
||||
+ unsigned long long val; \
|
||||
+ \
|
||||
+ if (ACPI_FAILURE(acpi_evaluate_integer( \
|
||||
+ sd->adev->handle, \
|
||||
+ _method, NULL, &val))) \
|
||||
+ return -EIO; \
|
||||
+ \
|
||||
+ 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 struct attribute *steamdeck_attrs[] = {
|
||||
+ &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,
|
||||
+
|
||||
+ &dev_attr_firmware_version.attr,
|
||||
+ &dev_attr_board_id.attr,
|
||||
+ &dev_attr_pdcs.attr,
|
||||
+
|
||||
+ NULL
|
||||
+};
|
||||
+
|
||||
+ATTRIBUTE_GROUPS(steamdeck);
|
||||
+
|
||||
+static int steamdeck_read_fan_speed(struct steamdeck *jup, long *speed)
|
||||
+{
|
||||
+ unsigned long long val;
|
||||
+
|
||||
+ if (ACPI_FAILURE(acpi_evaluate_integer(jup->adev->handle,
|
||||
+ "FANR", NULL, &val)))
|
||||
+ return -EIO;
|
||||
+
|
||||
+ *speed = val;
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+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;
|
||||
+
|
||||
+ switch (type) {
|
||||
+ case hwmon_temp:
|
||||
+ if (attr != hwmon_temp_input)
|
||||
+ return -EOPNOTSUPP;
|
||||
+
|
||||
+ if (ACPI_FAILURE(acpi_evaluate_integer(sd->adev->handle,
|
||||
+ "BATT", NULL, &val)))
|
||||
+ return -EIO;
|
||||
+ /*
|
||||
+ * Assuming BATT returns deg C we need to mutiply it
|
||||
+ * by 1000 to convert to mC
|
||||
+ */
|
||||
+ *out = val * 1000;
|
||||
+ break;
|
||||
+ case hwmon_fan:
|
||||
+ switch (attr) {
|
||||
+ case hwmon_fan_input:
|
||||
+ return steamdeck_read_fan_speed(sd, out);
|
||||
+ case hwmon_fan_target:
|
||||
+ *out = sd->fan_target;
|
||||
+ break;
|
||||
+ case hwmon_fan_fault:
|
||||
+ if (ACPI_FAILURE(acpi_evaluate_integer(
|
||||
+ sd->adev->handle,
|
||||
+ "FANC", NULL, &val)))
|
||||
+ return -EIO;
|
||||
+ /*
|
||||
+ * FANC (Fan check):
|
||||
+ * 0: Abnormal
|
||||
+ * 1: Normal
|
||||
+ */
|
||||
+ *out = !val;
|
||||
+ 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) {
|
||||
+ 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 *sd = dev_get_drvdata(dev);
|
||||
+
|
||||
+ if (type != hwmon_fan ||
|
||||
+ attr != hwmon_fan_target)
|
||||
+ return -EOPNOTSUPP;
|
||||
+
|
||||
+ val = clamp_val(val, 0, U16_MAX);
|
||||
+ sd->fan_target = val;
|
||||
+
|
||||
+ 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_info[] = {
|
||||
+ 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_chip_info = {
|
||||
+ .ops = &steamdeck_hwmon_ops,
|
||||
+ .info = steamdeck_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)
|
||||
+{
|
||||
+ 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;
|
||||
+
|
||||
+ obj.integer.value = reg;
|
||||
+
|
||||
+ if (ACPI_FAILURE(acpi_evaluate_integer(sd->adev->handle,
|
||||
+ "RDDI", &arg_list, &_val)))
|
||||
+ return -EIO;
|
||||
+
|
||||
+ *val = _val;
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+static int steamdeck_read_pdcs(struct steamdeck *sd, unsigned long long *pdcs)
|
||||
+{
|
||||
+ acpi_status status;
|
||||
+
|
||||
+ status = acpi_evaluate_integer(sd->adev->handle, "PDCS", NULL, pdcs);
|
||||
+ if (ACPI_FAILURE(status)) {
|
||||
+ dev_err(sd->dev, "PDCS evaluation failed: %s\n",
|
||||
+ acpi_format_exception(status));
|
||||
+ return -EIO;
|
||||
+ }
|
||||
+
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+static void steamdeck_usb_role_work(struct work_struct *work)
|
||||
+{
|
||||
+ struct steamdeck *sd =
|
||||
+ container_of(work, struct steamdeck, role_work.work);
|
||||
+ unsigned long long pdcs;
|
||||
+ bool usb_host;
|
||||
+
|
||||
+ if (steamdeck_read_pdcs(sd, &pdcs))
|
||||
+ return;
|
||||
+
|
||||
+ /*
|
||||
+ * We only care about these two
|
||||
+ */
|
||||
+ pdcs &= ACPI_STEAMDECK_PORT_CONNECT | ACPI_STEAMDECK_CUR_DATA_ROLE;
|
||||
+
|
||||
+ /*
|
||||
+ * For "connect" events our role is determined by a bit in
|
||||
+ * PDCS, for "disconnect" we switch to being a gadget
|
||||
+ * unconditionally. The thinking for the latter is we don't
|
||||
+ * want to start acting as a USB host until we get
|
||||
+ * confirmation from the firmware that we are a USB host
|
||||
+ */
|
||||
+ usb_host = (pdcs & ACPI_STEAMDECK_PORT_CONNECT) ?
|
||||
+ pdcs & ACPI_STEAMDECK_CUR_DATA_ROLE : false;
|
||||
+
|
||||
+ 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);
|
||||
+ unsigned long long pdcs;
|
||||
+ unsigned long delay;
|
||||
+
|
||||
+ switch (event) {
|
||||
+ case ACPI_STEAMDECK_NOTIFY_STATUS:
|
||||
+ if (steamdeck_read_pdcs(sd, &pdcs))
|
||||
+ return;
|
||||
+ /*
|
||||
+ * We process "disconnect" events immediately and
|
||||
+ * "connect" events with a delay to give the HW time
|
||||
+ * to settle. For example attaching USB hub (at least
|
||||
+ * for HW used for testing) will generate intermediary
|
||||
+ * event with "host" bit not set, followed by the one
|
||||
+ * that does have it set.
|
||||
+ */
|
||||
+ delay = (pdcs & ACPI_STEAMDECK_PORT_CONNECT) ?
|
||||
+ STEAMDECK_ROLE_SWITCH_DELAY : 0;
|
||||
+
|
||||
+ queue_delayed_work(system_long_wq, &sd->role_work, delay);
|
||||
+ break;
|
||||
+ default:
|
||||
+ dev_warn(dev, "Unsupported event [0x%x]\n", event);
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
+static void steamdeck_remove_notify_handler(void *data)
|
||||
+{
|
||||
+ struct steamdeck *sd = data;
|
||||
+
|
||||
+ acpi_remove_notify_handler(sd->adev->handle, ACPI_DEVICE_NOTIFY,
|
||||
+ steamdeck_notify);
|
||||
+ cancel_delayed_work_sync(&sd->role_work);
|
||||
+}
|
||||
+
|
||||
+static const unsigned int steamdeck_extcon_cable[] = {
|
||||
+ EXTCON_USB,
|
||||
+ EXTCON_USB_HOST,
|
||||
+ EXTCON_CHG_USB_SDP,
|
||||
+ EXTCON_CHG_USB_CDP,
|
||||
+ EXTCON_CHG_USB_DCP,
|
||||
+ EXTCON_CHG_USB_ACA,
|
||||
+ EXTCON_NONE,
|
||||
+};
|
||||
+
|
||||
+static int steamdeck_probe(struct platform_device *pdev)
|
||||
+{
|
||||
+ struct device *dev = &pdev->dev;
|
||||
+ struct steamdeck *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");
|
||||
+
|
||||
+ sd->edev = devm_extcon_dev_allocate(dev, steamdeck_extcon_cable);
|
||||
+ if (IS_ERR(sd->edev))
|
||||
+ return PTR_ERR(sd->edev);
|
||||
+
|
||||
+ ret = devm_extcon_dev_register(dev, sd->edev);
|
||||
+ if (ret < 0) {
|
||||
+ dev_err(dev, "Failed to register extcon device: %d\n", ret);
|
||||
+ return ret;
|
||||
+ }
|
||||
+
|
||||
+ /*
|
||||
+ * Set initial role value
|
||||
+ */
|
||||
+ queue_delayed_work(system_long_wq, &sd->role_work, 0);
|
||||
+ flush_delayed_work(&sd->role_work);
|
||||
+
|
||||
+ status = acpi_install_notify_handler(sd->adev->handle,
|
||||
+ ACPI_DEVICE_NOTIFY,
|
||||
+ steamdeck_notify,
|
||||
+ dev);
|
||||
+ if (ACPI_FAILURE(status)) {
|
||||
+ dev_err(dev, "Error installing ACPI notify handler\n");
|
||||
+ return -EIO;
|
||||
+ }
|
||||
+
|
||||
+ ret = devm_add_action_or_reset(dev, steamdeck_remove_notify_handler,
|
||||
+ sd);
|
||||
+ return ret;
|
||||
+}
|
||||
+
|
||||
+static const struct acpi_device_id steamdeck_device_ids[] = {
|
||||
+ { "VLV0100", 0 },
|
||||
+ { "", 0 },
|
||||
+};
|
||||
+MODULE_DEVICE_TABLE(acpi, steamdeck_device_ids);
|
||||
+
|
||||
+static struct platform_driver steamdeck_driver = {
|
||||
+ .probe = steamdeck_probe,
|
||||
+ .driver = {
|
||||
+ .name = "steamdeck",
|
||||
+ .acpi_match_table = steamdeck_device_ids,
|
||||
+ },
|
||||
+};
|
||||
+module_platform_driver(steamdeck_driver);
|
||||
+
|
||||
+MODULE_AUTHOR("Andrey Smirnov <andrew.smirnov@gmail.com>");
|
||||
+MODULE_DESCRIPTION("Steam Deck ACPI platform driver");
|
||||
+MODULE_LICENSE("GPL");
|
|
@ -0,0 +1,43 @@
|
|||
#!/bin/bash
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
# Copyright (C) 2021-present Fewtarius (https://github.com/fewtarius)
|
||||
|
||||
. /etc/profile
|
||||
|
||||
|
||||
### Set a custom device so we don't clobber it.
|
||||
set-audio set "CUSTOM (UNMANAGED)"
|
||||
set-audio esset "PCM"
|
||||
### Temporary workaround until we can fix it correctly
|
||||
cat <<EOF >/storage/.config/asound.conf
|
||||
ctl.!default {
|
||||
type hw
|
||||
card 1
|
||||
}
|
||||
|
||||
pcm.!default {
|
||||
type plug
|
||||
slave.pcm "softvol"
|
||||
}
|
||||
|
||||
pcm.softvol {
|
||||
type softvol
|
||||
slave.pcm "dmixer"
|
||||
control {
|
||||
name "PCM"
|
||||
card 1
|
||||
}
|
||||
}
|
||||
|
||||
pcm.dmixer {
|
||||
type dmix
|
||||
ipc_key 1024
|
||||
slave {
|
||||
pcm "hw:1,1"
|
||||
period_time 0
|
||||
period_size 4096
|
||||
buffer_size 131072
|
||||
rate 176400
|
||||
}
|
||||
}
|
||||
EOF
|
File diff suppressed because it is too large
Load diff
Loading…
Reference in a new issue