Skip to content

Commit bb5f86e

Browse files
jimxbj-dottiwai
authored andcommitted
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 <[email protected]> Link: https://patch.msgid.link/[email protected] Signed-off-by: Takashi Iwai <[email protected]>
1 parent d466887 commit bb5f86e

File tree

8 files changed

+3478
-0
lines changed

8 files changed

+3478
-0
lines changed

drivers/acpi/scan.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1769,6 +1769,7 @@ static bool acpi_device_enumeration_by_parent(struct acpi_device *device)
17691769
{"CSC3557", },
17701770
{"INT33FE", },
17711771
{"INT3515", },
1772+
{"TXNW2781", },
17721773
/* Non-conforming _HID for Cirrus Logic already released */
17731774
{"CLSA0100", },
17741775
{"CLSA0101", },

drivers/platform/x86/serial-multi-instantiate.c

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -384,6 +384,17 @@ static const struct smi_node cs35l57_hda = {
384384
.bus_type = SMI_AUTO_DETECT,
385385
};
386386

387+
static const struct smi_node tas2781_hda = {
388+
.instances = {
389+
{ "tas2781-hda", IRQ_RESOURCE_AUTO, 0 },
390+
{ "tas2781-hda", IRQ_RESOURCE_AUTO, 0 },
391+
{ "tas2781-hda", IRQ_RESOURCE_AUTO, 0 },
392+
{ "tas2781-hda", IRQ_RESOURCE_AUTO, 0 },
393+
{}
394+
},
395+
.bus_type = SMI_AUTO_DETECT,
396+
};
397+
387398
/*
388399
* Note new device-ids must also be added to ignore_serial_bus_ids in
389400
* drivers/acpi/scan.c: acpi_device_enumeration_by_parent().
@@ -396,6 +407,7 @@ static const struct acpi_device_id smi_acpi_ids[] = {
396407
{ "CSC3556", (unsigned long)&cs35l56_hda },
397408
{ "CSC3557", (unsigned long)&cs35l57_hda },
398409
{ "INT3515", (unsigned long)&int3515_data },
410+
{ "TXNW2781", (unsigned long)&tas2781_hda },
399411
/* Non-conforming _HID for Cirrus Logic already released */
400412
{ "CLSA0100", (unsigned long)&cs35l41_hda },
401413
{ "CLSA0101", (unsigned long)&cs35l41_hda },

sound/pci/hda/Kconfig

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -206,6 +206,20 @@ config SND_HDA_SCODEC_TAS2781_I2C
206206
comment "Set to Y if you want auto-loading the side codec driver"
207207
depends on SND_HDA=y && SND_HDA_SCODEC_TAS2781_I2C=m
208208

209+
config SND_HDA_SCODEC_TAS2781_SPI
210+
tristate "Build TAS2781 HD-audio side codec support for SPI Bus"
211+
depends on SPI_MASTER
212+
depends on ACPI
213+
depends on EFI
214+
depends on SND_SOC
215+
select CRC32_SARWATE
216+
help
217+
Say Y or M here to include TAS2781 SPI HD-audio side codec support
218+
in snd-hda-intel driver, such as ALC287.
219+
220+
comment "Set to Y if you want auto-loading the side codec driver"
221+
depends on SND_HDA=y && SND_HDA_SCODEC_TAS2781_SPI=m
222+
209223
config SND_HDA_CODEC_REALTEK
210224
tristate "Build Realtek HD-audio codec support"
211225
select SND_HDA_GENERIC

sound/pci/hda/Makefile

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ snd-hda-scodec-cs35l56-spi-y := cs35l56_hda_spi.o
4040
snd-hda-cs-dsp-ctls-y := hda_cs_dsp_ctl.o
4141
snd-hda-scodec-component-y := hda_component.o
4242
snd-hda-scodec-tas2781-i2c-y := tas2781_hda_i2c.o
43+
snd-hda-scodec-tas2781-spi-y := tas2781_hda_spi.o tas2781_spi_fwlib.o
4344

4445
# common driver
4546
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
7273
obj-$(CONFIG_SND_HDA_CS_DSP_CONTROLS) += snd-hda-cs-dsp-ctls.o
7374
obj-$(CONFIG_SND_HDA_SCODEC_COMPONENT) += snd-hda-scodec-component.o
7475
obj-$(CONFIG_SND_HDA_SCODEC_TAS2781_I2C) += snd-hda-scodec-tas2781-i2c.o
76+
obj-$(CONFIG_SND_HDA_SCODEC_TAS2781_SPI) += snd-hda-scodec-tas2781-spi.o
7577

7678
# this must be the last entry after codec drivers;
7779
# otherwise the codec patches won't be hooked before the PCI probe

sound/pci/hda/patch_realtek.c

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7135,6 +7135,11 @@ static void tas2781_fixup_i2c(struct hda_codec *cdc,
71357135
comp_generic_fixup(cdc, action, "i2c", "TIAS2781", "-%s:00", 1);
71367136
}
71377137

7138+
static void tas2781_fixup_spi(struct hda_codec *cdc, const struct hda_fixup *fix, int action)
7139+
{
7140+
comp_generic_fixup(cdc, action, "spi", "TXNW2781", "-%s:00-tas2781-hda.%d", 2);
7141+
}
7142+
71387143
static void yoga7_14arb7_fixup_i2c(struct hda_codec *cdc,
71397144
const struct hda_fixup *fix, int action)
71407145
{
@@ -7770,6 +7775,7 @@ enum {
77707775
ALC236_FIXUP_DELL_DUAL_CODECS,
77717776
ALC287_FIXUP_CS35L41_I2C_2_THINKPAD_ACPI,
77727777
ALC287_FIXUP_TAS2781_I2C,
7778+
ALC245_FIXUP_TAS2781_SPI_2,
77737779
ALC287_FIXUP_YOGA7_14ARB7_I2C,
77747780
ALC245_FIXUP_HP_MUTE_LED_COEFBIT,
77757781
ALC245_FIXUP_HP_X360_MUTE_LEDS,
@@ -10000,6 +10006,12 @@ static const struct hda_fixup alc269_fixups[] = {
1000010006
.chained = true,
1000110007
.chain_id = ALC285_FIXUP_THINKPAD_HEADSET_JACK,
1000210008
},
10009+
[ALC245_FIXUP_TAS2781_SPI_2] = {
10010+
.type = HDA_FIXUP_FUNC,
10011+
.v.func = tas2781_fixup_spi,
10012+
.chained = true,
10013+
.chain_id = ALC285_FIXUP_HP_GPIO_LED,
10014+
},
1000310015
[ALC287_FIXUP_YOGA7_14ARB7_I2C] = {
1000410016
.type = HDA_FIXUP_FUNC,
1000510017
.v.func = yoga7_14arb7_fixup_i2c,
@@ -10562,6 +10574,8 @@ static const struct hda_quirk alc269_fixup_tbl[] = {
1056210574
SND_PCI_QUIRK(0x103c, 0x8d84, "HP EliteBook X G1i", ALC285_FIXUP_HP_GPIO_LED),
1056310575
SND_PCI_QUIRK(0x103c, 0x8d91, "HP ZBook Firefly 14 G12", ALC285_FIXUP_HP_GPIO_LED),
1056410576
SND_PCI_QUIRK(0x103c, 0x8d92, "HP ZBook Firefly 16 G12", ALC285_FIXUP_HP_GPIO_LED),
10577+
SND_PCI_QUIRK(0x103c, 0x8de8, "HP Gemtree", ALC245_FIXUP_TAS2781_SPI_2),
10578+
SND_PCI_QUIRK(0x103c, 0x8de9, "HP Gemtree", ALC245_FIXUP_TAS2781_SPI_2),
1056510579
SND_PCI_QUIRK(0x103c, 0x8e18, "HP ZBook Firefly 14 G12A", ALC285_FIXUP_HP_GPIO_LED),
1056610580
SND_PCI_QUIRK(0x103c, 0x8e19, "HP ZBook Firefly 14 G12A", ALC285_FIXUP_HP_GPIO_LED),
1056710581
SND_PCI_QUIRK(0x103c, 0x8e1a, "HP ZBook Firefly 14 G12A", ALC285_FIXUP_HP_GPIO_LED),

sound/pci/hda/tas2781-spi.h

Lines changed: 158 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,158 @@
1+
/* SPDX-License-Identifier: GPL-2.0 */
2+
//
3+
// ALSA SoC Texas Instruments TAS2781 Audio Smart Amplifier
4+
//
5+
// Copyright (C) 2024 Texas Instruments Incorporated
6+
// https://www.ti.com
7+
//
8+
// The TAS2781 driver implements a flexible and configurable
9+
// algo coefficient setting for TAS2781 chips.
10+
//
11+
// Author: Baojun Xu <[email protected]>
12+
//
13+
14+
#ifndef __TAS2781_SPI_H__
15+
#define __TAS2781_SPI_H__
16+
17+
#define TASDEVICE_RATES \
18+
(SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000 | \
19+
SNDRV_PCM_RATE_96000 | SNDRV_PCM_RATE_88200)
20+
21+
#define TASDEVICE_FORMATS \
22+
(SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE | \
23+
SNDRV_PCM_FMTBIT_S32_LE)
24+
25+
#define TASDEVICE_MAX_BOOK_NUM 256
26+
#define TASDEVICE_MAX_PAGE 256
27+
28+
#define TASDEVICE_MAX_SIZE (TASDEVICE_MAX_BOOK_NUM * TASDEVICE_MAX_PAGE)
29+
30+
/* PAGE Control Register (available in page0 of each book) */
31+
#define TASDEVICE_PAGE_SELECT 0x00
32+
#define TASDEVICE_BOOKCTL_PAGE 0x00
33+
#define TASDEVICE_BOOKCTL_REG GENMASK(7, 1)
34+
#define TASDEVICE_BOOK_ID(reg) (((reg) & GENMASK(24, 16)) >> 16)
35+
#define TASDEVICE_PAGE_ID(reg) (((reg) & GENMASK(15, 8)) >> 8)
36+
#define TASDEVICE_REG_ID(reg) (((reg) & GENMASK(7, 1)) >> 1)
37+
#define TASDEVICE_PAGE_REG(reg) ((reg) & GENMASK(15, 1))
38+
#define TASDEVICE_REG(book, page, reg) \
39+
(((book) << 16) | ((page) << 8) | ((reg) << 1))
40+
41+
/* Software Reset */
42+
#define TAS2781_REG_SWRESET TASDEVICE_REG(0x0, 0x0, 0x01)
43+
#define TAS2781_REG_SWRESET_RESET BIT(0)
44+
45+
/* System Reset Check Register */
46+
#define TAS2781_REG_CLK_CONFIG TASDEVICE_REG(0x0, 0x0, 0x5c)
47+
#define TAS2781_REG_CLK_CONFIG_RESET (0x19)
48+
#define TAS2781_PRE_POST_RESET_CFG 3
49+
50+
/* Block Checksum */
51+
#define TASDEVICE_CHECKSUM TASDEVICE_REG(0x0, 0x0, 0x7e)
52+
53+
/* Volume control */
54+
#define TAS2781_DVC_LVL TASDEVICE_REG(0x0, 0x0, 0x1a)
55+
#define TAS2781_AMP_LEVEL TASDEVICE_REG(0x0, 0x0, 0x03)
56+
#define TAS2781_AMP_LEVEL_MASK GENMASK(5, 1)
57+
58+
#define TASDEVICE_CMD_SING_W 0x1
59+
#define TASDEVICE_CMD_BURST 0x2
60+
#define TASDEVICE_CMD_DELAY 0x3
61+
#define TASDEVICE_CMD_FIELD_W 0x4
62+
63+
#define TAS2781_SPI_MAX_FREQ (4 * HZ_PER_MHZ)
64+
65+
#define TASDEVICE_CRC8_POLYNOMIAL 0x4d
66+
#define TASDEVICE_SPEAKER_CALIBRATION_SIZE 20
67+
68+
/* Flag of calibration registers address. */
69+
#define TASDEVICE_CALIBRATION_REG_ADDRESS BIT(7)
70+
71+
#define TASDEVICE_CALIBRATION_DATA_NAME L"CALI_DATA"
72+
#define TASDEVICE_CALIBRATION_DATA_SIZE 256
73+
74+
enum calib_data {
75+
R0_VAL = 0,
76+
INV_R0,
77+
R0LOW,
78+
POWER,
79+
TLIM,
80+
CALIB_MAX
81+
};
82+
83+
struct tasdevice_priv {
84+
struct tasdevice_fw *cali_data_fmw;
85+
struct tasdevice_rca rcabin;
86+
struct tasdevice_fw *fmw;
87+
struct gpio_desc *reset;
88+
struct mutex codec_lock;
89+
struct regmap *regmap;
90+
struct device *dev;
91+
struct tm tm;
92+
93+
unsigned char crc8_lkp_tbl[CRC8_TABLE_SIZE];
94+
unsigned char coef_binaryname[64];
95+
unsigned char rca_binaryname[64];
96+
unsigned char dev_name[32];
97+
98+
bool force_fwload_status;
99+
bool playback_started;
100+
bool is_loading;
101+
bool is_loaderr;
102+
unsigned int cali_reg_array[CALIB_MAX];
103+
unsigned int cali_data[CALIB_MAX];
104+
unsigned int err_code;
105+
void *codec;
106+
int cur_book;
107+
int cur_prog;
108+
int cur_conf;
109+
int fw_state;
110+
int index;
111+
int irq;
112+
113+
int (*fw_parse_variable_header)(struct tasdevice_priv *tas_priv,
114+
const struct firmware *fmw,
115+
int offset);
116+
int (*fw_parse_program_data)(struct tasdevice_priv *tas_priv,
117+
struct tasdevice_fw *tas_fmw,
118+
const struct firmware *fmw, int offset);
119+
int (*fw_parse_configuration_data)(struct tasdevice_priv *tas_priv,
120+
struct tasdevice_fw *tas_fmw,
121+
const struct firmware *fmw,
122+
int offset);
123+
int (*tasdevice_load_block)(struct tasdevice_priv *tas_priv,
124+
struct tasdev_blk *block);
125+
126+
int (*save_calibration)(struct tasdevice_priv *tas_priv);
127+
void (*apply_calibration)(struct tasdevice_priv *tas_priv);
128+
};
129+
130+
int tasdevice_spi_dev_read(struct tasdevice_priv *tas_priv,
131+
unsigned int reg, unsigned int *value);
132+
int tasdevice_spi_dev_write(struct tasdevice_priv *tas_priv,
133+
unsigned int reg, unsigned int value);
134+
int tasdevice_spi_dev_bulk_write(struct tasdevice_priv *tas_priv,
135+
unsigned int reg, unsigned char *p_data,
136+
unsigned int n_length);
137+
int tasdevice_spi_dev_bulk_read(struct tasdevice_priv *tas_priv,
138+
unsigned int reg, unsigned char *p_data,
139+
unsigned int n_length);
140+
int tasdevice_spi_dev_update_bits(struct tasdevice_priv *tasdevice,
141+
unsigned int reg, unsigned int mask,
142+
unsigned int value);
143+
144+
void tasdevice_spi_select_cfg_blk(void *context, int conf_no,
145+
unsigned char block_type);
146+
void tasdevice_spi_config_info_remove(void *context);
147+
int tasdevice_spi_dsp_parser(void *context);
148+
int tasdevice_spi_rca_parser(void *context, const struct firmware *fmw);
149+
void tasdevice_spi_dsp_remove(void *context);
150+
void tasdevice_spi_calbin_remove(void *context);
151+
int tasdevice_spi_select_tuningprm_cfg(void *context, int prm, int cfg_no,
152+
int rca_conf_no);
153+
int tasdevice_spi_prmg_load(void *context, int prm_no);
154+
int tasdevice_spi_prmg_calibdata_load(void *context, int prm_no);
155+
void tasdevice_spi_tuning_switch(void *context, int state);
156+
int tas2781_spi_load_calibration(void *context, char *file_name,
157+
unsigned short i);
158+
#endif /* __TAS2781_SPI_H__ */

0 commit comments

Comments
 (0)