summaryrefslogtreecommitdiffstats
path: root/sound
diff options
context:
space:
mode:
authorSubhransu S. Prusty <subhransu.s.prusty@intel.com>2016-02-12 07:46:02 +0530
committerMark Brown <broonie@kernel.org>2016-02-15 20:11:09 +0000
commit2428bca305e082885e08e7f3399db616daf3a51a (patch)
treead8c3854df15bb582876336244d10b38b4449301 /sound
parentb8a54545b00cbf2aff743578c5c69aafdcde1d64 (diff)
downloadlinux-stable-2428bca305e082885e08e7f3399db616daf3a51a.tar.gz
linux-stable-2428bca305e082885e08e7f3399db616daf3a51a.tar.bz2
linux-stable-2428bca305e082885e08e7f3399db616daf3a51a.zip
ASoC: hdac_hdmi: Apply constraints based on ELD
Uses the drm ELD core framework to apply rate and channel Also compute the format to be set based on ELD. Even though the channel constraint is based on ELD, infoframe is set with stereo only. Multichannel support will be added later. 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/Kconfig1
-rw-r--r--sound/soc/codecs/hdac_hdmi.c51
2 files changed, 49 insertions, 3 deletions
diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig
index 50693c867e71..8c86239cc3f2 100644
--- a/sound/soc/codecs/Kconfig
+++ b/sound/soc/codecs/Kconfig
@@ -490,6 +490,7 @@ config SND_SOC_GTM601
config SND_SOC_HDAC_HDMI
tristate
select SND_HDA_EXT_CORE
+ select SND_PCM_ELD
select HDMI
config SND_SOC_ICS43432
diff --git a/sound/soc/codecs/hdac_hdmi.c b/sound/soc/codecs/hdac_hdmi.c
index fff225d6539c..d22fa6b66c80 100644
--- a/sound/soc/codecs/hdac_hdmi.c
+++ b/sound/soc/codecs/hdac_hdmi.c
@@ -22,10 +22,12 @@
#include <linux/module.h>
#include <linux/pm_runtime.h>
#include <linux/hdmi.h>
+#include <drm/drm_edid.h>
#include <sound/pcm_params.h>
#include <sound/soc.h>
#include <sound/hdaudio_ext.h>
#include <sound/hda_i915.h>
+#include <sound/pcm_drm_eld.h>
#include "../../hda/local.h"
#define AMP_OUT_MUTE 0xb080
@@ -90,6 +92,45 @@ static inline struct hdac_ext_device *to_hda_ext_device(struct device *dev)
return to_ehdac_device(hdac);
}
+static unsigned int sad_format(const u8 *sad)
+{
+ return ((sad[0] >> 0x3) & 0x1f);
+}
+
+static unsigned int sad_sample_bits_lpcm(const u8 *sad)
+{
+ return (sad[2] & 7);
+}
+
+static int hdac_hdmi_eld_limit_formats(struct snd_pcm_runtime *runtime,
+ void *eld)
+{
+ u64 formats = SNDRV_PCM_FMTBIT_S16;
+ int i;
+ const u8 *sad, *eld_buf = eld;
+
+ sad = drm_eld_sad(eld_buf);
+ if (!sad)
+ goto format_constraint;
+
+ for (i = drm_eld_sad_count(eld_buf); i > 0; i--, sad += 3) {
+ if (sad_format(sad) == 1) { /* AUDIO_CODING_TYPE_LPCM */
+
+ /*
+ * the controller support 20 and 24 bits in 32 bit
+ * container so we set S32
+ */
+ if (sad_sample_bits_lpcm(sad) & 0x6)
+ formats |= SNDRV_PCM_FMTBIT_S32;
+ }
+ }
+
+format_constraint:
+ return snd_pcm_hw_constraint_mask64(runtime, SNDRV_PCM_HW_PARAM_FORMAT,
+ formats);
+
+}
+
/* HDMI ELD routines */
static unsigned int hdac_hdmi_get_eld_data(struct hdac_device *codec,
hda_nid_t nid, int byte_index)
@@ -334,6 +375,7 @@ static int hdac_hdmi_pcm_open(struct snd_pcm_substream *substream,
struct hdac_ext_device *hdac = snd_soc_dai_get_drvdata(dai);
struct hdac_hdmi_priv *hdmi = hdac->private_data;
struct hdac_hdmi_dai_pin_map *dai_map;
+ int ret;
if (dai->id > 0) {
dev_err(&hdac->hdac.dev, "Only one dai supported as of now\n");
@@ -358,10 +400,13 @@ static int hdac_hdmi_pcm_open(struct snd_pcm_substream *substream,
snd_hdac_codec_write(&hdac->hdac, dai_map->pin->nid, 0,
AC_VERB_SET_AMP_GAIN_MUTE, AMP_OUT_UNMUTE);
- snd_pcm_hw_constraint_step(substream->runtime, 0,
- SNDRV_PCM_HW_PARAM_CHANNELS, 2);
+ ret = hdac_hdmi_eld_limit_formats(substream->runtime,
+ dai_map->pin->eld.eld_buffer);
+ if (ret < 0)
+ return ret;
- return 0;
+ return snd_pcm_hw_constraint_eld(substream->runtime,
+ dai_map->pin->eld.eld_buffer);
}
static void hdac_hdmi_pcm_close(struct snd_pcm_substream *substream,