All of lore.kernel.org
 help / color / mirror / Atom feed
* [RFC PATCH 1/3] ASoC: simple-card-utils: add support for componants provideing jack events via set_jack
@ 2021-12-28 18:09 ` Carl Philipp Klemm
  0 siblings, 0 replies; 30+ messages in thread
From: Carl Philipp Klemm @ 2021-12-28 18:09 UTC (permalink / raw)
  To: alsa-devel; +Cc: merlijn, tony, sre, linux-omap, kuninori.morimoto.gx

This allows componants that want a jack to report state on to do so by calling
set_jack on components implementing this function.

Im not entirely sure this is the right way to do this so RFC

Signed-off-by: Carl Philipp Klemm <philipp@uvos.xyz>
---
 include/sound/simple_card_utils.h     |  6 ++--
 sound/soc/generic/simple-card-utils.c | 47 +++++++++++++++++++--------
 2 files changed, 36 insertions(+), 17 deletions(-)

diff --git a/include/sound/simple_card_utils.h b/include/sound/simple_card_utils.h
index 51b3b485a92e..547ad537613d 100644
--- a/include/sound/simple_card_utils.h
+++ b/include/sound/simple_card_utils.h
@@ -57,8 +57,8 @@ struct asoc_simple_priv {
 		struct prop_nums num;
 		unsigned int mclk_fs;
 	} *dai_props;
-	struct asoc_simple_jack hp_jack;
-	struct asoc_simple_jack mic_jack;
+	struct asoc_simple_jack *hp_jack;
+	struct asoc_simple_jack *mic_jack;
 	struct snd_soc_dai_link *dai_link;
 	struct asoc_simple_dai *dais;
 	struct snd_soc_dai_link_component *dlcs;
@@ -173,7 +173,7 @@ int asoc_simple_parse_pin_switches(struct snd_soc_card *card,
 				   char *prefix);
 
 int asoc_simple_init_jack(struct snd_soc_card *card,
-			       struct asoc_simple_jack *sjack,
+			       struct asoc_simple_jack **sjack,
 			       int is_hp, char *prefix, char *pin);
 int asoc_simple_init_priv(struct asoc_simple_priv *priv,
 			       struct link_info *li);
diff --git a/sound/soc/generic/simple-card-utils.c b/sound/soc/generic/simple-card-utils.c
index 10c63b73900c..1899feba16cc 100644
--- a/sound/soc/generic/simple-card-utils.c
+++ b/sound/soc/generic/simple-card-utils.c
@@ -395,6 +395,7 @@ int asoc_simple_dai_init(struct snd_soc_pcm_runtime *rtd)
 	struct asoc_simple_priv *priv = snd_soc_card_get_drvdata(rtd->card);
 	struct simple_dai_props *props = simple_priv_to_props(priv, rtd->num);
 	struct asoc_simple_dai *dai;
+	struct snd_soc_component *component;
 	int i, ret;
 
 	for_each_prop_dai_codec(props, i, dai) {
@@ -412,6 +413,21 @@ int asoc_simple_dai_init(struct snd_soc_pcm_runtime *rtd)
 	if (ret < 0)
 		return ret;
 
+	for_each_rtd_components(rtd, i, component) {
+		if (component->driver->set_jack) {
+			if (!priv->hp_jack) {
+				priv->hp_jack = devm_kzalloc(priv->snd_card.dev,
+					sizeof(*priv->hp_jack), GFP_KERNEL);
+				snd_soc_card_jack_new(&priv->snd_card,
+					"Headphones",
+					SND_JACK_HEADPHONE,
+					&priv->hp_jack->jack,
+					NULL, 0);
+			}
+			snd_soc_component_set_jack(component, &priv->hp_jack->jack, NULL);
+		}
+	}
+
 	return 0;
 }
 EXPORT_SYMBOL_GPL(asoc_simple_dai_init);
@@ -554,7 +570,7 @@ int asoc_simple_parse_pin_switches(struct snd_soc_card *card,
 EXPORT_SYMBOL_GPL(asoc_simple_parse_pin_switches);
 
 int asoc_simple_init_jack(struct snd_soc_card *card,
-			  struct asoc_simple_jack *sjack,
+			  struct asoc_simple_jack **sjack,
 			  int is_hp, char *prefix,
 			  char *pin)
 {
@@ -569,8 +585,6 @@ int asoc_simple_init_jack(struct snd_soc_card *card,
 	if (!prefix)
 		prefix = "";
 
-	sjack->gpio.gpio = -ENOENT;
-
 	if (is_hp) {
 		snprintf(prop, sizeof(prop), "%shp-det-gpio", prefix);
 		pin_name	= pin ? pin : "Headphones";
@@ -588,21 +602,26 @@ int asoc_simple_init_jack(struct snd_soc_card *card,
 		return -EPROBE_DEFER;
 
 	if (gpio_is_valid(det)) {
-		sjack->pin.pin		= pin_name;
-		sjack->pin.mask		= mask;
+		struct asoc_simple_jack *sjack_d;
+
+		sjack = devm_kzalloc(dev, sizeof(*(*sjack)), GFP_KERNEL);
+		sjack_d = *sjack;
+
+		sjack_d->pin.pin		= pin_name;
+		sjack_d->pin.mask		= mask;
 
-		sjack->gpio.name	= gpio_name;
-		sjack->gpio.report	= mask;
-		sjack->gpio.gpio	= det;
-		sjack->gpio.invert	= !!(flags & OF_GPIO_ACTIVE_LOW);
-		sjack->gpio.debounce_time = 150;
+		sjack_d->gpio.name	= gpio_name;
+		sjack_d->gpio.report	= mask;
+		sjack_d->gpio.gpio	= det;
+		sjack_d->gpio.invert	= !!(flags & OF_GPIO_ACTIVE_LOW);
+		sjack_d->gpio.debounce_time = 150;
 
 		snd_soc_card_jack_new(card, pin_name, mask,
-				      &sjack->jack,
-				      &sjack->pin, 1);
+				      &sjack_d->jack,
+				      &sjack_d->pin, 1);
 
-		snd_soc_jack_add_gpios(&sjack->jack, 1,
-				       &sjack->gpio);
+		snd_soc_jack_add_gpios(&sjack_d->jack, 1,
+				       &sjack_d->gpio);
 	}
 
 	return 0;
-- 
2.34.1

^ permalink raw reply related	[flat|nested] 30+ messages in thread

* [RFC PATCH 1/3] ASoC: simple-card-utils: add support for componants provideing jack events via set_jack
@ 2021-12-28 18:09 ` Carl Philipp Klemm
  0 siblings, 0 replies; 30+ messages in thread
From: Carl Philipp Klemm @ 2021-12-28 18:09 UTC (permalink / raw)
  To: alsa-devel; +Cc: tony, merlijn, linux-omap, sre, kuninori.morimoto.gx

This allows componants that want a jack to report state on to do so by calling
set_jack on components implementing this function.

Im not entirely sure this is the right way to do this so RFC

Signed-off-by: Carl Philipp Klemm <philipp@uvos.xyz>
---
 include/sound/simple_card_utils.h     |  6 ++--
 sound/soc/generic/simple-card-utils.c | 47 +++++++++++++++++++--------
 2 files changed, 36 insertions(+), 17 deletions(-)

diff --git a/include/sound/simple_card_utils.h b/include/sound/simple_card_utils.h
index 51b3b485a92e..547ad537613d 100644
--- a/include/sound/simple_card_utils.h
+++ b/include/sound/simple_card_utils.h
@@ -57,8 +57,8 @@ struct asoc_simple_priv {
 		struct prop_nums num;
 		unsigned int mclk_fs;
 	} *dai_props;
-	struct asoc_simple_jack hp_jack;
-	struct asoc_simple_jack mic_jack;
+	struct asoc_simple_jack *hp_jack;
+	struct asoc_simple_jack *mic_jack;
 	struct snd_soc_dai_link *dai_link;
 	struct asoc_simple_dai *dais;
 	struct snd_soc_dai_link_component *dlcs;
@@ -173,7 +173,7 @@ int asoc_simple_parse_pin_switches(struct snd_soc_card *card,
 				   char *prefix);
 
 int asoc_simple_init_jack(struct snd_soc_card *card,
-			       struct asoc_simple_jack *sjack,
+			       struct asoc_simple_jack **sjack,
 			       int is_hp, char *prefix, char *pin);
 int asoc_simple_init_priv(struct asoc_simple_priv *priv,
 			       struct link_info *li);
diff --git a/sound/soc/generic/simple-card-utils.c b/sound/soc/generic/simple-card-utils.c
index 10c63b73900c..1899feba16cc 100644
--- a/sound/soc/generic/simple-card-utils.c
+++ b/sound/soc/generic/simple-card-utils.c
@@ -395,6 +395,7 @@ int asoc_simple_dai_init(struct snd_soc_pcm_runtime *rtd)
 	struct asoc_simple_priv *priv = snd_soc_card_get_drvdata(rtd->card);
 	struct simple_dai_props *props = simple_priv_to_props(priv, rtd->num);
 	struct asoc_simple_dai *dai;
+	struct snd_soc_component *component;
 	int i, ret;
 
 	for_each_prop_dai_codec(props, i, dai) {
@@ -412,6 +413,21 @@ int asoc_simple_dai_init(struct snd_soc_pcm_runtime *rtd)
 	if (ret < 0)
 		return ret;
 
+	for_each_rtd_components(rtd, i, component) {
+		if (component->driver->set_jack) {
+			if (!priv->hp_jack) {
+				priv->hp_jack = devm_kzalloc(priv->snd_card.dev,
+					sizeof(*priv->hp_jack), GFP_KERNEL);
+				snd_soc_card_jack_new(&priv->snd_card,
+					"Headphones",
+					SND_JACK_HEADPHONE,
+					&priv->hp_jack->jack,
+					NULL, 0);
+			}
+			snd_soc_component_set_jack(component, &priv->hp_jack->jack, NULL);
+		}
+	}
+
 	return 0;
 }
 EXPORT_SYMBOL_GPL(asoc_simple_dai_init);
@@ -554,7 +570,7 @@ int asoc_simple_parse_pin_switches(struct snd_soc_card *card,
 EXPORT_SYMBOL_GPL(asoc_simple_parse_pin_switches);
 
 int asoc_simple_init_jack(struct snd_soc_card *card,
-			  struct asoc_simple_jack *sjack,
+			  struct asoc_simple_jack **sjack,
 			  int is_hp, char *prefix,
 			  char *pin)
 {
@@ -569,8 +585,6 @@ int asoc_simple_init_jack(struct snd_soc_card *card,
 	if (!prefix)
 		prefix = "";
 
-	sjack->gpio.gpio = -ENOENT;
-
 	if (is_hp) {
 		snprintf(prop, sizeof(prop), "%shp-det-gpio", prefix);
 		pin_name	= pin ? pin : "Headphones";
@@ -588,21 +602,26 @@ int asoc_simple_init_jack(struct snd_soc_card *card,
 		return -EPROBE_DEFER;
 
 	if (gpio_is_valid(det)) {
-		sjack->pin.pin		= pin_name;
-		sjack->pin.mask		= mask;
+		struct asoc_simple_jack *sjack_d;
+
+		sjack = devm_kzalloc(dev, sizeof(*(*sjack)), GFP_KERNEL);
+		sjack_d = *sjack;
+
+		sjack_d->pin.pin		= pin_name;
+		sjack_d->pin.mask		= mask;
 
-		sjack->gpio.name	= gpio_name;
-		sjack->gpio.report	= mask;
-		sjack->gpio.gpio	= det;
-		sjack->gpio.invert	= !!(flags & OF_GPIO_ACTIVE_LOW);
-		sjack->gpio.debounce_time = 150;
+		sjack_d->gpio.name	= gpio_name;
+		sjack_d->gpio.report	= mask;
+		sjack_d->gpio.gpio	= det;
+		sjack_d->gpio.invert	= !!(flags & OF_GPIO_ACTIVE_LOW);
+		sjack_d->gpio.debounce_time = 150;
 
 		snd_soc_card_jack_new(card, pin_name, mask,
-				      &sjack->jack,
-				      &sjack->pin, 1);
+				      &sjack_d->jack,
+				      &sjack_d->pin, 1);
 
-		snd_soc_jack_add_gpios(&sjack->jack, 1,
-				       &sjack->gpio);
+		snd_soc_jack_add_gpios(&sjack_d->jack, 1,
+				       &sjack_d->gpio);
 	}
 
 	return 0;
-- 
2.34.1

^ permalink raw reply related	[flat|nested] 30+ messages in thread

* [RFC PATCH 2/3] ARM: dts: motorola-mapphone: add interrupt for headphone detection
  2021-12-28 18:09 ` Carl Philipp Klemm
@ 2021-12-28 18:11   ` Carl Philipp Klemm
  -1 siblings, 0 replies; 30+ messages in thread
From: Carl Philipp Klemm @ 2021-12-28 18:11 UTC (permalink / raw)
  To: alsa-devel; +Cc: merlijn, tony, sre, linux-omap, kuninori.morimoto.gx

Signed-off-by: Carl Philipp Klemm <philipp@uvos.xyz>
---
 arch/arm/boot/dts/motorola-cpcap-mapphone.dtsi | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/arch/arm/boot/dts/motorola-cpcap-mapphone.dtsi b/arch/arm/boot/dts/motorola-cpcap-mapphone.dtsi
index 0aff0d306d06..e164169bf820 100644
--- a/arch/arm/boot/dts/motorola-cpcap-mapphone.dtsi
+++ b/arch/arm/boot/dts/motorola-cpcap-mapphone.dtsi
@@ -72,6 +72,9 @@ cpcap_audio: audio-codec {
 			#address-cells = <1>;
 			#size-cells = <0>;
 
+			interrupts-extended = <&cpcap 9 0>;
+			interrupt-names = "hpplugged";
+
 			port@0 {
 				reg = <0>;
 				cpcap_audio_codec0: endpoint {
-- 
2.34.1

^ permalink raw reply related	[flat|nested] 30+ messages in thread

* [RFC PATCH 2/3] ARM: dts: motorola-mapphone: add interrupt for headphone detection
@ 2021-12-28 18:11   ` Carl Philipp Klemm
  0 siblings, 0 replies; 30+ messages in thread
From: Carl Philipp Klemm @ 2021-12-28 18:11 UTC (permalink / raw)
  To: alsa-devel; +Cc: tony, merlijn, linux-omap, sre, kuninori.morimoto.gx

Signed-off-by: Carl Philipp Klemm <philipp@uvos.xyz>
---
 arch/arm/boot/dts/motorola-cpcap-mapphone.dtsi | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/arch/arm/boot/dts/motorola-cpcap-mapphone.dtsi b/arch/arm/boot/dts/motorola-cpcap-mapphone.dtsi
index 0aff0d306d06..e164169bf820 100644
--- a/arch/arm/boot/dts/motorola-cpcap-mapphone.dtsi
+++ b/arch/arm/boot/dts/motorola-cpcap-mapphone.dtsi
@@ -72,6 +72,9 @@ cpcap_audio: audio-codec {
 			#address-cells = <1>;
 			#size-cells = <0>;
 
+			interrupts-extended = <&cpcap 9 0>;
+			interrupt-names = "hpplugged";
+
 			port@0 {
 				reg = <0>;
 				cpcap_audio_codec0: endpoint {
-- 
2.34.1

^ permalink raw reply related	[flat|nested] 30+ messages in thread

* [RFC PATCH 3/3] ASoC: cpcap: add headphone jack plug detection support
  2021-12-28 18:11   ` Carl Philipp Klemm
@ 2021-12-28 18:15     ` Carl Philipp Klemm
  -1 siblings, 0 replies; 30+ messages in thread
From: Carl Philipp Klemm @ 2021-12-28 18:15 UTC (permalink / raw)
  To: alsa-devel; +Cc: merlijn, tony, sre, linux-omap, kuninori.morimoto.gx

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

This patch currently also reports on "Headphones" pin. this correctly
causes a warning as this pin dose not exist, however reporting on any
other pin causes userspace (pulse audio) to not react to the change, im
not sure how pulseaudio is supposed to be configured to avoid this
deliemma "Headphones" apears to be hard-coded, please do lmk if someone
knows how to resolve this.

---
 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 3c2bc98031b5..ed418ac75eca 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.34.1



^ permalink raw reply related	[flat|nested] 30+ messages in thread

* [RFC PATCH 3/3] ASoC: cpcap: add headphone jack plug detection support
@ 2021-12-28 18:15     ` Carl Philipp Klemm
  0 siblings, 0 replies; 30+ messages in thread
From: Carl Philipp Klemm @ 2021-12-28 18:15 UTC (permalink / raw)
  To: alsa-devel; +Cc: tony, merlijn, linux-omap, sre, kuninori.morimoto.gx

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

This patch currently also reports on "Headphones" pin. this correctly
causes a warning as this pin dose not exist, however reporting on any
other pin causes userspace (pulse audio) to not react to the change, im
not sure how pulseaudio is supposed to be configured to avoid this
deliemma "Headphones" apears to be hard-coded, please do lmk if someone
knows how to resolve this.

---
 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 3c2bc98031b5..ed418ac75eca 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.34.1



^ permalink raw reply related	[flat|nested] 30+ messages in thread

* Re: [RFC PATCH 3/3 V2] ASoC: cpcap: add headphone jack plug detection support
  2021-12-28 18:15     ` Carl Philipp Klemm
  (?)
@ 2022-01-04 15:50     ` Carl Philipp Klemm
  2022-01-04 15:51       ` Carl Philipp Klemm
  -1 siblings, 1 reply; 30+ messages in thread
From: Carl Philipp Klemm @ 2022-01-04 15:50 UTC (permalink / raw)
  To: inux-omap; +Cc: tony, alsa-devel, merlijn, kuninori.morimoto.gx, sre

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 3c2bc98031b5..ed418ac75eca 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.34.1

^ permalink raw reply related	[flat|nested] 30+ messages in thread

* [RFC PATCH 3/3 V2] ASoC: cpcap: add headphone jack plug detection support
  2022-01-04 15:50     ` [RFC PATCH 3/3 V2] " Carl Philipp Klemm
@ 2022-01-04 15:51       ` Carl Philipp Klemm
  0 siblings, 0 replies; 30+ messages in thread
From: Carl Philipp Klemm @ 2022-01-04 15:51 UTC (permalink / raw)
  To: linux-omap

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 3c2bc98031b5..ed418ac75eca 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.34.1


^ permalink raw reply related	[flat|nested] 30+ messages in thread

* Re: [RFC PATCH 1/3] ASoC: simple-card-utils: add support for componants provideing jack events via set_jack
  2021-12-28 18:09 ` Carl Philipp Klemm
@ 2022-01-05  5:36   ` kuninori.morimoto.gx
  -1 siblings, 0 replies; 30+ messages in thread
From: kuninori.morimoto.gx @ 2022-01-05  5:36 UTC (permalink / raw)
  To: Carl Philipp Klemm
  Cc: alsa-devel, merlijn, tony, sre, linux-omap, kuninori.morimoto.gx


Hi Carl

Thank you for your patch.

> This allows componants that want a jack to report state on to do so by calling
> set_jack on components implementing this function.
>
> Im not entirely sure this is the right way to do this so RFC
(snip)
> +	for_each_rtd_components(rtd, i, component) {
> +		if (component->driver->set_jack) {
> +			if (!priv->hp_jack) {
> +				priv->hp_jack = devm_kzalloc(priv->snd_card.dev,
> +					sizeof(*priv->hp_jack), GFP_KERNEL);
> +				snd_soc_card_jack_new(&priv->snd_card,
> +					"Headphones",
> +					SND_JACK_HEADPHONE,
> +					&priv->hp_jack->jack,
> +					NULL, 0);
> +			}
> +			snd_soc_component_set_jack(component, &priv->hp_jack->jack, NULL);
> +		}
> +	}

I'm sorry but I don't understand what you want to do by this patch.
Is main code of this patch asoc_simple_dai_init() update
(= call set_jack() for all component) ?

>  int asoc_simple_init_jack(struct snd_soc_card *card,
> -			       struct asoc_simple_jack *sjack,
> +			       struct asoc_simple_jack **sjack,
>  			       int is_hp, char *prefix, char *pin);

${LINUX}/sound/soc/fsl/fsl-asoc-card.c is using this function, too.
We will have compile error without update it.

>  int asoc_simple_init_jack(struct snd_soc_card *card,
> -			  struct asoc_simple_jack *sjack,
> +			  struct asoc_simple_jack **sjack,
>  			  int is_hp, char *prefix,
>  			  char *pin)
(snip)
>  	if (gpio_is_valid(det)) {
> -		sjack->pin.pin		= pin_name;
> -		sjack->pin.mask		= mask;
> +		struct asoc_simple_jack *sjack_d;
> +
> +		sjack = devm_kzalloc(dev, sizeof(*(*sjack)), GFP_KERNEL);
> +		sjack_d = *sjack;

Am I misunderstanding ?
I think you need to do here is this ?

	-	sjack = devm_kzalloc(dev, sizeof(*(*sjack)), GFP_KERNEL);	
	+	*sjack = devm_kzalloc(dev, sizeof(*(*sjack)), GFP_KERNEL);

Thank you for your help !!

Best regards
---
Kuninori Morimoto

^ permalink raw reply	[flat|nested] 30+ messages in thread

* Re: [RFC PATCH 1/3] ASoC: simple-card-utils: add support for componants provideing jack events via set_jack
@ 2022-01-05  5:36   ` kuninori.morimoto.gx
  0 siblings, 0 replies; 30+ messages in thread
From: kuninori.morimoto.gx @ 2022-01-05  5:36 UTC (permalink / raw)
  To: Carl Philipp Klemm
  Cc: alsa-devel, kuninori.morimoto.gx, tony, merlijn, sre, linux-omap


Hi Carl

Thank you for your patch.

> This allows componants that want a jack to report state on to do so by calling
> set_jack on components implementing this function.
>
> Im not entirely sure this is the right way to do this so RFC
(snip)
> +	for_each_rtd_components(rtd, i, component) {
> +		if (component->driver->set_jack) {
> +			if (!priv->hp_jack) {
> +				priv->hp_jack = devm_kzalloc(priv->snd_card.dev,
> +					sizeof(*priv->hp_jack), GFP_KERNEL);
> +				snd_soc_card_jack_new(&priv->snd_card,
> +					"Headphones",
> +					SND_JACK_HEADPHONE,
> +					&priv->hp_jack->jack,
> +					NULL, 0);
> +			}
> +			snd_soc_component_set_jack(component, &priv->hp_jack->jack, NULL);
> +		}
> +	}

I'm sorry but I don't understand what you want to do by this patch.
Is main code of this patch asoc_simple_dai_init() update
(= call set_jack() for all component) ?

>  int asoc_simple_init_jack(struct snd_soc_card *card,
> -			       struct asoc_simple_jack *sjack,
> +			       struct asoc_simple_jack **sjack,
>  			       int is_hp, char *prefix, char *pin);

${LINUX}/sound/soc/fsl/fsl-asoc-card.c is using this function, too.
We will have compile error without update it.

>  int asoc_simple_init_jack(struct snd_soc_card *card,
> -			  struct asoc_simple_jack *sjack,
> +			  struct asoc_simple_jack **sjack,
>  			  int is_hp, char *prefix,
>  			  char *pin)
(snip)
>  	if (gpio_is_valid(det)) {
> -		sjack->pin.pin		= pin_name;
> -		sjack->pin.mask		= mask;
> +		struct asoc_simple_jack *sjack_d;
> +
> +		sjack = devm_kzalloc(dev, sizeof(*(*sjack)), GFP_KERNEL);
> +		sjack_d = *sjack;

Am I misunderstanding ?
I think you need to do here is this ?

	-	sjack = devm_kzalloc(dev, sizeof(*(*sjack)), GFP_KERNEL);	
	+	*sjack = devm_kzalloc(dev, sizeof(*(*sjack)), GFP_KERNEL);

Thank you for your help !!

Best regards
---
Kuninori Morimoto

^ permalink raw reply	[flat|nested] 30+ messages in thread

* Re: [RFC PATCH 1/3] ASoC: simple-card-utils: add support for componants provideing jack events via set_jack
  2022-01-05  5:36   ` kuninori.morimoto.gx
@ 2022-01-05  9:10     ` Carl Philipp Klemm
  -1 siblings, 0 replies; 30+ messages in thread
From: Carl Philipp Klemm @ 2022-01-05  9:10 UTC (permalink / raw)
  To: kuninori.morimoto.gx
  Cc: alsa-devel, merlijn, tony, sre, linux-omap, kuninori.morimoto.gx

Hi,

> I'm sorry but I don't understand what you want to do by this patch.
> Is main code of this patch asoc_simple_dai_init() update
> (= call set_jack() for all component) ?

Yes, so asoc-audio-graph-card currently only supports headphone jack plug
detection on devices that provide a simple gpio to sense plug state. The
intent of this patch is to allow the componant driver to implement jack
detection in cases where something else has to be done to sense state,
sutch as comunicating with device firmware or using a shared irq. See
the other patches in this series for an example. This is performed by
sharing the jack with the component via set_jack().
 
> ${LINUX}/sound/soc/fsl/fsl-asoc-card.c is using this function, too.
> We will have compile error without update it.

indeed, will do.

> > +		sjack = devm_kzalloc(dev, sizeof(*(*sjack)), GFP_KERNEL);
> > +		sjack_d = *sjack;
> 
> Am I misunderstanding ?
> I think you need to do here is this ?
> 
> 	-	sjack = devm_kzalloc(dev, sizeof(*(*sjack)), GFP_KERNEL);	
> 	+	*sjack = devm_kzalloc(dev, sizeof(*(*sjack)), GFP_KERNEL);

Ah yes thank you, another problem is i lack hardware to test this (the gpio) path.

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

^ permalink raw reply	[flat|nested] 30+ messages in thread

* Re: [RFC PATCH 1/3] ASoC: simple-card-utils: add support for componants provideing jack events via set_jack
@ 2022-01-05  9:10     ` Carl Philipp Klemm
  0 siblings, 0 replies; 30+ messages in thread
From: Carl Philipp Klemm @ 2022-01-05  9:10 UTC (permalink / raw)
  To: kuninori.morimoto.gx
  Cc: alsa-devel, kuninori.morimoto.gx, tony, merlijn, sre, linux-omap

Hi,

> I'm sorry but I don't understand what you want to do by this patch.
> Is main code of this patch asoc_simple_dai_init() update
> (= call set_jack() for all component) ?

Yes, so asoc-audio-graph-card currently only supports headphone jack plug
detection on devices that provide a simple gpio to sense plug state. The
intent of this patch is to allow the componant driver to implement jack
detection in cases where something else has to be done to sense state,
sutch as comunicating with device firmware or using a shared irq. See
the other patches in this series for an example. This is performed by
sharing the jack with the component via set_jack().
 
> ${LINUX}/sound/soc/fsl/fsl-asoc-card.c is using this function, too.
> We will have compile error without update it.

indeed, will do.

> > +		sjack = devm_kzalloc(dev, sizeof(*(*sjack)), GFP_KERNEL);
> > +		sjack_d = *sjack;
> 
> Am I misunderstanding ?
> I think you need to do here is this ?
> 
> 	-	sjack = devm_kzalloc(dev, sizeof(*(*sjack)), GFP_KERNEL);	
> 	+	*sjack = devm_kzalloc(dev, sizeof(*(*sjack)), GFP_KERNEL);

Ah yes thank you, another problem is i lack hardware to test this (the gpio) path.

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

^ permalink raw reply	[flat|nested] 30+ messages in thread

* Re: [RFC PATCH 1/3] ASoC: simple-card-utils: add support for componants provideing jack events via set_jack
  2022-01-05  9:10     ` Carl Philipp Klemm
@ 2022-01-06  1:47       ` kuninori.morimoto.gx
  -1 siblings, 0 replies; 30+ messages in thread
From: kuninori.morimoto.gx @ 2022-01-06  1:47 UTC (permalink / raw)
  To: Carl Philipp Klemm
  Cc: alsa-devel, merlijn, tony, sre, linux-omap, kuninori.morimoto.gx


Hi Carl

> Yes, so asoc-audio-graph-card currently only supports headphone jack plug
> detection on devices that provide a simple gpio to sense plug state. The
> intent of this patch is to allow the componant driver to implement jack
> detection in cases where something else has to be done to sense state,
> sutch as comunicating with device firmware or using a shared irq. See
> the other patches in this series for an example. This is performed by
> sharing the jack with the component via set_jack().

OK, I see.
It seems other drivers are using dai_link->init for detecting and set_jack().

I guess we can call set_jack() at asoc_simple_init_jack() and
call asoc_simple_init_hp() at dai_link->init ?

It is not tested, but I added sample code below.
I hope my understanding was correct and it solves your issue.

> sutch as comunicating with device firmware or using a shared irq. See
> the other patches in this series for an example. This is performed by

I now noticed that I had mailing list issue...

Thank you for your help !!

-----------
From: Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
Subject: [PATCH] ASoC: simple_card_utils: call snd_soc_component_set_jack() at
 asoc_simple_init_jack()

Current simple-card / audio-graph-card are detecting HP/MIC at card->probe
timing (= A), and not calling snd_soc_component_set_jack() for it.
Other sound card drivers are using dai_link->init timing (= B) for
both detecting and set_jack().

	static int snd_soc_bind_card(...)
	{
		....
(A)		ret = snd_soc_card_probe(card);
		...
		for_each_card_rtds(card, rtd) {
(B)			ret = soc_init_pcm_runtime(card, rtd);
			...
		}
		...
	}

This patch do
(a) call set_jack() (= Y) at asoc_simple_init_jack() (= X) which is
    used to detect HP/MIC.
(b) call it from dai_link->init timing (= B) instead of card->probe
    timing (= A).
(c) remove card->init (= A) timing function from
    simple-card / audio-graph-card.

(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, ...);
		}
		...
	}

One note here is that simple-card needs PREFIX to detecting HP/MIC,
but it is not needed on audio-graph-card.
Thus simple-card uses local function for it, and audio-graph-card is
using global function and sharing the code with
audio-graph-card / audio-graph-card2 / audio-graph-card2-custom-sample /
tegra_audio_graph_card.

Reported-by: Carl Philipp Klemm <philipp@uvos.xyz>
Signed-off-by: Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
---
 include/sound/simple_card_utils.h             |  2 +-
 sound/soc/generic/audio-graph-card.c          |  3 +-
 .../generic/audio-graph-card2-custom-sample.c |  3 +-
 sound/soc/generic/audio-graph-card2.c         |  3 +-
 sound/soc/generic/simple-card-utils.c         | 14 ++++++-
 sound/soc/generic/simple-card.c               | 40 ++++++++++---------
 sound/soc/tegra/tegra_audio_graph_card.c      |  2 +-
 7 files changed, 39 insertions(+), 28 deletions(-)

diff --git a/include/sound/simple_card_utils.h b/include/sound/simple_card_utils.h
index df430f1c2a10..34891da5a0fa 100644
--- a/include/sound/simple_card_utils.h
+++ b/include/sound/simple_card_utils.h
@@ -182,7 +182,7 @@ int asoc_simple_init_priv(struct asoc_simple_priv *priv,
 			       struct link_info *li);
 int asoc_simple_remove(struct platform_device *pdev);
 
-int asoc_graph_card_probe(struct snd_soc_card *card);
+int asoc_graph_dai_init(struct snd_soc_pcm_runtime *rtd);
 int asoc_graph_is_ports0(struct device_node *port);
 
 #ifdef DEBUG
diff --git a/sound/soc/generic/audio-graph-card.c b/sound/soc/generic/audio-graph-card.c
index 2b598af8feef..456db1f894af 100644
--- a/sound/soc/generic/audio-graph-card.c
+++ b/sound/soc/generic/audio-graph-card.c
@@ -259,7 +259,7 @@ static int graph_link_init(struct asoc_simple_priv *priv,
 	if (ret < 0)
 		return ret;
 
-	dai_link->init		= asoc_simple_dai_init;
+	dai_link->init		= asoc_graph_dai_init;
 	dai_link->ops		= &graph_ops;
 	if (priv->ops)
 		dai_link->ops	= priv->ops;
@@ -716,7 +716,6 @@ static int graph_probe(struct platform_device *pdev)
 	card = simple_priv_to_card(priv);
 	card->dapm_widgets	= graph_dapm_widgets;
 	card->num_dapm_widgets	= ARRAY_SIZE(graph_dapm_widgets);
-	card->probe		= asoc_graph_card_probe;
 
 	if (of_device_get_match_data(dev))
 		priv->dpcm_selectable = 1;
diff --git a/sound/soc/generic/audio-graph-card2-custom-sample.c b/sound/soc/generic/audio-graph-card2-custom-sample.c
index 4a2c743e286c..da6cb69faa8d 100644
--- a/sound/soc/generic/audio-graph-card2-custom-sample.c
+++ b/sound/soc/generic/audio-graph-card2-custom-sample.c
@@ -34,8 +34,7 @@ static int custom_card_probe(struct snd_soc_card *card)
 
 	custom_priv->custom_params = 1;
 
-	/* you can use generic probe function */
-	return asoc_graph_card_probe(card);
+	return 0;
 }
 
 static int custom_hook_pre(struct asoc_simple_priv *priv)
diff --git a/sound/soc/generic/audio-graph-card2.c b/sound/soc/generic/audio-graph-card2.c
index c3947347dda3..75a1aeb75d2c 100644
--- a/sound/soc/generic/audio-graph-card2.c
+++ b/sound/soc/generic/audio-graph-card2.c
@@ -710,7 +710,7 @@ static void graph_link_init(struct asoc_simple_priv *priv,
 		daiclk = snd_soc_daifmt_clock_provider_fliped(daiclk);
 
 	dai_link->dai_fmt	= daifmt | daiclk;
-	dai_link->init		= asoc_simple_dai_init;
+	dai_link->init		= asoc_graph_dai_init;
 	dai_link->ops		= &graph_ops;
 	if (priv->ops)
 		dai_link->ops	= priv->ops;
@@ -1180,7 +1180,6 @@ int audio_graph2_parse_of(struct asoc_simple_priv *priv, struct device *dev,
 	if (!li)
 		return -ENOMEM;
 
-	card->probe	= asoc_graph_card_probe;
 	card->owner	= THIS_MODULE;
 	card->dev	= dev;
 
diff --git a/sound/soc/generic/simple-card-utils.c b/sound/soc/generic/simple-card-utils.c
index 850e968677f1..398fc4cb1d07 100644
--- a/sound/soc/generic/simple-card-utils.c
+++ b/sound/soc/generic/simple-card-utils.c
@@ -588,6 +588,8 @@ int asoc_simple_init_jack(struct snd_soc_card *card,
 		return -EPROBE_DEFER;
 
 	if (gpio_is_valid(det)) {
+		struct snd_soc_component *component;
+
 		sjack->pin.pin		= pin_name;
 		sjack->pin.mask		= mask;
 
@@ -603,6 +605,9 @@ int asoc_simple_init_jack(struct snd_soc_card *card,
 
 		snd_soc_jack_add_gpios(&sjack->jack, 1,
 				       &sjack->gpio);
+
+		for_each_card_components(card, component)
+			snd_soc_component_set_jack(component, &sjack->jack, NULL);
 	}
 
 	return 0;
@@ -758,11 +763,16 @@ int asoc_simple_remove(struct platform_device *pdev)
 }
 EXPORT_SYMBOL_GPL(asoc_simple_remove);
 
-int asoc_graph_card_probe(struct snd_soc_card *card)
+int asoc_graph_dai_init(struct snd_soc_pcm_runtime *rtd)
 {
+	struct snd_soc_card *card = rtd->card;
 	struct asoc_simple_priv *priv = snd_soc_card_get_drvdata(card);
 	int ret;
 
+	ret = asoc_simple_dai_init(rtd);
+	if (ret < 0)
+		return ret;
+
 	ret = asoc_simple_init_hp(card, &priv->hp_jack, NULL);
 	if (ret < 0)
 		return ret;
@@ -773,7 +783,7 @@ int asoc_graph_card_probe(struct snd_soc_card *card)
 
 	return 0;
 }
-EXPORT_SYMBOL_GPL(asoc_graph_card_probe);
+EXPORT_SYMBOL_GPL(asoc_graph_dai_init);
 
 int asoc_graph_is_ports0(struct device_node *np)
 {
diff --git a/sound/soc/generic/simple-card.c b/sound/soc/generic/simple-card.c
index a89d1cfdda32..e76bfae6ced4 100644
--- a/sound/soc/generic/simple-card.c
+++ b/sound/soc/generic/simple-card.c
@@ -149,6 +149,27 @@ static int simple_parse_node(struct asoc_simple_priv *priv,
 	return 0;
 }
 
+static int simple_dai_init(struct snd_soc_pcm_runtime *rtd)
+{
+	struct snd_soc_card *card = rtd->card;
+	struct asoc_simple_priv *priv = snd_soc_card_get_drvdata(card);
+	int ret;
+
+	ret = asoc_simple_dai_init(rtd);
+	if (ret < 0)
+		return ret;
+
+	ret = asoc_simple_init_hp(card, &priv->hp_jack, PREFIX);
+	if (ret < 0)
+		return ret;
+
+	ret = asoc_simple_init_mic(card, &priv->mic_jack, PREFIX);
+	if (ret < 0)
+		return ret;
+
+	return 0;
+}
+
 static int simple_link_init(struct asoc_simple_priv *priv,
 			    struct device_node *node,
 			    struct device_node *codec,
@@ -164,7 +185,7 @@ static int simple_link_init(struct asoc_simple_priv *priv,
 	if (ret < 0)
 		return 0;
 
-	dai_link->init			= asoc_simple_dai_init;
+	dai_link->init			= simple_dai_init;
 	dai_link->ops			= &simple_ops;
 
 	return asoc_simple_set_dailink_name(dev, dai_link, name);
@@ -587,22 +608,6 @@ static int simple_get_dais_count(struct asoc_simple_priv *priv,
 				    simple_count_dpcm);
 }
 
-static int simple_soc_probe(struct snd_soc_card *card)
-{
-	struct asoc_simple_priv *priv = snd_soc_card_get_drvdata(card);
-	int ret;
-
-	ret = asoc_simple_init_hp(card, &priv->hp_jack, PREFIX);
-	if (ret < 0)
-		return ret;
-
-	ret = asoc_simple_init_mic(card, &priv->mic_jack, PREFIX);
-	if (ret < 0)
-		return ret;
-
-	return 0;
-}
-
 static int asoc_simple_probe(struct platform_device *pdev)
 {
 	struct asoc_simple_priv *priv;
@@ -620,7 +625,6 @@ static int asoc_simple_probe(struct platform_device *pdev)
 	card = simple_priv_to_card(priv);
 	card->owner		= THIS_MODULE;
 	card->dev		= dev;
-	card->probe		= simple_soc_probe;
 	card->driver_name       = "simple-card";
 
 	li = devm_kzalloc(dev, sizeof(*li), GFP_KERNEL);
diff --git a/sound/soc/tegra/tegra_audio_graph_card.c b/sound/soc/tegra/tegra_audio_graph_card.c
index 1f2c5018bf5a..404762d40389 100644
--- a/sound/soc/tegra/tegra_audio_graph_card.c
+++ b/sound/soc/tegra/tegra_audio_graph_card.c
@@ -184,7 +184,7 @@ static int tegra_audio_graph_card_probe(struct snd_soc_card *card)
 		return PTR_ERR(priv->clk_plla_out0);
 	}
 
-	return asoc_graph_card_probe(card);
+	return 0;
 }
 
 static int tegra_audio_graph_probe(struct platform_device *pdev)
-- 
2.25.1


Best regards
---
Kuninori Morimoto

^ permalink raw reply related	[flat|nested] 30+ messages in thread

* Re: [RFC PATCH 1/3] ASoC: simple-card-utils: add support for componants provideing jack events via set_jack
@ 2022-01-06  1:47       ` kuninori.morimoto.gx
  0 siblings, 0 replies; 30+ messages in thread
From: kuninori.morimoto.gx @ 2022-01-06  1:47 UTC (permalink / raw)
  To: Carl Philipp Klemm
  Cc: alsa-devel, kuninori.morimoto.gx, tony, merlijn, sre, linux-omap


Hi Carl

> Yes, so asoc-audio-graph-card currently only supports headphone jack plug
> detection on devices that provide a simple gpio to sense plug state. The
> intent of this patch is to allow the componant driver to implement jack
> detection in cases where something else has to be done to sense state,
> sutch as comunicating with device firmware or using a shared irq. See
> the other patches in this series for an example. This is performed by
> sharing the jack with the component via set_jack().

OK, I see.
It seems other drivers are using dai_link->init for detecting and set_jack().

I guess we can call set_jack() at asoc_simple_init_jack() and
call asoc_simple_init_hp() at dai_link->init ?

It is not tested, but I added sample code below.
I hope my understanding was correct and it solves your issue.

> sutch as comunicating with device firmware or using a shared irq. See
> the other patches in this series for an example. This is performed by

I now noticed that I had mailing list issue...

Thank you for your help !!

-----------
From: Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
Subject: [PATCH] ASoC: simple_card_utils: call snd_soc_component_set_jack() at
 asoc_simple_init_jack()

Current simple-card / audio-graph-card are detecting HP/MIC at card->probe
timing (= A), and not calling snd_soc_component_set_jack() for it.
Other sound card drivers are using dai_link->init timing (= B) for
both detecting and set_jack().

	static int snd_soc_bind_card(...)
	{
		....
(A)		ret = snd_soc_card_probe(card);
		...
		for_each_card_rtds(card, rtd) {
(B)			ret = soc_init_pcm_runtime(card, rtd);
			...
		}
		...
	}

This patch do
(a) call set_jack() (= Y) at asoc_simple_init_jack() (= X) which is
    used to detect HP/MIC.
(b) call it from dai_link->init timing (= B) instead of card->probe
    timing (= A).
(c) remove card->init (= A) timing function from
    simple-card / audio-graph-card.

(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, ...);
		}
		...
	}

One note here is that simple-card needs PREFIX to detecting HP/MIC,
but it is not needed on audio-graph-card.
Thus simple-card uses local function for it, and audio-graph-card is
using global function and sharing the code with
audio-graph-card / audio-graph-card2 / audio-graph-card2-custom-sample /
tegra_audio_graph_card.

Reported-by: Carl Philipp Klemm <philipp@uvos.xyz>
Signed-off-by: Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
---
 include/sound/simple_card_utils.h             |  2 +-
 sound/soc/generic/audio-graph-card.c          |  3 +-
 .../generic/audio-graph-card2-custom-sample.c |  3 +-
 sound/soc/generic/audio-graph-card2.c         |  3 +-
 sound/soc/generic/simple-card-utils.c         | 14 ++++++-
 sound/soc/generic/simple-card.c               | 40 ++++++++++---------
 sound/soc/tegra/tegra_audio_graph_card.c      |  2 +-
 7 files changed, 39 insertions(+), 28 deletions(-)

diff --git a/include/sound/simple_card_utils.h b/include/sound/simple_card_utils.h
index df430f1c2a10..34891da5a0fa 100644
--- a/include/sound/simple_card_utils.h
+++ b/include/sound/simple_card_utils.h
@@ -182,7 +182,7 @@ int asoc_simple_init_priv(struct asoc_simple_priv *priv,
 			       struct link_info *li);
 int asoc_simple_remove(struct platform_device *pdev);
 
-int asoc_graph_card_probe(struct snd_soc_card *card);
+int asoc_graph_dai_init(struct snd_soc_pcm_runtime *rtd);
 int asoc_graph_is_ports0(struct device_node *port);
 
 #ifdef DEBUG
diff --git a/sound/soc/generic/audio-graph-card.c b/sound/soc/generic/audio-graph-card.c
index 2b598af8feef..456db1f894af 100644
--- a/sound/soc/generic/audio-graph-card.c
+++ b/sound/soc/generic/audio-graph-card.c
@@ -259,7 +259,7 @@ static int graph_link_init(struct asoc_simple_priv *priv,
 	if (ret < 0)
 		return ret;
 
-	dai_link->init		= asoc_simple_dai_init;
+	dai_link->init		= asoc_graph_dai_init;
 	dai_link->ops		= &graph_ops;
 	if (priv->ops)
 		dai_link->ops	= priv->ops;
@@ -716,7 +716,6 @@ static int graph_probe(struct platform_device *pdev)
 	card = simple_priv_to_card(priv);
 	card->dapm_widgets	= graph_dapm_widgets;
 	card->num_dapm_widgets	= ARRAY_SIZE(graph_dapm_widgets);
-	card->probe		= asoc_graph_card_probe;
 
 	if (of_device_get_match_data(dev))
 		priv->dpcm_selectable = 1;
diff --git a/sound/soc/generic/audio-graph-card2-custom-sample.c b/sound/soc/generic/audio-graph-card2-custom-sample.c
index 4a2c743e286c..da6cb69faa8d 100644
--- a/sound/soc/generic/audio-graph-card2-custom-sample.c
+++ b/sound/soc/generic/audio-graph-card2-custom-sample.c
@@ -34,8 +34,7 @@ static int custom_card_probe(struct snd_soc_card *card)
 
 	custom_priv->custom_params = 1;
 
-	/* you can use generic probe function */
-	return asoc_graph_card_probe(card);
+	return 0;
 }
 
 static int custom_hook_pre(struct asoc_simple_priv *priv)
diff --git a/sound/soc/generic/audio-graph-card2.c b/sound/soc/generic/audio-graph-card2.c
index c3947347dda3..75a1aeb75d2c 100644
--- a/sound/soc/generic/audio-graph-card2.c
+++ b/sound/soc/generic/audio-graph-card2.c
@@ -710,7 +710,7 @@ static void graph_link_init(struct asoc_simple_priv *priv,
 		daiclk = snd_soc_daifmt_clock_provider_fliped(daiclk);
 
 	dai_link->dai_fmt	= daifmt | daiclk;
-	dai_link->init		= asoc_simple_dai_init;
+	dai_link->init		= asoc_graph_dai_init;
 	dai_link->ops		= &graph_ops;
 	if (priv->ops)
 		dai_link->ops	= priv->ops;
@@ -1180,7 +1180,6 @@ int audio_graph2_parse_of(struct asoc_simple_priv *priv, struct device *dev,
 	if (!li)
 		return -ENOMEM;
 
-	card->probe	= asoc_graph_card_probe;
 	card->owner	= THIS_MODULE;
 	card->dev	= dev;
 
diff --git a/sound/soc/generic/simple-card-utils.c b/sound/soc/generic/simple-card-utils.c
index 850e968677f1..398fc4cb1d07 100644
--- a/sound/soc/generic/simple-card-utils.c
+++ b/sound/soc/generic/simple-card-utils.c
@@ -588,6 +588,8 @@ int asoc_simple_init_jack(struct snd_soc_card *card,
 		return -EPROBE_DEFER;
 
 	if (gpio_is_valid(det)) {
+		struct snd_soc_component *component;
+
 		sjack->pin.pin		= pin_name;
 		sjack->pin.mask		= mask;
 
@@ -603,6 +605,9 @@ int asoc_simple_init_jack(struct snd_soc_card *card,
 
 		snd_soc_jack_add_gpios(&sjack->jack, 1,
 				       &sjack->gpio);
+
+		for_each_card_components(card, component)
+			snd_soc_component_set_jack(component, &sjack->jack, NULL);
 	}
 
 	return 0;
@@ -758,11 +763,16 @@ int asoc_simple_remove(struct platform_device *pdev)
 }
 EXPORT_SYMBOL_GPL(asoc_simple_remove);
 
-int asoc_graph_card_probe(struct snd_soc_card *card)
+int asoc_graph_dai_init(struct snd_soc_pcm_runtime *rtd)
 {
+	struct snd_soc_card *card = rtd->card;
 	struct asoc_simple_priv *priv = snd_soc_card_get_drvdata(card);
 	int ret;
 
+	ret = asoc_simple_dai_init(rtd);
+	if (ret < 0)
+		return ret;
+
 	ret = asoc_simple_init_hp(card, &priv->hp_jack, NULL);
 	if (ret < 0)
 		return ret;
@@ -773,7 +783,7 @@ int asoc_graph_card_probe(struct snd_soc_card *card)
 
 	return 0;
 }
-EXPORT_SYMBOL_GPL(asoc_graph_card_probe);
+EXPORT_SYMBOL_GPL(asoc_graph_dai_init);
 
 int asoc_graph_is_ports0(struct device_node *np)
 {
diff --git a/sound/soc/generic/simple-card.c b/sound/soc/generic/simple-card.c
index a89d1cfdda32..e76bfae6ced4 100644
--- a/sound/soc/generic/simple-card.c
+++ b/sound/soc/generic/simple-card.c
@@ -149,6 +149,27 @@ static int simple_parse_node(struct asoc_simple_priv *priv,
 	return 0;
 }
 
+static int simple_dai_init(struct snd_soc_pcm_runtime *rtd)
+{
+	struct snd_soc_card *card = rtd->card;
+	struct asoc_simple_priv *priv = snd_soc_card_get_drvdata(card);
+	int ret;
+
+	ret = asoc_simple_dai_init(rtd);
+	if (ret < 0)
+		return ret;
+
+	ret = asoc_simple_init_hp(card, &priv->hp_jack, PREFIX);
+	if (ret < 0)
+		return ret;
+
+	ret = asoc_simple_init_mic(card, &priv->mic_jack, PREFIX);
+	if (ret < 0)
+		return ret;
+
+	return 0;
+}
+
 static int simple_link_init(struct asoc_simple_priv *priv,
 			    struct device_node *node,
 			    struct device_node *codec,
@@ -164,7 +185,7 @@ static int simple_link_init(struct asoc_simple_priv *priv,
 	if (ret < 0)
 		return 0;
 
-	dai_link->init			= asoc_simple_dai_init;
+	dai_link->init			= simple_dai_init;
 	dai_link->ops			= &simple_ops;
 
 	return asoc_simple_set_dailink_name(dev, dai_link, name);
@@ -587,22 +608,6 @@ static int simple_get_dais_count(struct asoc_simple_priv *priv,
 				    simple_count_dpcm);
 }
 
-static int simple_soc_probe(struct snd_soc_card *card)
-{
-	struct asoc_simple_priv *priv = snd_soc_card_get_drvdata(card);
-	int ret;
-
-	ret = asoc_simple_init_hp(card, &priv->hp_jack, PREFIX);
-	if (ret < 0)
-		return ret;
-
-	ret = asoc_simple_init_mic(card, &priv->mic_jack, PREFIX);
-	if (ret < 0)
-		return ret;
-
-	return 0;
-}
-
 static int asoc_simple_probe(struct platform_device *pdev)
 {
 	struct asoc_simple_priv *priv;
@@ -620,7 +625,6 @@ static int asoc_simple_probe(struct platform_device *pdev)
 	card = simple_priv_to_card(priv);
 	card->owner		= THIS_MODULE;
 	card->dev		= dev;
-	card->probe		= simple_soc_probe;
 	card->driver_name       = "simple-card";
 
 	li = devm_kzalloc(dev, sizeof(*li), GFP_KERNEL);
diff --git a/sound/soc/tegra/tegra_audio_graph_card.c b/sound/soc/tegra/tegra_audio_graph_card.c
index 1f2c5018bf5a..404762d40389 100644
--- a/sound/soc/tegra/tegra_audio_graph_card.c
+++ b/sound/soc/tegra/tegra_audio_graph_card.c
@@ -184,7 +184,7 @@ static int tegra_audio_graph_card_probe(struct snd_soc_card *card)
 		return PTR_ERR(priv->clk_plla_out0);
 	}
 
-	return asoc_graph_card_probe(card);
+	return 0;
 }
 
 static int tegra_audio_graph_probe(struct platform_device *pdev)
-- 
2.25.1


Best regards
---
Kuninori Morimoto

^ permalink raw reply related	[flat|nested] 30+ messages in thread

* Re: [RFC PATCH 1/3] ASoC: simple-card-utils: add support for componants provideing jack events via set_jack
  2022-01-06  1:47       ` kuninori.morimoto.gx
@ 2022-01-08 13:57         ` Carl Philipp Klemm
  -1 siblings, 0 replies; 30+ messages in thread
From: Carl Philipp Klemm @ 2022-01-08 13:57 UTC (permalink / raw)
  To: kuninori.morimoto.gx
  Cc: alsa-devel, merlijn, tony, sre, linux-omap, kuninori.morimoto.gx

Hi,

> (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.
-- 
Carl Philipp Klemm <philipp@uvos.xyz> <carl@uvos.xyz>

^ permalink raw reply	[flat|nested] 30+ messages in thread

* Re: [RFC PATCH 1/3] ASoC: simple-card-utils: add support for componants provideing jack events via set_jack
@ 2022-01-08 13:57         ` Carl Philipp Klemm
  0 siblings, 0 replies; 30+ messages in thread
From: Carl Philipp Klemm @ 2022-01-08 13:57 UTC (permalink / raw)
  To: kuninori.morimoto.gx
  Cc: alsa-devel, kuninori.morimoto.gx, tony, merlijn, sre, linux-omap

Hi,

> (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.
-- 
Carl Philipp Klemm <philipp@uvos.xyz> <carl@uvos.xyz>

^ permalink raw reply	[flat|nested] 30+ messages in thread

* RE: [RFC PATCH 1/3] ASoC: simple-card-utils: add support for componants provideing jack events via set_jack
  2022-01-08 13:57         ` Carl Philipp Klemm
@ 2022-01-10 23:27           ` Kuninori Morimoto
  -1 siblings, 0 replies; 30+ messages in thread
From: Kuninori Morimoto @ 2022-01-10 23:27 UTC (permalink / raw)
  To: Carl Philipp Klemm, kuninori.morimoto.gx
  Cc: alsa-devel, merlijn, tony, sre, linux-omap, Kuninori Morimoto


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

^ permalink raw reply	[flat|nested] 30+ messages in thread

* RE: [RFC PATCH 1/3] ASoC: simple-card-utils: add support for componants provideing jack events via set_jack
@ 2022-01-10 23:27           ` Kuninori Morimoto
  0 siblings, 0 replies; 30+ messages in thread
From: Kuninori Morimoto @ 2022-01-10 23:27 UTC (permalink / raw)
  To: Carl Philipp Klemm, kuninori.morimoto.gx
  Cc: alsa-devel, Kuninori Morimoto, tony, merlijn, sre, linux-omap


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

^ permalink raw reply	[flat|nested] 30+ messages in thread

* [PATCH 1/6] ASoC: simple_card_utils: call snd_soc_component_set_jack() at asoc_simple_init_jack()
  2022-01-10 23:27           ` Kuninori Morimoto
@ 2022-02-20  0:14             ` Carl Philipp Klemm
  -1 siblings, 0 replies; 30+ messages in thread
From: Carl Philipp Klemm @ 2022-02-20  0:14 UTC (permalink / raw)
  To: Kuninori Morimoto
  Cc: alsa-devel, tony, merlijn, sre, linux-omap, kuninori.morimoto.gx

Current simple-card / audio-graph-card are detecting HP/MIC at card->probe
timing (= A), and not calling snd_soc_component_set_jack() for it.
Other sound card drivers are using dai_link->init timing (= B) for
both detecting and set_jack().

	static int snd_soc_bind_card(...)
	{
		....
(A)		ret = snd_soc_card_probe(card);
		...
		for_each_card_rtds(card, rtd) {
(B)			ret = soc_init_pcm_runtime(card, rtd);
			...
		}
		...
	}

This patch
(a) calls set_jack() (= Y) at asoc_simple_init_jack() (= X) which is
    used to detect HP/MIC.
(b) calls it from dai_link->init timing (= B) instead of card->probe
    timing (= A).
(c) allows  non-gpio jacks to be reported by a componant give it via
    snd_soc_component_set_jack if a of node defined by the driver is set
(d) remove card->init (= A) timing function from
    simple-card / audio-graph-card.

(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, ...);
		}
		...
	}

One note here is that simple-card needs PREFIX to detecting HP/MIC,
but it is not needed on audio-graph-card.
Thus simple-card uses local function for it, and audio-graph-card is
using global function and sharing the code with
audio-graph-card / audio-graph-card2 / audio-graph-card2-custom-sample /
tegra_audio_graph_card.

Co-Developed-by: Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
Signed-off-by: Carl Philipp Klemm <philipp@uvos.xyz>
---
 include/sound/simple_card_utils.h             |  2 +-
 .../generic/audio-graph-card2-custom-sample.c |  3 +-
 sound/soc/generic/audio-graph-card2.c         |  3 +-
 sound/soc/generic/simple-card-utils.c         | 20 +++++++++-
 sound/soc/generic/simple-card.c               | 40 ++++++++++---------
 sound/soc/tegra/tegra_audio_graph_card.c      |  2 +-
 6 files changed, 44 insertions(+), 26 deletions(-)

diff --git a/include/sound/simple_card_utils.h b/include/sound/simple_card_utils.h
index df430f1c2a10..34891da5a0fa 100644
--- a/include/sound/simple_card_utils.h
+++ b/include/sound/simple_card_utils.h
@@ -182,7 +182,7 @@ int asoc_simple_init_priv(struct asoc_simple_priv *priv,
 			       struct link_info *li);
 int asoc_simple_remove(struct platform_device *pdev);
 
-int asoc_graph_card_probe(struct snd_soc_card *card);
+int asoc_graph_dai_init(struct snd_soc_pcm_runtime *rtd);
 int asoc_graph_is_ports0(struct device_node *port);
 
 #ifdef DEBUG
diff --git a/sound/soc/generic/audio-graph-card2-custom-sample.c b/sound/soc/generic/audio-graph-card2-custom-sample.c
index 4a2c743e286c..da6cb69faa8d 100644
--- a/sound/soc/generic/audio-graph-card2-custom-sample.c
+++ b/sound/soc/generic/audio-graph-card2-custom-sample.c
@@ -34,8 +34,7 @@ static int custom_card_probe(struct snd_soc_card *card)
 
 	custom_priv->custom_params = 1;
 
-	/* you can use generic probe function */
-	return asoc_graph_card_probe(card);
+	return 0;
 }
 
 static int custom_hook_pre(struct asoc_simple_priv *priv)
diff --git a/sound/soc/generic/audio-graph-card2.c b/sound/soc/generic/audio-graph-card2.c
index b6049bcfb771..dacf158389f9 100644
--- a/sound/soc/generic/audio-graph-card2.c
+++ b/sound/soc/generic/audio-graph-card2.c
@@ -710,7 +710,7 @@ static void graph_link_init(struct asoc_simple_priv *priv,
 		daiclk = snd_soc_daifmt_clock_provider_fliped(daiclk);
 
 	dai_link->dai_fmt	= daifmt | daiclk;
-	dai_link->init		= asoc_simple_dai_init;
+	dai_link->init		= asoc_graph_dai_init;
 	dai_link->ops		= &graph_ops;
 	if (priv->ops)
 		dai_link->ops	= priv->ops;
@@ -1180,7 +1180,6 @@ int audio_graph2_parse_of(struct asoc_simple_priv *priv, struct device *dev,
 	if (!li)
 		return -ENOMEM;
 
-	card->probe	= asoc_graph_card_probe;
 	card->owner	= THIS_MODULE;
 	card->dev	= dev;
 
diff --git a/sound/soc/generic/simple-card-utils.c b/sound/soc/generic/simple-card-utils.c
index 850e968677f1..a135c85584df 100644
--- a/sound/soc/generic/simple-card-utils.c
+++ b/sound/soc/generic/simple-card-utils.c
@@ -588,6 +588,8 @@ int asoc_simple_init_jack(struct snd_soc_card *card,
 		return -EPROBE_DEFER;
 
 	if (gpio_is_valid(det)) {
+		struct snd_soc_component *component;
+
 		sjack->pin.pin		= pin_name;
 		sjack->pin.mask		= mask;
 
@@ -603,6 +605,15 @@ int asoc_simple_init_jack(struct snd_soc_card *card,
 
 		snd_soc_jack_add_gpios(&sjack->jack, 1,
 				       &sjack->gpio);
+
+		for_each_card_components(card, component)
+			snd_soc_component_set_jack(component, &sjack->jack, NULL);
+	} else if (of_property_read_bool(dev->of_node, prefix)) {
+		snd_soc_card_jack_new(card, pin_name, mask,
+				      &sjack->jack,
+				      &sjack->pin, 1);
+		for_each_card_components(card, component)
+			snd_soc_component_set_jack(component, &sjack->jack, NULL);
 	}
 
 	return 0;
@@ -758,11 +769,16 @@ int asoc_simple_remove(struct platform_device *pdev)
 }
 EXPORT_SYMBOL_GPL(asoc_simple_remove);
 
-int asoc_graph_card_probe(struct snd_soc_card *card)
+int asoc_graph_dai_init(struct snd_soc_pcm_runtime *rtd)
 {
+	struct snd_soc_card *card = rtd->card;
 	struct asoc_simple_priv *priv = snd_soc_card_get_drvdata(card);
 	int ret;
 
+	ret = asoc_simple_dai_init(rtd);
+	if (ret < 0)
+		return ret;
+
 	ret = asoc_simple_init_hp(card, &priv->hp_jack, NULL);
 	if (ret < 0)
 		return ret;
@@ -773,7 +789,7 @@ int asoc_graph_card_probe(struct snd_soc_card *card)
 
 	return 0;
 }
-EXPORT_SYMBOL_GPL(asoc_graph_card_probe);
+EXPORT_SYMBOL_GPL(asoc_graph_dai_init);
 
 int asoc_graph_is_ports0(struct device_node *np)
 {
diff --git a/sound/soc/generic/simple-card.c b/sound/soc/generic/simple-card.c
index a3a7990b5cb6..0ead77c40a30 100644
--- a/sound/soc/generic/simple-card.c
+++ b/sound/soc/generic/simple-card.c
@@ -149,6 +149,27 @@ static int simple_parse_node(struct asoc_simple_priv *priv,
 	return 0;
 }
 
+static int simple_dai_init(struct snd_soc_pcm_runtime *rtd)
+{
+	struct snd_soc_card *card = rtd->card;
+	struct asoc_simple_priv *priv = snd_soc_card_get_drvdata(card);
+	int ret;
+
+	ret = asoc_simple_dai_init(rtd);
+	if (ret < 0)
+		return ret;
+
+	ret = asoc_simple_init_hp(card, &priv->hp_jack, PREFIX);
+	if (ret < 0)
+		return ret;
+
+	ret = asoc_simple_init_mic(card, &priv->mic_jack, PREFIX);
+	if (ret < 0)
+		return ret;
+
+	return 0;
+}
+
 static int simple_link_init(struct asoc_simple_priv *priv,
 			    struct device_node *node,
 			    struct device_node *codec,
@@ -164,7 +185,7 @@ static int simple_link_init(struct asoc_simple_priv *priv,
 	if (ret < 0)
 		return 0;
 
-	dai_link->init			= asoc_simple_dai_init;
+	dai_link->init			= simple_dai_init;
 	dai_link->ops			= &simple_ops;
 
 	return asoc_simple_set_dailink_name(dev, dai_link, name);
@@ -587,22 +608,6 @@ static int simple_get_dais_count(struct asoc_simple_priv *priv,
 				    simple_count_dpcm);
 }
 
-static int simple_soc_probe(struct snd_soc_card *card)
-{
-	struct asoc_simple_priv *priv = snd_soc_card_get_drvdata(card);
-	int ret;
-
-	ret = asoc_simple_init_hp(card, &priv->hp_jack, PREFIX);
-	if (ret < 0)
-		return ret;
-
-	ret = asoc_simple_init_mic(card, &priv->mic_jack, PREFIX);
-	if (ret < 0)
-		return ret;
-
-	return 0;
-}
-
 static int asoc_simple_probe(struct platform_device *pdev)
 {
 	struct asoc_simple_priv *priv;
@@ -620,7 +625,6 @@ static int asoc_simple_probe(struct platform_device *pdev)
 	card = simple_priv_to_card(priv);
 	card->owner		= THIS_MODULE;
 	card->dev		= dev;
-	card->probe		= simple_soc_probe;
 	card->driver_name       = "simple-card";
 
 	li = devm_kzalloc(dev, sizeof(*li), GFP_KERNEL);
diff --git a/sound/soc/tegra/tegra_audio_graph_card.c b/sound/soc/tegra/tegra_audio_graph_card.c
index 1f2c5018bf5a..404762d40389 100644
--- a/sound/soc/tegra/tegra_audio_graph_card.c
+++ b/sound/soc/tegra/tegra_audio_graph_card.c
@@ -184,7 +184,7 @@ static int tegra_audio_graph_card_probe(struct snd_soc_card *card)
 		return PTR_ERR(priv->clk_plla_out0);
 	}
 
-	return asoc_graph_card_probe(card);
+	return 0;
 }
 
 static int tegra_audio_graph_probe(struct platform_device *pdev)
-- 
2.35.1

^ permalink raw reply related	[flat|nested] 30+ messages in thread

* [PATCH 1/6] ASoC: simple_card_utils: call snd_soc_component_set_jack() at asoc_simple_init_jack()
@ 2022-02-20  0:14             ` Carl Philipp Klemm
  0 siblings, 0 replies; 30+ messages in thread
From: Carl Philipp Klemm @ 2022-02-20  0:14 UTC (permalink / raw)
  To: Kuninori Morimoto
  Cc: kuninori.morimoto.gx, alsa-devel, merlijn, tony, sre, linux-omap

Current simple-card / audio-graph-card are detecting HP/MIC at card->probe
timing (= A), and not calling snd_soc_component_set_jack() for it.
Other sound card drivers are using dai_link->init timing (= B) for
both detecting and set_jack().

	static int snd_soc_bind_card(...)
	{
		....
(A)		ret = snd_soc_card_probe(card);
		...
		for_each_card_rtds(card, rtd) {
(B)			ret = soc_init_pcm_runtime(card, rtd);
			...
		}
		...
	}

This patch
(a) calls set_jack() (= Y) at asoc_simple_init_jack() (= X) which is
    used to detect HP/MIC.
(b) calls it from dai_link->init timing (= B) instead of card->probe
    timing (= A).
(c) allows  non-gpio jacks to be reported by a componant give it via
    snd_soc_component_set_jack if a of node defined by the driver is set
(d) remove card->init (= A) timing function from
    simple-card / audio-graph-card.

(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, ...);
		}
		...
	}

One note here is that simple-card needs PREFIX to detecting HP/MIC,
but it is not needed on audio-graph-card.
Thus simple-card uses local function for it, and audio-graph-card is
using global function and sharing the code with
audio-graph-card / audio-graph-card2 / audio-graph-card2-custom-sample /
tegra_audio_graph_card.

Co-Developed-by: Kuninori Morimoto <kuninori.morimoto.gx@renesas.com>
Signed-off-by: Carl Philipp Klemm <philipp@uvos.xyz>
---
 include/sound/simple_card_utils.h             |  2 +-
 .../generic/audio-graph-card2-custom-sample.c |  3 +-
 sound/soc/generic/audio-graph-card2.c         |  3 +-
 sound/soc/generic/simple-card-utils.c         | 20 +++++++++-
 sound/soc/generic/simple-card.c               | 40 ++++++++++---------
 sound/soc/tegra/tegra_audio_graph_card.c      |  2 +-
 6 files changed, 44 insertions(+), 26 deletions(-)

diff --git a/include/sound/simple_card_utils.h b/include/sound/simple_card_utils.h
index df430f1c2a10..34891da5a0fa 100644
--- a/include/sound/simple_card_utils.h
+++ b/include/sound/simple_card_utils.h
@@ -182,7 +182,7 @@ int asoc_simple_init_priv(struct asoc_simple_priv *priv,
 			       struct link_info *li);
 int asoc_simple_remove(struct platform_device *pdev);
 
-int asoc_graph_card_probe(struct snd_soc_card *card);
+int asoc_graph_dai_init(struct snd_soc_pcm_runtime *rtd);
 int asoc_graph_is_ports0(struct device_node *port);
 
 #ifdef DEBUG
diff --git a/sound/soc/generic/audio-graph-card2-custom-sample.c b/sound/soc/generic/audio-graph-card2-custom-sample.c
index 4a2c743e286c..da6cb69faa8d 100644
--- a/sound/soc/generic/audio-graph-card2-custom-sample.c
+++ b/sound/soc/generic/audio-graph-card2-custom-sample.c
@@ -34,8 +34,7 @@ static int custom_card_probe(struct snd_soc_card *card)
 
 	custom_priv->custom_params = 1;
 
-	/* you can use generic probe function */
-	return asoc_graph_card_probe(card);
+	return 0;
 }
 
 static int custom_hook_pre(struct asoc_simple_priv *priv)
diff --git a/sound/soc/generic/audio-graph-card2.c b/sound/soc/generic/audio-graph-card2.c
index b6049bcfb771..dacf158389f9 100644
--- a/sound/soc/generic/audio-graph-card2.c
+++ b/sound/soc/generic/audio-graph-card2.c
@@ -710,7 +710,7 @@ static void graph_link_init(struct asoc_simple_priv *priv,
 		daiclk = snd_soc_daifmt_clock_provider_fliped(daiclk);
 
 	dai_link->dai_fmt	= daifmt | daiclk;
-	dai_link->init		= asoc_simple_dai_init;
+	dai_link->init		= asoc_graph_dai_init;
 	dai_link->ops		= &graph_ops;
 	if (priv->ops)
 		dai_link->ops	= priv->ops;
@@ -1180,7 +1180,6 @@ int audio_graph2_parse_of(struct asoc_simple_priv *priv, struct device *dev,
 	if (!li)
 		return -ENOMEM;
 
-	card->probe	= asoc_graph_card_probe;
 	card->owner	= THIS_MODULE;
 	card->dev	= dev;
 
diff --git a/sound/soc/generic/simple-card-utils.c b/sound/soc/generic/simple-card-utils.c
index 850e968677f1..a135c85584df 100644
--- a/sound/soc/generic/simple-card-utils.c
+++ b/sound/soc/generic/simple-card-utils.c
@@ -588,6 +588,8 @@ int asoc_simple_init_jack(struct snd_soc_card *card,
 		return -EPROBE_DEFER;
 
 	if (gpio_is_valid(det)) {
+		struct snd_soc_component *component;
+
 		sjack->pin.pin		= pin_name;
 		sjack->pin.mask		= mask;
 
@@ -603,6 +605,15 @@ int asoc_simple_init_jack(struct snd_soc_card *card,
 
 		snd_soc_jack_add_gpios(&sjack->jack, 1,
 				       &sjack->gpio);
+
+		for_each_card_components(card, component)
+			snd_soc_component_set_jack(component, &sjack->jack, NULL);
+	} else if (of_property_read_bool(dev->of_node, prefix)) {
+		snd_soc_card_jack_new(card, pin_name, mask,
+				      &sjack->jack,
+				      &sjack->pin, 1);
+		for_each_card_components(card, component)
+			snd_soc_component_set_jack(component, &sjack->jack, NULL);
 	}
 
 	return 0;
@@ -758,11 +769,16 @@ int asoc_simple_remove(struct platform_device *pdev)
 }
 EXPORT_SYMBOL_GPL(asoc_simple_remove);
 
-int asoc_graph_card_probe(struct snd_soc_card *card)
+int asoc_graph_dai_init(struct snd_soc_pcm_runtime *rtd)
 {
+	struct snd_soc_card *card = rtd->card;
 	struct asoc_simple_priv *priv = snd_soc_card_get_drvdata(card);
 	int ret;
 
+	ret = asoc_simple_dai_init(rtd);
+	if (ret < 0)
+		return ret;
+
 	ret = asoc_simple_init_hp(card, &priv->hp_jack, NULL);
 	if (ret < 0)
 		return ret;
@@ -773,7 +789,7 @@ int asoc_graph_card_probe(struct snd_soc_card *card)
 
 	return 0;
 }
-EXPORT_SYMBOL_GPL(asoc_graph_card_probe);
+EXPORT_SYMBOL_GPL(asoc_graph_dai_init);
 
 int asoc_graph_is_ports0(struct device_node *np)
 {
diff --git a/sound/soc/generic/simple-card.c b/sound/soc/generic/simple-card.c
index a3a7990b5cb6..0ead77c40a30 100644
--- a/sound/soc/generic/simple-card.c
+++ b/sound/soc/generic/simple-card.c
@@ -149,6 +149,27 @@ static int simple_parse_node(struct asoc_simple_priv *priv,
 	return 0;
 }
 
+static int simple_dai_init(struct snd_soc_pcm_runtime *rtd)
+{
+	struct snd_soc_card *card = rtd->card;
+	struct asoc_simple_priv *priv = snd_soc_card_get_drvdata(card);
+	int ret;
+
+	ret = asoc_simple_dai_init(rtd);
+	if (ret < 0)
+		return ret;
+
+	ret = asoc_simple_init_hp(card, &priv->hp_jack, PREFIX);
+	if (ret < 0)
+		return ret;
+
+	ret = asoc_simple_init_mic(card, &priv->mic_jack, PREFIX);
+	if (ret < 0)
+		return ret;
+
+	return 0;
+}
+
 static int simple_link_init(struct asoc_simple_priv *priv,
 			    struct device_node *node,
 			    struct device_node *codec,
@@ -164,7 +185,7 @@ static int simple_link_init(struct asoc_simple_priv *priv,
 	if (ret < 0)
 		return 0;
 
-	dai_link->init			= asoc_simple_dai_init;
+	dai_link->init			= simple_dai_init;
 	dai_link->ops			= &simple_ops;
 
 	return asoc_simple_set_dailink_name(dev, dai_link, name);
@@ -587,22 +608,6 @@ static int simple_get_dais_count(struct asoc_simple_priv *priv,
 				    simple_count_dpcm);
 }
 
-static int simple_soc_probe(struct snd_soc_card *card)
-{
-	struct asoc_simple_priv *priv = snd_soc_card_get_drvdata(card);
-	int ret;
-
-	ret = asoc_simple_init_hp(card, &priv->hp_jack, PREFIX);
-	if (ret < 0)
-		return ret;
-
-	ret = asoc_simple_init_mic(card, &priv->mic_jack, PREFIX);
-	if (ret < 0)
-		return ret;
-
-	return 0;
-}
-
 static int asoc_simple_probe(struct platform_device *pdev)
 {
 	struct asoc_simple_priv *priv;
@@ -620,7 +625,6 @@ static int asoc_simple_probe(struct platform_device *pdev)
 	card = simple_priv_to_card(priv);
 	card->owner		= THIS_MODULE;
 	card->dev		= dev;
-	card->probe		= simple_soc_probe;
 	card->driver_name       = "simple-card";
 
 	li = devm_kzalloc(dev, sizeof(*li), GFP_KERNEL);
diff --git a/sound/soc/tegra/tegra_audio_graph_card.c b/sound/soc/tegra/tegra_audio_graph_card.c
index 1f2c5018bf5a..404762d40389 100644
--- a/sound/soc/tegra/tegra_audio_graph_card.c
+++ b/sound/soc/tegra/tegra_audio_graph_card.c
@@ -184,7 +184,7 @@ static int tegra_audio_graph_card_probe(struct snd_soc_card *card)
 		return PTR_ERR(priv->clk_plla_out0);
 	}
 
-	return asoc_graph_card_probe(card);
+	return 0;
 }
 
 static int tegra_audio_graph_probe(struct platform_device *pdev)
-- 
2.35.1

^ permalink raw reply related	[flat|nested] 30+ messages in thread

* [PATCH 2/6] ASoC: audio-graph-card: use new functionality in simple_card_utils to implement has-hp-jack of property
  2022-01-10 23:27           ` Kuninori Morimoto
@ 2022-02-20  0:15             ` Carl Philipp Klemm
  -1 siblings, 0 replies; 30+ messages in thread
From: Carl Philipp Klemm @ 2022-02-20  0:15 UTC (permalink / raw)
  To: Kuninori Morimoto
  Cc: alsa-devel, tony, merlijn, sre, linux-omap, kuninori.morimoto.gx

Setting this will cause audio-graph-card to register a headphone jack
and provide it to its componants via set_jack.

Signed-off-by: Carl Philipp Klemm <philipp@uvos.xyz>
---
 sound/soc/generic/audio-graph-card.c | 5 +++--
 1 file changed, 3 insertions(+), 2 deletions(-)

diff --git a/sound/soc/generic/audio-graph-card.c b/sound/soc/generic/audio-graph-card.c
index 7eb027238327..32a81bf10f18 100644
--- a/sound/soc/generic/audio-graph-card.c
+++ b/sound/soc/generic/audio-graph-card.c
@@ -259,7 +259,7 @@ static int graph_link_init(struct asoc_simple_priv *priv,
 	if (ret < 0)
 		return ret;
 
-	dai_link->init		= asoc_simple_dai_init;
+	dai_link->init		= asoc_graph_dai_init;
 	dai_link->ops		= &graph_ops;
 	if (priv->ops)
 		dai_link->ops	= priv->ops;
@@ -568,6 +568,8 @@ int audio_graph_parse_of(struct asoc_simple_priv *priv, struct device *dev)
 	if (ret < 0)
 		return ret;
 
+	asoc_simple_init_jack(card, &priv->hp_jack, TRUE, "has-hp-jack", NULL);
+
 	memset(li, 0, sizeof(*li));
 	ret = graph_for_each_link(priv, li,
 				  graph_dai_link_of,
@@ -719,7 +721,6 @@ static int graph_probe(struct platform_device *pdev)
 	card = simple_priv_to_card(priv);
 	card->dapm_widgets	= graph_dapm_widgets;
 	card->num_dapm_widgets	= ARRAY_SIZE(graph_dapm_widgets);
-	card->probe		= asoc_graph_card_probe;
 
 	if (of_device_get_match_data(dev))
 		priv->dpcm_selectable = 1;
-- 
2.35.1


^ permalink raw reply related	[flat|nested] 30+ messages in thread

* [PATCH 2/6] ASoC: audio-graph-card: use new functionality in simple_card_utils to implement has-hp-jack of property
@ 2022-02-20  0:15             ` Carl Philipp Klemm
  0 siblings, 0 replies; 30+ messages in thread
From: Carl Philipp Klemm @ 2022-02-20  0:15 UTC (permalink / raw)
  To: Kuninori Morimoto
  Cc: kuninori.morimoto.gx, alsa-devel, merlijn, tony, sre, linux-omap

Setting this will cause audio-graph-card to register a headphone jack
and provide it to its componants via set_jack.

Signed-off-by: Carl Philipp Klemm <philipp@uvos.xyz>
---
 sound/soc/generic/audio-graph-card.c | 5 +++--
 1 file changed, 3 insertions(+), 2 deletions(-)

diff --git a/sound/soc/generic/audio-graph-card.c b/sound/soc/generic/audio-graph-card.c
index 7eb027238327..32a81bf10f18 100644
--- a/sound/soc/generic/audio-graph-card.c
+++ b/sound/soc/generic/audio-graph-card.c
@@ -259,7 +259,7 @@ static int graph_link_init(struct asoc_simple_priv *priv,
 	if (ret < 0)
 		return ret;
 
-	dai_link->init		= asoc_simple_dai_init;
+	dai_link->init		= asoc_graph_dai_init;
 	dai_link->ops		= &graph_ops;
 	if (priv->ops)
 		dai_link->ops	= priv->ops;
@@ -568,6 +568,8 @@ int audio_graph_parse_of(struct asoc_simple_priv *priv, struct device *dev)
 	if (ret < 0)
 		return ret;
 
+	asoc_simple_init_jack(card, &priv->hp_jack, TRUE, "has-hp-jack", NULL);
+
 	memset(li, 0, sizeof(*li));
 	ret = graph_for_each_link(priv, li,
 				  graph_dai_link_of,
@@ -719,7 +721,6 @@ static int graph_probe(struct platform_device *pdev)
 	card = simple_priv_to_card(priv);
 	card->dapm_widgets	= graph_dapm_widgets;
 	card->num_dapm_widgets	= ARRAY_SIZE(graph_dapm_widgets);
-	card->probe		= asoc_graph_card_probe;
 
 	if (of_device_get_match_data(dev))
 		priv->dpcm_selectable = 1;
-- 
2.35.1


^ permalink raw reply related	[flat|nested] 30+ messages in thread

* [PATCH 3/6] ASoC: cpcap: add headphone jack plug detection support
  2022-01-10 23:27           ` Kuninori Morimoto
@ 2022-02-20  0:15             ` Carl Philipp Klemm
  -1 siblings, 0 replies; 30+ messages in thread
From: Carl Philipp Klemm @ 2022-02-20  0:15 UTC (permalink / raw)
  To: Kuninori Morimoto
  Cc: alsa-devel, tony, merlijn, sre, linux-omap, kuninori.morimoto.gx

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

^ permalink raw reply related	[flat|nested] 30+ messages in thread

* [PATCH 3/6] ASoC: cpcap: add headphone jack plug detection support
@ 2022-02-20  0:15             ` Carl Philipp Klemm
  0 siblings, 0 replies; 30+ messages in thread
From: Carl Philipp Klemm @ 2022-02-20  0:15 UTC (permalink / raw)
  To: Kuninori Morimoto
  Cc: kuninori.morimoto.gx, alsa-devel, merlijn, tony, sre, linux-omap

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

^ permalink raw reply related	[flat|nested] 30+ messages in thread

* [PATCH 4/6] ARM: dts: motorola-mapphone: add interrupt for headphone detection
  2022-01-10 23:27           ` Kuninori Morimoto
@ 2022-02-20  0:15             ` Carl Philipp Klemm
  -1 siblings, 0 replies; 30+ messages in thread
From: Carl Philipp Klemm @ 2022-02-20  0:15 UTC (permalink / raw)
  To: Kuninori Morimoto
  Cc: alsa-devel, tony, merlijn, sre, linux-omap, kuninori.morimoto.gx

Signed-off-by: Carl Philipp Klemm <philipp@uvos.xyz>
---
 arch/arm/boot/dts/motorola-cpcap-mapphone.dtsi | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/arch/arm/boot/dts/motorola-cpcap-mapphone.dtsi b/arch/arm/boot/dts/motorola-cpcap-mapphone.dtsi
index 0aff0d306d06..e164169bf820 100644
--- a/arch/arm/boot/dts/motorola-cpcap-mapphone.dtsi
+++ b/arch/arm/boot/dts/motorola-cpcap-mapphone.dtsi
@@ -72,6 +72,9 @@ cpcap_audio: audio-codec {
 			#address-cells = <1>;
 			#size-cells = <0>;
 
+			interrupts-extended = <&cpcap 9 0>;
+			interrupt-names = "hpplugged";
+
 			port@0 {
 				reg = <0>;
 				cpcap_audio_codec0: endpoint {
-- 
2.35.1

^ permalink raw reply related	[flat|nested] 30+ messages in thread

* [PATCH 4/6] ARM: dts: motorola-mapphone: add interrupt for headphone detection
@ 2022-02-20  0:15             ` Carl Philipp Klemm
  0 siblings, 0 replies; 30+ messages in thread
From: Carl Philipp Klemm @ 2022-02-20  0:15 UTC (permalink / raw)
  To: Kuninori Morimoto
  Cc: kuninori.morimoto.gx, alsa-devel, merlijn, tony, sre, linux-omap

Signed-off-by: Carl Philipp Klemm <philipp@uvos.xyz>
---
 arch/arm/boot/dts/motorola-cpcap-mapphone.dtsi | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/arch/arm/boot/dts/motorola-cpcap-mapphone.dtsi b/arch/arm/boot/dts/motorola-cpcap-mapphone.dtsi
index 0aff0d306d06..e164169bf820 100644
--- a/arch/arm/boot/dts/motorola-cpcap-mapphone.dtsi
+++ b/arch/arm/boot/dts/motorola-cpcap-mapphone.dtsi
@@ -72,6 +72,9 @@ cpcap_audio: audio-codec {
 			#address-cells = <1>;
 			#size-cells = <0>;
 
+			interrupts-extended = <&cpcap 9 0>;
+			interrupt-names = "hpplugged";
+
 			port@0 {
 				reg = <0>;
 				cpcap_audio_codec0: endpoint {
-- 
2.35.1

^ permalink raw reply related	[flat|nested] 30+ messages in thread

* [PATCH 5/6] ARM: dts: motorola-mapphone: add has-hp-jack for audio-graph-card
  2022-01-10 23:27           ` Kuninori Morimoto
@ 2022-02-20  0:15             ` Carl Philipp Klemm
  -1 siblings, 0 replies; 30+ messages in thread
From: Carl Philipp Klemm @ 2022-02-20  0:15 UTC (permalink / raw)
  To: Kuninori Morimoto
  Cc: alsa-devel, tony, merlijn, sre, linux-omap, kuninori.morimoto.gx

Signed-off-by: Carl Philipp Klemm <philipp@uvos.xyz>
---
 arch/arm/boot/dts/motorola-mapphone-common.dtsi | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/arch/arm/boot/dts/motorola-mapphone-common.dtsi b/arch/arm/boot/dts/motorola-mapphone-common.dtsi
index e26950d8ca85..800017ce096f 100644
--- a/arch/arm/boot/dts/motorola-mapphone-common.dtsi
+++ b/arch/arm/boot/dts/motorola-mapphone-common.dtsi
@@ -150,6 +150,8 @@ soundcard {
 			"Headphone Jack", "HSR",
 			"MICR", "Internal Mic";
 
+		has-hp-jack;
+
 		dais = <&mcbsp2_port>, <&mcbsp3_port>;
 	};
 
-- 
2.35.1

^ permalink raw reply related	[flat|nested] 30+ messages in thread

* [PATCH 5/6] ARM: dts: motorola-mapphone: add has-hp-jack for audio-graph-card
@ 2022-02-20  0:15             ` Carl Philipp Klemm
  0 siblings, 0 replies; 30+ messages in thread
From: Carl Philipp Klemm @ 2022-02-20  0:15 UTC (permalink / raw)
  To: Kuninori Morimoto
  Cc: kuninori.morimoto.gx, alsa-devel, merlijn, tony, sre, linux-omap

Signed-off-by: Carl Philipp Klemm <philipp@uvos.xyz>
---
 arch/arm/boot/dts/motorola-mapphone-common.dtsi | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/arch/arm/boot/dts/motorola-mapphone-common.dtsi b/arch/arm/boot/dts/motorola-mapphone-common.dtsi
index e26950d8ca85..800017ce096f 100644
--- a/arch/arm/boot/dts/motorola-mapphone-common.dtsi
+++ b/arch/arm/boot/dts/motorola-mapphone-common.dtsi
@@ -150,6 +150,8 @@ soundcard {
 			"Headphone Jack", "HSR",
 			"MICR", "Internal Mic";
 
+		has-hp-jack;
+
 		dais = <&mcbsp2_port>, <&mcbsp3_port>;
 	};
 
-- 
2.35.1

^ permalink raw reply related	[flat|nested] 30+ messages in thread

* [PATCH 6/6] Documentation: sound: audio-graph-card: update dts bindings to add has-hp-jack
  2022-01-10 23:27           ` Kuninori Morimoto
@ 2022-02-20  0:18             ` Carl Philipp Klemm
  -1 siblings, 0 replies; 30+ messages in thread
From: Carl Philipp Klemm @ 2022-02-20  0:18 UTC (permalink / raw)
  To: Kuninori Morimoto
  Cc: kuninori.morimoto.gx, alsa-devel, merlijn, tony, sre, linux-omap

Signed-off-by: Carl Philipp Klemm <philipp@uvos.xyz>
---
 Documentation/devicetree/bindings/sound/audio-graph.yaml | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/Documentation/devicetree/bindings/sound/audio-graph.yaml b/Documentation/devicetree/bindings/sound/audio-graph.yaml
index 4b46794e5153..5844b900789a 100644
--- a/Documentation/devicetree/bindings/sound/audio-graph.yaml
+++ b/Documentation/devicetree/bindings/sound/audio-graph.yaml
@@ -38,6 +38,8 @@ properties:
     maxItems: 1
   mic-det-gpio:
     maxItems: 1
+  hp-det-gpio:
+    description: Set this properties if the device has a headphone jack to be reported on by a snd_soc_component
 
 required:
   - dais
-- 
2.35.1


^ permalink raw reply related	[flat|nested] 30+ messages in thread

* [PATCH 6/6] Documentation: sound: audio-graph-card: update dts bindings to add has-hp-jack
@ 2022-02-20  0:18             ` Carl Philipp Klemm
  0 siblings, 0 replies; 30+ messages in thread
From: Carl Philipp Klemm @ 2022-02-20  0:18 UTC (permalink / raw)
  To: Kuninori Morimoto
  Cc: alsa-devel, tony, merlijn, sre, linux-omap, kuninori.morimoto.gx

Signed-off-by: Carl Philipp Klemm <philipp@uvos.xyz>
---
 Documentation/devicetree/bindings/sound/audio-graph.yaml | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/Documentation/devicetree/bindings/sound/audio-graph.yaml b/Documentation/devicetree/bindings/sound/audio-graph.yaml
index 4b46794e5153..5844b900789a 100644
--- a/Documentation/devicetree/bindings/sound/audio-graph.yaml
+++ b/Documentation/devicetree/bindings/sound/audio-graph.yaml
@@ -38,6 +38,8 @@ properties:
     maxItems: 1
   mic-det-gpio:
     maxItems: 1
+  hp-det-gpio:
+    description: Set this properties if the device has a headphone jack to be reported on by a snd_soc_component
 
 required:
   - dais
-- 
2.35.1


^ permalink raw reply related	[flat|nested] 30+ messages in thread

end of thread, other threads:[~2022-02-20  0:31 UTC | newest]

Thread overview: 30+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
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           ` [PATCH 3/6] ASoC: cpcap: add headphone jack plug detection support Carl Philipp Klemm
2022-02-20  0:15             ` 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

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.