lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [thread-next>] [day] [month] [year] [list]
Message-ID: <20250507045813.151-1-shenghao-ding@ti.com>
Date: Wed, 7 May 2025 12:58:13 +0800
From: Shenghao Ding <shenghao-ding@...com>
To: <tiwai@...e.de>
CC: <broonie@...nel.org>, <andriy.shevchenko@...ux.intel.com>,
        <13564923607@....com>, <13916275206@....com>,
        <alsa-devel@...a-project.org>, <linux-kernel@...r.kernel.org>,
        <baojun.xu@...com>, <Baojun.Xu@....com>, <robinchen@...com>,
        Shenghao Ding <shenghao-ding@...com>
Subject: [PATCH v1] ALSA: hda/tas2781: Create an independent lib to save the shared parts for both SPI and I2C driver

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@...com>

---
v1:
 - Define a shared struct tas2781_hda{...} for both SPI and I2C HDA driver.
 - Move the different part, such as sound controls, into tas2781_hda::priv.
 - remove the unused dacpi in struct tas2781_hda{...} for SPI driver.
 - Move tas2781_hda_remove to the tas2781-hda-lib.
 - Optimize the kcontrols creation in SPI driver, remove the unnecessary
   kcotnrols
---
 sound/pci/hda/Kconfig           |   7 +
 sound/pci/hda/Makefile          |   2 +
 sound/pci/hda/tas2781_hda.c     | 198 +++++++++++++++
 sound/pci/hda/tas2781_hda.h     |  31 +++
 sound/pci/hda/tas2781_hda_i2c.c | 214 ++---------------
 sound/pci/hda/tas2781_hda_spi.c | 410 ++++++++++++--------------------
 6 files changed, 405 insertions(+), 457 deletions(-)
 create mode 100644 sound/pci/hda/tas2781_hda.c

diff --git a/sound/pci/hda/Kconfig b/sound/pci/hda/Kconfig
index d5b29b5eb1f6..339c80d2cce5 100644
--- a/sound/pci/hda/Kconfig
+++ b/sound/pci/hda/Kconfig
@@ -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
diff --git a/sound/pci/hda/Makefile b/sound/pci/hda/Makefile
index 13d6c7e63203..5adff1cab101 100644
--- a/sound/pci/hda/Makefile
+++ b/sound/pci/hda/Makefile
@@ -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
index 000000000000..9d8e0d938d5a
--- /dev/null
+++ b/sound/pci/hda/tas2781_hda.c
@@ -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@...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@...com>");
diff --git a/sound/pci/hda/tas2781_hda.h b/sound/pci/hda/tas2781_hda.h
index 444231f87e53..95229083ce6a 100644
--- a/sound/pci/hda/tas2781_hda.h
+++ b/sound/pci/hda/tas2781_hda.h
@@ -44,4 +44,35 @@
 	.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
diff --git a/sound/pci/hda/tas2781_hda_i2c.c b/sound/pci/hda/tas2781_hda_i2c.c
index 0a686e850540..0e51b07dbd05 100644
--- a/sound/pci/hda/tas2781_hda_i2c.c
+++ b/sound/pci/hda/tas2781_hda_i2c.c
@@ -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@...com>");
 MODULE_LICENSE("GPL");
 MODULE_IMPORT_NS("SND_SOC_TAS2781_FMWLIB");
+MODULE_IMPORT_NS("SND_HDA_SCODEC_TAS2781");
diff --git a/sound/pci/hda/tas2781_hda_spi.c b/sound/pci/hda/tas2781_hda_spi.c
index 426fc6044c65..50b82ecabb90 100644
--- a/sound/pci/hda/tas2781_hda_spi.c
+++ b/sound/pci/hda/tas2781_hda_spi.c
@@ -49,13 +49,8 @@
 #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@...com>");
 MODULE_LICENSE("GPL");
 MODULE_IMPORT_NS("SND_SOC_TAS2781_FMWLIB");
+MODULE_IMPORT_NS("SND_HDA_SCODEC_TAS2781");
-- 
2.43.0


Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ