[PATCH 1/4] ASoC: codecs: tas5720: split a tas5720_mute_soc_component() function
This is to be re-used in tas5720_mute() (which is part of the dai_ops) and also in the tas5720_fault_check_work() hook.
The benefit here isn't too great (now). It's only when we add support for a new device with a slightly different regmap that this becomes more useful.
Signed-off-by: Alexandru Ardelean alex@shruggie.ro --- sound/soc/codecs/tas5720.c | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-)
diff --git a/sound/soc/codecs/tas5720.c b/sound/soc/codecs/tas5720.c index 3885c0bf0b01..0587c9bb3c4e 100644 --- a/sound/soc/codecs/tas5720.c +++ b/sound/soc/codecs/tas5720.c @@ -199,9 +199,8 @@ static int tas5720_set_dai_tdm_slot(struct snd_soc_dai *dai, return ret; }
-static int tas5720_mute(struct snd_soc_dai *dai, int mute, int direction) +static int tas5720_mute_soc_component(struct snd_soc_component *component, int mute) { - struct snd_soc_component *component = dai->component; int ret;
ret = snd_soc_component_update_bits(component, TAS5720_DIGITAL_CTRL2_REG, @@ -214,6 +213,11 @@ static int tas5720_mute(struct snd_soc_dai *dai, int mute, int direction) return 0; }
+static int tas5720_mute(struct snd_soc_dai *dai, int mute, int direction) +{ + return tas5720_mute_soc_component(dai->component, mute); +} + static void tas5720_fault_check_work(struct work_struct *work) { struct tas5720_data *tas5720 = container_of(work, struct tas5720_data, @@ -318,8 +322,7 @@ static int tas5720_codec_probe(struct snd_soc_component *component) expected_device_id, device_id);
/* Set device to mute */ - ret = snd_soc_component_update_bits(component, TAS5720_DIGITAL_CTRL2_REG, - TAS5720_MUTE, TAS5720_MUTE); + ret = tas5720_mute_soc_component(component, 1); if (ret < 0) goto error_snd_soc_component_update_bits;
From: Steffen Aschbacher steffen.aschbacher@stihl.de
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: Steffen Aschbacher steffen.aschbacher@stihl.de Signed-off-by: Alexandru Ardelean alex@shruggie.ro --- sound/soc/codecs/tas5720.c | 103 ++++++++++++++++++++++++++++++++----- sound/soc/codecs/tas5720.h | 15 +++++- 2 files changed, 105 insertions(+), 13 deletions(-)
diff --git a/sound/soc/codecs/tas5720.c b/sound/soc/codecs/tas5720.c index 0587c9bb3c4e..d9d08593ff7a 100644 --- a/sound/soc/codecs/tas5720.c +++ b/sound/soc/codecs/tas5720.c @@ -30,6 +30,7 @@
enum tas572x_type { TAS5720, + TAS5720A_Q1, TAS5722, };
@@ -166,17 +167,26 @@ static int tas5720_set_dai_tdm_slot(struct snd_soc_dai *dai, return -EINVAL; }
- /* Enable manual TDM slot selection (instead of I2C ID based) */ - ret = snd_soc_component_update_bits(component, TAS5720_DIGITAL_CTRL1_REG, - TAS5720_TDM_CFG_SRC, TAS5720_TDM_CFG_SRC); - if (ret < 0) - goto error_snd_soc_component_update_bits; + /* + * 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) + goto error_snd_soc_component_update_bits;
- /* Configure the TDM slot to process audio from */ - ret = snd_soc_component_update_bits(component, TAS5720_DIGITAL_CTRL2_REG, - TAS5720_TDM_SLOT_SEL_MASK, first_slot); - if (ret < 0) - goto error_snd_soc_component_update_bits; + /* Configure the TDM slot to process audio from */ + ret = snd_soc_component_update_bits(component, TAS5720_DIGITAL_CTRL2_REG, + 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,21 @@ 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) { + unsigned int reg, mask, val; 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 +330,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 +498,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 +527,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 +583,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 +629,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 +704,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 +731,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 +767,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 +794,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", }, { }, }; diff --git a/sound/soc/codecs/tas5720.h b/sound/soc/codecs/tas5720.h index 223858f0de71..b38459570241 100644 --- a/sound/soc/codecs/tas5720.h +++ b/sound/soc/codecs/tas5720.h @@ -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)
On Sun, Jan 15, 2023 at 09:33:45PM +0200, Alexandru Ardelean wrote:
static int tas5720_mute_soc_component(struct snd_soc_component *component, int mute) {
- unsigned int reg, mask, val; 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:
This doesn't build:
/build/stage/linux/sound/soc/codecs/tas5720.c:217:17: error: ‘tas5720’ undeclare d (first use in this function); did you mean ‘TAS5720’? 217 | switch (tas5720->devtype) { | ^~~~~~~ | TAS5720 /build/stage/linux/sound/soc/codecs/tas5720.c:217:17: note: each undeclared iden tifier is reported only once for each function it appears in /build/stage/linux/sound/soc/codecs/tas5720.c:214:33: error: unused variable ‘va l’ [-Werror=unused-variable] 214 | unsigned int reg, mask, val; | ^~~ cc1: all warnings being treated as errors
On Wed, Jan 25, 2023 at 4:23 PM Mark Brown broonie@kernel.org wrote:
On Sun, Jan 15, 2023 at 09:33:45PM +0200, Alexandru Ardelean wrote:
static int tas5720_mute_soc_component(struct snd_soc_component *component, int mute) {
unsigned int reg, mask, val; 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:
This doesn't build:
My bad. Will fix
/build/stage/linux/sound/soc/codecs/tas5720.c:217:17: error: ‘tas5720’ undeclare d (first use in this function); did you mean ‘TAS5720’? 217 | switch (tas5720->devtype) { | ^~~~~~~ | TAS5720 /build/stage/linux/sound/soc/codecs/tas5720.c:217:17: note: each undeclared iden tifier is reported only once for each function it appears in /build/stage/linux/sound/soc/codecs/tas5720.c:214:33: error: unused variable ‘va l’ [-Werror=unused-variable] 214 | unsigned int reg, mask, val; | ^~~ cc1: all warnings being treated as errors
From: Steffen Aschbacher steffen.aschbacher@stihl.de
Set the reserved bit 7 in the ANALOG_CTRL_REG for the TAS5720A-Q1 device, when probing. The datasheet mentions that the bit should be 1 during reset/powerup.
The device did not initialize before setting this value to 1. So, this could be a quirk of this device. Or it could be a quirk with the board on which it was tested.
That is why this patch is separate from the patch that adds support for the TAS5720A-Q1 device. It's unclear whether this change is the proper way to do it.
Signed-off-by: Steffen Aschbacher steffen.aschbacher@stihl.de Signed-off-by: Alexandru Ardelean alex@shruggie.ro --- sound/soc/codecs/tas5720.c | 13 +++++++++++++ sound/soc/codecs/tas5720.h | 1 + 2 files changed, 14 insertions(+)
diff --git a/sound/soc/codecs/tas5720.c b/sound/soc/codecs/tas5720.c index d9d08593ff7a..0a7ad35c3b9b 100644 --- a/sound/soc/codecs/tas5720.c +++ b/sound/soc/codecs/tas5720.c @@ -350,6 +350,19 @@ static int tas5720_codec_probe(struct snd_soc_component *component) if (ret < 0) goto error_snd_soc_component_update_bits;
+ /* Set Bit 7 in TAS5720_ANALOG_CTRL_REG to 1 for TAS5720A_Q1 */ + switch (tas5720->devtype) { + case TAS5720A_Q1: + ret = snd_soc_component_update_bits(component, TAS5720_ANALOG_CTRL_REG, + TAS5720_Q1_RESERVED7_BIT, + TAS5720_Q1_RESERVED7_BIT); + break; + default: + break; + } + if (ret < 0) + goto error_snd_soc_component_update_bits; + /* * Enter shutdown mode - our default when not playing audio - to * minimize current consumption. On the TAS5720 there is no real down diff --git a/sound/soc/codecs/tas5720.h b/sound/soc/codecs/tas5720.h index b38459570241..54b59b05ef0a 100644 --- a/sound/soc/codecs/tas5720.h +++ b/sound/soc/codecs/tas5720.h @@ -81,6 +81,7 @@ #define TAS5720_ANALOG_GAIN_SHIFT (0x2)
/* TAS5720_Q1_ANALOG_CTRL_REG */ +#define TAS5720_Q1_RESERVED7_BIT BIT(7) #define TAS5720_Q1_CHAN_SEL BIT(1)
/* TAS5720_FAULT_REG */
From: Steffen Aschbacher steffen.aschbacher@stihl.de
Add entry for the TAS5720A-Q1 driver in the dt-bindings doc.
Signed-off-by: Steffen Aschbacher steffen.aschbacher@stihl.de Signed-off-by: Alexandru Ardelean alex@shruggie.ro --- Documentation/devicetree/bindings/sound/tas5720.txt | 2 ++ 1 file changed, 2 insertions(+)
diff --git a/Documentation/devicetree/bindings/sound/tas5720.txt b/Documentation/devicetree/bindings/sound/tas5720.txt index df99ca9451b0..7d851ae2bba2 100644 --- a/Documentation/devicetree/bindings/sound/tas5720.txt +++ b/Documentation/devicetree/bindings/sound/tas5720.txt @@ -6,11 +6,13 @@ audio playback. For more product information please see the links below:
https://www.ti.com/product/TAS5720L https://www.ti.com/product/TAS5720M +https://www.ti.com/product/TAS5720A-Q1 https://www.ti.com/product/TAS5722L
Required properties:
- compatible : "ti,tas5720", + "ti,tas5720a-q1", "ti,tas5722" - reg : I2C slave address - dvdd-supply : phandle to a 3.3-V supply for the digital circuitry
On 15/01/2023 20:33, Alexandru Ardelean wrote:
From: Steffen Aschbacher steffen.aschbacher@stihl.de
Add entry for the TAS5720A-Q1 driver in the dt-bindings doc.
Signed-off-by: Steffen Aschbacher steffen.aschbacher@stihl.de Signed-off-by: Alexandru Ardelean alex@shruggie.ro
Acked-by: Krzysztof Kozlowski krzysztof.kozlowski@linaro.org
Best regards, Krzysztof
participants (3)
-
Alexandru Ardelean
-
Krzysztof Kozlowski
-
Mark Brown