[PATCH 2/3] ASoC: simple-card: Add support jack detection via codec

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 




In most cases, many codecs already supports jack detection, previouslly,
we need to create a customized machine driver every time.

Hence, the simple-card need to support use them dynamically via parse dts
file for better flexibility.

Signed-off-by: Xing Zheng <zhengxing@xxxxxxxxxxxxxx>
---

 .../devicetree/bindings/sound/simple-card.txt      |   17 +++
 sound/soc/generic/simple-card.c                    |  126 +++++++++++++++++++-
 2 files changed, 140 insertions(+), 3 deletions(-)

diff --git a/Documentation/devicetree/bindings/sound/simple-card.txt b/Documentation/devicetree/bindings/sound/simple-card.txt
index cf3979e..d25c8eb 100644
--- a/Documentation/devicetree/bindings/sound/simple-card.txt
+++ b/Documentation/devicetree/bindings/sound/simple-card.txt
@@ -22,6 +22,23 @@ Optional properties:
 					  headphones are attached.
 - simple-audio-card,mic-det-gpio	: Reference to GPIO that signals when
 					  a microphone is attached.
+- simple-audio-card,codec-jack		: A list of the codec supports jack detection.
+					  The jack types which are supported refer to include/sound/jack.h.
+					  All of the jack types:
+						"JACK_HEADPHONE",
+						"JACK_MICROPHONE",
+						"JACK_HEADSET",
+						"JACK_LINEOUT",
+						"JACK_MECHANICAL",
+						"JACK_VIDEOOUT",
+						"JACK_AVOUT",
+						"JACK_LINEIN",
+						"JACK_BTN_0",
+						"JACK_BTN_1",
+						"JACK_BTN_2",
+						"JACK_BTN_3",
+						"JACK_BTN_4",
+						"JACK_BTN_5".
 
 Optional subnodes:
 
diff --git a/sound/soc/generic/simple-card.c b/sound/soc/generic/simple-card.c
index 2389ab4..bc61022 100644
--- a/sound/soc/generic/simple-card.c
+++ b/sound/soc/generic/simple-card.c
@@ -33,12 +33,35 @@ struct simple_card_data {
 	int gpio_hp_det_invert;
 	int gpio_mic_det;
 	int gpio_mic_det_invert;
+	struct simple_codecs_jack {
+		int jack_det;
+		int jack_types;
+		struct snd_soc_jack codec_jack;
+	} *codec_det_jack;
 	struct snd_soc_dai_link dai_link[];	/* dynamically allocated */
 };
 
 #define simple_priv_to_dev(priv) ((priv)->snd_card.dev)
 #define simple_priv_to_link(priv, i) ((priv)->snd_card.dai_link + i)
 #define simple_priv_to_props(priv, i) ((priv)->dai_props + i)
+#define simple_priv_to_codecdetjack(priv, i) ((priv)->codec_det_jack + i)
+
+static const char * const jack_types_list[] = {
+	"JACK_HEADPHONE",
+	"JACK_MICROPHONE",
+	"JACK_HEADSET",
+	"JACK_LINEOUT",
+	"JACK_MECHANICAL",
+	"JACK_VIDEOOUT",
+	"JACK_AVOUT",
+	"JACK_LINEIN",
+	"JACK_BTN_0",
+	"JACK_BTN_1",
+	"JACK_BTN_2",
+	"JACK_BTN_3",
+	"JACK_BTN_4",
+	"JACK_BTN_5",
+};
 
 static int asoc_simple_card_startup(struct snd_pcm_substream *substream)
 {
@@ -136,6 +159,8 @@ static struct snd_soc_jack_gpio simple_card_mic_jack_gpio = {
 	.debounce_time = 150,
 };
 
+static struct snd_soc_jack simple_card_codecs_jack;
+
 static int __asoc_simple_card_dai_init(struct snd_soc_dai *dai,
 				       struct asoc_simple_dai *set)
 {
@@ -173,9 +198,12 @@ static int asoc_simple_card_dai_init(struct snd_soc_pcm_runtime *rtd)
 	struct snd_soc_dai *codec = rtd->codec_dai;
 	struct snd_soc_dai *cpu = rtd->cpu_dai;
 	struct simple_dai_props *dai_props;
+	struct simple_codecs_jack *codec_det_jack;
 	int ret;
 
 	dai_props = &priv->dai_props[rtd->num];
+	codec_det_jack = &priv->codec_det_jack[rtd->num];
+
 	ret = __asoc_simple_card_dai_init(codec, &dai_props->codec_dai);
 	if (ret < 0)
 		return ret;
@@ -208,6 +236,80 @@ static int asoc_simple_card_dai_init(struct snd_soc_pcm_runtime *rtd)
 		snd_soc_jack_add_gpios(&simple_card_mic_jack, 1,
 				       &simple_card_mic_jack_gpio);
 	}
+
+	if (codec_det_jack->jack_det) {
+		ret = snd_soc_card_jack_new(rtd->card, "Simple-card Codec Jack",
+					    codec_det_jack->jack_types,
+					    &simple_card_codecs_jack, NULL, 0);
+		if (ret) {
+			dev_err(rtd->card->dev, "New Simple-card Codec Jack failed! (%d)\n", ret);
+			return ret;
+		}
+
+		snd_soc_jack_codec_detect(rtd->codec, &simple_card_codecs_jack);
+	}
+
+	return 0;
+}
+
+static int asoc_simple_card_parse_jack(struct device_node *np, int *jack_types)
+{
+	const char *propname = "simple-audio-card,codec-jack";
+	const char *jack_name;
+	int num_jacks, i, j, ret;
+
+	/* init with invalid, don't need to de-init if get count strings failed. */
+	*jack_types = -1;
+
+	num_jacks = of_property_count_strings(np, propname);
+	if (num_jacks < 0) {
+		pr_err("simple-card: Property '%s' number is invalid\n", propname);
+		return -EINVAL;
+	}
+
+	/* init and clean value */
+	*jack_types = 0;
+
+	for (i = 0; i < num_jacks; i++) {
+		ret = of_property_read_string_index(np, propname, i, &jack_name);
+		if (ret) {
+			pr_err("simple-card: Property '%s' index %d read error: %d\n",
+				propname, i, ret);
+			return -EINVAL;
+		}
+
+		for (j = 0; j < ARRAY_SIZE(jack_types_list); j++) {
+			if (!strcmp(jack_name, "JACK_HEADPHONE"))
+				*jack_types |= SND_JACK_HEADPHONE;
+			else if (!strcmp(jack_name, "JACK_MICROPHONE"))
+				*jack_types |= SND_JACK_MICROPHONE;
+			else if (!strcmp(jack_name, "JACK_HEADSET"))
+				*jack_types |= SND_JACK_HEADSET;
+			else if (!strcmp(jack_name, "JACK_LINEOUT"))
+				*jack_types |= SND_JACK_LINEOUT;
+			else if (!strcmp(jack_name, "JACK_MECHANICAL"))
+				*jack_types |= SND_JACK_MECHANICAL;
+			else if (!strcmp(jack_name, "JACK_VIDEOOUT"))
+				*jack_types |= SND_JACK_VIDEOOUT;
+			else if (!strcmp(jack_name, "JACK_AVOUT"))
+				*jack_types |= SND_JACK_AVOUT;
+			else if (!strcmp(jack_name, "JACK_LINEIN"))
+				*jack_types |= SND_JACK_LINEIN;
+			else if (!strcmp(jack_name, "JACK_BTN_0"))
+				*jack_types |= SND_JACK_BTN_0;
+			else if (!strcmp(jack_name, "JACK_BTN_1"))
+				*jack_types |= SND_JACK_BTN_1;
+			else if (!strcmp(jack_name, "JACK_BTN_2"))
+				*jack_types |= SND_JACK_BTN_2;
+			else if (!strcmp(jack_name, "JACK_BTN_3"))
+				*jack_types |= SND_JACK_BTN_3;
+			else if (!strcmp(jack_name, "JACK_BTN_4"))
+				*jack_types |= SND_JACK_BTN_4;
+			else if (!strcmp(jack_name, "JACK_BTN_5"))
+				*jack_types |= SND_JACK_BTN_5;
+		}
+	}
+
 	return 0;
 }
 
@@ -216,7 +318,8 @@ asoc_simple_card_sub_parse_of(struct device_node *np,
 			      struct asoc_simple_dai *dai,
 			      struct device_node **p_node,
 			      const char **name,
-			      int *args_count)
+			      int *args_count,
+			      struct simple_codecs_jack *codec_det_jack)
 {
 	struct of_phandle_args args;
 	struct clk *clk;
@@ -272,6 +375,13 @@ asoc_simple_card_sub_parse_of(struct device_node *np,
 			dai->sysclk = clk_get_rate(clk);
 	}
 
+	if (codec_det_jack) {
+		codec_det_jack->jack_det = of_property_read_bool(np,
+						"simple-audio-card,codec-jack");
+		if (codec_det_jack->jack_det)
+			asoc_simple_card_parse_jack(np, &codec_det_jack->jack_types);
+	}
+
 	return 0;
 }
 
@@ -325,6 +435,7 @@ static int asoc_simple_card_dai_link_of(struct device_node *node,
 	struct device *dev = simple_priv_to_dev(priv);
 	struct snd_soc_dai_link *dai_link = simple_priv_to_link(priv, idx);
 	struct simple_dai_props *dai_props = simple_priv_to_props(priv, idx);
+	struct simple_codecs_jack *codec_det_jack = simple_priv_to_codecdetjack(priv, idx);
 	struct device_node *cpu = NULL;
 	struct device_node *plat = NULL;
 	struct device_node *codec = NULL;
@@ -364,13 +475,15 @@ static int asoc_simple_card_dai_link_of(struct device_node *node,
 	ret = asoc_simple_card_sub_parse_of(cpu, &dai_props->cpu_dai,
 					    &dai_link->cpu_of_node,
 					    &dai_link->cpu_dai_name,
-					    &cpu_args);
+					    &cpu_args, NULL);
 	if (ret < 0)
 		goto dai_link_of_err;
 
 	ret = asoc_simple_card_sub_parse_of(codec, &dai_props->codec_dai,
 					    &dai_link->codec_of_node,
-					    &dai_link->codec_dai_name, NULL);
+					    &dai_link->codec_dai_name, NULL,
+					    codec_det_jack);
+
 	if (ret < 0)
 		goto dai_link_of_err;
 
@@ -565,6 +678,13 @@ static int asoc_simple_card_probe(struct platform_device *pdev)
 	if (!priv->dai_props)
 		return -ENOMEM;
 
+	/* Get room for the other properties */
+	priv->codec_det_jack = devm_kzalloc(dev,
+			sizeof(*priv->codec_det_jack) * num_links,
+			GFP_KERNEL);
+	if (!priv->codec_det_jack)
+		return -ENOMEM;
+
 	if (np && of_device_is_available(np)) {
 
 		ret = asoc_simple_card_parse_of(np, priv);
-- 
1.7.9.5


--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html



[Index of Archives]     [Device Tree Compilter]     [Device Tree Spec]     [Linux Driver Backports]     [Video for Linux]     [Linux USB Devel]     [Linux PCI Devel]     [Linux Audio Users]     [Linux Kernel]     [Linux SCSI]     [XFree86]     [Yosemite Backpacking]
  Powered by Linux