xref: /linux/sound/pci/hda/tas2781_hda.c (revision d006330be3f782ff3fb7c3ed51e617e01f29a465)
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 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 
tas2781_apply_calib(struct tasdevice_priv * p)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, node_num;
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 		node_num = tmp_val[1];
84 
85 		for (j = 0, k = 0; j < node_num; j++) {
86 			oft = j * 6 + 3;
87 			if (tmp_val[oft] == TASDEV_UEFI_CALI_REG_ADDR_FLG) {
88 				for (i = 0; i < TASDEV_CALIB_N; i++) {
89 					buf = &data[(oft + i + 1) * 4];
90 					cali_reg[i] = TASDEVICE_REG(buf[1],
91 						buf[2], buf[3]);
92 				}
93 			} else {
94 				l = j * (cali_data->cali_dat_sz_per_dev + 1);
95 				if (k >= p->ndev || l > oft * 4) {
96 					dev_err(p->dev, "%s: dev sum error\n",
97 						__func__);
98 					cali_data->total_sz = 0;
99 					return;
100 				}
101 
102 				data[l] = k;
103 				oft++;
104 				for (i = 0; i < TASDEV_CALIB_N * 4; i++)
105 					data[l + i + 1] = data[4 * oft + i];
106 				k++;
107 			}
108 		}
109 	} else {
110 		/*
111 		 * Calibration data is in V1 format.
112 		 * struct cali_data {
113 		 *     char cali_data[20];
114 		 * }
115 		 *
116 		 * struct {
117 		 *     struct cali_data cali_data[4];
118 		 *     int  TimeStamp of Calibration (4 bytes)
119 		 *     int CRC (4 bytes)
120 		 * } ueft;
121 		 */
122 		crc = crc32(~0, data, 84) ^ ~0;
123 		if (crc != tmp_val[21]) {
124 			cali_data->total_sz = 0;
125 			dev_err(p->dev, "%s: V1 CRC error\n", __func__);
126 			return;
127 		}
128 
129 		for (j = p->ndev - 1; j >= 0; j--) {
130 			l = j * (cali_data->cali_dat_sz_per_dev + 1);
131 			for (i = TASDEV_CALIB_N * 4; i > 0 ; i--)
132 				data[l + i] = data[p->index * 5 + i];
133 			data[l+i] = j;
134 		}
135 	}
136 
137 	if (p->dspbin_typ == TASDEV_BASIC) {
138 		r->r0_reg = cali_reg[0];
139 		r->invr0_reg = cali_reg[1];
140 		r->r0_low_reg = cali_reg[2];
141 		r->pow_reg = cali_reg[3];
142 		r->tlimit_reg = cali_reg[4];
143 	}
144 
145 	p->is_user_space_calidata = true;
146 	cali_data->total_sz = p->ndev * (cali_data->cali_dat_sz_per_dev + 1);
147 }
148 
149 /*
150  * Update the calibration data, including speaker impedance, f0, etc,
151  * into algo. Calibrate data is done by manufacturer in the factory.
152  * The data is used by Algo for calculating the speaker temperature,
153  * speaker membrane excursion and f0 in real time during playback.
154  * Calibration data format in EFI is V2, since 2024.
155  */
tas2781_save_calibration(struct tas2781_hda * hda)156 int tas2781_save_calibration(struct tas2781_hda *hda)
157 {
158 	/*
159 	 * GUID was used for data access in BIOS, it was provided by board
160 	 * manufactory.
161 	 */
162 	efi_guid_t efi_guid = tasdev_fct_efi_guid[LENOVO];
163 	static efi_char16_t efi_name[] = TASDEVICE_CALIBRATION_DATA_NAME;
164 	struct tasdevice_priv *p = hda->priv;
165 	struct calidata *cali_data = &p->cali_data;
166 	unsigned long total_sz = 0;
167 	unsigned int attr, size;
168 	unsigned char *data;
169 	efi_status_t status;
170 
171 	if (hda->catlog_id < LENOVO)
172 		efi_guid = tasdev_fct_efi_guid[hda->catlog_id];
173 
174 	cali_data->cali_dat_sz_per_dev = 20;
175 	size = p->ndev * (cali_data->cali_dat_sz_per_dev + 1);
176 	/* Get real size of UEFI variable */
177 	status = efi.get_variable(efi_name, &efi_guid, &attr, &total_sz, NULL);
178 	cali_data->total_sz = total_sz > size ? total_sz : size;
179 	if (status == EFI_BUFFER_TOO_SMALL) {
180 		/* Allocate data buffer of data_size bytes */
181 		data = p->cali_data.data = devm_kzalloc(p->dev,
182 			p->cali_data.total_sz, GFP_KERNEL);
183 		if (!data) {
184 			p->cali_data.total_sz = 0;
185 			return -ENOMEM;
186 		}
187 		/* Get variable contents into buffer */
188 		status = efi.get_variable(efi_name, &efi_guid, &attr,
189 			&p->cali_data.total_sz, data);
190 	}
191 	if (status != EFI_SUCCESS) {
192 		p->cali_data.total_sz = 0;
193 		return status;
194 	}
195 
196 	tas2781_apply_calib(p);
197 
198 	return 0;
199 }
200 EXPORT_SYMBOL_NS_GPL(tas2781_save_calibration, "SND_HDA_SCODEC_TAS2781");
201 
tas2781_hda_remove(struct device * dev,const struct component_ops * ops)202 void tas2781_hda_remove(struct device *dev,
203 	const struct component_ops *ops)
204 {
205 	struct tas2781_hda *tas_hda = dev_get_drvdata(dev);
206 
207 	component_del(tas_hda->dev, ops);
208 
209 	pm_runtime_get_sync(tas_hda->dev);
210 	pm_runtime_disable(tas_hda->dev);
211 
212 	pm_runtime_put_noidle(tas_hda->dev);
213 
214 	tasdevice_remove(tas_hda->priv);
215 }
216 EXPORT_SYMBOL_NS_GPL(tas2781_hda_remove, "SND_HDA_SCODEC_TAS2781");
217 
tasdevice_info_profile(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_info * uinfo)218 int tasdevice_info_profile(struct snd_kcontrol *kcontrol,
219 			struct snd_ctl_elem_info *uinfo)
220 {
221 	struct tasdevice_priv *tas_priv = snd_kcontrol_chip(kcontrol);
222 
223 	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
224 	uinfo->count = 1;
225 	uinfo->value.integer.min = 0;
226 	uinfo->value.integer.max = tas_priv->rcabin.ncfgs - 1;
227 
228 	return 0;
229 }
230 EXPORT_SYMBOL_NS_GPL(tasdevice_info_profile, "SND_HDA_SCODEC_TAS2781");
231 
tasdevice_info_programs(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_info * uinfo)232 int tasdevice_info_programs(struct snd_kcontrol *kcontrol,
233 				   struct snd_ctl_elem_info *uinfo)
234 {
235 	struct tasdevice_priv *tas_priv = snd_kcontrol_chip(kcontrol);
236 
237 	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
238 	uinfo->count = 1;
239 	uinfo->value.integer.min = 0;
240 	uinfo->value.integer.max = tas_priv->fmw->nr_programs - 1;
241 
242 	return 0;
243 }
244 EXPORT_SYMBOL_NS_GPL(tasdevice_info_programs, "SND_HDA_SCODEC_TAS2781");
245 
tasdevice_info_config(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_info * uinfo)246 int tasdevice_info_config(struct snd_kcontrol *kcontrol,
247 	struct snd_ctl_elem_info *uinfo)
248 {
249 	struct tasdevice_priv *tas_priv = snd_kcontrol_chip(kcontrol);
250 	struct tasdevice_fw *tas_fw = tas_priv->fmw;
251 
252 	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
253 	uinfo->count = 1;
254 	uinfo->value.integer.min = 0;
255 	uinfo->value.integer.max = tas_fw->nr_configurations - 1;
256 
257 	return 0;
258 }
259 EXPORT_SYMBOL_NS_GPL(tasdevice_info_config, "SND_HDA_SCODEC_TAS2781");
260 
tasdevice_get_profile_id(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)261 int tasdevice_get_profile_id(struct snd_kcontrol *kcontrol,
262 			struct snd_ctl_elem_value *ucontrol)
263 {
264 	struct tasdevice_priv *tas_priv = snd_kcontrol_chip(kcontrol);
265 
266 	ucontrol->value.integer.value[0] = tas_priv->rcabin.profile_cfg_id;
267 
268 	dev_dbg(tas_priv->dev, "%s: kcontrol %s: %d\n", __func__,
269 		kcontrol->id.name, tas_priv->rcabin.profile_cfg_id);
270 
271 	return 0;
272 }
273 EXPORT_SYMBOL_NS_GPL(tasdevice_get_profile_id, "SND_HDA_SCODEC_TAS2781");
274 
tasdevice_set_profile_id(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)275 int tasdevice_set_profile_id(struct snd_kcontrol *kcontrol,
276 		struct snd_ctl_elem_value *ucontrol)
277 {
278 	struct tasdevice_priv *tas_priv = snd_kcontrol_chip(kcontrol);
279 	int profile_id = ucontrol->value.integer.value[0];
280 	int max = tas_priv->rcabin.ncfgs - 1;
281 	int val, ret = 0;
282 
283 	val = clamp(profile_id, 0, max);
284 
285 	guard(mutex)(&tas_priv->codec_lock);
286 
287 	dev_dbg(tas_priv->dev, "%s: kcontrol %s: %d -> %d\n", __func__,
288 		kcontrol->id.name, tas_priv->rcabin.profile_cfg_id, val);
289 
290 	if (tas_priv->rcabin.profile_cfg_id != val) {
291 		tas_priv->rcabin.profile_cfg_id = val;
292 		ret = 1;
293 	}
294 
295 	return ret;
296 }
297 EXPORT_SYMBOL_NS_GPL(tasdevice_set_profile_id, "SND_HDA_SCODEC_TAS2781");
298 
tasdevice_program_get(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)299 int tasdevice_program_get(struct snd_kcontrol *kcontrol,
300 	struct snd_ctl_elem_value *ucontrol)
301 {
302 	struct tasdevice_priv *tas_priv = snd_kcontrol_chip(kcontrol);
303 
304 	ucontrol->value.integer.value[0] = tas_priv->cur_prog;
305 
306 	dev_dbg(tas_priv->dev, "%s: kcontrol %s: %d\n", __func__,
307 		kcontrol->id.name, tas_priv->cur_prog);
308 
309 	return 0;
310 }
311 EXPORT_SYMBOL_NS_GPL(tasdevice_program_get, "SND_HDA_SCODEC_TAS2781");
312 
tasdevice_program_put(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)313 int tasdevice_program_put(struct snd_kcontrol *kcontrol,
314 	struct snd_ctl_elem_value *ucontrol)
315 {
316 	struct tasdevice_priv *tas_priv = snd_kcontrol_chip(kcontrol);
317 	struct tasdevice_fw *tas_fw = tas_priv->fmw;
318 	int nr_program = ucontrol->value.integer.value[0];
319 	int max = tas_fw->nr_programs - 1;
320 	int val, ret = 0;
321 
322 	val = clamp(nr_program, 0, max);
323 
324 	guard(mutex)(&tas_priv->codec_lock);
325 
326 	dev_dbg(tas_priv->dev, "%s: kcontrol %s: %d -> %d\n", __func__,
327 		kcontrol->id.name, tas_priv->cur_prog, val);
328 
329 	if (tas_priv->cur_prog != val) {
330 		tas_priv->cur_prog = val;
331 		ret = 1;
332 	}
333 
334 	return ret;
335 }
336 EXPORT_SYMBOL_NS_GPL(tasdevice_program_put, "SND_HDA_SCODEC_TAS2781");
337 
tasdevice_config_get(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)338 int tasdevice_config_get(struct snd_kcontrol *kcontrol,
339 	struct snd_ctl_elem_value *ucontrol)
340 {
341 	struct tasdevice_priv *tas_priv = snd_kcontrol_chip(kcontrol);
342 
343 	ucontrol->value.integer.value[0] = tas_priv->cur_conf;
344 
345 	dev_dbg(tas_priv->dev, "%s: kcontrol %s: %d\n", __func__,
346 		kcontrol->id.name, tas_priv->cur_conf);
347 
348 	return 0;
349 }
350 EXPORT_SYMBOL_NS_GPL(tasdevice_config_get, "SND_HDA_SCODEC_TAS2781");
351 
tasdevice_config_put(struct snd_kcontrol * kcontrol,struct snd_ctl_elem_value * ucontrol)352 int tasdevice_config_put(struct snd_kcontrol *kcontrol,
353 	struct snd_ctl_elem_value *ucontrol)
354 {
355 	struct tasdevice_priv *tas_priv = snd_kcontrol_chip(kcontrol);
356 	struct tasdevice_fw *tas_fw = tas_priv->fmw;
357 	int nr_config = ucontrol->value.integer.value[0];
358 	int max = tas_fw->nr_configurations - 1;
359 	int val, ret = 0;
360 
361 	val = clamp(nr_config, 0, max);
362 
363 	guard(mutex)(&tas_priv->codec_lock);
364 
365 	dev_dbg(tas_priv->dev, "%s: kcontrol %s: %d -> %d\n", __func__,
366 		kcontrol->id.name, tas_priv->cur_conf, val);
367 
368 	if (tas_priv->cur_conf != val) {
369 		tas_priv->cur_conf = val;
370 		ret = 1;
371 	}
372 
373 	return ret;
374 }
375 EXPORT_SYMBOL_NS_GPL(tasdevice_config_put, "SND_HDA_SCODEC_TAS2781");
376 
377 MODULE_DESCRIPTION("TAS2781 HDA Driver");
378 MODULE_LICENSE("GPL");
379 MODULE_AUTHOR("Shenghao Ding, TI, <shenghao-ding@ti.com>");
380