1 // SPDX-License-Identifier: GPL-2.0-only 2 // Copyright(c) 2015-18 Intel Corporation. 3 4 /* 5 * Machine Driver for SKL+ platforms with DSP and iDisp, HDA Codecs 6 */ 7 8 #include <linux/module.h> 9 #include <linux/platform_device.h> 10 #include <sound/core.h> 11 #include <sound/hda_codec.h> 12 #include <sound/jack.h> 13 #include <sound/pcm.h> 14 #include <sound/pcm_params.h> 15 #include <sound/soc.h> 16 #include <sound/soc-acpi.h> 17 #include "../../codecs/hdac_hda.h" 18 #include "../../sof/intel/hda.h" 19 #include "sof_board_helpers.h" 20 21 static int skl_hda_card_late_probe(struct snd_soc_card *card) 22 { 23 return sof_intel_board_card_late_probe(card); 24 } 25 26 #define HDA_CODEC_AUTOSUSPEND_DELAY_MS 1000 27 28 static void skl_set_hda_codec_autosuspend_delay(struct snd_soc_card *card) 29 { 30 struct snd_soc_pcm_runtime *rtd; 31 struct hdac_hda_priv *hda_pvt; 32 struct snd_soc_dai *dai; 33 34 for_each_card_rtds(card, rtd) { 35 if (!strstr(rtd->dai_link->codecs->name, "ehdaudio0D0")) 36 continue; 37 dai = snd_soc_rtd_to_codec(rtd, 0); 38 hda_pvt = snd_soc_component_get_drvdata(dai->component); 39 if (hda_pvt) { 40 /* 41 * all codecs are on the same bus, so it's sufficient 42 * to look up only the first one 43 */ 44 snd_hda_set_power_save(hda_pvt->codec->bus, 45 HDA_CODEC_AUTOSUSPEND_DELAY_MS); 46 break; 47 } 48 } 49 } 50 51 #define IDISP_HDMI_BE_ID 1 52 #define HDA_BE_ID 4 53 #define DMIC01_BE_ID 6 54 #define DMIC16K_BE_ID 7 55 #define BT_OFFLOAD_BE_ID 8 56 57 #define HDA_LINK_ORDER SOF_LINK_ORDER(SOF_LINK_IDISP_HDMI, \ 58 SOF_LINK_HDA, \ 59 SOF_LINK_DMIC01, \ 60 SOF_LINK_DMIC16K, \ 61 SOF_LINK_BT_OFFLOAD, \ 62 SOF_LINK_NONE, \ 63 SOF_LINK_NONE) 64 65 #define HDA_LINK_IDS SOF_LINK_ORDER(IDISP_HDMI_BE_ID, \ 66 HDA_BE_ID, \ 67 DMIC01_BE_ID, \ 68 DMIC16K_BE_ID, \ 69 BT_OFFLOAD_BE_ID, \ 70 0, \ 71 0) 72 73 static unsigned long 74 skl_hda_get_board_quirk(struct snd_soc_acpi_mach_params *mach_params) 75 { 76 unsigned long board_quirk = 0; 77 int ssp_bt; 78 79 if (hweight_long(mach_params->bt_link_mask) == 1) { 80 ssp_bt = fls(mach_params->bt_link_mask) - 1; 81 board_quirk |= SOF_SSP_PORT_BT_OFFLOAD(ssp_bt) | 82 SOF_BT_OFFLOAD_PRESENT; 83 } 84 85 return board_quirk; 86 } 87 88 static int skl_hda_audio_probe(struct platform_device *pdev) 89 { 90 struct snd_soc_acpi_mach *mach = pdev->dev.platform_data; 91 struct sof_card_private *ctx; 92 struct snd_soc_card *card; 93 unsigned long board_quirk = skl_hda_get_board_quirk(&mach->mach_params); 94 int ret; 95 96 card = devm_kzalloc(&pdev->dev, sizeof(struct snd_soc_card), GFP_KERNEL); 97 if (!card) 98 return -ENOMEM; 99 100 card->name = "hda-dsp"; 101 card->owner = THIS_MODULE; 102 card->fully_routed = true; 103 card->late_probe = skl_hda_card_late_probe; 104 105 dev_dbg(&pdev->dev, "board_quirk = %lx\n", board_quirk); 106 107 /* initialize ctx with board quirk */ 108 ctx = sof_intel_board_get_ctx(&pdev->dev, board_quirk); 109 if (!ctx) 110 return -ENOMEM; 111 112 if (HDA_EXT_CODEC(mach->mach_params.codec_mask)) 113 ctx->hda_codec_present = true; 114 115 if (mach->mach_params.codec_mask & IDISP_CODEC_MASK) 116 ctx->hdmi.idisp_codec = true; 117 118 ctx->link_order_overwrite = HDA_LINK_ORDER; 119 ctx->link_id_overwrite = HDA_LINK_IDS; 120 121 /* update dai_link */ 122 ret = sof_intel_board_set_dai_link(&pdev->dev, card, ctx); 123 if (ret) 124 return ret; 125 126 card->dev = &pdev->dev; 127 if (!snd_soc_acpi_sof_parent(&pdev->dev)) 128 card->disable_route_checks = true; 129 130 if (mach->mach_params.dmic_num > 0) { 131 card->components = devm_kasprintf(card->dev, GFP_KERNEL, 132 "cfg-dmics:%d", 133 mach->mach_params.dmic_num); 134 if (!card->components) 135 return -ENOMEM; 136 } 137 138 ret = snd_soc_fixup_dai_links_platform_name(card, 139 mach->mach_params.platform); 140 if (ret) 141 return ret; 142 143 snd_soc_card_set_drvdata(card, ctx); 144 145 ret = devm_snd_soc_register_card(&pdev->dev, card); 146 if (!ret) 147 skl_set_hda_codec_autosuspend_delay(card); 148 149 return ret; 150 } 151 152 static struct platform_driver skl_hda_audio = { 153 .probe = skl_hda_audio_probe, 154 .driver = { 155 .name = "skl_hda_dsp_generic", 156 .pm = &snd_soc_pm_ops, 157 }, 158 }; 159 160 module_platform_driver(skl_hda_audio) 161 162 /* Module information */ 163 MODULE_DESCRIPTION("SKL/KBL/BXT/APL HDA Generic Machine driver"); 164 MODULE_AUTHOR("Rakesh Ughreja <rakesh.a.ughreja@intel.com>"); 165 MODULE_LICENSE("GPL v2"); 166 MODULE_ALIAS("platform:skl_hda_dsp_generic"); 167 MODULE_IMPORT_NS(SND_SOC_INTEL_SOF_BOARD_HELPERS); 168