]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
ASoC: SDCA: add function devices
authorPierre-Louis Bossart <pierre-louis.bossart@linux.intel.com>
Thu, 20 Nov 2025 15:30:20 +0000 (15:30 +0000)
committerMark Brown <broonie@kernel.org>
Thu, 20 Nov 2025 17:22:59 +0000 (17:22 +0000)
Use the auxiliary bus to register/unregister subdevices for each
function. Each function will be handled with a separate driver,
matched using a name.

If a vendor wants to override a specific function driver, they could
use a custom name to match with a custom function driver.

Signed-off-by: Pierre-Louis Bossart <pierre-louis.bossart@linux.intel.com>
Tested-by: Bard Liao <yung-chuan.liao@linux.intel.com>
Reviewed-by: Maciej Strozek <mstrozek@opensource.cirrus.com>
Reviewed-by: Peter Ujfalusi <peter.ujfalusi@linux.intel.com>
Tested-by: Richard Fitzgerald <rf@opensource.cirrus.com>
Signed-off-by: Charles Keepax <ckeepax@opensource.cirrus.com>
Link: https://patch.msgid.link/20251120153023.2105663-12-ckeepax@opensource.cirrus.com
Reviewed-by: Vinod Koul <vkoul@kernel.org>
Signed-off-by: Mark Brown <broonie@kernel.org>
include/sound/sdca.h
sound/soc/sdca/Kconfig
sound/soc/sdca/Makefile
sound/soc/sdca/sdca_function_device.c [new file with mode: 0644]
sound/soc/sdca/sdca_function_device.h [new file with mode: 0644]

index d58d60221277171f19084c6813f53943c4c71fe8..67ff3c88705d5e0fcb18e7454c747a4df1b2ef3a 100644 (file)
 struct acpi_table_swft;
 struct fwnode_handle;
 struct sdw_slave;
+struct sdca_dev;
 
 #define SDCA_MAX_FUNCTION_COUNT 8
 
 /**
  * struct sdca_function_desc - short descriptor for an SDCA Function
  * @node: firmware node for the Function.
+ * @func_dev: pointer to SDCA function device.
  * @name: Human-readable string.
  * @type: Function topology type.
  * @adr: ACPI address (used for SDCA register access).
  */
 struct sdca_function_desc {
        struct fwnode_handle *node;
+       struct sdca_dev *func_dev;
        const char *name;
        u32 type;
        u8 adr;
@@ -59,6 +62,8 @@ void sdca_lookup_functions(struct sdw_slave *slave);
 void sdca_lookup_swft(struct sdw_slave *slave);
 void sdca_lookup_interface_revision(struct sdw_slave *slave);
 bool sdca_device_quirk_match(struct sdw_slave *slave, enum sdca_quirk quirk);
+int sdca_dev_register_functions(struct sdw_slave *slave);
+void sdca_dev_unregister_functions(struct sdw_slave *slave);
 
 #else
 
@@ -69,6 +74,14 @@ static inline bool sdca_device_quirk_match(struct sdw_slave *slave, enum sdca_qu
 {
        return false;
 }
+
+static inline int sdca_dev_register_functions(struct sdw_slave *slave)
+{
+       return 0;
+}
+
+static inline void sdca_dev_unregister_functions(struct sdw_slave *slave) {}
+
 #endif
 
 #endif
index a73920d07073ea05865e4bcf8cce6bffa8696d7d..e7f36d668f1596c1f9a25362a46ed4e61a9d836c 100644 (file)
@@ -4,6 +4,7 @@ menu "SoundWire (SDCA)"
 config SND_SOC_SDCA
        tristate
        depends on ACPI
+       select AUXILIARY_BUS
        help
          This option enables support for the MIPI SoundWire Device
          Class for Audio (SDCA).
index be911c399bbdeda17d02623b1cc350ae3d6263b0..babe3fa2bb3ffc3e64b5eba41c7ecd8b7fad2bb9 100644 (file)
@@ -1,7 +1,7 @@
 # SPDX-License-Identifier: GPL-2.0-only
 
-snd-soc-sdca-y := sdca_functions.o sdca_device.o sdca_regmap.o sdca_asoc.o \
-                 sdca_ump.o
+snd-soc-sdca-y := sdca_functions.o sdca_device.o sdca_function_device.o \
+                 sdca_regmap.o sdca_asoc.o sdca_ump.o
 snd-soc-sdca-$(CONFIG_SND_SOC_SDCA_HID) += sdca_hid.o
 snd-soc-sdca-$(CONFIG_SND_SOC_SDCA_IRQ) += sdca_interrupts.o
 snd-soc-sdca-$(CONFIG_SND_SOC_SDCA_FDL) += sdca_fdl.o
diff --git a/sound/soc/sdca/sdca_function_device.c b/sound/soc/sdca/sdca_function_device.c
new file mode 100644 (file)
index 0000000..91c49d7
--- /dev/null
@@ -0,0 +1,117 @@
+// SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause)
+// Copyright(c) 2024 Intel Corporation.
+
+/*
+ * SDCA Function Device management
+ */
+
+#include <linux/acpi.h>
+#include <linux/module.h>
+#include <linux/auxiliary_bus.h>
+#include <linux/soundwire/sdw.h>
+#include <sound/sdca.h>
+#include <sound/sdca_function.h>
+#include "sdca_function_device.h"
+
+/*
+ * A SoundWire device can have multiple SDCA functions identified by
+ * their type and ADR. there can be multiple SoundWire devices per
+ * link, or multiple devices spread across multiple links. An IDA is
+ * required to identify each instance.
+ */
+static DEFINE_IDA(sdca_function_ida);
+
+static void sdca_dev_release(struct device *dev)
+{
+       struct auxiliary_device *auxdev = to_auxiliary_dev(dev);
+       struct sdca_dev *sdev = auxiliary_dev_to_sdca_dev(auxdev);
+
+       ida_free(&sdca_function_ida, auxdev->id);
+       kfree(sdev);
+}
+
+/* alloc, init and add link devices */
+static struct sdca_dev *sdca_dev_register(struct device *parent,
+                                         struct sdca_function_desc *function_desc)
+{
+       struct sdca_dev *sdev;
+       struct auxiliary_device *auxdev;
+       int ret;
+       int rc;
+
+       sdev = kzalloc(sizeof(*sdev), GFP_KERNEL);
+       if (!sdev)
+               return ERR_PTR(-ENOMEM);
+
+       auxdev = &sdev->auxdev;
+       auxdev->name = function_desc->name;
+       auxdev->dev.parent = parent;
+       auxdev->dev.fwnode = function_desc->node;
+       auxdev->dev.release = sdca_dev_release;
+
+       sdev->function.desc = function_desc;
+
+       rc = ida_alloc(&sdca_function_ida, GFP_KERNEL);
+       if (rc < 0) {
+               kfree(sdev);
+               return ERR_PTR(rc);
+       }
+       auxdev->id = rc;
+
+       /* now follow the two-step init/add sequence */
+       ret = auxiliary_device_init(auxdev);
+       if (ret < 0) {
+               dev_err(parent, "failed to initialize SDCA function dev %s\n",
+                       function_desc->name);
+               ida_free(&sdca_function_ida, auxdev->id);
+               kfree(sdev);
+               return ERR_PTR(ret);
+       }
+
+       ret = auxiliary_device_add(auxdev);
+       if (ret < 0) {
+               dev_err(parent, "failed to add SDCA function dev %s\n",
+                       sdev->auxdev.name);
+               /* sdev will be freed with the put_device() and .release sequence */
+               auxiliary_device_uninit(&sdev->auxdev);
+               return ERR_PTR(ret);
+       }
+
+       return sdev;
+}
+
+static void sdca_dev_unregister(struct sdca_dev *sdev)
+{
+       auxiliary_device_delete(&sdev->auxdev);
+       auxiliary_device_uninit(&sdev->auxdev);
+}
+
+int sdca_dev_register_functions(struct sdw_slave *slave)
+{
+       struct sdca_device_data *sdca_data = &slave->sdca_data;
+       int i;
+
+       for (i = 0; i < sdca_data->num_functions; i++) {
+               struct sdca_dev *func_dev;
+
+               func_dev = sdca_dev_register(&slave->dev,
+                                            &sdca_data->function[i]);
+               if (!func_dev)
+                       return -ENODEV;
+
+               sdca_data->function[i].func_dev = func_dev;
+       }
+
+       return 0;
+}
+EXPORT_SYMBOL_NS(sdca_dev_register_functions, "SND_SOC_SDCA");
+
+void sdca_dev_unregister_functions(struct sdw_slave *slave)
+{
+       struct sdca_device_data *sdca_data = &slave->sdca_data;
+       int i;
+
+       for (i = 0; i < sdca_data->num_functions; i++)
+               sdca_dev_unregister(sdca_data->function[i].func_dev);
+}
+EXPORT_SYMBOL_NS(sdca_dev_unregister_functions, "SND_SOC_SDCA");
diff --git a/sound/soc/sdca/sdca_function_device.h b/sound/soc/sdca/sdca_function_device.h
new file mode 100644 (file)
index 0000000..5adf755
--- /dev/null
@@ -0,0 +1,15 @@
+/* SPDX-License-Identifier: (GPL-2.0 OR BSD-3-Clause) */
+/* Copyright(c) 2024 Intel Corporation. */
+
+#ifndef __SDCA_FUNCTION_DEVICE_H
+#define __SDCA_FUNCTION_DEVICE_H
+
+struct sdca_dev {
+       struct auxiliary_device auxdev;
+       struct sdca_function_data function;
+};
+
+#define auxiliary_dev_to_sdca_dev(auxiliary_dev)               \
+       container_of(auxiliary_dev, struct sdca_dev, auxdev)
+
+#endif