ALSA: hda/tas2781: Create an independent lib to save the shared parts for both SPI...
authorShenghao Ding <shenghao-ding@ti.com>
Wed, 7 May 2025 04:58:13 +0000 (12:58 +0800)
committerTakashi Iwai <tiwai@suse.de>
Thu, 8 May 2025 09:50:59 +0000 (11:50 +0200)
Some common parts, such as struct tas2781_hda{...} and some audio
kcontrols are moved into an independent lib for code cleanup.

Signed-off-by: Shenghao Ding <shenghao-ding@ti.com>
Link: https://patch.msgid.link/20250507045813.151-1-shenghao-ding@ti.com
Signed-off-by: Takashi Iwai <tiwai@suse.de>
sound/pci/hda/Kconfig
sound/pci/hda/Makefile
sound/pci/hda/tas2781_hda.c [new file with mode: 0644]
sound/pci/hda/tas2781_hda.h
sound/pci/hda/tas2781_hda_i2c.c
sound/pci/hda/tas2781_hda_spi.c

index d5b29b5eb1f6c943e896cfb15ef981e550b1b714..339c80d2cce54692ebe92d80e420fb00ba705ad2 100644 (file)
@@ -180,12 +180,17 @@ config SND_HDA_SCODEC_CS35L56_SPI
          Say Y or M here to include CS35L56 amplifier support with
          SPI control.
 
+config SND_HDA_SCODEC_TAS2781
+       tristate
+       select SND_HDA_GENERIC
+
 config SND_HDA_SCODEC_TAS2781_I2C
        tristate "Build TAS2781 HD-audio side codec support for I2C Bus"
        depends on I2C
        depends on ACPI
        depends on EFI
        depends on SND_SOC
+       select SND_HDA_SCODEC_TAS2781
        select SND_SOC_TAS2781_COMLIB_I2C
        select SND_SOC_TAS2781_FMWLIB
        select CRC32
@@ -202,6 +207,8 @@ config SND_HDA_SCODEC_TAS2781_SPI
        depends on ACPI
        depends on EFI
        depends on SND_SOC
+       select SND_HDA_SCODEC_TAS2781
+       select SND_SOC_TAS2781_COMLIB
        select SND_SOC_TAS2781_FMWLIB
        select CRC8
        select CRC32
index 13d6c7e6320354408726e379eff47b5ff7c6925e..5adff1cab101239961743fa10cf87348b3291e59 100644 (file)
@@ -38,6 +38,7 @@ snd-hda-scodec-cs35l56-y :=   cs35l56_hda.o
 snd-hda-scodec-cs35l56-i2c-y :=        cs35l56_hda_i2c.o
 snd-hda-scodec-cs35l56-spi-y :=        cs35l56_hda_spi.o
 snd-hda-scodec-component-y :=  hda_component.o
+snd-hda-scodec-tas2781-y :=    tas2781_hda.o
 snd-hda-scodec-tas2781-i2c-y :=        tas2781_hda_i2c.o
 snd-hda-scodec-tas2781-spi-y :=        tas2781_hda_spi.o
 
@@ -70,6 +71,7 @@ obj-$(CONFIG_SND_HDA_SCODEC_CS35L56) += snd-hda-scodec-cs35l56.o
 obj-$(CONFIG_SND_HDA_SCODEC_CS35L56_I2C) += snd-hda-scodec-cs35l56-i2c.o
 obj-$(CONFIG_SND_HDA_SCODEC_CS35L56_SPI) += snd-hda-scodec-cs35l56-spi.o
 obj-$(CONFIG_SND_HDA_SCODEC_COMPONENT) += snd-hda-scodec-component.o
+obj-$(CONFIG_SND_HDA_SCODEC_TAS2781) += snd-hda-scodec-tas2781.o
 obj-$(CONFIG_SND_HDA_SCODEC_TAS2781_I2C) += snd-hda-scodec-tas2781-i2c.o
 obj-$(CONFIG_SND_HDA_SCODEC_TAS2781_SPI) += snd-hda-scodec-tas2781-spi.o
 
diff --git a/sound/pci/hda/tas2781_hda.c b/sound/pci/hda/tas2781_hda.c
new file mode 100644 (file)
index 0000000..9d8e0d9
--- /dev/null
@@ -0,0 +1,198 @@
+// SPDX-License-Identifier: GPL-2.0
+//
+// TAS2781 HDA Shared Lib for I2C&SPI driver
+//
+// Copyright 2025 Texas Instruments, Inc.
+//
+// Author: Shenghao Ding <shenghao-ding@ti.com>
+
+#include <linux/component.h>
+#include <linux/crc8.h>
+#include <linux/crc32.h>
+#include <linux/efi.h>
+#include <linux/firmware.h>
+#include <linux/i2c.h>
+#include <linux/pm_runtime.h>
+#include <sound/soc.h>
+#include <sound/tas2781.h>
+
+#include "tas2781_hda.h"
+
+void tas2781_hda_remove(struct device *dev,
+       const struct component_ops *ops)
+{
+       struct tas2781_hda *tas_hda = dev_get_drvdata(dev);
+
+       component_del(tas_hda->dev, ops);
+
+       pm_runtime_get_sync(tas_hda->dev);
+       pm_runtime_disable(tas_hda->dev);
+
+       pm_runtime_put_noidle(tas_hda->dev);
+
+       tasdevice_remove(tas_hda->priv);
+}
+EXPORT_SYMBOL_NS_GPL(tas2781_hda_remove, "SND_HDA_SCODEC_TAS2781");
+
+int tasdevice_info_profile(struct snd_kcontrol *kcontrol,
+                       struct snd_ctl_elem_info *uinfo)
+{
+       struct tasdevice_priv *tas_priv = snd_kcontrol_chip(kcontrol);
+
+       uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
+       uinfo->count = 1;
+       uinfo->value.integer.min = 0;
+       uinfo->value.integer.max = tas_priv->rcabin.ncfgs - 1;
+
+       return 0;
+}
+EXPORT_SYMBOL_NS_GPL(tasdevice_info_profile, "SND_HDA_SCODEC_TAS2781");
+
+int tasdevice_info_programs(struct snd_kcontrol *kcontrol,
+                                  struct snd_ctl_elem_info *uinfo)
+{
+       struct tasdevice_priv *tas_priv = snd_kcontrol_chip(kcontrol);
+
+       uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
+       uinfo->count = 1;
+       uinfo->value.integer.min = 0;
+       uinfo->value.integer.max = tas_priv->fmw->nr_programs - 1;
+
+       return 0;
+}
+EXPORT_SYMBOL_NS_GPL(tasdevice_info_programs, "SND_HDA_SCODEC_TAS2781");
+
+int tasdevice_info_config(struct snd_kcontrol *kcontrol,
+       struct snd_ctl_elem_info *uinfo)
+{
+       struct tasdevice_priv *tas_priv = snd_kcontrol_chip(kcontrol);
+       struct tasdevice_fw *tas_fw = tas_priv->fmw;
+
+       uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
+       uinfo->count = 1;
+       uinfo->value.integer.min = 0;
+       uinfo->value.integer.max = tas_fw->nr_configurations - 1;
+
+       return 0;
+}
+EXPORT_SYMBOL_NS_GPL(tasdevice_info_config, "SND_HDA_SCODEC_TAS2781");
+
+int tasdevice_get_profile_id(struct snd_kcontrol *kcontrol,
+                       struct snd_ctl_elem_value *ucontrol)
+{
+       struct tasdevice_priv *tas_priv = snd_kcontrol_chip(kcontrol);
+
+       ucontrol->value.integer.value[0] = tas_priv->rcabin.profile_cfg_id;
+
+       dev_dbg(tas_priv->dev, "%s: kcontrol %s: %d\n", __func__,
+               kcontrol->id.name, tas_priv->rcabin.profile_cfg_id);
+
+       return 0;
+}
+EXPORT_SYMBOL_NS_GPL(tasdevice_get_profile_id, "SND_HDA_SCODEC_TAS2781");
+
+int tasdevice_set_profile_id(struct snd_kcontrol *kcontrol,
+               struct snd_ctl_elem_value *ucontrol)
+{
+       struct tasdevice_priv *tas_priv = snd_kcontrol_chip(kcontrol);
+       int profile_id = ucontrol->value.integer.value[0];
+       int max = tas_priv->rcabin.ncfgs - 1;
+       int val, ret = 0;
+
+       val = clamp(profile_id, 0, max);
+
+       guard(mutex)(&tas_priv->codec_lock);
+
+       dev_dbg(tas_priv->dev, "%s: kcontrol %s: %d -> %d\n", __func__,
+               kcontrol->id.name, tas_priv->rcabin.profile_cfg_id, val);
+
+       if (tas_priv->rcabin.profile_cfg_id != val) {
+               tas_priv->rcabin.profile_cfg_id = val;
+               ret = 1;
+       }
+
+       return ret;
+}
+EXPORT_SYMBOL_NS_GPL(tasdevice_set_profile_id, "SND_HDA_SCODEC_TAS2781");
+
+int tasdevice_program_get(struct snd_kcontrol *kcontrol,
+       struct snd_ctl_elem_value *ucontrol)
+{
+       struct tasdevice_priv *tas_priv = snd_kcontrol_chip(kcontrol);
+
+       ucontrol->value.integer.value[0] = tas_priv->cur_prog;
+
+       dev_dbg(tas_priv->dev, "%s: kcontrol %s: %d\n", __func__,
+               kcontrol->id.name, tas_priv->cur_prog);
+
+       return 0;
+}
+EXPORT_SYMBOL_NS_GPL(tasdevice_program_get, "SND_HDA_SCODEC_TAS2781");
+
+int tasdevice_program_put(struct snd_kcontrol *kcontrol,
+       struct snd_ctl_elem_value *ucontrol)
+{
+       struct tasdevice_priv *tas_priv = snd_kcontrol_chip(kcontrol);
+       struct tasdevice_fw *tas_fw = tas_priv->fmw;
+       int nr_program = ucontrol->value.integer.value[0];
+       int max = tas_fw->nr_programs - 1;
+       int val, ret = 0;
+
+       val = clamp(nr_program, 0, max);
+
+       guard(mutex)(&tas_priv->codec_lock);
+
+       dev_dbg(tas_priv->dev, "%s: kcontrol %s: %d -> %d\n", __func__,
+               kcontrol->id.name, tas_priv->cur_prog, val);
+
+       if (tas_priv->cur_prog != val) {
+               tas_priv->cur_prog = val;
+               ret = 1;
+       }
+
+       return ret;
+}
+EXPORT_SYMBOL_NS_GPL(tasdevice_program_put, "SND_HDA_SCODEC_TAS2781");
+
+int tasdevice_config_get(struct snd_kcontrol *kcontrol,
+       struct snd_ctl_elem_value *ucontrol)
+{
+       struct tasdevice_priv *tas_priv = snd_kcontrol_chip(kcontrol);
+
+       ucontrol->value.integer.value[0] = tas_priv->cur_conf;
+
+       dev_dbg(tas_priv->dev, "%s: kcontrol %s: %d\n", __func__,
+               kcontrol->id.name, tas_priv->cur_conf);
+
+       return 0;
+}
+EXPORT_SYMBOL_NS_GPL(tasdevice_config_get, "SND_HDA_SCODEC_TAS2781");
+
+int tasdevice_config_put(struct snd_kcontrol *kcontrol,
+       struct snd_ctl_elem_value *ucontrol)
+{
+       struct tasdevice_priv *tas_priv = snd_kcontrol_chip(kcontrol);
+       struct tasdevice_fw *tas_fw = tas_priv->fmw;
+       int nr_config = ucontrol->value.integer.value[0];
+       int max = tas_fw->nr_configurations - 1;
+       int val, ret = 0;
+
+       val = clamp(nr_config, 0, max);
+
+       guard(mutex)(&tas_priv->codec_lock);
+
+       dev_dbg(tas_priv->dev, "%s: kcontrol %s: %d -> %d\n", __func__,
+               kcontrol->id.name, tas_priv->cur_conf, val);
+
+       if (tas_priv->cur_conf != val) {
+               tas_priv->cur_conf = val;
+               ret = 1;
+       }
+
+       return ret;
+}
+EXPORT_SYMBOL_NS_GPL(tasdevice_config_put, "SND_HDA_SCODEC_TAS2781");
+
+MODULE_DESCRIPTION("TAS2781 HDA Driver");
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Shenghao Ding, TI, <shenghao-ding@ti.com>");
index 444231f87e53e8ebf6f033977ce63f5810f4f4d1..95229083ce6a145e2573364fa0d8e72abffc47a8 100644 (file)
        .private_value = xdata, \
 }
 
+struct tas2781_hda {
+       struct device *dev;
+       struct tasdevice_priv *priv;
+       struct snd_kcontrol *dsp_prog_ctl;
+       struct snd_kcontrol *dsp_conf_ctl;
+       struct snd_kcontrol *prof_ctl;
+       enum device_catlog_id catlog_id;
+       void *hda_priv;
+};
+
+void tas2781_hda_remove(struct device *dev,
+       const struct component_ops *ops);
+int tasdevice_info_profile(struct snd_kcontrol *kctl,
+       struct snd_ctl_elem_info *uctl);
+int tasdevice_info_programs(struct snd_kcontrol *kctl,
+       struct snd_ctl_elem_info *uctl);
+int tasdevice_info_config(struct snd_kcontrol *kctl,
+       struct snd_ctl_elem_info *uctl);
+int tasdevice_set_profile_id(struct snd_kcontrol *kctl,
+       struct snd_ctl_elem_value *uctl);
+int tasdevice_get_profile_id(struct snd_kcontrol *kctl,
+       struct snd_ctl_elem_value *uctl);
+int tasdevice_program_get(struct snd_kcontrol *kctl,
+       struct snd_ctl_elem_value *uctl);
+int tasdevice_program_put(struct snd_kcontrol *kctl,
+       struct snd_ctl_elem_value *uctl);
+int tasdevice_config_put(struct snd_kcontrol *kctl,
+       struct snd_ctl_elem_value *uctl);
+int tasdevice_config_get(struct snd_kcontrol *kctl,
+       struct snd_ctl_elem_value *uctl);
+
 #endif
index 0a686e850540c88d5b9561841630a36361d4a335..0e51b07dbd0581ba4ff98ca5ebd973fee8e0eb37 100644 (file)
@@ -51,12 +51,7 @@ static unsigned int cal_regs[TASDEV_CALIB_N] = {
        TAS2563_CAL_R0_LOW, TAS2563_CAL_TLIM,
 };
 
-struct tas2781_hda {
-       struct device *dev;
-       struct tasdevice_priv *priv;
-       struct snd_kcontrol *dsp_prog_ctl;
-       struct snd_kcontrol *dsp_conf_ctl;
-       struct snd_kcontrol *prof_ctl;
+struct tas2781_hda_i2c_priv {
        struct snd_kcontrol *snd_ctls[2];
 };
 
@@ -175,176 +170,6 @@ static void tas2781_hda_playback_hook(struct device *dev, int action)
        }
 }
 
-static int tasdevice_info_profile(struct snd_kcontrol *kcontrol,
-                       struct snd_ctl_elem_info *uinfo)
-{
-       struct tasdevice_priv *tas_priv = snd_kcontrol_chip(kcontrol);
-
-       uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
-       uinfo->count = 1;
-       uinfo->value.integer.min = 0;
-       uinfo->value.integer.max = tas_priv->rcabin.ncfgs - 1;
-
-       return 0;
-}
-
-static int tasdevice_get_profile_id(struct snd_kcontrol *kcontrol,
-                       struct snd_ctl_elem_value *ucontrol)
-{
-       struct tasdevice_priv *tas_priv = snd_kcontrol_chip(kcontrol);
-
-       mutex_lock(&tas_priv->codec_lock);
-
-       ucontrol->value.integer.value[0] = tas_priv->rcabin.profile_cfg_id;
-
-       dev_dbg(tas_priv->dev, "%s: kcontrol %s: %d\n",
-               __func__, kcontrol->id.name, tas_priv->rcabin.profile_cfg_id);
-
-       mutex_unlock(&tas_priv->codec_lock);
-
-       return 0;
-}
-
-static int tasdevice_set_profile_id(struct snd_kcontrol *kcontrol,
-               struct snd_ctl_elem_value *ucontrol)
-{
-       struct tasdevice_priv *tas_priv = snd_kcontrol_chip(kcontrol);
-       int nr_profile = ucontrol->value.integer.value[0];
-       int max = tas_priv->rcabin.ncfgs - 1;
-       int val, ret = 0;
-
-       val = clamp(nr_profile, 0, max);
-
-       mutex_lock(&tas_priv->codec_lock);
-
-       dev_dbg(tas_priv->dev, "%s: kcontrol %s: %d -> %d\n",
-               __func__, kcontrol->id.name,
-               tas_priv->rcabin.profile_cfg_id, val);
-
-       if (tas_priv->rcabin.profile_cfg_id != val) {
-               tas_priv->rcabin.profile_cfg_id = val;
-               ret = 1;
-       }
-
-       mutex_unlock(&tas_priv->codec_lock);
-
-       return ret;
-}
-
-static int tasdevice_info_programs(struct snd_kcontrol *kcontrol,
-                       struct snd_ctl_elem_info *uinfo)
-{
-       struct tasdevice_priv *tas_priv = snd_kcontrol_chip(kcontrol);
-       struct tasdevice_fw *tas_fw = tas_priv->fmw;
-
-       uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
-       uinfo->count = 1;
-       uinfo->value.integer.min = 0;
-       uinfo->value.integer.max = tas_fw->nr_programs - 1;
-
-       return 0;
-}
-
-static int tasdevice_info_config(struct snd_kcontrol *kcontrol,
-       struct snd_ctl_elem_info *uinfo)
-{
-       struct tasdevice_priv *tas_priv = snd_kcontrol_chip(kcontrol);
-       struct tasdevice_fw *tas_fw = tas_priv->fmw;
-
-       uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
-       uinfo->count = 1;
-       uinfo->value.integer.min = 0;
-       uinfo->value.integer.max = tas_fw->nr_configurations - 1;
-
-       return 0;
-}
-
-static int tasdevice_program_get(struct snd_kcontrol *kcontrol,
-       struct snd_ctl_elem_value *ucontrol)
-{
-       struct tasdevice_priv *tas_priv = snd_kcontrol_chip(kcontrol);
-
-       mutex_lock(&tas_priv->codec_lock);
-
-       ucontrol->value.integer.value[0] = tas_priv->cur_prog;
-
-       dev_dbg(tas_priv->dev, "%s: kcontrol %s: %d\n",
-               __func__, kcontrol->id.name, tas_priv->cur_prog);
-
-       mutex_unlock(&tas_priv->codec_lock);
-
-       return 0;
-}
-
-static int tasdevice_program_put(struct snd_kcontrol *kcontrol,
-       struct snd_ctl_elem_value *ucontrol)
-{
-       struct tasdevice_priv *tas_priv = snd_kcontrol_chip(kcontrol);
-       struct tasdevice_fw *tas_fw = tas_priv->fmw;
-       int nr_program = ucontrol->value.integer.value[0];
-       int max = tas_fw->nr_programs - 1;
-       int val, ret = 0;
-
-       val = clamp(nr_program, 0, max);
-
-       mutex_lock(&tas_priv->codec_lock);
-
-       dev_dbg(tas_priv->dev, "%s: kcontrol %s: %d -> %d\n",
-               __func__, kcontrol->id.name, tas_priv->cur_prog, val);
-
-       if (tas_priv->cur_prog != val) {
-               tas_priv->cur_prog = val;
-               ret = 1;
-       }
-
-       mutex_unlock(&tas_priv->codec_lock);
-
-       return ret;
-}
-
-static int tasdevice_config_get(struct snd_kcontrol *kcontrol,
-       struct snd_ctl_elem_value *ucontrol)
-{
-       struct tasdevice_priv *tas_priv = snd_kcontrol_chip(kcontrol);
-
-       mutex_lock(&tas_priv->codec_lock);
-
-       ucontrol->value.integer.value[0] = tas_priv->cur_conf;
-
-       dev_dbg(tas_priv->dev, "%s: kcontrol %s: %d\n",
-               __func__, kcontrol->id.name, tas_priv->cur_conf);
-
-       mutex_unlock(&tas_priv->codec_lock);
-
-       return 0;
-}
-
-static int tasdevice_config_put(struct snd_kcontrol *kcontrol,
-       struct snd_ctl_elem_value *ucontrol)
-{
-       struct tasdevice_priv *tas_priv = snd_kcontrol_chip(kcontrol);
-       struct tasdevice_fw *tas_fw = tas_priv->fmw;
-       int nr_config = ucontrol->value.integer.value[0];
-       int max = tas_fw->nr_configurations - 1;
-       int val, ret = 0;
-
-       val = clamp(nr_config, 0, max);
-
-       mutex_lock(&tas_priv->codec_lock);
-
-       dev_dbg(tas_priv->dev, "%s: kcontrol %s: %d -> %d\n",
-               __func__, kcontrol->id.name, tas_priv->cur_conf, val);
-
-       if (tas_priv->cur_conf != val) {
-               tas_priv->cur_conf = val;
-               ret = 1;
-       }
-
-       mutex_unlock(&tas_priv->codec_lock);
-
-       return ret;
-}
-
 static int tas2781_amp_getvol(struct snd_kcontrol *kcontrol,
        struct snd_ctl_elem_value *ucontrol)
 {
@@ -615,13 +440,14 @@ static int tas2781_save_calibration(struct tasdevice_priv *tas_priv)
 
 static void tas2781_hda_remove_controls(struct tas2781_hda *tas_hda)
 {
+       struct tas2781_hda_i2c_priv *hda_priv = tas_hda->hda_priv;
        struct hda_codec *codec = tas_hda->priv->codec;
 
        snd_ctl_remove(codec->card, tas_hda->dsp_prog_ctl);
        snd_ctl_remove(codec->card, tas_hda->dsp_conf_ctl);
 
-       for (int i = ARRAY_SIZE(tas_hda->snd_ctls) - 1; i >= 0; i--)
-               snd_ctl_remove(codec->card, tas_hda->snd_ctls[i]);
+       for (int i = ARRAY_SIZE(hda_priv->snd_ctls) - 1; i >= 0; i--)
+               snd_ctl_remove(codec->card, hda_priv->snd_ctls[i]);
 
        snd_ctl_remove(codec->card, tas_hda->prof_ctl);
 }
@@ -630,6 +456,7 @@ static void tasdev_fw_ready(const struct firmware *fmw, void *context)
 {
        struct tasdevice_priv *tas_priv = context;
        struct tas2781_hda *tas_hda = dev_get_drvdata(tas_priv->dev);
+       struct tas2781_hda_i2c_priv *hda_priv = tas_hda->hda_priv;
        struct hda_codec *codec = tas_priv->codec;
        int i, ret, spk_id;
 
@@ -650,9 +477,9 @@ static void tasdev_fw_ready(const struct firmware *fmw, void *context)
        }
 
        for (i = 0; i < ARRAY_SIZE(tas2781_snd_controls); i++) {
-               tas_hda->snd_ctls[i] = snd_ctl_new1(&tas2781_snd_controls[i],
+               hda_priv->snd_ctls[i] = snd_ctl_new1(&tas2781_snd_controls[i],
                        tas_priv);
-               ret = snd_ctl_add(codec->card, tas_hda->snd_ctls[i]);
+               ret = snd_ctl_add(codec->card, hda_priv->snd_ctls[i]);
                if (ret) {
                        dev_err(tas_priv->dev,
                                "Failed to add KControl %s = %d\n",
@@ -805,31 +632,23 @@ static const struct component_ops tas2781_hda_comp_ops = {
        .unbind = tas2781_hda_unbind,
 };
 
-static void tas2781_hda_remove(struct device *dev)
-{
-       struct tas2781_hda *tas_hda = dev_get_drvdata(dev);
-
-       component_del(tas_hda->dev, &tas2781_hda_comp_ops);
-
-       pm_runtime_get_sync(tas_hda->dev);
-       pm_runtime_disable(tas_hda->dev);
-
-       pm_runtime_put_noidle(tas_hda->dev);
-
-       tasdevice_remove(tas_hda->priv);
-}
-
 static int tas2781_hda_i2c_probe(struct i2c_client *clt)
 {
+       struct tas2781_hda_i2c_priv *hda_priv;
        struct tas2781_hda *tas_hda;
        const char *device_name;
        int ret;
 
-
        tas_hda = devm_kzalloc(&clt->dev, sizeof(*tas_hda), GFP_KERNEL);
        if (!tas_hda)
                return -ENOMEM;
 
+       hda_priv = devm_kzalloc(&clt->dev, sizeof(*hda_priv), GFP_KERNEL);
+       if (!hda_priv)
+               return -ENOMEM;
+
+       tas_hda->hda_priv = hda_priv;
+
        dev_set_drvdata(&clt->dev, tas_hda);
        tas_hda->dev = &clt->dev;
 
@@ -876,13 +695,13 @@ static int tas2781_hda_i2c_probe(struct i2c_client *clt)
 
 err:
        if (ret)
-               tas2781_hda_remove(&clt->dev);
+               tas2781_hda_remove(&clt->dev, &tas2781_hda_comp_ops);
        return ret;
 }
 
 static void tas2781_hda_i2c_remove(struct i2c_client *clt)
 {
-       tas2781_hda_remove(&clt->dev);
+       tas2781_hda_remove(&clt->dev, &tas2781_hda_comp_ops);
 }
 
 static int tas2781_runtime_suspend(struct device *dev)
@@ -1010,3 +829,4 @@ MODULE_DESCRIPTION("TAS2781 HDA Driver");
 MODULE_AUTHOR("Shenghao Ding, TI, <shenghao-ding@ti.com>");
 MODULE_LICENSE("GPL");
 MODULE_IMPORT_NS("SND_SOC_TAS2781_FMWLIB");
+MODULE_IMPORT_NS("SND_HDA_SCODEC_TAS2781");
index 426fc6044c6583283f08507aa1d0d7c4fa2834fe..50b82ecabb901866997cba8bc0cb1e6896098f3f 100644 (file)
 #define TAS2781_REG_CLK_CONFIG         TASDEVICE_REG(0x0, 0x0, 0x5c)
 #define TAS2781_REG_CLK_CONFIG_RESET   0x19
 
-struct tas2781_hda {
-       struct tasdevice_priv *priv;
-       struct acpi_device *dacpi;
-       struct snd_kcontrol *dsp_prog_ctl;
-       struct snd_kcontrol *dsp_conf_ctl;
+struct tas2781_hda_spi_priv {
        struct snd_kcontrol *snd_ctls[3];
-       struct snd_kcontrol *prof_ctl;
 };
 
 static const struct regmap_range_cfg tasdevice_ranges[] = {
@@ -193,8 +188,10 @@ static void tas2781_spi_reset(struct tasdevice_priv *tas_dev)
        } else {
                ret = tasdevice_dev_write(tas_dev, tas_dev->index,
                        TASDEVICE_REG_SWRESET, TASDEVICE_REG_SWRESET_RESET);
-               if (ret < 0)
+               if (ret < 0) {
                        dev_err(tas_dev->dev, "dev sw-reset fail, %d\n", ret);
+                       return;
+               }
                fsleep(1000);
        }
 }
@@ -323,8 +320,7 @@ static int tasdevice_spi_digital_getvol(struct tasdevice_priv *p,
 }
 
 static int tas2781_read_acpi(struct tas2781_hda *tas_hda,
-                            const char *hid,
-                            int id)
+       const char *hid, int id)
 {
        struct tasdevice_priv *p = tas_hda->priv;
        struct acpi_device *adev;
@@ -341,7 +337,6 @@ static int tas2781_read_acpi(struct tas2781_hda *tas_hda,
        }
 
        strscpy(p->dev_name, hid, sizeof(p->dev_name));
-       tas_hda->dacpi = adev;
        physdev = get_device(acpi_get_first_physical_node(adev));
        acpi_dev_put(adev);
 
@@ -410,126 +405,6 @@ static void tas2781_hda_playback_hook(struct device *dev, int action)
        }
 }
 
-static int tasdevice_info_profile(struct snd_kcontrol *kcontrol,
-                                 struct snd_ctl_elem_info *uinfo)
-{
-       struct tasdevice_priv *tas_priv = snd_kcontrol_chip(kcontrol);
-
-       uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
-       uinfo->count = 1;
-       uinfo->value.integer.min = 0;
-       uinfo->value.integer.max = tas_priv->rcabin.ncfgs - 1;
-
-       return 0;
-}
-
-static int tasdevice_get_profile_id(struct snd_kcontrol *kcontrol,
-       struct snd_ctl_elem_value *ucontrol)
-{
-       struct tasdevice_priv *tas_priv = snd_kcontrol_chip(kcontrol);
-
-       ucontrol->value.integer.value[0] = tas_priv->rcabin.profile_cfg_id;
-
-       return 0;
-}
-
-static int tasdevice_set_profile_id(struct snd_kcontrol *kcontrol,
-                                   struct snd_ctl_elem_value *ucontrol)
-{
-       struct tasdevice_priv *tas_priv = snd_kcontrol_chip(kcontrol);
-       int max = tas_priv->rcabin.ncfgs - 1;
-       int val;
-
-       val = clamp(ucontrol->value.integer.value[0], 0, max);
-       if (tas_priv->rcabin.profile_cfg_id != val) {
-               tas_priv->rcabin.profile_cfg_id = val;
-               return 1;
-       }
-
-       return 0;
-}
-
-static int tasdevice_info_programs(struct snd_kcontrol *kcontrol,
-                                  struct snd_ctl_elem_info *uinfo)
-{
-       struct tasdevice_priv *tas_priv = snd_kcontrol_chip(kcontrol);
-
-       uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
-       uinfo->count = 1;
-       uinfo->value.integer.min = 0;
-       uinfo->value.integer.max = tas_priv->fmw->nr_programs - 1;
-
-       return 0;
-}
-
-static int tasdevice_info_config(struct snd_kcontrol *kcontrol,
-                                struct snd_ctl_elem_info *uinfo)
-{
-       struct tasdevice_priv *tas_priv = snd_kcontrol_chip(kcontrol);
-
-       uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
-       uinfo->count = 1;
-       uinfo->value.integer.min = 0;
-       uinfo->value.integer.max = tas_priv->fmw->nr_configurations - 1;
-
-       return 0;
-}
-
-static int tasdevice_program_get(struct snd_kcontrol *kcontrol,
-                                struct snd_ctl_elem_value *ucontrol)
-{
-       struct tasdevice_priv *tas_priv = snd_kcontrol_chip(kcontrol);
-
-       ucontrol->value.integer.value[0] = tas_priv->cur_prog;
-
-       return 0;
-}
-
-static int tasdevice_program_put(struct snd_kcontrol *kcontrol,
-                                struct snd_ctl_elem_value *ucontrol)
-{
-       struct tasdevice_priv *tas_priv = snd_kcontrol_chip(kcontrol);
-       int nr_program = ucontrol->value.integer.value[0];
-       int max = tas_priv->fmw->nr_programs - 1;
-       int val;
-
-       val = clamp(nr_program, 0, max);
-
-       if (tas_priv->cur_prog != val) {
-               tas_priv->cur_prog = val;
-               return 1;
-       }
-
-       return 0;
-}
-
-static int tasdevice_config_get(struct snd_kcontrol *kcontrol,
-                               struct snd_ctl_elem_value *ucontrol)
-{
-       struct tasdevice_priv *tas_priv = snd_kcontrol_chip(kcontrol);
-
-       ucontrol->value.integer.value[0] = tas_priv->cur_conf;
-
-       return 0;
-}
-
-static int tasdevice_config_put(struct snd_kcontrol *kcontrol,
-                               struct snd_ctl_elem_value *ucontrol)
-{
-       struct tasdevice_priv *tas_priv = snd_kcontrol_chip(kcontrol);
-       int max = tas_priv->fmw->nr_configurations - 1;
-       int val;
-
-       val = clamp(ucontrol->value.integer.value[0], 0, max);
-
-       if (tas_priv->cur_conf != val) {
-               tas_priv->cur_conf = val;
-               return 1;
-       }
-
-       return 0;
-}
-
 /*
  * tas2781_digital_getvol - get the volum control
  * @kcontrol: control pointer
@@ -618,73 +493,37 @@ static int tas2781_force_fwload_put(struct snd_kcontrol *kcontrol,
        return change;
 }
 
-static const struct snd_kcontrol_new tas2781_snd_controls[] = {
-       ACARD_SINGLE_RANGE_EXT_TLV("Speaker Analog Gain 0", TAS2781_AMP_LEVEL,
-               1, 0, 20, 0, tas2781_amp_getvol,
-               tas2781_amp_putvol, amp_vol_tlv),
-       ACARD_SINGLE_RANGE_EXT_TLV("Speaker Digital Gain 0", TAS2781_DVC_LVL,
-               0, 0, 200, 1, tas2781_digital_getvol,
-               tas2781_digital_putvol, dvc_tlv),
-       ACARD_SINGLE_BOOL_EXT("Speaker Force Firmware Load 0", 0,
-               tas2781_force_fwload_get, tas2781_force_fwload_put),
-       ACARD_SINGLE_RANGE_EXT_TLV("Speaker Analog Gain 1", TAS2781_AMP_LEVEL,
-               1, 0, 20, 0, tas2781_amp_getvol,
-               tas2781_amp_putvol, amp_vol_tlv),
-       ACARD_SINGLE_RANGE_EXT_TLV("Speaker Digital Gain 1", TAS2781_DVC_LVL,
-               0, 0, 200, 1, tas2781_digital_getvol,
-               tas2781_digital_putvol, dvc_tlv),
-       ACARD_SINGLE_BOOL_EXT("Speaker Force Firmware Load 1", 0,
-               tas2781_force_fwload_get, tas2781_force_fwload_put),
+struct snd_kcontrol_new tas2781_snd_ctls[] = {
+       ACARD_SINGLE_RANGE_EXT_TLV(NULL, TAS2781_AMP_LEVEL, 1, 0, 20, 0,
+               tas2781_amp_getvol, tas2781_amp_putvol, amp_vol_tlv),
+       ACARD_SINGLE_RANGE_EXT_TLV(NULL, TAS2781_DVC_LVL, 0, 0, 200, 1,
+               tas2781_digital_getvol, tas2781_digital_putvol, dvc_tlv),
+       ACARD_SINGLE_BOOL_EXT(NULL, 0, tas2781_force_fwload_get,
+               tas2781_force_fwload_put),
 };
 
-static const struct snd_kcontrol_new tas2781_prof_ctrl[] = {
-{
-       .name = "Speaker Profile Id - 0",
+struct snd_kcontrol_new tas2781_prof_ctl = {
        .iface = SNDRV_CTL_ELEM_IFACE_CARD,
        .info = tasdevice_info_profile,
        .get = tasdevice_get_profile_id,
        .put = tasdevice_set_profile_id,
-},
-{
-       .name = "Speaker Profile Id - 1",
-       .iface = SNDRV_CTL_ELEM_IFACE_CARD,
-       .info = tasdevice_info_profile,
-       .get = tasdevice_get_profile_id,
-       .put = tasdevice_set_profile_id,
-},
-};
-static const struct snd_kcontrol_new tas2781_dsp_prog_ctrl[] = {
-{
-       .name = "Speaker Program Id 0",
-       .iface = SNDRV_CTL_ELEM_IFACE_CARD,
-       .info = tasdevice_info_programs,
-       .get = tasdevice_program_get,
-       .put = tasdevice_program_put,
-},
-{
-       .name = "Speaker Program Id 1",
-       .iface = SNDRV_CTL_ELEM_IFACE_CARD,
-       .info = tasdevice_info_programs,
-       .get = tasdevice_program_get,
-       .put = tasdevice_program_put,
-},
 };
 
-static const struct snd_kcontrol_new tas2781_dsp_conf_ctrl[] = {
-{
-       .name = "Speaker Config Id 0",
-       .iface = SNDRV_CTL_ELEM_IFACE_CARD,
-       .info = tasdevice_info_config,
-       .get = tasdevice_config_get,
-       .put = tasdevice_config_put,
-},
-{
-       .name = "Speaker Config Id 1",
-       .iface = SNDRV_CTL_ELEM_IFACE_CARD,
-       .info = tasdevice_info_config,
-       .get = tasdevice_config_get,
-       .put = tasdevice_config_put,
-},
+struct snd_kcontrol_new tas2781_dsp_ctls[] = {
+       /* Speaker Program */
+       {
+               .iface = SNDRV_CTL_ELEM_IFACE_CARD,
+               .info = tasdevice_info_programs,
+               .get = tasdevice_program_get,
+               .put = tasdevice_program_put,
+       },
+       /* Speaker Config */
+       {
+               .iface = SNDRV_CTL_ELEM_IFACE_CARD,
+               .info = tasdevice_info_config,
+               .get = tasdevice_config_get,
+               .put = tasdevice_config_put,
+       },
 };
 
 static void tas2781_apply_calib(struct tasdevice_priv *tas_priv)
@@ -853,23 +692,111 @@ static int tas2781_save_calibration(struct tasdevice_priv *tas_priv)
 static void tas2781_hda_remove_controls(struct tas2781_hda *tas_hda)
 {
        struct hda_codec *codec = tas_hda->priv->codec;
+       struct tas2781_hda_spi_priv *h_priv = tas_hda->hda_priv;
 
        snd_ctl_remove(codec->card, tas_hda->dsp_prog_ctl);
 
        snd_ctl_remove(codec->card, tas_hda->dsp_conf_ctl);
 
-       for (int i = ARRAY_SIZE(tas_hda->snd_ctls) - 1; i >= 0; i--)
-               snd_ctl_remove(codec->card, tas_hda->snd_ctls[i]);
+       for (int i = ARRAY_SIZE(h_priv->snd_ctls) - 1; i >= 0; i--)
+               snd_ctl_remove(codec->card, h_priv->snd_ctls[i]);
 
        snd_ctl_remove(codec->card, tas_hda->prof_ctl);
 }
 
+static int tas2781_hda_spi_prf_ctl(struct tas2781_hda *h)
+{
+       struct tasdevice_priv *p = h->priv;
+       struct hda_codec *c = p->codec;
+       char name[64];
+       int rc;
+
+       snprintf(name, sizeof(name), "Speaker-%d Profile Id", p->index);
+       tas2781_prof_ctl.name = name;
+       h->prof_ctl = snd_ctl_new1(&tas2781_prof_ctl, p);
+       rc = snd_ctl_add(c->card, h->prof_ctl);
+       if (rc)
+               dev_err(p->dev, "Failed to add KControl: %s, rc = %d\n",
+                       tas2781_prof_ctl.name, rc);
+       return rc;
+}
+
+static int tas2781_hda_spi_snd_ctls(struct tas2781_hda *h)
+{
+       struct tas2781_hda_spi_priv *h_priv = h->hda_priv;
+       struct tasdevice_priv *p = h->priv;
+       struct hda_codec *c = p->codec;
+       char name[64];
+       int i = 0;
+       int rc;
+
+       snprintf(name, sizeof(name), "Speaker-%d Analog Volume", p->index);
+       tas2781_snd_ctls[i].name = name;
+       h_priv->snd_ctls[i] = snd_ctl_new1(&tas2781_snd_ctls[i], p);
+       rc = snd_ctl_add(c->card, h_priv->snd_ctls[i]);
+       if (rc) {
+               dev_err(p->dev, "Failed to add KControl: %s, rc = %d\n",
+                       tas2781_snd_ctls[i].name, rc);
+               return rc;
+       }
+       i++;
+       snprintf(name, sizeof(name), "Speaker-%d Digital Volume", p->index);
+       tas2781_snd_ctls[i].name = name;
+       h_priv->snd_ctls[i] = snd_ctl_new1(&tas2781_snd_ctls[i], p);
+       rc = snd_ctl_add(c->card, h_priv->snd_ctls[i]);
+       if (rc) {
+               dev_err(p->dev, "Failed to add KControl: %s, rc = %d\n",
+                       tas2781_snd_ctls[i].name, rc);
+               return rc;
+       }
+       i++;
+       snprintf(name, sizeof(name), "Froce Speaker-%d FW Load", p->index);
+       tas2781_snd_ctls[i].name = name;
+       h_priv->snd_ctls[i] = snd_ctl_new1(&tas2781_snd_ctls[i], p);
+       rc = snd_ctl_add(c->card, h_priv->snd_ctls[i]);
+       if (rc) {
+               dev_err(p->dev, "Failed to add KControl: %s, rc = %d\n",
+                       tas2781_snd_ctls[i].name, rc);
+       }
+       return rc;
+}
+
+static int tas2781_hda_spi_dsp_ctls(struct tas2781_hda *h)
+{
+       struct tasdevice_priv *p = h->priv;
+       struct hda_codec *c = p->codec;
+       char name[64];
+       int i = 0;
+       int rc;
+
+       snprintf(name, sizeof(name), "Speaker-%d Program Id", p->index);
+       tas2781_dsp_ctls[i].name = name;
+       h->dsp_prog_ctl = snd_ctl_new1(&tas2781_dsp_ctls[i], p);
+       rc = snd_ctl_add(c->card, h->dsp_prog_ctl);
+       if (rc) {
+               dev_err(p->dev, "Failed to add KControl: %s, rc = %d\n",
+                       tas2781_dsp_ctls[i].name, rc);
+               return rc;
+       }
+       i++;
+       snprintf(name, sizeof(name), "Speaker-%d Config Id", p->index);
+       tas2781_dsp_ctls[i].name = name;
+       h->dsp_conf_ctl = snd_ctl_new1(&tas2781_dsp_ctls[i], p);
+       rc = snd_ctl_add(c->card, h->dsp_conf_ctl);
+       if (rc) {
+               dev_err(p->dev, "Failed to add KControl: %s, rc = %d\n",
+                       tas2781_dsp_ctls[i].name, rc);
+       }
+
+       return rc;
+}
+
 static void tasdev_fw_ready(const struct firmware *fmw, void *context)
 {
        struct tasdevice_priv *tas_priv = context;
        struct tas2781_hda *tas_hda = dev_get_drvdata(tas_priv->dev);
        struct hda_codec *codec = tas_priv->codec;
-       int i, j, ret, val;
+       int ret, val;
 
        pm_runtime_get_sync(tas_priv->dev);
        guard(mutex)(&tas_priv->codec_lock);
@@ -879,33 +806,19 @@ static void tasdev_fw_ready(const struct firmware *fmw, void *context)
                goto out;
 
        /* Add control one time only. */
-       tas_hda->prof_ctl = snd_ctl_new1(&tas2781_prof_ctrl[tas_priv->index],
-               tas_priv);
-       ret = snd_ctl_add(codec->card, tas_hda->prof_ctl);
-       if (ret) {
-               dev_err(tas_priv->dev, "Failed to add KControl %s = %d\n",
-                       tas2781_prof_ctrl[tas_priv->index].name, ret);
+       ret = tas2781_hda_spi_prf_ctl(tas_hda);
+       if (ret)
+               goto out;
+
+       ret = tas2781_hda_spi_snd_ctls(tas_hda);
+       if (ret)
                goto out;
-       }
-       j = tas_priv->index * ARRAY_SIZE(tas2781_snd_controls) / 2;
-       for (i = 0; i < 3; i++) {
-               tas_hda->snd_ctls[i] = snd_ctl_new1(&tas2781_snd_controls[i+j],
-                       tas_priv);
-               ret = snd_ctl_add(codec->card, tas_hda->snd_ctls[i]);
-               if (ret) {
-                       dev_err(tas_priv->dev,
-                               "Failed to add KControl %s = %d\n",
-                               tas2781_snd_controls[i+tas_priv->index*3].name,
-                               ret);
-                       goto out;
-               }
-       }
 
        tasdevice_dsp_remove(tas_priv);
 
        tas_priv->fw_state = TASDEVICE_DSP_FW_PENDING;
-       scnprintf(tas_priv->coef_binaryname, 64, "TAS2XXX%08X-%01d.bin",
-               codec->core.subsystem_id, tas_priv->index);
+       scnprintf(tas_priv->coef_binaryname, 64, "TAS2XXX%04X-%01d.bin",
+               lower_16_bits(codec->core.subsystem_id), tas_priv->index);
        ret = tasdevice_dsp_parser(tas_priv);
        if (ret) {
                dev_err(tas_priv->dev, "dspfw load %s error\n",
@@ -914,33 +827,15 @@ static void tasdev_fw_ready(const struct firmware *fmw, void *context)
                goto out;
        }
 
-       /* Add control one time only. */
-       tas_hda->dsp_prog_ctl =
-               snd_ctl_new1(&tas2781_dsp_prog_ctrl[tas_priv->index],
-                            tas_priv);
-       ret = snd_ctl_add(codec->card, tas_hda->dsp_prog_ctl);
-       if (ret) {
-               dev_err(tas_priv->dev,
-                       "Failed to add KControl %s = %d\n",
-                       tas2781_dsp_prog_ctrl[tas_priv->index].name, ret);
-               goto out;
-       }
-
-       tas_hda->dsp_conf_ctl =
-               snd_ctl_new1(&tas2781_dsp_conf_ctrl[tas_priv->index],
-                            tas_priv);
-       ret = snd_ctl_add(codec->card, tas_hda->dsp_conf_ctl);
-       if (ret) {
-               dev_err(tas_priv->dev, "Failed to add KControl %s = %d\n",
-                       tas2781_dsp_conf_ctrl[tas_priv->index].name, ret);
+       ret = tas2781_hda_spi_dsp_ctls(tas_hda);
+       if (ret)
                goto out;
-       }
-
+       /* Perform AMP reset before firmware download. */
        tas2781_spi_reset(tas_priv);
        tas_priv->rcabin.profile_cfg_id = 0;
 
        tas_priv->fw_state = TASDEVICE_DSP_FW_ALL_OK;
-       ret = tas_priv->dev_read(tas_priv, tas_priv->index,
+       ret = tasdevice_spi_dev_read(tas_priv, tas_priv->index,
                TAS2781_REG_CLK_CONFIG, &val);
        if (ret < 0)
                goto out;
@@ -952,6 +847,7 @@ static void tasdev_fw_ready(const struct firmware *fmw, void *context)
                                ret);
                        goto out;
                }
+               tas_priv->fw_state = TASDEVICE_DSP_FW_ALL_OK;
        }
        if (tas_priv->fmw->nr_programs > 0)
                tas_priv->tasdevice[tas_priv->index].cur_prog = 0;
@@ -962,7 +858,7 @@ static void tasdev_fw_ready(const struct firmware *fmw, void *context)
         * If calibrated data occurs error, dsp will still works with default
         * calibrated data inside algo.
         */
-
+       tas2781_save_calibration(tas_priv);
 out:
        release_firmware(fmw);
        pm_runtime_mark_last_busy(tas_hda->priv->dev);
@@ -1032,22 +928,9 @@ static const struct component_ops tas2781_hda_comp_ops = {
        .unbind = tas2781_hda_unbind,
 };
 
-static void tas2781_hda_remove(struct device *dev)
-{
-       struct tas2781_hda *tas_hda = dev_get_drvdata(dev);
-
-       component_del(tas_hda->priv->dev, &tas2781_hda_comp_ops);
-
-       pm_runtime_get_sync(tas_hda->priv->dev);
-       pm_runtime_disable(tas_hda->priv->dev);
-
-       pm_runtime_put_noidle(tas_hda->priv->dev);
-
-       mutex_destroy(&tas_hda->priv->codec_lock);
-}
-
 static int tas2781_hda_spi_probe(struct spi_device *spi)
 {
+       struct tas2781_hda_spi_priv *hda_priv;
        struct tasdevice_priv *tas_priv;
        struct tas2781_hda *tas_hda;
        const char *device_name;
@@ -1057,6 +940,11 @@ static int tas2781_hda_spi_probe(struct spi_device *spi)
        if (!tas_hda)
                return -ENOMEM;
 
+       hda_priv = devm_kzalloc(&spi->dev, sizeof(*hda_priv), GFP_KERNEL);
+       if (!hda_priv)
+               return -ENOMEM;
+
+       tas_hda->hda_priv = hda_priv;
        spi->max_speed_hz = TAS2781_SPI_MAX_FREQ;
 
        tas_priv = devm_kzalloc(&spi->dev, sizeof(*tas_priv), GFP_KERNEL);
@@ -1087,16 +975,10 @@ static int tas2781_hda_spi_probe(struct spi_device *spi)
                                spi_get_chipselect(spi, 0));
        if (ret)
                return dev_err_probe(tas_priv->dev, ret,
-                                    "Platform not supported\n");
+                               "Platform not supported\n");
 
        tasdevice_spi_init(tas_priv);
 
-       ret = component_add(tas_priv->dev, &tas2781_hda_comp_ops);
-       if (ret) {
-               dev_err(tas_priv->dev, "Register component fail: %d\n", ret);
-               return ret;
-       }
-
        pm_runtime_set_autosuspend_delay(tas_priv->dev, 3000);
        pm_runtime_use_autosuspend(tas_priv->dev);
        pm_runtime_mark_last_busy(tas_priv->dev);
@@ -1106,12 +988,19 @@ static int tas2781_hda_spi_probe(struct spi_device *spi)
 
        pm_runtime_put_autosuspend(tas_priv->dev);
 
-       return 0;
+       ret = component_add(tas_priv->dev, &tas2781_hda_comp_ops);
+       if (ret) {
+               dev_err(tas_priv->dev, "Register component fail: %d\n", ret);
+               pm_runtime_disable(tas_priv->dev);
+               tas2781_hda_remove(&spi->dev, &tas2781_hda_comp_ops);
+       }
+
+       return ret;
 }
 
 static void tas2781_hda_spi_remove(struct spi_device *spi)
 {
-       tas2781_hda_remove(&spi->dev);
+       tas2781_hda_remove(&spi->dev, &tas2781_hda_comp_ops);
 }
 
 static int tas2781_runtime_suspend(struct device *dev)
@@ -1231,3 +1120,4 @@ MODULE_DESCRIPTION("TAS2781 HDA SPI Driver");
 MODULE_AUTHOR("Baojun, Xu, <baojun.xug@ti.com>");
 MODULE_LICENSE("GPL");
 MODULE_IMPORT_NS("SND_SOC_TAS2781_FMWLIB");
+MODULE_IMPORT_NS("SND_HDA_SCODEC_TAS2781");