File Index
Files and directories
Sign in
FILE

tas2781_hda.c

File preview with syntax highlighting.

linux-6.19.14/sound/hda/codecs/side-codecs/tas2781_hda.c C
  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
 23const 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};
 34EXPORT_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 */
 41static 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
 53static 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	p->is_user_space_calidata = true;
163	cali_data->total_sz = p->ndev * (cali_data->cali_dat_sz_per_dev + 1);
164}
165
166/*
167 * Update the calibration data, including speaker impedance, f0, etc,
168 * into algo. Calibrate data is done by manufacturer in the factory.
169 * The data is used by Algo for calculating the speaker temperature,
170 * speaker membrane excursion and f0 in real time during playback.
171 * Calibration data format in EFI is V2, since 2024.
172 */
173int tas2781_save_calibration(struct tas2781_hda *hda)
174{
175	/*
176	 * GUID was used for data access in BIOS, it was provided by board
177	 * manufactory.
178	 */
179	efi_guid_t efi_guid = tasdev_fct_efi_guid[LENOVO];
180	/*
181	 * Some devices save the calibrated data into L"CALI_DATA",
182	 * and others into L"SmartAmpCalibrationData".
183	 */
184	static efi_char16_t *efi_name[CALIBRATION_DATA_AREA_NUM] = {
185		L"CALI_DATA",
186		L"SmartAmpCalibrationData",
187	};
188	struct tasdevice_priv *p = hda->priv;
189	struct calidata *cali_data = &p->cali_data;
190	unsigned long total_sz = 0;
191	unsigned int attr, size;
192	unsigned char *data;
193	efi_status_t status;
194	int i;
195
196	if (!efi_rt_services_supported(EFI_RT_SUPPORTED_GET_VARIABLE)) {
197		dev_err(p->dev, "%s: NO EFI FOUND!\n", __func__);
198		return -EINVAL;
199	}
200
201	if (hda->catlog_id < LENOVO)
202		efi_guid = tasdev_fct_efi_guid[hda->catlog_id];
203
204	cali_data->cali_dat_sz_per_dev = 20;
205	size = p->ndev * (cali_data->cali_dat_sz_per_dev + 1);
206	for (i = 0; i < CALIBRATION_DATA_AREA_NUM; i++) {
207		/* Get real size of UEFI variable */
208		status = efi.get_variable(efi_name[i], &efi_guid, &attr,
209			&total_sz, NULL);
210		cali_data->total_sz = total_sz > size ? total_sz : size;
211		if (status == EFI_BUFFER_TOO_SMALL) {
212			/* Allocate data buffer of data_size bytes */
213			data = cali_data->data = devm_kzalloc(p->dev,
214				cali_data->total_sz, GFP_KERNEL);
215			if (!data) {
216				status = -ENOMEM;
217				continue;
218			}
219			/* Get variable contents into buffer */
220			status = efi.get_variable(efi_name[i], &efi_guid,
221				&attr, &cali_data->total_sz, data);
222		}
223		/* Check whether get the calibrated data */
224		if (status == EFI_SUCCESS)
225			break;
226	}
227
228	if (status != EFI_SUCCESS) {
229		cali_data->total_sz = 0;
230		return status;
231	}
232
233	tas2781_apply_calib(p);
234
235	return 0;
236}
237EXPORT_SYMBOL_NS_GPL(tas2781_save_calibration, "SND_HDA_SCODEC_TAS2781");
238
239void tas2781_hda_remove(struct device *dev,
240	const struct component_ops *ops)
241{
242	struct tas2781_hda *tas_hda = dev_get_drvdata(dev);
243
244	component_del(tas_hda->dev, ops);
245
246	pm_runtime_get_sync(tas_hda->dev);
247	pm_runtime_disable(tas_hda->dev);
248
249	pm_runtime_put_noidle(tas_hda->dev);
250
251	tasdevice_remove(tas_hda->priv);
252}
253EXPORT_SYMBOL_NS_GPL(tas2781_hda_remove, "SND_HDA_SCODEC_TAS2781");
254
255int tasdevice_info_profile(struct snd_kcontrol *kcontrol,
256			struct snd_ctl_elem_info *uinfo)
257{
258	struct tasdevice_priv *tas_priv = snd_kcontrol_chip(kcontrol);
259
260	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
261	uinfo->count = 1;
262	uinfo->value.integer.min = 0;
263	uinfo->value.integer.max = tas_priv->rcabin.ncfgs - 1;
264
265	return 0;
266}
267EXPORT_SYMBOL_NS_GPL(tasdevice_info_profile, "SND_HDA_SCODEC_TAS2781");
268
269int tasdevice_info_programs(struct snd_kcontrol *kcontrol,
270				   struct snd_ctl_elem_info *uinfo)
271{
272	struct tasdevice_priv *tas_priv = snd_kcontrol_chip(kcontrol);
273
274	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
275	uinfo->count = 1;
276	uinfo->value.integer.min = 0;
277	uinfo->value.integer.max = tas_priv->fmw->nr_programs - 1;
278
279	return 0;
280}
281EXPORT_SYMBOL_NS_GPL(tasdevice_info_programs, "SND_HDA_SCODEC_TAS2781");
282
283int tasdevice_info_config(struct snd_kcontrol *kcontrol,
284	struct snd_ctl_elem_info *uinfo)
285{
286	struct tasdevice_priv *tas_priv = snd_kcontrol_chip(kcontrol);
287	struct tasdevice_fw *tas_fw = tas_priv->fmw;
288
289	uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
290	uinfo->count = 1;
291	uinfo->value.integer.min = 0;
292	uinfo->value.integer.max = tas_fw->nr_configurations - 1;
293
294	return 0;
295}
296EXPORT_SYMBOL_NS_GPL(tasdevice_info_config, "SND_HDA_SCODEC_TAS2781");
297
298int tasdevice_get_profile_id(struct snd_kcontrol *kcontrol,
299			struct snd_ctl_elem_value *ucontrol)
300{
301	struct tasdevice_priv *tas_priv = snd_kcontrol_chip(kcontrol);
302
303	ucontrol->value.integer.value[0] = tas_priv->rcabin.profile_cfg_id;
304
305	dev_dbg(tas_priv->dev, "%s: kcontrol %s: %d\n", __func__,
306		kcontrol->id.name, tas_priv->rcabin.profile_cfg_id);
307
308	return 0;
309}
310EXPORT_SYMBOL_NS_GPL(tasdevice_get_profile_id, "SND_HDA_SCODEC_TAS2781");
311
312int tasdevice_set_profile_id(struct snd_kcontrol *kcontrol,
313		struct snd_ctl_elem_value *ucontrol)
314{
315	struct tasdevice_priv *tas_priv = snd_kcontrol_chip(kcontrol);
316	int profile_id = ucontrol->value.integer.value[0];
317	int max = tas_priv->rcabin.ncfgs - 1;
318	int val, ret = 0;
319
320	val = clamp(profile_id, 0, max);
321
322	guard(mutex)(&tas_priv->codec_lock);
323
324	dev_dbg(tas_priv->dev, "%s: kcontrol %s: %d -> %d\n", __func__,
325		kcontrol->id.name, tas_priv->rcabin.profile_cfg_id, val);
326
327	if (tas_priv->rcabin.profile_cfg_id != val) {
328		tas_priv->rcabin.profile_cfg_id = val;
329		ret = 1;
330	}
331
332	return ret;
333}
334EXPORT_SYMBOL_NS_GPL(tasdevice_set_profile_id, "SND_HDA_SCODEC_TAS2781");
335
336int tasdevice_program_get(struct snd_kcontrol *kcontrol,
337	struct snd_ctl_elem_value *ucontrol)
338{
339	struct tasdevice_priv *tas_priv = snd_kcontrol_chip(kcontrol);
340
341	ucontrol->value.integer.value[0] = tas_priv->cur_prog;
342
343	dev_dbg(tas_priv->dev, "%s: kcontrol %s: %d\n", __func__,
344		kcontrol->id.name, tas_priv->cur_prog);
345
346	return 0;
347}
348EXPORT_SYMBOL_NS_GPL(tasdevice_program_get, "SND_HDA_SCODEC_TAS2781");
349
350int tasdevice_program_put(struct snd_kcontrol *kcontrol,
351	struct snd_ctl_elem_value *ucontrol)
352{
353	struct tasdevice_priv *tas_priv = snd_kcontrol_chip(kcontrol);
354	struct tasdevice_fw *tas_fw = tas_priv->fmw;
355	int nr_program = ucontrol->value.integer.value[0];
356	int max = tas_fw->nr_programs - 1;
357	int val, ret = 0;
358
359	val = clamp(nr_program, 0, max);
360
361	guard(mutex)(&tas_priv->codec_lock);
362
363	dev_dbg(tas_priv->dev, "%s: kcontrol %s: %d -> %d\n", __func__,
364		kcontrol->id.name, tas_priv->cur_prog, val);
365
366	if (tas_priv->cur_prog != val) {
367		tas_priv->cur_prog = val;
368		ret = 1;
369	}
370
371	return ret;
372}
373EXPORT_SYMBOL_NS_GPL(tasdevice_program_put, "SND_HDA_SCODEC_TAS2781");
374
375int tasdevice_config_get(struct snd_kcontrol *kcontrol,
376	struct snd_ctl_elem_value *ucontrol)
377{
378	struct tasdevice_priv *tas_priv = snd_kcontrol_chip(kcontrol);
379
380	ucontrol->value.integer.value[0] = tas_priv->cur_conf;
381
382	dev_dbg(tas_priv->dev, "%s: kcontrol %s: %d\n", __func__,
383		kcontrol->id.name, tas_priv->cur_conf);
384
385	return 0;
386}
387EXPORT_SYMBOL_NS_GPL(tasdevice_config_get, "SND_HDA_SCODEC_TAS2781");
388
389int tasdevice_config_put(struct snd_kcontrol *kcontrol,
390	struct snd_ctl_elem_value *ucontrol)
391{
392	struct tasdevice_priv *tas_priv = snd_kcontrol_chip(kcontrol);
393	struct tasdevice_fw *tas_fw = tas_priv->fmw;
394	int nr_config = ucontrol->value.integer.value[0];
395	int max = tas_fw->nr_configurations - 1;
396	int val, ret = 0;
397
398	val = clamp(nr_config, 0, max);
399
400	guard(mutex)(&tas_priv->codec_lock);
401
402	dev_dbg(tas_priv->dev, "%s: kcontrol %s: %d -> %d\n", __func__,
403		kcontrol->id.name, tas_priv->cur_conf, val);
404
405	if (tas_priv->cur_conf != val) {
406		tas_priv->cur_conf = val;
407		ret = 1;
408	}
409
410	return ret;
411}
412EXPORT_SYMBOL_NS_GPL(tasdevice_config_put, "SND_HDA_SCODEC_TAS2781");
413
414MODULE_DESCRIPTION("TAS2781 HDA Driver");
415MODULE_LICENSE("GPL");
416MODULE_AUTHOR("Shenghao Ding, TI, <shenghao-ding@ti.com>");
~/ Read-only file preview.