1
0
Fork 0
mirror of synced 2025-03-06 20:59:54 +01:00

ALSA: hda/tas2781: Add tas2781 hda SPI driver

This patch was used to add TAS2781 devices on SPI support in sound/pci/hda.
It use ACPI node descript about parameters of TAS2781 on SPI, it like:
    Scope (_SB.PC00.SPI0)
    {
        Device (GSPK)
        {
            Name (_HID, "TXNW2781")  // _HID: Hardware ID
            Method (_CRS, 0, NotSerialized)
            {
                Name (RBUF, ResourceTemplate ()
                {
                    SpiSerialBusV2 (...)
                    SpiSerialBusV2 (...)
                }
            }
        }
    }

And in platform/x86/serial-multi-instantiate.c, those spi devices will be
added into system as a single SPI device, so TAS2781 SPI driver will
probe twice for every single SPI device. And driver will also parser
mono DSP firmware binary and RCA binary for itself.
The code support Realtek as the primary codec.
In patch version-10, add multi devices firmware binary support,
to compatble with windows driver, they can share same firmware binary.

Signed-off-by: Baojun Xu <baojun.xu@ti.com>
Link: https://patch.msgid.link/20241216122008.15425-1-baojun.xu@ti.com
Signed-off-by: Takashi Iwai <tiwai@suse.de>
This commit is contained in:
Baojun Xu 2024-12-16 20:20:08 +08:00 committed by Takashi Iwai
parent d466887a94
commit bb5f86ea50
8 changed files with 3478 additions and 0 deletions

View file

@ -1769,6 +1769,7 @@ static bool acpi_device_enumeration_by_parent(struct acpi_device *device)
{"CSC3557", },
{"INT33FE", },
{"INT3515", },
{"TXNW2781", },
/* Non-conforming _HID for Cirrus Logic already released */
{"CLSA0100", },
{"CLSA0101", },

View file

@ -384,6 +384,17 @@ static const struct smi_node cs35l57_hda = {
.bus_type = SMI_AUTO_DETECT,
};
static const struct smi_node tas2781_hda = {
.instances = {
{ "tas2781-hda", IRQ_RESOURCE_AUTO, 0 },
{ "tas2781-hda", IRQ_RESOURCE_AUTO, 0 },
{ "tas2781-hda", IRQ_RESOURCE_AUTO, 0 },
{ "tas2781-hda", IRQ_RESOURCE_AUTO, 0 },
{}
},
.bus_type = SMI_AUTO_DETECT,
};
/*
* Note new device-ids must also be added to ignore_serial_bus_ids in
* drivers/acpi/scan.c: acpi_device_enumeration_by_parent().
@ -396,6 +407,7 @@ static const struct acpi_device_id smi_acpi_ids[] = {
{ "CSC3556", (unsigned long)&cs35l56_hda },
{ "CSC3557", (unsigned long)&cs35l57_hda },
{ "INT3515", (unsigned long)&int3515_data },
{ "TXNW2781", (unsigned long)&tas2781_hda },
/* Non-conforming _HID for Cirrus Logic already released */
{ "CLSA0100", (unsigned long)&cs35l41_hda },
{ "CLSA0101", (unsigned long)&cs35l41_hda },

View file

@ -206,6 +206,20 @@ config SND_HDA_SCODEC_TAS2781_I2C
comment "Set to Y if you want auto-loading the side codec driver"
depends on SND_HDA=y && SND_HDA_SCODEC_TAS2781_I2C=m
config SND_HDA_SCODEC_TAS2781_SPI
tristate "Build TAS2781 HD-audio side codec support for SPI Bus"
depends on SPI_MASTER
depends on ACPI
depends on EFI
depends on SND_SOC
select CRC32_SARWATE
help
Say Y or M here to include TAS2781 SPI HD-audio side codec support
in snd-hda-intel driver, such as ALC287.
comment "Set to Y if you want auto-loading the side codec driver"
depends on SND_HDA=y && SND_HDA_SCODEC_TAS2781_SPI=m
config SND_HDA_CODEC_REALTEK
tristate "Build Realtek HD-audio codec support"
select SND_HDA_GENERIC

View file

@ -40,6 +40,7 @@ snd-hda-scodec-cs35l56-spi-y := cs35l56_hda_spi.o
snd-hda-cs-dsp-ctls-y := hda_cs_dsp_ctl.o
snd-hda-scodec-component-y := hda_component.o
snd-hda-scodec-tas2781-i2c-y := tas2781_hda_i2c.o
snd-hda-scodec-tas2781-spi-y := tas2781_hda_spi.o tas2781_spi_fwlib.o
# common driver
obj-$(CONFIG_SND_HDA) := snd-hda-codec.o
@ -72,6 +73,7 @@ obj-$(CONFIG_SND_HDA_SCODEC_CS35L56_SPI) += snd-hda-scodec-cs35l56-spi.o
obj-$(CONFIG_SND_HDA_CS_DSP_CONTROLS) += snd-hda-cs-dsp-ctls.o
obj-$(CONFIG_SND_HDA_SCODEC_COMPONENT) += snd-hda-scodec-component.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
# this must be the last entry after codec drivers;
# otherwise the codec patches won't be hooked before the PCI probe

View file

@ -7135,6 +7135,11 @@ static void tas2781_fixup_i2c(struct hda_codec *cdc,
comp_generic_fixup(cdc, action, "i2c", "TIAS2781", "-%s:00", 1);
}
static void tas2781_fixup_spi(struct hda_codec *cdc, const struct hda_fixup *fix, int action)
{
comp_generic_fixup(cdc, action, "spi", "TXNW2781", "-%s:00-tas2781-hda.%d", 2);
}
static void yoga7_14arb7_fixup_i2c(struct hda_codec *cdc,
const struct hda_fixup *fix, int action)
{
@ -7770,6 +7775,7 @@ enum {
ALC236_FIXUP_DELL_DUAL_CODECS,
ALC287_FIXUP_CS35L41_I2C_2_THINKPAD_ACPI,
ALC287_FIXUP_TAS2781_I2C,
ALC245_FIXUP_TAS2781_SPI_2,
ALC287_FIXUP_YOGA7_14ARB7_I2C,
ALC245_FIXUP_HP_MUTE_LED_COEFBIT,
ALC245_FIXUP_HP_X360_MUTE_LEDS,
@ -10000,6 +10006,12 @@ static const struct hda_fixup alc269_fixups[] = {
.chained = true,
.chain_id = ALC285_FIXUP_THINKPAD_HEADSET_JACK,
},
[ALC245_FIXUP_TAS2781_SPI_2] = {
.type = HDA_FIXUP_FUNC,
.v.func = tas2781_fixup_spi,
.chained = true,
.chain_id = ALC285_FIXUP_HP_GPIO_LED,
},
[ALC287_FIXUP_YOGA7_14ARB7_I2C] = {
.type = HDA_FIXUP_FUNC,
.v.func = yoga7_14arb7_fixup_i2c,
@ -10562,6 +10574,8 @@ static const struct hda_quirk alc269_fixup_tbl[] = {
SND_PCI_QUIRK(0x103c, 0x8d84, "HP EliteBook X G1i", ALC285_FIXUP_HP_GPIO_LED),
SND_PCI_QUIRK(0x103c, 0x8d91, "HP ZBook Firefly 14 G12", ALC285_FIXUP_HP_GPIO_LED),
SND_PCI_QUIRK(0x103c, 0x8d92, "HP ZBook Firefly 16 G12", ALC285_FIXUP_HP_GPIO_LED),
SND_PCI_QUIRK(0x103c, 0x8de8, "HP Gemtree", ALC245_FIXUP_TAS2781_SPI_2),
SND_PCI_QUIRK(0x103c, 0x8de9, "HP Gemtree", ALC245_FIXUP_TAS2781_SPI_2),
SND_PCI_QUIRK(0x103c, 0x8e18, "HP ZBook Firefly 14 G12A", ALC285_FIXUP_HP_GPIO_LED),
SND_PCI_QUIRK(0x103c, 0x8e19, "HP ZBook Firefly 14 G12A", ALC285_FIXUP_HP_GPIO_LED),
SND_PCI_QUIRK(0x103c, 0x8e1a, "HP ZBook Firefly 14 G12A", ALC285_FIXUP_HP_GPIO_LED),

158
sound/pci/hda/tas2781-spi.h Normal file
View file

@ -0,0 +1,158 @@
/* SPDX-License-Identifier: GPL-2.0 */
//
// ALSA SoC Texas Instruments TAS2781 Audio Smart Amplifier
//
// Copyright (C) 2024 Texas Instruments Incorporated
// https://www.ti.com
//
// The TAS2781 driver implements a flexible and configurable
// algo coefficient setting for TAS2781 chips.
//
// Author: Baojun Xu <baojun.xu@ti.com>
//
#ifndef __TAS2781_SPI_H__
#define __TAS2781_SPI_H__
#define TASDEVICE_RATES \
(SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000 | \
SNDRV_PCM_RATE_96000 | SNDRV_PCM_RATE_88200)
#define TASDEVICE_FORMATS \
(SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE | \
SNDRV_PCM_FMTBIT_S32_LE)
#define TASDEVICE_MAX_BOOK_NUM 256
#define TASDEVICE_MAX_PAGE 256
#define TASDEVICE_MAX_SIZE (TASDEVICE_MAX_BOOK_NUM * TASDEVICE_MAX_PAGE)
/* PAGE Control Register (available in page0 of each book) */
#define TASDEVICE_PAGE_SELECT 0x00
#define TASDEVICE_BOOKCTL_PAGE 0x00
#define TASDEVICE_BOOKCTL_REG GENMASK(7, 1)
#define TASDEVICE_BOOK_ID(reg) (((reg) & GENMASK(24, 16)) >> 16)
#define TASDEVICE_PAGE_ID(reg) (((reg) & GENMASK(15, 8)) >> 8)
#define TASDEVICE_REG_ID(reg) (((reg) & GENMASK(7, 1)) >> 1)
#define TASDEVICE_PAGE_REG(reg) ((reg) & GENMASK(15, 1))
#define TASDEVICE_REG(book, page, reg) \
(((book) << 16) | ((page) << 8) | ((reg) << 1))
/* Software Reset */
#define TAS2781_REG_SWRESET TASDEVICE_REG(0x0, 0x0, 0x01)
#define TAS2781_REG_SWRESET_RESET BIT(0)
/* System Reset Check Register */
#define TAS2781_REG_CLK_CONFIG TASDEVICE_REG(0x0, 0x0, 0x5c)
#define TAS2781_REG_CLK_CONFIG_RESET (0x19)
#define TAS2781_PRE_POST_RESET_CFG 3
/* Block Checksum */
#define TASDEVICE_CHECKSUM TASDEVICE_REG(0x0, 0x0, 0x7e)
/* Volume control */
#define TAS2781_DVC_LVL TASDEVICE_REG(0x0, 0x0, 0x1a)
#define TAS2781_AMP_LEVEL TASDEVICE_REG(0x0, 0x0, 0x03)
#define TAS2781_AMP_LEVEL_MASK GENMASK(5, 1)
#define TASDEVICE_CMD_SING_W 0x1
#define TASDEVICE_CMD_BURST 0x2
#define TASDEVICE_CMD_DELAY 0x3
#define TASDEVICE_CMD_FIELD_W 0x4
#define TAS2781_SPI_MAX_FREQ (4 * HZ_PER_MHZ)
#define TASDEVICE_CRC8_POLYNOMIAL 0x4d
#define TASDEVICE_SPEAKER_CALIBRATION_SIZE 20
/* Flag of calibration registers address. */
#define TASDEVICE_CALIBRATION_REG_ADDRESS BIT(7)
#define TASDEVICE_CALIBRATION_DATA_NAME L"CALI_DATA"
#define TASDEVICE_CALIBRATION_DATA_SIZE 256
enum calib_data {
R0_VAL = 0,
INV_R0,
R0LOW,
POWER,
TLIM,
CALIB_MAX
};
struct tasdevice_priv {
struct tasdevice_fw *cali_data_fmw;
struct tasdevice_rca rcabin;
struct tasdevice_fw *fmw;
struct gpio_desc *reset;
struct mutex codec_lock;
struct regmap *regmap;
struct device *dev;
struct tm tm;
unsigned char crc8_lkp_tbl[CRC8_TABLE_SIZE];
unsigned char coef_binaryname[64];
unsigned char rca_binaryname[64];
unsigned char dev_name[32];
bool force_fwload_status;
bool playback_started;
bool is_loading;
bool is_loaderr;
unsigned int cali_reg_array[CALIB_MAX];
unsigned int cali_data[CALIB_MAX];
unsigned int err_code;
void *codec;
int cur_book;
int cur_prog;
int cur_conf;
int fw_state;
int index;
int irq;
int (*fw_parse_variable_header)(struct tasdevice_priv *tas_priv,
const struct firmware *fmw,
int offset);
int (*fw_parse_program_data)(struct tasdevice_priv *tas_priv,
struct tasdevice_fw *tas_fmw,
const struct firmware *fmw, int offset);
int (*fw_parse_configuration_data)(struct tasdevice_priv *tas_priv,
struct tasdevice_fw *tas_fmw,
const struct firmware *fmw,
int offset);
int (*tasdevice_load_block)(struct tasdevice_priv *tas_priv,
struct tasdev_blk *block);
int (*save_calibration)(struct tasdevice_priv *tas_priv);
void (*apply_calibration)(struct tasdevice_priv *tas_priv);
};
int tasdevice_spi_dev_read(struct tasdevice_priv *tas_priv,
unsigned int reg, unsigned int *value);
int tasdevice_spi_dev_write(struct tasdevice_priv *tas_priv,
unsigned int reg, unsigned int value);
int tasdevice_spi_dev_bulk_write(struct tasdevice_priv *tas_priv,
unsigned int reg, unsigned char *p_data,
unsigned int n_length);
int tasdevice_spi_dev_bulk_read(struct tasdevice_priv *tas_priv,
unsigned int reg, unsigned char *p_data,
unsigned int n_length);
int tasdevice_spi_dev_update_bits(struct tasdevice_priv *tasdevice,
unsigned int reg, unsigned int mask,
unsigned int value);
void tasdevice_spi_select_cfg_blk(void *context, int conf_no,
unsigned char block_type);
void tasdevice_spi_config_info_remove(void *context);
int tasdevice_spi_dsp_parser(void *context);
int tasdevice_spi_rca_parser(void *context, const struct firmware *fmw);
void tasdevice_spi_dsp_remove(void *context);
void tasdevice_spi_calbin_remove(void *context);
int tasdevice_spi_select_tuningprm_cfg(void *context, int prm, int cfg_no,
int rca_conf_no);
int tasdevice_spi_prmg_load(void *context, int prm_no);
int tasdevice_spi_prmg_calibdata_load(void *context, int prm_no);
void tasdevice_spi_tuning_switch(void *context, int state);
int tas2781_spi_load_calibration(void *context, char *file_name,
unsigned short i);
#endif /* __TAS2781_SPI_H__ */

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff