177 lines
4.7 KiB
Diff
177 lines
4.7 KiB
Diff
From 947c953bf24af62c58e9eb0bab533816882b83a3 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 5/6] 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: Alexandre Frade <kernel@xanmod.org>
|
|
---
|
|
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
|
|
|
|
--- a/drivers/mfd/Kconfig
|
|
+++ b/drivers/mfd/Kconfig
|
|
@@ -2402,5 +2402,16 @@ config MFD_RSMU_SPI
|
|
Additional drivers must be enabled in order to use the functionality
|
|
of the device.
|
|
|
|
+config MFD_STEAMDECK
|
|
+ tristate "Valve Steam Deck"
|
|
+ select MFD_CORE
|
|
+ depends on ACPI
|
|
+ depends on X86_64 || COMPILE_TEST
|
|
+ help
|
|
+ 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
|
|
--- a/drivers/mfd/Makefile
|
|
+++ b/drivers/mfd/Makefile
|
|
@@ -289,3 +289,5 @@ obj-$(CONFIG_MFD_ATC260X_I2C) += atc260x
|
|
|
|
obj-$(CONFIG_MFD_RSMU_I2C) += rsmu_i2c.o rsmu_core.o
|
|
obj-$(CONFIG_MFD_RSMU_SPI) += rsmu_spi.o rsmu_core.o
|
|
+
|
|
+obj-$(CONFIG_MFD_STEAMDECK) += steamdeck.o
|
|
--- /dev/null
|
|
+++ b/drivers/mfd/steamdeck.c
|
|
@@ -0,0 +1,127 @@
|
|
+// SPDX-License-Identifier: GPL-2.0+
|
|
+
|
|
+/*
|
|
+ * Steam Deck EC MFD core driver
|
|
+ *
|
|
+ * Copyright (C) 2021-2022 Valve Corporation
|
|
+ *
|
|
+ */
|
|
+
|
|
+#include <linux/acpi.h>
|
|
+#include <linux/platform_device.h>
|
|
+#include <linux/mfd/core.h>
|
|
+
|
|
+#define STEAMDECK_STA_OK \
|
|
+ (ACPI_STA_DEVICE_ENABLED | \
|
|
+ ACPI_STA_DEVICE_PRESENT | \
|
|
+ ACPI_STA_DEVICE_FUNCTIONING)
|
|
+
|
|
+struct steamdeck {
|
|
+ struct acpi_device *adev;
|
|
+ struct device *dev;
|
|
+};
|
|
+
|
|
+#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");
|
|
+
|
|
+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)
|
|
+{
|
|
+ struct steamdeck *sd = data;
|
|
+
|
|
+ sysfs_remove_groups(&sd->dev->kobj, steamdeck_groups);
|
|
+}
|
|
+
|
|
+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;
|
|
+
|
|
+ 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);
|
|
+
|
|
+ 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 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 EC MFD core driver");
|
|
+MODULE_LICENSE("GPL");
|