[alsa-devel] [PATCH 0/4] ASoC: tlv320aic32x4: DT support
Hi,
Here are some more updates for the tlv320aic32x4 codec. This series fixes the mixer controls to operate on the full range instead of only the positive range. This depends on my other series: "ASoC: core: volume control using signed register values"
Patch 3 adds DT support. Patch 4 adds support to control the master clock connected to the codec.
Regards,
Markus
Markus Pargmann (4): ASoC: tlv320aic32x4: Use signed int mixer controls ASoC: tlv320aic32x4: Use gpio_is_valid ASoC: tlv320aic32x4: DT support ASoC: tlv320aic32x4: Support for master clock
.../devicetree/bindings/sound/tlv320aic32x4.txt | 25 +++++++ sound/soc/codecs/tlv320aic32x4.c | 83 ++++++++++++++++++---- 2 files changed, 96 insertions(+), 12 deletions(-) create mode 100644 Documentation/devicetree/bindings/sound/tlv320aic32x4.txt
There are a number of mixer controls that support negative values. They use signed values for this with different number of bits for the values. Currently they only support the positive range.
This patch replaces the unsigned mixers with signed mixers to support the full range.
Signed-off-by: Markus Pargmann mpa@pengutronix.de --- sound/soc/codecs/tlv320aic32x4.c | 26 ++++++++++++++++---------- 1 file changed, 16 insertions(+), 10 deletions(-)
diff --git a/sound/soc/codecs/tlv320aic32x4.c b/sound/soc/codecs/tlv320aic32x4.c index 688151b..86bcae9 100644 --- a/sound/soc/codecs/tlv320aic32x4.c +++ b/sound/soc/codecs/tlv320aic32x4.c @@ -68,18 +68,24 @@ struct aic32x4_priv { int rstn_gpio; };
-/* 0dB min, 1dB steps */ -static DECLARE_TLV_DB_SCALE(tlv_step_1, 0, 100, 0); /* 0dB min, 0.5dB steps */ static DECLARE_TLV_DB_SCALE(tlv_step_0_5, 0, 50, 0); +/* -63.5dB min, 0.5dB steps */ +static DECLARE_TLV_DB_SCALE(tlv_pcm, -6350, 50, 0); +/* -6dB min, 1dB steps */ +static DECLARE_TLV_DB_SCALE(tlv_driver_gain, -600, 100, 0); +/* -12dB min, 0.5dB steps */ +static DECLARE_TLV_DB_SCALE(tlv_adc_vol, -1200, 50, 0);
static const struct snd_kcontrol_new aic32x4_snd_controls[] = { - SOC_DOUBLE_R_TLV("PCM Playback Volume", AIC32X4_LDACVOL, - AIC32X4_RDACVOL, 0, 0x30, 0, tlv_step_0_5), - SOC_DOUBLE_R_TLV("HP Driver Gain Volume", AIC32X4_HPLGAIN, - AIC32X4_HPRGAIN, 0, 0x1D, 0, tlv_step_1), - SOC_DOUBLE_R_TLV("LO Driver Gain Volume", AIC32X4_LOLGAIN, - AIC32X4_LORGAIN, 0, 0x1D, 0, tlv_step_1), + SOC_DOUBLE_R_S_TLV("PCM Playback Volume", AIC32X4_LDACVOL, + AIC32X4_RDACVOL, 0, (s8)0x81, 0x30, 7, 0, tlv_pcm), + SOC_DOUBLE_R_S_TLV("HP Driver Gain Volume", AIC32X4_HPLGAIN, + AIC32X4_HPRGAIN, 0, (s8)0xfa, 0x1d, 5, 0, + tlv_driver_gain), + SOC_DOUBLE_R_S_TLV("LO Driver Gain Volume", AIC32X4_LOLGAIN, + AIC32X4_LORGAIN, 0, (s8)0xfa, 0x1d, 5, 0, + tlv_driver_gain), SOC_DOUBLE_R("HP DAC Playback Switch", AIC32X4_HPLGAIN, AIC32X4_HPRGAIN, 6, 0x01, 1), SOC_DOUBLE_R("LO DAC Playback Switch", AIC32X4_LOLGAIN, @@ -90,8 +96,8 @@ static const struct snd_kcontrol_new aic32x4_snd_controls[] = { SOC_SINGLE("ADCFGA Left Mute Switch", AIC32X4_ADCFGA, 7, 1, 0), SOC_SINGLE("ADCFGA Right Mute Switch", AIC32X4_ADCFGA, 3, 1, 0),
- SOC_DOUBLE_R_TLV("ADC Level Volume", AIC32X4_LADCVOL, - AIC32X4_RADCVOL, 0, 0x28, 0, tlv_step_0_5), + SOC_DOUBLE_R_S_TLV("ADC Level Volume", AIC32X4_LADCVOL, + AIC32X4_RADCVOL, 0, (s8)0xe8, 0x28, 6, 0, tlv_adc_vol), SOC_DOUBLE_R_TLV("PGA Level Volume", AIC32X4_LMICPGAVOL, AIC32X4_RMICPGAVOL, 0, 0x5f, 0, tlv_step_0_5),
Use function gpio_is_valid to check for gpio ports.
Signed-off-by: Markus Pargmann mpa@pengutronix.de --- sound/soc/codecs/tlv320aic32x4.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/sound/soc/codecs/tlv320aic32x4.c b/sound/soc/codecs/tlv320aic32x4.c index 86bcae9..1c9f1d8 100644 --- a/sound/soc/codecs/tlv320aic32x4.c +++ b/sound/soc/codecs/tlv320aic32x4.c @@ -594,7 +594,7 @@ static int aic32x4_probe(struct snd_soc_codec *codec)
snd_soc_codec_set_cache_io(codec, 8, 8, SND_SOC_REGMAP);
- if (aic32x4->rstn_gpio >= 0) { + if (gpio_is_valid(aic32x4->rstn_gpio)) { ndelay(10); gpio_set_value(aic32x4->rstn_gpio, 1); } @@ -699,7 +699,7 @@ static int aic32x4_i2c_probe(struct i2c_client *i2c, aic32x4->rstn_gpio = -1; }
- if (aic32x4->rstn_gpio >= 0) { + if (gpio_is_valid(aic32x4->rstn_gpio)) { ret = devm_gpio_request_one(&i2c->dev, aic32x4->rstn_gpio, GPIOF_OUT_INIT_LOW, "tlv320aic32x4 rstn"); if (ret != 0)
Add DT support for this codec. The bindings differ a bit from the aic3x codec bindings, so I created a new binding documentation. The difference is especially a "ti,ldo-enable" property, which enables the internal LDOs.
Cc: Rob Herring robh+dt@kernel.org Cc: Pawel Moll pawel.moll@arm.com Cc: Mark Rutland mark.rutland@arm.com Cc: Ian Campbell ijc+devicetree@hellion.org.uk Cc: Kumar Gala galak@codeaurora.org Cc: devicetree@vger.kernel.org Signed-off-by: Markus Pargmann mpa@pengutronix.de --- .../devicetree/bindings/sound/tlv320aic32x4.txt | 23 +++++++++++++++++ sound/soc/codecs/tlv320aic32x4.c | 30 ++++++++++++++++++++++ 2 files changed, 53 insertions(+) create mode 100644 Documentation/devicetree/bindings/sound/tlv320aic32x4.txt
diff --git a/Documentation/devicetree/bindings/sound/tlv320aic32x4.txt b/Documentation/devicetree/bindings/sound/tlv320aic32x4.txt new file mode 100644 index 0000000..5c8fb4a --- /dev/null +++ b/Documentation/devicetree/bindings/sound/tlv320aic32x4.txt @@ -0,0 +1,23 @@ +Texas Instruments - tlv320aic32x4 Codec module + +The tlv320aic32x4 serial control bus communicates through I2C protocols + +Required properties: + - compatible: Should be "ti,tlv320aic32x4" + - reg: I2C slave address + +Optional properties: + - ti,ldo-enable: Bool, has to be set when the codec is powered only through the + LDOIN pin. + - gpio-reset - gpio pin number used for codec reset + + +Example: + +codec: tlv320aic32x4@18 { + compatible = "ti,tlv320aic32x4"; + reg = <0x18>; + clocks = <&clks 201>; + clock-names = "mclk"; + ti,ldo-enable; +}; diff --git a/sound/soc/codecs/tlv320aic32x4.c b/sound/soc/codecs/tlv320aic32x4.c index 1c9f1d8..840f529 100644 --- a/sound/soc/codecs/tlv320aic32x4.c +++ b/sound/soc/codecs/tlv320aic32x4.c @@ -29,6 +29,7 @@ #include <linux/delay.h> #include <linux/pm.h> #include <linux/gpio.h> +#include <linux/of_gpio.h> #include <linux/i2c.h> #include <linux/cdev.h> #include <linux/slab.h> @@ -669,11 +670,27 @@ static struct snd_soc_codec_driver soc_codec_dev_aic32x4 = { .num_dapm_routes = ARRAY_SIZE(aic32x4_dapm_routes), };
+static int aic32x4_parse_dt(struct aic32x4_priv *aic32x4, + struct device_node *np) +{ + aic32x4->swapdacs = false; + aic32x4->micpga_routing = 0; + aic32x4->rstn_gpio = of_get_named_gpio(np, "gpio-reset", 0); + + if (of_property_read_bool(np, "ti,ldo-enable")) + aic32x4->power_cfg = AIC32X4_PWR_AIC32X4_LDO_ENABLE; + else + aic32x4->power_cfg = 0; + + return 0; +} + static int aic32x4_i2c_probe(struct i2c_client *i2c, const struct i2c_device_id *id) { struct aic32x4_pdata *pdata = i2c->dev.platform_data; struct aic32x4_priv *aic32x4; + struct device_node *np = i2c->dev.of_node; int ret;
aic32x4 = devm_kzalloc(&i2c->dev, sizeof(struct aic32x4_priv), @@ -692,6 +709,12 @@ static int aic32x4_i2c_probe(struct i2c_client *i2c, aic32x4->swapdacs = pdata->swapdacs; aic32x4->micpga_routing = pdata->micpga_routing; aic32x4->rstn_gpio = pdata->rstn_gpio; + } else if (np) { + ret = aic32x4_parse_dt(aic32x4, np); + if (ret) { + dev_err(&i2c->dev, "Failed to parse DT node\n"); + return ret; + } } else { aic32x4->power_cfg = 0; aic32x4->swapdacs = false; @@ -723,10 +746,17 @@ static const struct i2c_device_id aic32x4_i2c_id[] = { }; MODULE_DEVICE_TABLE(i2c, aic32x4_i2c_id);
+static const struct of_device_id aic32x4_of_id[] = { + { .compatible = "ti,tlv320aic32x4", }, + { /* senitel */ } +}; +MODULE_DEVICE_TABLE(of, aic32x4_of_id); + static struct i2c_driver aic32x4_i2c_driver = { .driver = { .name = "tlv320aic32x4", .owner = THIS_MODULE, + .of_match_table = aic32x4_of_id, }, .probe = aic32x4_i2c_probe, .remove = aic32x4_i2c_remove,
On Thu, Jan 16, 2014 at 04:30:26PM +0100, Markus Pargmann wrote:
+Optional properties:
- ti,ldo-enable: Bool, has to be set when the codec is powered only through the
- LDOIN pin.
This seems very odd. Should the regulator bindings not be being used for this, either having a regulator in the device that's bound via the DT or using regulator_get_optional() to check for the other supplies that might be used being provided?
- gpio-reset - gpio pin number used for codec reset
This should be a standard GPIO specifier.
Add support for a master clock passed through DT. The master clock of the codec is only active when the codec is in use.
Cc: Rob Herring robh+dt@kernel.org Cc: Pawel Moll pawel.moll@arm.com Cc: Mark Rutland mark.rutland@arm.com Cc: Ian Campbell ijc+devicetree@hellion.org.uk Cc: Kumar Gala galak@codeaurora.org Cc: devicetree@vger.kernel.org Signed-off-by: Markus Pargmann mpa@pengutronix.de --- .../devicetree/bindings/sound/tlv320aic32x4.txt | 2 ++ sound/soc/codecs/tlv320aic32x4.c | 23 ++++++++++++++++++++++ 2 files changed, 25 insertions(+)
diff --git a/Documentation/devicetree/bindings/sound/tlv320aic32x4.txt b/Documentation/devicetree/bindings/sound/tlv320aic32x4.txt index 5c8fb4a..4ed7c37 100644 --- a/Documentation/devicetree/bindings/sound/tlv320aic32x4.txt +++ b/Documentation/devicetree/bindings/sound/tlv320aic32x4.txt @@ -10,6 +10,8 @@ Optional properties: - ti,ldo-enable: Bool, has to be set when the codec is powered only through the LDOIN pin. - gpio-reset - gpio pin number used for codec reset + - clocks/clock-names: Clock named 'mclk' for the master clock of the codec. + See clock/clock-bindings.txt for information about the detailed format.
Example: diff --git a/sound/soc/codecs/tlv320aic32x4.c b/sound/soc/codecs/tlv320aic32x4.c index 840f529..33ab004 100644 --- a/sound/soc/codecs/tlv320aic32x4.c +++ b/sound/soc/codecs/tlv320aic32x4.c @@ -33,6 +33,7 @@ #include <linux/i2c.h> #include <linux/cdev.h> #include <linux/slab.h> +#include <linux/clk.h>
#include <sound/tlv320aic32x4.h> #include <sound/core.h> @@ -67,6 +68,7 @@ struct aic32x4_priv { u32 micpga_routing; bool swapdacs; int rstn_gpio; + struct clk *mclk; };
/* 0dB min, 0.5dB steps */ @@ -487,8 +489,21 @@ static int aic32x4_mute(struct snd_soc_dai *dai, int mute) static int aic32x4_set_bias_level(struct snd_soc_codec *codec, enum snd_soc_bias_level level) { + struct aic32x4_priv *aic32x4 = snd_soc_codec_get_drvdata(codec); + switch (level) { case SND_SOC_BIAS_ON: + /* Switch on master clock */ + if (!IS_ERR(aic32x4->mclk)) { + int ret; + + ret = clk_prepare_enable(aic32x4->mclk); + if (ret) { + dev_err(codec->dev, "Failed to enable master clock\n"); + return ret; + } + } + /* Switch on PLL */ snd_soc_update_bits(codec, AIC32X4_PLLPR, AIC32X4_PLLEN, AIC32X4_PLLEN); @@ -516,6 +531,10 @@ static int aic32x4_set_bias_level(struct snd_soc_codec *codec, case SND_SOC_BIAS_PREPARE: break; case SND_SOC_BIAS_STANDBY: + /* Switch off master clock */ + if (!IS_ERR(aic32x4->mclk)) + clk_disable_unprepare(aic32x4->mclk); + /* Switch off PLL */ snd_soc_update_bits(codec, AIC32X4_PLLPR, AIC32X4_PLLEN, 0); @@ -722,6 +741,10 @@ static int aic32x4_i2c_probe(struct i2c_client *i2c, aic32x4->rstn_gpio = -1; }
+ aic32x4->mclk = devm_clk_get(&i2c->dev, "mclk"); + if (IS_ERR(aic32x4->mclk)) + dev_info(&i2c->dev, "No mclk found, continuing without clock\n"); + if (gpio_is_valid(aic32x4->rstn_gpio)) { ret = devm_gpio_request_one(&i2c->dev, aic32x4->rstn_gpio, GPIOF_OUT_INIT_LOW, "tlv320aic32x4 rstn");
participants (2)
-
Mark Brown
-
Markus Pargmann