Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
torvalds
GitHub Repository: torvalds/linux
Path: blob/master/sound/hda/codecs/side-codecs/tas2781_hda.c
51706 views
1
// SPDX-License-Identifier: GPL-2.0
2
//
3
// TAS2781 HDA Shared Lib for I2C&SPI driver
4
//
5
// Copyright 2025 - 2026 Texas Instruments, Inc.
6
//
7
// Author: Shenghao Ding <[email protected]>
8
9
#include <linux/component.h>
10
#include <linux/crc8.h>
11
#include <linux/crc32.h>
12
#include <linux/efi.h>
13
#include <linux/firmware.h>
14
#include <linux/i2c.h>
15
#include <linux/pm_runtime.h>
16
#include <sound/soc.h>
17
#include <sound/tas2781.h>
18
19
#include "tas2781_hda.h"
20
21
#define CALIBRATION_DATA_AREA_NUM 2
22
23
const efi_guid_t tasdev_fct_efi_guid[] = {
24
/* DELL */
25
EFI_GUID(0xcc92382d, 0x6337, 0x41cb, 0xa8, 0x8b, 0x8e, 0xce, 0x74,
26
0x91, 0xea, 0x9f),
27
/* HP */
28
EFI_GUID(0x02f9af02, 0x7734, 0x4233, 0xb4, 0x3d, 0x93, 0xfe, 0x5a,
29
0xa3, 0x5d, 0xb3),
30
/* LENOVO & OTHERS */
31
EFI_GUID(0x1f52d2a1, 0xbb3a, 0x457d, 0xbc, 0x09, 0x43, 0xa3, 0xf4,
32
0x31, 0x0a, 0x92),
33
};
34
EXPORT_SYMBOL_NS_GPL(tasdev_fct_efi_guid, "SND_HDA_SCODEC_TAS2781");
35
36
/*
37
* The order of calibrated-data writing function is a bit different from the
38
* order in UEFI. Here is the conversion to match the order of calibrated-data
39
* writing function.
40
*/
41
static void cali_cnv(unsigned char *data, unsigned int base, int offset)
42
{
43
struct cali_reg reg_data;
44
45
memcpy(&reg_data, &data[base], sizeof(reg_data));
46
/* the data order has to be swapped between r0_low_reg and inv0_reg */
47
swap(reg_data.r0_low_reg, reg_data.invr0_reg);
48
49
cpu_to_be32_array((__force __be32 *)(data + offset + 1),
50
(u32 *)&reg_data, TASDEV_CALIB_N);
51
}
52
53
static void tas2781_apply_calib(struct tasdevice_priv *p)
54
{
55
struct calidata *cali_data = &p->cali_data;
56
struct cali_reg *r = &cali_data->cali_reg_array;
57
unsigned char *data = cali_data->data;
58
unsigned int *tmp_val = (unsigned int *)data;
59
unsigned int cali_reg[TASDEV_CALIB_N] = {
60
TASDEVICE_REG(0, 0x17, 0x74),
61
TASDEVICE_REG(0, 0x18, 0x0c),
62
TASDEVICE_REG(0, 0x18, 0x14),
63
TASDEVICE_REG(0, 0x13, 0x70),
64
TASDEVICE_REG(0, 0x18, 0x7c),
65
};
66
unsigned int crc, oft, node_num;
67
unsigned char *buf;
68
int i, j, k, l;
69
70
if (tmp_val[0] == 2781) {
71
/*
72
* New features were added in calibrated Data V3:
73
* 1. Added calibration registers address define in
74
* a node, marked as Device id == 0x80.
75
* New features were added in calibrated Data V2:
76
* 1. Added some the fields to store the link_id and
77
* uniqie_id for multi-link solutions
78
* 2. Support flexible number of devices instead of
79
* fixed one in V1.
80
* Layout of calibrated data V2 in UEFI(total 256 bytes):
81
* ChipID (2781, 4 bytes)
82
* Data-Group-Sum (4 bytes)
83
* TimeStamp of Calibration (4 bytes)
84
* for (i = 0; i < Data-Group-Sum; i++) {
85
* if (Data type != 0x80) (4 bytes)
86
* Calibrated Data of Device #i (20 bytes)
87
* else
88
* Calibration registers address (5*4 = 20 bytes)
89
* # V2: No reg addr in data grp section.
90
* # V3: Normally the last grp is the reg addr.
91
* }
92
* CRC (4 bytes)
93
* Reserved (the rest)
94
*/
95
crc = crc32(~0, data, (3 + tmp_val[1] * 6) * 4) ^ ~0;
96
97
if (crc != tmp_val[3 + tmp_val[1] * 6]) {
98
cali_data->total_sz = 0;
99
dev_err(p->dev, "%s: CRC error\n", __func__);
100
return;
101
}
102
node_num = tmp_val[1];
103
104
for (j = 0, k = 0; j < node_num; j++) {
105
oft = j * 6 + 3;
106
if (tmp_val[oft] == TASDEV_UEFI_CALI_REG_ADDR_FLG) {
107
for (i = 0; i < TASDEV_CALIB_N; i++) {
108
buf = &data[(oft + i + 1) * 4];
109
cali_reg[i] = TASDEVICE_REG(buf[1],
110
buf[2], buf[3]);
111
}
112
} else {
113
l = j * (cali_data->cali_dat_sz_per_dev + 1);
114
if (k >= p->ndev || l > oft * 4) {
115
dev_err(p->dev, "%s: dev sum error\n",
116
__func__);
117
cali_data->total_sz = 0;
118
return;
119
}
120
121
data[l] = k;
122
oft++;
123
cali_cnv(data, 4 * oft, l);
124
k++;
125
}
126
}
127
} else {
128
/*
129
* Calibration data is in V1 format.
130
* struct cali_data {
131
* char cali_data[20];
132
* }
133
*
134
* struct {
135
* struct cali_data cali_data[4];
136
* int TimeStamp of Calibration (4 bytes)
137
* int CRC (4 bytes)
138
* } ueft;
139
*/
140
crc = crc32(~0, data, 84) ^ ~0;
141
if (crc != tmp_val[21]) {
142
cali_data->total_sz = 0;
143
dev_err(p->dev, "%s: V1 CRC error\n", __func__);
144
return;
145
}
146
147
for (j = p->ndev - 1; j >= 0; j--) {
148
l = j * (cali_data->cali_dat_sz_per_dev + 1);
149
cali_cnv(data, cali_data->cali_dat_sz_per_dev * j, l);
150
data[l] = j;
151
}
152
}
153
154
if (p->dspbin_typ == TASDEV_BASIC) {
155
r->r0_reg = cali_reg[0];
156
r->invr0_reg = cali_reg[1];
157
r->r0_low_reg = cali_reg[2];
158
r->pow_reg = cali_reg[3];
159
r->tlimit_reg = cali_reg[4];
160
}
161
162
cali_data->total_sz = p->ndev * (cali_data->cali_dat_sz_per_dev + 1);
163
}
164
165
/*
166
* Update the calibration data, including speaker impedance, f0, etc,
167
* into algo. Calibrate data is done by manufacturer in the factory.
168
* The data is used by Algo for calculating the speaker temperature,
169
* speaker membrane excursion and f0 in real time during playback.
170
* Calibration data format in EFI is V2, since 2024.
171
*/
172
int tas2781_save_calibration(struct tas2781_hda *hda)
173
{
174
/*
175
* GUID was used for data access in BIOS, it was provided by board
176
* manufactory.
177
*/
178
efi_guid_t efi_guid = tasdev_fct_efi_guid[LENOVO];
179
/*
180
* Some devices save the calibrated data into L"CALI_DATA",
181
* and others into L"SmartAmpCalibrationData".
182
*/
183
static efi_char16_t *efi_name[CALIBRATION_DATA_AREA_NUM] = {
184
L"CALI_DATA",
185
L"SmartAmpCalibrationData",
186
};
187
struct tasdevice_priv *p = hda->priv;
188
struct calidata *cali_data = &p->cali_data;
189
unsigned long total_sz = 0;
190
unsigned int attr, size;
191
unsigned char *data;
192
efi_status_t status;
193
int i;
194
195
if (!efi_rt_services_supported(EFI_RT_SUPPORTED_GET_VARIABLE)) {
196
dev_err(p->dev, "%s: NO EFI FOUND!\n", __func__);
197
return -EINVAL;
198
}
199
200
if (hda->catlog_id < LENOVO)
201
efi_guid = tasdev_fct_efi_guid[hda->catlog_id];
202
203
cali_data->cali_dat_sz_per_dev = 20;
204
size = p->ndev * (cali_data->cali_dat_sz_per_dev + 1);
205
for (i = 0; i < CALIBRATION_DATA_AREA_NUM; i++) {
206
/* Get real size of UEFI variable */
207
status = efi.get_variable(efi_name[i], &efi_guid, &attr,
208
&total_sz, NULL);
209
cali_data->total_sz = total_sz > size ? total_sz : size;
210
if (status == EFI_BUFFER_TOO_SMALL) {
211
/* Allocate data buffer of data_size bytes */
212
data = cali_data->data = devm_kzalloc(p->dev,
213
cali_data->total_sz, GFP_KERNEL);
214
if (!data) {
215
status = -ENOMEM;
216
continue;
217
}
218
/*
219
* Set to an invalid value before the calibrated data
220
* is stored into it, for the default value is 0, which
221
* means the first device.
222
*/
223
data[0] = 0xff;
224
/* Get variable contents into buffer */
225
status = efi.get_variable(efi_name[i], &efi_guid,
226
&attr, &cali_data->total_sz, data);
227
}
228
/* Check whether get the calibrated data */
229
if (status == EFI_SUCCESS)
230
break;
231
}
232
233
if (status != EFI_SUCCESS) {
234
cali_data->total_sz = 0;
235
return status;
236
}
237
238
tas2781_apply_calib(p);
239
240
return 0;
241
}
242
EXPORT_SYMBOL_NS_GPL(tas2781_save_calibration, "SND_HDA_SCODEC_TAS2781");
243
244
void tas2781_hda_remove(struct device *dev,
245
const struct component_ops *ops)
246
{
247
struct tas2781_hda *tas_hda = dev_get_drvdata(dev);
248
249
component_del(tas_hda->dev, ops);
250
251
pm_runtime_get_sync(tas_hda->dev);
252
pm_runtime_disable(tas_hda->dev);
253
254
pm_runtime_put_noidle(tas_hda->dev);
255
256
tasdevice_remove(tas_hda->priv);
257
}
258
EXPORT_SYMBOL_NS_GPL(tas2781_hda_remove, "SND_HDA_SCODEC_TAS2781");
259
260
int tasdevice_info_profile(struct snd_kcontrol *kcontrol,
261
struct snd_ctl_elem_info *uinfo)
262
{
263
struct tasdevice_priv *tas_priv = snd_kcontrol_chip(kcontrol);
264
265
uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
266
uinfo->count = 1;
267
uinfo->value.integer.min = 0;
268
uinfo->value.integer.max = tas_priv->rcabin.ncfgs - 1;
269
270
return 0;
271
}
272
EXPORT_SYMBOL_NS_GPL(tasdevice_info_profile, "SND_HDA_SCODEC_TAS2781");
273
274
int tasdevice_info_programs(struct snd_kcontrol *kcontrol,
275
struct snd_ctl_elem_info *uinfo)
276
{
277
struct tasdevice_priv *tas_priv = snd_kcontrol_chip(kcontrol);
278
279
uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
280
uinfo->count = 1;
281
uinfo->value.integer.min = 0;
282
uinfo->value.integer.max = tas_priv->fmw->nr_programs - 1;
283
284
return 0;
285
}
286
EXPORT_SYMBOL_NS_GPL(tasdevice_info_programs, "SND_HDA_SCODEC_TAS2781");
287
288
int tasdevice_info_config(struct snd_kcontrol *kcontrol,
289
struct snd_ctl_elem_info *uinfo)
290
{
291
struct tasdevice_priv *tas_priv = snd_kcontrol_chip(kcontrol);
292
struct tasdevice_fw *tas_fw = tas_priv->fmw;
293
294
uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
295
uinfo->count = 1;
296
uinfo->value.integer.min = 0;
297
uinfo->value.integer.max = tas_fw->nr_configurations - 1;
298
299
return 0;
300
}
301
EXPORT_SYMBOL_NS_GPL(tasdevice_info_config, "SND_HDA_SCODEC_TAS2781");
302
303
int tasdevice_get_profile_id(struct snd_kcontrol *kcontrol,
304
struct snd_ctl_elem_value *ucontrol)
305
{
306
struct tasdevice_priv *tas_priv = snd_kcontrol_chip(kcontrol);
307
308
ucontrol->value.integer.value[0] = tas_priv->rcabin.profile_cfg_id;
309
310
dev_dbg(tas_priv->dev, "%s: kcontrol %s: %d\n", __func__,
311
kcontrol->id.name, tas_priv->rcabin.profile_cfg_id);
312
313
return 0;
314
}
315
EXPORT_SYMBOL_NS_GPL(tasdevice_get_profile_id, "SND_HDA_SCODEC_TAS2781");
316
317
int tasdevice_set_profile_id(struct snd_kcontrol *kcontrol,
318
struct snd_ctl_elem_value *ucontrol)
319
{
320
struct tasdevice_priv *tas_priv = snd_kcontrol_chip(kcontrol);
321
int profile_id = ucontrol->value.integer.value[0];
322
int max = tas_priv->rcabin.ncfgs - 1;
323
int val, ret = 0;
324
325
val = clamp(profile_id, 0, max);
326
327
guard(mutex)(&tas_priv->codec_lock);
328
329
dev_dbg(tas_priv->dev, "%s: kcontrol %s: %d -> %d\n", __func__,
330
kcontrol->id.name, tas_priv->rcabin.profile_cfg_id, val);
331
332
if (tas_priv->rcabin.profile_cfg_id != val) {
333
tas_priv->rcabin.profile_cfg_id = val;
334
ret = 1;
335
}
336
337
return ret;
338
}
339
EXPORT_SYMBOL_NS_GPL(tasdevice_set_profile_id, "SND_HDA_SCODEC_TAS2781");
340
341
int tasdevice_program_get(struct snd_kcontrol *kcontrol,
342
struct snd_ctl_elem_value *ucontrol)
343
{
344
struct tasdevice_priv *tas_priv = snd_kcontrol_chip(kcontrol);
345
346
ucontrol->value.integer.value[0] = tas_priv->cur_prog;
347
348
dev_dbg(tas_priv->dev, "%s: kcontrol %s: %d\n", __func__,
349
kcontrol->id.name, tas_priv->cur_prog);
350
351
return 0;
352
}
353
EXPORT_SYMBOL_NS_GPL(tasdevice_program_get, "SND_HDA_SCODEC_TAS2781");
354
355
int tasdevice_program_put(struct snd_kcontrol *kcontrol,
356
struct snd_ctl_elem_value *ucontrol)
357
{
358
struct tasdevice_priv *tas_priv = snd_kcontrol_chip(kcontrol);
359
struct tasdevice_fw *tas_fw = tas_priv->fmw;
360
int nr_program = ucontrol->value.integer.value[0];
361
int max = tas_fw->nr_programs - 1;
362
int val, ret = 0;
363
364
val = clamp(nr_program, 0, max);
365
366
guard(mutex)(&tas_priv->codec_lock);
367
368
dev_dbg(tas_priv->dev, "%s: kcontrol %s: %d -> %d\n", __func__,
369
kcontrol->id.name, tas_priv->cur_prog, val);
370
371
if (tas_priv->cur_prog != val) {
372
tas_priv->cur_prog = val;
373
ret = 1;
374
}
375
376
return ret;
377
}
378
EXPORT_SYMBOL_NS_GPL(tasdevice_program_put, "SND_HDA_SCODEC_TAS2781");
379
380
int tasdevice_config_get(struct snd_kcontrol *kcontrol,
381
struct snd_ctl_elem_value *ucontrol)
382
{
383
struct tasdevice_priv *tas_priv = snd_kcontrol_chip(kcontrol);
384
385
ucontrol->value.integer.value[0] = tas_priv->cur_conf;
386
387
dev_dbg(tas_priv->dev, "%s: kcontrol %s: %d\n", __func__,
388
kcontrol->id.name, tas_priv->cur_conf);
389
390
return 0;
391
}
392
EXPORT_SYMBOL_NS_GPL(tasdevice_config_get, "SND_HDA_SCODEC_TAS2781");
393
394
int tasdevice_config_put(struct snd_kcontrol *kcontrol,
395
struct snd_ctl_elem_value *ucontrol)
396
{
397
struct tasdevice_priv *tas_priv = snd_kcontrol_chip(kcontrol);
398
struct tasdevice_fw *tas_fw = tas_priv->fmw;
399
int nr_config = ucontrol->value.integer.value[0];
400
int max = tas_fw->nr_configurations - 1;
401
int val, ret = 0;
402
403
val = clamp(nr_config, 0, max);
404
405
guard(mutex)(&tas_priv->codec_lock);
406
407
dev_dbg(tas_priv->dev, "%s: kcontrol %s: %d -> %d\n", __func__,
408
kcontrol->id.name, tas_priv->cur_conf, val);
409
410
if (tas_priv->cur_conf != val) {
411
tas_priv->cur_conf = val;
412
ret = 1;
413
}
414
415
return ret;
416
}
417
EXPORT_SYMBOL_NS_GPL(tasdevice_config_put, "SND_HDA_SCODEC_TAS2781");
418
419
MODULE_DESCRIPTION("TAS2781 HDA Driver");
420
MODULE_LICENSE("GPL");
421
MODULE_AUTHOR("Shenghao Ding, TI, <[email protected]>");
422
423