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_BASIC_MIN 0x14600
|
||||||
#define PPC3_VERSION_TAS2781_ALPHA_MIN 0x4a00
|
#define PPC3_VERSION_TAS2781_ALPHA_MIN 0x4a00
|
||||||
#define PPC3_VERSION_TAS2781_BETA_MIN 0x19400
|
#define PPC3_VERSION_TAS2781_BETA_MIN 0x19400
|
||||||
|
#define PPC3_VERSION_TAS5825_BASE 0x114200
|
||||||
#define TASDEVICE_DEVICE_SUM 8
|
#define TASDEVICE_DEVICE_SUM 8
|
||||||
#define TASDEVICE_CONFIG_SUM 64
|
#define TASDEVICE_CONFIG_SUM 64
|
||||||
|
|
||||||
@@ -53,6 +54,8 @@ enum tasdevice_dsp_dev_idx {
|
|||||||
TASDEVICE_DSP_TAS_2781_DUAL_MONO,
|
TASDEVICE_DSP_TAS_2781_DUAL_MONO,
|
||||||
TASDEVICE_DSP_TAS_2781_21,
|
TASDEVICE_DSP_TAS_2781_21,
|
||||||
TASDEVICE_DSP_TAS_2781_QUAD,
|
TASDEVICE_DSP_TAS_2781_QUAD,
|
||||||
|
TASDEVICE_DSP_TAS_5825_MONO,
|
||||||
|
TASDEVICE_DSP_TAS_5825_DUAL,
|
||||||
TASDEVICE_DSP_TAS_MAX_DEVICE
|
TASDEVICE_DSP_TAS_MAX_DEVICE
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -49,9 +49,9 @@
|
|||||||
#define TASDEVICE_REG(book, page, reg) (((book * 256 * 128) + \
|
#define TASDEVICE_REG(book, page, reg) (((book * 256 * 128) + \
|
||||||
(page * 128)) + reg)
|
(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 TASDEVICE_REG(0x0, 0x0, 0x01)
|
||||||
#define TASDEVICE_REG_SWRESET_RESET BIT(0)
|
#define TASDEVICE_REG_SWRESET_RESET (BIT(0) | BIT(4))
|
||||||
|
|
||||||
/* Checksum */
|
/* Checksum */
|
||||||
#define TASDEVICE_CHECKSUM_REG TASDEVICE_REG(0x0, 0x0, 0x7e)
|
#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/tlv.h>
|
||||||
#include <sound/tas2770-tlv.h>
|
#include <sound/tas2770-tlv.h>
|
||||||
#include <sound/tas2781-tlv.h>
|
#include <sound/tas2781-tlv.h>
|
||||||
|
#include <sound/tas5825-tlv.h>
|
||||||
|
|
||||||
#include "hda_local.h"
|
#include "hda_local.h"
|
||||||
#include "hda_auto_parser.h"
|
#include "hda_auto_parser.h"
|
||||||
@@ -50,6 +51,7 @@ enum device_chip_id {
|
|||||||
HDA_TAS2563,
|
HDA_TAS2563,
|
||||||
HDA_TAS2770,
|
HDA_TAS2770,
|
||||||
HDA_TAS2781,
|
HDA_TAS2781,
|
||||||
|
HDA_TAS5825,
|
||||||
HDA_OTHERS
|
HDA_OTHERS
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -272,6 +274,17 @@ static const struct snd_kcontrol_new tas2781_snd_controls[] = {
|
|||||||
tas2781_force_fwload_get, tas2781_force_fwload_put),
|
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 = {
|
static const struct snd_kcontrol_new tasdevice_prof_ctrl = {
|
||||||
.name = "Speaker Profile Id",
|
.name = "Speaker Profile Id",
|
||||||
.iface = SNDRV_CTL_ELEM_IFACE_CARD,
|
.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));
|
ARRAY_SIZE(tas2781_snd_controls));
|
||||||
tasdevice_dspfw_init(context);
|
tasdevice_dspfw_init(context);
|
||||||
break;
|
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:
|
case HDA_TAS2563:
|
||||||
tasdevice_dspfw_init(context);
|
tasdevice_dspfw_init(context);
|
||||||
break;
|
break;
|
||||||
@@ -628,6 +647,7 @@ static int tas2781_hda_i2c_probe(struct i2c_client *clt)
|
|||||||
} else if (strstarts(dev_name(&clt->dev),
|
} else if (strstarts(dev_name(&clt->dev),
|
||||||
"i2c-TXNW2781:00-tas2781-hda.0")) {
|
"i2c-TXNW2781:00-tas2781-hda.0")) {
|
||||||
device_name = "TXNW2781";
|
device_name = "TXNW2781";
|
||||||
|
hda_priv->hda_chip_id = HDA_TAS2781;
|
||||||
hda_priv->save_calibration = tas2781_save_calibration;
|
hda_priv->save_calibration = tas2781_save_calibration;
|
||||||
tas_hda->priv->global_addr = TAS2781_GLOBAL_ADDR;
|
tas_hda->priv->global_addr = TAS2781_GLOBAL_ADDR;
|
||||||
} else if (strstr(dev_name(&clt->dev), "INT8866")) {
|
} 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->hda_chip_id = HDA_TAS2563;
|
||||||
hda_priv->save_calibration = tas2563_save_calibration;
|
hda_priv->save_calibration = tas2563_save_calibration;
|
||||||
tas_hda->priv->global_addr = TAS2563_GLOBAL_ADDR;
|
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 {
|
} else {
|
||||||
return -ENODEV;
|
return -ENODEV;
|
||||||
}
|
}
|
||||||
@@ -775,6 +802,7 @@ static const struct acpi_device_id tas2781_acpi_hda_match[] = {
|
|||||||
{"TIAS2781", 0 },
|
{"TIAS2781", 0 },
|
||||||
{"TXNW2770", 0 },
|
{"TXNW2770", 0 },
|
||||||
{"TXNW2781", 0 },
|
{"TXNW2781", 0 },
|
||||||
|
{"TXNW5825", 0 },
|
||||||
{}
|
{}
|
||||||
};
|
};
|
||||||
MODULE_DEVICE_TABLE(acpi, tas2781_acpi_hda_match);
|
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] = {
|
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 */
|
/* fixed m68k compiling issue: mapping table can save code field */
|
||||||
@@ -509,6 +509,56 @@ out:
|
|||||||
return offset;
|
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(
|
static int fw_parse_program_data_kernel(
|
||||||
struct tasdevice_priv *tas_priv, struct tasdevice_fw *tas_fmw,
|
struct tasdevice_priv *tas_priv, struct tasdevice_fw *tas_fmw,
|
||||||
const struct firmware *fmw, int offset)
|
const struct firmware *fmw, int offset)
|
||||||
@@ -1826,7 +1876,8 @@ static void dspbin_type_check(struct tasdevice_priv *tas_priv,
|
|||||||
else
|
else
|
||||||
tas_priv->dspbin_typ = TASDEV_ALPHA;
|
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 =
|
tas_priv->fw_parse_fct_param_address =
|
||||||
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;
|
int rc = 0;
|
||||||
|
|
||||||
if (drv_ver == 0x100) {
|
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 =
|
tas_priv->fw_parse_variable_header =
|
||||||
fw_parse_variable_header_kernel;
|
fw_parse_variable_header_kernel;
|
||||||
tas_priv->fw_parse_program_data =
|
tas_priv->fw_parse_program_data =
|
||||||
|
|||||||
Reference in New Issue
Block a user