All of lore.kernel.org
 help / color / mirror / Atom feed
From: Carl Philipp Klemm <philipp@uvos.xyz>
To: Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
Cc: "alsa-devel@alsa-project.org" <alsa-devel@alsa-project.org>,
	"tony@atomide.com" <tony@atomide.com>,
	"merlijn@wizzup.org" <merlijn@wizzup.org>,
	"sre@kernel.org" <sre@kernel.org>,
	"linux-omap@vger.kernel.org" <linux-omap@vger.kernel.org>,
	"kuninori.morimoto.gx@gmail.com" <kuninori.morimoto.gx@gmail.com>
Subject: [PATCH 3/6] ASoC: cpcap: add headphone jack plug detection support
Date: Sun, 20 Feb 2022 01:15:51 +0100	[thread overview]
Message-ID: <20220220011551.a132b8f7d033d3e1eb731013@uvos.xyz> (raw)
In-Reply-To: <OS3PR01MB8426FD3FD1B45BB31C971A56D4509@OS3PR01MB8426.jpnprd01.prod.outlook.com>

Implements an interrupt handler that fires when a headphone
is inserted. A jack must be provided to the codec via
snd_soc_component_driver .set_jack

Signed-off-by: Carl Philipp Klemm <philipp@uvos.xyz>
---
 sound/soc/codecs/cpcap.c | 104 +++++++++++++++++++++++++++++++++++----
 1 file changed, 94 insertions(+), 10 deletions(-)

diff --git a/sound/soc/codecs/cpcap.c b/sound/soc/codecs/cpcap.c
index 598e09024e23..8114d78726ff 100644
--- a/sound/soc/codecs/cpcap.c
+++ b/sound/soc/codecs/cpcap.c
@@ -15,6 +15,7 @@
 #include <sound/core.h>
 #include <sound/soc.h>
 #include <sound/tlv.h>
+#include <sound/jack.h>
 
 /* Register 512 CPCAP_REG_VAUDIOC --- Audio Regulator and Bias Voltage */
 #define CPCAP_BIT_AUDIO_LOW_PWR           6
@@ -252,8 +253,14 @@ enum cpcap_dai {
 };
 
 struct cpcap_audio {
+	struct device *dev;
 	struct snd_soc_component *component;
 	struct regmap *regmap;
+	struct snd_soc_jack *hp_jack;
+
+	struct delayed_work jack_detect_work;
+
+	int hp_irq;
 
 	u16 vendor;
 
@@ -603,6 +610,21 @@ static int cpcap_input_left_mux_put_enum(struct snd_kcontrol *kcontrol,
 	return 0;
 }
 
+static struct snd_soc_jack_pin headset_jack_pins[] = {
+	{
+		.pin = "Headset Right Playback Route",
+		.mask = SND_JACK_HEADPHONE,
+	},
+	{
+		.pin = "Headset Left Playback Route",
+		.mask = SND_JACK_HEADPHONE,
+	},
+	{
+		.pin = "Headphones",
+		.mask = SND_JACK_HEADPHONE,
+	}
+};
+
 static const struct snd_kcontrol_new cpcap_input_left_mux =
 	SOC_DAPM_ENUM_EXT("Input Left", cpcap_input_left_mux_enum,
 			  cpcap_input_left_mux_get_enum,
@@ -1561,8 +1583,6 @@ static int cpcap_dai_mux(struct cpcap_audio *cpcap, bool swap_dai_configuration)
 	u16 voice_mask = BIT(CPCAP_BIT_DIG_AUD_IN);
 	int err;
 
-
-
 	if (!swap_dai_configuration) {
 		/* Codec on DAI0, HiFi on DAI1 */
 		voice_val = 0;
@@ -1586,6 +1606,44 @@ static int cpcap_dai_mux(struct cpcap_audio *cpcap, bool swap_dai_configuration)
 	return 0;
 }
 
+static irqreturn_t cpcap_hp_irq_thread(int irq, void *arg)
+{
+	struct cpcap_audio *cpcap = arg;
+	int val = -1;
+	bool plugged;
+
+	regmap_read(cpcap->regmap, CPCAP_REG_INTS1, &val);
+	plugged = val & (1<<9);
+
+	if (!cpcap->component) {
+		dev_warn(cpcap->dev, "%s called before component is ready.", __func__);
+		return IRQ_HANDLED;
+	}
+
+	if (!cpcap->hp_jack) {
+		dev_warn(cpcap->dev, "%s called before jack is ready.", __func__);
+		return IRQ_HANDLED;
+	}
+
+	snd_soc_jack_report(cpcap->hp_jack, plugged ? 0 : SND_JACK_HEADPHONE, SND_JACK_HEADPHONE);
+
+	return IRQ_HANDLED;
+}
+
+static int cpcap_set_jack_detect(struct snd_soc_component *component,
+	struct snd_soc_jack *hp_jack, void *data)
+{
+	struct cpcap_audio *cpcap = snd_soc_component_get_drvdata(component);
+
+	if (!cpcap->hp_jack) {
+		dev_info(cpcap->dev, "registering jack");
+		cpcap->hp_jack = hp_jack;
+		snd_soc_jack_add_pins(hp_jack, ARRAY_SIZE(headset_jack_pins), headset_jack_pins);
+	}
+
+	return 0;
+}
+
 static int cpcap_audio_reset(struct snd_soc_component *component,
 			     bool swap_dai_configuration)
 {
@@ -1628,13 +1686,9 @@ static int cpcap_audio_reset(struct snd_soc_component *component,
 
 static int cpcap_soc_probe(struct snd_soc_component *component)
 {
-	struct cpcap_audio *cpcap;
+	struct cpcap_audio *cpcap = snd_soc_component_get_drvdata(component);
 	int err;
 
-	cpcap = devm_kzalloc(component->dev, sizeof(*cpcap), GFP_KERNEL);
-	if (!cpcap)
-		return -ENOMEM;
-	snd_soc_component_set_drvdata(component, cpcap);
 	cpcap->component = component;
 
 	cpcap->regmap = dev_get_regmap(component->dev->parent, NULL);
@@ -1657,6 +1711,7 @@ static struct snd_soc_component_driver soc_codec_dev_cpcap = {
 	.num_dapm_widgets	= ARRAY_SIZE(cpcap_dapm_widgets),
 	.dapm_routes		= intercon,
 	.num_dapm_routes	= ARRAY_SIZE(intercon),
+	.set_jack = cpcap_set_jack_detect,
 	.idle_bias_on		= 1,
 	.use_pmdown_time	= 1,
 	.endianness		= 1,
@@ -1665,13 +1720,42 @@ static struct snd_soc_component_driver soc_codec_dev_cpcap = {
 
 static int cpcap_codec_probe(struct platform_device *pdev)
 {
-	struct device_node *codec_node =
-		of_get_child_by_name(pdev->dev.parent->of_node, "audio-codec");
+	struct cpcap_audio *cpcap;
+	struct device_node *codec_node;
+	int ret;
 
+	codec_node = of_get_child_by_name(pdev->dev.parent->of_node, "audio-codec");
 	pdev->dev.of_node = codec_node;
 
-	return devm_snd_soc_register_component(&pdev->dev, &soc_codec_dev_cpcap,
+	cpcap = devm_kzalloc(&pdev->dev, sizeof(*cpcap), GFP_KERNEL);
+	if (!cpcap)
+		return -ENOMEM;
+	dev_set_drvdata(&pdev->dev, cpcap);
+
+	ret = devm_snd_soc_register_component(&pdev->dev, &soc_codec_dev_cpcap,
 				      cpcap_dai, ARRAY_SIZE(cpcap_dai));
+	if (ret < 0)
+		return ret;
+
+	cpcap->hp_irq = platform_get_irq_byname(pdev, "hpplugged");
+	if (cpcap->hp_irq < 0)
+		return -ENODEV;
+
+	cpcap->dev = &pdev->dev;
+
+	ret = devm_request_threaded_irq(&pdev->dev, cpcap->hp_irq, NULL,
+					  cpcap_hp_irq_thread,
+					  IRQF_TRIGGER_RISING |
+					  IRQF_TRIGGER_FALLING |
+					  IRQF_ONESHOT,
+					  "cpcap-codec-headphone", cpcap);
+	if (ret) {
+		dev_err(&pdev->dev, "could not get irq: %i\n",
+			ret);
+		return ret;
+	}
+
+	return 0;
 }
 
 static struct platform_driver cpcap_codec_driver = {
-- 
2.35.1

-- 
Carl Philipp Klemm <philipp@uvos.xyz> <carl@uvos.xyz>

On Mon, 10 Jan 2022 23:27:52 +0000
Kuninori Morimoto <kuninori.morimoto.gx@renesas.com> wrote:

> 
> Hi Carl
> 
> >> (X)	int asoc_simple_init_jack(...)
> >> 	{
> >> 		...
> >> 		if (gpio_is_valid(det)) {
> >> 			...
> >> 
> >> 			snd_soc_card_jack_new(...);
> >> 			snd_soc_jack_add_gpios(...);
> >> 			for_each_card_components(card, component)
> >> (Y)				snd_soc_component_set_jack(component, ...);
> >> 		}
> >> 		...
> >> 	}
> >
> > So for the case of cpcap codec on motorola mapphones this dosent help,
> > because we dont have a gpio to sense plug state, thus no gpio in dts
> > and thus gpio_is_valid will return false, therefore, no jack.
> >
> > Moving 
> >
> > sjack->pin.pin		= pin_name;
> > sjack->pin.mask		= mask;
> >
> > snd_soc_card_jack_new(card, pin_name, mask,
> > 		      &sjack->jack,
> > 		      &sjack->pin, 1);
> >
> > and
> >
> > for_each_card_components(card, component)
> > 			snd_soc_component_set_jack(component, &sjack->jack, NULL);
> >
> > outside of the if block should make this work, at least cpcap gets the jack then.
> 
> I see.
> 
> simple-card is checking hp-det-gpio on DT now.
> I guess it can help you if simple-card also check "hp-det" (no gpio)
> (and customize previous patch) ?
> Is "enable-hp" better naming... ?
> 
> Best regards
> ---
> Kuninori Morimoto

WARNING: multiple messages have this Message-ID (diff)
From: Carl Philipp Klemm <philipp@uvos.xyz>
To: Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
Cc: "kuninori.morimoto.gx@gmail.com" <kuninori.morimoto.gx@gmail.com>,
	"alsa-devel@alsa-project.org" <alsa-devel@alsa-project.org>,
	"merlijn@wizzup.org" <merlijn@wizzup.org>,
	"tony@atomide.com" <tony@atomide.com>,
	"sre@kernel.org" <sre@kernel.org>,
	"linux-omap@vger.kernel.org" <linux-omap@vger.kernel.org>
Subject: [PATCH 3/6] ASoC: cpcap: add headphone jack plug detection support
Date: Sun, 20 Feb 2022 01:15:51 +0100	[thread overview]
Message-ID: <20220220011551.a132b8f7d033d3e1eb731013@uvos.xyz> (raw)
In-Reply-To: <OS3PR01MB8426FD3FD1B45BB31C971A56D4509@OS3PR01MB8426.jpnprd01.prod.outlook.com>

Implements an interrupt handler that fires when a headphone
is inserted. A jack must be provided to the codec via
snd_soc_component_driver .set_jack

Signed-off-by: Carl Philipp Klemm <philipp@uvos.xyz>
---
 sound/soc/codecs/cpcap.c | 104 +++++++++++++++++++++++++++++++++++----
 1 file changed, 94 insertions(+), 10 deletions(-)

diff --git a/sound/soc/codecs/cpcap.c b/sound/soc/codecs/cpcap.c
index 598e09024e23..8114d78726ff 100644
--- a/sound/soc/codecs/cpcap.c
+++ b/sound/soc/codecs/cpcap.c
@@ -15,6 +15,7 @@
 #include <sound/core.h>
 #include <sound/soc.h>
 #include <sound/tlv.h>
+#include <sound/jack.h>
 
 /* Register 512 CPCAP_REG_VAUDIOC --- Audio Regulator and Bias Voltage */
 #define CPCAP_BIT_AUDIO_LOW_PWR           6
@@ -252,8 +253,14 @@ enum cpcap_dai {
 };
 
 struct cpcap_audio {
+	struct device *dev;
 	struct snd_soc_component *component;
 	struct regmap *regmap;
+	struct snd_soc_jack *hp_jack;
+
+	struct delayed_work jack_detect_work;
+
+	int hp_irq;
 
 	u16 vendor;
 
@@ -603,6 +610,21 @@ static int cpcap_input_left_mux_put_enum(struct snd_kcontrol *kcontrol,
 	return 0;
 }
 
+static struct snd_soc_jack_pin headset_jack_pins[] = {
+	{
+		.pin = "Headset Right Playback Route",
+		.mask = SND_JACK_HEADPHONE,
+	},
+	{
+		.pin = "Headset Left Playback Route",
+		.mask = SND_JACK_HEADPHONE,
+	},
+	{
+		.pin = "Headphones",
+		.mask = SND_JACK_HEADPHONE,
+	}
+};
+
 static const struct snd_kcontrol_new cpcap_input_left_mux =
 	SOC_DAPM_ENUM_EXT("Input Left", cpcap_input_left_mux_enum,
 			  cpcap_input_left_mux_get_enum,
@@ -1561,8 +1583,6 @@ static int cpcap_dai_mux(struct cpcap_audio *cpcap, bool swap_dai_configuration)
 	u16 voice_mask = BIT(CPCAP_BIT_DIG_AUD_IN);
 	int err;
 
-
-
 	if (!swap_dai_configuration) {
 		/* Codec on DAI0, HiFi on DAI1 */
 		voice_val = 0;
@@ -1586,6 +1606,44 @@ static int cpcap_dai_mux(struct cpcap_audio *cpcap, bool swap_dai_configuration)
 	return 0;
 }
 
+static irqreturn_t cpcap_hp_irq_thread(int irq, void *arg)
+{
+	struct cpcap_audio *cpcap = arg;
+	int val = -1;
+	bool plugged;
+
+	regmap_read(cpcap->regmap, CPCAP_REG_INTS1, &val);
+	plugged = val & (1<<9);
+
+	if (!cpcap->component) {
+		dev_warn(cpcap->dev, "%s called before component is ready.", __func__);
+		return IRQ_HANDLED;
+	}
+
+	if (!cpcap->hp_jack) {
+		dev_warn(cpcap->dev, "%s called before jack is ready.", __func__);
+		return IRQ_HANDLED;
+	}
+
+	snd_soc_jack_report(cpcap->hp_jack, plugged ? 0 : SND_JACK_HEADPHONE, SND_JACK_HEADPHONE);
+
+	return IRQ_HANDLED;
+}
+
+static int cpcap_set_jack_detect(struct snd_soc_component *component,
+	struct snd_soc_jack *hp_jack, void *data)
+{
+	struct cpcap_audio *cpcap = snd_soc_component_get_drvdata(component);
+
+	if (!cpcap->hp_jack) {
+		dev_info(cpcap->dev, "registering jack");
+		cpcap->hp_jack = hp_jack;
+		snd_soc_jack_add_pins(hp_jack, ARRAY_SIZE(headset_jack_pins), headset_jack_pins);
+	}
+
+	return 0;
+}
+
 static int cpcap_audio_reset(struct snd_soc_component *component,
 			     bool swap_dai_configuration)
 {
@@ -1628,13 +1686,9 @@ static int cpcap_audio_reset(struct snd_soc_component *component,
 
 static int cpcap_soc_probe(struct snd_soc_component *component)
 {
-	struct cpcap_audio *cpcap;
+	struct cpcap_audio *cpcap = snd_soc_component_get_drvdata(component);
 	int err;
 
-	cpcap = devm_kzalloc(component->dev, sizeof(*cpcap), GFP_KERNEL);
-	if (!cpcap)
-		return -ENOMEM;
-	snd_soc_component_set_drvdata(component, cpcap);
 	cpcap->component = component;
 
 	cpcap->regmap = dev_get_regmap(component->dev->parent, NULL);
@@ -1657,6 +1711,7 @@ static struct snd_soc_component_driver soc_codec_dev_cpcap = {
 	.num_dapm_widgets	= ARRAY_SIZE(cpcap_dapm_widgets),
 	.dapm_routes		= intercon,
 	.num_dapm_routes	= ARRAY_SIZE(intercon),
+	.set_jack = cpcap_set_jack_detect,
 	.idle_bias_on		= 1,
 	.use_pmdown_time	= 1,
 	.endianness		= 1,
@@ -1665,13 +1720,42 @@ static struct snd_soc_component_driver soc_codec_dev_cpcap = {
 
 static int cpcap_codec_probe(struct platform_device *pdev)
 {
-	struct device_node *codec_node =
-		of_get_child_by_name(pdev->dev.parent->of_node, "audio-codec");
+	struct cpcap_audio *cpcap;
+	struct device_node *codec_node;
+	int ret;
 
+	codec_node = of_get_child_by_name(pdev->dev.parent->of_node, "audio-codec");
 	pdev->dev.of_node = codec_node;
 
-	return devm_snd_soc_register_component(&pdev->dev, &soc_codec_dev_cpcap,
+	cpcap = devm_kzalloc(&pdev->dev, sizeof(*cpcap), GFP_KERNEL);
+	if (!cpcap)
+		return -ENOMEM;
+	dev_set_drvdata(&pdev->dev, cpcap);
+
+	ret = devm_snd_soc_register_component(&pdev->dev, &soc_codec_dev_cpcap,
 				      cpcap_dai, ARRAY_SIZE(cpcap_dai));
+	if (ret < 0)
+		return ret;
+
+	cpcap->hp_irq = platform_get_irq_byname(pdev, "hpplugged");
+	if (cpcap->hp_irq < 0)
+		return -ENODEV;
+
+	cpcap->dev = &pdev->dev;
+
+	ret = devm_request_threaded_irq(&pdev->dev, cpcap->hp_irq, NULL,
+					  cpcap_hp_irq_thread,
+					  IRQF_TRIGGER_RISING |
+					  IRQF_TRIGGER_FALLING |
+					  IRQF_ONESHOT,
+					  "cpcap-codec-headphone", cpcap);
+	if (ret) {
+		dev_err(&pdev->dev, "could not get irq: %i\n",
+			ret);
+		return ret;
+	}
+
+	return 0;
 }
 
 static struct platform_driver cpcap_codec_driver = {
-- 
2.35.1

-- 
Carl Philipp Klemm <philipp@uvos.xyz> <carl@uvos.xyz>

On Mon, 10 Jan 2022 23:27:52 +0000
Kuninori Morimoto <kuninori.morimoto.gx@renesas.com> wrote:

> 
> Hi Carl
> 
> >> (X)	int asoc_simple_init_jack(...)
> >> 	{
> >> 		...
> >> 		if (gpio_is_valid(det)) {
> >> 			...
> >> 
> >> 			snd_soc_card_jack_new(...);
> >> 			snd_soc_jack_add_gpios(...);
> >> 			for_each_card_components(card, component)
> >> (Y)				snd_soc_component_set_jack(component, ...);
> >> 		}
> >> 		...
> >> 	}
> >
> > So for the case of cpcap codec on motorola mapphones this dosent help,
> > because we dont have a gpio to sense plug state, thus no gpio in dts
> > and thus gpio_is_valid will return false, therefore, no jack.
> >
> > Moving 
> >
> > sjack->pin.pin		= pin_name;
> > sjack->pin.mask		= mask;
> >
> > snd_soc_card_jack_new(card, pin_name, mask,
> > 		      &sjack->jack,
> > 		      &sjack->pin, 1);
> >
> > and
> >
> > for_each_card_components(card, component)
> > 			snd_soc_component_set_jack(component, &sjack->jack, NULL);
> >
> > outside of the if block should make this work, at least cpcap gets the jack then.
> 
> I see.
> 
> simple-card is checking hp-det-gpio on DT now.
> I guess it can help you if simple-card also check "hp-det" (no gpio)
> (and customize previous patch) ?
> Is "enable-hp" better naming... ?
> 
> Best regards
> ---
> Kuninori Morimoto

  parent reply	other threads:[~2022-02-20  0:17 UTC|newest]

Thread overview: 30+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2021-12-28 18:09 [RFC PATCH 1/3] ASoC: simple-card-utils: add support for componants provideing jack events via set_jack Carl Philipp Klemm
2021-12-28 18:09 ` Carl Philipp Klemm
2021-12-28 18:11 ` [RFC PATCH 2/3] ARM: dts: motorola-mapphone: add interrupt for headphone detection Carl Philipp Klemm
2021-12-28 18:11   ` Carl Philipp Klemm
2021-12-28 18:15   ` [RFC PATCH 3/3] ASoC: cpcap: add headphone jack plug detection support Carl Philipp Klemm
2021-12-28 18:15     ` Carl Philipp Klemm
2022-01-04 15:50     ` [RFC PATCH 3/3 V2] " Carl Philipp Klemm
2022-01-04 15:51       ` Carl Philipp Klemm
2022-01-05  5:36 ` [RFC PATCH 1/3] ASoC: simple-card-utils: add support for componants provideing jack events via set_jack kuninori.morimoto.gx
2022-01-05  5:36   ` kuninori.morimoto.gx
2022-01-05  9:10   ` Carl Philipp Klemm
2022-01-05  9:10     ` Carl Philipp Klemm
2022-01-06  1:47     ` kuninori.morimoto.gx
2022-01-06  1:47       ` kuninori.morimoto.gx
2022-01-08 13:57       ` Carl Philipp Klemm
2022-01-08 13:57         ` Carl Philipp Klemm
2022-01-10 23:27         ` Kuninori Morimoto
2022-01-10 23:27           ` Kuninori Morimoto
2022-02-20  0:14           ` [PATCH 1/6] ASoC: simple_card_utils: call snd_soc_component_set_jack() at asoc_simple_init_jack() Carl Philipp Klemm
2022-02-20  0:14             ` Carl Philipp Klemm
2022-02-20  0:15           ` [PATCH 2/6] ASoC: audio-graph-card: use new functionality in simple_card_utils to implement has-hp-jack of property Carl Philipp Klemm
2022-02-20  0:15             ` Carl Philipp Klemm
2022-02-20  0:15           ` Carl Philipp Klemm [this message]
2022-02-20  0:15             ` [PATCH 3/6] ASoC: cpcap: add headphone jack plug detection support Carl Philipp Klemm
2022-02-20  0:15           ` [PATCH 4/6] ARM: dts: motorola-mapphone: add interrupt for headphone detection Carl Philipp Klemm
2022-02-20  0:15             ` Carl Philipp Klemm
2022-02-20  0:15           ` [PATCH 5/6] ARM: dts: motorola-mapphone: add has-hp-jack for audio-graph-card Carl Philipp Klemm
2022-02-20  0:15             ` Carl Philipp Klemm
2022-02-20  0:18           ` [PATCH 6/6] Documentation: sound: audio-graph-card: update dts bindings to add has-hp-jack Carl Philipp Klemm
2022-02-20  0:18             ` Carl Philipp Klemm

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20220220011551.a132b8f7d033d3e1eb731013@uvos.xyz \
    --to=philipp@uvos.xyz \
    --cc=alsa-devel@alsa-project.org \
    --cc=kuninori.morimoto.gx@gmail.com \
    --cc=kuninori.morimoto.gx@renesas.com \
    --cc=linux-omap@vger.kernel.org \
    --cc=merlijn@wizzup.org \
    --cc=sre@kernel.org \
    --cc=tony@atomide.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.