[alsa-devel] [PATCH v4 0/4] ASoC: tlv320aic32x4: DT support
Hi,
These are the remaining patches from v3 of this version. They add master clock and regulator support.
In v4 I added a check for the regulator dependencies and updated the binding documentation for them. I fixed the master clock patch to shutdown the master clock after the PLL and added another patch to shutdown all dividers before the PLL.
Regards,
Markus
Changes in v4: - Fix clock shutdown order - Add regulator dependency checks - Revert the previously added tlv320aic32x4 compatible from the binding documentation
Markus Pargmann (4): ASoC: tlv320aic32x4: Support for master clock ASoC: tlv320aic32x4: Support for regulators ASoC: tlv320aic32x4: Rearrange clock tree shutdown Revert "ASoC: codec doc, tlv320aic3x: Add tlv320aic32x4 as compatible"
.../devicetree/bindings/sound/tlv320aic32x4.txt | 12 ++ .../devicetree/bindings/sound/tlv320aic3x.txt | 1 - sound/soc/codecs/tlv320aic32x4.c | 126 ++++++++++++++++++--- 3 files changed, 123 insertions(+), 16 deletions(-)
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 | 4 ++++ sound/soc/codecs/tlv320aic32x4.c | 23 ++++++++++++++++++++++ 2 files changed, 27 insertions(+)
diff --git a/Documentation/devicetree/bindings/sound/tlv320aic32x4.txt b/Documentation/devicetree/bindings/sound/tlv320aic32x4.txt index db05510..352be7b 100644 --- a/Documentation/devicetree/bindings/sound/tlv320aic32x4.txt +++ b/Documentation/devicetree/bindings/sound/tlv320aic32x4.txt @@ -8,6 +8,8 @@ Required properties:
Optional properties: - reset-gpios: Reset-GPIO phandle with args as described in gpio/gpio.txt + - 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: @@ -15,4 +17,6 @@ Example: codec: tlv320aic32x4@18 { compatible = "ti,tlv320aic32x4"; reg = <0x18>; + clocks = <&clks 201>; + clock-names = "mclk"; }; diff --git a/sound/soc/codecs/tlv320aic32x4.c b/sound/soc/codecs/tlv320aic32x4.c index 1dd50e4..d96cb7c 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); @@ -539,6 +554,10 @@ static int aic32x4_set_bias_level(struct snd_soc_codec *codec, /* Switch off BCLK_N Divider */ snd_soc_update_bits(codec, AIC32X4_BCLKN, AIC32X4_BCLKEN, 0); + + /* Switch off master clock */ + if (!IS_ERR(aic32x4->mclk)) + clk_disable_unprepare(aic32x4->mclk); break; case SND_SOC_BIAS_OFF: break; @@ -717,6 +736,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");
Support regulators to power up the codec. This patch also enables the AVDD LDO if no AV regulator was found.
Signed-off-by: Markus Pargmann mpa@pengutronix.de --- .../devicetree/bindings/sound/tlv320aic32x4.txt | 8 +++ sound/soc/codecs/tlv320aic32x4.c | 73 ++++++++++++++++++++++ 2 files changed, 81 insertions(+)
diff --git a/Documentation/devicetree/bindings/sound/tlv320aic32x4.txt b/Documentation/devicetree/bindings/sound/tlv320aic32x4.txt index 352be7b..5e2741a 100644 --- a/Documentation/devicetree/bindings/sound/tlv320aic32x4.txt +++ b/Documentation/devicetree/bindings/sound/tlv320aic32x4.txt @@ -5,6 +5,14 @@ The tlv320aic32x4 serial control bus communicates through I2C protocols Required properties: - compatible: Should be "ti,tlv320aic32x4" - reg: I2C slave address + - supply-*: Required supply regulators are: + "iov" - digital IO power supply + "ldoin" - LDO power supply + "dv" - Digital core power supply + "av" - Analog core power supply + If you supply ldoin, dv and av are optional. Otherwise they are required + See regulator/regulator.txt for more information about the detailed binding + format.
Optional properties: - reset-gpios: Reset-GPIO phandle with args as described in gpio/gpio.txt diff --git a/sound/soc/codecs/tlv320aic32x4.c b/sound/soc/codecs/tlv320aic32x4.c index d96cb7c..2196af6 100644 --- a/sound/soc/codecs/tlv320aic32x4.c +++ b/sound/soc/codecs/tlv320aic32x4.c @@ -34,6 +34,7 @@ #include <linux/cdev.h> #include <linux/slab.h> #include <linux/clk.h> +#include <linux/regulator/consumer.h>
#include <sound/tlv320aic32x4.h> #include <sound/core.h> @@ -69,6 +70,11 @@ struct aic32x4_priv { bool swapdacs; int rstn_gpio; struct clk *mclk; + + struct regulator *supply_ldo; + struct regulator *supply_iov; + struct regulator *supply_dv; + struct regulator *supply_av; };
/* 0dB min, 0.5dB steps */ @@ -699,6 +705,67 @@ static int aic32x4_parse_dt(struct aic32x4_priv *aic32x4, return 0; }
+static int aic32x4_i2c_setup_regulators(struct device *dev, + struct aic32x4_priv *aic32x4) +{ + int ret; + + aic32x4->supply_ldo = devm_regulator_get_optional(dev, "ldoin"); + aic32x4->supply_iov = devm_regulator_get(dev, "iov"); + aic32x4->supply_dv = devm_regulator_get_optional(dev, "dv"); + aic32x4->supply_av = devm_regulator_get_optional(dev, "av"); + + /* Check if the regulator requirements are fulfilled */ + + if (IS_ERR(aic32x4->supply_iov)) { + dev_err(dev, "Missing supply 'iov'\n"); + ret = -EINVAL; + } + + if (IS_ERR(aic32x4->supply_ldo)) { + if (IS_ERR(aic32x4->supply_dv)) { + dev_err(dev, "Missing supply 'dv' or 'ldoin'\n"); + ret = -EINVAL; + } + if (IS_ERR(aic32x4->supply_av)) { + dev_err(dev, "Missing supply 'av' or 'ldoin'\n"); + ret = -EINVAL; + } + } + + if (ret) + return ret; + + if (!IS_ERR(aic32x4->supply_ldo)) { + ret = regulator_enable(aic32x4->supply_ldo); + if (ret) + return ret; + } + + if (!IS_ERR(aic32x4->supply_iov)) { + ret = regulator_enable(aic32x4->supply_iov); + if (ret) + return ret; + } + + if (!IS_ERR(aic32x4->supply_dv)) { + ret = regulator_enable(aic32x4->supply_dv); + if (ret) + return ret; + } + + if (!IS_ERR(aic32x4->supply_av)) { + ret = regulator_enable(aic32x4->supply_av); + if (ret) + return ret; + } + + if (!IS_ERR(aic32x4->supply_ldo) && IS_ERR(aic32x4->supply_av)) + aic32x4->power_cfg |= AIC32X4_PWR_AIC32X4_LDO_ENABLE; + + return 0; +} + static int aic32x4_i2c_probe(struct i2c_client *i2c, const struct i2c_device_id *id) { @@ -736,6 +803,12 @@ static int aic32x4_i2c_probe(struct i2c_client *i2c, aic32x4->rstn_gpio = -1; }
+ ret = aic32x4_i2c_setup_regulators(&i2c->dev, aic32x4); + if (ret) { + dev_err(&i2c->dev, "Failed to setup regulators\n"); + return ret; + } + aic32x4->mclk = devm_clk_get(&i2c->dev, "mclk"); if (IS_ERR(aic32x4->mclk)) dev_info(&i2c->dev, "No mclk found, continuing without clock\n");
Hi,
On Sun, Feb 16, 2014 at 07:27:30PM +0100, Markus Pargmann wrote:
Support regulators to power up the codec. This patch also enables the AVDD LDO if no AV regulator was found.
Signed-off-by: Markus Pargmann mpa@pengutronix.de
.../devicetree/bindings/sound/tlv320aic32x4.txt | 8 +++ sound/soc/codecs/tlv320aic32x4.c | 73 ++++++++++++++++++++++ 2 files changed, 81 insertions(+)
diff --git a/Documentation/devicetree/bindings/sound/tlv320aic32x4.txt b/Documentation/devicetree/bindings/sound/tlv320aic32x4.txt index 352be7b..5e2741a 100644 --- a/Documentation/devicetree/bindings/sound/tlv320aic32x4.txt +++ b/Documentation/devicetree/bindings/sound/tlv320aic32x4.txt
...
@@ -699,6 +705,67 @@ static int aic32x4_parse_dt(struct aic32x4_priv *aic32x4, return 0; }
+static int aic32x4_i2c_setup_regulators(struct device *dev,
struct aic32x4_priv *aic32x4)
+{
- int ret;
This ret is uninitialized and returned later in this function. I will fix it and send a new version for this.
Regards,
Markus
- aic32x4->supply_ldo = devm_regulator_get_optional(dev, "ldoin");
- aic32x4->supply_iov = devm_regulator_get(dev, "iov");
- aic32x4->supply_dv = devm_regulator_get_optional(dev, "dv");
- aic32x4->supply_av = devm_regulator_get_optional(dev, "av");
- /* Check if the regulator requirements are fulfilled */
- if (IS_ERR(aic32x4->supply_iov)) {
dev_err(dev, "Missing supply 'iov'\n");
ret = -EINVAL;
- }
- if (IS_ERR(aic32x4->supply_ldo)) {
if (IS_ERR(aic32x4->supply_dv)) {
dev_err(dev, "Missing supply 'dv' or 'ldoin'\n");
ret = -EINVAL;
}
if (IS_ERR(aic32x4->supply_av)) {
dev_err(dev, "Missing supply 'av' or 'ldoin'\n");
ret = -EINVAL;
}
- }
- if (ret)
return ret;
- if (!IS_ERR(aic32x4->supply_ldo)) {
ret = regulator_enable(aic32x4->supply_ldo);
if (ret)
return ret;
- }
- if (!IS_ERR(aic32x4->supply_iov)) {
ret = regulator_enable(aic32x4->supply_iov);
if (ret)
return ret;
- }
- if (!IS_ERR(aic32x4->supply_dv)) {
ret = regulator_enable(aic32x4->supply_dv);
if (ret)
return ret;
- }
- if (!IS_ERR(aic32x4->supply_av)) {
ret = regulator_enable(aic32x4->supply_av);
if (ret)
return ret;
- }
- if (!IS_ERR(aic32x4->supply_ldo) && IS_ERR(aic32x4->supply_av))
aic32x4->power_cfg |= AIC32X4_PWR_AIC32X4_LDO_ENABLE;
- return 0;
+}
static int aic32x4_i2c_probe(struct i2c_client *i2c, const struct i2c_device_id *id) { @@ -736,6 +803,12 @@ static int aic32x4_i2c_probe(struct i2c_client *i2c, aic32x4->rstn_gpio = -1; }
- ret = aic32x4_i2c_setup_regulators(&i2c->dev, aic32x4);
- if (ret) {
dev_err(&i2c->dev, "Failed to setup regulators\n");
return ret;
- }
- aic32x4->mclk = devm_clk_get(&i2c->dev, "mclk"); if (IS_ERR(aic32x4->mclk)) dev_info(&i2c->dev, "No mclk found, continuing without clock\n");
-- 1.8.5.3
Rearrange clock tree shutdown to disable them in the reversed order of startup. First disable all dividers, then PLL followed by master clock.
Signed-off-by: Markus Pargmann mpa@pengutronix.de --- sound/soc/codecs/tlv320aic32x4.c | 32 ++++++++++++++++---------------- 1 file changed, 16 insertions(+), 16 deletions(-)
diff --git a/sound/soc/codecs/tlv320aic32x4.c b/sound/soc/codecs/tlv320aic32x4.c index 2196af6..7540288 100644 --- a/sound/soc/codecs/tlv320aic32x4.c +++ b/sound/soc/codecs/tlv320aic32x4.c @@ -537,29 +537,29 @@ static int aic32x4_set_bias_level(struct snd_soc_codec *codec, case SND_SOC_BIAS_PREPARE: break; case SND_SOC_BIAS_STANDBY: - /* Switch off PLL */ - snd_soc_update_bits(codec, AIC32X4_PLLPR, - AIC32X4_PLLEN, 0); - - /* Switch off NDAC Divider */ - snd_soc_update_bits(codec, AIC32X4_NDAC, - AIC32X4_NDACEN, 0); + /* Switch off BCLK_N Divider */ + snd_soc_update_bits(codec, AIC32X4_BCLKN, + AIC32X4_BCLKEN, 0);
- /* Switch off MDAC Divider */ - snd_soc_update_bits(codec, AIC32X4_MDAC, - AIC32X4_MDACEN, 0); + /* Switch off MADC Divider */ + snd_soc_update_bits(codec, AIC32X4_MADC, + AIC32X4_MADCEN, 0);
/* Switch off NADC Divider */ snd_soc_update_bits(codec, AIC32X4_NADC, AIC32X4_NADCEN, 0);
- /* Switch off MADC Divider */ - snd_soc_update_bits(codec, AIC32X4_MADC, - AIC32X4_MADCEN, 0); + /* Switch off MDAC Divider */ + snd_soc_update_bits(codec, AIC32X4_MDAC, + AIC32X4_MDACEN, 0);
- /* Switch off BCLK_N Divider */ - snd_soc_update_bits(codec, AIC32X4_BCLKN, - AIC32X4_BCLKEN, 0); + /* Switch off NDAC Divider */ + snd_soc_update_bits(codec, AIC32X4_NDAC, + AIC32X4_NDACEN, 0); + + /* Switch off PLL */ + snd_soc_update_bits(codec, AIC32X4_PLLPR, + AIC32X4_PLLEN, 0);
/* Switch off master clock */ if (!IS_ERR(aic32x4->mclk))
This reverts tlv320aic32x4 as compatible for tlv320aic3x as it has its own bindings now. --- Documentation/devicetree/bindings/sound/tlv320aic3x.txt | 1 - 1 file changed, 1 deletion(-)
diff --git a/Documentation/devicetree/bindings/sound/tlv320aic3x.txt b/Documentation/devicetree/bindings/sound/tlv320aic3x.txt index 9d8ea14..5e6040c 100644 --- a/Documentation/devicetree/bindings/sound/tlv320aic3x.txt +++ b/Documentation/devicetree/bindings/sound/tlv320aic3x.txt @@ -6,7 +6,6 @@ Required properties:
- compatible - "string" - One of: "ti,tlv320aic3x" - Generic TLV320AIC3x device - "ti,tlv320aic32x4" - TLV320AIC32x4 "ti,tlv320aic33" - TLV320AIC33 "ti,tlv320aic3007" - TLV320AIC3007 "ti,tlv320aic3106" - TLV320AIC3106
Hi,
v5 fixes the uninitialized variable in the regulator patch.
Regards,
Markus
Changes in v5: - Fix uninitialized variable in regulator setup function
Changes in v4: - Fix clock shutdown order - Add regulator dependency checks - Revert the previously added tlv320aic32x4 compatible from the binding documentation
Markus Pargmann (4): ASoC: tlv320aic32x4: Support for master clock ASoC: tlv320aic32x4: Support for regulators ASoC: tlv320aic32x4: Rearrange clock tree shutdown Revert "ASoC: codec doc, tlv320aic3x: Add tlv320aic32x4 as compatible"
.../devicetree/bindings/sound/tlv320aic32x4.txt | 12 ++ .../devicetree/bindings/sound/tlv320aic3x.txt | 1 - sound/soc/codecs/tlv320aic32x4.c | 134 ++++++++++++++++++--- 3 files changed, 131 insertions(+), 16 deletions(-)
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 | 4 ++++ sound/soc/codecs/tlv320aic32x4.c | 23 ++++++++++++++++++++++ 2 files changed, 27 insertions(+)
diff --git a/Documentation/devicetree/bindings/sound/tlv320aic32x4.txt b/Documentation/devicetree/bindings/sound/tlv320aic32x4.txt index db05510..352be7b 100644 --- a/Documentation/devicetree/bindings/sound/tlv320aic32x4.txt +++ b/Documentation/devicetree/bindings/sound/tlv320aic32x4.txt @@ -8,6 +8,8 @@ Required properties:
Optional properties: - reset-gpios: Reset-GPIO phandle with args as described in gpio/gpio.txt + - 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: @@ -15,4 +17,6 @@ Example: codec: tlv320aic32x4@18 { compatible = "ti,tlv320aic32x4"; reg = <0x18>; + clocks = <&clks 201>; + clock-names = "mclk"; }; diff --git a/sound/soc/codecs/tlv320aic32x4.c b/sound/soc/codecs/tlv320aic32x4.c index 1dd50e4..d96cb7c 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); @@ -539,6 +554,10 @@ static int aic32x4_set_bias_level(struct snd_soc_codec *codec, /* Switch off BCLK_N Divider */ snd_soc_update_bits(codec, AIC32X4_BCLKN, AIC32X4_BCLKEN, 0); + + /* Switch off master clock */ + if (!IS_ERR(aic32x4->mclk)) + clk_disable_unprepare(aic32x4->mclk); break; case SND_SOC_BIAS_OFF: break; @@ -717,6 +736,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");
On Mon, Feb 17, 2014 at 11:04:17AM +0100, Markus Pargmann wrote:
Optional properties:
- reset-gpios: Reset-GPIO phandle with args as described in gpio/gpio.txt
- clocks/clock-names: Clock named 'mclk' for the master clock of the codec.
- See clock/clock-bindings.txt for information about the detailed format.
Looking at the code the clock isn't physically optional, why not make it mandatory? There's only one mainline user, it looks like it should be straightforward to update with a fixed clock.
- aic32x4->mclk = devm_clk_get(&i2c->dev, "mclk");
- if (IS_ERR(aic32x4->mclk))
dev_info(&i2c->dev, "No mclk found, continuing without clock\n");
This is going to break with deferred probe, we need to handle that at least.
Hi,
On Tue, Feb 18, 2014 at 10:23:29AM +0900, Mark Brown wrote:
On Mon, Feb 17, 2014 at 11:04:17AM +0100, Markus Pargmann wrote:
Optional properties:
- reset-gpios: Reset-GPIO phandle with args as described in gpio/gpio.txt
- clocks/clock-names: Clock named 'mclk' for the master clock of the codec.
- See clock/clock-bindings.txt for information about the detailed format.
Looking at the code the clock isn't physically optional, why not make it mandatory? There's only one mainline user, it looks like it should be straightforward to update with a fixed clock.
The masterclock is physically optional. There are several modes to use this codec without master clock. The PLL can use different clock inputs, BCLK, MCLK, etc. and even the PLL is not necessary. Instead BCLK and so on can be used as direct codec clock input. However, most of this is not supported by the driver yet and I can't test these cases.
- aic32x4->mclk = devm_clk_get(&i2c->dev, "mclk");
- if (IS_ERR(aic32x4->mclk))
dev_info(&i2c->dev, "No mclk found, continuing without clock\n");
This is going to break with deferred probe, we need to handle that at least.
Yes, I fixed this.
Thanks,
Markus
On Tue, Feb 18, 2014 at 09:46:46PM +0100, Markus Pargmann wrote:
On Tue, Feb 18, 2014 at 10:23:29AM +0900, Mark Brown wrote:
Looking at the code the clock isn't physically optional, why not make it mandatory? There's only one mainline user, it looks like it should be straightforward to update with a fixed clock.
The masterclock is physically optional. There are several modes to use this codec without master clock. The PLL can use different clock inputs, BCLK, MCLK, etc. and even the PLL is not necessary. Instead BCLK and so on can be used as direct codec clock input. However, most of this is not supported by the driver yet and I can't test these cases.
Are any of these modes supported by the driver yet? If there's modes that don't use MCLK supported then I'd expect them to only enable MCLK if it's actively being used in the current configuration (triggered via set_sysclk()).
Hi,
On Wed, Feb 19, 2014 at 12:54:06PM +0900, Mark Brown wrote:
On Tue, Feb 18, 2014 at 09:46:46PM +0100, Markus Pargmann wrote:
On Tue, Feb 18, 2014 at 10:23:29AM +0900, Mark Brown wrote:
Looking at the code the clock isn't physically optional, why not make it mandatory? There's only one mainline user, it looks like it should be straightforward to update with a fixed clock.
The masterclock is physically optional. There are several modes to use this codec without master clock. The PLL can use different clock inputs, BCLK, MCLK, etc. and even the PLL is not necessary. Instead BCLK and so on can be used as direct codec clock input. However, most of this is not supported by the driver yet and I can't test these cases.
Are any of these modes supported by the driver yet? If there's modes that don't use MCLK supported then I'd expect them to only enable MCLK if it's actively being used in the current configuration (triggered via set_sysclk()).
It seems none of these modes are supported yet. aic32x4_hw_params setups the clock tree relying on a master clock to be used for the PLL. Otherwise hw_params fails. So currently mclk is not optional for the driver. But it is still optional for the real hardware.
What do you think about declaring the mclk as optional property in the DT bindings documentation but to handle it as a required clock in the driver?
Thanks,
Markus
On Thu, Feb 20, 2014 at 12:37:49PM +0100, Markus Pargmann wrote:
It seems none of these modes are supported yet. aic32x4_hw_params setups the clock tree relying on a master clock to be used for the PLL. Otherwise hw_params fails. So currently mclk is not optional for the driver. But it is still optional for the real hardware.
What do you think about declaring the mclk as optional property in the DT bindings documentation but to handle it as a required clock in the driver?
That's fine, makes sense.
Support regulators to power up the codec. This patch also enables the AVDD LDO if no AV regulator was found.
Signed-off-by: Markus Pargmann mpa@pengutronix.de --- .../devicetree/bindings/sound/tlv320aic32x4.txt | 8 +++ sound/soc/codecs/tlv320aic32x4.c | 81 ++++++++++++++++++++++ 2 files changed, 89 insertions(+)
diff --git a/Documentation/devicetree/bindings/sound/tlv320aic32x4.txt b/Documentation/devicetree/bindings/sound/tlv320aic32x4.txt index 352be7b..5e2741a 100644 --- a/Documentation/devicetree/bindings/sound/tlv320aic32x4.txt +++ b/Documentation/devicetree/bindings/sound/tlv320aic32x4.txt @@ -5,6 +5,14 @@ The tlv320aic32x4 serial control bus communicates through I2C protocols Required properties: - compatible: Should be "ti,tlv320aic32x4" - reg: I2C slave address + - supply-*: Required supply regulators are: + "iov" - digital IO power supply + "ldoin" - LDO power supply + "dv" - Digital core power supply + "av" - Analog core power supply + If you supply ldoin, dv and av are optional. Otherwise they are required + See regulator/regulator.txt for more information about the detailed binding + format.
Optional properties: - reset-gpios: Reset-GPIO phandle with args as described in gpio/gpio.txt diff --git a/sound/soc/codecs/tlv320aic32x4.c b/sound/soc/codecs/tlv320aic32x4.c index d96cb7c..e4a7231 100644 --- a/sound/soc/codecs/tlv320aic32x4.c +++ b/sound/soc/codecs/tlv320aic32x4.c @@ -34,6 +34,7 @@ #include <linux/cdev.h> #include <linux/slab.h> #include <linux/clk.h> +#include <linux/regulator/consumer.h>
#include <sound/tlv320aic32x4.h> #include <sound/core.h> @@ -69,6 +70,11 @@ struct aic32x4_priv { bool swapdacs; int rstn_gpio; struct clk *mclk; + + struct regulator *supply_ldo; + struct regulator *supply_iov; + struct regulator *supply_dv; + struct regulator *supply_av; };
/* 0dB min, 0.5dB steps */ @@ -699,6 +705,75 @@ static int aic32x4_parse_dt(struct aic32x4_priv *aic32x4, return 0; }
+static int aic32x4_i2c_setup_regulators(struct device *dev, + struct aic32x4_priv *aic32x4) +{ + int ret = 0; + + aic32x4->supply_ldo = devm_regulator_get_optional(dev, "ldoin"); + aic32x4->supply_iov = devm_regulator_get(dev, "iov"); + aic32x4->supply_dv = devm_regulator_get_optional(dev, "dv"); + aic32x4->supply_av = devm_regulator_get_optional(dev, "av"); + + /* Check if the regulator requirements are fulfilled */ + + if (IS_ERR(aic32x4->supply_iov)) { + dev_err(dev, "Missing supply 'iov'\n"); + ret = -EINVAL; + } + + if (IS_ERR(aic32x4->supply_ldo)) { + if (IS_ERR(aic32x4->supply_dv)) { + dev_err(dev, "Missing supply 'dv' or 'ldoin'\n"); + ret = -EINVAL; + } + if (IS_ERR(aic32x4->supply_av)) { + dev_err(dev, "Missing supply 'av' or 'ldoin'\n"); + ret = -EINVAL; + } + } + + if (ret) + return ret; + + if (!IS_ERR(aic32x4->supply_ldo)) { + ret = regulator_enable(aic32x4->supply_ldo); + if (ret) { + printk("Failed to enable regulator ldo\n"); + return ret; + } + } + + if (!IS_ERR(aic32x4->supply_iov)) { + ret = regulator_enable(aic32x4->supply_iov); + if (ret) { + printk("Failed to enable regulator iov\n"); + return ret; + } + } + + if (!IS_ERR(aic32x4->supply_dv)) { + ret = regulator_enable(aic32x4->supply_dv); + if (ret) { + printk("Failed to enable regulator dv\n"); + return ret; + } + } + + if (!IS_ERR(aic32x4->supply_av)) { + ret = regulator_enable(aic32x4->supply_av); + if (ret) { + printk("Failed to enable regulator av\n"); + return ret; + } + } + + if (!IS_ERR(aic32x4->supply_ldo) && IS_ERR(aic32x4->supply_av)) + aic32x4->power_cfg |= AIC32X4_PWR_AIC32X4_LDO_ENABLE; + + return 0; +} + static int aic32x4_i2c_probe(struct i2c_client *i2c, const struct i2c_device_id *id) { @@ -736,6 +811,12 @@ static int aic32x4_i2c_probe(struct i2c_client *i2c, aic32x4->rstn_gpio = -1; }
+ ret = aic32x4_i2c_setup_regulators(&i2c->dev, aic32x4); + if (ret) { + dev_err(&i2c->dev, "Failed to setup regulators\n"); + return ret; + } + aic32x4->mclk = devm_clk_get(&i2c->dev, "mclk"); if (IS_ERR(aic32x4->mclk)) dev_info(&i2c->dev, "No mclk found, continuing without clock\n");
On Mon, Feb 17, 2014 at 11:04:18AM +0100, Markus Pargmann wrote:
- if (IS_ERR(aic32x4->supply_iov)) {
dev_err(dev, "Missing supply 'iov'\n");
ret = -EINVAL;
- }
This won't work with deferred probe and is ignoring the error value reported by the regualtor API. It should pass back what it was given and still needs to handle deferred probe even if it's happy for a regulator not to be there.
- if (!IS_ERR(aic32x4->supply_iov)) {
ret = regulator_enable(aic32x4->supply_iov);
if (ret) {
printk("Failed to enable regulator iov\n");
return ret;
}
- }
dev_err(). It would probably be easier to put one of the child regulators you did get into supply_iov instead so that outside of the probe you don't need to worry about which is actually there.
I'm also not seeing any disables prior to remove.
On Tue, Feb 18, 2014 at 10:27:25AM +0900, Mark Brown wrote:
On Mon, Feb 17, 2014 at 11:04:18AM +0100, Markus Pargmann wrote:
- if (IS_ERR(aic32x4->supply_iov)) {
dev_err(dev, "Missing supply 'iov'\n");
ret = -EINVAL;
- }
This won't work with deferred probe and is ignoring the error value reported by the regualtor API. It should pass back what it was given and still needs to handle deferred probe even if it's happy for a regulator not to be there.
Right, I added -EPROBE_DEFER checks for every regulator. I replaced the usage of the return value to directly return the errors. Otherwise it could be confusing to see multiple error messages and get one error value returned.
- if (!IS_ERR(aic32x4->supply_iov)) {
ret = regulator_enable(aic32x4->supply_iov);
if (ret) {
printk("Failed to enable regulator iov\n");
return ret;
}
- }
dev_err(). It would probably be easier to put one of the child regulators you did get into supply_iov instead so that outside of the probe you don't need to worry about which is actually there.
I'm also not seeing any disables prior to remove.
Replaced all printk's with dev_err. I am now disabling all regulators in the remove function and added error handling which disables the regulators.
I will test all changes tomorrow and resend the series.
Thanks,
Markus
Rearrange clock tree shutdown to disable them in the reversed order of startup. First disable all dividers, then PLL followed by master clock.
Signed-off-by: Markus Pargmann mpa@pengutronix.de --- sound/soc/codecs/tlv320aic32x4.c | 32 ++++++++++++++++---------------- 1 file changed, 16 insertions(+), 16 deletions(-)
diff --git a/sound/soc/codecs/tlv320aic32x4.c b/sound/soc/codecs/tlv320aic32x4.c index e4a7231..f76a693 100644 --- a/sound/soc/codecs/tlv320aic32x4.c +++ b/sound/soc/codecs/tlv320aic32x4.c @@ -537,29 +537,29 @@ static int aic32x4_set_bias_level(struct snd_soc_codec *codec, case SND_SOC_BIAS_PREPARE: break; case SND_SOC_BIAS_STANDBY: - /* Switch off PLL */ - snd_soc_update_bits(codec, AIC32X4_PLLPR, - AIC32X4_PLLEN, 0); - - /* Switch off NDAC Divider */ - snd_soc_update_bits(codec, AIC32X4_NDAC, - AIC32X4_NDACEN, 0); + /* Switch off BCLK_N Divider */ + snd_soc_update_bits(codec, AIC32X4_BCLKN, + AIC32X4_BCLKEN, 0);
- /* Switch off MDAC Divider */ - snd_soc_update_bits(codec, AIC32X4_MDAC, - AIC32X4_MDACEN, 0); + /* Switch off MADC Divider */ + snd_soc_update_bits(codec, AIC32X4_MADC, + AIC32X4_MADCEN, 0);
/* Switch off NADC Divider */ snd_soc_update_bits(codec, AIC32X4_NADC, AIC32X4_NADCEN, 0);
- /* Switch off MADC Divider */ - snd_soc_update_bits(codec, AIC32X4_MADC, - AIC32X4_MADCEN, 0); + /* Switch off MDAC Divider */ + snd_soc_update_bits(codec, AIC32X4_MDAC, + AIC32X4_MDACEN, 0);
- /* Switch off BCLK_N Divider */ - snd_soc_update_bits(codec, AIC32X4_BCLKN, - AIC32X4_BCLKEN, 0); + /* Switch off NDAC Divider */ + snd_soc_update_bits(codec, AIC32X4_NDAC, + AIC32X4_NDACEN, 0); + + /* Switch off PLL */ + snd_soc_update_bits(codec, AIC32X4_PLLPR, + AIC32X4_PLLEN, 0);
/* Switch off master clock */ if (!IS_ERR(aic32x4->mclk))
This reverts tlv320aic32x4 as compatible for tlv320aic3x as it has its own bindings now. --- Documentation/devicetree/bindings/sound/tlv320aic3x.txt | 1 - 1 file changed, 1 deletion(-)
diff --git a/Documentation/devicetree/bindings/sound/tlv320aic3x.txt b/Documentation/devicetree/bindings/sound/tlv320aic3x.txt index 9d8ea14..5e6040c 100644 --- a/Documentation/devicetree/bindings/sound/tlv320aic3x.txt +++ b/Documentation/devicetree/bindings/sound/tlv320aic3x.txt @@ -6,7 +6,6 @@ Required properties:
- compatible - "string" - One of: "ti,tlv320aic3x" - Generic TLV320AIC3x device - "ti,tlv320aic32x4" - TLV320AIC32x4 "ti,tlv320aic33" - TLV320AIC33 "ti,tlv320aic3007" - TLV320AIC3007 "ti,tlv320aic3106" - TLV320AIC3106
On Mon, Feb 17, 2014 at 11:04:20AM +0100, Markus Pargmann wrote:
This reverts tlv320aic32x4 as compatible for tlv320aic3x as it has its own bindings now.
Please use a normal subject line for this ("ASoC: ...") when you resubmit the series.
On Tue, Feb 18, 2014 at 10:28:48AM +0900, Mark Brown wrote:
On Mon, Feb 17, 2014 at 11:04:20AM +0100, Markus Pargmann wrote:
This reverts tlv320aic32x4 as compatible for tlv320aic3x as it has its own bindings now.
Please use a normal subject line for this ("ASoC: ...") when you resubmit the series.
Okay, will fix.
Thanks,
Markus
On Mon, Feb 17, 2014 at 11:04:16AM +0100, Markus Pargmann wrote:
Hi,
v5 fixes the uninitialized variable in the regulator patch.
Please don't bury patch serieses in reply to old ones, it makes things harder to follow in mailboxes/archives.
On Tue, Feb 18, 2014 at 09:50:46AM +0900, Mark Brown wrote:
On Mon, Feb 17, 2014 at 11:04:16AM +0100, Markus Pargmann wrote:
Hi,
v5 fixes the uninitialized variable in the regulator patch.
Please don't bury patch serieses in reply to old ones, it makes things harder to follow in mailboxes/archives.
Okay, I will avoid this in the future.
Thanks,
Markus
participants (2)
-
Mark Brown
-
Markus Pargmann