diff --git a/sound/soc/intel/avs/pcm.c b/sound/soc/intel/avs/pcm.c index dac463390da1..d7d3c696be28 100644 --- a/sound/soc/intel/avs/pcm.c +++ b/sound/soc/intel/avs/pcm.c @@ -32,6 +32,7 @@ struct avs_dma_data { }; struct work_struct period_elapsed_work; + struct hdac_ext_link *link; struct snd_pcm_substream *substream; }; @@ -278,32 +279,75 @@ static const struct snd_soc_dai_ops avs_dai_nonhda_be_ops = { .trigger = avs_dai_nonhda_be_trigger, }; -static int avs_dai_hda_be_startup(struct snd_pcm_substream *substream, struct snd_soc_dai *dai) +static int __avs_dai_hda_be_startup(struct snd_pcm_substream *substream, struct snd_soc_dai *dai, + struct hdac_ext_link *link) { - struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream); struct hdac_ext_stream *link_stream; struct avs_dma_data *data; - struct hda_codec *codec; int ret; ret = avs_dai_startup(substream, dai); if (ret) return ret; - codec = dev_to_hda_codec(snd_soc_rtd_to_codec(rtd, 0)->dev); - link_stream = snd_hdac_ext_stream_assign(&codec->bus->core, substream, + data = snd_soc_dai_get_dma_data(dai, substream); + link_stream = snd_hdac_ext_stream_assign(&data->adev->base.core, substream, HDAC_EXT_STREAM_TYPE_LINK); if (!link_stream) { avs_dai_shutdown(substream, dai); return -EBUSY; } - data = snd_soc_dai_get_dma_data(dai, substream); data->link_stream = link_stream; - substream->runtime->private_data = link_stream; + data->link = link; return 0; } +static int avs_dai_hda_be_startup(struct snd_pcm_substream *substream, struct snd_soc_dai *dai) +{ + struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream); + struct hdac_ext_link *link; + struct avs_dma_data *data; + struct hda_codec *codec; + int ret; + + codec = dev_to_hda_codec(snd_soc_rtd_to_codec(rtd, 0)->dev); + + link = snd_hdac_ext_bus_get_hlink_by_addr(&codec->bus->core, codec->core.addr); + if (!link) + return -EINVAL; + + ret = __avs_dai_hda_be_startup(substream, dai, link); + if (!ret) { + data = snd_soc_dai_get_dma_data(dai, substream); + substream->runtime->private_data = data->link_stream; + } + + return ret; +} + +static int avs_dai_i2shda_be_startup(struct snd_pcm_substream *substream, struct snd_soc_dai *dai) +{ + struct avs_dev *adev = to_avs_dev(dai->component->dev); + struct hdac_ext_link *link; + + link = snd_hdac_ext_bus_get_hlink_by_id(&adev->base.core, AZX_REG_ML_LEPTR_ID_INTEL_SSP); + if (!link) + return -EINVAL; + return __avs_dai_hda_be_startup(substream, dai, link); +} + +static int avs_dai_dmichda_be_startup(struct snd_pcm_substream *substream, struct snd_soc_dai *dai) +{ + struct avs_dev *adev = to_avs_dev(dai->component->dev); + struct hdac_ext_link *link; + + link = snd_hdac_ext_bus_get_hlink_by_id(&adev->base.core, AZX_REG_ML_LEPTR_ID_INTEL_DMIC); + if (!link) + return -EINVAL; + return __avs_dai_hda_be_startup(substream, dai, link); +} + static void avs_dai_hda_be_shutdown(struct snd_pcm_substream *substream, struct snd_soc_dai *dai) { struct avs_dma_data *data = snd_soc_dai_get_dma_data(dai, substream); @@ -313,6 +357,14 @@ static void avs_dai_hda_be_shutdown(struct snd_pcm_substream *substream, struct avs_dai_shutdown(substream, dai); } +static void avs_dai_althda_be_shutdown(struct snd_pcm_substream *substream, struct snd_soc_dai *dai) +{ + struct avs_dma_data *data = snd_soc_dai_get_dma_data(dai, substream); + + snd_hdac_ext_stream_release(data->link_stream, HDAC_EXT_STREAM_TYPE_LINK); + avs_dai_shutdown(substream, dai); +} + static int avs_dai_hda_be_hw_params(struct snd_pcm_substream *substream, struct snd_pcm_hw_params *hw_params, struct snd_soc_dai *dai) { @@ -328,13 +380,8 @@ static int avs_dai_hda_be_hw_params(struct snd_pcm_substream *substream, static int avs_dai_hda_be_hw_free(struct snd_pcm_substream *substream, struct snd_soc_dai *dai) { - struct avs_dma_data *data; - struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream); struct hdac_ext_stream *link_stream; - struct hdac_ext_link *link; - struct hda_codec *codec; - - dev_dbg(dai->dev, "%s: %s\n", __func__, dai->name); + struct avs_dma_data *data; data = snd_soc_dai_get_dma_data(dai, substream); if (!data->path) @@ -346,27 +393,19 @@ static int avs_dai_hda_be_hw_free(struct snd_pcm_substream *substream, struct sn data->path = NULL; /* clear link <-> stream mapping */ - codec = dev_to_hda_codec(snd_soc_rtd_to_codec(rtd, 0)->dev); - link = snd_hdac_ext_bus_get_hlink_by_addr(&codec->bus->core, codec->core.addr); - if (!link) - return -EINVAL; - if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) - snd_hdac_ext_bus_link_clear_stream_id(link, hdac_stream(link_stream)->stream_tag); + snd_hdac_ext_bus_link_clear_stream_id(data->link, + hdac_stream(link_stream)->stream_tag); return 0; } static int avs_dai_hda_be_prepare(struct snd_pcm_substream *substream, struct snd_soc_dai *dai) { - struct snd_soc_pcm_runtime *rtd = snd_soc_substream_to_rtd(substream); struct snd_pcm_runtime *runtime = substream->runtime; const struct snd_soc_pcm_stream *stream_info; struct hdac_ext_stream *link_stream; - struct hdac_ext_link *link; struct avs_dma_data *data; - struct hda_codec *codec; - struct hdac_bus *bus; unsigned int format_val; unsigned int bits; int ret; @@ -377,23 +416,18 @@ static int avs_dai_hda_be_prepare(struct snd_pcm_substream *substream, struct sn if (link_stream->link_prepared) return 0; - codec = dev_to_hda_codec(snd_soc_rtd_to_codec(rtd, 0)->dev); - bus = &codec->bus->core; stream_info = snd_soc_dai_get_pcm_stream(dai, substream->stream); bits = snd_hdac_stream_format_bits(runtime->format, runtime->subformat, stream_info->sig_bits); format_val = snd_hdac_stream_format(runtime->channels, bits, runtime->rate); - snd_hdac_ext_stream_decouple(bus, link_stream, true); + snd_hdac_ext_stream_decouple(&data->adev->base.core, link_stream, true); snd_hdac_ext_stream_reset(link_stream); snd_hdac_ext_stream_setup(link_stream, format_val); - link = snd_hdac_ext_bus_get_hlink_by_addr(bus, codec->core.addr); - if (!link) - return -EINVAL; - if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) - snd_hdac_ext_bus_link_set_stream_id(link, hdac_stream(link_stream)->stream_tag); + snd_hdac_ext_bus_link_set_stream_id(data->link, + hdac_stream(link_stream)->stream_tag); ret = avs_dai_prepare(substream, dai); if (ret) @@ -468,6 +502,26 @@ static const struct snd_soc_dai_ops avs_dai_hda_be_ops = { .trigger = avs_dai_hda_be_trigger, }; +__maybe_unused +static const struct snd_soc_dai_ops avs_dai_i2shda_be_ops = { + .startup = avs_dai_i2shda_be_startup, + .shutdown = avs_dai_althda_be_shutdown, + .hw_params = avs_dai_hda_be_hw_params, + .hw_free = avs_dai_hda_be_hw_free, + .prepare = avs_dai_hda_be_prepare, + .trigger = avs_dai_hda_be_trigger, +}; + +__maybe_unused +static const struct snd_soc_dai_ops avs_dai_dmichda_be_ops = { + .startup = avs_dai_dmichda_be_startup, + .shutdown = avs_dai_althda_be_shutdown, + .hw_params = avs_dai_hda_be_hw_params, + .hw_free = avs_dai_hda_be_hw_free, + .prepare = avs_dai_hda_be_prepare, + .trigger = avs_dai_hda_be_trigger, +}; + static int hw_rule_param_size(struct snd_pcm_hw_params *params, struct snd_pcm_hw_rule *rule) { struct snd_interval *interval = hw_param_interval(params, rule->var);