From 847175e8e660045f9366e7efd091969e8f32cc0c Mon Sep 17 00:00:00 2001
From: Vaibhav Agarwal <vaibhav.agarwal@linaro.org>
Date: Thu, 1 Sep 2016 11:38:40 +0530
Subject: [PATCH] greybus: audio: Fetch jack_mask, button_mask from module's
 topology data

Added extra fields namely jack_mask & button_mask for each module_info.
These fields are required while registering jack & reporting jack
events.

Earlier, these were hard coded values assuming fixed capabilities say
HEADSET, LINEOUT, etc. supported by GB-codec driver. Now these are
computed dynamically based on module's jack capability shared via
topology data.

Signed-off-by: Vaibhav Agarwal <vaibhav.agarwal@linaro.org>
Reviewed-by: Mark Greer <mgreer@animalcreek.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@google.com>
---
 drivers/staging/greybus/audio_codec.c    | 68 ++++++++++++++++--------
 drivers/staging/greybus/audio_codec.h    |  8 +--
 drivers/staging/greybus/audio_module.c   | 15 +++---
 drivers/staging/greybus/audio_topology.c |  7 +++
 4 files changed, 63 insertions(+), 35 deletions(-)

diff --git a/drivers/staging/greybus/audio_codec.c b/drivers/staging/greybus/audio_codec.c
index 810ac6269cff6..2f70295e00946 100644
--- a/drivers/staging/greybus/audio_codec.c
+++ b/drivers/staging/greybus/audio_codec.c
@@ -707,50 +707,72 @@ static int gbaudio_init_jack(struct gbaudio_module_info *module,
 {
 	int ret;
 
+	if (!module->jack_mask)
+		return 0;
+
 	snprintf(module->jack_name, NAME_SIZE, "GB %d Headset Jack",
 		 module->dev_id);
-	ret = snd_soc_jack_new(codec, module->jack_name, GBCODEC_JACK_MASK,
+	ret = snd_soc_jack_new(codec, module->jack_name, module->jack_mask,
 			       &module->headset_jack);
 	if (ret) {
 		dev_err(module->dev, "Failed to create new jack\n");
 		return ret;
 	}
 
+	if (!module->button_mask)
+		return 0;
+
 	snprintf(module->button_name, NAME_SIZE, "GB %d Button Jack",
 		 module->dev_id);
-	ret = snd_soc_jack_new(codec, module->button_name,
-			       GBCODEC_JACK_BUTTON_MASK, &module->button_jack);
+	ret = snd_soc_jack_new(codec, module->button_name, module->button_mask,
+			       &module->button_jack);
 	if (ret) {
 		dev_err(module->dev, "Failed to create button jack\n");
 		return ret;
 	}
 
-	ret = snd_jack_set_key(module->button_jack.jack, SND_JACK_BTN_0,
-			       KEY_MEDIA);
-	if (ret) {
-		dev_err(module->dev, "Failed to set BTN_0\n");
-		return ret;
+	/*
+	 * Currently, max 4 buttons are supported with following key mapping
+	 * BTN_0 = KEY_MEDIA
+	 * BTN_1 = KEY_VOICECOMMAND
+	 * BTN_2 = KEY_VOLUMEUP
+	 * BTN_3 = KEY_VOLUMEDOWN
+	 */
+
+	if (module->button_mask & SND_JACK_BTN_0) {
+		ret = snd_jack_set_key(module->button_jack.jack, SND_JACK_BTN_0,
+				       KEY_MEDIA);
+		if (ret) {
+			dev_err(module->dev, "Failed to set BTN_0\n");
+			return ret;
+		}
 	}
 
-	ret = snd_jack_set_key(module->button_jack.jack, SND_JACK_BTN_1,
-			       KEY_VOICECOMMAND);
-	if (ret) {
-		dev_err(module->dev, "Failed to set BTN_1\n");
-		return ret;
+	if (module->button_mask & SND_JACK_BTN_1) {
+		ret = snd_jack_set_key(module->button_jack.jack, SND_JACK_BTN_1,
+				       KEY_VOICECOMMAND);
+		if (ret) {
+			dev_err(module->dev, "Failed to set BTN_1\n");
+			return ret;
+		}
 	}
 
-	ret = snd_jack_set_key(module->button_jack.jack, SND_JACK_BTN_2,
-			       KEY_VOLUMEUP);
-	if (ret) {
-		dev_err(module->dev, "Failed to set BTN_2\n");
-		return ret;
+	if (module->button_mask & SND_JACK_BTN_2) {
+		ret = snd_jack_set_key(module->button_jack.jack, SND_JACK_BTN_2,
+				       KEY_VOLUMEUP);
+		if (ret) {
+			dev_err(module->dev, "Failed to set BTN_2\n");
+			return ret;
+		}
 	}
 
-	ret = snd_jack_set_key(module->button_jack.jack, SND_JACK_BTN_3,
-			       KEY_VOLUMEDOWN);
-	if (ret) {
-		dev_err(module->dev, "Failed to set BTN_0\n");
-		return ret;
+	if (module->button_mask & SND_JACK_BTN_3) {
+		ret = snd_jack_set_key(module->button_jack.jack, SND_JACK_BTN_3,
+				       KEY_VOLUMEDOWN);
+		if (ret) {
+			dev_err(module->dev, "Failed to set BTN_0\n");
+			return ret;
+		}
 	}
 
 	/* FIXME
diff --git a/drivers/staging/greybus/audio_codec.h b/drivers/staging/greybus/audio_codec.h
index 5a397b0a1886c..0a864592560f8 100644
--- a/drivers/staging/greybus/audio_codec.h
+++ b/drivers/staging/greybus/audio_codec.h
@@ -73,10 +73,8 @@ enum {
 #define GBCODEC_APB1_MUX_REG_DEFAULT	0x00
 #define GBCODEC_APB2_MUX_REG_DEFAULT	0x00
 
-#define GBCODEC_JACK_MASK (SND_JACK_HEADSET | SND_JACK_LINEOUT | \
-			   SND_JACK_LINEIN | SND_JACK_UNSUPPORTED)
-#define GBCODEC_JACK_BUTTON_MASK (SND_JACK_BTN_0 | SND_JACK_BTN_1 | \
-				  SND_JACK_BTN_2 | SND_JACK_BTN_3)
+#define GBCODEC_JACK_MASK		0x0000FFFF
+#define GBCODEC_JACK_BUTTON_MASK	0xFFFF0000
 
 static const u8 gbcodec_reg_defaults[GBCODEC_REG_COUNT] = {
 	GBCODEC_CTL_REG_DEFAULT,
@@ -176,6 +174,8 @@ struct gbaudio_module_info {
 	char jack_name[NAME_SIZE];
 	char button_name[NAME_SIZE];
 	int jack_type;
+	int jack_mask;
+	int button_mask;
 	int button_status;
 	struct snd_soc_jack headset_jack;
 	struct snd_soc_jack button_jack;
diff --git a/drivers/staging/greybus/audio_module.c b/drivers/staging/greybus/audio_module.c
index c2172719e6876..f764f007b5432 100644
--- a/drivers/staging/greybus/audio_module.c
+++ b/drivers/staging/greybus/audio_module.c
@@ -33,22 +33,22 @@ static int gbaudio_request_jack(struct gbaudio_module_info *module,
 		module->button_status = 0;
 		if (button_status)
 			snd_soc_jack_report(&module->button_jack, 0,
-					    GBCODEC_JACK_BUTTON_MASK);
+					    module->button_mask);
 		snd_soc_jack_report(&module->headset_jack, 0,
-				    GBCODEC_JACK_MASK);
+				    module->jack_mask);
 		return 0;
 	}
 
 	/* currently supports Headphone, Headset & Lineout only */
-	report &= ~GBCODEC_JACK_MASK;
-	report |= req->jack_attribute & GBCODEC_JACK_MASK;
+	report &= ~module->jack_mask;
+	report |= req->jack_attribute & module->jack_mask;
 	if (module->jack_type)
 		dev_warn_ratelimited(module->dev,
 				     "Modifying jack from %d to %d\n",
 				     module->jack_type, report);
 
 	module->jack_type = report;
-	snd_soc_jack_report(&module->headset_jack, report, GBCODEC_JACK_MASK);
+	snd_soc_jack_report(&module->headset_jack, report, module->jack_mask);
 
 	return 0;
 }
@@ -69,7 +69,7 @@ static int gbaudio_request_button(struct gbaudio_module_info *module,
 		return -EINVAL;
 	}
 
-	report = module->button_status & GBCODEC_JACK_BUTTON_MASK;
+	report = module->button_status & module->button_mask;
 
 	switch (req->button_id) {
 	case 1:
@@ -100,8 +100,7 @@ static int gbaudio_request_button(struct gbaudio_module_info *module,
 
 	module->button_status = report;
 
-	snd_soc_jack_report(&module->button_jack, report,
-			    GBCODEC_JACK_BUTTON_MASK);
+	snd_soc_jack_report(&module->button_jack, report, module->button_mask);
 
 	return 0;
 }
diff --git a/drivers/staging/greybus/audio_topology.c b/drivers/staging/greybus/audio_topology.c
index e2fc186756a7c..5eef5367896c2 100644
--- a/drivers/staging/greybus/audio_topology.c
+++ b/drivers/staging/greybus/audio_topology.c
@@ -1393,6 +1393,13 @@ int gbaudio_tplg_parse_data(struct gbaudio_module_info *module,
 	}
 	dev_dbg(module->dev, "Route parsing finished\n");
 
+	/* parse jack capabilities */
+	if (tplg_data->jack_type) {
+		module->jack_mask = tplg_data->jack_type & GBCODEC_JACK_MASK;
+		module->button_mask = tplg_data->jack_type &
+			GBCODEC_JACK_BUTTON_MASK;
+	}
+
 	return ret;
 }
 
-- 
2.30.2