Merge series "ASoC: fsl-asoc-card: Support hp and mic detection" from Shengjiu Wang...
authorMark Brown <broonie@kernel.org>
Thu, 16 Jul 2020 22:51:52 +0000 (23:51 +0100)
committerMark Brown <broonie@kernel.org>
Thu, 16 Jul 2020 22:51:52 +0000 (23:51 +0100)
Support hp and mic detection.
Add a parameter for asoc_simple_init_jack.

Shengjiu Wang (3):
  ASoC: simple-card-utils: Support configure pin_name for
    asoc_simple_init_jack
  ASoC: bindings: fsl-asoc-card: Support hp-det-gpio and mic-det-gpio
  ASoC: fsl-asoc-card: Support Headphone and Microphone Jack detection

changes in v2:
- Add more comments in third commit
- Add Acked-by Nicolin.

 .../bindings/sound/fsl-asoc-card.txt          |  3 +
 include/sound/simple_card_utils.h             |  6 +-
 sound/soc/fsl/Kconfig                         |  1 +
 sound/soc/fsl/fsl-asoc-card.c                 | 77 ++++++++++++++++++-
 sound/soc/generic/simple-card-utils.c         |  7 +-
 5 files changed, 86 insertions(+), 8 deletions(-)

--
2.27.0

Documentation/devicetree/bindings/sound/fsl-asoc-card.txt
include/sound/simple_card_utils.h
sound/soc/fsl/Kconfig
sound/soc/fsl/fsl-asoc-card.c
sound/soc/generic/simple-card-utils.c

index 133d7e1..8a6a3d0 100644 (file)
@@ -69,6 +69,9 @@ Optional properties:
                                coexisting in order to support the old bindings
                                of wm8962 and sgtl5000.
 
+  - hp-det-gpio                : The GPIO that detect headphones are plugged in
+  - mic-det-gpio       : The GPIO that detect microphones are plugged in
+
 Optional unless SSI is selected as a CPU DAI:
 
   - mux-int-port       : The internal port of the i.MX audio muxer (AUDMUX)
index bbdd154..86a1e95 100644 (file)
@@ -12,9 +12,9 @@
 #include <sound/soc.h>
 
 #define asoc_simple_init_hp(card, sjack, prefix) \
-       asoc_simple_init_jack(card, sjack, 1, prefix)
+       asoc_simple_init_jack(card, sjack, 1, prefix, NULL)
 #define asoc_simple_init_mic(card, sjack, prefix) \
-       asoc_simple_init_jack(card, sjack, 0, prefix)
+       asoc_simple_init_jack(card, sjack, 0, prefix, NULL)
 
 struct asoc_simple_dai {
        const char *name;
@@ -131,7 +131,7 @@ int asoc_simple_parse_pin_switches(struct snd_soc_card *card,
 
 int asoc_simple_init_jack(struct snd_soc_card *card,
                               struct asoc_simple_jack *sjack,
-                              int is_hp, char *prefix);
+                              int is_hp, char *prefix, char *pin);
 int asoc_simple_init_priv(struct asoc_simple_priv *priv,
                               struct link_info *li);
 
index ea7b478..1c4ca5e 100644 (file)
@@ -315,6 +315,7 @@ config SND_SOC_FSL_ASOC_CARD
        depends on OF && I2C
        # enforce SND_SOC_FSL_ASOC_CARD=m if SND_AC97_CODEC=m:
        depends on SND_AC97_CODEC || SND_AC97_CODEC=n
+       select SND_SIMPLE_CARD_UTILS
        select SND_SOC_IMX_AUDMUX
        select SND_SOC_IMX_PCM_DMA
        select SND_SOC_FSL_ESAI
index dbacdd2..ee80d02 100644 (file)
@@ -15,6 +15,8 @@
 #endif
 #include <sound/pcm_params.h>
 #include <sound/soc.h>
+#include <sound/jack.h>
+#include <sound/simple_card_utils.h>
 
 #include "fsl_esai.h"
 #include "fsl_sai.h"
@@ -65,6 +67,8 @@ struct cpu_priv {
 /**
  * struct fsl_asoc_card_priv - Freescale Generic ASOC card private data
  * @dai_link: DAI link structure including normal one and DPCM link
+ * @hp_jack: Headphone Jack structure
+ * @mic_jack: Microphone Jack structure
  * @pdev: platform device pointer
  * @codec_priv: CODEC private data
  * @cpu_priv: CPU private data
@@ -79,6 +83,8 @@ struct cpu_priv {
 
 struct fsl_asoc_card_priv {
        struct snd_soc_dai_link dai_link[3];
+       struct asoc_simple_jack hp_jack;
+       struct asoc_simple_jack mic_jack;
        struct platform_device *pdev;
        struct codec_priv codec_priv;
        struct cpu_priv cpu_priv;
@@ -445,6 +451,44 @@ static int fsl_asoc_card_audmux_init(struct device_node *np,
        return 0;
 }
 
+static int hp_jack_event(struct notifier_block *nb, unsigned long event,
+                        void *data)
+{
+       struct snd_soc_jack *jack = (struct snd_soc_jack *)data;
+       struct snd_soc_dapm_context *dapm = &jack->card->dapm;
+
+       if (event & SND_JACK_HEADPHONE)
+               /* Disable speaker if headphone is plugged in */
+               snd_soc_dapm_disable_pin(dapm, "Ext Spk");
+       else
+               snd_soc_dapm_enable_pin(dapm, "Ext Spk");
+
+       return 0;
+}
+
+static struct notifier_block hp_jack_nb = {
+       .notifier_call = hp_jack_event,
+};
+
+static int mic_jack_event(struct notifier_block *nb, unsigned long event,
+                         void *data)
+{
+       struct snd_soc_jack *jack = (struct snd_soc_jack *)data;
+       struct snd_soc_dapm_context *dapm = &jack->card->dapm;
+
+       if (event & SND_JACK_MICROPHONE)
+               /* Disable dmic if microphone is plugged in */
+               snd_soc_dapm_disable_pin(dapm, "DMIC");
+       else
+               snd_soc_dapm_enable_pin(dapm, "DMIC");
+
+       return 0;
+}
+
+static struct notifier_block mic_jack_nb = {
+       .notifier_call = mic_jack_event,
+};
+
 static int fsl_asoc_card_late_probe(struct snd_soc_card *card)
 {
        struct fsl_asoc_card_priv *priv = snd_soc_card_get_drvdata(card);
@@ -745,8 +789,37 @@ static int fsl_asoc_card_probe(struct platform_device *pdev)
        snd_soc_card_set_drvdata(&priv->card, priv);
 
        ret = devm_snd_soc_register_card(&pdev->dev, &priv->card);
-       if (ret && ret != -EPROBE_DEFER)
-               dev_err(&pdev->dev, "snd_soc_register_card failed (%d)\n", ret);
+       if (ret) {
+               if (ret != -EPROBE_DEFER)
+                       dev_err(&pdev->dev, "snd_soc_register_card failed (%d)\n", ret);
+               goto asrc_fail;
+       }
+
+       /*
+        * Properties "hp-det-gpio" and "mic-det-gpio" are optional, and
+        * asoc_simple_init_jack uses these properties for creating
+        * Headphone Jack and Microphone Jack.
+        *
+        * The notifier is initialized in snd_soc_card_jack_new(), then
+        * snd_soc_jack_notifier_register can be called.
+        */
+       if (of_property_read_bool(np, "hp-det-gpio")) {
+               ret = asoc_simple_init_jack(&priv->card, &priv->hp_jack,
+                                           1, NULL, "Headphone Jack");
+               if (ret)
+                       goto asrc_fail;
+
+               snd_soc_jack_notifier_register(&priv->hp_jack.jack, &hp_jack_nb);
+       }
+
+       if (of_property_read_bool(np, "mic-det-gpio")) {
+               ret = asoc_simple_init_jack(&priv->card, &priv->mic_jack,
+                                           0, NULL, "Mic Jack");
+               if (ret)
+                       goto asrc_fail;
+
+               snd_soc_jack_notifier_register(&priv->mic_jack.jack, &mic_jack_nb);
+       }
 
 asrc_fail:
        of_node_put(asrc_np);
index 8c54dc6..b408cb5 100644 (file)
@@ -540,7 +540,8 @@ EXPORT_SYMBOL_GPL(asoc_simple_parse_pin_switches);
 
 int asoc_simple_init_jack(struct snd_soc_card *card,
                          struct asoc_simple_jack *sjack,
-                         int is_hp, char *prefix)
+                         int is_hp, char *prefix,
+                         char *pin)
 {
        struct device *dev = card->dev;
        enum of_gpio_flags flags;
@@ -557,12 +558,12 @@ int asoc_simple_init_jack(struct snd_soc_card *card,
 
        if (is_hp) {
                snprintf(prop, sizeof(prop), "%shp-det-gpio", prefix);
-               pin_name        = "Headphones";
+               pin_name        = pin ? pin : "Headphones";
                gpio_name       = "Headphone detection";
                mask            = SND_JACK_HEADPHONE;
        } else {
                snprintf(prop, sizeof(prop), "%smic-det-gpio", prefix);
-               pin_name        = "Mic Jack";
+               pin_name        = pin ? pin : "Mic Jack";
                gpio_name       = "Mic detection";
                mask            = SND_JACK_MICROPHONE;
        }