Skip to content

Commit 4fe2385

Browse files
Shenghao-Dingtiwai
authored andcommitted
ALSA: hda/tas2781: Move and unified the calibrated-data getting function for SPI and I2C into the tas2781_hda lib
Calibration data getting function for SPI and I2C HDA drivers are almost same, which read the calibration data from UEFI. To put them into tas2781_hda lib for code cleanup is more reasonable than to still keep them in the codec driver. For tas2781 codec driver, there're two different sources for calibrated data, one is from bin file, generated in factory test, requested and read in codec driver side; the other is from user space during device bootup. Signed-off-by: Shenghao Ding <shenghao-ding@ti.com> Link: https://patch.msgid.link/20250522014347.1163-1-shenghao-ding@ti.com Signed-off-by: Takashi Iwai <tiwai@suse.de>
1 parent c597ce5 commit 4fe2385

File tree

6 files changed

+272
-356
lines changed

6 files changed

+272
-356
lines changed

include/sound/tas2781.h

Lines changed: 0 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -121,11 +121,6 @@ enum dspbin_type {
121121
TASDEV_BETA,
122122
};
123123

124-
enum device_catlog_id {
125-
LENOVO = 0,
126-
OTHERS
127-
};
128-
129124
struct bulk_reg_val {
130125
int reg;
131126
unsigned char val[4];
@@ -172,7 +167,6 @@ struct tasdevice_priv {
172167
struct regmap *regmap;
173168
struct device *dev;
174169

175-
enum device_catlog_id catlog_id;
176170
unsigned char cal_binaryname[TASDEVICE_MAX_CHANNELS][64];
177171
unsigned char crc8_lkp_tbl[CRC8_TABLE_SIZE];
178172
unsigned char coef_binaryname[64];
@@ -223,8 +217,6 @@ struct tasdevice_priv {
223217
int (*dev_bulk_read)(struct tasdevice_priv *tas_priv,
224218
unsigned short chn, unsigned int reg, unsigned char *p_data,
225219
unsigned int n_length);
226-
int (*save_calibration)(struct tasdevice_priv *tas_priv);
227-
void (*apply_calibration)(struct tasdevice_priv *tas_priv);
228220
};
229221

230222
int tasdevice_dev_read(struct tasdevice_priv *tas_priv,
@@ -238,6 +230,4 @@ int tasdevice_dev_bulk_write(
238230
struct tasdevice_priv *tas_priv, unsigned short chn,
239231
unsigned int reg, unsigned char *p_data, unsigned int n_length);
240232
void tasdevice_remove(struct tasdevice_priv *tas_priv);
241-
int tasdevice_save_calibration(struct tasdevice_priv *tas_priv);
242-
void tasdevice_apply_calibration(struct tasdevice_priv *tas_priv);
243233
#endif /* __TAS2781_H__ */

sound/pci/hda/tas2781_hda.c

Lines changed: 179 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,185 @@
1818

1919
#include "tas2781_hda.h"
2020

21+
const efi_guid_t tasdev_fct_efi_guid[] = {
22+
/* DELL */
23+
EFI_GUID(0xcc92382d, 0x6337, 0x41cb, 0xa8, 0x8b, 0x8e, 0xce, 0x74,
24+
0x91, 0xea, 0x9f),
25+
/* HP */
26+
EFI_GUID(0x02f9af02, 0x7734, 0x4233, 0xb4, 0x3d, 0x93, 0xfe, 0x5a,
27+
0xa3, 0x5d, 0xb3),
28+
/* LENOVO & OTHERS */
29+
EFI_GUID(0x1f52d2a1, 0xbb3a, 0x457d, 0xbc, 0x09, 0x43, 0xa3, 0xf4,
30+
0x31, 0x0a, 0x92),
31+
};
32+
EXPORT_SYMBOL_NS_GPL(tasdev_fct_efi_guid, "SND_HDA_SCODEC_TAS2781");
33+
34+
static void tas2781_apply_calib(struct tasdevice_priv *p)
35+
{
36+
struct calidata *cali_data = &p->cali_data;
37+
struct cali_reg *r = &cali_data->cali_reg_array;
38+
unsigned char *data = cali_data->data;
39+
unsigned int *tmp_val = (unsigned int *)data;
40+
unsigned int cali_reg[TASDEV_CALIB_N] = {
41+
TASDEVICE_REG(0, 0x17, 0x74),
42+
TASDEVICE_REG(0, 0x18, 0x0c),
43+
TASDEVICE_REG(0, 0x18, 0x14),
44+
TASDEVICE_REG(0, 0x13, 0x70),
45+
TASDEVICE_REG(0, 0x18, 0x7c),
46+
};
47+
unsigned int crc, oft;
48+
unsigned char *buf;
49+
int i, j, k, l;
50+
51+
if (tmp_val[0] == 2781) {
52+
/*
53+
* New features were added in calibrated Data V3:
54+
* 1. Added calibration registers address define in
55+
* a node, marked as Device id == 0x80.
56+
* New features were added in calibrated Data V2:
57+
* 1. Added some the fields to store the link_id and
58+
* uniqie_id for multi-link solutions
59+
* 2. Support flexible number of devices instead of
60+
* fixed one in V1.
61+
* Layout of calibrated data V2 in UEFI(total 256 bytes):
62+
* ChipID (2781, 4 bytes)
63+
* Data-Group-Sum (4 bytes)
64+
* TimeStamp of Calibration (4 bytes)
65+
* for (i = 0; i < Data-Group-Sum; i++) {
66+
* if (Data type != 0x80) (4 bytes)
67+
* Calibrated Data of Device #i (20 bytes)
68+
* else
69+
* Calibration registers address (5*4 = 20 bytes)
70+
* # V2: No reg addr in data grp section.
71+
* # V3: Normally the last grp is the reg addr.
72+
* }
73+
* CRC (4 bytes)
74+
* Reserved (the rest)
75+
*/
76+
crc = crc32(~0, data, (3 + tmp_val[1] * 6) * 4) ^ ~0;
77+
78+
if (crc != tmp_val[3 + tmp_val[1] * 6]) {
79+
cali_data->total_sz = 0;
80+
dev_err(p->dev, "%s: CRC error\n", __func__);
81+
return;
82+
}
83+
84+
for (j = 0, k = 0; j < tmp_val[1]; j++) {
85+
oft = j * 6 + 3;
86+
if (tmp_val[oft] == TASDEV_UEFI_CALI_REG_ADDR_FLG) {
87+
for (i = 0; i < TASDEV_CALIB_N; i++) {
88+
buf = &data[(oft + i + 1) * 4];
89+
cali_reg[i] = TASDEVICE_REG(buf[1],
90+
buf[2], buf[3]);
91+
}
92+
} else {
93+
l = j * (cali_data->cali_dat_sz_per_dev + 1);
94+
if (k >= p->ndev || l > oft * 4) {
95+
dev_err(p->dev, "%s: dev sum error\n",
96+
__func__);
97+
cali_data->total_sz = 0;
98+
return;
99+
}
100+
101+
data[l] = k;
102+
for (i = 0; i < TASDEV_CALIB_N * 4; i++)
103+
data[l + i] = data[4 * oft + i];
104+
k++;
105+
}
106+
}
107+
} else {
108+
/*
109+
* Calibration data is in V1 format.
110+
* struct cali_data {
111+
* char cali_data[20];
112+
* }
113+
*
114+
* struct {
115+
* struct cali_data cali_data[4];
116+
* int TimeStamp of Calibration (4 bytes)
117+
* int CRC (4 bytes)
118+
* } ueft;
119+
*/
120+
crc = crc32(~0, data, 84) ^ ~0;
121+
if (crc != tmp_val[21]) {
122+
cali_data->total_sz = 0;
123+
dev_err(p->dev, "%s: V1 CRC error\n", __func__);
124+
return;
125+
}
126+
127+
for (j = p->ndev - 1; j >= 0; j--) {
128+
l = j * (cali_data->cali_dat_sz_per_dev + 1);
129+
for (i = TASDEV_CALIB_N * 4; i > 0 ; i--)
130+
data[l + i] = data[p->index * 5 + i];
131+
data[l+i] = j;
132+
}
133+
}
134+
135+
if (p->dspbin_typ == TASDEV_BASIC) {
136+
r->r0_reg = cali_reg[0];
137+
r->invr0_reg = cali_reg[1];
138+
r->r0_low_reg = cali_reg[2];
139+
r->pow_reg = cali_reg[3];
140+
r->tlimit_reg = cali_reg[4];
141+
}
142+
143+
p->is_user_space_calidata = true;
144+
cali_data->total_sz = p->ndev * (cali_data->cali_dat_sz_per_dev + 1);
145+
}
146+
147+
/*
148+
* Update the calibration data, including speaker impedance, f0, etc,
149+
* into algo. Calibrate data is done by manufacturer in the factory.
150+
* The data is used by Algo for calculating the speaker temperature,
151+
* speaker membrane excursion and f0 in real time during playback.
152+
* Calibration data format in EFI is V2, since 2024.
153+
*/
154+
int tas2781_save_calibration(struct tas2781_hda *hda)
155+
{
156+
/*
157+
* GUID was used for data access in BIOS, it was provided by board
158+
* manufactory.
159+
*/
160+
efi_guid_t efi_guid = tasdev_fct_efi_guid[LENOVO];
161+
static efi_char16_t efi_name[] = TASDEVICE_CALIBRATION_DATA_NAME;
162+
struct tasdevice_priv *p = hda->priv;
163+
struct calidata *cali_data = &p->cali_data;
164+
unsigned long total_sz = 0;
165+
unsigned int attr, size;
166+
unsigned char *data;
167+
efi_status_t status;
168+
169+
if (hda->catlog_id < LENOVO)
170+
efi_guid = tasdev_fct_efi_guid[hda->catlog_id];
171+
172+
cali_data->cali_dat_sz_per_dev = 20;
173+
size = p->ndev * (cali_data->cali_dat_sz_per_dev + 1);
174+
/* Get real size of UEFI variable */
175+
status = efi.get_variable(efi_name, &efi_guid, &attr, &total_sz, NULL);
176+
cali_data->total_sz = total_sz > size ? total_sz : size;
177+
if (status == EFI_BUFFER_TOO_SMALL) {
178+
/* Allocate data buffer of data_size bytes */
179+
data = p->cali_data.data = devm_kzalloc(p->dev,
180+
p->cali_data.total_sz, GFP_KERNEL);
181+
if (!data) {
182+
p->cali_data.total_sz = 0;
183+
return -ENOMEM;
184+
}
185+
/* Get variable contents into buffer */
186+
status = efi.get_variable(efi_name, &efi_guid, &attr,
187+
&p->cali_data.total_sz, data);
188+
}
189+
if (status != EFI_SUCCESS) {
190+
p->cali_data.total_sz = 0;
191+
return status;
192+
}
193+
194+
tas2781_apply_calib(p);
195+
196+
return 0;
197+
}
198+
EXPORT_SYMBOL_NS_GPL(tas2781_save_calibration, "SND_HDA_SCODEC_TAS2781");
199+
21200
void tas2781_hda_remove(struct device *dev,
22201
const struct component_ops *ops)
23202
{

sound/pci/hda/tas2781_hda.h

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,8 @@
99

1010
#include <sound/asound.h>
1111

12+
/* Flag of calibration registers address. */
13+
#define TASDEV_UEFI_CALI_REG_ADDR_FLG BIT(7)
1214
#define TASDEVICE_CALIBRATION_DATA_NAME L"CALI_DATA"
1315
#define TASDEV_CALIB_N 5
1416

@@ -44,6 +46,13 @@
4446
.private_value = xdata, \
4547
}
4648

49+
enum device_catlog_id {
50+
DELL = 0,
51+
HP,
52+
LENOVO,
53+
OTHERS
54+
};
55+
4756
struct tas2781_hda {
4857
struct device *dev;
4958
struct tasdevice_priv *priv;
@@ -54,6 +63,9 @@ struct tas2781_hda {
5463
void *hda_priv;
5564
};
5665

66+
extern const efi_guid_t tasdev_fct_efi_guid[];
67+
68+
int tas2781_save_calibration(struct tas2781_hda *p);
5769
void tas2781_hda_remove(struct device *dev,
5870
const struct component_ops *ops);
5971
int tasdevice_info_profile(struct snd_kcontrol *kctl,

0 commit comments

Comments
 (0)