[alsa-devel] [PATCH] ak4642 codec updates
This series has some updates to the ak4642 codec driver like ALC controls, improved sysclk support for the ak4648.
Sascha
---------------------------------------------------------------- Sascha Hauer (6): ASoC: ak4642: Fix typo zoro -> zero ASoC: ak4642: Add ALC controls ASoC: ak4642: Add driver data and driver private struct ASoC: ak4642: Add support for extended sysclk frequencies of the ak4648 ASoC: ak4642: Implement Microphone in pathes ASoC: ak4642: Add enable gpio support
Documentation/devicetree/bindings/sound/ak4642.txt | 3 + sound/soc/codecs/ak4642.c | 230 +++++++++++++++++++-- 2 files changed, 221 insertions(+), 12 deletions(-)
Signed-off-by: Sascha Hauer s.hauer@pengutronix.de --- sound/soc/codecs/ak4642.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/sound/soc/codecs/ak4642.c b/sound/soc/codecs/ak4642.c index 92655cc..3373a9c 100644 --- a/sound/soc/codecs/ak4642.c +++ b/sound/soc/codecs/ak4642.c @@ -98,7 +98,7 @@ #define MGAIN0 (1 << 0) /* MIC amp gain*/
/* TIMER */ -#define ZTM(param) ((param & 0x3) << 4) /* ALC Zoro Crossing TimeOut */ +#define ZTM(param) ((param & 0x3) << 4) /* ALC Zero Crossing TimeOut */ #define WTM(param) (((param & 0x4) << 4) | ((param & 0x3) << 2))
/* ALC_CTL1 */
On Wed, May 14, 2014 at 09:37:33AM +0200, Sascha Hauer wrote:
Signed-off-by: Sascha Hauer s.hauer@pengutronix.de
Applied, thanks.
ALC and ALC Zero crossing detection has been enabled unconditionally. Add controls for this.
Signed-off-by: Sascha Hauer s.hauer@pengutronix.de --- sound/soc/codecs/ak4642.c | 2 ++ 1 file changed, 2 insertions(+)
diff --git a/sound/soc/codecs/ak4642.c b/sound/soc/codecs/ak4642.c index 3373a9c..90d2d93 100644 --- a/sound/soc/codecs/ak4642.c +++ b/sound/soc/codecs/ak4642.c @@ -148,6 +148,8 @@ static const struct snd_kcontrol_new ak4642_snd_controls[] = {
SOC_DOUBLE_R_TLV("Digital Playback Volume", L_DVC, R_DVC, 0, 0xFF, 1, out_tlv), + SOC_SINGLE("ALC Capture Switch", ALC_CTL1, 5, 1, 0), + SOC_SINGLE("ALC Capture ZC Switch", ALC_CTL1, 4, 1, 1), };
static const struct snd_kcontrol_new ak4642_headphone_control =
Currently unused, this is done to let the driver distinguish between the different supported codec types in later patches.
Signed-off-by: Sascha Hauer s.hauer@pengutronix.de --- sound/soc/codecs/ak4642.c | 51 +++++++++++++++++++++++++++++++++++++---------- 1 file changed, 40 insertions(+), 11 deletions(-)
diff --git a/sound/soc/codecs/ak4642.c b/sound/soc/codecs/ak4642.c index 90d2d93..b568692 100644 --- a/sound/soc/codecs/ak4642.c +++ b/sound/soc/codecs/ak4642.c @@ -134,6 +134,14 @@ /* MD_CTL4 */ #define DACH (1 << 0)
+struct ak4642_drvdata { + const struct regmap_config *regmap_config; +}; + +struct ak4642_priv { + const struct ak4642_drvdata *drvdata; +}; + /* * Playback Volume (table 39) * @@ -507,30 +515,51 @@ static const struct regmap_config ak4648_regmap = { .num_reg_defaults = ARRAY_SIZE(ak4648_reg), };
+static const struct ak4642_drvdata ak4642_drvdata = { + .regmap_config = &ak4642_regmap, +}; + +static const struct ak4642_drvdata ak4643_drvdata = { + .regmap_config = &ak4642_regmap, +}; + +static const struct ak4642_drvdata ak4648_drvdata = { + .regmap_config = &ak4648_regmap, +}; + static struct of_device_id ak4642_of_match[]; static int ak4642_i2c_probe(struct i2c_client *i2c, const struct i2c_device_id *id) { struct device_node *np = i2c->dev.of_node; - const struct regmap_config *regmap_config = NULL; + const struct ak4642_drvdata *drvdata = NULL; struct regmap *regmap; + struct ak4642_priv *priv;
if (np) { const struct of_device_id *of_id;
of_id = of_match_device(ak4642_of_match, &i2c->dev); if (of_id) - regmap_config = of_id->data; + drvdata = of_id->data; } else { - regmap_config = (const struct regmap_config *)id->driver_data; + drvdata = (const struct ak4642_drvdata *)id->driver_data; }
- if (!regmap_config) { + if (!drvdata) { dev_err(&i2c->dev, "Unknown device type\n"); return -EINVAL; }
- regmap = devm_regmap_init_i2c(i2c, regmap_config); + priv = devm_kzalloc(&i2c->dev, sizeof(*priv), GFP_KERNEL); + if (!priv) + return -ENOMEM; + + priv->drvdata = drvdata; + + i2c_set_clientdata(i2c, priv); + + regmap = devm_regmap_init_i2c(i2c, drvdata->regmap_config); if (IS_ERR(regmap)) return PTR_ERR(regmap);
@@ -545,17 +574,17 @@ static int ak4642_i2c_remove(struct i2c_client *client) }
static struct of_device_id ak4642_of_match[] = { - { .compatible = "asahi-kasei,ak4642", .data = &ak4642_regmap}, - { .compatible = "asahi-kasei,ak4643", .data = &ak4642_regmap}, - { .compatible = "asahi-kasei,ak4648", .data = &ak4648_regmap}, + { .compatible = "asahi-kasei,ak4642", .data = &ak4642_drvdata}, + { .compatible = "asahi-kasei,ak4643", .data = &ak4643_drvdata}, + { .compatible = "asahi-kasei,ak4648", .data = &ak4648_drvdata}, {}, }; MODULE_DEVICE_TABLE(of, ak4642_of_match);
static const struct i2c_device_id ak4642_i2c_id[] = { - { "ak4642", (kernel_ulong_t)&ak4642_regmap }, - { "ak4643", (kernel_ulong_t)&ak4642_regmap }, - { "ak4648", (kernel_ulong_t)&ak4648_regmap }, + { "ak4642", (kernel_ulong_t)&ak4642_drvdata }, + { "ak4643", (kernel_ulong_t)&ak4643_drvdata }, + { "ak4648", (kernel_ulong_t)&ak4648_drvdata }, { } }; MODULE_DEVICE_TABLE(i2c, ak4642_i2c_id);
On Wed, May 14, 2014 at 09:37:35AM +0200, Sascha Hauer wrote:
Currently unused, this is done to let the driver distinguish between the different supported codec types in later patches.
Applied, thanks.
Additionally to the ak4642 pll frequencies the ak4648 also supports 13MHz, 19.2MHz and 26MHz. This adds support for these frequencies.
Signed-off-by: Sascha Hauer s.hauer@pengutronix.de --- sound/soc/codecs/ak4642.c | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+)
diff --git a/sound/soc/codecs/ak4642.c b/sound/soc/codecs/ak4642.c index b568692..3ba4c0f 100644 --- a/sound/soc/codecs/ak4642.c +++ b/sound/soc/codecs/ak4642.c @@ -136,6 +136,7 @@
struct ak4642_drvdata { const struct regmap_config *regmap_config; + int extended_frequencies; };
struct ak4642_priv { @@ -297,7 +298,9 @@ static int ak4642_dai_set_sysclk(struct snd_soc_dai *codec_dai, int clk_id, unsigned int freq, int dir) { struct snd_soc_codec *codec = codec_dai->codec; + struct ak4642_priv *priv = snd_soc_codec_get_drvdata(codec); u8 pll; + int extended_freq = 0;
switch (freq) { case 11289600: @@ -318,9 +321,25 @@ static int ak4642_dai_set_sysclk(struct snd_soc_dai *codec_dai, case 27000000: pll = PLL3 | PLL2 | PLL0; break; + case 19200000: + pll = PLL3; + extended_freq = 1; + break; + case 13000000: + pll = PLL3 | PLL2 | PLL1; + extended_freq = 1; + break; + case 26000000: + pll = PLL3 | PLL2 | PLL1 | PLL0; + extended_freq = 1; + break; default: return -EINVAL; } + + if (extended_freq && !priv->drvdata->extended_frequencies) + return -EINVAL; + snd_soc_update_bits(codec, MD_CTL1, PLL_MASK, pll);
return 0; @@ -525,6 +544,7 @@ static const struct ak4642_drvdata ak4643_drvdata = {
static const struct ak4642_drvdata ak4648_drvdata = { .regmap_config = &ak4648_regmap, + .extended_frequencies = 1, };
static struct of_device_id ak4642_of_match[];
On Wed, May 14, 2014 at 09:37:36AM +0200, Sascha Hauer wrote:
Additionally to the ak4642 pll frequencies the ak4648 also supports 13MHz, 19.2MHz and 26MHz. This adds support for these frequencies.
Applied, thanks. However...
- case 19200000:
pll = PLL3;
extended_freq = 1;
break;
- case 13000000:
pll = PLL3 | PLL2 | PLL1;
extended_freq = 1;
break;
- case 26000000:
...the sorting here is a bit odd - we do 19.2MHz then 13MHz then 26MHz.
Signed-off-by: Sascha Hauer s.hauer@pengutronix.de --- sound/soc/codecs/ak4642.c | 114 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 114 insertions(+)
diff --git a/sound/soc/codecs/ak4642.c b/sound/soc/codecs/ak4642.c index 3ba4c0f..6292a6a 100644 --- a/sound/soc/codecs/ak4642.c +++ b/sound/soc/codecs/ak4642.c @@ -153,6 +153,81 @@ struct ak4642_priv { */ static const DECLARE_TLV_DB_SCALE(out_tlv, -11550, 50, 1);
+static const char * const ak4642_micl_strings[] = { "LIN1", "LIN2", "LIN3", "LIN4" }; +static const char * const ak4642_micr_strings[] = { "RIN1", "RIN2", "RIN3", "RIN4" }; + +static const struct soc_enum ak4642_micl_enum = + SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(ak4642_micl_strings), + ak4642_micl_strings); + +static const struct soc_enum ak4642_micr_enum = + SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(ak4642_micr_strings), + ak4642_micr_strings); + +static int ak4642_micl_enum_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_codec *codec = snd_soc_dapm_kcontrol_codec(kcontrol); + u32 val, inl; + + val = snd_soc_read(codec, PW_MGMT3); + + inl = (val >> 1) & 0x1; + inl |= (val >> 5) & 0x2; + + ucontrol->value.integer.value[0] = inl; + + return 0; +} + +static int ak4642_micl_enum_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_codec *codec = snd_soc_dapm_kcontrol_codec(kcontrol); + int val, inl; + + val = ucontrol->value.integer.value[0]; + + inl = (val & 0x1) << 1; + inl |= (val & 0x2) << 5; + + snd_soc_update_bits(codec, PW_MGMT3, (1 << 1) | (1 << 6), inl); + + return 1; +} + +static int ak4642_micr_enum_get(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_codec *codec = snd_soc_dapm_kcontrol_codec(kcontrol); + u32 val, inr; + + val = snd_soc_read(codec, PW_MGMT3); + + inr = (val >> 2) & 0x1; + inr |= (val >> 6) & 0x2; + + ucontrol->value.integer.value[0] = inr; + + return 0; +} + +static int ak4642_micr_enum_put(struct snd_kcontrol *kcontrol, + struct snd_ctl_elem_value *ucontrol) +{ + struct snd_soc_codec *codec = snd_soc_dapm_kcontrol_codec(kcontrol); + int val, inr; + + val = ucontrol->value.integer.value[0]; + + inr = (val & 0x1) << 2; + inr |= (val & 0x2) << 6; + + snd_soc_update_bits(codec, PW_MGMT3, (1 << 2) | (1 << 7), inr); + + return 1; +} + static const struct snd_kcontrol_new ak4642_snd_controls[] = {
SOC_DOUBLE_R_TLV("Digital Playback Volume", L_DVC, R_DVC, @@ -168,6 +243,16 @@ static const struct snd_kcontrol_new ak4642_lout_mixer_controls[] = { SOC_DAPM_SINGLE("DACL", SG_SL1, 4, 1, 0), };
+static const struct snd_kcontrol_new ak4642_micl_controls[] = { + SOC_ENUM_EXT("Mic Left Capture Route", ak4642_micl_enum, + ak4642_micl_enum_get, ak4642_micl_enum_put), +}; + +static const struct snd_kcontrol_new ak4642_micr_controls[] = { + SOC_ENUM_EXT("Mic Right Capture Route", ak4642_micr_enum, + ak4642_micr_enum_get, ak4642_micr_enum_put), +}; + static const struct snd_soc_dapm_widget ak4642_dapm_widgets[] = {
/* Outputs */ @@ -188,6 +273,22 @@ static const struct snd_soc_dapm_widget ak4642_dapm_widgets[] = {
/* DAC */ SND_SOC_DAPM_DAC("DAC", "HiFi Playback", PW_MGMT1, 2, 0), + + SND_SOC_DAPM_ADC("ADC", "Capture", SND_SOC_NOPM, 0, 0), + + SND_SOC_DAPM_MUX("Mic Left Capture Route", + SND_SOC_NOPM, 0, 0, ak4642_micl_controls), + SND_SOC_DAPM_MUX("Mic Right Capture Route", + SND_SOC_NOPM, 0, 0, ak4642_micr_controls), + + SND_SOC_DAPM_INPUT("LIN1"), + SND_SOC_DAPM_INPUT("LIN2"), + SND_SOC_DAPM_INPUT("LIN3"), + SND_SOC_DAPM_INPUT("LIN4"), + SND_SOC_DAPM_INPUT("RIN1"), + SND_SOC_DAPM_INPUT("RIN2"), + SND_SOC_DAPM_INPUT("RIN3"), + SND_SOC_DAPM_INPUT("RIN4"), };
static const struct snd_soc_dapm_route ak4642_intercon[] = { @@ -205,6 +306,19 @@ static const struct snd_soc_dapm_route ak4642_intercon[] = { {"DACH", NULL, "DAC"},
{"LINEOUT Mixer", "DACL", "DAC"}, + + {"Mic Left Capture Route", "LIN1", "LIN1"}, + {"Mic Left Capture Route", NULL, "LIN2"}, + {"Mic Left Capture Route", NULL, "LIN3"}, + {"Mic Left Capture Route", NULL, "LIN4"}, + + {"Mic Right Capture Route", "RIN1", "RIN1"}, + {"Mic Right Capture Route", NULL, "RIN2"}, + {"Mic Right Capture Route", NULL, "RIN3"}, + {"Mic Right Capture Route", NULL, "RIN4"}, + + {"ADC", NULL, "Mic Right Capture Route"}, + {"ADC", NULL, "Mic Left Capture Route"}, };
/*
On Wed, May 14, 2014 at 09:37:37AM +0200, Sascha Hauer wrote:
Signed-off-by: Sascha Hauer s.hauer@pengutronix.de
sound/soc/codecs/ak4642.c | 114 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 114 insertions(+)
I'll rework this patch. I just realized that it is only valid for the ak4648. The ak4642 does not have that many microphone in sources.
Sasca
diff --git a/sound/soc/codecs/ak4642.c b/sound/soc/codecs/ak4642.c index 3ba4c0f..6292a6a 100644 --- a/sound/soc/codecs/ak4642.c +++ b/sound/soc/codecs/ak4642.c @@ -153,6 +153,81 @@ struct ak4642_priv { */ static const DECLARE_TLV_DB_SCALE(out_tlv, -11550, 50, 1);
+static const char * const ak4642_micl_strings[] = { "LIN1", "LIN2", "LIN3", "LIN4" }; +static const char * const ak4642_micr_strings[] = { "RIN1", "RIN2", "RIN3", "RIN4" };
+static const struct soc_enum ak4642_micl_enum =
- SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(ak4642_micl_strings),
ak4642_micl_strings);
+static const struct soc_enum ak4642_micr_enum =
- SOC_ENUM_SINGLE_EXT(ARRAY_SIZE(ak4642_micr_strings),
ak4642_micr_strings);
+static int ak4642_micl_enum_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
+{
- struct snd_soc_codec *codec = snd_soc_dapm_kcontrol_codec(kcontrol);
- u32 val, inl;
- val = snd_soc_read(codec, PW_MGMT3);
- inl = (val >> 1) & 0x1;
- inl |= (val >> 5) & 0x2;
- ucontrol->value.integer.value[0] = inl;
- return 0;
+}
+static int ak4642_micl_enum_put(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
+{
- struct snd_soc_codec *codec = snd_soc_dapm_kcontrol_codec(kcontrol);
- int val, inl;
- val = ucontrol->value.integer.value[0];
- inl = (val & 0x1) << 1;
- inl |= (val & 0x2) << 5;
- snd_soc_update_bits(codec, PW_MGMT3, (1 << 1) | (1 << 6), inl);
- return 1;
+}
+static int ak4642_micr_enum_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
+{
- struct snd_soc_codec *codec = snd_soc_dapm_kcontrol_codec(kcontrol);
- u32 val, inr;
- val = snd_soc_read(codec, PW_MGMT3);
- inr = (val >> 2) & 0x1;
- inr |= (val >> 6) & 0x2;
- ucontrol->value.integer.value[0] = inr;
- return 0;
+}
+static int ak4642_micr_enum_put(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
+{
- struct snd_soc_codec *codec = snd_soc_dapm_kcontrol_codec(kcontrol);
- int val, inr;
- val = ucontrol->value.integer.value[0];
- inr = (val & 0x1) << 2;
- inr |= (val & 0x2) << 6;
- snd_soc_update_bits(codec, PW_MGMT3, (1 << 2) | (1 << 7), inr);
- return 1;
+}
static const struct snd_kcontrol_new ak4642_snd_controls[] = {
SOC_DOUBLE_R_TLV("Digital Playback Volume", L_DVC, R_DVC, @@ -168,6 +243,16 @@ static const struct snd_kcontrol_new ak4642_lout_mixer_controls[] = { SOC_DAPM_SINGLE("DACL", SG_SL1, 4, 1, 0), };
+static const struct snd_kcontrol_new ak4642_micl_controls[] = {
- SOC_ENUM_EXT("Mic Left Capture Route", ak4642_micl_enum,
ak4642_micl_enum_get, ak4642_micl_enum_put),
+};
+static const struct snd_kcontrol_new ak4642_micr_controls[] = {
- SOC_ENUM_EXT("Mic Right Capture Route", ak4642_micr_enum,
ak4642_micr_enum_get, ak4642_micr_enum_put),
+};
static const struct snd_soc_dapm_widget ak4642_dapm_widgets[] = {
/* Outputs */ @@ -188,6 +273,22 @@ static const struct snd_soc_dapm_widget ak4642_dapm_widgets[] = {
/* DAC */ SND_SOC_DAPM_DAC("DAC", "HiFi Playback", PW_MGMT1, 2, 0),
- SND_SOC_DAPM_ADC("ADC", "Capture", SND_SOC_NOPM, 0, 0),
- SND_SOC_DAPM_MUX("Mic Left Capture Route",
SND_SOC_NOPM, 0, 0, ak4642_micl_controls),
- SND_SOC_DAPM_MUX("Mic Right Capture Route",
SND_SOC_NOPM, 0, 0, ak4642_micr_controls),
- SND_SOC_DAPM_INPUT("LIN1"),
- SND_SOC_DAPM_INPUT("LIN2"),
- SND_SOC_DAPM_INPUT("LIN3"),
- SND_SOC_DAPM_INPUT("LIN4"),
- SND_SOC_DAPM_INPUT("RIN1"),
- SND_SOC_DAPM_INPUT("RIN2"),
- SND_SOC_DAPM_INPUT("RIN3"),
- SND_SOC_DAPM_INPUT("RIN4"),
};
static const struct snd_soc_dapm_route ak4642_intercon[] = { @@ -205,6 +306,19 @@ static const struct snd_soc_dapm_route ak4642_intercon[] = { {"DACH", NULL, "DAC"},
{"LINEOUT Mixer", "DACL", "DAC"},
- {"Mic Left Capture Route", "LIN1", "LIN1"},
- {"Mic Left Capture Route", NULL, "LIN2"},
- {"Mic Left Capture Route", NULL, "LIN3"},
- {"Mic Left Capture Route", NULL, "LIN4"},
- {"Mic Right Capture Route", "RIN1", "RIN1"},
- {"Mic Right Capture Route", NULL, "RIN2"},
- {"Mic Right Capture Route", NULL, "RIN3"},
- {"Mic Right Capture Route", NULL, "RIN4"},
- {"ADC", NULL, "Mic Right Capture Route"},
- {"ADC", NULL, "Mic Left Capture Route"},
};
/*
2.0.0.rc0
Signed-off-by: Sascha Hauer s.hauer@pengutronix.de --- Documentation/devicetree/bindings/sound/ak4642.txt | 3 ++ sound/soc/codecs/ak4642.c | 41 ++++++++++++++++++++++ 2 files changed, 44 insertions(+)
diff --git a/Documentation/devicetree/bindings/sound/ak4642.txt b/Documentation/devicetree/bindings/sound/ak4642.txt index 623d4e7..21bc8ef 100644 --- a/Documentation/devicetree/bindings/sound/ak4642.txt +++ b/Documentation/devicetree/bindings/sound/ak4642.txt @@ -7,6 +7,9 @@ Required properties: - compatible : "asahi-kasei,ak4642" or "asahi-kasei,ak4643" or "asahi-kasei,ak4648" - reg : The chip select number on the I2C bus
+Optional properties: + - enable-gpios : contains a GPIO used to enable the codec + Example:
&i2c { diff --git a/sound/soc/codecs/ak4642.c b/sound/soc/codecs/ak4642.c index 6292a6a..67b8c25 100644 --- a/sound/soc/codecs/ak4642.c +++ b/sound/soc/codecs/ak4642.c @@ -29,6 +29,7 @@ #include <linux/of_device.h> #include <linux/module.h> #include <linux/regmap.h> +#include <linux/gpio/consumer.h> #include <sound/soc.h> #include <sound/initval.h> #include <sound/tlv.h> @@ -141,6 +142,7 @@ struct ak4642_drvdata {
struct ak4642_priv { const struct ak4642_drvdata *drvdata; + struct gpio_desc *pdn_gpio; };
/* @@ -596,9 +598,23 @@ static struct snd_soc_dai_driver ak4642_dai = { .symmetric_rates = 1, };
+static int ak4642_suspend(struct snd_soc_codec *codec) +{ + struct ak4642_priv *priv = snd_soc_codec_get_drvdata(codec); + + if (priv->pdn_gpio) + gpiod_set_value(priv->pdn_gpio, 0); + + return 0; +} + static int ak4642_resume(struct snd_soc_codec *codec) { struct regmap *regmap = dev_get_regmap(codec->dev, NULL); + struct ak4642_priv *priv = snd_soc_codec_get_drvdata(codec); + + if (priv->pdn_gpio) + gpiod_set_value(priv->pdn_gpio, 1);
regcache_mark_dirty(regmap); regcache_sync(regmap); @@ -608,6 +624,15 @@ static int ak4642_resume(struct snd_soc_codec *codec)
static int ak4642_probe(struct snd_soc_codec *codec) { + struct ak4642_priv *priv = snd_soc_codec_get_drvdata(codec); + int ret; + + if (priv->pdn_gpio) { + ret = gpiod_direction_output(priv->pdn_gpio, 1); + if (ret) + return ret; + } + ak4642_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
return 0; @@ -615,13 +640,20 @@ static int ak4642_probe(struct snd_soc_codec *codec)
static int ak4642_remove(struct snd_soc_codec *codec) { + struct ak4642_priv *priv = snd_soc_codec_get_drvdata(codec); + ak4642_set_bias_level(codec, SND_SOC_BIAS_OFF); + + if (priv->pdn_gpio) + gpiod_set_value(priv->pdn_gpio, 0); + return 0; }
static struct snd_soc_codec_driver soc_codec_dev_ak4642 = { .probe = ak4642_probe, .remove = ak4642_remove, + .suspend = ak4642_suspend, .resume = ak4642_resume, .set_bias_level = ak4642_set_bias_level, .controls = ak4642_snd_controls, @@ -669,6 +701,7 @@ static int ak4642_i2c_probe(struct i2c_client *i2c, const struct ak4642_drvdata *drvdata = NULL; struct regmap *regmap; struct ak4642_priv *priv; + struct gpio_desc *gpio;
if (np) { const struct of_device_id *of_id; @@ -691,6 +724,14 @@ static int ak4642_i2c_probe(struct i2c_client *i2c,
priv->drvdata = drvdata;
+ gpio = devm_gpiod_get(&i2c->dev, "enable"); + if (IS_ERR(gpio)) { + if (PTR_ERR(gpio) != -ENOENT) + return PTR_ERR(gpio); + } else { + priv->pdn_gpio = gpio; + } + i2c_set_clientdata(i2c, priv);
regmap = devm_regmap_init_i2c(i2c, drvdata->regmap_config);
participants (2)
-
Mark Brown
-
Sascha Hauer