xref: /linux/sound/hda/codecs/side-codecs/tas2781_hda.c (revision 1fd1dc41724319406b0aff221a352a400b0ddfc5)
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 <shenghao-ding@ti.com>
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, <shenghao-ding@ti.com>");
422