1// SPDX-License-Identifier: GPL-2.0-only
2//
3// Copyright(c) 2019 Intel Corporation
4
5#include <linux/module.h>
6#include <sound/pcm.h>
7#include <sound/soc.h>
8#include <sound/hda_codec.h>
9#include <sound/hda_i915.h>
10#include "../../codecs/hdac_hda.h"
11
12#include "hda_dsp_common.h"
13
14#if IS_ENABLED(CONFIG_SND_SOC_SOF_HDA_AUDIO_CODEC)
15
16/*
17 * Search card topology and return PCM device number
18 * matching Nth playback HDMI device (zero-based index).
19 */
20static struct snd_pcm *hda_dsp_hdmi_pcm_handle(struct snd_soc_card *card,
21 int hdmi_idx)
22{
23 struct snd_soc_pcm_runtime *rtd;
24 struct snd_pcm *spcm;
25 int i = 0;
26
27 for_each_card_rtds(card, rtd) {
28 /* ignore BE PCMs */
29 if (rtd->dai_link && rtd->dai_link->no_pcm)
30 continue;
31
32 spcm = rtd->pcm;
33
34 /* ignore PCMs with no playback streams */
35 if (!spcm || !spcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream)
36 continue;
37
38 /* look for FE PCMs with name "HDMI x" */
39 if (spcm && strstr(spcm->id, "HDMI")) {
40 if (i == hdmi_idx)
41 return rtd->pcm;
42 ++i;
43 }
44 }
45
46 return NULL;
47}
48
49/*
50 * Search card topology and register HDMI PCM related controls
51 * to codec driver.
52 */
53int hda_dsp_hdmi_build_controls(struct snd_soc_card *card,
54 struct snd_soc_component *comp)
55{
56 struct hdac_hda_priv *hda_pvt;
57 struct hda_codec *hcodec;
58 struct snd_pcm *spcm;
59 struct hda_pcm *hpcm;
60 int err = 0, i = 0;
61
62 if (!comp)
63 return -EINVAL;
64
65 hda_pvt = snd_soc_component_get_drvdata(c: comp);
66 hcodec = hda_pvt->codec;
67
68 list_for_each_entry(hpcm, &hcodec->pcm_list_head, list) {
69 spcm = hda_dsp_hdmi_pcm_handle(card, hdmi_idx: i);
70 if (spcm) {
71 hpcm->pcm = spcm;
72 hpcm->device = spcm->device;
73 dev_dbg(card->dev,
74 "mapping HDMI converter %d to PCM %d (%p)\n",
75 i, hpcm->device, spcm);
76 } else {
77 hpcm->pcm = NULL;
78 hpcm->device = SNDRV_PCM_INVALID_DEVICE;
79 dev_warn(card->dev,
80 "%s: no PCM in topology for HDMI converter %d\n",
81 __func__, i);
82 }
83 i++;
84 }
85 snd_hdac_display_power(bus: hcodec->core.bus,
86 HDA_CODEC_IDX_CONTROLLER, enable: true);
87 err = snd_hda_codec_build_controls(codec: hcodec);
88 if (err < 0)
89 dev_err(card->dev, "unable to create controls %d\n", err);
90 snd_hdac_display_power(bus: hcodec->core.bus,
91 HDA_CODEC_IDX_CONTROLLER, enable: false);
92
93 return err;
94}
95EXPORT_SYMBOL_NS(hda_dsp_hdmi_build_controls, "SND_SOC_INTEL_HDA_DSP_COMMON");
96
97#endif
98
99MODULE_DESCRIPTION("ASoC Intel HDMI helpers");
100MODULE_LICENSE("GPL");
101

source code of linux/sound/soc/intel/boards/hda_dsp_common.c