]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
ALSA: hda: Add TAS5825 support
authorBaojun Xu <baojun.xu@ti.com>
Sun, 10 Aug 2025 12:23:58 +0000 (20:23 +0800)
committerTakashi Iwai <tiwai@suse.de>
Mon, 11 Aug 2025 07:13:42 +0000 (09:13 +0200)
Add TAS5825 support in TI's HDA driver.
TAS5825 is an on-chip DSP, but no calibration is required,
and no global address support smart amplifier devices.

Signed-off-by: Baojun Xu <baojun.xu@ti.com>
Acked-by: Mark Brown <broonie@kernel.org>
Signed-off-by: Takashi Iwai <tiwai@suse.de>
Link: https://patch.msgid.link/20250810122358.1575-1-baojun.xu@ti.com
include/sound/tas2781-dsp.h
include/sound/tas2781.h
include/sound/tas5825-tlv.h [new file with mode: 0644]
sound/hda/codecs/side-codecs/tas2781_hda_i2c.c
sound/soc/codecs/tas2781-fmwlib.c

index c3a9efa73d5d0578e4a09b8737133c7456c7fb20..49bbf24d65594fcd44d2217f1cd964d70e43010a 100644 (file)
@@ -34,6 +34,7 @@
 #define PPC3_VERSION_TAS2781_BASIC_MIN         0x14600
 #define PPC3_VERSION_TAS2781_ALPHA_MIN         0x4a00
 #define PPC3_VERSION_TAS2781_BETA_MIN          0x19400
+#define PPC3_VERSION_TAS5825_BASE              0x114200
 #define TASDEVICE_DEVICE_SUM                   8
 #define TASDEVICE_CONFIG_SUM                   64
 
@@ -53,6 +54,8 @@ enum tasdevice_dsp_dev_idx {
        TASDEVICE_DSP_TAS_2781_DUAL_MONO,
        TASDEVICE_DSP_TAS_2781_21,
        TASDEVICE_DSP_TAS_2781_QUAD,
+       TASDEVICE_DSP_TAS_5825_MONO,
+       TASDEVICE_DSP_TAS_5825_DUAL,
        TASDEVICE_DSP_TAS_MAX_DEVICE
 };
 
index 3875e92f1ec5af88cdcee8830ed125a7e3bfaeb1..f0aefc04a957a9c493c206a91827a449367331d3 100644 (file)
@@ -49,9 +49,9 @@
 #define TASDEVICE_REG(book, page, reg) (((book * 256 * 128) + \
                                        (page * 128)) + reg)
 
-/* Software Reset */
+/* Software Reset, compatble with new device (TAS5825). */
 #define TASDEVICE_REG_SWRESET          TASDEVICE_REG(0x0, 0x0, 0x01)
-#define TASDEVICE_REG_SWRESET_RESET    BIT(0)
+#define TASDEVICE_REG_SWRESET_RESET    (BIT(0) | BIT(4))
 
 /* Checksum */
 #define TASDEVICE_CHECKSUM_REG         TASDEVICE_REG(0x0, 0x0, 0x7e)
diff --git a/include/sound/tas5825-tlv.h b/include/sound/tas5825-tlv.h
new file mode 100644 (file)
index 0000000..95f2d3f
--- /dev/null
@@ -0,0 +1,24 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+//
+// ALSA SoC Texas Instruments TAS5825 Audio Smart Amplifier
+//
+// Copyright (C) 2025 Texas Instruments Incorporated
+// https://www.ti.com
+//
+// The TAS5825 hda driver implements for one or two TAS5825 chips.
+//
+// Author: Baojun Xu <baojun.xu@ti.com>
+//
+
+#ifndef __TAS5825_TLV_H__
+#define __TAS5825_TLV_H__
+
+#define TAS5825_DVC_LEVEL              TASDEVICE_REG(0x0, 0x0, 0x4c)
+#define TAS5825_AMP_LEVEL              TASDEVICE_REG(0x0, 0x0, 0x54)
+
+static const __maybe_unused DECLARE_TLV_DB_SCALE(
+               tas5825_dvc_tlv, -10300, 50, 0);
+static const __maybe_unused DECLARE_TLV_DB_SCALE(
+               tas5825_amp_tlv, -1550, 50, 0);
+
+#endif
index e1d60da50897f25166787b3c74cb2e30637801fe..8fae0fea37a01d4c455a36659e02db48277664eb 100644 (file)
@@ -26,6 +26,7 @@
 #include <sound/tlv.h>
 #include <sound/tas2770-tlv.h>
 #include <sound/tas2781-tlv.h>
+#include <sound/tas5825-tlv.h>
 
 #include "hda_local.h"
 #include "hda_auto_parser.h"
@@ -50,6 +51,7 @@ enum device_chip_id {
        HDA_TAS2563,
        HDA_TAS2770,
        HDA_TAS2781,
+       HDA_TAS5825,
        HDA_OTHERS
 };
 
@@ -272,6 +274,17 @@ static const struct snd_kcontrol_new tas2781_snd_controls[] = {
                tas2781_force_fwload_get, tas2781_force_fwload_put),
 };
 
+static const struct snd_kcontrol_new tas5825_snd_controls[] = {
+       ACARD_SINGLE_RANGE_EXT_TLV("Speaker Analog Volume", TAS5825_AMP_LEVEL,
+               0, 0, 31, 1, tas2781_amp_getvol,
+               tas2781_amp_putvol, tas5825_amp_tlv),
+       ACARD_SINGLE_RANGE_EXT_TLV("Speaker Digital Volume", TAS5825_DVC_LEVEL,
+               0, 0, 254, 1, tas2781_amp_getvol,
+               tas2781_amp_putvol, tas5825_dvc_tlv),
+       ACARD_SINGLE_BOOL_EXT("Speaker Force Firmware Load", 0,
+               tas2781_force_fwload_get, tas2781_force_fwload_put),
+};
+
 static const struct snd_kcontrol_new tasdevice_prof_ctrl = {
        .name = "Speaker Profile Id",
        .iface = SNDRV_CTL_ELEM_IFACE_CARD,
@@ -501,6 +514,12 @@ static void tasdev_fw_ready(const struct firmware *fmw, void *context)
                                     ARRAY_SIZE(tas2781_snd_controls));
                tasdevice_dspfw_init(context);
                break;
+       case HDA_TAS5825:
+               tasdev_add_kcontrols(tas_priv, hda_priv->snd_ctls, codec,
+                                    &tas5825_snd_controls[0],
+                                    ARRAY_SIZE(tas5825_snd_controls));
+               tasdevice_dspfw_init(context);
+               break;
        case HDA_TAS2563:
                tasdevice_dspfw_init(context);
                break;
@@ -628,6 +647,7 @@ static int tas2781_hda_i2c_probe(struct i2c_client *clt)
        } else if (strstarts(dev_name(&clt->dev),
                             "i2c-TXNW2781:00-tas2781-hda.0")) {
                device_name = "TXNW2781";
+               hda_priv->hda_chip_id = HDA_TAS2781;
                hda_priv->save_calibration = tas2781_save_calibration;
                tas_hda->priv->global_addr = TAS2781_GLOBAL_ADDR;
        } else if (strstr(dev_name(&clt->dev), "INT8866")) {
@@ -639,6 +659,13 @@ static int tas2781_hda_i2c_probe(struct i2c_client *clt)
                hda_priv->hda_chip_id = HDA_TAS2563;
                hda_priv->save_calibration = tas2563_save_calibration;
                tas_hda->priv->global_addr = TAS2563_GLOBAL_ADDR;
+       } else if (strstarts(dev_name(&clt->dev), "i2c-TXNW5825")) {
+               /*
+                * TAS5825, integrated on-chip DSP without
+                * global I2C address and calibration supported.
+                */
+               device_name = "TXNW5825";
+               hda_priv->hda_chip_id = HDA_TAS5825;
        } else {
                return -ENODEV;
        }
@@ -775,6 +802,7 @@ static const struct acpi_device_id tas2781_acpi_hda_match[] = {
        {"TIAS2781", 0 },
        {"TXNW2770", 0 },
        {"TXNW2781", 0 },
+       {"TXNW5825", 0 },
        {}
 };
 MODULE_DEVICE_TABLE(acpi, tas2781_acpi_hda_match);
index c9c1e608ddb757d52aad08b6d35be104eac81af3..d69faef8a4d7467ddb90d5f633a4d00a8a389f8d 100644 (file)
@@ -91,7 +91,7 @@ struct blktyp_devidx_map {
 };
 
 static const char deviceNumber[TASDEVICE_DSP_TAS_MAX_DEVICE] = {
-       1, 2, 1, 2, 1, 1, 0, 2, 4, 3, 1, 2, 3, 4
+       1, 2, 1, 2, 1, 1, 0, 2, 4, 3, 1, 2, 3, 4, 1, 2
 };
 
 /* fixed m68k compiling issue: mapping table can save code field */
@@ -509,6 +509,56 @@ out:
        return offset;
 }
 
+static int fw_parse_tas5825_program_data_kernel(
+       struct tasdevice_priv *tas_priv, struct tasdevice_fw *tas_fmw,
+       const struct firmware *fmw, int offset)
+{
+       struct tasdevice_prog *program;
+       unsigned int i;
+
+       for (i = 0; i < tas_fmw->nr_programs; i++) {
+               program = &(tas_fmw->programs[i]);
+               if (offset + 72 > fmw->size) {
+                       dev_err(tas_priv->dev, "%s: mpName error\n", __func__);
+                       return -EINVAL;
+               }
+               /* Skip 65 unused byts*/
+               offset += 65;
+               offset = fw_parse_data_kernel(tas_fmw, &(program->dev_data),
+                       fmw, offset);
+               if (offset < 0)
+                       return offset;
+       }
+
+       return offset;
+}
+
+static int fw_parse_tas5825_configuration_data_kernel(
+       struct tasdevice_priv *tas_priv,
+       struct tasdevice_fw *tas_fmw, const struct firmware *fmw, int offset)
+{
+       const unsigned char *data = fmw->data;
+       struct tasdevice_config *config;
+       unsigned int i;
+
+       for (i = 0; i < tas_fmw->nr_configurations; i++) {
+               config = &(tas_fmw->configs[i]);
+               if (offset + 80 > fmw->size) {
+                       dev_err(tas_priv->dev, "%s: mpName error\n", __func__);
+                       return -EINVAL;
+               }
+               memcpy(config->name, &data[offset], 64);
+               /* Skip extra 8 bytes*/
+               offset += 72;
+               offset = fw_parse_data_kernel(tas_fmw, &(config->dev_data),
+                       fmw, offset);
+               if (offset < 0)
+                       return offset;
+       }
+
+       return offset;
+}
+
 static int fw_parse_program_data_kernel(
        struct tasdevice_priv *tas_priv, struct tasdevice_fw *tas_fmw,
        const struct firmware *fmw, int offset)
@@ -1826,7 +1876,8 @@ static void dspbin_type_check(struct tasdevice_priv *tas_priv,
                else
                        tas_priv->dspbin_typ = TASDEV_ALPHA;
        }
-       if (tas_priv->dspbin_typ != TASDEV_BASIC)
+       if ((tas_priv->dspbin_typ != TASDEV_BASIC) &&
+               (ppcver < PPC3_VERSION_TAS5825_BASE))
                tas_priv->fw_parse_fct_param_address =
                        fw_parse_fct_param_address;
 }
@@ -1837,7 +1888,17 @@ static int dspfw_default_callback(struct tasdevice_priv *tas_priv,
        int rc = 0;
 
        if (drv_ver == 0x100) {
-               if (ppcver >= PPC3_VERSION_BASE) {
+               if (ppcver >= PPC3_VERSION_TAS5825_BASE) {
+                       tas_priv->fw_parse_variable_header =
+                               fw_parse_variable_header_kernel;
+                       tas_priv->fw_parse_program_data =
+                               fw_parse_tas5825_program_data_kernel;
+                       tas_priv->fw_parse_configuration_data =
+                               fw_parse_tas5825_configuration_data_kernel;
+                       tas_priv->tasdevice_load_block =
+                               tasdevice_load_block_kernel;
+                       dspbin_type_check(tas_priv, ppcver);
+               } else if (ppcver >= PPC3_VERSION_BASE) {
                        tas_priv->fw_parse_variable_header =
                                fw_parse_variable_header_kernel;
                        tas_priv->fw_parse_program_data =