]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
ASoC: sun4i-codec: support hp-det-gpios property
authorRyan Walklin <ryan@testtoast.com>
Fri, 14 Feb 2025 22:02:25 +0000 (11:02 +1300)
committerMark Brown <broonie@kernel.org>
Thu, 13 Mar 2025 22:50:06 +0000 (22:50 +0000)
Add support for GPIO headphone detection with the hp-det-gpios
property. In order for this to properly disable the path upon
removal of headphones, the output must be labelled Headphone which
is a common sink in the driver.

Describe a headphone jack and detection GPIO in the driver, check for
a corresponding device tree node, and enable jack detection in a new
machine init function if described.

Signed-off-by: Chris Morgan <macromorgan@hotmail.com>
Signed-off-by: Ryan Walklin <ryan@testtoast.com>
--
Changelog v1..v2:
- Separate DAPM changes into separate patch and add rationale.

Tested-by: Philippe Simons <simons.philippe@gmail.com>
Link: https://patch.msgid.link/20250214220247.10810-4-ryan@testtoast.com
Signed-off-by: Mark Brown <broonie@kernel.org>
sound/soc/sunxi/sun4i-codec.c

index f24bbefeb39236e01db6e6c99870288ae9a9502b..3701f56c72756a751abbef57ee81fdbf2c5b4575 100644 (file)
@@ -22,6 +22,7 @@
 #include <linux/gpio/consumer.h>
 
 #include <sound/core.h>
+#include <sound/jack.h>
 #include <sound/pcm.h>
 #include <sound/pcm_params.h>
 #include <sound/soc.h>
@@ -331,6 +332,7 @@ struct sun4i_codec {
        struct clk      *clk_module;
        struct reset_control *rst;
        struct gpio_desc *gpio_pa;
+       struct gpio_desc *gpio_hp;
 
        /* ADC_FIFOC register is at different offset on different SoCs */
        struct regmap_field *reg_adc_fifoc;
@@ -1583,6 +1585,49 @@ static struct snd_soc_dai_driver dummy_cpu_dai = {
        .ops = &dummy_dai_ops,
 };
 
+static struct snd_soc_jack sun4i_headphone_jack;
+
+static struct snd_soc_jack_pin sun4i_headphone_jack_pins[] = {
+       { .pin = "Headphone", .mask = SND_JACK_HEADPHONE },
+};
+
+static struct snd_soc_jack_gpio sun4i_headphone_jack_gpio = {
+       .name = "hp-det",
+       .report = SND_JACK_HEADPHONE,
+       .debounce_time = 150,
+};
+
+static int sun4i_codec_machine_init(struct snd_soc_pcm_runtime *rtd)
+{
+       struct snd_soc_card *card = rtd->card;
+       struct sun4i_codec *scodec = snd_soc_card_get_drvdata(card);
+       int ret;
+
+       if (scodec->gpio_hp) {
+               ret = snd_soc_card_jack_new_pins(card, "Headphone Jack",
+                                                SND_JACK_HEADPHONE,
+                                                &sun4i_headphone_jack,
+                                                sun4i_headphone_jack_pins,
+                                                ARRAY_SIZE(sun4i_headphone_jack_pins));
+               if (ret) {
+                       dev_err(rtd->dev,
+                               "Headphone jack creation failed: %d\n", ret);
+                       return ret;
+               }
+
+               sun4i_headphone_jack_gpio.desc = scodec->gpio_hp;
+               ret = snd_soc_jack_add_gpios(&sun4i_headphone_jack, 1,
+                                            &sun4i_headphone_jack_gpio);
+
+               if (ret) {
+                       dev_err(rtd->dev, "Headphone GPIO not added: %d\n", ret);
+                       return ret;
+               }
+       }
+
+       return 0;
+}
+
 static struct snd_soc_dai_link *sun4i_codec_create_link(struct device *dev,
                                                        int *num_links)
 {
@@ -1608,6 +1653,7 @@ static struct snd_soc_dai_link *sun4i_codec_create_link(struct device *dev,
        link->codecs->name      = dev_name(dev);
        link->platforms->name   = dev_name(dev);
        link->dai_fmt           = SND_SOC_DAIFMT_I2S;
+       link->init              = sun4i_codec_machine_init;
 
        *num_links = 1;
 
@@ -2302,6 +2348,13 @@ static int sun4i_codec_probe(struct platform_device *pdev)
                return ret;
        }
 
+       scodec->gpio_hp = devm_gpiod_get_optional(&pdev->dev, "hp-det", GPIOD_IN);
+       if (IS_ERR(scodec->gpio_hp)) {
+               ret = PTR_ERR(scodec->gpio_hp);
+               dev_err_probe(&pdev->dev, ret, "Failed to get hp-det gpio\n");
+               return ret;
+       }
+
        /* reg_field setup */
        scodec->reg_adc_fifoc = devm_regmap_field_alloc(&pdev->dev,
                                                        scodec->regmap,