summaryrefslogtreecommitdiff
path: root/sound/soc/intel/common/sof-function-topology-lib.c
blob: 90fe7aa3df1cb461d4b17eb18fc7de1199278ac2 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
// SPDX-License-Identifier: (GPL-2.0-only OR BSD-3-Clause)
//
// This file is provided under a dual BSD/GPLv2 license.  When using or
// redistributing this file, you may do so under either license.
//
// Copyright(c) 2025 Intel Corporation.
//

#include <linux/device.h>
#include <linux/errno.h>
#include <linux/firmware.h>
#include <sound/soc.h>
#include <sound/soc-acpi.h>
#include "sof-function-topology-lib.h"

enum tplg_device_id {
	TPLG_DEVICE_SDCA_JACK,
	TPLG_DEVICE_SDCA_AMP,
	TPLG_DEVICE_SDCA_MIC,
	TPLG_DEVICE_INTEL_PCH_DMIC,
	TPLG_DEVICE_HDMI,
	TPLG_DEVICE_MAX
};

#define SDCA_DEVICE_MASK (BIT(TPLG_DEVICE_SDCA_JACK) | BIT(TPLG_DEVICE_SDCA_AMP) | \
			  BIT(TPLG_DEVICE_SDCA_MIC))

#define SOF_INTEL_PLATFORM_NAME_MAX 4

int sof_sdw_get_tplg_files(struct snd_soc_card *card, const struct snd_soc_acpi_mach *mach,
			   const char *prefix, const char ***tplg_files)
{
	struct snd_soc_acpi_mach_params mach_params = mach->mach_params;
	struct snd_soc_dai_link *dai_link;
	const struct firmware *fw;
	char platform[SOF_INTEL_PLATFORM_NAME_MAX];
	unsigned long tplg_mask = 0;
	int tplg_num = 0;
	int tplg_dev;
	int ret;
	int i;

	ret = sscanf(mach->sof_tplg_filename, "sof-%3s-*.tplg", platform);
	if (ret != 1) {
		dev_err(card->dev, "Invalid platform name %s of tplg %s\n",
			platform, mach->sof_tplg_filename);
		return -EINVAL;
	}

	for_each_card_prelinks(card, i, dai_link) {
		char *tplg_dev_name;

		dev_dbg(card->dev, "dai_link %s id %d\n", dai_link->name, dai_link->id);
		if (strstr(dai_link->name, "SimpleJack")) {
			tplg_dev = TPLG_DEVICE_SDCA_JACK;
			tplg_dev_name = "sdca-jack";
		} else if (strstr(dai_link->name, "SmartAmp")) {
			tplg_dev = TPLG_DEVICE_SDCA_AMP;
			tplg_dev_name = devm_kasprintf(card->dev, GFP_KERNEL,
						       "sdca-%damp", dai_link->num_cpus);
			if (!tplg_dev_name)
				return -ENOMEM;
		} else if (strstr(dai_link->name, "SmartMic")) {
			tplg_dev = TPLG_DEVICE_SDCA_MIC;
			tplg_dev_name = "sdca-mic";
		} else if (strstr(dai_link->name, "dmic")) {
			switch (mach_params.dmic_num) {
			case 2:
				tplg_dev_name = "dmic-2ch";
				break;
			case 4:
				tplg_dev_name = "dmic-4ch";
				break;
			default:
				dev_warn(card->dev,
					 "only -2ch and -4ch are supported for dmic\n");
				continue;
			}
			tplg_dev = TPLG_DEVICE_INTEL_PCH_DMIC;
		} else if (strstr(dai_link->name, "iDisp")) {
			tplg_dev = TPLG_DEVICE_HDMI;
			tplg_dev_name = "hdmi-pcm5";

		} else {
			/* The dai link is not supported by separated tplg yet */
			dev_dbg(card->dev,
				"dai_link %s is not supported by separated tplg yet\n",
				dai_link->name);
			return 0;
		}
		if (tplg_mask & BIT(tplg_dev))
			continue;

		tplg_mask |= BIT(tplg_dev);

		/*
		 * The tplg file naming rule is sof-<platform>-<function>-id<BE id number>.tplg
		 * where <platform> is only required for the DMIC function as the nhlt blob
		 * is platform dependent.
		 */
		switch (tplg_dev) {
		case TPLG_DEVICE_INTEL_PCH_DMIC:
			(*tplg_files)[tplg_num] = devm_kasprintf(card->dev, GFP_KERNEL,
								 "%s/sof-%s-%s-id%d.tplg",
								 prefix, platform,
								 tplg_dev_name, dai_link->id);
			break;
		default:
			(*tplg_files)[tplg_num] = devm_kasprintf(card->dev, GFP_KERNEL,
								 "%s/sof-%s-id%d.tplg",
								 prefix, tplg_dev_name,
								 dai_link->id);
			break;
		}
		if (!(*tplg_files)[tplg_num])
			return -ENOMEM;
		tplg_num++;
	}

	dev_dbg(card->dev, "tplg_mask %#lx tplg_num %d\n", tplg_mask, tplg_num);

	/* Check presence of sub-topologies */
	for (i = 0; i < tplg_num; i++) {
		ret = firmware_request_nowarn(&fw, (*tplg_files)[i], card->dev);
		if (!ret) {
			release_firmware(fw);
		} else {
			dev_dbg(card->dev, "Failed to open topology file: %s\n", (*tplg_files)[i]);
			return 0;
		}
	}

	return tplg_num;
}