sound/soc/loongson/loongson_card.c

Source file repositories/reference/linux-study-clean/sound/soc/loongson/loongson_card.c

File Facts

System
Linux kernel
Corpus path
sound/soc/loongson/loongson_card.c
Extension
.c
Size
5892 bytes
Lines
221
Domain
Driver Families
Bucket
sound/soc
Inferred role
Driver Families: implementation source
Status
source implementation candidate

Why This File Exists

Repeatable hardware-adapter layer. Deep compatibility for every driver is out of scope; this atlas records patterns, probe lifecycles, bus glue, IRQ/DMA usage, and links back to core abstractions.

Dependency Surface

Detected Declarations

Annotated Snippet

struct loongson_card_data {
	struct snd_soc_card snd_card;
	unsigned int mclk_fs;
};

static int loongson_card_hw_params(struct snd_pcm_substream *substream,
				   struct snd_pcm_hw_params *params)
{
	struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream);
	struct loongson_card_data *ls_card = snd_soc_card_get_drvdata(rtd->card);
	struct snd_soc_dai *codec_dai = snd_soc_rtd_to_codec(rtd, 0);
	struct snd_soc_dai *cpu_dai = snd_soc_rtd_to_cpu(rtd, 0);
	int ret, mclk;

	if (!ls_card->mclk_fs)
		return 0;

	mclk = ls_card->mclk_fs * params_rate(params);
	ret = snd_soc_dai_set_sysclk(cpu_dai, 0, mclk, SND_SOC_CLOCK_OUT);
	if (ret < 0) {
		dev_err(codec_dai->dev, "cpu_dai clock not set\n");
		return ret;
	}

	ret = snd_soc_dai_set_sysclk(codec_dai, 0, mclk, SND_SOC_CLOCK_IN);
	if (ret < 0) {
		dev_err(codec_dai->dev, "codec_dai clock not set\n");
		return ret;
	}

	return 0;
}

static const struct snd_soc_ops loongson_ops = {
	.hw_params = loongson_card_hw_params,
};

SND_SOC_DAILINK_DEFS(analog,
	DAILINK_COMP_ARRAY(COMP_CPU("loongson-i2s")),
	DAILINK_COMP_ARRAY(COMP_EMPTY()),
	DAILINK_COMP_ARRAY(COMP_EMPTY()));

static struct snd_soc_dai_link loongson_dai_links[] = {
	{
		.name = "Loongson Audio Port",
		.stream_name = "Loongson Audio",
		.dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_IB_NF
			| SND_SOC_DAIFMT_CBC_CFC,
		SND_SOC_DAILINK_REG(analog),
		.ops = &loongson_ops,
	},
};

static struct acpi_device *loongson_card_acpi_find_device(struct snd_soc_card *card,
							  const char *name)
{
	struct fwnode_handle *fwnode = card->dev->fwnode;
	struct fwnode_reference_args args;
	int status;

	memset(&args, 0, sizeof(args));
	status = acpi_node_get_property_reference(fwnode, name, 0, &args);
	if (status || !is_acpi_device_node(args.fwnode)) {
		dev_err(card->dev, "No matching phy in ACPI table\n");
		return NULL;
	}

	return to_acpi_device_node(args.fwnode);
}

static int loongson_card_parse_acpi(struct loongson_card_data *data)
{
	struct snd_soc_card *card = &data->snd_card;
	const char *codec_dai_name;
	struct acpi_device *adev;
	struct device *phy_dev;
	int i;

	/* fixup platform name based on reference node */
	adev = loongson_card_acpi_find_device(card, "cpu");
	if (!adev)
		return -ENOENT;

	phy_dev = acpi_get_first_physical_node(adev);
	if (!phy_dev)
		return -EPROBE_DEFER;

	/* fixup codec name based on reference node */
	adev = loongson_card_acpi_find_device(card, "codec");
	if (!adev)

Annotation

Implementation Notes