Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

ALSA: hda: Add TAS5825 support

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

authored by

Baojun Xu and committed by
Takashi Iwai
f4ee43ae 03714939

+121 -5
+3
include/sound/tas2781-dsp.h
··· 34 34 #define PPC3_VERSION_TAS2781_BASIC_MIN 0x14600 35 35 #define PPC3_VERSION_TAS2781_ALPHA_MIN 0x4a00 36 36 #define PPC3_VERSION_TAS2781_BETA_MIN 0x19400 37 + #define PPC3_VERSION_TAS5825_BASE 0x114200 37 38 #define TASDEVICE_DEVICE_SUM 8 38 39 #define TASDEVICE_CONFIG_SUM 64 39 40 ··· 54 53 TASDEVICE_DSP_TAS_2781_DUAL_MONO, 55 54 TASDEVICE_DSP_TAS_2781_21, 56 55 TASDEVICE_DSP_TAS_2781_QUAD, 56 + TASDEVICE_DSP_TAS_5825_MONO, 57 + TASDEVICE_DSP_TAS_5825_DUAL, 57 58 TASDEVICE_DSP_TAS_MAX_DEVICE 58 59 }; 59 60
+2 -2
include/sound/tas2781.h
··· 49 49 #define TASDEVICE_REG(book, page, reg) (((book * 256 * 128) + \ 50 50 (page * 128)) + reg) 51 51 52 - /* Software Reset */ 52 + /* Software Reset, compatble with new device (TAS5825). */ 53 53 #define TASDEVICE_REG_SWRESET TASDEVICE_REG(0x0, 0x0, 0x01) 54 - #define TASDEVICE_REG_SWRESET_RESET BIT(0) 54 + #define TASDEVICE_REG_SWRESET_RESET (BIT(0) | BIT(4)) 55 55 56 56 /* Checksum */ 57 57 #define TASDEVICE_CHECKSUM_REG TASDEVICE_REG(0x0, 0x0, 0x7e)
+24
include/sound/tas5825-tlv.h
··· 1 + /* SPDX-License-Identifier: GPL-2.0 */ 2 + // 3 + // ALSA SoC Texas Instruments TAS5825 Audio Smart Amplifier 4 + // 5 + // Copyright (C) 2025 Texas Instruments Incorporated 6 + // https://www.ti.com 7 + // 8 + // The TAS5825 hda driver implements for one or two TAS5825 chips. 9 + // 10 + // Author: Baojun Xu <baojun.xu@ti.com> 11 + // 12 + 13 + #ifndef __TAS5825_TLV_H__ 14 + #define __TAS5825_TLV_H__ 15 + 16 + #define TAS5825_DVC_LEVEL TASDEVICE_REG(0x0, 0x0, 0x4c) 17 + #define TAS5825_AMP_LEVEL TASDEVICE_REG(0x0, 0x0, 0x54) 18 + 19 + static const __maybe_unused DECLARE_TLV_DB_SCALE( 20 + tas5825_dvc_tlv, -10300, 50, 0); 21 + static const __maybe_unused DECLARE_TLV_DB_SCALE( 22 + tas5825_amp_tlv, -1550, 50, 0); 23 + 24 + #endif
+28
sound/hda/codecs/side-codecs/tas2781_hda_i2c.c
··· 26 26 #include <sound/tlv.h> 27 27 #include <sound/tas2770-tlv.h> 28 28 #include <sound/tas2781-tlv.h> 29 + #include <sound/tas5825-tlv.h> 29 30 30 31 #include "hda_local.h" 31 32 #include "hda_auto_parser.h" ··· 51 50 HDA_TAS2563, 52 51 HDA_TAS2770, 53 52 HDA_TAS2781, 53 + HDA_TAS5825, 54 54 HDA_OTHERS 55 55 }; 56 56 ··· 270 268 ACARD_SINGLE_RANGE_EXT_TLV("Speaker Analog Gain", TAS2781_AMP_LEVEL, 271 269 1, 0, 20, 0, tas2781_amp_getvol, 272 270 tas2781_amp_putvol, amp_vol_tlv), 271 + ACARD_SINGLE_BOOL_EXT("Speaker Force Firmware Load", 0, 272 + tas2781_force_fwload_get, tas2781_force_fwload_put), 273 + }; 274 + 275 + static const struct snd_kcontrol_new tas5825_snd_controls[] = { 276 + ACARD_SINGLE_RANGE_EXT_TLV("Speaker Analog Volume", TAS5825_AMP_LEVEL, 277 + 0, 0, 31, 1, tas2781_amp_getvol, 278 + tas2781_amp_putvol, tas5825_amp_tlv), 279 + ACARD_SINGLE_RANGE_EXT_TLV("Speaker Digital Volume", TAS5825_DVC_LEVEL, 280 + 0, 0, 254, 1, tas2781_amp_getvol, 281 + tas2781_amp_putvol, tas5825_dvc_tlv), 273 282 ACARD_SINGLE_BOOL_EXT("Speaker Force Firmware Load", 0, 274 283 tas2781_force_fwload_get, tas2781_force_fwload_put), 275 284 }; ··· 514 501 ARRAY_SIZE(tas2781_snd_controls)); 515 502 tasdevice_dspfw_init(context); 516 503 break; 504 + case HDA_TAS5825: 505 + tasdev_add_kcontrols(tas_priv, hda_priv->snd_ctls, codec, 506 + &tas5825_snd_controls[0], 507 + ARRAY_SIZE(tas5825_snd_controls)); 508 + tasdevice_dspfw_init(context); 509 + break; 517 510 case HDA_TAS2563: 518 511 tasdevice_dspfw_init(context); 519 512 break; ··· 647 628 } else if (strstarts(dev_name(&clt->dev), 648 629 "i2c-TXNW2781:00-tas2781-hda.0")) { 649 630 device_name = "TXNW2781"; 631 + hda_priv->hda_chip_id = HDA_TAS2781; 650 632 hda_priv->save_calibration = tas2781_save_calibration; 651 633 tas_hda->priv->global_addr = TAS2781_GLOBAL_ADDR; 652 634 } else if (strstr(dev_name(&clt->dev), "INT8866")) { ··· 659 639 hda_priv->hda_chip_id = HDA_TAS2563; 660 640 hda_priv->save_calibration = tas2563_save_calibration; 661 641 tas_hda->priv->global_addr = TAS2563_GLOBAL_ADDR; 642 + } else if (strstarts(dev_name(&clt->dev), "i2c-TXNW5825")) { 643 + /* 644 + * TAS5825, integrated on-chip DSP without 645 + * global I2C address and calibration supported. 646 + */ 647 + device_name = "TXNW5825"; 648 + hda_priv->hda_chip_id = HDA_TAS5825; 662 649 } else { 663 650 return -ENODEV; 664 651 } ··· 802 775 {"TIAS2781", 0 }, 803 776 {"TXNW2770", 0 }, 804 777 {"TXNW2781", 0 }, 778 + {"TXNW5825", 0 }, 805 779 {} 806 780 }; 807 781 MODULE_DEVICE_TABLE(acpi, tas2781_acpi_hda_match);
+64 -3
sound/soc/codecs/tas2781-fmwlib.c
··· 91 91 }; 92 92 93 93 static const char deviceNumber[TASDEVICE_DSP_TAS_MAX_DEVICE] = { 94 - 1, 2, 1, 2, 1, 1, 0, 2, 4, 3, 1, 2, 3, 4 94 + 1, 2, 1, 2, 1, 1, 0, 2, 4, 3, 1, 2, 3, 4, 1, 2 95 95 }; 96 96 97 97 /* fixed m68k compiling issue: mapping table can save code field */ ··· 506 506 } 507 507 508 508 out: 509 + return offset; 510 + } 511 + 512 + static int fw_parse_tas5825_program_data_kernel( 513 + struct tasdevice_priv *tas_priv, struct tasdevice_fw *tas_fmw, 514 + const struct firmware *fmw, int offset) 515 + { 516 + struct tasdevice_prog *program; 517 + unsigned int i; 518 + 519 + for (i = 0; i < tas_fmw->nr_programs; i++) { 520 + program = &(tas_fmw->programs[i]); 521 + if (offset + 72 > fmw->size) { 522 + dev_err(tas_priv->dev, "%s: mpName error\n", __func__); 523 + return -EINVAL; 524 + } 525 + /* Skip 65 unused byts*/ 526 + offset += 65; 527 + offset = fw_parse_data_kernel(tas_fmw, &(program->dev_data), 528 + fmw, offset); 529 + if (offset < 0) 530 + return offset; 531 + } 532 + 533 + return offset; 534 + } 535 + 536 + static int fw_parse_tas5825_configuration_data_kernel( 537 + struct tasdevice_priv *tas_priv, 538 + struct tasdevice_fw *tas_fmw, const struct firmware *fmw, int offset) 539 + { 540 + const unsigned char *data = fmw->data; 541 + struct tasdevice_config *config; 542 + unsigned int i; 543 + 544 + for (i = 0; i < tas_fmw->nr_configurations; i++) { 545 + config = &(tas_fmw->configs[i]); 546 + if (offset + 80 > fmw->size) { 547 + dev_err(tas_priv->dev, "%s: mpName error\n", __func__); 548 + return -EINVAL; 549 + } 550 + memcpy(config->name, &data[offset], 64); 551 + /* Skip extra 8 bytes*/ 552 + offset += 72; 553 + offset = fw_parse_data_kernel(tas_fmw, &(config->dev_data), 554 + fmw, offset); 555 + if (offset < 0) 556 + return offset; 557 + } 558 + 509 559 return offset; 510 560 } 511 561 ··· 1876 1826 else 1877 1827 tas_priv->dspbin_typ = TASDEV_ALPHA; 1878 1828 } 1879 - if (tas_priv->dspbin_typ != TASDEV_BASIC) 1829 + if ((tas_priv->dspbin_typ != TASDEV_BASIC) && 1830 + (ppcver < PPC3_VERSION_TAS5825_BASE)) 1880 1831 tas_priv->fw_parse_fct_param_address = 1881 1832 fw_parse_fct_param_address; 1882 1833 } ··· 1888 1837 int rc = 0; 1889 1838 1890 1839 if (drv_ver == 0x100) { 1891 - if (ppcver >= PPC3_VERSION_BASE) { 1840 + if (ppcver >= PPC3_VERSION_TAS5825_BASE) { 1841 + tas_priv->fw_parse_variable_header = 1842 + fw_parse_variable_header_kernel; 1843 + tas_priv->fw_parse_program_data = 1844 + fw_parse_tas5825_program_data_kernel; 1845 + tas_priv->fw_parse_configuration_data = 1846 + fw_parse_tas5825_configuration_data_kernel; 1847 + tas_priv->tasdevice_load_block = 1848 + tasdevice_load_block_kernel; 1849 + dspbin_type_check(tas_priv, ppcver); 1850 + } else if (ppcver >= PPC3_VERSION_BASE) { 1892 1851 tas_priv->fw_parse_variable_header = 1893 1852 fw_parse_variable_header_kernel; 1894 1853 tas_priv->fw_parse_program_data =