[alsa-devel] [PATCH v2 1/2] ASoC: codecs: tas5720: add TAS5722 specific volume control
From: Andreas Dannenberg dannenberg@ti.com
The TAS5722 supports modifying volume in 0.25dB steps (as opposed to 0.5dB steps on the TAS5720). Introduce a custom mixer control that allows taking advantage of this finer output volume granularity.
Also add custom getters/setters for access as the TAS5722 digital volume controls are split over two registers.
Signed-off-by: Andreas Dannenberg dannenberg@ti.com Signed-off-by: Andrew F. Davis afd@ti.com ---
Changes from v1: - Revise commit message - codec -> component
sound/soc/codecs/tas5720.c | 88 ++++++++++++++++++++++++++++++++++---- 1 file changed, 80 insertions(+), 8 deletions(-)
diff --git a/sound/soc/codecs/tas5720.c b/sound/soc/codecs/tas5720.c index ae3d032ac35a..3c469112477a 100644 --- a/sound/soc/codecs/tas5720.c +++ b/sound/soc/codecs/tas5720.c @@ -485,15 +485,56 @@ static const DECLARE_TLV_DB_RANGE(dac_analog_tlv, );
/* - * DAC digital volumes. From -103.5 to 24 dB in 0.5 dB steps. Note that - * setting the gain below -100 dB (register value <0x7) is effectively a MUTE - * as per device datasheet. + * 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 + * (register value <0x7) is effectively a MUTE as per device datasheet. + * + * Note that for the TAS5722 the digital volume controls are actually split + * over two registers, so we need custom getters/setters for access. */ -static DECLARE_TLV_DB_SCALE(dac_tlv, -10350, 50, 0); +static DECLARE_TLV_DB_SCALE(tas5720_dac_tlv, -10350, 50, 0); +static DECLARE_TLV_DB_SCALE(tas5722_dac_tlv, -10350, 25, 0); + +static int tas5722_volume_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol); + unsigned int val; + + snd_soc_component_read(component, TAS5720_VOLUME_CTRL_REG, &val); + ucontrol->value.integer.value[0] = val << 1; + + snd_soc_component_read(component, TAS5722_DIGITAL_CTRL2_REG, &val); + ucontrol->value.integer.value[0] |= val & TAS5722_VOL_CONTROL_LSB; + + return 0; +} + +static int tas5722_volume_set(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol); + unsigned int sel = ucontrol->value.integer.value[0]; + + snd_soc_component_write(component, TAS5720_VOLUME_CTRL_REG, sel >> 1); + snd_soc_component_update_bits(component, TAS5722_DIGITAL_CTRL2_REG, + TAS5722_VOL_CONTROL_LSB, sel); + + return 0; +}
static const struct snd_kcontrol_new tas5720_snd_controls[] = { SOC_SINGLE_TLV("Speaker Driver Playback Volume", - TAS5720_VOLUME_CTRL_REG, 0, 0xff, 0, dac_tlv), + TAS5720_VOLUME_CTRL_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), +}; + +static const struct snd_kcontrol_new tas5722_snd_controls[] = { + SOC_SINGLE_EXT_TLV("Speaker Driver Playback Volume", + 0, 0, 511, 0, + tas5722_volume_get, tas5722_volume_set, + tas5722_dac_tlv), SOC_SINGLE_TLV("Speaker Driver Analog Gain", TAS5720_ANALOG_CTRL_REG, TAS5720_ANALOG_GAIN_SHIFT, 3, 0, dac_analog_tlv), }; @@ -527,6 +568,23 @@ static const struct snd_soc_component_driver soc_component_dev_tas5720 = { .non_legacy_dai_naming = 1, };
+static const struct snd_soc_component_driver soc_component_dev_tas5722 = { + .probe = tas5720_codec_probe, + .remove = tas5720_codec_remove, + .suspend = tas5720_suspend, + .resume = tas5720_resume, + .controls = tas5722_snd_controls, + .num_controls = ARRAY_SIZE(tas5722_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, + .non_legacy_dai_naming = 1, +}; + /* PCM rates supported by the TAS5720 driver */ #define TAS5720_RATES (SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000 |\ SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000) @@ -613,9 +671,23 @@ static int tas5720_probe(struct i2c_client *client,
dev_set_drvdata(dev, data);
- ret = devm_snd_soc_register_component(&client->dev, - &soc_component_dev_tas5720, - tas5720_dai, ARRAY_SIZE(tas5720_dai)); + switch (id->driver_data) { + case TAS5720: + ret = devm_snd_soc_register_component(&client->dev, + &soc_component_dev_tas5720, + tas5720_dai, + ARRAY_SIZE(tas5720_dai)); + break; + case TAS5722: + ret = devm_snd_soc_register_component(&client->dev, + &soc_component_dev_tas5722, + tas5720_dai, + ARRAY_SIZE(tas5720_dai)); + break; + default: + dev_err(dev, "unexpected private driver data\n"); + return -EINVAL; + } if (ret < 0) { dev_err(dev, "failed to register component: %d\n", ret); return ret;
From: Andreas Dannenberg dannenberg@ti.com
Unlike the TAS5720, the TAS5722 can be configured to utilize 16-bit wide slots in TDM mode. This can help easing audio clocking/frequency requirements.
Signed-off-by: Andreas Dannenberg dannenberg@ti.com Signed-off-by: Andrew F. Davis afd@ti.com ---
Changes from v1: - Use switch over if
sound/soc/codecs/tas5720.c | 15 +++++++++++++++ 1 file changed, 15 insertions(+)
diff --git a/sound/soc/codecs/tas5720.c b/sound/soc/codecs/tas5720.c index 3c469112477a..6bd0e5d5347f 100644 --- a/sound/soc/codecs/tas5720.c +++ b/sound/soc/codecs/tas5720.c @@ -152,6 +152,7 @@ static int tas5720_set_dai_tdm_slot(struct snd_soc_dai *dai, int slots, int slot_width) { struct snd_soc_component *component = dai->component; + struct tas5720_data *tas5720 = snd_soc_component_get_drvdata(component); unsigned int first_slot; int ret;
@@ -185,6 +186,20 @@ static int tas5720_set_dai_tdm_slot(struct snd_soc_dai *dai, if (ret < 0) goto error_snd_soc_component_update_bits;
+ /* Configure TDM slot width. This is only applicable to TAS5722. */ + switch (tas5720->devtype) { + case TAS5722: + ret = snd_soc_component_update_bits(component, TAS5722_DIGITAL_CTRL2_REG, + TAS5722_TDM_SLOT_16B, + slot_width == 16 ? + TAS5722_TDM_SLOT_16B : 0); + if (ret < 0) + goto error_snd_soc_component_update_bits; + break; + default: + break; + } + return 0;
error_snd_soc_component_update_bits:
The patch
ASoC: codecs: tas5720: add TAS5722 TDM slot width setting support
has been applied to the asoc tree at
https://git.kernel.org/pub/scm/linux/kernel/git/broonie/sound.git
All being well this means that it will be integrated into the linux-next tree (usually sometime in the next 24 hours) and sent to Linus during the next merge window (or sooner if it is a bug fix), however if problems are discovered then the patch may be dropped or reverted.
You may get further e-mails resulting from automated or manual testing and review of the tree, please engage with people reporting problems and send followup patches addressing any issues that are reported if needed.
If any updates are required or you are submitting further changes they should be sent as incremental updates against current git, existing patches will not be replaced.
Please add any relevant lists and maintainers to the CCs when replying to this mail.
Thanks, Mark
From db658f40cae33a9fddbd9ca5c35c6bbfbd593a82 Mon Sep 17 00:00:00 2001
From: Andreas Dannenberg dannenberg@ti.com Date: Fri, 31 Aug 2018 09:47:14 -0500 Subject: [PATCH] ASoC: codecs: tas5720: add TAS5722 TDM slot width setting support
Unlike the TAS5720, the TAS5722 can be configured to utilize 16-bit wide slots in TDM mode. This can help easing audio clocking/frequency requirements.
Signed-off-by: Andreas Dannenberg dannenberg@ti.com Signed-off-by: Andrew F. Davis afd@ti.com Signed-off-by: Mark Brown broonie@kernel.org --- sound/soc/codecs/tas5720.c | 15 +++++++++++++++ 1 file changed, 15 insertions(+)
diff --git a/sound/soc/codecs/tas5720.c b/sound/soc/codecs/tas5720.c index 3c469112477a..6bd0e5d5347f 100644 --- a/sound/soc/codecs/tas5720.c +++ b/sound/soc/codecs/tas5720.c @@ -152,6 +152,7 @@ static int tas5720_set_dai_tdm_slot(struct snd_soc_dai *dai, int slots, int slot_width) { struct snd_soc_component *component = dai->component; + struct tas5720_data *tas5720 = snd_soc_component_get_drvdata(component); unsigned int first_slot; int ret;
@@ -185,6 +186,20 @@ static int tas5720_set_dai_tdm_slot(struct snd_soc_dai *dai, if (ret < 0) goto error_snd_soc_component_update_bits;
+ /* Configure TDM slot width. This is only applicable to TAS5722. */ + switch (tas5720->devtype) { + case TAS5722: + ret = snd_soc_component_update_bits(component, TAS5722_DIGITAL_CTRL2_REG, + TAS5722_TDM_SLOT_16B, + slot_width == 16 ? + TAS5722_TDM_SLOT_16B : 0); + if (ret < 0) + goto error_snd_soc_component_update_bits; + break; + default: + break; + } + return 0;
error_snd_soc_component_update_bits:
The patch
ASoC: codecs: tas5720: add TAS5722 specific volume control
has been applied to the asoc tree at
https://git.kernel.org/pub/scm/linux/kernel/git/broonie/sound.git
All being well this means that it will be integrated into the linux-next tree (usually sometime in the next 24 hours) and sent to Linus during the next merge window (or sooner if it is a bug fix), however if problems are discovered then the patch may be dropped or reverted.
You may get further e-mails resulting from automated or manual testing and review of the tree, please engage with people reporting problems and send followup patches addressing any issues that are reported if needed.
If any updates are required or you are submitting further changes they should be sent as incremental updates against current git, existing patches will not be replaced.
Please add any relevant lists and maintainers to the CCs when replying to this mail.
Thanks, Mark
From ec94c177bf3700ce44c53c375a3fb4c347f2b08f Mon Sep 17 00:00:00 2001
From: Andreas Dannenberg dannenberg@ti.com Date: Fri, 31 Aug 2018 09:47:13 -0500 Subject: [PATCH] ASoC: codecs: tas5720: add TAS5722 specific volume control
The TAS5722 supports modifying volume in 0.25dB steps (as opposed to 0.5dB steps on the TAS5720). Introduce a custom mixer control that allows taking advantage of this finer output volume granularity.
Also add custom getters/setters for access as the TAS5722 digital volume controls are split over two registers.
Signed-off-by: Andreas Dannenberg dannenberg@ti.com Signed-off-by: Andrew F. Davis afd@ti.com Signed-off-by: Mark Brown broonie@kernel.org --- sound/soc/codecs/tas5720.c | 88 ++++++++++++++++++++++++++++++++++---- 1 file changed, 80 insertions(+), 8 deletions(-)
diff --git a/sound/soc/codecs/tas5720.c b/sound/soc/codecs/tas5720.c index ae3d032ac35a..3c469112477a 100644 --- a/sound/soc/codecs/tas5720.c +++ b/sound/soc/codecs/tas5720.c @@ -485,15 +485,56 @@ static const DECLARE_TLV_DB_RANGE(dac_analog_tlv, );
/* - * DAC digital volumes. From -103.5 to 24 dB in 0.5 dB steps. Note that - * setting the gain below -100 dB (register value <0x7) is effectively a MUTE - * as per device datasheet. + * 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 + * (register value <0x7) is effectively a MUTE as per device datasheet. + * + * Note that for the TAS5722 the digital volume controls are actually split + * over two registers, so we need custom getters/setters for access. */ -static DECLARE_TLV_DB_SCALE(dac_tlv, -10350, 50, 0); +static DECLARE_TLV_DB_SCALE(tas5720_dac_tlv, -10350, 50, 0); +static DECLARE_TLV_DB_SCALE(tas5722_dac_tlv, -10350, 25, 0); + +static int tas5722_volume_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol); + unsigned int val; + + snd_soc_component_read(component, TAS5720_VOLUME_CTRL_REG, &val); + ucontrol->value.integer.value[0] = val << 1; + + snd_soc_component_read(component, TAS5722_DIGITAL_CTRL2_REG, &val); + ucontrol->value.integer.value[0] |= val & TAS5722_VOL_CONTROL_LSB; + + return 0; +} + +static int tas5722_volume_set(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_component *component = snd_soc_kcontrol_component(kcontrol); + unsigned int sel = ucontrol->value.integer.value[0]; + + snd_soc_component_write(component, TAS5720_VOLUME_CTRL_REG, sel >> 1); + snd_soc_component_update_bits(component, TAS5722_DIGITAL_CTRL2_REG, + TAS5722_VOL_CONTROL_LSB, sel); + + return 0; +}
static const struct snd_kcontrol_new tas5720_snd_controls[] = { SOC_SINGLE_TLV("Speaker Driver Playback Volume", - TAS5720_VOLUME_CTRL_REG, 0, 0xff, 0, dac_tlv), + TAS5720_VOLUME_CTRL_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), +}; + +static const struct snd_kcontrol_new tas5722_snd_controls[] = { + SOC_SINGLE_EXT_TLV("Speaker Driver Playback Volume", + 0, 0, 511, 0, + tas5722_volume_get, tas5722_volume_set, + tas5722_dac_tlv), SOC_SINGLE_TLV("Speaker Driver Analog Gain", TAS5720_ANALOG_CTRL_REG, TAS5720_ANALOG_GAIN_SHIFT, 3, 0, dac_analog_tlv), }; @@ -527,6 +568,23 @@ static const struct snd_soc_component_driver soc_component_dev_tas5720 = { .non_legacy_dai_naming = 1, };
+static const struct snd_soc_component_driver soc_component_dev_tas5722 = { + .probe = tas5720_codec_probe, + .remove = tas5720_codec_remove, + .suspend = tas5720_suspend, + .resume = tas5720_resume, + .controls = tas5722_snd_controls, + .num_controls = ARRAY_SIZE(tas5722_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, + .non_legacy_dai_naming = 1, +}; + /* PCM rates supported by the TAS5720 driver */ #define TAS5720_RATES (SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000 |\ SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000) @@ -613,9 +671,23 @@ static int tas5720_probe(struct i2c_client *client,
dev_set_drvdata(dev, data);
- ret = devm_snd_soc_register_component(&client->dev, - &soc_component_dev_tas5720, - tas5720_dai, ARRAY_SIZE(tas5720_dai)); + switch (id->driver_data) { + case TAS5720: + ret = devm_snd_soc_register_component(&client->dev, + &soc_component_dev_tas5720, + tas5720_dai, + ARRAY_SIZE(tas5720_dai)); + break; + case TAS5722: + ret = devm_snd_soc_register_component(&client->dev, + &soc_component_dev_tas5722, + tas5720_dai, + ARRAY_SIZE(tas5720_dai)); + break; + default: + dev_err(dev, "unexpected private driver data\n"); + return -EINVAL; + } if (ret < 0) { dev_err(dev, "failed to register component: %d\n", ret); return ret;
participants (2)
-
Andrew F. Davis
-
Mark Brown