xref: /linux/sound/hda/codecs/side-codecs/tas2781_hda.c (revision cac5f2af13459f6258c4857d2e61ea53d0dfd751)
1 // SPDX-License-Identifier: GPL-2.0
2 //
3 // TAS2781 HDA Shared Lib for I2C&SPI driver
4 //
5 // Copyright 2025 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 
tas2781_apply_calib(struct tasdevice_priv * p)36 static void tas2781_apply_calib(struct tasdevice_priv *p)
37 {
38 	struct calidata *cali_data = &p->cali_data;
39 	struct cali_reg *r = &cali_data->cali_reg_array;
40 	unsigned char *data = cali_data->data;
41 	unsigned int *tmp_val = (unsigned int *)data;
42 	unsigned int cali_reg[TASDEV_CALIB_N] = {
43 		TASDEVICE_REG(0, 0x17, 0x74),
44 		TASDEVICE_REG(0, 0x18, 0x0c),
45 		TASDEVICE_REG(0, 0x18, 0x14),
46 		TASDEVICE_REG(0, 0x13, 0x70),
47 		TASDEVICE_REG(0, 0x18, 0x7c),
48 	};
49 	unsigned int crc, oft, node_num;
50 	unsigned char *buf;
51 	int i, j, k, l;
52 
53 	if (tmp_val[0] == 2781) {
54 		/*
55 		 * New features were added in calibrated Data V3:
56 		 *     1. Added calibration registers address define in
57 		 *	    a node, marked as Device id == 0x80.
58 		 * New features were added in calibrated Data V2:
59 		 *     1. Added some the fields to store the link_id and
60 		 *	    uniqie_id for multi-link solutions
61 		 *     2. Support flexible number of devices instead of
62 		 *	    fixed one in V1.
63 		 * Layout of calibrated data V2 in UEFI(total 256 bytes):
64 		 *     ChipID (2781, 4 bytes)
65 		 *     Data-Group-Sum (4 bytes)
66 		 *     TimeStamp of Calibration (4 bytes)
67 		 *     for (i = 0; i < Data-Group-Sum; i++) {
68 		 *	    if (Data type != 0x80) (4 bytes)
69 		 *		 Calibrated Data of Device #i (20 bytes)
70 		 *	    else
71 		 *		 Calibration registers address (5*4 = 20 bytes)
72 		 *		 # V2: No reg addr in data grp section.
73 		 *		 # V3: Normally the last grp is the reg addr.
74 		 *     }
75 		 *     CRC (4 bytes)
76 		 *     Reserved (the rest)
77 		 */
78 		crc = crc32(~0, data, (3 + tmp_val[1] * 6) * 4) ^ ~0;
79 
80 		if (crc != tmp_val[3 + tmp_val[1] * 6]) {
81 			cali_data->total_sz = 0;
82 			dev_err(p->dev, "%s: CRC error\n", __func__);
83 			return;
84 		}
85 		node_num = tmp_val[1];
86 
87 		for (j = 0, k = 0; j < node_num; j++) {
88 			oft = j * 6 + 3;
89 			if (tmp_val[oft] == TASDEV_UEFI_CALI_REG_ADDR_FLG) {
90 				for (i = 0; i < TASDEV_CALIB_N; i++) {
91 					buf = &data[(oft + i + 1) * 4];
92 					cali_reg[i] = TASDEVICE_REG(buf[1],
93 						buf[2], buf[3]);
94 				}
95 			} else {
96 				l = j * (cali_data->cali_dat_sz_per_dev + 1);
97 				if (k >= p->ndev || l > oft * 4) {
98 					dev_err(p->dev, "%s: dev sum error\n",
99 						__func__);
100 					cali_data->total_sz = 0;
101 					return;
102 				}
103 
104 				data[l] = k;
105 				oft++;
106 				for (i = 0; i < TASDEV_CALIB_N * 4; i++)
107 					data[l + i + 1] = data[4 * oft + i];
108 				k++;
109 			}
110 		}
111 	} else {
112 		/*
113 		 * Calibration data is in V1 format.
114 		 * struct cali_data {
115 		 *     char cali_data[20];
116 		 * }
117 		 *
118 		 * struct {
119 		 *     struct cali_data cali_data[4];
120 		 *     int  TimeStamp of Calibration (4 bytes)
121 		 *     int CRC (4 bytes)
122 		 * } ueft;
123 		 */
124 		crc = crc32(~0, data, 84) ^ ~0;
125 		if (crc != tmp_val[21]) {
126 			cali_data->total_sz = 0;
127 			dev_err(p->dev, "%s: V1 CRC error\n", __func__);
128 			return;
129 		}
130 
131 		for (j = p->ndev - 1; j >= 0; j--) {
132 			l = j * (cali_data->cali_dat_sz_per_dev + 1);
133 			for (i = TASDEV_CALIB_N * 4; i > 0 ; i--)
134 				data[l + i] = data[p->index * 5 + i];
135 			data[l+i] = j;
136 		}
137 	}
138 
139 	if (p->dspbin_typ == TASDEV_BASIC) {
140 		r->r0_reg = cali_reg[0];
141 		r->invr0_reg = cali_reg[1];
142 		r->r0_low_reg = cali_reg[2];
143 		r->pow_reg = cali_reg[3];
144 		r->tlimit_reg = cali_reg[4];
145 	}
146 
147 	p->is_user_space_calidata = true;
148 	cali_data->total_sz = p->ndev * (cali_data->cali_dat_sz_per_dev + 1);
149 }
150 
151 /*
152  * Update the calibration data, including speaker impedance, f0, etc,
153  * into algo. Calibrate data is done by manufacturer in the factory.
154  * The data is used by Algo for calculating the speaker temperature,
155  * speaker membrane excursion and f0 in real time during playback.
156  * Calibration data format in EFI is V2, since 2024.
157  */
tas2781_save_calibration(struct tas2781_hda * hda)158 int tas2781_save_calibration(struct tas2781_hda *hda)
159 {
160 	/*
161 	 * GUID was used for data access in BIOS, it was provided by board
162 	 * manufactory.
163 	 */
164 	efi_guid_t efi_guid = tasdev_fct_efi_guid[LENOVO];
165 	/*
166 	 * Some devices save the calibrated data into L"CALI_DATA",
167 	 * and others into L"SmartAmpCalibrationData".
168 	 */
169 	static efi_char16_t *efi_name[CALIBRATION_DATA_AREA_NUM] = {
170 		L"CALI_DATA",
171 		L"SmartAmpCalibrationData",
172 	};
173 	struct tasdevice_priv *p = hda->priv;
174 	struct calidata *cali_data = &p->cali_data;
175 	unsigned long total_sz = 0;
176 	unsigned int attr, size;
177 	unsigned char *data;
178 	efi_status_t status;
179 	int i;
180 
181 	if (hda->catlog_id < LENOVO)
182 		efi_guid = tasdev_fct_efi_guid[hda->catlog_id];
183 
184 	cali_data->cali_dat_sz_per_dev = 20;
185 	size = p->ndev * (cali_data->cali_dat_sz_per_dev + 1);
186 	for (i = 0; i < CALIBRATION_DATA_AREA_NUM; i++) {
187 		/* Get real size of UEFI variable */
188 		status = efi.get_variable(efi_name[i], &efi_guid, &attr,
189 			&total_sz, NULL);
190 		cali_data->total_sz = total_sz > size ? total_sz : size;
191 		if (status == EFI_BUFFER_TOO_SMALL) {
192 			/* Allocate data buffer of data_size bytes */
193 			data = cali_data->data = devm_kzalloc(p->dev,
194 				cali_data->total_sz, GFP_KERNEL);
195 			if (!data) {
196 				status = -ENOMEM;
197 				continue;
198 			}
199 			/* Get variable contents into buffer */
200 			status = efi.get_variable(efi_name[i], &efi_guid,
201 				&attr, &cali_data->total_sz, data);
202 		}
203 		/* Check whether get the calibrated data */
204 		if (status == EFI_SUCCESS)
205 			break;
206 	}
207 
208 	if (status != EFI_SUCCESS) {
209 		cali_data->total_sz = 0;
210 		return status;
211 	}
212 
213 	tas2781_apply_calib(p);
214 
215 	return 0;
216 }
217 EXPORT_SYMBOL_NS_GPL(tas2781_save_calibration, "SND_HDA_SCODEC_TAS2781");
218 
tas2781_hda_remove(struct device * dev,const struct component_ops * ops)219 void tas2781_hda_remove(struct device *dev,
220 	const struct component_ops *ops)
221 {
222 	struct tas2781_hda *tas_hda = dev_get_drvdata(dev);
223 
224 	component_del(tas_hda->dev, ops);
225 
226 	pm_runtime_get_sync(tas_hda->dev);
227 	pm_runtime_disable(tas_hda->dev);
228 
229 	pm_runtime_put_noidle(tas_hda->dev);
230 
231 	tasdevice_remove(tas_hda->priv);
232 }
233 EXPORT_SYMBOL_NS_GPL(tas2781_hda_remove, "SND_HDA_SCODEC_TAS2781");
234 
tasdevice_info_profile(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_info * uinfo)235 int tasdevice_info_profile(struct snd_kcontrol *kcontrol,
236 			struct snd_ctl_elem_info *uinfo)
237 {
238 	struct tasdevice_priv *tas_priv = snd_kcontrol_chip(kcontrol);
239 
240 	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
241 	uinfo->count = 1;
242 	uinfo->value.integer.min = 0;
243 	uinfo->value.integer.max = tas_priv->rcabin.ncfgs - 1;
244 
245 	return 0;
246 }
247 EXPORT_SYMBOL_NS_GPL(tasdevice_info_profile, "SND_HDA_SCODEC_TAS2781");
248 
tasdevice_info_programs(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_info * uinfo)249 int tasdevice_info_programs(struct snd_kcontrol *kcontrol,
250 				   struct snd_ctl_elem_info *uinfo)
251 {
252 	struct tasdevice_priv *tas_priv = snd_kcontrol_chip(kcontrol);
253 
254 	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
255 	uinfo->count = 1;
256 	uinfo->value.integer.min = 0;
257 	uinfo->value.integer.max = tas_priv->fmw->nr_programs - 1;
258 
259 	return 0;
260 }
261 EXPORT_SYMBOL_NS_GPL(tasdevice_info_programs, "SND_HDA_SCODEC_TAS2781");
262 
tasdevice_info_config(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_info * uinfo)263 int tasdevice_info_config(struct snd_kcontrol *kcontrol,
264 	struct snd_ctl_elem_info *uinfo)
265 {
266 	struct tasdevice_priv *tas_priv = snd_kcontrol_chip(kcontrol);
267 	struct tasdevice_fw *tas_fw = tas_priv->fmw;
268 
269 	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
270 	uinfo->count = 1;
271 	uinfo->value.integer.min = 0;
272 	uinfo->value.integer.max = tas_fw->nr_configurations - 1;
273 
274 	return 0;
275 }
276 EXPORT_SYMBOL_NS_GPL(tasdevice_info_config, "SND_HDA_SCODEC_TAS2781");
277 
tasdevice_get_profile_id(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)278 int tasdevice_get_profile_id(struct snd_kcontrol *kcontrol,
279 			struct snd_ctl_elem_value *ucontrol)
280 {
281 	struct tasdevice_priv *tas_priv = snd_kcontrol_chip(kcontrol);
282 
283 	ucontrol->value.integer.value[0] = tas_priv->rcabin.profile_cfg_id;
284 
285 	dev_dbg(tas_priv->dev, "%s: kcontrol %s: %d\n", __func__,
286 		kcontrol->id.name, tas_priv->rcabin.profile_cfg_id);
287 
288 	return 0;
289 }
290 EXPORT_SYMBOL_NS_GPL(tasdevice_get_profile_id, "SND_HDA_SCODEC_TAS2781");
291 
tasdevice_set_profile_id(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)292 int tasdevice_set_profile_id(struct snd_kcontrol *kcontrol,
293 		struct snd_ctl_elem_value *ucontrol)
294 {
295 	struct tasdevice_priv *tas_priv = snd_kcontrol_chip(kcontrol);
296 	int profile_id = ucontrol->value.integer.value[0];
297 	int max = tas_priv->rcabin.ncfgs - 1;
298 	int val, ret = 0;
299 
300 	val = clamp(profile_id, 0, max);
301 
302 	guard(mutex)(&tas_priv->codec_lock);
303 
304 	dev_dbg(tas_priv->dev, "%s: kcontrol %s: %d -> %d\n", __func__,
305 		kcontrol->id.name, tas_priv->rcabin.profile_cfg_id, val);
306 
307 	if (tas_priv->rcabin.profile_cfg_id != val) {
308 		tas_priv->rcabin.profile_cfg_id = val;
309 		ret = 1;
310 	}
311 
312 	return ret;
313 }
314 EXPORT_SYMBOL_NS_GPL(tasdevice_set_profile_id, "SND_HDA_SCODEC_TAS2781");
315 
tasdevice_program_get(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)316 int tasdevice_program_get(struct snd_kcontrol *kcontrol,
317 	struct snd_ctl_elem_value *ucontrol)
318 {
319 	struct tasdevice_priv *tas_priv = snd_kcontrol_chip(kcontrol);
320 
321 	ucontrol->value.integer.value[0] = tas_priv->cur_prog;
322 
323 	dev_dbg(tas_priv->dev, "%s: kcontrol %s: %d\n", __func__,
324 		kcontrol->id.name, tas_priv->cur_prog);
325 
326 	return 0;
327 }
328 EXPORT_SYMBOL_NS_GPL(tasdevice_program_get, "SND_HDA_SCODEC_TAS2781");
329 
tasdevice_program_put(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)330 int tasdevice_program_put(struct snd_kcontrol *kcontrol,
331 	struct snd_ctl_elem_value *ucontrol)
332 {
333 	struct tasdevice_priv *tas_priv = snd_kcontrol_chip(kcontrol);
334 	struct tasdevice_fw *tas_fw = tas_priv->fmw;
335 	int nr_program = ucontrol->value.integer.value[0];
336 	int max = tas_fw->nr_programs - 1;
337 	int val, ret = 0;
338 
339 	val = clamp(nr_program, 0, max);
340 
341 	guard(mutex)(&tas_priv->codec_lock);
342 
343 	dev_dbg(tas_priv->dev, "%s: kcontrol %s: %d -> %d\n", __func__,
344 		kcontrol->id.name, tas_priv->cur_prog, val);
345 
346 	if (tas_priv->cur_prog != val) {
347 		tas_priv->cur_prog = val;
348 		ret = 1;
349 	}
350 
351 	return ret;
352 }
353 EXPORT_SYMBOL_NS_GPL(tasdevice_program_put, "SND_HDA_SCODEC_TAS2781");
354 
tasdevice_config_get(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)355 int tasdevice_config_get(struct snd_kcontrol *kcontrol,
356 	struct snd_ctl_elem_value *ucontrol)
357 {
358 	struct tasdevice_priv *tas_priv = snd_kcontrol_chip(kcontrol);
359 
360 	ucontrol->value.integer.value[0] = tas_priv->cur_conf;
361 
362 	dev_dbg(tas_priv->dev, "%s: kcontrol %s: %d\n", __func__,
363 		kcontrol->id.name, tas_priv->cur_conf);
364 
365 	return 0;
366 }
367 EXPORT_SYMBOL_NS_GPL(tasdevice_config_get, "SND_HDA_SCODEC_TAS2781");
368 
tasdevice_config_put(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)369 int tasdevice_config_put(struct snd_kcontrol *kcontrol,
370 	struct snd_ctl_elem_value *ucontrol)
371 {
372 	struct tasdevice_priv *tas_priv = snd_kcontrol_chip(kcontrol);
373 	struct tasdevice_fw *tas_fw = tas_priv->fmw;
374 	int nr_config = ucontrol->value.integer.value[0];
375 	int max = tas_fw->nr_configurations - 1;
376 	int val, ret = 0;
377 
378 	val = clamp(nr_config, 0, max);
379 
380 	guard(mutex)(&tas_priv->codec_lock);
381 
382 	dev_dbg(tas_priv->dev, "%s: kcontrol %s: %d -> %d\n", __func__,
383 		kcontrol->id.name, tas_priv->cur_conf, val);
384 
385 	if (tas_priv->cur_conf != val) {
386 		tas_priv->cur_conf = val;
387 		ret = 1;
388 	}
389 
390 	return ret;
391 }
392 EXPORT_SYMBOL_NS_GPL(tasdevice_config_put, "SND_HDA_SCODEC_TAS2781");
393 
394 MODULE_DESCRIPTION("TAS2781 HDA Driver");
395 MODULE_LICENSE("GPL");
396 MODULE_AUTHOR("Shenghao Ding, TI, <shenghao-ding@ti.com>");
397