[PATCH v1] ALSA: hda: Add TAS2770 support

Add TAS2770 support in TI's HDA driver. And add hda_chip_id for more product support in the future. Separated DSP and non-DSP in firmware load function.
Signed-off-by: Baojun Xu baojun.xu@ti.com --- include/sound/tas2770-tlv.h | 23 +++++ sound/pci/hda/tas2781_hda_i2c.c | 157 ++++++++++++++++++++++---------- 2 files changed, 133 insertions(+), 47 deletions(-) create mode 100644 include/sound/tas2770-tlv.h
diff --git a/include/sound/tas2770-tlv.h b/include/sound/tas2770-tlv.h new file mode 100644 index 000000000000..c0bd495b4a07 --- /dev/null +++ b/include/sound/tas2770-tlv.h @@ -0,0 +1,23 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +// +// ALSA SoC Texas Instruments TAS2770 Audio Smart Amplifier +// +// Copyright (C) 2025 Texas Instruments Incorporated +// https://www.ti.com +// +// The TAS2770 hda driver implements for one, two, or even multiple +// TAS2770 chips. +// +// Author: Baojun Xu baojun.xu@ti.com +// + +#ifndef __TAS2770_TLV_H__ +#define __TAS2770_TLV_H__ + +#define TAS2770_DVC_LEVEL TASDEVICE_REG(0x0, 0x0, 0x17) +#define TAS2770_AMP_LEVEL TASDEVICE_REG(0x0, 0x0, 0x03) + +static const __maybe_unused DECLARE_TLV_DB_SCALE(tas2770_dvc_tlv, 1650, 50, 0); +static const __maybe_unused DECLARE_TLV_DB_SCALE(tas2770_amp_tlv, 1100, 50, 0); + +#endif diff --git a/sound/pci/hda/tas2781_hda_i2c.c b/sound/pci/hda/tas2781_hda_i2c.c index d91eed9f7804..2fdff0f88af7 100644 --- a/sound/pci/hda/tas2781_hda_i2c.c +++ b/sound/pci/hda/tas2781_hda_i2c.c @@ -24,6 +24,7 @@ #include <sound/tas2781.h> #include <sound/tas2781-comlib-i2c.h> #include <sound/tlv.h> +#include <sound/tas2770-tlv.h> #include <sound/tas2781-tlv.h>
#include "hda_local.h" @@ -45,9 +46,18 @@ #define TAS2563_CAL_TLIM TASDEVICE_REG(0, 0x10, 0x14) #define TAS2563_CAL_R0 TASDEVICE_REG(0, 0x0f, 0x34)
+enum device_chip_id { + HDA_TAS2563, + HDA_TAS2770, + HDA_TAS2781, + HDA_OTHERS +}; + struct tas2781_hda_i2c_priv { struct snd_kcontrol *snd_ctls[2]; int (*save_calibration)(struct tas2781_hda *h); + + int hda_chip_id; };
static int tas2781_get_i2c_res(struct acpi_resource *ares, void *data) @@ -246,6 +256,15 @@ static int tas2781_force_fwload_put(struct snd_kcontrol *kcontrol, return change; }
+static const struct snd_kcontrol_new tas2770_snd_controls[] = { + ACARD_SINGLE_RANGE_EXT_TLV("Speaker Analog Volume", TAS2770_AMP_LEVEL, + 0, 0, 20, 0, tas2781_amp_getvol, + tas2781_amp_putvol, tas2770_amp_tlv), + ACARD_SINGLE_RANGE_EXT_TLV("Speaker Digital Volume", TAS2770_DVC_LEVEL, + 0, 0, 31, 0, tas2781_amp_getvol, + tas2781_amp_putvol, tas2770_dvc_tlv), +}; + static const struct snd_kcontrol_new tas2781_snd_controls[] = { ACARD_SINGLE_RANGE_EXT_TLV("Speaker Analog Gain", TAS2781_AMP_LEVEL, 1, 0, 20, 0, tas2781_amp_getvol, @@ -254,7 +273,7 @@ static const struct snd_kcontrol_new tas2781_snd_controls[] = { tas2781_force_fwload_get, tas2781_force_fwload_put), };
-static const struct snd_kcontrol_new tas2781_prof_ctrl = { +static const struct snd_kcontrol_new tasdevice_prof_ctrl = { .name = "Speaker Profile Id", .iface = SNDRV_CTL_ELEM_IFACE_CARD, .info = tasdevice_info_profile, @@ -262,7 +281,7 @@ static const struct snd_kcontrol_new tas2781_prof_ctrl = { .put = tasdevice_set_profile_id, };
-static const struct snd_kcontrol_new tas2781_dsp_prog_ctrl = { +static const struct snd_kcontrol_new tasdevice_dsp_prog_ctrl = { .name = "Speaker Program Id", .iface = SNDRV_CTL_ELEM_IFACE_CARD, .info = tasdevice_info_programs, @@ -270,7 +289,7 @@ static const struct snd_kcontrol_new tas2781_dsp_prog_ctrl = { .put = tasdevice_program_put, };
-static const struct snd_kcontrol_new tas2781_dsp_conf_ctrl = { +static const struct snd_kcontrol_new tasdevice_dsp_conf_ctrl = { .name = "Speaker Config Id", .iface = SNDRV_CTL_ELEM_IFACE_CARD, .info = tasdevice_info_config, @@ -379,44 +398,15 @@ static void tas2781_hda_remove_controls(struct tas2781_hda *tas_hda) snd_ctl_remove(codec->card, tas_hda->prof_ctl); }
-static void tasdev_fw_ready(const struct firmware *fmw, void *context) +static void tasdevice_dspfw_init(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; - - pm_runtime_get_sync(tas_priv->dev); - mutex_lock(&tas_priv->codec_lock); - - ret = tasdevice_rca_parser(tas_priv, fmw); - if (ret) - goto out; - - tas_hda->prof_ctl = snd_ctl_new1(&tas2781_prof_ctrl, 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.name, ret); - goto out; - } - - for (i = 0; i < ARRAY_SIZE(tas2781_snd_controls); i++) { - hda_priv->snd_ctls[i] = snd_ctl_new1(&tas2781_snd_controls[i], - tas_priv); - 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", - tas2781_snd_controls[i].name, ret); - goto out; - } - } + int ret, spk_id;
tasdevice_dsp_remove(tas_priv); - tas_priv->fw_state = TASDEVICE_DSP_FW_PENDING; if (tas_priv->speaker_id != NULL) { // Speaker id need to be checked for ASUS only. @@ -442,48 +432,101 @@ static void tasdev_fw_ready(const struct firmware *fmw, void *context) dev_err(tas_priv->dev, "dspfw load %s error\n", tas_priv->coef_binaryname); tas_priv->fw_state = TASDEVICE_DSP_FW_FAIL; - goto out; + return; }
- tas_hda->dsp_prog_ctl = snd_ctl_new1(&tas2781_dsp_prog_ctrl, + tas_hda->dsp_prog_ctl = snd_ctl_new1(&tasdevice_dsp_prog_ctrl, 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.name, ret); - goto out; + tasdevice_dsp_prog_ctrl.name, ret); + return; }
- tas_hda->dsp_conf_ctl = snd_ctl_new1(&tas2781_dsp_conf_ctrl, + tas_hda->dsp_conf_ctl = snd_ctl_new1(&tasdevice_dsp_conf_ctrl, 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.name, ret); - goto out; + tasdevice_dsp_conf_ctrl.name, ret); + return; } - tas_priv->fw_state = TASDEVICE_DSP_FW_ALL_OK; + tasdevice_prmg_load(tas_priv, 0); if (tas_priv->fmw->nr_programs > 0) tas_priv->cur_prog = 0; if (tas_priv->fmw->nr_configurations > 0) tas_priv->cur_conf = 0; - /* If calibrated data occurs error, dsp will still works with default * calibrated data inside algo. */ hda_priv->save_calibration(tas_hda); +} + +static void tasdev_add_kcontrols(struct tasdevice_priv *tas_priv, + struct snd_kcontrol **ctls, struct hda_codec *codec, + const struct snd_kcontrol_new *tas_snd_ctrls, int num_ctls) +{ + int i, ret; + + for (i = 0; i < num_ctls; i++) { + ctls[i] = snd_ctl_new1( + &tas_snd_ctrls[i], tas_priv); + ret = snd_ctl_add(codec->card, ctls[i]); + if (ret) { + dev_err(tas_priv->dev, + "Failed to add KControl %s = %d\n", + tas_snd_ctrls[i].name, ret); + break; + } + } +} + +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 ret; + + pm_runtime_get_sync(tas_priv->dev); + mutex_lock(&tas_priv->codec_lock);
- tasdevice_tuning_switch(tas_hda->priv, 0); - tas_hda->priv->playback_started = true; + ret = tasdevice_rca_parser(tas_priv, fmw); + if (ret) + goto out; + + tas_priv->fw_state = TASDEVICE_RCA_FW_OK; + tasdev_add_kcontrols(tas_priv, &tas_hda->prof_ctl, codec, + &tasdevice_prof_ctrl, 1); + + switch (hda_priv->hda_chip_id) { + case HDA_TAS2770: + tasdev_add_kcontrols(tas_priv, hda_priv->snd_ctls, codec, + &tas2770_snd_controls[0], + ARRAY_SIZE(tas2770_snd_controls)); + break; + case HDA_TAS2781: + tasdev_add_kcontrols(tas_priv, hda_priv->snd_ctls, codec, + &tas2781_snd_controls[0], + ARRAY_SIZE(tas2781_snd_controls)); + tasdevice_dspfw_init(context); + break; + case HDA_TAS2563: + tasdevice_dspfw_init(context); + break; + default: + break; + }
out: mutex_unlock(&tas_hda->priv->codec_lock); release_firmware(fmw); - pm_runtime_mark_last_busy(tas_hda->dev); pm_runtime_put_autosuspend(tas_hda->dev); }
@@ -584,15 +627,34 @@ static int tas2781_hda_i2c_probe(struct i2c_client *clt) return -ENOMEM;
if (strstr(dev_name(&clt->dev), "TIAS2781")) { + /* + * TAS2781, integrated on-chip DSP with + * global I2C address supported. + */ device_name = "TIAS2781"; + hda_priv->hda_chip_id = HDA_TAS2781; hda_priv->save_calibration = tas2781_save_calibration; tas_hda->priv->global_addr = TAS2781_GLOBAL_ADDR; + } else if (strstarts(dev_name(&clt->dev), "i2c-TXNW2770")) { + /* + * TAS2770, has no on-chip DSP, so no calibration data + * required; has no global I2C address supported. + */ + device_name = "TXNW2770"; + hda_priv->hda_chip_id = HDA_TAS2770; } else if (strstr(dev_name(&clt->dev), "INT8866")) { + /* + * TAS2563, integrated on-chip DSP with + * global I2C address supported. + */ device_name = "INT8866"; + hda_priv->hda_chip_id = HDA_TAS2563; hda_priv->save_calibration = tas2563_save_calibration; tas_hda->priv->global_addr = TAS2563_GLOBAL_ADDR; - } else + } else { return -ENODEV; + } +
tas_hda->priv->irq = clt->irq; ret = tas2781_read_acpi(tas_hda->priv, device_name); @@ -724,6 +786,7 @@ static const struct i2c_device_id tas2781_hda_i2c_id[] = { static const struct acpi_device_id tas2781_acpi_hda_match[] = { {"TIAS2781", 0 }, {"INT8866", 0 }, + {"TXNW2770", 0 }, {} }; MODULE_DEVICE_TABLE(acpi, tas2781_acpi_hda_match);

On Fri, 18 Jul 2025 11:44:54 +0200, Baojun Xu wrote:
Add TAS2770 support in TI's HDA driver. And add hda_chip_id for more product support in the future. Separated DSP and non-DSP in firmware load function.
Signed-off-by: Baojun Xu baojun.xu@ti.com
Any reason of the submission of the very same patch? It was requested to resubmit after rebasing to the new location for HD-audio (sound/hda/*) as found in for-next branch of sound.git tree.
thanks,
Takashi

From: Takashi Iwai tiwai@suse.de Sent: 18 July 2025 20:29 To: Xu, Baojun Cc: broonie@kernel.org; andriy.shevchenko@linux.intel.com; alsa-devel@alsa-project.org; Ding, Shenghao; Navada Kanyana, Mukund; 13916275206@139.com; Hampiholi, Vallabha; P O, Vijeth; linux-sound@vger.kernel.org; linux-kernel@vger.kernel.org Subject: [EXTERNAL] Re: [PATCH v1] ALSA: hda: Add TAS2770 support
On Fri, 18 Jul 2025 11: 44: 54 +0200, Baojun Xu wrote:
Add TAS2770 support in TI's HDA driver. And add hda_chip_id for more product support in the future. Separated DSP and non-DSP in firmware load function.
Signed-off-by: ZjQcmQRYFpfptBannerStart This message was sent from outside of Texas Instruments. Do not click links or open attachments unless you recognize the source of this email and know the content is safe. https://us-phishalarm-ewt.proofpoint.com/EWT/v1/G3vK!vxdrHfwnF007wWzvvxtoX6USmVeMCYVcebtNTsaFw2PGCzl2HC8-5XErXla_Mkw92m8ysw$ Report Suspicious
ZjQcmQRYFpfptBannerEnd
On Fri, 18 Jul 2025 11:44:54 +0200, Baojun Xu wrote:
Add TAS2770 support in TI's HDA driver. And add hda_chip_id for more product support in the future. Separated DSP and non-DSP in firmware load function.
Signed-off-by: Baojun Xu baojun.xu@ti.com
Any reason of the submission of the very same patch? It was requested to resubmit after rebasing to the new location for HD-audio (sound/hda/*) as found in for-next branch of sound.git tree.
I have uploaded to: git.kernel.org/pub/scm/linux/kernel/git/next/linux-next.git, and you said: "Takashi Iwai tiwai@suse.de, Sat 12/07/2025 16:29
The whole HD-audio stuff has been moved under sound/hda recently. Please create a patch based on for-next branch of the sound git tree."
So I re-patched it to for-next: git.kernel.org/pub/scm/linux/kernel/git/broonie/sound.
Do I have a misunderstanding about it? Do I still need patch on /next/linux-next.git, just after the code was moved to sound/hda/codecs/side-codecs?
thanks,
Takashi
Best Regards Jim
participants (3)
-
Baojun Xu
-
Takashi Iwai
-
Xu, Baojun