diff mbox series

[04/21] ASoC: amd: acp70: add logic for scanning acp child devices

Message ID 20241219054857.2070420-5-Vijendar.Mukunda@amd.com (mailing list archive)
State New
Headers show
Series ASoC: amd: acp70: add soundwire and acp pdm support | expand

Commit Message

Vijendar Mukunda Dec. 19, 2024, 5:48 a.m. UTC
Based on acp pin configuration, add logic for scanning child devices
under acp pci device acpi scope.

Signed-off-by: Vijendar Mukunda <Vijendar.Mukunda@amd.com>
---
 sound/soc/amd/acp70/acp70.h     |  43 +++++++++++++
 sound/soc/amd/acp70/pci-acp70.c | 103 ++++++++++++++++++++++++++++++++
 2 files changed, 146 insertions(+)
diff mbox series

Patch

diff --git a/sound/soc/amd/acp70/acp70.h b/sound/soc/amd/acp70/acp70.h
index b6f0f75de91d..1b20de75876a 100644
--- a/sound/soc/amd/acp70/acp70.h
+++ b/sound/soc/amd/acp70/acp70.h
@@ -5,6 +5,7 @@ 
  * Copyright (C) 2024 Advanced Micro Devices, Inc. All rights reserved.
  */
 
+#include <linux/soundwire/sdw_amd.h>
 #include <sound/acp70_chip_offset_byte.h>
 
 #define ACP_DEVICE_ID		0x15E2
@@ -28,21 +29,63 @@ 
 #define ACP_EXT_INTR_STAT_CLEAR_MASK	0xFFFFFFFF
 #define ACP_ERROR_IRQ			BIT(29)
 
+#define ACP_DMIC_DEV			2
+#define ACP70_DMIC_ADDR			2
+#define ACP70_SDW_ADDR			5
+#define AMD_SDW_MAX_MANAGERS		2
+
+enum acp_config {
+	ACP_CONFIG_0 = 0,
+	ACP_CONFIG_1,
+	ACP_CONFIG_2,
+	ACP_CONFIG_3,
+	ACP_CONFIG_4,
+	ACP_CONFIG_5,
+	ACP_CONFIG_6,
+	ACP_CONFIG_7,
+	ACP_CONFIG_8,
+	ACP_CONFIG_9,
+	ACP_CONFIG_10,
+	ACP_CONFIG_11,
+	ACP_CONFIG_12,
+	ACP_CONFIG_13,
+	ACP_CONFIG_14,
+	ACP_CONFIG_15,
+	ACP_CONFIG_16,
+	ACP_CONFIG_17,
+	ACP_CONFIG_18,
+	ACP_CONFIG_19,
+	ACP_CONFIG_20,
+};
+
 /**
  * struct acp70_dev_data - acp pci driver context
  * @acp70_base: acp mmio base
  * @acp_lock: used to protect acp common registers
+ * @info: SoundWire AMD information found in ACPI tables
+ * @sdw: SoundWire context for all SoundWire manager instances
  * @addr: pci ioremap address
  * @reg_range: ACP reigister range
  * @acp_rev : ACP PCI revision id
+ * @is_sdw_dev: flag set to true when any SoundWire manager instances are available
+ * @is_pdm_dev: flag set to true when ACP PDM controller exists
+ * @is_pdm_config: flat set to true when PDM configuration is selected from BIOS
+ * @is_sdw_config: flag set to true when SDW configuration is selected from BIOS
  */
 
 struct acp70_dev_data {
 	void __iomem *acp70_base;
 	struct mutex acp_lock; /* protect shared registers */
+	struct sdw_amd_acpi_info info;
+	/* sdw context allocated by SoundWire driver */
+	struct sdw_amd_ctx *sdw;
 	u32 addr;
 	u32 reg_range;
 	u32 acp_rev;
+	bool is_sdw_dev;
+	bool is_pdm_dev;
+	bool is_pdm_config;
+	bool is_sdw_config;
 };
 
 int snd_amd_acp_find_config(struct pci_dev *pci);
diff --git a/sound/soc/amd/acp70/pci-acp70.c b/sound/soc/amd/acp70/pci-acp70.c
index a98407fa2cd2..d360dfc396ad 100644
--- a/sound/soc/amd/acp70/pci-acp70.c
+++ b/sound/soc/amd/acp70/pci-acp70.c
@@ -5,6 +5,8 @@ 
  * Copyright 2024 Advanced Micro Devices, Inc.
  */
 
+#include <linux/acpi.h>
+#include <linux/bitops.h>
 #include <linux/delay.h>
 #include <linux/io.h>
 #include <linux/iopoll.h>
@@ -93,6 +95,99 @@  static int acp70_deinit(void __iomem *acp_base, struct device *dev)
 	return 0;
 }
 
+#if IS_ENABLED(CONFIG_SND_SOC_AMD_SOUNDWIRE)
+static int acp_scan_sdw_devices(struct device *dev, u64 addr)
+{
+	struct acpi_device *sdw_dev;
+	struct acp70_dev_data *acp_data;
+
+	acp_data = dev_get_drvdata(dev);
+	if (!addr)
+		return -ENODEV;
+
+	sdw_dev = acpi_find_child_device(ACPI_COMPANION(dev), addr, 0);
+	if (!sdw_dev) {
+		pr_err("%s No SoundWire devices found\n", __func__);
+		return -ENODEV;
+	}
+
+	acp_data->info.handle = sdw_dev->handle;
+	acp_data->info.count = AMD_SDW_MAX_MANAGERS;
+	return amd_sdw_scan_controller(&acp_data->info);
+}
+#else
+static int acp_scan_sdw_devices(struct device *dev, u64 addr)
+{
+	return 0;
+}
+#endif
+
+static int get_acp70_device_config(struct pci_dev *pci, struct acp70_dev_data *acp_data)
+{
+	struct acpi_device *pdm_dev;
+	const union acpi_object *obj;
+	u32 config;
+	int ret;
+	bool is_dmic_dev = false;
+	bool is_sdw_dev = false;
+
+	config = readl(acp_data->acp70_base + ACP_PIN_CONFIG);
+	dev_dbg(&pci->dev, "ACP_PIN_CONFIG:0x%x\n", config);
+	switch (config) {
+	case ACP_CONFIG_4:
+	case ACP_CONFIG_5:
+	case ACP_CONFIG_10:
+	case ACP_CONFIG_11:
+	case ACP_CONFIG_20:
+		acp_data->is_pdm_config = true;
+		break;
+	case ACP_CONFIG_2:
+	case ACP_CONFIG_3:
+	case ACP_CONFIG_16:
+		acp_data->is_sdw_config = true;
+		break;
+	case ACP_CONFIG_6:
+	case ACP_CONFIG_7:
+	case ACP_CONFIG_12:
+	case ACP_CONFIG_8:
+	case ACP_CONFIG_13:
+	case ACP_CONFIG_14:
+	case ACP_CONFIG_17:
+	case ACP_CONFIG_18:
+	case ACP_CONFIG_19:
+		acp_data->is_pdm_config = true;
+		acp_data->is_sdw_config = true;
+		break;
+	default:
+		break;
+	}
+
+	if (acp_data->is_pdm_config) {
+		pdm_dev = acpi_find_child_device(ACPI_COMPANION(&pci->dev), ACP70_DMIC_ADDR, 0);
+		if (pdm_dev) {
+			/* is_dmic_dev flag will be set when ACP PDM controller device exists */
+			if (!acpi_dev_get_property(pdm_dev, "acp-audio-device-type",
+						   ACPI_TYPE_INTEGER, &obj) &&
+						   obj->integer.value == ACP_DMIC_DEV)
+				is_dmic_dev = true;
+		}
+	}
+
+	if (acp_data->is_sdw_config) {
+		ret = acp_scan_sdw_devices(&pci->dev, ACP70_SDW_ADDR);
+		if (!ret && acp_data->info.link_mask)
+			is_sdw_dev = true;
+	}
+
+	acp_data->is_pdm_dev = is_dmic_dev;
+	acp_data->is_sdw_dev = is_sdw_dev;
+	dev_dbg(&pci->dev, "is_pdm_dev:%d is_sdw_dev:%d\n", is_dmic_dev, is_sdw_dev);
+	if (!is_dmic_dev && !is_sdw_dev) {
+		dev_dbg(&pci->dev, "No PDM or SoundWire manager devices found\n");
+		return -ENODEV;
+	}
+	return 0;
+}
 static int snd_acp70_probe(struct pci_dev *pci,
 			   const struct pci_device_id *pci_id)
 {
@@ -148,6 +243,13 @@  static int snd_acp70_probe(struct pci_dev *pci,
 	if (ret)
 		goto release_regions;
 
+	ret = get_acp70_device_config(pci, adata);
+	/* ACP PCI driver probe should be continued even PDM or SoundWire Devices are not found */
+	if (ret) {
+		dev_dbg(&pci->dev, "get acp device config failed:%d\n", ret);
+		goto skip_pdev_creation;
+	}
+skip_pdev_creation:
 	return 0;
 release_regions:
 	pci_release_regions(pci);
@@ -189,4 +291,5 @@  module_pci_driver(ps_acp70_driver);
 
 MODULE_AUTHOR("Vijendar.Mukunda@amd.com");
 MODULE_DESCRIPTION("AMD ACP7.0 PCI driver");
+MODULE_IMPORT_NS("SND_AMD_SOUNDWIRE_ACPI");
 MODULE_LICENSE("GPL");