diff options
Diffstat (limited to 'sound/soc/codecs/hdmi-codec.c')
-rw-r--r-- | sound/soc/codecs/hdmi-codec.c | 104 |
1 files changed, 94 insertions, 10 deletions
diff --git a/sound/soc/codecs/hdmi-codec.c b/sound/soc/codecs/hdmi-codec.c index f8b5b960e597..cc67f79c8c3d 100644 --- a/sound/soc/codecs/hdmi-codec.c +++ b/sound/soc/codecs/hdmi-codec.c @@ -277,10 +277,12 @@ struct hdmi_codec_priv { unsigned long busy; struct snd_soc_jack *jack; unsigned int jack_status; + struct snd_aes_iec958 iec; }; static const struct snd_soc_dapm_widget hdmi_widgets[] = { SND_SOC_DAPM_OUTPUT("TX"), + SND_SOC_DAPM_OUTPUT("RX"), }; enum { @@ -384,10 +386,56 @@ static int hdmi_codec_chmap_ctl_get(struct snd_kcontrol *kcontrol, return 0; } +/* + * ALSA iec958 controls + */ +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_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *comp = snd_kcontrol_chip(kcontrol); + struct hdmi_codec_priv *hcp = snd_soc_component_get_drvdata(comp); + int i; + + for (i = 0; i < 24; i++) + ucontrol->value.iec958.status[i] = hcp->iec.status[i]; + + return 0; +} + +static int hdmi_codec_iec958_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *comp = snd_kcontrol_chip(kcontrol); + struct hdmi_codec_priv *hcp = snd_soc_component_get_drvdata(comp); + int i; + + for (i = 0; i < 24; i++) + hcp->iec.status[i] = ucontrol->value.iec958.status[i]; + + return 0; +} + +static const struct snd_kcontrol_new hdmi_codec_controls = { + .iface = SNDRV_CTL_ELEM_IFACE_PCM, + .name = SNDRV_CTL_NAME_IEC958("", PLAYBACK, DEFAULT), + .info = hdmi_codec_iec958_info, + .get = hdmi_codec_iec958_get, + .put = hdmi_codec_iec958_put, +}; + static int hdmi_codec_startup(struct snd_pcm_substream *substream, struct snd_soc_dai *dai) { struct hdmi_codec_priv *hcp = snd_soc_dai_get_drvdata(dai); + bool tx = substream->stream == SNDRV_PCM_STREAM_PLAYBACK; int ret = 0; ret = test_and_set_bit(0, &hcp->busy); @@ -402,7 +450,7 @@ static int hdmi_codec_startup(struct snd_pcm_substream *substream, goto err; } - if (hcp->hcd.ops->get_eld) { + if (tx && hcp->hcd.ops->get_eld) { ret = hcp->hcd.ops->get_eld(dai->dev->parent, hcp->hcd.data, hcp->eld, sizeof(hcp->eld)); @@ -462,6 +510,15 @@ static int hdmi_codec_hw_params(struct snd_pcm_substream *substream, return ret; } + if (hcp->iec.status[0] || hcp->iec.status[1] || hcp->iec.status[2] || + hcp->iec.status[3] || hcp->iec.status[4]) { + hp.iec.status[0] = hcp->iec.status[0]; + hp.iec.status[1] = hcp->iec.status[1]; + hp.iec.status[2] = hcp->iec.status[2]; + hp.iec.status[3] = hcp->iec.status[3]; + hp.iec.status[4] = hcp->iec.status[4]; + } + hdmi_audio_infoframe_init(&hp.cea); hp.cea.channels = params_channels(params); hp.cea.coding_type = HDMI_AUDIO_CODING_TYPE_STREAM; @@ -471,13 +528,11 @@ static int hdmi_codec_hw_params(struct snd_pcm_substream *substream, /* Select a channel allocation that matches with ELD and pcm channels */ idx = hdmi_codec_get_ch_alloc_table_idx(hcp, hp.cea.channels); if (idx < 0) { - dev_err(dai->dev, "Not able to map channels to speakers (%d)\n", - idx); hcp->chmap_idx = HDMI_CODEC_CHMAP_IDX_UNKNOWN; - return idx; + } else { + hp.cea.channel_allocation = hdmi_codec_channel_alloc[idx].ca_id; + hcp->chmap_idx = hdmi_codec_channel_alloc[idx].ca_id; } - hp.cea.channel_allocation = hdmi_codec_channel_alloc[idx].ca_id; - hcp->chmap_idx = hdmi_codec_channel_alloc[idx].ca_id; hp.sample_width = params_width(params); hp.sample_rate = params_rate(params); @@ -635,6 +690,14 @@ static int hdmi_codec_pcm_new(struct snd_soc_pcm_runtime *rtd, hcp->chmap_info->chmap = hdmi_codec_stereo_chmaps; hcp->chmap_idx = HDMI_CODEC_CHMAP_IDX_UNKNOWN; + kctl = snd_ctl_new1(&hdmi_codec_controls, dai->component); + if (!kctl) + return -ENOMEM; + + ret = snd_ctl_add(rtd->card->snd_card, kctl); + if (ret < 0) + return ret; + /* add ELD ctl with the device number corresponding to the PCM stream */ kctl = snd_ctl_new1(&hdmi_eld_ctl, dai->component); if (!kctl) @@ -647,14 +710,20 @@ static int hdmi_dai_probe(struct snd_soc_dai *dai) { struct snd_soc_dapm_context *dapm; struct hdmi_codec_daifmt *daifmt; - struct snd_soc_dapm_route route = { - .sink = "TX", - .source = dai->driver->playback.stream_name, + struct snd_soc_dapm_route route[] = { + { + .sink = "TX", + .source = dai->driver->playback.stream_name, + }, + { + .sink = dai->driver->playback.stream_name, + .source = "RX", + }, }; int ret; dapm = snd_soc_component_get_dapm(dai->component); - ret = snd_soc_dapm_add_routes(dapm, &route, 1); + ret = snd_soc_dapm_add_routes(dapm, route, 2); if (ret) return ret; @@ -744,6 +813,14 @@ static const struct snd_soc_dai_driver hdmi_i2s_dai = { .sig_bits = 24, }, .ops = &hdmi_codec_i2s_dai_ops, + .capture = { + .stream_name = "Capture", + .channels_min = 2, + .channels_max = 8, + .rates = HDMI_RATES, + .formats = I2S_FORMATS, + .sig_bits = 24, + }, .pcm_new = hdmi_codec_pcm_new, }; @@ -760,6 +837,13 @@ static const struct snd_soc_dai_driver hdmi_spdif_dai = { .formats = SPDIF_FORMATS, }, .ops = &hdmi_codec_spdif_dai_ops, + .capture = { + .stream_name = "Capture", + .channels_min = 2, + .channels_max = 2, + .rates = HDMI_RATES, + .formats = SPDIF_FORMATS, + }, .pcm_new = hdmi_codec_pcm_new, }; |