Unverified Commit a149377c authored by Ryan Walklin's avatar Ryan Walklin Committed by Mark Brown
Browse files

ASoC: sun4i-codec: support hp-det-gpios property



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: default avatarChris Morgan <macromorgan@hotmail.com>
Signed-off-by: default avatarRyan Walklin <ryan@testtoast.com>

--
Changelog v1..v2:
- Separate DAPM changes into separate patch and add rationale.

Tested-by: default avatarPhilippe Simons <simons.philippe@gmail.com>
Link: https://patch.msgid.link/20250214220247.10810-4-ryan@testtoast.com


Signed-off-by: default avatarMark Brown <broonie@kernel.org>
parent ae5f76d4
Loading
Loading
Loading
Loading
+53 −0
Original line number Diff line number Diff line
@@ -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,