ASoC: hdac_hda: add HDA patch loader support
authorBard Liao <yung-chuan.liao@linux.intel.com>
Tue, 19 Sep 2023 08:32:09 +0000 (16:32 +0800)
committerMark Brown <broonie@kernel.org>
Tue, 19 Sep 2023 12:49:16 +0000 (13:49 +0100)
HDA patch loader is supported by legacy HDA driver. Implement it on
ASoC HDA driver, too.

Signed-off-by: Bard Liao <yung-chuan.liao@linux.intel.com>
Reviewed-by: Kai Vehmanen <kai.vehmanen@linux.intel.com>
Reviewed-by: Pierre-Louis Bossart <pierre-louis.bossart@linux.intel.com>
Reviewed-by: Rander Wang <rander.wang@intel.com>
Link: https://lore.kernel.org/r/20230919083209.1919921-1-yung-chuan.liao@linux.intel.com
Signed-off-by: Mark Brown <broonie@kernel.org>
sound/soc/codecs/hdac_hda.c
sound/soc/codecs/hdac_hda.h
sound/soc/intel/skylake/skl.c
sound/soc/sof/intel/hda-codec.c

index be66853afbe2b6cec0defb3e914110594996a5b2..8f5d97949d3d030e10b4bd263c190c8a6dc71ff8 100644 (file)
@@ -7,6 +7,7 @@
  * codec drivers using hdac_ext_bus_ops ops.
  */
 
+#include <linux/firmware.h>
 #include <linux/init.h>
 #include <linux/delay.h>
 #include <linux/module.h>
                                 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
index b65560981abb2399f975424b592a2365d0167b5f..b7a12aea8d323c75d0919e07df8a1fc7c0635599 100644 (file)
@@ -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);
index 77408a981b9773874f4dd1610de772f971d6c6cf..d753d393a428e0684c1f20196392d9eab83486eb 100644 (file)
@@ -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 */
index 8a5e99a898ecb4b941faafc092aea8c0ac0ba691..28ecbebb4b848f0857b005158782b2531c76d539 100644 (file)
@@ -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) {