From 4da3a97e04773e7d26ec595b8326c437a39083d7 Mon Sep 17 00:00:00 2001
From: Wang Xingchao <xingchao.wang@linux.intel.com>
Date: Thu, 25 Jul 2013 09:24:49 -0400
Subject: [PATCH] ALSA: hda - Jack hotplug support in D3

This patch intended to avoid waking up the controller/codec, but FAILED.
Even no touch hardware register in runtime_resum/suspend callback when
detected jack hotplug(leave codec/controller in D3), i still see the
controller was waken up, pm_notify() was called.

Signed-off-by: Wang Xingchao <xingchao.wang@linux.intel.com>
---
 sound/pci/hda/hda_intel.c | 16 ++++++++++----
 sound/pci/hda/hda_jack.c  | 55 ++++++++++++++++++++++++++++++++++++++++-------
 sound/pci/hda/hda_jack.h  |  1 +
 3 files changed, 60 insertions(+), 12 deletions(-)

diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c
index 708e988..38eac3a 100644
--- a/sound/pci/hda/hda_intel.c
+++ b/sound/pci/hda/hda_intel.c
@@ -63,6 +63,7 @@
 #include <linux/firmware.h>
 #include "hda_codec.h"
 #include "hda_i915.h"
+#include "hda_jack.h"
 
 
 static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX;
@@ -529,6 +530,7 @@ struct azx {
 	unsigned int snoop:1;
 	unsigned int align_buffer_size:1;
 	unsigned int region_requested:1;
+	unsigned int jack_resume:1;
 
 	/* VGA-switcheroo setup */
 	unsigned int use_vga_switcheroo:1;
@@ -1378,6 +1380,7 @@ static irqreturn_t azx_interrupt(int irq, void *dev_id)
 	u8 sd_status;
 	int i, ok;
 
+
 #ifdef CONFIG_PM_RUNTIME
 	if (chip->pci->dev.power.runtime_status != RPM_ACTIVE)
 		return IRQ_NONE;
@@ -2823,6 +2826,7 @@ static void azx_load_dsp_cleanup(struct hda_bus *bus,
 static void azx_power_notify(struct hda_bus *bus, bool power_up)
 {
 	struct azx *chip = bus->private_data;
+	snd_printk("jack: check calling here\n");
 
 	if (!(chip->driver_caps & AZX_DCAPS_PM_RUNTIME))
 		return;
@@ -2956,12 +2960,13 @@ static int azx_runtime_suspend(struct device *dev)
 	int event, status;
 	unsigned long timeout;
 
-	snd_printk("Power-well: Azx runtime suspend called\n");
-
 	/* enable controller wake up event */
 	azx_writew(chip, WAKEEN, azx_readb(chip, WAKEEN) |
 		  STATESTS_INT_MASK);
 
+	if (chip->jack_resume)
+		goto out;
+
 	azx_stop_chip(chip);
 	azx_clear_irq_pending(chip);
 
@@ -2974,6 +2979,7 @@ static int azx_runtime_suspend(struct device *dev)
 			time_before(jiffies, timeout))
 		usleep_range(500, 1000);
 
+out:
 	if (chip->driver_caps & AZX_DCAPS_I915_POWERWELL)
 		hda_display_power(false);
 	return 0;
@@ -2998,11 +3004,13 @@ static int azx_runtime_resume(struct device *dev)
 	azx_init_pci(chip);
 	azx_init_chip(chip, 1);
 
+	chip->jack_resume = !!status;
 	if (status && bus) {
 		list_for_each_entry(codec, &bus->codec_list, list)
 			if (status & (1 << codec->addr))
-				queue_delayed_work(codec->bus->workq,
-						   &codec->jackpoll_work, codec->jackpoll_interval);
+				snd_hda_jack_report_no_wakeup(codec);
+	
+		return 0;
 	}
 
 	/* disable controller Wake Up event*/
diff --git a/sound/pci/hda/hda_jack.c b/sound/pci/hda/hda_jack.c
index 9e0a952..8b0f619 100644
--- a/sound/pci/hda/hda_jack.c
+++ b/sound/pci/hda/hda_jack.c
@@ -260,23 +260,23 @@ int snd_hda_jack_set_gating_jack(struct hda_codec *codec, hda_nid_t gated_nid,
 }
 EXPORT_SYMBOL_HDA(snd_hda_jack_set_gating_jack);
 
-/**
- * snd_hda_jack_report_sync - sync the states of all jacks and report if changed
- */
-void snd_hda_jack_report_sync(struct hda_codec *codec)
+static void update_jacks(struct hda_codec *codec)
 {
 	struct hda_jack_tbl *jack;
-	int i, state;
+	int i;
 
 	/* update all jacks at first */
 	jack = codec->jacktbl.list;
 	for (i = 0; i < codec->jacktbl.used; i++, jack++)
 		if (jack->nid)
 			jack_detect_update(codec, jack);
+}
+
+static void report_jacks(struct hda_codec *codec)
+{
+	struct hda_jack_tbl *jack;
+	int i, state;
 
-	/* report the updated jacks; it's done after updating all jacks
-	 * to make sure that all gating jacks properly have been set
-	 */
 	jack = codec->jacktbl.list;
 	for (i = 0; i < codec->jacktbl.used; i++, jack++)
 		if (jack->nid) {
@@ -290,9 +290,48 @@ void snd_hda_jack_report_sync(struct hda_codec *codec)
 						state ? jack->type : 0);
 #endif
 		}
+
+}
+
+/**
+ * snd_hda_jack_report_sync - sync the states of all jacks and report if changed
+ */
+void snd_hda_jack_report_sync(struct hda_codec *codec)
+{
+	struct hda_jack_tbl *jack;
+	int i, state;
+
+	update_jacks(codec);
+	/* report the updated jacks; it's done after updating all jacks
+	 * to make sure that all gating jacks properly have been set
+	 */
+	report_jacks(codec);
 }
 EXPORT_SYMBOL_HDA(snd_hda_jack_report_sync);
 
+void snd_hda_jack_report_no_wakeup(struct hda_codec *codec)
+{
+	struct hda_jack_tbl *jack;
+	int i, state;
+
+	/* revert all jack state */
+	jack = codec->jacktbl.list;
+	for (i = 0; i < codec->jacktbl.used; i++, jack++)
+		if (jack->nid) {
+			state = get_jack_plug_state(jack->pin_sense);
+			if (!jack->pin_sense)
+				jack->pin_sense = AC_PINSENSE_PRESENCE;
+			else
+				jack->pin_sense = 0;
+		}
+
+	/* report the updated jacks; it's done after updating all jacks
+	 * to make sure that all gating jacks properly have been set
+	 */
+	report_jacks(codec);
+}
+EXPORT_SYMBOL_HDA(snd_hda_jack_report_no_wakeup);
+
 #ifdef CONFIG_SND_HDA_INPUT_JACK
 /* guess the jack type from the pin-config */
 static int get_input_jack_type(struct hda_codec *codec, hda_nid_t nid)
diff --git a/sound/pci/hda/hda_jack.h b/sound/pci/hda/hda_jack.h
index ec12abd..b14cf24 100644
--- a/sound/pci/hda/hda_jack.h
+++ b/sound/pci/hda/hda_jack.h
@@ -85,6 +85,7 @@ int snd_hda_jack_add_kctls(struct hda_codec *codec,
 			   const struct auto_pin_cfg *cfg);
 
 void snd_hda_jack_report_sync(struct hda_codec *codec);
+void snd_hda_jack_report_no_wakeup(struct hda_codec *codec);
 
 void snd_hda_jack_unsol_event(struct hda_codec *codec, unsigned int res);
 
-- 
1.8.3.2

