diff options
| author | Linus Torvalds <[email protected]> | 2019-07-09 09:59:43 -0700 |
|---|---|---|
| committer | Linus Torvalds <[email protected]> | 2019-07-09 09:59:43 -0700 |
| commit | 4cdd5f9186bbe80306e76f11da7ecb0b9720433c (patch) | |
| tree | 23c2f39933cd8253a65385eab00405beaf602f01 /sound/soc/codecs/hdmi-codec.c | |
| parent | 2d41ef5432b76ae90dc0db93026f1d981f874ec4 (diff) | |
| parent | 0dcb4efb1095d0a1f5f681c2b94e98b009cc5d77 (diff) | |
Merge tag 'sound-5.3-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/tiwai/sound
Pull sound updates from Takashi Iwai:
"Many updates in this development cycle are found in ASoC where it got
a wide range of changes for the continued refactoring.
Some highlights are below.
ASoC:
- Continued refactoring work by Morimoto-san toward the full
componentization; the changes are seen allover the places
- Support for force disconnecting muxes in DAPM
- Continued development of ASoC Intel SOF stuff
- New drivers for Cirrus Logic CS47L35, CS47L85 and CS47L90, Conexant
CX2072X, Realtek RT1011 and RT1308
HD-audio:
- More fixes and adjustments for ASoC SOF HD-audio
- Fix for resume problem on some Realtek codecs
USB-audio:
- A few fixes for the issues reported by syzbot USB fuzzer
- Fix for UAC2 extension unit parser
- Quirks for Line6 Helix, Emgaic Unitor 8
FireWire:
- Lots of code refactoring and fixes in most of its components"
* tag 'sound-5.3-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/tiwai/sound: (626 commits)
ALSA: firewire-lib: code refactoring for local variables
ALSA: firewire-lib: code refactoring for post operation to data block counter
ALSA: firewire-lib: code refactoring for error path of parser for CIP header
ALSA: firewire-lib: fix different data block counter between probed event and transferred isochronous packet
ALSA: firewire-lib: fix initial value of data block count for IR context without CIP_DBC_IS_END_EVENT
ALSA: firewire-lib/fireface: fix initial value of data block counter for IR context with CIP_NO_HEADER
ALSA: firewire-lib: fix invalid length of rx packet payload for tracepoint events
ALSA: usb-audio: fix Line6 Helix audio format rates
firewire-motu: fix wrong reference count for stream functionality at error path of rawmidi interface
ALSA: firewire-digi00x: fix wrong reference count for stream functionality at error path of rawmidi interface
ALSA: dice: fix wrong reference count for stream functionality at error path of rawmidi interface
ALSA: oxfw: fix wrong reference count for stream functionality at error path of rawmidi interface
ALSA: fireworks: fix wrong reference count for stream functionality at error path of rawmidi interface
ALSA: bebob: fix wrong reference count for stream functionality at error path of rawmidi interface
ASoC: SOF: Intel: implement runtime idle for CNL/APL
ASoC: SOF: add runtime idle callback
ASoC: hdac_hdmi: report codec link up/down status to bus
ASoC: SOF: debug: fix possible memory leak in sof_dfsentry_write()
ASoC: sunxi: sun50i-codec-analog: Add earpiece
ASoC: rt5665: remove redundant assignment to variable idx
...
Diffstat (limited to 'sound/soc/codecs/hdmi-codec.c')
| -rw-r--r-- | sound/soc/codecs/hdmi-codec.c | 188 |
1 files changed, 92 insertions, 96 deletions
diff --git a/sound/soc/codecs/hdmi-codec.c b/sound/soc/codecs/hdmi-codec.c index 615f17d4b934..0bf1c8cad108 100644 --- a/sound/soc/codecs/hdmi-codec.c +++ b/sound/soc/codecs/hdmi-codec.c @@ -270,13 +270,10 @@ static const struct hdmi_codec_cea_spk_alloc hdmi_codec_channel_alloc[] = { struct hdmi_codec_priv { struct hdmi_codec_pdata hcd; - struct snd_soc_dai_driver *daidrv; - struct hdmi_codec_daifmt daifmt[2]; - struct mutex current_stream_lock; - struct snd_pcm_substream *current_stream; uint8_t eld[MAX_ELD_BYTES]; struct snd_pcm_chmap *chmap_info; unsigned int chmap_idx; + struct mutex lock; }; static const struct snd_soc_dapm_widget hdmi_widgets[] = { @@ -384,44 +381,22 @@ static int hdmi_codec_chmap_ctl_get(struct snd_kcontrol *kcontrol, return 0; } -static int hdmi_codec_new_stream(struct snd_pcm_substream *substream, - struct snd_soc_dai *dai) -{ - struct hdmi_codec_priv *hcp = snd_soc_dai_get_drvdata(dai); - int ret = 0; - - mutex_lock(&hcp->current_stream_lock); - if (!hcp->current_stream) { - hcp->current_stream = substream; - } else if (hcp->current_stream != substream) { - dev_err(dai->dev, "Only one simultaneous stream supported!\n"); - ret = -EINVAL; - } - mutex_unlock(&hcp->current_stream_lock); - - return ret; -} - 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); int ret = 0; - dev_dbg(dai->dev, "%s()\n", __func__); - - ret = hdmi_codec_new_stream(substream, dai); - if (ret) - return ret; + ret = mutex_trylock(&hcp->lock); + if (!ret) { + dev_err(dai->dev, "Only one simultaneous stream supported!\n"); + return -EINVAL; + } if (hcp->hcd.ops->audio_startup) { ret = hcp->hcd.ops->audio_startup(dai->dev->parent, hcp->hcd.data); - if (ret) { - mutex_lock(&hcp->current_stream_lock); - hcp->current_stream = NULL; - mutex_unlock(&hcp->current_stream_lock); - return ret; - } + if (ret) + goto err; } if (hcp->hcd.ops->get_eld) { @@ -431,17 +406,18 @@ static int hdmi_codec_startup(struct snd_pcm_substream *substream, if (!ret) { ret = snd_pcm_hw_constraint_eld(substream->runtime, hcp->eld); - if (ret) { - mutex_lock(&hcp->current_stream_lock); - hcp->current_stream = NULL; - mutex_unlock(&hcp->current_stream_lock); - return ret; - } + if (ret) + goto err; } /* Select chmap supported */ hdmi_codec_eld_chmap(hcp); } return 0; + +err: + /* Release the exclusive lock on error */ + mutex_unlock(&hcp->lock); + return ret; } static void hdmi_codec_shutdown(struct snd_pcm_substream *substream, @@ -449,16 +425,10 @@ static void hdmi_codec_shutdown(struct snd_pcm_substream *substream, { struct hdmi_codec_priv *hcp = snd_soc_dai_get_drvdata(dai); - dev_dbg(dai->dev, "%s()\n", __func__); - - WARN_ON(hcp->current_stream != substream); - hcp->chmap_idx = HDMI_CODEC_CHMAP_IDX_UNKNOWN; hcp->hcd.ops->audio_shutdown(dai->dev->parent, hcp->hcd.data); - mutex_lock(&hcp->current_stream_lock); - hcp->current_stream = NULL; - mutex_unlock(&hcp->current_stream_lock); + mutex_unlock(&hcp->lock); } static int hdmi_codec_hw_params(struct snd_pcm_substream *substream, @@ -466,6 +436,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_params hp = { .iec = { .status = { 0 }, @@ -510,30 +481,27 @@ static int hdmi_codec_hw_params(struct snd_pcm_substream *substream, hp.channels = params_channels(params); return hcp->hcd.ops->hw_params(dai->dev->parent, hcp->hcd.data, - &hcp->daifmt[dai->id], &hp); + cf, &hp); } -static int hdmi_codec_set_fmt(struct snd_soc_dai *dai, - unsigned int fmt) +static int hdmi_codec_i2s_set_fmt(struct snd_soc_dai *dai, + unsigned int fmt) { - struct hdmi_codec_priv *hcp = snd_soc_dai_get_drvdata(dai); - struct hdmi_codec_daifmt cf = { 0 }; + struct hdmi_codec_daifmt *cf = dai->playback_dma_data; - dev_dbg(dai->dev, "%s()\n", __func__); - - if (dai->id == DAI_ID_SPDIF) - return 0; + /* 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; + cf->bit_clk_master = 1; + cf->frame_clk_master = 1; break; case SND_SOC_DAIFMT_CBS_CFM: - cf.frame_clk_master = 1; + cf->frame_clk_master = 1; break; case SND_SOC_DAIFMT_CBM_CFS: - cf.bit_clk_master = 1; + cf->bit_clk_master = 1; break; case SND_SOC_DAIFMT_CBS_CFS: break; @@ -545,43 +513,41 @@ static int hdmi_codec_set_fmt(struct snd_soc_dai *dai, case SND_SOC_DAIFMT_NB_NF: break; case SND_SOC_DAIFMT_NB_IF: - cf.frame_clk_inv = 1; + cf->frame_clk_inv = 1; break; case SND_SOC_DAIFMT_IB_NF: - cf.bit_clk_inv = 1; + cf->bit_clk_inv = 1; break; case SND_SOC_DAIFMT_IB_IF: - cf.frame_clk_inv = 1; - cf.bit_clk_inv = 1; + cf->frame_clk_inv = 1; + cf->bit_clk_inv = 1; break; } switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { case SND_SOC_DAIFMT_I2S: - cf.fmt = HDMI_I2S; + cf->fmt = HDMI_I2S; break; case SND_SOC_DAIFMT_DSP_A: - cf.fmt = HDMI_DSP_A; + cf->fmt = HDMI_DSP_A; break; case SND_SOC_DAIFMT_DSP_B: - cf.fmt = HDMI_DSP_B; + cf->fmt = HDMI_DSP_B; break; case SND_SOC_DAIFMT_RIGHT_J: - cf.fmt = HDMI_RIGHT_J; + cf->fmt = HDMI_RIGHT_J; break; case SND_SOC_DAIFMT_LEFT_J: - cf.fmt = HDMI_LEFT_J; + cf->fmt = HDMI_LEFT_J; break; case SND_SOC_DAIFMT_AC97: - cf.fmt = HDMI_AC97; + cf->fmt = HDMI_AC97; break; default: dev_err(dai->dev, "Invalid DAI interface format\n"); return -EINVAL; } - hcp->daifmt[dai->id] = cf; - return 0; } @@ -589,8 +555,6 @@ static int hdmi_codec_digital_mute(struct snd_soc_dai *dai, int mute) { struct hdmi_codec_priv *hcp = snd_soc_dai_get_drvdata(dai); - dev_dbg(dai->dev, "%s()\n", __func__); - if (hcp->hcd.ops->digital_mute) return hcp->hcd.ops->digital_mute(dai->dev->parent, hcp->hcd.data, mute); @@ -598,14 +562,20 @@ static int hdmi_codec_digital_mute(struct snd_soc_dai *dai, int mute) return 0; } -static const struct snd_soc_dai_ops hdmi_dai_ops = { +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, - .set_fmt = hdmi_codec_set_fmt, + .set_fmt = hdmi_codec_i2s_set_fmt, .digital_mute = hdmi_codec_digital_mute, }; +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, + .digital_mute = hdmi_codec_digital_mute, +}; #define HDMI_RATES (SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 |\ SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_88200 |\ @@ -648,8 +618,6 @@ static int hdmi_codec_pcm_new(struct snd_soc_pcm_runtime *rtd, }; int ret; - dev_dbg(dai->dev, "%s()\n", __func__); - ret = snd_pcm_add_chmap_ctls(rtd->pcm, SNDRV_PCM_STREAM_PLAYBACK, NULL, drv->playback.channels_max, 0, &hcp->chmap_info); @@ -675,20 +643,52 @@ static int hdmi_codec_pcm_new(struct snd_soc_pcm_runtime *rtd, 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, }; + int ret; dapm = snd_soc_component_get_dapm(dai->component); + ret = snd_soc_dapm_add_routes(dapm, &route, 1); + if (ret) + return ret; + + daifmt = kzalloc(sizeof(*daifmt), GFP_KERNEL); + if (!daifmt) + return -ENOMEM; + + dai->playback_dma_data = daifmt; + return 0; +} + +static int hdmi_dai_spdif_probe(struct snd_soc_dai *dai) +{ + struct hdmi_codec_daifmt *cf = dai->playback_dma_data; + int ret; + + ret = hdmi_dai_probe(dai); + if (ret) + return ret; + + cf = dai->playback_dma_data; + cf->fmt = HDMI_SPDIF; + + return 0; +} - return snd_soc_dapm_add_routes(dapm, &route, 1); +static int hdmi_codec_dai_remove(struct snd_soc_dai *dai) +{ + kfree(dai->playback_dma_data); + return 0; } 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, @@ -697,14 +697,15 @@ static const struct snd_soc_dai_driver hdmi_i2s_dai = { .formats = I2S_FORMATS, .sig_bits = 24, }, - .ops = &hdmi_dai_ops, + .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_probe, + .probe = hdmi_dai_spdif_probe, + .remove = hdmi_codec_dai_remove, .playback = { .stream_name = "SPDIF Playback", .channels_min = 2, @@ -712,7 +713,7 @@ static const struct snd_soc_dai_driver hdmi_spdif_dai = { .rates = HDMI_RATES, .formats = SPDIF_FORMATS, }, - .ops = &hdmi_dai_ops, + .ops = &hdmi_codec_spdif_dai_ops, .pcm_new = hdmi_codec_pcm_new, }; @@ -741,13 +742,12 @@ static const struct snd_soc_component_driver hdmi_driver = { static int hdmi_codec_probe(struct platform_device *pdev) { struct hdmi_codec_pdata *hcd = pdev->dev.platform_data; + struct snd_soc_dai_driver *daidrv; struct device *dev = &pdev->dev; struct hdmi_codec_priv *hcp; int dai_count, i = 0; int ret; - dev_dbg(dev, "%s()\n", __func__); - if (!hcd) { dev_err(dev, "%s: No platform data\n", __func__); return -EINVAL; @@ -765,29 +765,25 @@ static int hdmi_codec_probe(struct platform_device *pdev) return -ENOMEM; hcp->hcd = *hcd; - mutex_init(&hcp->current_stream_lock); + mutex_init(&hcp->lock); - hcp->daidrv = devm_kcalloc(dev, dai_count, sizeof(*hcp->daidrv), - GFP_KERNEL); - if (!hcp->daidrv) + daidrv = devm_kcalloc(dev, dai_count, sizeof(*daidrv), GFP_KERNEL); + if (!daidrv) return -ENOMEM; if (hcd->i2s) { - hcp->daidrv[i] = hdmi_i2s_dai; - hcp->daidrv[i].playback.channels_max = - hcd->max_i2s_channels; + daidrv[i] = hdmi_i2s_dai; + daidrv[i].playback.channels_max = hcd->max_i2s_channels; i++; } - if (hcd->spdif) { - hcp->daidrv[i] = hdmi_spdif_dai; - hcp->daifmt[DAI_ID_SPDIF].fmt = HDMI_SPDIF; - } + if (hcd->spdif) + daidrv[i] = hdmi_spdif_dai; dev_set_drvdata(dev, hcp); - ret = devm_snd_soc_register_component(dev, &hdmi_driver, hcp->daidrv, - dai_count); + ret = devm_snd_soc_register_component(dev, &hdmi_driver, daidrv, + dai_count); if (ret) { dev_err(dev, "%s: snd_soc_register_component() failed (%d)\n", __func__, ret); |