[alsa-devel] [RFC PATCH 1/2] ALSA: hda - jack support DP MST audio

libin.yang at linux.intel.com libin.yang at linux.intel.com
Tue Nov 3 09:42:55 CET 2015


From: Libin Yang <libin.yang at linux.intel.com>

Add jack support for DP MST audio in hda_jack.c

Signed-off-by: Libin Yang <libin.yang at linux.intel.com>
---
 sound/pci/hda/hda_jack.c   | 158 +++++++++++++++++++++++++++++++++++++++------
 sound/pci/hda/hda_jack.h   |  28 +++++++-
 sound/pci/hda/patch_hdmi.c |   2 +-
 3 files changed, 166 insertions(+), 22 deletions(-)

diff --git a/sound/pci/hda/hda_jack.c b/sound/pci/hda/hda_jack.c
index 366efbf..c0a018b 100644
--- a/sound/pci/hda/hda_jack.c
+++ b/sound/pci/hda/hda_jack.c
@@ -47,7 +47,8 @@ bool is_jack_detectable(struct hda_codec *codec, hda_nid_t nid)
 EXPORT_SYMBOL_GPL(is_jack_detectable);
 
 /* execute pin sense measurement */
-static u32 read_pin_sense(struct hda_codec *codec, hda_nid_t nid)
+static u32 read_pin_sense(struct hda_codec *codec, hda_nid_t nid,
+					hda_dev_t dev_id)
 {
 	u32 pincap;
 	u32 val;
@@ -59,7 +60,7 @@ static u32 read_pin_sense(struct hda_codec *codec, hda_nid_t nid)
 					AC_VERB_SET_PIN_SENSE, 0);
 	}
 	val = snd_hda_codec_read(codec, nid, 0,
-				  AC_VERB_GET_PIN_SENSE, 0);
+				  AC_VERB_GET_PIN_SENSE, dev_id);
 	if (codec->inv_jack_detect)
 		val ^= AC_PINSENSE_PRESENCE;
 	return val;
@@ -86,6 +87,28 @@ snd_hda_jack_tbl_get(struct hda_codec *codec, hda_nid_t nid)
 EXPORT_SYMBOL_GPL(snd_hda_jack_tbl_get);
 
 /**
+ * snd_hda_jack_tbl_get_mst - query the jack-table entry for the given NID
+ * @codec: the HDA codec
+ * @nid: pin NID to refer to
+ * @dev_id: device entry id
+ */
+struct hda_jack_tbl *
+snd_hda_jack_tbl_get_mst(struct hda_codec *codec, hda_nid_t nid,
+			hda_dev_t dev_id)
+{
+	struct hda_jack_tbl *jack = codec->jacktbl.list;
+	int i;
+
+	if (!nid || !jack)
+		return NULL;
+	for (i = 0; i < codec->jacktbl.used; i++, jack++)
+		if (jack->nid == nid && jack->dev_id == dev_id)
+			return jack;
+	return NULL;
+}
+EXPORT_SYMBOL_GPL(snd_hda_jack_tbl_get_mst);
+
+/**
  * snd_hda_jack_tbl_get_from_tag - query the jack-table entry for the given tag
  * @codec: the HDA codec
  * @tag: tag value to refer to
@@ -109,17 +132,20 @@ EXPORT_SYMBOL_GPL(snd_hda_jack_tbl_get_from_tag);
  * snd_hda_jack_tbl_new - create a jack-table entry for the given NID
  * @codec: the HDA codec
  * @nid: pin NID to assign
+ * @dev_id: device entry id
  */
 static struct hda_jack_tbl *
-snd_hda_jack_tbl_new(struct hda_codec *codec, hda_nid_t nid)
+snd_hda_jack_tbl_new(struct hda_codec *codec, hda_nid_t nid, hda_dev_t dev_id)
 {
-	struct hda_jack_tbl *jack = snd_hda_jack_tbl_get(codec, nid);
+	struct hda_jack_tbl *jack =
+		snd_hda_jack_tbl_get_mst(codec, nid, dev_id);
 	if (jack)
 		return jack;
 	jack = snd_array_new(&codec->jacktbl);
 	if (!jack)
 		return NULL;
 	jack->nid = nid;
+	jack->dev_id = dev_id;
 	jack->jack_dirty = 1;
 	jack->tag = codec->jacktbl.used;
 	return jack;
@@ -157,9 +183,11 @@ static void jack_detect_update(struct hda_codec *codec,
 	if (jack->phantom_jack)
 		jack->pin_sense = AC_PINSENSE_PRESENCE;
 	else
-		jack->pin_sense = read_pin_sense(codec, jack->nid);
+		jack->pin_sense =
+			read_pin_sense(codec, jack->nid, jack->dev_id);
 
 	/* A gating jack indicates the jack is invalid if gating is unplugged */
+	/* fixme: MST audio doesn't using gating and gated jack. */
 	if (jack->gating_jack && !snd_hda_jack_detect(codec, jack->gating_jack))
 		jack->pin_sense &= ~AC_PINSENSE_PRESENCE;
 
@@ -198,18 +226,20 @@ EXPORT_SYMBOL_GPL(snd_hda_jack_set_dirty_all);
  * snd_hda_pin_sense - execute pin sense measurement
  * @codec: the CODEC to sense
  * @nid: the pin NID to sense
+ * @dev_id: device entry id
  *
  * Execute necessary pin sense measurement and return its Presence Detect,
  * Impedance, ELD Valid etc. status bits.
  */
-u32 snd_hda_pin_sense(struct hda_codec *codec, hda_nid_t nid)
+u32 snd_hda_pin_sense(struct hda_codec *codec, hda_nid_t nid, hda_dev_t dev_id)
 {
-	struct hda_jack_tbl *jack = snd_hda_jack_tbl_get(codec, nid);
+	struct hda_jack_tbl *jack =
+		snd_hda_jack_tbl_get_mst(codec, nid, dev_id);
 	if (jack) {
 		jack_detect_update(codec, jack);
 		return jack->pin_sense;
 	}
-	return read_pin_sense(codec, nid);
+	return read_pin_sense(codec, nid, dev_id);
 }
 EXPORT_SYMBOL_GPL(snd_hda_pin_sense);
 
@@ -226,7 +256,7 @@ int snd_hda_jack_detect_state(struct hda_codec *codec, hda_nid_t nid)
 	struct hda_jack_tbl *jack = snd_hda_jack_tbl_get(codec, nid);
 	if (jack && jack->phantom_jack)
 		return HDA_JACK_PHANTOM;
-	else if (snd_hda_pin_sense(codec, nid) & AC_PINSENSE_PRESENCE)
+	else if (snd_hda_pin_sense(codec, nid, 0) & AC_PINSENSE_PRESENCE)
 		return HDA_JACK_PRESENT;
 	else
 		return HDA_JACK_NOT_PRESENT;
@@ -234,7 +264,31 @@ int snd_hda_jack_detect_state(struct hda_codec *codec, hda_nid_t nid)
 EXPORT_SYMBOL_GPL(snd_hda_jack_detect_state);
 
 /**
- * snd_hda_jack_detect_enable - enable the jack-detection
+ * snd_hda_jack_detect_state_mst - query pin Presence Detect status in mst mode
+ * @codec: the CODEC to sense
+ * @nid: the pin NID to sense
+ * @dev_id: device entry id
+ *
+ * Query and return the device entry's Presence Detect status, as either
+ * HDA_JACK_NOT_PRESENT, HDA_JACK_PRESENT or HDA_JACK_PHANTOM.
+ */
+int snd_hda_jack_detect_state_mst(struct hda_codec *codec, hda_nid_t nid,
+					hda_dev_t dev_id)
+{
+	struct hda_jack_tbl *jack =
+		snd_hda_jack_tbl_get_mst(codec, nid, dev_id);
+
+	if (jack && jack->phantom_jack)
+		return HDA_JACK_PHANTOM;
+	else if (snd_hda_pin_sense(codec, nid, dev_id) & AC_PINSENSE_PRESENCE)
+		return HDA_JACK_PRESENT;
+	else
+		return HDA_JACK_NOT_PRESENT;
+}
+EXPORT_SYMBOL_GPL(snd_hda_jack_detect_state_mst);
+
+/**
+ * snd_hda_jack_detect_enable_callback - enable the jack-detection
  * @codec: the HDA codec
  * @nid: pin NID to enable
  * @func: callback function to register
@@ -251,7 +305,7 @@ snd_hda_jack_detect_enable_callback(struct hda_codec *codec, hda_nid_t nid,
 	struct hda_jack_callback *callback = NULL;
 	int err;
 
-	jack = snd_hda_jack_tbl_new(codec, nid);
+	jack = snd_hda_jack_tbl_new(codec, nid, 0);
 	if (!jack)
 		return ERR_PTR(-ENOMEM);
 	if (func) {
@@ -279,6 +333,52 @@ snd_hda_jack_detect_enable_callback(struct hda_codec *codec, hda_nid_t nid,
 EXPORT_SYMBOL_GPL(snd_hda_jack_detect_enable_callback);
 
 /**
+ * snd_hda_jack_detect_enable_callback_mst - enable the jack-detection for mst
+ * @codec: the HDA codec
+ * @nid: pin NID to enable
+ * @dev_id: device entry id
+ * @func: callback function to register
+ *
+ * In the case of error, the return value will be a pointer embedded with
+ * errno.  Check and handle the return value appropriately with standard
+ * macros such as @IS_ERR() and @PTR_ERR().
+ */
+struct hda_jack_callback *
+snd_hda_jack_detect_enable_callback_mst(struct hda_codec *codec, hda_nid_t nid,
+			hda_dev_t dev_id, hda_jack_callback_fn func)
+{
+	struct hda_jack_tbl *jack;
+	struct hda_jack_callback *callback = NULL;
+	int err;
+
+	jack = snd_hda_jack_tbl_new(codec, nid, dev_id);
+	if (!jack)
+		return ERR_PTR(-ENOMEM);
+	if (func) {
+		callback = kzalloc(sizeof(*callback), GFP_KERNEL);
+		if (!callback)
+			return ERR_PTR(-ENOMEM);
+		callback->func = func;
+		callback->tbl = jack;
+		callback->next = jack->callback;
+		jack->callback = callback;
+	}
+
+	if (jack->jack_detect)
+		return callback; /* already registered */
+	jack->jack_detect = 1;
+	if (codec->jackpoll_interval > 0)
+		return callback; /* No unsol if we're polling instead */
+	err = snd_hda_codec_write_cache(codec, nid, 0,
+					 AC_VERB_SET_UNSOLICITED_ENABLE,
+					 AC_USRSP_EN | jack->tag);
+	if (err < 0)
+		return ERR_PTR(err);
+	return callback;
+}
+EXPORT_SYMBOL_GPL(snd_hda_jack_detect_enable_callback_mst);
+
+/**
  * snd_hda_jack_detect_enable - Enable the jack detection on the given pin
  * @codec: the HDA codec
  * @nid: pin NID to enable jack detection
@@ -303,8 +403,9 @@ EXPORT_SYMBOL_GPL(snd_hda_jack_detect_enable);
 int snd_hda_jack_set_gating_jack(struct hda_codec *codec, hda_nid_t gated_nid,
 				 hda_nid_t gating_nid)
 {
-	struct hda_jack_tbl *gated = snd_hda_jack_tbl_new(codec, gated_nid);
-	struct hda_jack_tbl *gating = snd_hda_jack_tbl_new(codec, gating_nid);
+	struct hda_jack_tbl *gated = snd_hda_jack_tbl_new(codec, gated_nid, 0);
+	struct hda_jack_tbl *gating =
+		snd_hda_jack_tbl_new(codec, gating_nid, 0);
 
 	if (!gated || !gating)
 		return -EINVAL;
@@ -369,6 +470,8 @@ static int get_input_jack_type(struct hda_codec *codec, hda_nid_t nid)
 static void hda_free_jack_priv(struct snd_jack *jack)
 {
 	struct hda_jack_tbl *jacks = jack->private_data;
+	if (jacks == NULL)
+		return;
 	jacks->nid = 0;
 	jacks->jack = NULL;
 }
@@ -377,6 +480,7 @@ static void hda_free_jack_priv(struct snd_jack *jack)
  * snd_hda_jack_add_kctl - Add a kctl for the given pin
  * @codec: the HDA codec
  * @nid: pin NID to assign
+ * @dev_id: device entry id
  * @name: string name for the jack
  * @phantom_jack: flag to deal as a phantom jack
  *
@@ -384,17 +488,18 @@ static void hda_free_jack_priv(struct snd_jack *jack)
  * will have the given name and index.
  */
 static int __snd_hda_jack_add_kctl(struct hda_codec *codec, hda_nid_t nid,
-			  const char *name, bool phantom_jack)
+		hda_dev_t dev_id, const char *name, bool phantom_jack)
 {
 	struct hda_jack_tbl *jack;
 	int err, state, type;
 
-	jack = snd_hda_jack_tbl_new(codec, nid);
+	jack = snd_hda_jack_tbl_new(codec, nid, dev_id);
 	if (!jack)
 		return 0;
 	if (jack->jack)
 		return 0; /* already created */
 
+	/* all device entries use same pincfg */
 	type = get_input_jack_type(codec, nid);
 	err = snd_jack_new(codec->card, name, type,
 			   &jack->jack, true, phantom_jack);
@@ -405,7 +510,7 @@ static int __snd_hda_jack_add_kctl(struct hda_codec *codec, hda_nid_t nid,
 	jack->type = type;
 	jack->jack->private_data = jack;
 	jack->jack->private_free = hda_free_jack_priv;
-	state = snd_hda_jack_detect(codec, nid);
+	state = snd_hda_jack_detect_mst(codec, nid, dev_id);
 	snd_jack_report(jack->jack, state ? jack->type : 0);
 
 	return 0;
@@ -422,10 +527,27 @@ static int __snd_hda_jack_add_kctl(struct hda_codec *codec, hda_nid_t nid,
 int snd_hda_jack_add_kctl(struct hda_codec *codec, hda_nid_t nid,
 			  const char *name)
 {
-	return __snd_hda_jack_add_kctl(codec, nid, name, false);
+	return __snd_hda_jack_add_kctl(codec, nid, 0, name, false);
 }
 EXPORT_SYMBOL_GPL(snd_hda_jack_add_kctl);
 
+/**
+ * snd_hda_jack_add_kctl_mst - Add a jack kctl for the given pin for mst mode
+ * @codec: the HDA codec
+ * @nid: pin NID
+ * @dev_id: device entry id
+ * @name: the name string for the jack ctl
+ *
+ * This is a simple helper calling __snd_hda_jack_add_kctl().
+ */
+int snd_hda_jack_add_kctl_mst(struct hda_codec *codec, hda_nid_t nid,
+			hda_dev_t dev_id, const char *name)
+{
+	return __snd_hda_jack_add_kctl(codec, nid, dev_id, name, false);
+}
+EXPORT_SYMBOL_GPL(snd_hda_jack_add_kctl_mst);
+
+
 static int add_jack_kctl(struct hda_codec *codec, hda_nid_t nid,
 			 const struct auto_pin_cfg *cfg,
 			 const char *base_name)
@@ -451,7 +573,7 @@ static int add_jack_kctl(struct hda_codec *codec, hda_nid_t nid,
 	if (phantom_jack)
 		/* Example final name: "Internal Mic Phantom Jack" */
 		strncat(name, " Phantom", sizeof(name) - strlen(name) - 1);
-	err = __snd_hda_jack_add_kctl(codec, nid, name, phantom_jack);
+	err = __snd_hda_jack_add_kctl(codec, nid, 0, name, phantom_jack);
 	if (err < 0)
 		return err;
 
diff --git a/sound/pci/hda/hda_jack.h b/sound/pci/hda/hda_jack.h
index 387d309..c9d4f8e 100644
--- a/sound/pci/hda/hda_jack.h
+++ b/sound/pci/hda/hda_jack.h
@@ -29,6 +29,7 @@ struct hda_jack_callback {
 
 struct hda_jack_tbl {
 	hda_nid_t nid;
+	hda_dev_t dev_id;
 	unsigned char tag;		/* unsol event tag */
 	struct hda_jack_callback *callback;
 	/* jack-detection stuff */
@@ -46,6 +47,9 @@ struct hda_jack_tbl {
 struct hda_jack_tbl *
 snd_hda_jack_tbl_get(struct hda_codec *codec, hda_nid_t nid);
 struct hda_jack_tbl *
+snd_hda_jack_tbl_get_mst(struct hda_codec *codec, hda_nid_t nid,
+				 hda_dev_t dev_id);
+struct hda_jack_tbl *
 snd_hda_jack_tbl_get_from_tag(struct hda_codec *codec, unsigned char tag);
 
 void snd_hda_jack_tbl_clear(struct hda_codec *codec);
@@ -56,11 +60,14 @@ int snd_hda_jack_detect_enable(struct hda_codec *codec, hda_nid_t nid);
 struct hda_jack_callback *
 snd_hda_jack_detect_enable_callback(struct hda_codec *codec, hda_nid_t nid,
 				    hda_jack_callback_fn cb);
+struct hda_jack_callback *
+snd_hda_jack_detect_enable_callback_mst(struct hda_codec *codec, hda_nid_t nid,
+			hda_dev_t dev_id, hda_jack_callback_fn func);
 
 int snd_hda_jack_set_gating_jack(struct hda_codec *codec, hda_nid_t gated_nid,
 				 hda_nid_t gating_nid);
 
-u32 snd_hda_pin_sense(struct hda_codec *codec, hda_nid_t nid);
+u32 snd_hda_pin_sense(struct hda_codec *codec, hda_nid_t nid, hda_dev_t dev_id);
 
 /* the jack state returned from snd_hda_jack_detect_state() */
 enum {
@@ -68,7 +75,8 @@ enum {
 };
 
 int snd_hda_jack_detect_state(struct hda_codec *codec, hda_nid_t nid);
-
+int snd_hda_jack_detect_state_mst(struct hda_codec *codec,
+					hda_nid_t nid, hda_dev_t dev_id);
 /**
  * snd_hda_jack_detect - Detect the jack
  * @codec: the HDA codec
@@ -79,13 +87,27 @@ static inline bool snd_hda_jack_detect(struct hda_codec *codec, hda_nid_t nid)
 	return snd_hda_jack_detect_state(codec, nid) != HDA_JACK_NOT_PRESENT;
 }
 
+/**
+ * snd_hda_jack_detect - Detect the jack
+ * @codec: the HDA codec
+ * @nid: pin NID to check jack detection
+ * @dev_id: device entry id
+ */
+static inline bool snd_hda_jack_detect_mst(struct hda_codec *codec,
+				hda_nid_t nid, hda_dev_t dev_id)
+{
+	return (snd_hda_jack_detect_state_mst(codec, nid, dev_id) !=
+			HDA_JACK_NOT_PRESENT);
+}
+
 bool is_jack_detectable(struct hda_codec *codec, hda_nid_t nid);
 
 int snd_hda_jack_add_kctl(struct hda_codec *codec, hda_nid_t nid,
 			  const char *name);
 int snd_hda_jack_add_kctls(struct hda_codec *codec,
 			   const struct auto_pin_cfg *cfg);
-
+int snd_hda_jack_add_kctl_mst(struct hda_codec *codec, hda_nid_t nid,
+			   hda_dev_t dev_id, const char *name);
 void snd_hda_jack_report_sync(struct hda_codec *codec);
 
 void snd_hda_jack_unsol_event(struct hda_codec *codec, unsigned int res);
diff --git a/sound/pci/hda/patch_hdmi.c b/sound/pci/hda/patch_hdmi.c
index 8d31366..39d68ba 100644
--- a/sound/pci/hda/patch_hdmi.c
+++ b/sound/pci/hda/patch_hdmi.c
@@ -1664,7 +1664,7 @@ static bool hdmi_present_sense(struct hdmi_spec_per_pin *per_pin, int repoll)
 	bool ret;
 
 	snd_hda_power_up_pm(codec);
-	present = snd_hda_pin_sense(codec, pin_nid);
+	present = snd_hda_pin_sense(codec, pin_nid, 0);
 
 	mutex_lock(&per_pin->lock);
 	pin_eld->monitor_present = !!(present & AC_PINSENSE_PRESENCE);
-- 
1.9.1



More information about the Alsa-devel mailing list