Unverified Commit c24a62be authored by Steffen Aschbacher's avatar Steffen Aschbacher Committed by Mark Brown
Browse files

ASoC: codecs: tas5720: add support for TAS5720A-Q1 (automotive) variant



This change adds support the TAS5720A-Q1 audio codec, in the same driver as
tas5720.

Functionally, this driver is pretty similar to it's TAS5720x variant.

The first 3 registers are the same, so the main control and device
identification can happen with these registers.

The next registers differ.
This variant offers control (in the registers) for 2 speakers, which is
implemented here (in a basic manner).

Signed-off-by: default avatarSteffen Aschbacher <steffen.aschbacher@stihl.de>
Signed-off-by: default avatarAlexandru Ardelean <alex@shruggie.ro>
Link: https://lore.kernel.org/r/20230128082744.41849-2-alex@shruggie.ro


Signed-off-by: default avatarMark Brown <broonie@kernel.org>
parent 879142be
Loading
Loading
Loading
Loading
+92 −12
Original line number Diff line number Diff line
@@ -30,6 +30,7 @@

enum tas572x_type {
	TAS5720,
	TAS5720A_Q1,
	TAS5722,
};

@@ -166,7 +167,14 @@ static int tas5720_set_dai_tdm_slot(struct snd_soc_dai *dai,
		return -EINVAL;
	}

	/* Enable manual TDM slot selection (instead of I2C ID based) */
	/*
	 * Enable manual TDM slot selection (instead of I2C ID based).
	 * This is not applicable to TAS5720A-Q1.
	 */
	switch (tas5720->devtype) {
	case TAS5720A_Q1:
		break;
	default:
		ret = snd_soc_component_update_bits(component, TAS5720_DIGITAL_CTRL1_REG,
					  TAS5720_TDM_CFG_SRC, TAS5720_TDM_CFG_SRC);
		if (ret < 0)
@@ -177,6 +185,8 @@ static int tas5720_set_dai_tdm_slot(struct snd_soc_dai *dai,
					  TAS5720_TDM_SLOT_SEL_MASK, first_slot);
		if (ret < 0)
			goto error_snd_soc_component_update_bits;
		break;
	}

	/* Configure TDM slot width. This is only applicable to TAS5722. */
	switch (tas5720->devtype) {
@@ -201,10 +211,22 @@ static int tas5720_set_dai_tdm_slot(struct snd_soc_dai *dai,

static int tas5720_mute_soc_component(struct snd_soc_component *component, int mute)
{
	struct tas5720_data *tas5720 = snd_soc_component_get_drvdata(component);
	unsigned int reg, mask;
	int ret;

	ret = snd_soc_component_update_bits(component, TAS5720_DIGITAL_CTRL2_REG,
				  TAS5720_MUTE, mute ? TAS5720_MUTE : 0);
	switch (tas5720->devtype) {
	case TAS5720A_Q1:
		reg = TAS5720_Q1_VOLUME_CTRL_CFG_REG;
		mask = TAS5720_Q1_MUTE;
		break;
	default:
		reg = TAS5720_DIGITAL_CTRL2_REG;
		mask = TAS5720_MUTE;
		break;
	}

	ret = snd_soc_component_update_bits(component, reg, mask, mute ? mask : 0);
	if (ret < 0) {
		dev_err(component->dev, "error (un-)muting device: %d\n", ret);
		return ret;
@@ -309,6 +331,9 @@ static int tas5720_codec_probe(struct snd_soc_component *component)
	case TAS5720:
		expected_device_id = TAS5720_DEVICE_ID;
		break;
	case TAS5720A_Q1:
		expected_device_id = TAS5720A_Q1_DEVICE_ID;
		break;
	case TAS5722:
		expected_device_id = TAS5722_DEVICE_ID;
		break;
@@ -474,6 +499,15 @@ static const struct regmap_config tas5720_regmap_config = {
	.volatile_reg = tas5720_is_volatile_reg,
};

static const struct regmap_config tas5720a_q1_regmap_config = {
	.reg_bits = 8,
	.val_bits = 8,

	.max_register = TAS5720_MAX_REG,
	.cache_type = REGCACHE_RBTREE,
	.volatile_reg = tas5720_is_volatile_reg,
};

static const struct regmap_config tas5722_regmap_config = {
	.reg_bits = 8,
	.val_bits = 8,
@@ -494,6 +528,16 @@ static const DECLARE_TLV_DB_RANGE(dac_analog_tlv,
	0x3, 0x3, TLV_DB_SCALE_ITEM(2630, 0, 0),
);

/*
 * DAC analog gain for TAS5720A-Q1. There are three discrete values to select from, ranging
 * from 19.2 dB to 25.0dB.
 */
static const DECLARE_TLV_DB_RANGE(dac_analog_tlv_a_q1,
	0x0, 0x0, TLV_DB_SCALE_ITEM(1920, 0, 0),
	0x1, 0x1, TLV_DB_SCALE_ITEM(2260, 0, 0),
	0x2, 0x2, TLV_DB_SCALE_ITEM(2500, 0, 0),
);

/*
 * DAC digital volumes. From -103.5 to 24 dB in 0.5 dB or 0.25 dB steps
 * depending on the device. Note that setting the gain below -100 dB
@@ -540,6 +584,15 @@ static const struct snd_kcontrol_new tas5720_snd_controls[] = {
		       TAS5720_ANALOG_GAIN_SHIFT, 3, 0, dac_analog_tlv),
};

static const struct snd_kcontrol_new tas5720a_q1_snd_controls[] = {
	SOC_DOUBLE_R_TLV("Speaker Driver Playback Volume",
				TAS5720_Q1_VOLUME_CTRL_LEFT_REG,
				TAS5720_Q1_VOLUME_CTRL_RIGHT_REG,
				0, 0xff, 0, tas5720_dac_tlv),
	SOC_SINGLE_TLV("Speaker Driver Analog Gain", TAS5720_ANALOG_CTRL_REG,
				TAS5720_ANALOG_GAIN_SHIFT, 3, 0, dac_analog_tlv_a_q1),
};

static const struct snd_kcontrol_new tas5722_snd_controls[] = {
	SOC_SINGLE_EXT_TLV("Speaker Driver Playback Volume",
			   0, 0, 511, 0,
@@ -577,6 +630,22 @@ static const struct snd_soc_component_driver soc_component_dev_tas5720 = {
	.endianness		= 1,
};

static const struct snd_soc_component_driver soc_component_dev_tas5720_a_q1 = {
	.probe			= tas5720_codec_probe,
	.remove			= tas5720_codec_remove,
	.suspend		= tas5720_suspend,
	.resume			= tas5720_resume,
	.controls		= tas5720a_q1_snd_controls,
	.num_controls		= ARRAY_SIZE(tas5720a_q1_snd_controls),
	.dapm_widgets		= tas5720_dapm_widgets,
	.num_dapm_widgets	= ARRAY_SIZE(tas5720_dapm_widgets),
	.dapm_routes		= tas5720_audio_map,
	.num_dapm_routes	= ARRAY_SIZE(tas5720_audio_map),
	.idle_bias_on		= 1,
	.use_pmdown_time	= 1,
	.endianness		= 1,
};

static const struct snd_soc_component_driver soc_component_dev_tas5722 = {
	.probe = tas5720_codec_probe,
	.remove = tas5720_codec_remove,
@@ -636,6 +705,7 @@ static struct snd_soc_dai_driver tas5720_dai[] = {

static const struct i2c_device_id tas5720_id[] = {
	{ "tas5720", TAS5720 },
	{ "tas5720a-q1", TAS5720A_Q1 },
	{ "tas5722", TAS5722 },
	{ }
};
@@ -662,6 +732,9 @@ static int tas5720_probe(struct i2c_client *client)
	case TAS5720:
		regmap_config = &tas5720_regmap_config;
		break;
	case TAS5720A_Q1:
		regmap_config = &tas5720a_q1_regmap_config;
		break;
	case TAS5722:
		regmap_config = &tas5722_regmap_config;
		break;
@@ -695,6 +768,12 @@ static int tas5720_probe(struct i2c_client *client)
					tas5720_dai,
					ARRAY_SIZE(tas5720_dai));
		break;
	case TAS5720A_Q1:
		ret = devm_snd_soc_register_component(&client->dev,
					&soc_component_dev_tas5720_a_q1,
					tas5720_dai,
					ARRAY_SIZE(tas5720_dai));
		break;
	case TAS5722:
		ret = devm_snd_soc_register_component(&client->dev,
					&soc_component_dev_tas5722,
@@ -716,6 +795,7 @@ static int tas5720_probe(struct i2c_client *client)
#if IS_ENABLED(CONFIG_OF)
static const struct of_device_id tas5720_of_match[] = {
	{ .compatible = "ti,tas5720", },
	{ .compatible = "ti,tas5720a-q1", },
	{ .compatible = "ti,tas5722", },
	{ },
};
+14 −1
Original line number Diff line number Diff line
@@ -10,7 +10,7 @@
#ifndef __TAS5720_H__
#define __TAS5720_H__

/* Register Address Map */
/* Register Address Map - first 3 regs are common for all variants */
#define TAS5720_DEVICE_ID_REG		0x00
#define TAS5720_POWER_CTRL_REG		0x01
#define TAS5720_DIGITAL_CTRL1_REG	0x02
@@ -27,7 +27,13 @@
#define TAS5722_ANALOG_CTRL2_REG	0x14
#define TAS5722_MAX_REG			TAS5722_ANALOG_CTRL2_REG

/* Register Address Map - volume controls for the TAS5720-Q1 variant */
#define TAS5720_Q1_VOLUME_CTRL_CFG_REG		0x03
#define TAS5720_Q1_VOLUME_CTRL_LEFT_REG		0x04
#define TAS5720_Q1_VOLUME_CTRL_RIGHT_REG	0x05

/* TAS5720_DEVICE_ID_REG */
#define TAS5720A_Q1_DEVICE_ID		0x00
#define TAS5720_DEVICE_ID		0x01
#define TAS5722_DEVICE_ID		0x12

@@ -53,6 +59,10 @@
#define TAS5720_MUTE			BIT(4)
#define TAS5720_TDM_SLOT_SEL_MASK	GENMASK(2, 0)

/* TAS5720_Q1_VOLUME_CTRL_CFG_REG */
#define TAS5720_Q1_FADE			BIT(7)
#define TAS5720_Q1_MUTE			GENMASK(1, 0)

/* TAS5720_ANALOG_CTRL_REG */
#define TAS5720_PWM_RATE_6_3_FSYNC	(0x0 << 4)
#define TAS5720_PWM_RATE_8_4_FSYNC	(0x1 << 4)
@@ -70,6 +80,9 @@
#define TAS5720_ANALOG_GAIN_MASK	GENMASK(3, 2)
#define TAS5720_ANALOG_GAIN_SHIFT	(0x2)

/* TAS5720_Q1_ANALOG_CTRL_REG */
#define TAS5720_Q1_CHAN_SEL		BIT(1)

/* TAS5720_FAULT_REG */
#define TAS5720_OC_THRESH_100PCT	(0x0 << 4)
#define TAS5720_OC_THRESH_75PCT		(0x1 << 4)