summaryrefslogtreecommitdiffstats
path: root/sound
diff options
context:
space:
mode:
authorSubhransu S. Prusty <subhransu.s.prusty@intel.com>2016-04-14 10:07:34 +0530
committerMark Brown <broonie@kernel.org>2016-04-28 18:49:24 +0100
commit2889099eb8cd0811dc2986643d46c0b62b90eeb4 (patch)
tree551e6701042faf94ee22e5acae94bdae8f7653e4 /sound
parent46ed1a27fb44febb2c362fc30fcb51e8eed06e3a (diff)
downloadtalos-op-linux-2889099eb8cd0811dc2986643d46c0b62b90eeb4.tar.gz
talos-op-linux-2889099eb8cd0811dc2986643d46c0b62b90eeb4.zip
ASoC: hdac_hdmi: Register chmap controls and ops
With this patch, chmap controls are created and user space can set the channel map. Signed-off-by: Subhransu S. Prusty <subhransu.s.prusty@intel.com> Signed-off-by: Vinod Koul <vinod.koul@intel.com> Signed-off-by: Mark Brown <broonie@kernel.org>
Diffstat (limited to 'sound')
-rw-r--r--sound/soc/codecs/hdac_hdmi.c100
1 files changed, 100 insertions, 0 deletions
diff --git a/sound/soc/codecs/hdac_hdmi.c b/sound/soc/codecs/hdac_hdmi.c
index 034593bf2cd6..0ed39753c871 100644
--- a/sound/soc/codecs/hdac_hdmi.c
+++ b/sound/soc/codecs/hdac_hdmi.c
@@ -114,6 +114,19 @@ struct hdac_hdmi_priv {
struct hdac_chmap chmap;
};
+static struct hdac_hdmi_pcm *get_hdmi_pcm_from_id(struct hdac_hdmi_priv *hdmi,
+ int pcm_idx)
+{
+ struct hdac_hdmi_pcm *pcm;
+
+ list_for_each_entry(pcm, &hdmi->pcm_list, head) {
+ if (pcm->pcm_id == pcm_idx)
+ return pcm;
+ }
+
+ return NULL;
+}
+
static inline struct hdac_ext_device *to_hda_ext_device(struct device *dev)
{
struct hdac_device *hdac = dev_to_hdac_dev(dev);
@@ -664,6 +677,8 @@ static void hdac_hdmi_pcm_close(struct snd_pcm_substream *substream,
AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_MUTE);
mutex_lock(&dai_map->pin->lock);
+ dai_map->pin->chmap_set = false;
+ memset(dai_map->pin->chmap, 0, sizeof(dai_map->pin->chmap));
dai_map->pin->channels = 0;
mutex_unlock(&dai_map->pin->lock);
@@ -1386,6 +1401,19 @@ static struct i915_audio_component_audio_ops aops = {
.pin_eld_notify = hdac_hdmi_eld_notify_cb,
};
+static struct snd_pcm *hdac_hdmi_get_pcm_from_id(struct snd_soc_card *card,
+ int device)
+{
+ struct snd_soc_pcm_runtime *rtd;
+
+ list_for_each_entry(rtd, &card->rtd_list, list) {
+ if (rtd->pcm && (rtd->pcm->device == device))
+ return rtd->pcm;
+ }
+
+ return NULL;
+}
+
int hdac_hdmi_jack_init(struct snd_soc_dai *dai, int device)
{
char jack_name[NAME_SIZE];
@@ -1395,6 +1423,8 @@ int hdac_hdmi_jack_init(struct snd_soc_dai *dai, int device)
snd_soc_component_get_dapm(&codec->component);
struct hdac_hdmi_priv *hdmi = edev->private_data;
struct hdac_hdmi_pcm *pcm;
+ struct snd_pcm *snd_pcm;
+ int err;
/*
* this is a new PCM device, create new pcm and
@@ -1406,6 +1436,18 @@ int hdac_hdmi_jack_init(struct snd_soc_dai *dai, int device)
pcm->pcm_id = device;
pcm->cvt = hdmi->dai_map[dai->id].cvt;
+ snd_pcm = hdac_hdmi_get_pcm_from_id(dai->component->card, device);
+ if (snd_pcm) {
+ err = snd_hdac_add_chmap_ctls(snd_pcm, device, &hdmi->chmap);
+ if (err < 0) {
+ dev_err(&edev->hdac.dev,
+ "chmap control add failed with err: %d for pcm: %d\n",
+ err, device);
+ kfree(pcm);
+ return err;
+ }
+ }
+
list_add_tail(&pcm->head, &hdmi->pcm_list);
sprintf(jack_name, "HDMI/DP, pcm=%d Jack", device);
@@ -1524,6 +1566,60 @@ static struct snd_soc_codec_driver hdmi_hda_codec = {
.idle_bias_off = true,
};
+static void hdac_hdmi_get_chmap(struct hdac_device *hdac, int pcm_idx,
+ unsigned char *chmap)
+{
+ struct hdac_ext_device *edev = to_ehdac_device(hdac);
+ struct hdac_hdmi_priv *hdmi = edev->private_data;
+ struct hdac_hdmi_pcm *pcm = get_hdmi_pcm_from_id(hdmi, pcm_idx);
+ struct hdac_hdmi_pin *pin = pcm->pin;
+
+ /* chmap is already set to 0 in caller */
+ if (!pin)
+ return;
+
+ memcpy(chmap, pin->chmap, ARRAY_SIZE(pin->chmap));
+}
+
+static void hdac_hdmi_set_chmap(struct hdac_device *hdac, int pcm_idx,
+ unsigned char *chmap, int prepared)
+{
+ struct hdac_ext_device *edev = to_ehdac_device(hdac);
+ struct hdac_hdmi_priv *hdmi = edev->private_data;
+ struct hdac_hdmi_pcm *pcm = get_hdmi_pcm_from_id(hdmi, pcm_idx);
+ struct hdac_hdmi_pin *pin = pcm->pin;
+
+ mutex_lock(&pin->lock);
+ pin->chmap_set = true;
+ memcpy(pin->chmap, chmap, ARRAY_SIZE(pin->chmap));
+ if (prepared)
+ hdac_hdmi_setup_audio_infoframe(edev, pcm->cvt->nid, pin->nid);
+ mutex_unlock(&pin->lock);
+}
+
+static bool is_hdac_hdmi_pcm_attached(struct hdac_device *hdac, int pcm_idx)
+{
+ struct hdac_ext_device *edev = to_ehdac_device(hdac);
+ struct hdac_hdmi_priv *hdmi = edev->private_data;
+ struct hdac_hdmi_pcm *pcm = get_hdmi_pcm_from_id(hdmi, pcm_idx);
+ struct hdac_hdmi_pin *pin = pcm->pin;
+
+ return pin ? true:false;
+}
+
+static int hdac_hdmi_get_spk_alloc(struct hdac_device *hdac, int pcm_idx)
+{
+ struct hdac_ext_device *edev = to_ehdac_device(hdac);
+ struct hdac_hdmi_priv *hdmi = edev->private_data;
+ struct hdac_hdmi_pcm *pcm = get_hdmi_pcm_from_id(hdmi, pcm_idx);
+ struct hdac_hdmi_pin *pin = pcm->pin;
+
+ if (!pin && !pin->eld.eld_valid)
+ return 0;
+
+ return pin->eld.info.spk_alloc;
+}
+
static int hdac_hdmi_dev_probe(struct hdac_ext_device *edev)
{
struct hdac_device *codec = &edev->hdac;
@@ -1538,6 +1634,10 @@ static int hdac_hdmi_dev_probe(struct hdac_ext_device *edev)
edev->private_data = hdmi_priv;
snd_hdac_register_chmap_ops(codec, &hdmi_priv->chmap);
+ hdmi_priv->chmap.ops.get_chmap = hdac_hdmi_get_chmap;
+ hdmi_priv->chmap.ops.set_chmap = hdac_hdmi_set_chmap;
+ hdmi_priv->chmap.ops.is_pcm_attached = is_hdac_hdmi_pcm_attached;
+ hdmi_priv->chmap.ops.get_spk_alloc = hdac_hdmi_get_spk_alloc;
dev_set_drvdata(&codec->dev, edev);
OpenPOWER on IntegriCloud