diff --git a/sound/soc/codecs/hdac_hda.c b/sound/soc/codecs/hdac_hda.c index be66853afbe2..8f5d97949d3d 100644 --- a/sound/soc/codecs/hdac_hda.c +++ b/sound/soc/codecs/hdac_hda.c @@ -7,6 +7,7 @@ * codec drivers using hdac_ext_bus_ops ops. */ +#include #include #include #include @@ -35,6 +36,13 @@ SNDRV_PCM_RATE_96000 | SNDRV_PCM_RATE_176400 |\ SNDRV_PCM_RATE_192000) +#ifdef CONFIG_SND_HDA_PATCH_LOADER +static char *loadable_patch[SNDRV_CARDS]; + +module_param_array_named(patch, loadable_patch, charp, NULL, 0444); +MODULE_PARM_DESC(patch, "Patch file for Intel HD audio interface."); +#endif + static int hdac_hda_dai_open(struct snd_pcm_substream *substream, struct snd_soc_dai *dai); static void hdac_hda_dai_close(struct snd_pcm_substream *substream, @@ -423,6 +431,26 @@ static int hdac_hda_codec_probe(struct snd_soc_component *component) dev_err(&hdev->dev, "failed to create hda codec %d\n", ret); goto error_no_pm; } + +#ifdef CONFIG_SND_HDA_PATCH_LOADER + if (loadable_patch[hda_pvt->dev_index] && *loadable_patch[hda_pvt->dev_index]) { + dev_info(&hdev->dev, "Applying patch firmware '%s'\n", + loadable_patch[hda_pvt->dev_index]); + ret = request_firmware(&hda_pvt->fw, loadable_patch[hda_pvt->dev_index], + &hdev->dev); + if (ret < 0) + goto error_no_pm; + if (hda_pvt->fw) { + ret = snd_hda_load_patch(hcodec->bus, hda_pvt->fw->size, hda_pvt->fw->data); + if (ret < 0) { + dev_err(&hdev->dev, "failed to load hda patch %d\n", ret); + goto error_no_pm; + } + release_firmware(hda_pvt->fw); + hda_pvt->fw = NULL; + } + } +#endif /* * Overwrite type to HDA_DEV_ASOC since it is a ASoC driver * hda_codec.c will check this flag to determine if unregister diff --git a/sound/soc/codecs/hdac_hda.h b/sound/soc/codecs/hdac_hda.h index b65560981abb..b7a12aea8d32 100644 --- a/sound/soc/codecs/hdac_hda.h +++ b/sound/soc/codecs/hdac_hda.h @@ -26,6 +26,10 @@ struct hdac_hda_priv { struct hda_codec *codec; struct hdac_hda_pcm pcm[HDAC_DAI_ID_NUM]; bool need_display_power; + int dev_index; +#ifdef CONFIG_SND_HDA_PATCH_LOADER + const struct firmware *fw; +#endif }; struct hdac_ext_bus_ops *snd_soc_hdac_hda_get_ops(void); diff --git a/sound/soc/intel/skylake/skl.c b/sound/soc/intel/skylake/skl.c index 77408a981b97..d753d393a428 100644 --- a/sound/soc/intel/skylake/skl.c +++ b/sound/soc/intel/skylake/skl.c @@ -736,6 +736,7 @@ static int probe_codec(struct hdac_bus *bus, int addr) return PTR_ERR(codec); hda_codec->codec = codec; + hda_codec->dev_index = addr; dev_set_drvdata(&codec->core.dev, hda_codec); /* use legacy bus only for HDA codecs, idisp uses ext bus */ diff --git a/sound/soc/sof/intel/hda-codec.c b/sound/soc/sof/intel/hda-codec.c index 8a5e99a898ec..28ecbebb4b84 100644 --- a/sound/soc/sof/intel/hda-codec.c +++ b/sound/soc/sof/intel/hda-codec.c @@ -169,6 +169,7 @@ static int hda_codec_probe(struct snd_sof_dev *sdev, int address) return ret; hda_priv->codec = codec; + hda_priv->dev_index = address; dev_set_drvdata(&codec->core.dev, hda_priv); if ((resp & 0xFFFF0000) == IDISP_VID_INTEL) {