[alsa-devel] [PATCH v3 00/10] Add Headphone Detection to TLV320AIC31xx Driver
Hello all,
This series has the end goal of adding headphone detection to the tlv320aic31xx driver. The first few patches are mostly cleanups. Then a couple bug fixes I noticed. Followed by adding interrupt handling and finally headphone detection.
Still not sure if the IRQ patch is correct, I think we have no good way to share this IRQ line, so leaving it the way it is for now.
Thanks, Andrew
Changes from v2: - Rebased on -next - Added delta patch for GPIO header fix - Split platform data remove into fwnode and pdata removal - Rework reset patch to print error code - Use snd_soc_codec_set_jack to set jack
Changes from v1: - Splitup the cleanup patch a bit more - Move the GPIO1 register fix patch before header cleanup so it can be taken back into stable - Added Acked-by - New patch dealing with regulator notifications - Various small touchups - Rebased on v4.15-rc1
Andrew F. Davis (10): ASoC: tlv320aic31xx: Fix GPIO header includes ASoC: tlv320aic31xx: Use fwnode APIs over raw OF calls ASoC: tlv320aic31xx: Remove platform data ASoC: tlv320aic31xx: Add MICBIAS off setting ASoC: tlv320aic31xx: Remove regulator notification handling ASoC: tlv320aic31xx: Reset registers during power up ASoC: tlv320aic31xx: Add short circuit detection support ASoC: tlv320aic31xx: Add overflow detection support ASoC: tlv320aic31xx: Add headphone/headset detection ASoC: tlv320aic31xx: Add button press detection
.../devicetree/bindings/sound/tlv320aic31xx.txt | 1 + include/dt-bindings/sound/tlv320aic31xx-micbias.h | 1 + sound/soc/codecs/tlv320aic31xx.c | 263 +++++++++++++-------- sound/soc/codecs/tlv320aic31xx.h | 41 +++- 4 files changed, 196 insertions(+), 110 deletions(-)
Use of gpiod_* needs <linux/gpio/consumer.h>, add this here.
Fixes: b6b247cd5e37 ("ASoC: tlv320aic31xx: Switch GPIO handling to use gpiod_* API") Signed-off-by: Andrew F. Davis afd@ti.com --- sound/soc/codecs/tlv320aic31xx.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/sound/soc/codecs/tlv320aic31xx.c b/sound/soc/codecs/tlv320aic31xx.c index 38fd6ea275fb..13471a900085 100644 --- a/sound/soc/codecs/tlv320aic31xx.c +++ b/sound/soc/codecs/tlv320aic31xx.c @@ -18,7 +18,7 @@ #include <linux/delay.h> #include <linux/pm.h> #include <linux/i2c.h> -#include <linux/gpio.h> +#include <linux/gpio/consumer.h> #include <linux/regulator/consumer.h> #include <linux/acpi.h> #include <linux/of.h>
The patch
ASoC: tlv320aic31xx: Fix GPIO header includes
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 283c35062f778fc40f8eb5dc004ca37a7208ea66 Mon Sep 17 00:00:00 2001
From: "Andrew F. Davis" afd@ti.com Date: Thu, 7 Dec 2017 09:38:51 -0600 Subject: [PATCH] ASoC: tlv320aic31xx: Fix GPIO header includes
Use of gpiod_* needs <linux/gpio/consumer.h>, add this here.
Fixes: b6b247cd5e37 ("ASoC: tlv320aic31xx: Switch GPIO handling to use gpiod_* API") Signed-off-by: Andrew F. Davis afd@ti.com Signed-off-by: Mark Brown broonie@kernel.org --- sound/soc/codecs/tlv320aic31xx.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/sound/soc/codecs/tlv320aic31xx.c b/sound/soc/codecs/tlv320aic31xx.c index 38fd6ea275fb..13471a900085 100644 --- a/sound/soc/codecs/tlv320aic31xx.c +++ b/sound/soc/codecs/tlv320aic31xx.c @@ -18,7 +18,7 @@ #include <linux/delay.h> #include <linux/pm.h> #include <linux/i2c.h> -#include <linux/gpio.h> +#include <linux/gpio/consumer.h> #include <linux/regulator/consumer.h> #include <linux/acpi.h> #include <linux/of.h>
Use fwnode_* API instead of of_*, the results are the same but fwnode_* is cleaner and we get ACPI support.
Signed-off-by: Andrew F. Davis afd@ti.com --- sound/soc/codecs/tlv320aic31xx.c | 77 +++++++++++++++------------------------- 1 file changed, 29 insertions(+), 48 deletions(-)
diff --git a/sound/soc/codecs/tlv320aic31xx.c b/sound/soc/codecs/tlv320aic31xx.c index 13471a900085..655c99db2426 100644 --- a/sound/soc/codecs/tlv320aic31xx.c +++ b/sound/soc/codecs/tlv320aic31xx.c @@ -157,7 +157,9 @@ struct aic31xx_priv { u8 i2c_regs_status; struct device *dev; struct regmap *regmap; + enum aic31xx_type codec_type; struct gpio_desc *gpio_reset; + int micbias_vg; struct aic31xx_pdata pdata; struct regulator_bulk_data supplies[AIC31XX_NUM_SUPPLIES]; struct aic31xx_disable_nb disable_nb[AIC31XX_NUM_SUPPLIES]; @@ -450,7 +452,7 @@ static int mic_bias_event(struct snd_soc_dapm_widget *w, /* change mic bias voltage to user defined */ snd_soc_update_bits(codec, AIC31XX_MICBIAS, AIC31XX_MICBIAS_MASK, - aic31xx->pdata.micbias_vg << + aic31xx->micbias_vg << AIC31XX_MICBIAS_SHIFT); dev_dbg(codec->dev, "%s: turned on\n", __func__); break; @@ -673,14 +675,14 @@ static int aic31xx_add_controls(struct snd_soc_codec *codec) int ret = 0; struct aic31xx_priv *aic31xx = snd_soc_codec_get_drvdata(codec);
- if (!(aic31xx->pdata.codec_type & DAC31XX_BIT)) + if (!(aic31xx->codec_type & DAC31XX_BIT)) ret = snd_soc_add_codec_controls( codec, aic31xx_snd_controls, ARRAY_SIZE(aic31xx_snd_controls)); if (ret) return ret;
- if (aic31xx->pdata.codec_type & AIC31XX_STEREO_CLASS_D_BIT) + if (aic31xx->codec_type & AIC31XX_STEREO_CLASS_D_BIT) ret = snd_soc_add_codec_controls( codec, aic311x_snd_controls, ARRAY_SIZE(aic311x_snd_controls)); @@ -698,7 +700,7 @@ static int aic31xx_add_widgets(struct snd_soc_codec *codec) struct aic31xx_priv *aic31xx = snd_soc_codec_get_drvdata(codec); int ret = 0;
- if (aic31xx->pdata.codec_type & DAC31XX_BIT) { + if (aic31xx->codec_type & DAC31XX_BIT) { ret = snd_soc_dapm_new_controls( dapm, dac31xx_dapm_widgets, ARRAY_SIZE(dac31xx_dapm_widgets)); @@ -722,7 +724,7 @@ static int aic31xx_add_widgets(struct snd_soc_codec *codec) return ret; }
- if (aic31xx->pdata.codec_type & AIC31XX_STEREO_CLASS_D_BIT) { + if (aic31xx->codec_type & AIC31XX_STEREO_CLASS_D_BIT) { ret = snd_soc_dapm_new_controls( dapm, aic311x_dapm_widgets, ARRAY_SIZE(aic311x_dapm_widgets)); @@ -1279,42 +1281,6 @@ static const struct of_device_id tlv320aic31xx_of_match[] = { {}, }; MODULE_DEVICE_TABLE(of, tlv320aic31xx_of_match); - -static void aic31xx_pdata_from_of(struct aic31xx_priv *aic31xx) -{ - struct device_node *np = aic31xx->dev->of_node; - unsigned int value = MICBIAS_2_0V; - int ret; - - of_property_read_u32(np, "ai31xx-micbias-vg", &value); - switch (value) { - case MICBIAS_2_0V: - case MICBIAS_2_5V: - case MICBIAS_AVDDV: - aic31xx->pdata.micbias_vg = value; - break; - default: - dev_err(aic31xx->dev, - "Bad ai31xx-micbias-vg value %d DT\n", - value); - aic31xx->pdata.micbias_vg = MICBIAS_2_0V; - } - - ret = of_get_named_gpio(np, "reset-gpios", 0); - if (ret > 0) { - aic31xx->pdata.gpio_reset = ret; - } else { - ret = of_get_named_gpio(np, "gpio-reset", 0); - if (ret > 0) { - dev_warn(aic31xx->dev, "Using deprecated property "gpio-reset", please update your DT"); - aic31xx->pdata.gpio_reset = ret; - } - } -} -#else /* CONFIG_OF */ -static void aic31xx_pdata_from_of(struct aic31xx_priv *aic31xx) -{ -} #endif /* CONFIG_OF */
#ifdef CONFIG_ACPI @@ -1329,6 +1295,7 @@ static int aic31xx_i2c_probe(struct i2c_client *i2c, const struct i2c_device_id *id) { struct aic31xx_priv *aic31xx; + unsigned int micbias_value = MICBIAS_2_0V; int i, ret;
dev_dbg(&i2c->dev, "## %s: %s codec_type = %d\n", __func__, @@ -1347,15 +1314,29 @@ static int aic31xx_i2c_probe(struct i2c_client *i2c, } aic31xx->dev = &i2c->dev;
- aic31xx->pdata.codec_type = id->driver_data; + aic31xx->codec_type = id->driver_data;
dev_set_drvdata(aic31xx->dev, aic31xx);
- if (dev_get_platdata(aic31xx->dev)) - memcpy(&aic31xx->pdata, dev_get_platdata(aic31xx->dev), - sizeof(aic31xx->pdata)); - else if (aic31xx->dev->of_node) - aic31xx_pdata_from_of(aic31xx); + fwnode_property_read_u32(aic31xx->dev->fwnode, "ai31xx-micbias-vg", + &micbias_value); + switch (micbias_value) { + case MICBIAS_2_0V: + case MICBIAS_2_5V: + case MICBIAS_AVDDV: + aic31xx->micbias_vg = micbias_value; + break; + default: + dev_err(aic31xx->dev, "Bad ai31xx-micbias-vg value %d\n", + micbias_value); + aic31xx->micbias_vg = MICBIAS_2_0V; + } + + if (dev_get_platdata(aic31xx->dev)) { + memcpy(&aic31xx->pdata, dev_get_platdata(aic31xx->dev), sizeof(aic31xx->pdata)); + aic31xx->codec_type = aic31xx->pdata.codec_type; + aic31xx->micbias_vg = aic31xx->pdata.micbias_vg; + }
aic31xx->gpio_reset = devm_gpiod_get_optional(aic31xx->dev, "reset", GPIOD_OUT_LOW); @@ -1375,7 +1356,7 @@ static int aic31xx_i2c_probe(struct i2c_client *i2c, return ret; }
- if (aic31xx->pdata.codec_type & DAC31XX_BIT) + if (aic31xx->codec_type & DAC31XX_BIT) return snd_soc_register_codec(&i2c->dev, &soc_codec_driver_aic31xx, dac31xx_dai_driver,
The patch
ASoC: tlv320aic31xx: Use fwnode APIs over raw OF calls
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 cd15da88c358e9987a3b16bc821c980dd2377776 Mon Sep 17 00:00:00 2001
From: "Andrew F. Davis" afd@ti.com Date: Thu, 7 Dec 2017 09:38:52 -0600 Subject: [PATCH] ASoC: tlv320aic31xx: Use fwnode APIs over raw OF calls
Use fwnode_* API instead of of_*, the results are the same but fwnode_* is cleaner and we get ACPI support.
Signed-off-by: Andrew F. Davis afd@ti.com Signed-off-by: Mark Brown broonie@kernel.org --- sound/soc/codecs/tlv320aic31xx.c | 77 +++++++++++++++------------------------- 1 file changed, 29 insertions(+), 48 deletions(-)
diff --git a/sound/soc/codecs/tlv320aic31xx.c b/sound/soc/codecs/tlv320aic31xx.c index 13471a900085..655c99db2426 100644 --- a/sound/soc/codecs/tlv320aic31xx.c +++ b/sound/soc/codecs/tlv320aic31xx.c @@ -157,7 +157,9 @@ struct aic31xx_priv { u8 i2c_regs_status; struct device *dev; struct regmap *regmap; + enum aic31xx_type codec_type; struct gpio_desc *gpio_reset; + int micbias_vg; struct aic31xx_pdata pdata; struct regulator_bulk_data supplies[AIC31XX_NUM_SUPPLIES]; struct aic31xx_disable_nb disable_nb[AIC31XX_NUM_SUPPLIES]; @@ -450,7 +452,7 @@ static int mic_bias_event(struct snd_soc_dapm_widget *w, /* change mic bias voltage to user defined */ snd_soc_update_bits(codec, AIC31XX_MICBIAS, AIC31XX_MICBIAS_MASK, - aic31xx->pdata.micbias_vg << + aic31xx->micbias_vg << AIC31XX_MICBIAS_SHIFT); dev_dbg(codec->dev, "%s: turned on\n", __func__); break; @@ -673,14 +675,14 @@ static int aic31xx_add_controls(struct snd_soc_codec *codec) int ret = 0; struct aic31xx_priv *aic31xx = snd_soc_codec_get_drvdata(codec);
- if (!(aic31xx->pdata.codec_type & DAC31XX_BIT)) + if (!(aic31xx->codec_type & DAC31XX_BIT)) ret = snd_soc_add_codec_controls( codec, aic31xx_snd_controls, ARRAY_SIZE(aic31xx_snd_controls)); if (ret) return ret;
- if (aic31xx->pdata.codec_type & AIC31XX_STEREO_CLASS_D_BIT) + if (aic31xx->codec_type & AIC31XX_STEREO_CLASS_D_BIT) ret = snd_soc_add_codec_controls( codec, aic311x_snd_controls, ARRAY_SIZE(aic311x_snd_controls)); @@ -698,7 +700,7 @@ static int aic31xx_add_widgets(struct snd_soc_codec *codec) struct aic31xx_priv *aic31xx = snd_soc_codec_get_drvdata(codec); int ret = 0;
- if (aic31xx->pdata.codec_type & DAC31XX_BIT) { + if (aic31xx->codec_type & DAC31XX_BIT) { ret = snd_soc_dapm_new_controls( dapm, dac31xx_dapm_widgets, ARRAY_SIZE(dac31xx_dapm_widgets)); @@ -722,7 +724,7 @@ static int aic31xx_add_widgets(struct snd_soc_codec *codec) return ret; }
- if (aic31xx->pdata.codec_type & AIC31XX_STEREO_CLASS_D_BIT) { + if (aic31xx->codec_type & AIC31XX_STEREO_CLASS_D_BIT) { ret = snd_soc_dapm_new_controls( dapm, aic311x_dapm_widgets, ARRAY_SIZE(aic311x_dapm_widgets)); @@ -1279,42 +1281,6 @@ static const struct of_device_id tlv320aic31xx_of_match[] = { {}, }; MODULE_DEVICE_TABLE(of, tlv320aic31xx_of_match); - -static void aic31xx_pdata_from_of(struct aic31xx_priv *aic31xx) -{ - struct device_node *np = aic31xx->dev->of_node; - unsigned int value = MICBIAS_2_0V; - int ret; - - of_property_read_u32(np, "ai31xx-micbias-vg", &value); - switch (value) { - case MICBIAS_2_0V: - case MICBIAS_2_5V: - case MICBIAS_AVDDV: - aic31xx->pdata.micbias_vg = value; - break; - default: - dev_err(aic31xx->dev, - "Bad ai31xx-micbias-vg value %d DT\n", - value); - aic31xx->pdata.micbias_vg = MICBIAS_2_0V; - } - - ret = of_get_named_gpio(np, "reset-gpios", 0); - if (ret > 0) { - aic31xx->pdata.gpio_reset = ret; - } else { - ret = of_get_named_gpio(np, "gpio-reset", 0); - if (ret > 0) { - dev_warn(aic31xx->dev, "Using deprecated property "gpio-reset", please update your DT"); - aic31xx->pdata.gpio_reset = ret; - } - } -} -#else /* CONFIG_OF */ -static void aic31xx_pdata_from_of(struct aic31xx_priv *aic31xx) -{ -} #endif /* CONFIG_OF */
#ifdef CONFIG_ACPI @@ -1329,6 +1295,7 @@ static int aic31xx_i2c_probe(struct i2c_client *i2c, const struct i2c_device_id *id) { struct aic31xx_priv *aic31xx; + unsigned int micbias_value = MICBIAS_2_0V; int i, ret;
dev_dbg(&i2c->dev, "## %s: %s codec_type = %d\n", __func__, @@ -1347,15 +1314,29 @@ static int aic31xx_i2c_probe(struct i2c_client *i2c, } aic31xx->dev = &i2c->dev;
- aic31xx->pdata.codec_type = id->driver_data; + aic31xx->codec_type = id->driver_data;
dev_set_drvdata(aic31xx->dev, aic31xx);
- if (dev_get_platdata(aic31xx->dev)) - memcpy(&aic31xx->pdata, dev_get_platdata(aic31xx->dev), - sizeof(aic31xx->pdata)); - else if (aic31xx->dev->of_node) - aic31xx_pdata_from_of(aic31xx); + fwnode_property_read_u32(aic31xx->dev->fwnode, "ai31xx-micbias-vg", + &micbias_value); + switch (micbias_value) { + case MICBIAS_2_0V: + case MICBIAS_2_5V: + case MICBIAS_AVDDV: + aic31xx->micbias_vg = micbias_value; + break; + default: + dev_err(aic31xx->dev, "Bad ai31xx-micbias-vg value %d\n", + micbias_value); + aic31xx->micbias_vg = MICBIAS_2_0V; + } + + if (dev_get_platdata(aic31xx->dev)) { + memcpy(&aic31xx->pdata, dev_get_platdata(aic31xx->dev), sizeof(aic31xx->pdata)); + aic31xx->codec_type = aic31xx->pdata.codec_type; + aic31xx->micbias_vg = aic31xx->pdata.micbias_vg; + }
aic31xx->gpio_reset = devm_gpiod_get_optional(aic31xx->dev, "reset", GPIOD_OUT_LOW); @@ -1375,7 +1356,7 @@ static int aic31xx_i2c_probe(struct i2c_client *i2c, return ret; }
- if (aic31xx->pdata.codec_type & DAC31XX_BIT) + if (aic31xx->codec_type & DAC31XX_BIT) return snd_soc_register_codec(&i2c->dev, &soc_codec_driver_aic31xx, dac31xx_dai_driver,
Platform data is not used by anyone (at least in upstream) so drop this data.
Signed-off-by: Andrew F. Davis afd@ti.com --- sound/soc/codecs/tlv320aic31xx.c | 7 ------- sound/soc/codecs/tlv320aic31xx.h | 6 ------ 2 files changed, 13 deletions(-)
diff --git a/sound/soc/codecs/tlv320aic31xx.c b/sound/soc/codecs/tlv320aic31xx.c index 655c99db2426..266141d841e7 100644 --- a/sound/soc/codecs/tlv320aic31xx.c +++ b/sound/soc/codecs/tlv320aic31xx.c @@ -160,7 +160,6 @@ struct aic31xx_priv { enum aic31xx_type codec_type; struct gpio_desc *gpio_reset; int micbias_vg; - struct aic31xx_pdata pdata; struct regulator_bulk_data supplies[AIC31XX_NUM_SUPPLIES]; struct aic31xx_disable_nb disable_nb[AIC31XX_NUM_SUPPLIES]; unsigned int sysclk; @@ -1332,12 +1331,6 @@ static int aic31xx_i2c_probe(struct i2c_client *i2c, aic31xx->micbias_vg = MICBIAS_2_0V; }
- if (dev_get_platdata(aic31xx->dev)) { - memcpy(&aic31xx->pdata, dev_get_platdata(aic31xx->dev), sizeof(aic31xx->pdata)); - aic31xx->codec_type = aic31xx->pdata.codec_type; - aic31xx->micbias_vg = aic31xx->pdata.micbias_vg; - } - aic31xx->gpio_reset = devm_gpiod_get_optional(aic31xx->dev, "reset", GPIOD_OUT_LOW); if (IS_ERR(aic31xx->gpio_reset)) { diff --git a/sound/soc/codecs/tlv320aic31xx.h b/sound/soc/codecs/tlv320aic31xx.h index 15ac7cba86fe..ab94e6a0c742 100644 --- a/sound/soc/codecs/tlv320aic31xx.h +++ b/sound/soc/codecs/tlv320aic31xx.h @@ -29,12 +29,6 @@ enum aic31xx_type { DAC3101 = DAC31XX_BIT | AIC31XX_STEREO_CLASS_D_BIT, };
-struct aic31xx_pdata { - enum aic31xx_type codec_type; - unsigned int gpio_reset; - int micbias_vg; -}; - #define AIC31XX_REG(page, reg) ((page * 128) + reg)
#define AIC31XX_PAGECTL AIC31XX_REG(0, 0) /* Page Control Register */
Leaving microphone bias off is a valid setting and even used in the DT binding document example. Add this setting here and document the same.
Signed-off-by: Andrew F. Davis afd@ti.com Acked-by: Rob Herring robh@kernel.org --- Documentation/devicetree/bindings/sound/tlv320aic31xx.txt | 1 + include/dt-bindings/sound/tlv320aic31xx-micbias.h | 1 + sound/soc/codecs/tlv320aic31xx.c | 1 + 3 files changed, 3 insertions(+)
diff --git a/Documentation/devicetree/bindings/sound/tlv320aic31xx.txt b/Documentation/devicetree/bindings/sound/tlv320aic31xx.txt index 5b3c33bb99e5..411cc46a2c58 100644 --- a/Documentation/devicetree/bindings/sound/tlv320aic31xx.txt +++ b/Documentation/devicetree/bindings/sound/tlv320aic31xx.txt @@ -24,6 +24,7 @@ Optional properties:
- reset-gpios - GPIO specification for the active low RESET input. - ai31xx-micbias-vg - MicBias Voltage setting + 0 or MICBIAS_OFF - MICBIAS output is powered off 1 or MICBIAS_2_0V - MICBIAS output is powered to 2.0V 2 or MICBIAS_2_5V - MICBIAS output is powered to 2.5V 3 or MICBIAS_AVDD - MICBIAS output is connected to AVDD diff --git a/include/dt-bindings/sound/tlv320aic31xx-micbias.h b/include/dt-bindings/sound/tlv320aic31xx-micbias.h index c6895a18a455..069484070fcf 100644 --- a/include/dt-bindings/sound/tlv320aic31xx-micbias.h +++ b/include/dt-bindings/sound/tlv320aic31xx-micbias.h @@ -2,6 +2,7 @@ #ifndef __DT_TLV320AIC31XX_MICBIAS_H #define __DT_TLV320AIC31XX_MICBIAS_H
+#define MICBIAS_OFF 0 #define MICBIAS_2_0V 1 #define MICBIAS_2_5V 2 #define MICBIAS_AVDDV 3 diff --git a/sound/soc/codecs/tlv320aic31xx.c b/sound/soc/codecs/tlv320aic31xx.c index 266141d841e7..44950c1f2532 100644 --- a/sound/soc/codecs/tlv320aic31xx.c +++ b/sound/soc/codecs/tlv320aic31xx.c @@ -1320,6 +1320,7 @@ static int aic31xx_i2c_probe(struct i2c_client *i2c, fwnode_property_read_u32(aic31xx->dev->fwnode, "ai31xx-micbias-vg", &micbias_value); switch (micbias_value) { + case MICBIAS_OFF: case MICBIAS_2_0V: case MICBIAS_2_5V: case MICBIAS_AVDDV:
A regulator being forcefully disabled is a catastrophic event that should never happen to most devices, especially not sound CODECs. In addition, our handler sets the reset line but never disables it as no one is listening for an enable event, this is certainly broken and was mosy likely just copied from other CODECs, lets just remove this code.
Signed-off-by: Andrew F. Davis afd@ti.com --- sound/soc/codecs/tlv320aic31xx.c | 57 +--------------------------------------- 1 file changed, 1 insertion(+), 56 deletions(-)
diff --git a/sound/soc/codecs/tlv320aic31xx.c b/sound/soc/codecs/tlv320aic31xx.c index 44950c1f2532..e2bb78188b61 100644 --- a/sound/soc/codecs/tlv320aic31xx.c +++ b/sound/soc/codecs/tlv320aic31xx.c @@ -147,11 +147,6 @@ static const char * const aic31xx_supply_names[] = {
#define AIC31XX_NUM_SUPPLIES ARRAY_SIZE(aic31xx_supply_names)
-struct aic31xx_disable_nb { - struct notifier_block nb; - struct aic31xx_priv *aic31xx; -}; - struct aic31xx_priv { struct snd_soc_codec *codec; u8 i2c_regs_status; @@ -161,7 +156,6 @@ struct aic31xx_priv { struct gpio_desc *gpio_reset; int micbias_vg; struct regulator_bulk_data supplies[AIC31XX_NUM_SUPPLIES]; - struct aic31xx_disable_nb disable_nb[AIC31XX_NUM_SUPPLIES]; unsigned int sysclk; u8 p_div; int rate_div_line; @@ -1032,28 +1026,6 @@ static int aic31xx_set_dai_sysclk(struct snd_soc_dai *codec_dai, return 0; }
-static int aic31xx_regulator_event(struct notifier_block *nb, - unsigned long event, void *data) -{ - struct aic31xx_disable_nb *disable_nb = - container_of(nb, struct aic31xx_disable_nb, nb); - struct aic31xx_priv *aic31xx = disable_nb->aic31xx; - - if (event & REGULATOR_EVENT_DISABLE) { - /* - * Put codec to reset and as at least one of the - * supplies was disabled. - */ - if (aic31xx->gpio_reset) - gpiod_set_value(aic31xx->gpio_reset, 1); - - regcache_mark_dirty(aic31xx->regmap); - dev_dbg(aic31xx->dev, "## %s: DISABLE received\n", __func__); - } - - return 0; -} - static void aic31xx_clk_on(struct snd_soc_codec *codec) { struct aic31xx_priv *aic31xx = snd_soc_codec_get_drvdata(codec); @@ -1161,26 +1133,12 @@ static int aic31xx_set_bias_level(struct snd_soc_codec *codec, static int aic31xx_codec_probe(struct snd_soc_codec *codec) { struct aic31xx_priv *aic31xx = snd_soc_codec_get_drvdata(codec); - int i, ret; + int ret;
dev_dbg(aic31xx->dev, "## %s\n", __func__);
aic31xx->codec = codec;
- for (i = 0; i < ARRAY_SIZE(aic31xx->supplies); i++) { - aic31xx->disable_nb[i].nb.notifier_call = - aic31xx_regulator_event; - aic31xx->disable_nb[i].aic31xx = aic31xx; - ret = regulator_register_notifier(aic31xx->supplies[i].consumer, - &aic31xx->disable_nb[i].nb); - if (ret) { - dev_err(codec->dev, - "Failed to request regulator notifier: %d\n", - ret); - return ret; - } - } - regcache_cache_only(aic31xx->regmap, true); regcache_mark_dirty(aic31xx->regmap);
@@ -1195,21 +1153,8 @@ static int aic31xx_codec_probe(struct snd_soc_codec *codec) return 0; }
-static int aic31xx_codec_remove(struct snd_soc_codec *codec) -{ - struct aic31xx_priv *aic31xx = snd_soc_codec_get_drvdata(codec); - int i; - - for (i = 0; i < ARRAY_SIZE(aic31xx->supplies); i++) - regulator_unregister_notifier(aic31xx->supplies[i].consumer, - &aic31xx->disable_nb[i].nb); - - return 0; -} - static const struct snd_soc_codec_driver soc_codec_driver_aic31xx = { .probe = aic31xx_codec_probe, - .remove = aic31xx_codec_remove, .set_bias_level = aic31xx_set_bias_level, .suspend_bias_off = true,
Add a reset function that toggles the reset line if available or uses the software reset command otherwise. Use this in power up to ensure the registers are in a sane state. This is useful when the driver module is reloaded, or after Kexec, warm-reboots, etc..
Signed-off-by: Andrew F. Davis afd@ti.com --- sound/soc/codecs/tlv320aic31xx.c | 26 ++++++++++++++++++++++---- 1 file changed, 22 insertions(+), 4 deletions(-)
diff --git a/sound/soc/codecs/tlv320aic31xx.c b/sound/soc/codecs/tlv320aic31xx.c index e2bb78188b61..6cbe5820ce60 100644 --- a/sound/soc/codecs/tlv320aic31xx.c +++ b/sound/soc/codecs/tlv320aic31xx.c @@ -1026,6 +1026,22 @@ static int aic31xx_set_dai_sysclk(struct snd_soc_dai *codec_dai, return 0; }
+static int aic31xx_reset(struct aic31xx_priv *aic31xx) +{ + int ret = 0; + + if (aic31xx->gpio_reset) { + gpiod_set_value(aic31xx->gpio_reset, 1); + ndelay(10); /* At least 10ns */ + gpiod_set_value(aic31xx->gpio_reset, 0); + } else { + ret = regmap_write(aic31xx->regmap, AIC31XX_RESET, 1); + } + mdelay(1); /* At least 1ms */ + + return ret; +} + static void aic31xx_clk_on(struct snd_soc_codec *codec) { struct aic31xx_priv *aic31xx = snd_soc_codec_get_drvdata(codec); @@ -1069,11 +1085,13 @@ static int aic31xx_power_on(struct snd_soc_codec *codec) if (ret) return ret;
- if (aic31xx->gpio_reset) { - gpiod_set_value(aic31xx->gpio_reset, 0); - udelay(100); - } regcache_cache_only(aic31xx->regmap, false); + + /* Reset device registers for a consistent power-on like state */ + ret = aic31xx_reset(aic31xx); + if (ret < 0) + dev_err(aic31xx->dev, "Could not reset device: %d\n", ret); + ret = regcache_sync(aic31xx->regmap); if (ret) { dev_err(codec->dev,
The patch
ASoC: tlv320aic31xx: Reset registers during power up
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 0ce918c9e070bf4fd17af0d76096ad184815bd79 Mon Sep 17 00:00:00 2001
From: "Andrew F. Davis" afd@ti.com Date: Thu, 7 Dec 2017 09:38:56 -0600 Subject: [PATCH] ASoC: tlv320aic31xx: Reset registers during power up
Add a reset function that toggles the reset line if available or uses the software reset command otherwise. Use this in power up to ensure the registers are in a sane state. This is useful when the driver module is reloaded, or after Kexec, warm-reboots, etc..
Signed-off-by: Andrew F. Davis afd@ti.com Signed-off-by: Mark Brown broonie@kernel.org --- sound/soc/codecs/tlv320aic31xx.c | 26 ++++++++++++++++++++++---- 1 file changed, 22 insertions(+), 4 deletions(-)
diff --git a/sound/soc/codecs/tlv320aic31xx.c b/sound/soc/codecs/tlv320aic31xx.c index 655c99db2426..858cb8be445f 100644 --- a/sound/soc/codecs/tlv320aic31xx.c +++ b/sound/soc/codecs/tlv320aic31xx.c @@ -1055,6 +1055,22 @@ static int aic31xx_regulator_event(struct notifier_block *nb, return 0; }
+static int aic31xx_reset(struct aic31xx_priv *aic31xx) +{ + int ret = 0; + + if (aic31xx->gpio_reset) { + gpiod_set_value(aic31xx->gpio_reset, 1); + ndelay(10); /* At least 10ns */ + gpiod_set_value(aic31xx->gpio_reset, 0); + } else { + ret = regmap_write(aic31xx->regmap, AIC31XX_RESET, 1); + } + mdelay(1); /* At least 1ms */ + + return ret; +} + static void aic31xx_clk_on(struct snd_soc_codec *codec) { struct aic31xx_priv *aic31xx = snd_soc_codec_get_drvdata(codec); @@ -1098,11 +1114,13 @@ static int aic31xx_power_on(struct snd_soc_codec *codec) if (ret) return ret;
- if (aic31xx->gpio_reset) { - gpiod_set_value(aic31xx->gpio_reset, 0); - udelay(100); - } regcache_cache_only(aic31xx->regmap, false); + + /* Reset device registers for a consistent power-on like state */ + ret = aic31xx_reset(aic31xx); + if (ret < 0) + dev_err(aic31xx->dev, "Could not reset device: %d\n", ret); + ret = regcache_sync(aic31xx->regmap); if (ret) { dev_err(codec->dev,
These devices support detecting and reporting short circuits across the output stages. Add support for reporting these issue. Do this by registering an interrupt if available and enabling this error to trigger that interrupt in the device.
Signed-off-by: Andrew F. Davis afd@ti.com --- sound/soc/codecs/tlv320aic31xx.c | 42 ++++++++++++++++++++++++++++++++++++++++ sound/soc/codecs/tlv320aic31xx.h | 16 +++++++++++++++ 2 files changed, 58 insertions(+)
diff --git a/sound/soc/codecs/tlv320aic31xx.c b/sound/soc/codecs/tlv320aic31xx.c index 6cbe5820ce60..500284853a5c 100644 --- a/sound/soc/codecs/tlv320aic31xx.c +++ b/sound/soc/codecs/tlv320aic31xx.c @@ -159,6 +159,7 @@ struct aic31xx_priv { unsigned int sysclk; u8 p_div; int rate_div_line; + int irq; };
struct aic31xx_rate_divs { @@ -1253,6 +1254,27 @@ static const struct acpi_device_id aic31xx_acpi_match[] = { MODULE_DEVICE_TABLE(acpi, aic31xx_acpi_match); #endif
+static irqreturn_t aic31xx_irq(int irq, void *data) +{ + struct aic31xx_priv *aic31xx = data; + struct device *dev = aic31xx->dev; + unsigned int value; + int ret; + + ret = regmap_read(aic31xx->regmap, AIC31XX_INTRDACFLAG, &value); + if (ret) { + dev_err(dev, "Failed to read interrupt mask: %d\n", ret); + return IRQ_NONE; + } + + if (value & AIC31XX_HPLSCDETECT) + dev_err(dev, "Short circuit on Left output is detected\n"); + if (value & AIC31XX_HPRSCDETECT) + dev_err(dev, "Short circuit on Right output is detected\n"); + + return IRQ_HANDLED; +} + static int aic31xx_i2c_probe(struct i2c_client *i2c, const struct i2c_device_id *id) { @@ -1275,6 +1297,7 @@ static int aic31xx_i2c_probe(struct i2c_client *i2c, return ret; } aic31xx->dev = &i2c->dev; + aic31xx->irq = i2c->irq;
aic31xx->codec_type = id->driver_data;
@@ -1313,6 +1336,25 @@ static int aic31xx_i2c_probe(struct i2c_client *i2c, return ret; }
+ if (aic31xx->irq > 0) { + regmap_update_bits(aic31xx->regmap, AIC31XX_GPIO1, + AIC31XX_GPIO1_FUNC_MASK, + AIC31XX_GPIO1_INT1 << + AIC31XX_GPIO1_FUNC_SHIFT); + + regmap_write(aic31xx->regmap, AIC31XX_INT1CTRL, + AIC31XX_SC); + + ret = devm_request_threaded_irq(aic31xx->dev, aic31xx->irq, + NULL, aic31xx_irq, + IRQF_ONESHOT, "aic31xx-irq", + aic31xx); + if (ret) { + dev_err(aic31xx->dev, "Unable to request IRQ\n"); + return ret; + } + } + if (aic31xx->codec_type & DAC31XX_BIT) return snd_soc_register_codec(&i2c->dev, &soc_codec_driver_aic31xx, diff --git a/sound/soc/codecs/tlv320aic31xx.h b/sound/soc/codecs/tlv320aic31xx.h index ab94e6a0c742..9dc85b6f6ad3 100644 --- a/sound/soc/codecs/tlv320aic31xx.h +++ b/sound/soc/codecs/tlv320aic31xx.h @@ -184,6 +184,22 @@ enum aic31xx_type { #define AIC31XX_SC BIT(3) #define AIC31XX_ENGINE BIT(2)
+/* AIC31XX_GPIO1 */ +#define AIC31XX_GPIO1_FUNC_MASK GENMASK(5, 2) +#define AIC31XX_GPIO1_FUNC_SHIFT 2 +#define AIC31XX_GPIO1_DISABLED 0x00 +#define AIC31XX_GPIO1_INPUT 0x01 +#define AIC31XX_GPIO1_GPI 0x02 +#define AIC31XX_GPIO1_GPO 0x03 +#define AIC31XX_GPIO1_CLKOUT 0x04 +#define AIC31XX_GPIO1_INT1 0x05 +#define AIC31XX_GPIO1_INT2 0x06 +#define AIC31XX_GPIO1_ADC_WCLK 0x07 +#define AIC31XX_GPIO1_SBCLK 0x08 +#define AIC31XX_GPIO1_SWCLK 0x09 +#define AIC31XX_GPIO1_ADC_MOD_CLK 0x10 +#define AIC31XX_GPIO1_SDOUT 0x11 + /* AIC31XX_DACSETUP */ #define AIC31XX_SOFTSTEP_MASK GENMASK(1, 0)
Similar to short circuit detection, when the ADC/DAC is saturated and overflows poor audio quality can result and should be reported to the user. This device support Automatic Dynamic Range Compression (DRC) to reduce this but it is not enabled currently in this driver.
Signed-off-by: Andrew F. Davis afd@ti.com --- sound/soc/codecs/tlv320aic31xx.c | 20 +++++++++++++++++++- sound/soc/codecs/tlv320aic31xx.h | 7 +++++++ 2 files changed, 26 insertions(+), 1 deletion(-)
diff --git a/sound/soc/codecs/tlv320aic31xx.c b/sound/soc/codecs/tlv320aic31xx.c index 500284853a5c..8ee407eab81b 100644 --- a/sound/soc/codecs/tlv320aic31xx.c +++ b/sound/soc/codecs/tlv320aic31xx.c @@ -1272,6 +1272,23 @@ static irqreturn_t aic31xx_irq(int irq, void *data) if (value & AIC31XX_HPRSCDETECT) dev_err(dev, "Short circuit on Right output is detected\n");
+ ret = regmap_read(aic31xx->regmap, AIC31XX_OFFLAG, &value); + if (ret) { + dev_err(dev, "Failed to read overflow flag: %d\n", ret); + return IRQ_NONE; + } + + if (value & AIC31XX_DAC_OF_LEFT) + dev_err(dev, "Left-channel DAC overflow has occurred\n"); + if (value & AIC31XX_DAC_OF_RIGHT) + dev_err(dev, "Right-channel DAC overflow has occurred\n"); + if (value & AIC31XX_DAC_OF_SHIFTER) + dev_err(dev, "DAC barrel shifter overflow has occurred\n"); + if (value & AIC31XX_ADC_OF) + dev_err(dev, "ADC overflow has occurred\n"); + if (value & AIC31XX_ADC_OF_SHIFTER) + dev_err(dev, "ADC barrel shifter overflow has occurred\n"); + return IRQ_HANDLED; }
@@ -1343,7 +1360,8 @@ static int aic31xx_i2c_probe(struct i2c_client *i2c, AIC31XX_GPIO1_FUNC_SHIFT);
regmap_write(aic31xx->regmap, AIC31XX_INT1CTRL, - AIC31XX_SC); + AIC31XX_SC | + AIC31XX_ENGINE);
ret = devm_request_threaded_irq(aic31xx->dev, aic31xx->irq, NULL, aic31xx_irq, diff --git a/sound/soc/codecs/tlv320aic31xx.h b/sound/soc/codecs/tlv320aic31xx.h index 9dc85b6f6ad3..d062663f66b5 100644 --- a/sound/soc/codecs/tlv320aic31xx.h +++ b/sound/soc/codecs/tlv320aic31xx.h @@ -166,6 +166,13 @@ enum aic31xx_type { #define AIC31XX_HPRDRVPWRSTATUS_MASK BIT(1) #define AIC31XX_SPRDRVPWRSTATUS_MASK BIT(0)
+/* AIC31XX_OFFLAG */ +#define AIC31XX_DAC_OF_LEFT BIT(7) +#define AIC31XX_DAC_OF_RIGHT BIT(6) +#define AIC31XX_DAC_OF_SHIFTER BIT(5) +#define AIC31XX_ADC_OF BIT(3) +#define AIC31XX_ADC_OF_SHIFTER BIT(1) + /* AIC31XX_INTRDACFLAG */ #define AIC31XX_HPLSCDETECT BIT(7) #define AIC31XX_HPRSCDETECT BIT(6)
This device can detect the insertion/removal of headphones and headsets. Enable reporting this status by enabling this interrupt and forwarding this to upper-layers if a jack has been defined.
This jack definition and the resulting operation from a jack detection event must currently be defined by sound card platform code until CODEC outputs to jack mappings can be defined generically.
Signed-off-by: Andrew F. Davis afd@ti.com --- sound/soc/codecs/tlv320aic31xx.c | 45 ++++++++++++++++++++++++++++++++++++++++ sound/soc/codecs/tlv320aic31xx.h | 11 ++++++++++ 2 files changed, 56 insertions(+)
diff --git a/sound/soc/codecs/tlv320aic31xx.c b/sound/soc/codecs/tlv320aic31xx.c index 8ee407eab81b..fef402e0f9e8 100644 --- a/sound/soc/codecs/tlv320aic31xx.c +++ b/sound/soc/codecs/tlv320aic31xx.c @@ -25,6 +25,7 @@ #include <linux/of_gpio.h> #include <linux/slab.h> #include <sound/core.h> +#include <sound/jack.h> #include <sound/pcm.h> #include <sound/pcm_params.h> #include <sound/soc.h> @@ -89,6 +90,7 @@ static bool aic31xx_volatile(struct device *dev, unsigned int reg) case AIC31XX_INTRADCFLAG: /* Sticky interrupt flags */ case AIC31XX_INTRDACFLAG2: case AIC31XX_INTRADCFLAG2: + case AIC31XX_HSDETECT: return true; } return false; @@ -156,6 +158,7 @@ struct aic31xx_priv { struct gpio_desc *gpio_reset; int micbias_vg; struct regulator_bulk_data supplies[AIC31XX_NUM_SUPPLIES]; + struct snd_soc_jack *jack; unsigned int sysclk; u8 p_div; int rate_div_line; @@ -1149,6 +1152,20 @@ static int aic31xx_set_bias_level(struct snd_soc_codec *codec, return 0; }
+int aic31xx_set_jack(struct snd_soc_codec *codec, + struct snd_soc_jack *jack, void *data) +{ + struct aic31xx_priv *aic31xx = snd_soc_codec_get_drvdata(codec); + + aic31xx->jack = jack; + + /* Enable/Disable jack detection */ + regmap_write(aic31xx->regmap, AIC31XX_HSDETECT, + jack ? AIC31XX_HSD_ENABLE : 0); + + return 0; +} + static int aic31xx_codec_probe(struct snd_soc_codec *codec) { struct aic31xx_priv *aic31xx = snd_soc_codec_get_drvdata(codec); @@ -1174,6 +1191,7 @@ static int aic31xx_codec_probe(struct snd_soc_codec *codec)
static const struct snd_soc_codec_driver soc_codec_driver_aic31xx = { .probe = aic31xx_codec_probe, + .set_jack = aic31xx_set_jack, .set_bias_level = aic31xx_set_bias_level, .suspend_bias_off = true,
@@ -1272,6 +1290,32 @@ static irqreturn_t aic31xx_irq(int irq, void *data) if (value & AIC31XX_HPRSCDETECT) dev_err(dev, "Short circuit on Right output is detected\n");
+ if (value & AIC31XX_HSPLUG) { + int status = 0; + + ret = regmap_read(aic31xx->regmap, AIC31XX_HSDETECT, &value); + if (ret) { + dev_err(dev, "Failed to read headset type: %d\n", ret); + return IRQ_NONE; + } + + switch ((value & AIC31XX_HSD_TYPE_MASK) >> + AIC31XX_HSD_TYPE_SHIFT) { + case AIC31XX_HSD_HP: + status |= SND_JACK_HEADPHONE; + break; + case AIC31XX_HSD_HS: + status |= SND_JACK_HEADSET; + break; + default: + break; + } + + if (aic31xx->jack) + snd_soc_jack_report(aic31xx->jack, status, + AIC31XX_JACK_MASK); + } + ret = regmap_read(aic31xx->regmap, AIC31XX_OFFLAG, &value); if (ret) { dev_err(dev, "Failed to read overflow flag: %d\n", ret); @@ -1360,6 +1404,7 @@ static int aic31xx_i2c_probe(struct i2c_client *i2c, AIC31XX_GPIO1_FUNC_SHIFT);
regmap_write(aic31xx->regmap, AIC31XX_INT1CTRL, + AIC31XX_HSPLUGDET | AIC31XX_SC | AIC31XX_ENGINE);
diff --git a/sound/soc/codecs/tlv320aic31xx.h b/sound/soc/codecs/tlv320aic31xx.h index d062663f66b5..66c85df4d5be 100644 --- a/sound/soc/codecs/tlv320aic31xx.h +++ b/sound/soc/codecs/tlv320aic31xx.h @@ -20,6 +20,9 @@ #define AIC31XX_MINIDSP_BIT BIT(2) #define DAC31XX_BIT BIT(3)
+#define AIC31XX_JACK_MASK (SND_JACK_HEADPHONE | \ + SND_JACK_HEADSET) + enum aic31xx_type { AIC3100 = 0, AIC3110 = AIC31XX_STEREO_CLASS_D_BIT, @@ -213,6 +216,14 @@ enum aic31xx_type { /* AIC31XX_DACMUTE */ #define AIC31XX_DACMUTE_MASK GENMASK(3, 2)
+/* AIC31XX_HSDETECT */ +#define AIC31XX_HSD_ENABLE BIT(7) +#define AIC31XX_HSD_TYPE_MASK GENMASK(6, 5) +#define AIC31XX_HSD_TYPE_SHIFT 5 +#define AIC31XX_HSD_NONE 0x00 +#define AIC31XX_HSD_HP 0x01 +#define AIC31XX_HSD_HS 0x03 + /* AIC31XX_MICBIAS */ #define AIC31XX_MICBIAS_MASK GENMASK(1, 0) #define AIC31XX_MICBIAS_SHIFT 0
This device can optionally detect headset or microphone button presses. Add support for this by passing this event to the jack layer.
Signed-off-by: Andrew F. Davis afd@ti.com --- sound/soc/codecs/tlv320aic31xx.c | 14 +++++++++++++- sound/soc/codecs/tlv320aic31xx.h | 3 ++- 2 files changed, 15 insertions(+), 2 deletions(-)
diff --git a/sound/soc/codecs/tlv320aic31xx.c b/sound/soc/codecs/tlv320aic31xx.c index fef402e0f9e8..8f5dec414628 100644 --- a/sound/soc/codecs/tlv320aic31xx.c +++ b/sound/soc/codecs/tlv320aic31xx.c @@ -1290,9 +1290,20 @@ static irqreturn_t aic31xx_irq(int irq, void *data) if (value & AIC31XX_HPRSCDETECT) dev_err(dev, "Short circuit on Right output is detected\n");
- if (value & AIC31XX_HSPLUG) { + if (value & (AIC31XX_HSPLUG | AIC31XX_BUTTONPRESS)) { int status = 0;
+ ret = regmap_read(aic31xx->regmap, AIC31XX_INTRDACFLAG2, + &value); + if (ret) { + dev_err(dev, "Failed to read interrupt mask: %d\n", + ret); + return IRQ_NONE; + } + + if (value & AIC31XX_BUTTONPRESS) + status |= SND_JACK_BTN_0; + ret = regmap_read(aic31xx->regmap, AIC31XX_HSDETECT, &value); if (ret) { dev_err(dev, "Failed to read headset type: %d\n", ret); @@ -1405,6 +1416,7 @@ static int aic31xx_i2c_probe(struct i2c_client *i2c,
regmap_write(aic31xx->regmap, AIC31XX_INT1CTRL, AIC31XX_HSPLUGDET | + AIC31XX_BUTTONPRESSDET | AIC31XX_SC | AIC31XX_ENGINE);
diff --git a/sound/soc/codecs/tlv320aic31xx.h b/sound/soc/codecs/tlv320aic31xx.h index 66c85df4d5be..7fce278eadac 100644 --- a/sound/soc/codecs/tlv320aic31xx.h +++ b/sound/soc/codecs/tlv320aic31xx.h @@ -21,7 +21,8 @@ #define DAC31XX_BIT BIT(3)
#define AIC31XX_JACK_MASK (SND_JACK_HEADPHONE | \ - SND_JACK_HEADSET) + SND_JACK_HEADSET | \ + SND_JACK_BTN_0)
enum aic31xx_type { AIC3100 = 0,
participants (2)
-
Andrew F. Davis
-
Mark Brown