diff options
Diffstat (limited to '')
-rw-r--r-- | sound/soc/intel/boards/skl_hda_dsp_generic.c | 70 |
1 files changed, 60 insertions, 10 deletions
diff --git a/sound/soc/intel/boards/skl_hda_dsp_generic.c b/sound/soc/intel/boards/skl_hda_dsp_generic.c index 11eaee9ae41f..879ebba52832 100644 --- a/sound/soc/intel/boards/skl_hda_dsp_generic.c +++ b/sound/soc/intel/boards/skl_hda_dsp_generic.c @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: GPL-2.0 +// SPDX-License-Identifier: GPL-2.0-only // Copyright(c) 2015-18 Intel Corporation. /* @@ -61,6 +61,9 @@ static const struct snd_soc_dapm_route skl_hda_map[] = { { "Alt Analog CPU Capture", NULL, "Alt Analog Codec Capture" }, }; +SND_SOC_DAILINK_DEF(dummy_codec, + DAILINK_COMP_ARRAY(COMP_CODEC("snd-soc-dummy", "snd-soc-dummy-dai"))); + static int skl_hda_card_late_probe(struct snd_soc_card *card) { return skl_hda_hdmi_jack_init(card); @@ -72,10 +75,13 @@ skl_hda_add_dai_link(struct snd_soc_card *card, struct snd_soc_dai_link *link) struct skl_hda_private *ctx = snd_soc_card_get_drvdata(card); int ret = 0; - dev_dbg(card->dev, "%s: dai link name - %s\n", __func__, link->name); + dev_dbg(card->dev, "dai link name - %s\n", link->name); link->platforms->name = ctx->platform_name; link->nonatomic = 1; + if (!ctx->idisp_codec) + return 0; + if (strstr(link->name, "HDMI")) { ret = skl_hda_hdmi_add_pcm(card, ctx->pcm_count); @@ -110,17 +116,26 @@ static char hda_soc_components[30]; #define IDISP_ROUTE_COUNT (IDISP_DAI_COUNT * 2) #define IDISP_CODEC_MASK 0x4 +#define HDA_CODEC_AUTOSUSPEND_DELAY_MS 1000 + static int skl_hda_fill_card_info(struct snd_soc_acpi_mach_params *mach_params) { struct snd_soc_card *card = &hda_soc_card; + struct skl_hda_private *ctx = snd_soc_card_get_drvdata(card); struct snd_soc_dai_link *dai_link; u32 codec_count, codec_mask; int i, num_links, num_route; codec_mask = mach_params->codec_mask; codec_count = hweight_long(codec_mask); + ctx->idisp_codec = !!(codec_mask & IDISP_CODEC_MASK); + + if (!codec_count || codec_count > 2 || + (codec_count == 2 && !ctx->idisp_codec)) + return -EINVAL; - if (codec_count == 1 && codec_mask & IDISP_CODEC_MASK) { + if (codec_mask == IDISP_CODEC_MASK) { + /* topology with iDisp as the only HDA codec */ num_links = IDISP_DAI_COUNT + DMIC_DAI_COUNT; num_route = IDISP_ROUTE_COUNT; @@ -135,13 +150,19 @@ static int skl_hda_fill_card_info(struct snd_soc_acpi_mach_params *mach_params) skl_hda_be_dai_links[IDISP_DAI_COUNT + HDAC_DAI_COUNT + i]; } - } else if (codec_count == 2 && codec_mask & IDISP_CODEC_MASK) { + } else { + /* topology with external and iDisp HDA codecs */ num_links = ARRAY_SIZE(skl_hda_be_dai_links); num_route = ARRAY_SIZE(skl_hda_map); card->dapm_widgets = skl_hda_widgets; card->num_dapm_widgets = ARRAY_SIZE(skl_hda_widgets); - } else { - return -EINVAL; + if (!ctx->idisp_codec) { + for (i = 0; i < IDISP_DAI_COUNT; i++) { + skl_hda_be_dai_links[i].codecs = dummy_codec; + skl_hda_be_dai_links[i].num_codecs = + ARRAY_SIZE(dummy_codec); + } + } } card->num_links = num_links; @@ -153,13 +174,36 @@ static int skl_hda_fill_card_info(struct snd_soc_acpi_mach_params *mach_params) return 0; } +static void skl_set_hda_codec_autosuspend_delay(struct snd_soc_card *card) +{ + struct snd_soc_pcm_runtime *rtd; + struct hdac_hda_priv *hda_pvt; + struct snd_soc_dai *dai; + + for_each_card_rtds(card, rtd) { + if (!strstr(rtd->dai_link->codecs->name, "ehdaudio0D0")) + continue; + dai = asoc_rtd_to_codec(rtd, 0); + hda_pvt = snd_soc_component_get_drvdata(dai->component); + if (hda_pvt) { + /* + * all codecs are on the same bus, so it's sufficient + * to look up only the first one + */ + snd_hda_set_power_save(hda_pvt->codec->bus, + HDA_CODEC_AUTOSUSPEND_DELAY_MS); + break; + } + } +} + static int skl_hda_audio_probe(struct platform_device *pdev) { struct snd_soc_acpi_mach *mach; struct skl_hda_private *ctx; int ret; - dev_dbg(&pdev->dev, "%s: entry\n", __func__); + dev_dbg(&pdev->dev, "entry\n"); ctx = devm_kzalloc(&pdev->dev, sizeof(*ctx), GFP_KERNEL); if (!ctx) @@ -167,10 +211,12 @@ static int skl_hda_audio_probe(struct platform_device *pdev) INIT_LIST_HEAD(&ctx->hdmi_pcm_list); - mach = (&pdev->dev)->platform_data; + mach = pdev->dev.platform_data; if (!mach) return -EINVAL; + snd_soc_card_set_drvdata(&hda_soc_card, ctx); + ret = skl_hda_fill_card_info(&mach->mach_params); if (ret < 0) { dev_err(&pdev->dev, "Unsupported HDAudio/iDisp configuration found\n"); @@ -183,7 +229,6 @@ static int skl_hda_audio_probe(struct platform_device *pdev) ctx->common_hdmi_codec_drv = mach->mach_params.common_hdmi_codec_drv; hda_soc_card.dev = &pdev->dev; - snd_soc_card_set_drvdata(&hda_soc_card, ctx); if (mach->mach_params.dmic_num > 0) { snprintf(hda_soc_components, sizeof(hda_soc_components), @@ -191,7 +236,11 @@ static int skl_hda_audio_probe(struct platform_device *pdev) hda_soc_card.components = hda_soc_components; } - return devm_snd_soc_register_card(&pdev->dev, &hda_soc_card); + ret = devm_snd_soc_register_card(&pdev->dev, &hda_soc_card); + if (!ret) + skl_set_hda_codec_autosuspend_delay(&hda_soc_card); + + return ret; } static struct platform_driver skl_hda_audio = { @@ -209,3 +258,4 @@ MODULE_DESCRIPTION("SKL/KBL/BXT/APL HDA Generic Machine driver"); MODULE_AUTHOR("Rakesh Ughreja <rakesh.a.ughreja@intel.com>"); MODULE_LICENSE("GPL v2"); MODULE_ALIAS("platform:skl_hda_dsp_generic"); +MODULE_IMPORT_NS(SND_SOC_INTEL_HDA_DSP_COMMON); |