~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

TOMOYO Linux Cross Reference
Linux/sound/soc/intel/avs/boards/hdaudio.c

Version: ~ [ linux-6.11.5 ] ~ [ linux-6.10.14 ] ~ [ linux-6.9.12 ] ~ [ linux-6.8.12 ] ~ [ linux-6.7.12 ] ~ [ linux-6.6.58 ] ~ [ linux-6.5.13 ] ~ [ linux-6.4.16 ] ~ [ linux-6.3.13 ] ~ [ linux-6.2.16 ] ~ [ linux-6.1.114 ] ~ [ linux-6.0.19 ] ~ [ linux-5.19.17 ] ~ [ linux-5.18.19 ] ~ [ linux-5.17.15 ] ~ [ linux-5.16.20 ] ~ [ linux-5.15.169 ] ~ [ linux-5.14.21 ] ~ [ linux-5.13.19 ] ~ [ linux-5.12.19 ] ~ [ linux-5.11.22 ] ~ [ linux-5.10.228 ] ~ [ linux-5.9.16 ] ~ [ linux-5.8.18 ] ~ [ linux-5.7.19 ] ~ [ linux-5.6.19 ] ~ [ linux-5.5.19 ] ~ [ linux-5.4.284 ] ~ [ linux-5.3.18 ] ~ [ linux-5.2.21 ] ~ [ linux-5.1.21 ] ~ [ linux-5.0.21 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.322 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.336 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.337 ] ~ [ linux-4.4.302 ] ~ [ linux-3.10.108 ] ~ [ linux-2.6.32.71 ] ~ [ linux-2.6.0 ] ~ [ linux-2.4.37.11 ] ~ [ unix-v6-master ] ~ [ ccs-tools-1.8.9 ] ~ [ policy-sample ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

  1 // SPDX-License-Identifier: GPL-2.0-only
  2 //
  3 // Copyright(c) 2021-2022 Intel Corporation
  4 //
  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 
 17 static 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 
 73 static struct snd_pcm *
 74 avs_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 
 97 static 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 
126 static 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 
158 static 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 
170 static 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 
219 static const struct platform_device_id avs_hdaudio_driver_ids[] = {
220         {
221                 .name = "avs_hdaudio",
222         },
223         {},
224 };
225 MODULE_DEVICE_TABLE(platform, avs_hdaudio_driver_ids);
226 
227 static 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 
236 module_platform_driver(avs_hdaudio_driver)
237 
238 MODULE_DESCRIPTION("Intel HD-Audio machine driver");
239 MODULE_AUTHOR("Cezary Rojewski <cezary.rojewski@intel.com>");
240 MODULE_LICENSE("GPL");
241 

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

kernel.org | git.kernel.org | LWN.net | Project Home | SVN repository | Mail admin

Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.

sflogo.php