[PATCH v2 04/12] ASoC: hdmi-codec: Add iec958 controls
From: Maxime Ripard <hidden>
Date: 2021-05-25 13:25:06
Also in:
alsa-devel, dri-devel, linux-arm-kernel, linux-devicetree, lkml
Subsystem:
sound, sound - soc layer / dynamic audio power management (asoc), the rest · Maintainers:
Jaroslav Kysela, Takashi Iwai, Liam Girdwood, Mark Brown, Linus Torvalds
The IEC958 status bits can be exposed and modified by the userspace through dedicated ALSA controls. This patch implements those controls for the hdmi-codec driver. It relies on a default value being setup at probe time that can later be overridden by the control put. The hw_params callback is then called with a buffer filled with the proper bits for the current parameters being passed on so the underlying driver can just reuse those bits as is. Signed-off-by: Maxime Ripard <redacted> --- sound/soc/codecs/hdmi-codec.c | 66 +++++++++++++++++++++++++++++++++-- 1 file changed, 64 insertions(+), 2 deletions(-)
diff --git a/sound/soc/codecs/hdmi-codec.c b/sound/soc/codecs/hdmi-codec.c
index 65bde6f0ea1c..5d6324585a31 100644
--- a/sound/soc/codecs/hdmi-codec.c
+++ b/sound/soc/codecs/hdmi-codec.c@@ -277,6 +277,7 @@ struct hdmi_codec_priv { bool busy; struct snd_soc_jack *jack; unsigned int jack_status; + u8 iec_status[5]; }; static const struct snd_soc_dapm_widget hdmi_widgets[] = {
@@ -385,6 +386,47 @@ static int hdmi_codec_chmap_ctl_get(struct snd_kcontrol *kcontrol, return 0; } +static int hdmi_codec_iec958_info(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_info *uinfo) +{ + uinfo->type = SNDRV_CTL_ELEM_TYPE_IEC958; + uinfo->count = 1; + return 0; +} + +static int hdmi_codec_iec958_default_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); + struct hdmi_codec_priv *hcp = snd_soc_component_get_drvdata(component); + + memcpy(ucontrol->value.iec958.status, hcp->iec_status, + sizeof(hcp->iec_status)); + + return 0; +} + +static int hdmi_codec_iec958_default_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = snd_kcontrol_chip(kcontrol); + struct hdmi_codec_priv *hcp = snd_soc_component_get_drvdata(component); + + memcpy(hcp->iec_status, ucontrol->value.iec958.status, + sizeof(hcp->iec_status)); + + return 0; +} + +static int hdmi_codec_iec958_mask_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + memset(ucontrol->value.iec958.status, 0xff, + sizeof_field(struct hdmi_codec_priv, iec_status)); + + return 0; +} + static int hdmi_codec_startup(struct snd_pcm_substream *substream, struct snd_soc_dai *dai) {
@@ -459,8 +501,9 @@ static int hdmi_codec_hw_params(struct snd_pcm_substream *substream, params_width(params), params_rate(params), params_channels(params)); - ret = snd_pcm_create_iec958_consumer_hw_params(params, hp.iec.status, - sizeof(hp.iec.status)); + memcpy(hp.iec.status, hcp->iec_status, sizeof(hp->iec_status)); + ret = snd_pcm_fill_iec958_consumer_hw_params(params, hp.iec.status, + sizeof(hp.iec.status)); if (ret < 0) { dev_err(dai->dev, "Creating IEC958 channel status failed %d\n", ret);
@@ -621,6 +664,20 @@ static const struct snd_soc_dai_ops hdmi_codec_spdif_dai_ops = { SNDRV_PCM_FMTBIT_IEC958_SUBFRAME_LE) struct snd_kcontrol_new hdmi_codec_controls[] = { + { + .access = SNDRV_CTL_ELEM_ACCESS_READ, + .iface = SNDRV_CTL_ELEM_IFACE_PCM, + .name = SNDRV_CTL_NAME_IEC958("", PLAYBACK, MASK), + .info = hdmi_codec_iec958_info, + .get = hdmi_codec_iec958_mask_get, + }, + { + .iface = SNDRV_CTL_ELEM_IFACE_PCM, + .name = SNDRV_CTL_NAME_IEC958("", PLAYBACK, DEFAULT), + .info = hdmi_codec_iec958_info, + .get = hdmi_codec_iec958_default_get, + .put = hdmi_codec_iec958_default_put, + }, { .access = (SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE),
@@ -873,6 +930,11 @@ static int hdmi_codec_probe(struct platform_device *pdev) hcp->hcd = *hcd; mutex_init(&hcp->lock); + ret = snd_pcm_create_iec958_consumer_default(hcp->iec_status, + sizeof(hcp->iec_status)); + if (ret < 0) + return ret; + daidrv = devm_kcalloc(dev, dai_count, sizeof(*daidrv), GFP_KERNEL); if (!daidrv) return -ENOMEM;
--
2.31.1