diff options
Diffstat (limited to 'sound/soc/codecs/hdmi-codec.c')
| -rw-r--r-- | sound/soc/codecs/hdmi-codec.c | 460 |
1 files changed, 306 insertions, 154 deletions
diff --git a/sound/soc/codecs/hdmi-codec.c b/sound/soc/codecs/hdmi-codec.c index b61f980cabdc..13ae9e83bc21 100644 --- a/sound/soc/codecs/hdmi-codec.c +++ b/sound/soc/codecs/hdmi-codec.c @@ -17,13 +17,10 @@ #include <sound/pcm_iec958.h> #include <drm/drm_crtc.h> /* This is only to get MAX_ELD_BYTES */ +#include <drm/drm_eld.h> #define HDMI_CODEC_CHMAP_IDX_UNKNOWN -1 -struct hdmi_codec_channel_map_table { - unsigned char map; /* ALSA API channel map position */ -}; - /* * CEA speaker placement for HDMI 1.4: * @@ -188,96 +185,111 @@ static const struct snd_pcm_chmap_elem hdmi_codec_8ch_chmaps[] = { /* * hdmi_codec_channel_alloc: speaker configuration available for CEA * - * This is an ordered list that must match with hdmi_codec_8ch_chmaps struct + * This is an ordered list where ca_id must exist in hdmi_codec_8ch_chmaps * The preceding ones have better chances to be selected by * hdmi_codec_get_ch_alloc_table_idx(). */ static const struct hdmi_codec_cea_spk_alloc hdmi_codec_channel_alloc[] = { { .ca_id = 0x00, .n_ch = 2, - .mask = FL | FR}, - /* 2.1 */ - { .ca_id = 0x01, .n_ch = 4, - .mask = FL | FR | LFE}, - /* Dolby Surround */ + .mask = FL | FR }, + { .ca_id = 0x03, .n_ch = 4, + .mask = FL | FR | LFE | FC }, { .ca_id = 0x02, .n_ch = 4, .mask = FL | FR | FC }, - /* surround51 */ + { .ca_id = 0x01, .n_ch = 4, + .mask = FL | FR | LFE }, { .ca_id = 0x0b, .n_ch = 6, - .mask = FL | FR | LFE | FC | RL | RR}, - /* surround40 */ - { .ca_id = 0x08, .n_ch = 6, - .mask = FL | FR | RL | RR }, - /* surround41 */ - { .ca_id = 0x09, .n_ch = 6, - .mask = FL | FR | LFE | RL | RR }, - /* surround50 */ + .mask = FL | FR | LFE | FC | RL | RR }, { .ca_id = 0x0a, .n_ch = 6, .mask = FL | FR | FC | RL | RR }, - /* 6.1 */ - { .ca_id = 0x0f, .n_ch = 8, - .mask = FL | FR | LFE | FC | RL | RR | RC }, - /* surround71 */ + { .ca_id = 0x09, .n_ch = 6, + .mask = FL | FR | LFE | RL | RR }, + { .ca_id = 0x08, .n_ch = 6, + .mask = FL | FR | RL | RR }, + { .ca_id = 0x07, .n_ch = 6, + .mask = FL | FR | LFE | FC | RC }, + { .ca_id = 0x06, .n_ch = 6, + .mask = FL | FR | FC | RC }, + { .ca_id = 0x05, .n_ch = 6, + .mask = FL | FR | LFE | RC }, + { .ca_id = 0x04, .n_ch = 6, + .mask = FL | FR | RC }, { .ca_id = 0x13, .n_ch = 8, .mask = FL | FR | LFE | FC | RL | RR | RLC | RRC }, - /* others */ - { .ca_id = 0x03, .n_ch = 8, - .mask = FL | FR | LFE | FC }, - { .ca_id = 0x04, .n_ch = 8, - .mask = FL | FR | RC}, - { .ca_id = 0x05, .n_ch = 8, - .mask = FL | FR | LFE | RC }, - { .ca_id = 0x06, .n_ch = 8, - .mask = FL | FR | FC | RC }, - { .ca_id = 0x07, .n_ch = 8, - .mask = FL | FR | LFE | FC | RC }, - { .ca_id = 0x0c, .n_ch = 8, - .mask = FL | FR | RC | RL | RR }, - { .ca_id = 0x0d, .n_ch = 8, - .mask = FL | FR | LFE | RL | RR | RC }, - { .ca_id = 0x0e, .n_ch = 8, - .mask = FL | FR | FC | RL | RR | RC }, - { .ca_id = 0x10, .n_ch = 8, - .mask = FL | FR | RL | RR | RLC | RRC }, - { .ca_id = 0x11, .n_ch = 8, - .mask = FL | FR | LFE | RL | RR | RLC | RRC }, + { .ca_id = 0x1f, .n_ch = 8, + .mask = FL | FR | LFE | FC | RL | RR | FLC | FRC }, { .ca_id = 0x12, .n_ch = 8, .mask = FL | FR | FC | RL | RR | RLC | RRC }, - { .ca_id = 0x14, .n_ch = 8, - .mask = FL | FR | FLC | FRC }, - { .ca_id = 0x15, .n_ch = 8, - .mask = FL | FR | LFE | FLC | FRC }, - { .ca_id = 0x16, .n_ch = 8, - .mask = FL | FR | FC | FLC | FRC }, - { .ca_id = 0x17, .n_ch = 8, - .mask = FL | FR | LFE | FC | FLC | FRC }, - { .ca_id = 0x18, .n_ch = 8, - .mask = FL | FR | RC | FLC | FRC }, - { .ca_id = 0x19, .n_ch = 8, - .mask = FL | FR | LFE | RC | FLC | FRC }, - { .ca_id = 0x1a, .n_ch = 8, - .mask = FL | FR | RC | FC | FLC | FRC }, - { .ca_id = 0x1b, .n_ch = 8, - .mask = FL | FR | LFE | RC | FC | FLC | FRC }, - { .ca_id = 0x1c, .n_ch = 8, - .mask = FL | FR | RL | RR | FLC | FRC }, - { .ca_id = 0x1d, .n_ch = 8, - .mask = FL | FR | LFE | RL | RR | FLC | FRC }, { .ca_id = 0x1e, .n_ch = 8, .mask = FL | FR | FC | RL | RR | FLC | FRC }, - { .ca_id = 0x1f, .n_ch = 8, - .mask = FL | FR | LFE | FC | RL | RR | FLC | FRC }, + { .ca_id = 0x11, .n_ch = 8, + .mask = FL | FR | LFE | RL | RR | RLC | RRC }, + { .ca_id = 0x1d, .n_ch = 8, + .mask = FL | FR | LFE | RL | RR | FLC | FRC }, + { .ca_id = 0x10, .n_ch = 8, + .mask = FL | FR | RL | RR | RLC | RRC }, + { .ca_id = 0x1c, .n_ch = 8, + .mask = FL | FR | RL | RR | FLC | FRC }, + { .ca_id = 0x0f, .n_ch = 8, + .mask = FL | FR | LFE | FC | RL | RR | RC }, + { .ca_id = 0x1b, .n_ch = 8, + .mask = FL | FR | LFE | RC | FC | FLC | FRC }, + { .ca_id = 0x0e, .n_ch = 8, + .mask = FL | FR | FC | RL | RR | RC }, + { .ca_id = 0x1a, .n_ch = 8, + .mask = FL | FR | RC | FC | FLC | FRC }, + { .ca_id = 0x0d, .n_ch = 8, + .mask = FL | FR | LFE | RL | RR | RC }, + { .ca_id = 0x19, .n_ch = 8, + .mask = FL | FR | LFE | RC | FLC | FRC }, + { .ca_id = 0x0c, .n_ch = 8, + .mask = FL | FR | RC | RL | RR }, + { .ca_id = 0x18, .n_ch = 8, + .mask = FL | FR | RC | FLC | FRC }, + { .ca_id = 0x17, .n_ch = 8, + .mask = FL | FR | LFE | FC | FLC | FRC }, + { .ca_id = 0x16, .n_ch = 8, + .mask = FL | FR | FC | FLC | FRC }, + { .ca_id = 0x15, .n_ch = 8, + .mask = FL | FR | LFE | FLC | FRC }, + { .ca_id = 0x14, .n_ch = 8, + .mask = FL | FR | FLC | FRC }, + { .ca_id = 0x0b, .n_ch = 8, + .mask = FL | FR | LFE | FC | RL | RR }, + { .ca_id = 0x0a, .n_ch = 8, + .mask = FL | FR | FC | RL | RR }, + { .ca_id = 0x09, .n_ch = 8, + .mask = FL | FR | LFE | RL | RR }, + { .ca_id = 0x08, .n_ch = 8, + .mask = FL | FR | RL | RR }, + { .ca_id = 0x07, .n_ch = 8, + .mask = FL | FR | LFE | FC | RC }, + { .ca_id = 0x06, .n_ch = 8, + .mask = FL | FR | FC | RC }, + { .ca_id = 0x05, .n_ch = 8, + .mask = FL | FR | LFE | RC }, + { .ca_id = 0x04, .n_ch = 8, + .mask = FL | FR | RC }, + { .ca_id = 0x03, .n_ch = 8, + .mask = FL | FR | LFE | FC }, + { .ca_id = 0x02, .n_ch = 8, + .mask = FL | FR | FC }, + { .ca_id = 0x01, .n_ch = 8, + .mask = FL | FR | LFE }, }; struct hdmi_codec_priv { struct hdmi_codec_pdata hcd; uint8_t eld[MAX_ELD_BYTES]; + struct snd_parsed_hdmi_eld eld_parsed; struct snd_pcm_chmap *chmap_info; unsigned int chmap_idx; struct mutex lock; bool busy; struct snd_soc_jack *jack; unsigned int jack_status; - u8 iec_status[5]; + u8 iec_status[AES_IEC958_STATUS_SIZE]; + struct snd_info_entry *proc_entry; }; static const struct snd_soc_dapm_widget hdmi_widgets[] = { @@ -374,7 +386,8 @@ static int hdmi_codec_chmap_ctl_get(struct snd_kcontrol *kcontrol, struct snd_pcm_chmap *info = snd_kcontrol_chip(kcontrol); struct hdmi_codec_priv *hcp = info->private_data; - map = info->chmap[hcp->chmap_idx].map; + if (hcp->chmap_idx != HDMI_CODEC_CHMAP_IDX_UNKNOWN) + map = info->chmap[hcp->chmap_idx].map; for (i = 0; i < info->max_channels; i++) { if (hcp->chmap_idx == HDMI_CODEC_CHMAP_IDX_UNKNOWN) @@ -432,8 +445,13 @@ static int hdmi_codec_startup(struct snd_pcm_substream *substream, { struct hdmi_codec_priv *hcp = snd_soc_dai_get_drvdata(dai); bool tx = substream->stream == SNDRV_PCM_STREAM_PLAYBACK; + bool has_capture = !hcp->hcd.no_i2s_capture; + bool has_playback = !hcp->hcd.no_i2s_playback; int ret = 0; + if (!((has_playback && tx) || (has_capture && !tx))) + return 0; + mutex_lock(&hcp->lock); if (hcp->busy) { dev_err(dai->dev, "Only one simultaneous stream supported!\n"); @@ -453,6 +471,9 @@ static int hdmi_codec_startup(struct snd_pcm_substream *substream, if (ret) goto err; + snd_parse_eld(dai->dev, &hcp->eld_parsed, + hcp->eld, sizeof(hcp->eld)); + ret = snd_pcm_hw_constraint_eld(substream->runtime, hcp->eld); if (ret) goto err; @@ -472,6 +493,12 @@ static void hdmi_codec_shutdown(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; + bool has_capture = !hcp->hcd.no_i2s_capture; + bool has_playback = !hcp->hcd.no_i2s_playback; + + if (!((has_playback && tx) || (has_capture && !tx))) + return; hcp->chmap_idx = HDMI_CODEC_CHMAP_IDX_UNKNOWN; hcp->hcd.ops->audio_shutdown(dai->dev->parent, hcp->hcd.data); @@ -488,31 +515,46 @@ static int hdmi_codec_fill_codec_params(struct snd_soc_dai *dai, struct hdmi_codec_params *hp) { struct hdmi_codec_priv *hcp = snd_soc_dai_get_drvdata(dai); - int idx; + int idx = HDMI_CODEC_CHMAP_IDX_UNKNOWN; + u8 ca_id = 0; + bool pcm_audio = !(hcp->iec_status[0] & IEC958_AES0_NONAUDIO); + + if (pcm_audio) { + /* Select a channel allocation that matches with ELD and pcm channels */ + idx = hdmi_codec_get_ch_alloc_table_idx(hcp, 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; + } - /* Select a channel allocation that matches with ELD and pcm channels */ - idx = hdmi_codec_get_ch_alloc_table_idx(hcp, 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; + ca_id = hdmi_codec_channel_alloc[idx].ca_id; } memset(hp, 0, sizeof(*hp)); hdmi_audio_infoframe_init(&hp->cea); - hp->cea.channels = channels; + + if (pcm_audio) + hp->cea.channels = channels; + else + hp->cea.channels = 0; + hp->cea.coding_type = HDMI_AUDIO_CODING_TYPE_STREAM; hp->cea.sample_size = HDMI_AUDIO_SAMPLE_SIZE_STREAM; hp->cea.sample_frequency = HDMI_AUDIO_SAMPLE_FREQUENCY_STREAM; - hp->cea.channel_allocation = hdmi_codec_channel_alloc[idx].ca_id; + hp->cea.channel_allocation = ca_id; hp->sample_width = sample_width; hp->sample_rate = sample_rate; hp->channels = channels; - hcp->chmap_idx = hdmi_codec_channel_alloc[idx].ca_id; + if (pcm_audio) + hcp->chmap_idx = ca_id; + else + hcp->chmap_idx = HDMI_CODEC_CHMAP_IDX_UNKNOWN; return 0; } @@ -522,7 +564,7 @@ static int hdmi_codec_hw_params(struct snd_pcm_substream *substream, struct snd_soc_dai *dai) { struct hdmi_codec_priv *hcp = snd_soc_dai_get_drvdata(dai); - struct hdmi_codec_daifmt *cf = dai->playback_dma_data; + struct hdmi_codec_daifmt *cf = snd_soc_dai_dma_data_get_playback(dai); struct hdmi_codec_params hp = { .iec = { .status = { 0 }, @@ -566,7 +608,7 @@ static int hdmi_codec_prepare(struct snd_pcm_substream *substream, struct snd_soc_dai *dai) { struct hdmi_codec_priv *hcp = snd_soc_dai_get_drvdata(dai); - struct hdmi_codec_daifmt *cf = dai->playback_dma_data; + struct hdmi_codec_daifmt *cf = snd_soc_dai_dma_data_get_playback(dai); struct snd_pcm_runtime *runtime = substream->runtime; unsigned int channels = runtime->channels; unsigned int width = snd_pcm_format_width(runtime->format); @@ -601,23 +643,23 @@ static int hdmi_codec_prepare(struct snd_pcm_substream *substream, static int hdmi_codec_i2s_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) { - struct hdmi_codec_daifmt *cf = dai->playback_dma_data; + struct hdmi_codec_daifmt *cf = snd_soc_dai_dma_data_get_playback(dai); /* Reset daifmt */ memset(cf, 0, sizeof(*cf)); - switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) { - case SND_SOC_DAIFMT_CBM_CFM: - cf->bit_clk_master = 1; - cf->frame_clk_master = 1; + switch (fmt & SND_SOC_DAIFMT_CLOCK_PROVIDER_MASK) { + case SND_SOC_DAIFMT_CBP_CFP: + cf->bit_clk_provider = 1; + cf->frame_clk_provider = 1; break; - case SND_SOC_DAIFMT_CBS_CFM: - cf->frame_clk_master = 1; + case SND_SOC_DAIFMT_CBC_CFP: + cf->frame_clk_provider = 1; break; - case SND_SOC_DAIFMT_CBM_CFS: - cf->bit_clk_master = 1; + case SND_SOC_DAIFMT_CBP_CFC: + cf->bit_clk_provider = 1; break; - case SND_SOC_DAIFMT_CBS_CFS: + case SND_SOC_DAIFMT_CBC_CFC: break; default: return -EINVAL; @@ -677,7 +719,7 @@ static int hdmi_codec_mute(struct snd_soc_dai *dai, int mute, int direction) */ if (hcp->hcd.ops->mute_stream && (direction == SNDRV_PCM_STREAM_PLAYBACK || - !hcp->hcd.ops->no_capture_mute)) + !hcp->hcd.no_capture_mute)) return hcp->hcd.ops->mute_stream(dai->dev->parent, hcp->hcd.data, mute, direction); @@ -692,7 +734,7 @@ static int hdmi_codec_mute(struct snd_soc_dai *dai, int mute, int direction) * For example, * ${LINUX}/drivers/gpu/drm/bridge/synopsys/dw-hdmi-i2s-audio.c */ -static u64 hdmi_codec_formats = +static const u64 hdmi_codec_formats = SND_SOC_POSSIBLE_DAIFMT_NB_NF | SND_SOC_POSSIBLE_DAIFMT_NB_IF | SND_SOC_POSSIBLE_DAIFMT_IB_NF | @@ -704,33 +746,13 @@ static u64 hdmi_codec_formats = SND_SOC_POSSIBLE_DAIFMT_LEFT_J | SND_SOC_POSSIBLE_DAIFMT_AC97; -static const struct snd_soc_dai_ops hdmi_codec_i2s_dai_ops = { - .startup = hdmi_codec_startup, - .shutdown = hdmi_codec_shutdown, - .hw_params = hdmi_codec_hw_params, - .prepare = hdmi_codec_prepare, - .set_fmt = hdmi_codec_i2s_set_fmt, - .mute_stream = hdmi_codec_mute, - .auto_selectable_formats = &hdmi_codec_formats, - .num_auto_selectable_formats = 1, -}; - -static const struct snd_soc_dai_ops hdmi_codec_spdif_dai_ops = { - .startup = hdmi_codec_startup, - .shutdown = hdmi_codec_shutdown, - .hw_params = hdmi_codec_hw_params, - .mute_stream = hdmi_codec_mute, -}; - #define HDMI_RATES (SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 |\ SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_88200 |\ SNDRV_PCM_RATE_96000 | SNDRV_PCM_RATE_176400 |\ SNDRV_PCM_RATE_192000) -#define SPDIF_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S16_BE |\ - SNDRV_PCM_FMTBIT_S20_3LE | SNDRV_PCM_FMTBIT_S20_3BE |\ - SNDRV_PCM_FMTBIT_S24_3LE | SNDRV_PCM_FMTBIT_S24_3BE |\ - SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S24_BE) +#define SPDIF_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE |\ + SNDRV_PCM_FMTBIT_S24_3LE | SNDRV_PCM_FMTBIT_S24_LE) /* * This list is only for formats allowed on the I2S bus. So there is @@ -740,12 +762,9 @@ static const struct snd_soc_dai_ops hdmi_codec_spdif_dai_ops = { * problems, we should add the video side driver an option to disable * them. */ -#define I2S_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S16_BE |\ - SNDRV_PCM_FMTBIT_S20_3LE | SNDRV_PCM_FMTBIT_S20_3BE |\ - SNDRV_PCM_FMTBIT_S24_3LE | SNDRV_PCM_FMTBIT_S24_3BE |\ - SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S24_BE |\ - SNDRV_PCM_FMTBIT_S32_LE | SNDRV_PCM_FMTBIT_S32_BE |\ - SNDRV_PCM_FMTBIT_IEC958_SUBFRAME_LE) +#define I2S_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE |\ + SNDRV_PCM_FMTBIT_S24_3LE | SNDRV_PCM_FMTBIT_S24_LE |\ + SNDRV_PCM_FMTBIT_S32_LE | SNDRV_PCM_FMTBIT_IEC958_SUBFRAME_LE) static struct snd_kcontrol_new hdmi_codec_controls[] = { { @@ -811,8 +830,70 @@ static int hdmi_codec_pcm_new(struct snd_soc_pcm_runtime *rtd, return 0; } +#ifdef CONFIG_SND_PROC_FS +static void print_eld_info(struct snd_info_entry *entry, + struct snd_info_buffer *buffer) +{ + struct hdmi_codec_priv *hcp = entry->private_data; + + snd_print_eld_info(&hcp->eld_parsed, buffer); +} + +static int hdmi_dai_proc_new(struct hdmi_codec_priv *hcp, + struct snd_soc_dai *dai) +{ + struct snd_soc_component *component = dai->component; + struct snd_soc_card *card = component->card; + struct snd_soc_dai *d; + struct snd_soc_pcm_runtime *rtd; + struct snd_info_entry *entry; + char name[32]; + int err, i, id = 0; + + /* + * To avoid duplicate proc entry, find its rtd and use rtd->id + * instead of dai->id + */ + for_each_card_rtds(card, rtd) { + for_each_rtd_dais(rtd, i, d) + if (d == dai) { + id = rtd->id; + goto found; + } + } +found: + snprintf(name, sizeof(name), "eld#%d", id); + err = snd_card_proc_new(card->snd_card, name, &entry); + if (err < 0) + return err; + + snd_info_set_text_ops(entry, hcp, print_eld_info); + hcp->proc_entry = entry; + + return 0; +} + +static void hdmi_dai_proc_free(struct hdmi_codec_priv *hcp) +{ + snd_info_free_entry(hcp->proc_entry); + hcp->proc_entry = NULL; +} +#else +static int hdmi_dai_proc_new(struct hdmi_codec_priv *hcp, + struct snd_soc_dai *dai) +{ + return 0; +} + +static void hdmi_dai_proc_free(struct hdmi_codec_priv *hcp) +{ +} +#endif + static int hdmi_dai_probe(struct snd_soc_dai *dai) { + struct hdmi_codec_priv *hcp = + snd_soc_component_get_drvdata(dai->component); struct snd_soc_dapm_context *dapm; struct hdmi_codec_daifmt *daifmt; struct snd_soc_dapm_route route[] = { @@ -825,26 +906,44 @@ static int hdmi_dai_probe(struct snd_soc_dai *dai) .source = "RX", }, }; - int ret; + int ret, i; - dapm = snd_soc_component_get_dapm(dai->component); - ret = snd_soc_dapm_add_routes(dapm, route, 2); - if (ret) - return ret; + dapm = snd_soc_component_to_dapm(dai->component); + + /* One of the directions might be omitted for unidirectional DAIs */ + for (i = 0; i < ARRAY_SIZE(route); i++) { + if (!route[i].source || !route[i].sink) + continue; - daifmt = kzalloc(sizeof(*daifmt), GFP_KERNEL); + ret = snd_soc_dapm_add_routes(dapm, &route[i], 1); + if (ret) + return ret; + } + + daifmt = devm_kzalloc(dai->dev, sizeof(*daifmt), GFP_KERNEL); if (!daifmt) return -ENOMEM; - dai->playback_dma_data = daifmt; + snd_soc_dai_dma_data_set_playback(dai, daifmt); + + return hdmi_dai_proc_new(hcp, dai); +} + +static int hdmi_dai_remove(struct snd_soc_dai *dai) +{ + struct hdmi_codec_priv *hcp = + snd_soc_component_get_drvdata(dai->component); + + hdmi_dai_proc_free(hcp); return 0; } static void hdmi_codec_jack_report(struct hdmi_codec_priv *hcp, unsigned int jack_status) { - if (hcp->jack && jack_status != hcp->jack_status) { - snd_soc_jack_report(hcp->jack, jack_status, SND_JACK_LINEOUT); + if (jack_status != hcp->jack_status) { + if (hcp->jack) + snd_soc_jack_report(hcp->jack, jack_status, SND_JACK_AVOUT); hcp->jack_status = jack_status; } } @@ -852,13 +951,20 @@ static void hdmi_codec_jack_report(struct hdmi_codec_priv *hcp, static void plugged_cb(struct device *dev, bool plugged) { struct hdmi_codec_priv *hcp = dev_get_drvdata(dev); + int ret; if (plugged) { if (hcp->hcd.ops->get_eld) { hcp->hcd.ops->get_eld(dev->parent, hcp->hcd.data, hcp->eld, sizeof(hcp->eld)); + ret = snd_parse_eld(dev, &hcp->eld_parsed, + hcp->eld, sizeof(hcp->eld)); + if (ret < 0) + dev_dbg(dev, "Failed to parse ELD: %d\n", ret); + else + snd_show_eld(dev, &hcp->eld_parsed); } - hdmi_codec_jack_report(hcp, SND_JACK_LINEOUT); + hdmi_codec_jack_report(hcp, SND_JACK_AVOUT); } else { hdmi_codec_jack_report(hcp, 0); memset(hcp->eld, 0, sizeof(hcp->eld)); @@ -870,18 +976,20 @@ static int hdmi_codec_set_jack(struct snd_soc_component *component, void *data) { struct hdmi_codec_priv *hcp = snd_soc_component_get_drvdata(component); - int ret = -ENOTSUPP; if (hcp->hcd.ops->hook_plugged_cb) { hcp->jack = jack; - ret = hcp->hcd.ops->hook_plugged_cb(component->dev->parent, - hcp->hcd.data, - plugged_cb, - component->dev); - if (ret) - hcp->jack = NULL; + + /* + * Report the initial jack status which may have been provided + * by the parent hdmi driver while the hpd hook was registered. + */ + snd_soc_jack_report(jack, hcp->jack_status, SND_JACK_AVOUT); + + return 0; } - return ret; + + return -ENOTSUPP; } static int hdmi_dai_spdif_probe(struct snd_soc_dai *dai) @@ -893,23 +1001,39 @@ static int hdmi_dai_spdif_probe(struct snd_soc_dai *dai) if (ret) return ret; - cf = dai->playback_dma_data; + cf = snd_soc_dai_dma_data_get_playback(dai); cf->fmt = HDMI_SPDIF; return 0; } -static int hdmi_codec_dai_remove(struct snd_soc_dai *dai) -{ - kfree(dai->playback_dma_data); - return 0; -} +static const struct snd_soc_dai_ops hdmi_codec_i2s_dai_ops = { + .probe = hdmi_dai_probe, + .remove = hdmi_dai_remove, + .startup = hdmi_codec_startup, + .shutdown = hdmi_codec_shutdown, + .hw_params = hdmi_codec_hw_params, + .prepare = hdmi_codec_prepare, + .set_fmt = hdmi_codec_i2s_set_fmt, + .mute_stream = hdmi_codec_mute, + .pcm_new = hdmi_codec_pcm_new, + .auto_selectable_formats = &hdmi_codec_formats, + .num_auto_selectable_formats = 1, +}; + +static const struct snd_soc_dai_ops hdmi_codec_spdif_dai_ops = { + .probe = hdmi_dai_spdif_probe, + .startup = hdmi_codec_startup, + .shutdown = hdmi_codec_shutdown, + .hw_params = hdmi_codec_hw_params, + .prepare = hdmi_codec_prepare, + .mute_stream = hdmi_codec_mute, + .pcm_new = hdmi_codec_pcm_new, +}; static const struct snd_soc_dai_driver hdmi_i2s_dai = { .name = "i2s-hifi", .id = DAI_ID_I2S, - .probe = hdmi_dai_probe, - .remove = hdmi_codec_dai_remove, .playback = { .stream_name = "I2S Playback", .channels_min = 2, @@ -927,14 +1051,11 @@ static const struct snd_soc_dai_driver hdmi_i2s_dai = { .sig_bits = 24, }, .ops = &hdmi_codec_i2s_dai_ops, - .pcm_new = hdmi_codec_pcm_new, }; static const struct snd_soc_dai_driver hdmi_spdif_dai = { .name = "spdif-hifi", .id = DAI_ID_SPDIF, - .probe = hdmi_dai_spdif_probe, - .remove = hdmi_codec_dai_remove, .playback = { .stream_name = "SPDIF Playback", .channels_min = 2, @@ -950,7 +1071,6 @@ static const struct snd_soc_dai_driver hdmi_spdif_dai = { .formats = SPDIF_FORMATS, }, .ops = &hdmi_codec_spdif_dai_ops, - .pcm_new = hdmi_codec_pcm_new, }; static int hdmi_of_xlate_dai_id(struct snd_soc_component *component, @@ -960,7 +1080,22 @@ static int hdmi_of_xlate_dai_id(struct snd_soc_component *component, int ret = -ENOTSUPP; /* see snd_soc_get_dai_id() */ if (hcp->hcd.ops->get_dai_id) - ret = hcp->hcd.ops->get_dai_id(component, endpoint); + ret = hcp->hcd.ops->get_dai_id(component, endpoint, hcp->hcd.data); + + return ret; +} + +static int hdmi_probe(struct snd_soc_component *component) +{ + struct hdmi_codec_priv *hcp = snd_soc_component_get_drvdata(component); + int ret = 0; + + if (hcp->hcd.ops->hook_plugged_cb) { + ret = hcp->hcd.ops->hook_plugged_cb(component->dev->parent, + hcp->hcd.data, + plugged_cb, + component->dev); + } return ret; } @@ -975,6 +1110,7 @@ static void hdmi_remove(struct snd_soc_component *component) } static const struct snd_soc_component_driver hdmi_driver = { + .probe = hdmi_probe, .remove = hdmi_remove, .dapm_widgets = hdmi_widgets, .num_dapm_widgets = ARRAY_SIZE(hdmi_widgets), @@ -982,7 +1118,6 @@ static const struct snd_soc_component_driver hdmi_driver = { .idle_bias_on = 1, .use_pmdown_time = 1, .endianness = 1, - .non_legacy_dai_naming = 1, .set_jack = hdmi_codec_set_jack, }; @@ -1027,11 +1162,28 @@ static int hdmi_codec_probe(struct platform_device *pdev) if (hcd->i2s) { daidrv[i] = hdmi_i2s_dai; daidrv[i].playback.channels_max = hcd->max_i2s_channels; + if (hcd->i2s_formats) { + daidrv[i].playback.formats = hcd->i2s_formats; + daidrv[i].capture.formats = hcd->i2s_formats; + } + if (hcd->no_i2s_playback) + memset(&daidrv[i].playback, 0, + sizeof(daidrv[i].playback)); + if (hcd->no_i2s_capture) + memset(&daidrv[i].capture, 0, + sizeof(daidrv[i].capture)); i++; } - if (hcd->spdif) + if (hcd->spdif) { daidrv[i] = hdmi_spdif_dai; + if (hcd->no_spdif_playback) + memset(&daidrv[i].playback, 0, + sizeof(daidrv[i].playback)); + if (hcd->no_spdif_capture) + memset(&daidrv[i].capture, 0, + sizeof(daidrv[i].capture)); + } dev_set_drvdata(dev, hcp); |
