mirror of
https://github.com/torvalds/linux.git
synced 2025-12-07 20:06:24 +00:00
ALSA: hda: Add TAS5825 support
Add TAS5825 support in TI's HDA driver. TAS5825 is an on-chip DSP, but no calibration is required, and no global address support smart amplifier devices. Signed-off-by: Baojun Xu <baojun.xu@ti.com> Acked-by: Mark Brown <broonie@kernel.org> Signed-off-by: Takashi Iwai <tiwai@suse.de> Link: https://patch.msgid.link/20250810122358.1575-1-baojun.xu@ti.com
This commit is contained in:
@@ -34,6 +34,7 @@
|
||||
#define PPC3_VERSION_TAS2781_BASIC_MIN 0x14600
|
||||
#define PPC3_VERSION_TAS2781_ALPHA_MIN 0x4a00
|
||||
#define PPC3_VERSION_TAS2781_BETA_MIN 0x19400
|
||||
#define PPC3_VERSION_TAS5825_BASE 0x114200
|
||||
#define TASDEVICE_DEVICE_SUM 8
|
||||
#define TASDEVICE_CONFIG_SUM 64
|
||||
|
||||
@@ -53,6 +54,8 @@ enum tasdevice_dsp_dev_idx {
|
||||
TASDEVICE_DSP_TAS_2781_DUAL_MONO,
|
||||
TASDEVICE_DSP_TAS_2781_21,
|
||||
TASDEVICE_DSP_TAS_2781_QUAD,
|
||||
TASDEVICE_DSP_TAS_5825_MONO,
|
||||
TASDEVICE_DSP_TAS_5825_DUAL,
|
||||
TASDEVICE_DSP_TAS_MAX_DEVICE
|
||||
};
|
||||
|
||||
|
||||
@@ -49,9 +49,9 @@
|
||||
#define TASDEVICE_REG(book, page, reg) (((book * 256 * 128) + \
|
||||
(page * 128)) + reg)
|
||||
|
||||
/* Software Reset */
|
||||
/* Software Reset, compatble with new device (TAS5825). */
|
||||
#define TASDEVICE_REG_SWRESET TASDEVICE_REG(0x0, 0x0, 0x01)
|
||||
#define TASDEVICE_REG_SWRESET_RESET BIT(0)
|
||||
#define TASDEVICE_REG_SWRESET_RESET (BIT(0) | BIT(4))
|
||||
|
||||
/* Checksum */
|
||||
#define TASDEVICE_CHECKSUM_REG TASDEVICE_REG(0x0, 0x0, 0x7e)
|
||||
|
||||
24
include/sound/tas5825-tlv.h
Normal file
24
include/sound/tas5825-tlv.h
Normal file
@@ -0,0 +1,24 @@
|
||||
/* SPDX-License-Identifier: GPL-2.0 */
|
||||
//
|
||||
// ALSA SoC Texas Instruments TAS5825 Audio Smart Amplifier
|
||||
//
|
||||
// Copyright (C) 2025 Texas Instruments Incorporated
|
||||
// https://www.ti.com
|
||||
//
|
||||
// The TAS5825 hda driver implements for one or two TAS5825 chips.
|
||||
//
|
||||
// Author: Baojun Xu <baojun.xu@ti.com>
|
||||
//
|
||||
|
||||
#ifndef __TAS5825_TLV_H__
|
||||
#define __TAS5825_TLV_H__
|
||||
|
||||
#define TAS5825_DVC_LEVEL TASDEVICE_REG(0x0, 0x0, 0x4c)
|
||||
#define TAS5825_AMP_LEVEL TASDEVICE_REG(0x0, 0x0, 0x54)
|
||||
|
||||
static const __maybe_unused DECLARE_TLV_DB_SCALE(
|
||||
tas5825_dvc_tlv, -10300, 50, 0);
|
||||
static const __maybe_unused DECLARE_TLV_DB_SCALE(
|
||||
tas5825_amp_tlv, -1550, 50, 0);
|
||||
|
||||
#endif
|
||||
@@ -26,6 +26,7 @@
|
||||
#include <sound/tlv.h>
|
||||
#include <sound/tas2770-tlv.h>
|
||||
#include <sound/tas2781-tlv.h>
|
||||
#include <sound/tas5825-tlv.h>
|
||||
|
||||
#include "hda_local.h"
|
||||
#include "hda_auto_parser.h"
|
||||
@@ -50,6 +51,7 @@ enum device_chip_id {
|
||||
HDA_TAS2563,
|
||||
HDA_TAS2770,
|
||||
HDA_TAS2781,
|
||||
HDA_TAS5825,
|
||||
HDA_OTHERS
|
||||
};
|
||||
|
||||
@@ -272,6 +274,17 @@ static const struct snd_kcontrol_new tas2781_snd_controls[] = {
|
||||
tas2781_force_fwload_get, tas2781_force_fwload_put),
|
||||
};
|
||||
|
||||
static const struct snd_kcontrol_new tas5825_snd_controls[] = {
|
||||
ACARD_SINGLE_RANGE_EXT_TLV("Speaker Analog Volume", TAS5825_AMP_LEVEL,
|
||||
0, 0, 31, 1, tas2781_amp_getvol,
|
||||
tas2781_amp_putvol, tas5825_amp_tlv),
|
||||
ACARD_SINGLE_RANGE_EXT_TLV("Speaker Digital Volume", TAS5825_DVC_LEVEL,
|
||||
0, 0, 254, 1, tas2781_amp_getvol,
|
||||
tas2781_amp_putvol, tas5825_dvc_tlv),
|
||||
ACARD_SINGLE_BOOL_EXT("Speaker Force Firmware Load", 0,
|
||||
tas2781_force_fwload_get, tas2781_force_fwload_put),
|
||||
};
|
||||
|
||||
static const struct snd_kcontrol_new tasdevice_prof_ctrl = {
|
||||
.name = "Speaker Profile Id",
|
||||
.iface = SNDRV_CTL_ELEM_IFACE_CARD,
|
||||
@@ -501,6 +514,12 @@ static void tasdev_fw_ready(const struct firmware *fmw, void *context)
|
||||
ARRAY_SIZE(tas2781_snd_controls));
|
||||
tasdevice_dspfw_init(context);
|
||||
break;
|
||||
case HDA_TAS5825:
|
||||
tasdev_add_kcontrols(tas_priv, hda_priv->snd_ctls, codec,
|
||||
&tas5825_snd_controls[0],
|
||||
ARRAY_SIZE(tas5825_snd_controls));
|
||||
tasdevice_dspfw_init(context);
|
||||
break;
|
||||
case HDA_TAS2563:
|
||||
tasdevice_dspfw_init(context);
|
||||
break;
|
||||
@@ -628,6 +647,7 @@ static int tas2781_hda_i2c_probe(struct i2c_client *clt)
|
||||
} else if (strstarts(dev_name(&clt->dev),
|
||||
"i2c-TXNW2781:00-tas2781-hda.0")) {
|
||||
device_name = "TXNW2781";
|
||||
hda_priv->hda_chip_id = HDA_TAS2781;
|
||||
hda_priv->save_calibration = tas2781_save_calibration;
|
||||
tas_hda->priv->global_addr = TAS2781_GLOBAL_ADDR;
|
||||
} else if (strstr(dev_name(&clt->dev), "INT8866")) {
|
||||
@@ -639,6 +659,13 @@ static int tas2781_hda_i2c_probe(struct i2c_client *clt)
|
||||
hda_priv->hda_chip_id = HDA_TAS2563;
|
||||
hda_priv->save_calibration = tas2563_save_calibration;
|
||||
tas_hda->priv->global_addr = TAS2563_GLOBAL_ADDR;
|
||||
} else if (strstarts(dev_name(&clt->dev), "i2c-TXNW5825")) {
|
||||
/*
|
||||
* TAS5825, integrated on-chip DSP without
|
||||
* global I2C address and calibration supported.
|
||||
*/
|
||||
device_name = "TXNW5825";
|
||||
hda_priv->hda_chip_id = HDA_TAS5825;
|
||||
} else {
|
||||
return -ENODEV;
|
||||
}
|
||||
@@ -775,6 +802,7 @@ static const struct acpi_device_id tas2781_acpi_hda_match[] = {
|
||||
{"TIAS2781", 0 },
|
||||
{"TXNW2770", 0 },
|
||||
{"TXNW2781", 0 },
|
||||
{"TXNW5825", 0 },
|
||||
{}
|
||||
};
|
||||
MODULE_DEVICE_TABLE(acpi, tas2781_acpi_hda_match);
|
||||
|
||||
@@ -91,7 +91,7 @@ struct blktyp_devidx_map {
|
||||
};
|
||||
|
||||
static const char deviceNumber[TASDEVICE_DSP_TAS_MAX_DEVICE] = {
|
||||
1, 2, 1, 2, 1, 1, 0, 2, 4, 3, 1, 2, 3, 4
|
||||
1, 2, 1, 2, 1, 1, 0, 2, 4, 3, 1, 2, 3, 4, 1, 2
|
||||
};
|
||||
|
||||
/* fixed m68k compiling issue: mapping table can save code field */
|
||||
@@ -509,6 +509,56 @@ out:
|
||||
return offset;
|
||||
}
|
||||
|
||||
static int fw_parse_tas5825_program_data_kernel(
|
||||
struct tasdevice_priv *tas_priv, struct tasdevice_fw *tas_fmw,
|
||||
const struct firmware *fmw, int offset)
|
||||
{
|
||||
struct tasdevice_prog *program;
|
||||
unsigned int i;
|
||||
|
||||
for (i = 0; i < tas_fmw->nr_programs; i++) {
|
||||
program = &(tas_fmw->programs[i]);
|
||||
if (offset + 72 > fmw->size) {
|
||||
dev_err(tas_priv->dev, "%s: mpName error\n", __func__);
|
||||
return -EINVAL;
|
||||
}
|
||||
/* Skip 65 unused byts*/
|
||||
offset += 65;
|
||||
offset = fw_parse_data_kernel(tas_fmw, &(program->dev_data),
|
||||
fmw, offset);
|
||||
if (offset < 0)
|
||||
return offset;
|
||||
}
|
||||
|
||||
return offset;
|
||||
}
|
||||
|
||||
static int fw_parse_tas5825_configuration_data_kernel(
|
||||
struct tasdevice_priv *tas_priv,
|
||||
struct tasdevice_fw *tas_fmw, const struct firmware *fmw, int offset)
|
||||
{
|
||||
const unsigned char *data = fmw->data;
|
||||
struct tasdevice_config *config;
|
||||
unsigned int i;
|
||||
|
||||
for (i = 0; i < tas_fmw->nr_configurations; i++) {
|
||||
config = &(tas_fmw->configs[i]);
|
||||
if (offset + 80 > fmw->size) {
|
||||
dev_err(tas_priv->dev, "%s: mpName error\n", __func__);
|
||||
return -EINVAL;
|
||||
}
|
||||
memcpy(config->name, &data[offset], 64);
|
||||
/* Skip extra 8 bytes*/
|
||||
offset += 72;
|
||||
offset = fw_parse_data_kernel(tas_fmw, &(config->dev_data),
|
||||
fmw, offset);
|
||||
if (offset < 0)
|
||||
return offset;
|
||||
}
|
||||
|
||||
return offset;
|
||||
}
|
||||
|
||||
static int fw_parse_program_data_kernel(
|
||||
struct tasdevice_priv *tas_priv, struct tasdevice_fw *tas_fmw,
|
||||
const struct firmware *fmw, int offset)
|
||||
@@ -1826,7 +1876,8 @@ static void dspbin_type_check(struct tasdevice_priv *tas_priv,
|
||||
else
|
||||
tas_priv->dspbin_typ = TASDEV_ALPHA;
|
||||
}
|
||||
if (tas_priv->dspbin_typ != TASDEV_BASIC)
|
||||
if ((tas_priv->dspbin_typ != TASDEV_BASIC) &&
|
||||
(ppcver < PPC3_VERSION_TAS5825_BASE))
|
||||
tas_priv->fw_parse_fct_param_address =
|
||||
fw_parse_fct_param_address;
|
||||
}
|
||||
@@ -1837,7 +1888,17 @@ static int dspfw_default_callback(struct tasdevice_priv *tas_priv,
|
||||
int rc = 0;
|
||||
|
||||
if (drv_ver == 0x100) {
|
||||
if (ppcver >= PPC3_VERSION_BASE) {
|
||||
if (ppcver >= PPC3_VERSION_TAS5825_BASE) {
|
||||
tas_priv->fw_parse_variable_header =
|
||||
fw_parse_variable_header_kernel;
|
||||
tas_priv->fw_parse_program_data =
|
||||
fw_parse_tas5825_program_data_kernel;
|
||||
tas_priv->fw_parse_configuration_data =
|
||||
fw_parse_tas5825_configuration_data_kernel;
|
||||
tas_priv->tasdevice_load_block =
|
||||
tasdevice_load_block_kernel;
|
||||
dspbin_type_check(tas_priv, ppcver);
|
||||
} else if (ppcver >= PPC3_VERSION_BASE) {
|
||||
tas_priv->fw_parse_variable_header =
|
||||
fw_parse_variable_header_kernel;
|
||||
tas_priv->fw_parse_program_data =
|
||||
|
||||
Reference in New Issue
Block a user