brintos

brintos / linux-shallow public Read only

0
0
Text · 6.1 KiB · 430c070 Raw
241 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2//3// Copyright(c) 2021-2022 Intel Corporation4//5// Authors: Cezary Rojewski <cezary.rojewski@intel.com>6//          Amadeusz Slawinski <amadeuszx.slawinski@linux.intel.com>7//8 9#include <linux/module.h>10#include <linux/platform_device.h>11#include <sound/hda_codec.h>12#include <sound/hda_i915.h>13#include <sound/soc.h>14#include <sound/soc-acpi.h>15#include "../../../codecs/hda.h"16 17static int avs_create_dai_links(struct device *dev, struct hda_codec *codec, int pcm_count,18				const char *platform_name, struct snd_soc_dai_link **links)19{20	struct snd_soc_dai_link_component *platform;21	struct snd_soc_dai_link *dl;22	struct hda_pcm *pcm;23	const char *cname = dev_name(&codec->core.dev);24	int i;25 26	dl = devm_kcalloc(dev, pcm_count, sizeof(*dl), GFP_KERNEL);27	platform = devm_kzalloc(dev, sizeof(*platform), GFP_KERNEL);28	if (!dl || !platform)29		return -ENOMEM;30 31	platform->name = platform_name;32	pcm = list_first_entry(&codec->pcm_list_head, struct hda_pcm, list);33 34	for (i = 0; i < pcm_count; i++, pcm = list_next_entry(pcm, list)) {35		dl[i].name = devm_kasprintf(dev, GFP_KERNEL, "%s link%d", cname, i);36		if (!dl[i].name)37			return -ENOMEM;38 39		dl[i].id = i;40		dl[i].nonatomic = 1;41		dl[i].no_pcm = 1;42		dl[i].dpcm_playback = 1;43		dl[i].dpcm_capture = 1;44		dl[i].platforms = platform;45		dl[i].num_platforms = 1;46		dl[i].ignore_pmdown_time = 1;47 48		dl[i].codecs = devm_kzalloc(dev, sizeof(*dl->codecs), GFP_KERNEL);49		dl[i].cpus = devm_kzalloc(dev, sizeof(*dl->cpus), GFP_KERNEL);50		if (!dl[i].codecs || !dl[i].cpus)51			return -ENOMEM;52 53		dl[i].cpus->dai_name = devm_kasprintf(dev, GFP_KERNEL, "%s-cpu%d", cname, i);54		if (!dl[i].cpus->dai_name)55			return -ENOMEM;56 57		dl[i].codecs->name = devm_kstrdup_const(dev, cname, GFP_KERNEL);58		if (!dl[i].codecs->name)59			return -ENOMEM;60 61		dl[i].codecs->dai_name = pcm->name;62		dl[i].num_codecs = 1;63		dl[i].num_cpus = 1;64	}65 66	*links = dl;67	return 0;68}69 70/* Should be aligned with SectionPCM's name from topology */71#define FEDAI_NAME_PREFIX "HDMI"72 73static struct snd_pcm *74avs_card_hdmi_pcm_at(struct snd_soc_card *card, int hdmi_idx)75{76	struct snd_soc_pcm_runtime *rtd;77	int dir = SNDRV_PCM_STREAM_PLAYBACK;78 79	for_each_card_rtds(card, rtd) {80		struct snd_pcm *spcm;81		int ret, n;82 83		spcm = rtd->pcm ? rtd->pcm->streams[dir].pcm : NULL;84		if (!spcm || !strstr(spcm->id, FEDAI_NAME_PREFIX))85			continue;86 87		ret = sscanf(spcm->id, FEDAI_NAME_PREFIX "%d", &n);88		if (ret != 1)89			continue;90		if (n == hdmi_idx)91			return rtd->pcm;92	}93 94	return NULL;95}96 97static int avs_card_late_probe(struct snd_soc_card *card)98{99	struct snd_soc_acpi_mach *mach = dev_get_platdata(card->dev);100	struct hda_codec *codec = mach->pdata;101	struct hda_pcm *hpcm;102	/* Topology pcm indexing is 1-based */103	int i = 1;104 105	list_for_each_entry(hpcm, &codec->pcm_list_head, list) {106		struct snd_pcm *spcm;107 108		spcm = avs_card_hdmi_pcm_at(card, i);109		if (spcm) {110			hpcm->pcm = spcm;111			hpcm->device = spcm->device;112			dev_info(card->dev, "%s: mapping HDMI converter %d to PCM %d (%p)\n",113				 __func__, i, hpcm->device, spcm);114		} else {115			hpcm->pcm = NULL;116			hpcm->device = SNDRV_PCM_INVALID_DEVICE;117			dev_warn(card->dev, "%s: no PCM in topology for HDMI converter %d\n",118				 __func__, i);119		}120		i++;121	}122 123	return hda_codec_probe_complete(codec);124}125 126static int avs_probing_link_init(struct snd_soc_pcm_runtime *rtm)127{128	struct snd_soc_acpi_mach *mach;129	struct snd_soc_dai_link *links = NULL;130	struct snd_soc_card *card = rtm->card;131	struct hda_codec *codec;132	struct hda_pcm *pcm;133	int ret, pcm_count = 0;134 135	mach = dev_get_platdata(card->dev);136	codec = mach->pdata;137 138	if (list_empty(&codec->pcm_list_head))139		return -EINVAL;140	list_for_each_entry(pcm, &codec->pcm_list_head, list)141		pcm_count++;142 143	ret = avs_create_dai_links(card->dev, codec, pcm_count, mach->mach_params.platform, &links);144	if (ret < 0) {145		dev_err(card->dev, "create links failed: %d\n", ret);146		return ret;147	}148 149	ret = snd_soc_add_pcm_runtimes(card, links, pcm_count);150	if (ret < 0) {151		dev_err(card->dev, "add links failed: %d\n", ret);152		return ret;153	}154 155	return 0;156}157 158static const struct snd_soc_dai_link probing_link = {159	.name = "probing-LINK",160	.id = -1,161	.nonatomic = 1,162	.no_pcm = 1,163	.dpcm_playback = 1,164	.dpcm_capture = 1,165	.cpus = &snd_soc_dummy_dlc,166	.num_cpus = 1,167	.init = avs_probing_link_init,168};169 170static int avs_hdaudio_probe(struct platform_device *pdev)171{172	struct snd_soc_dai_link *binder;173	struct snd_soc_acpi_mach *mach;174	struct snd_soc_card *card;175	struct device *dev = &pdev->dev;176	struct hda_codec *codec;177 178	mach = dev_get_platdata(dev);179	codec = mach->pdata;180 181	/* codec may be unloaded before card's probe() fires */182	if (!device_is_registered(&codec->core.dev))183		return -ENODEV;184 185	binder = devm_kmemdup(dev, &probing_link, sizeof(probing_link), GFP_KERNEL);186	if (!binder)187		return -ENOMEM;188 189	binder->platforms = devm_kzalloc(dev, sizeof(*binder->platforms), GFP_KERNEL);190	binder->codecs = devm_kzalloc(dev, sizeof(*binder->codecs), GFP_KERNEL);191	if (!binder->platforms || !binder->codecs)192		return -ENOMEM;193 194	binder->codecs->name = devm_kstrdup_const(dev, dev_name(&codec->core.dev), GFP_KERNEL);195	if (!binder->codecs->name)196		return -ENOMEM;197 198	binder->platforms->name = mach->mach_params.platform;199	binder->num_platforms = 1;200	binder->codecs->dai_name = "codec-probing-DAI";201	binder->num_codecs = 1;202 203	card = devm_kzalloc(dev, sizeof(*card), GFP_KERNEL);204	if (!card)205		return -ENOMEM;206 207	card->name = binder->codecs->name;208	card->dev = dev;209	card->owner = THIS_MODULE;210	card->dai_link = binder;211	card->num_links = 1;212	card->fully_routed = true;213	if (hda_codec_is_display(codec))214		card->late_probe = avs_card_late_probe;215 216	return devm_snd_soc_register_card(dev, card);217}218 219static const struct platform_device_id avs_hdaudio_driver_ids[] = {220	{221		.name = "avs_hdaudio",222	},223	{},224};225MODULE_DEVICE_TABLE(platform, avs_hdaudio_driver_ids);226 227static struct platform_driver avs_hdaudio_driver = {228	.probe = avs_hdaudio_probe,229	.driver = {230		.name = "avs_hdaudio",231		.pm = &snd_soc_pm_ops,232	},233	.id_table = avs_hdaudio_driver_ids,234};235 236module_platform_driver(avs_hdaudio_driver)237 238MODULE_DESCRIPTION("Intel HD-Audio machine driver");239MODULE_AUTHOR("Cezary Rojewski <cezary.rojewski@intel.com>");240MODULE_LICENSE("GPL");241