[ALSA] intel8x0 - Fix PM

Intel8x0 driver
Fixed the PCM resume of intel8x0.
Restores the requested register setting.

Signed-off-by: Takashi Iwai <tiwai@suse.de>
diff --git a/sound/pci/intel8x0.c b/sound/pci/intel8x0.c
index d7af3e4..390b6c8 100644
--- a/sound/pci/intel8x0.c
+++ b/sound/pci/intel8x0.c
@@ -389,6 +389,7 @@
 	struct ac97_pcm *pcm;
 	int pcm_open_flag;
 	unsigned int page_attr_changed: 1;
+	unsigned int suspended: 1;
 } ichdev_t;
 
 typedef struct _snd_intel8x0 intel8x0_t;
@@ -862,12 +863,16 @@
 	unsigned long port = ichdev->reg_offset;
 
 	switch (cmd) {
-	case SNDRV_PCM_TRIGGER_START:
 	case SNDRV_PCM_TRIGGER_RESUME:
+		ichdev->suspended = 0;
+		/* fallthru */
+	case SNDRV_PCM_TRIGGER_START:
 		val = ICH_IOCE | ICH_STARTBM;
 		break;
-	case SNDRV_PCM_TRIGGER_STOP:
 	case SNDRV_PCM_TRIGGER_SUSPEND:
+		ichdev->suspended = 1;
+		/* fallthru */
+	case SNDRV_PCM_TRIGGER_STOP:
 		val = 0;
 		break;
 	case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
@@ -899,9 +904,11 @@
 
 	val = igetdword(chip, ICHREG(ALI_DMACR));
 	switch (cmd) {
+	case SNDRV_PCM_TRIGGER_RESUME:
+		ichdev->suspended = 0;
+		/* fallthru */
 	case SNDRV_PCM_TRIGGER_START:
 	case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
-	case SNDRV_PCM_TRIGGER_RESUME:
 		if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
 			/* clear FIFO for synchronization of channels */
 			fifo = igetdword(chip, fiforeg[ichdev->ali_slot / 4]);
@@ -913,9 +920,11 @@
 		val &= ~(1 << (ichdev->ali_slot + 16)); /* clear PAUSE flag */
 		iputdword(chip, ICHREG(ALI_DMACR), val | (1 << ichdev->ali_slot)); /* start DMA */
 		break;
+	case SNDRV_PCM_TRIGGER_SUSPEND:
+		ichdev->suspended = 1;
+		/* fallthru */
 	case SNDRV_PCM_TRIGGER_STOP:
 	case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
-	case SNDRV_PCM_TRIGGER_SUSPEND:
 		iputdword(chip, ICHREG(ALI_DMACR), val | (1 << (ichdev->ali_slot + 16))); /* pause */
 		iputbyte(chip, port + ICH_REG_OFF_CR, 0);
 		while (igetbyte(chip, port + ICH_REG_OFF_CR))
@@ -994,6 +1003,8 @@
 {
 	unsigned int cnt;
 	int dbl = runtime->rate > 48000;
+
+	spin_lock_irq(&chip->reg_lock);
 	switch (chip->device_type) {
 	case DEVICE_ALI:
 		cnt = igetdword(chip, ICHREG(ALI_SCR));
@@ -1037,6 +1048,7 @@
 		iputdword(chip, ICHREG(GLOB_CNT), cnt);
 		break;
 	}
+	spin_unlock_irq(&chip->reg_lock);
 }
 
 static int snd_intel8x0_pcm_prepare(snd_pcm_substream_t * substream)
@@ -1048,15 +1060,12 @@
 	ichdev->physbuf = runtime->dma_addr;
 	ichdev->size = snd_pcm_lib_buffer_bytes(substream);
 	ichdev->fragsize = snd_pcm_lib_period_bytes(substream);
-	spin_lock_irq(&chip->reg_lock);
 	if (ichdev->ichd == ICHD_PCMOUT) {
 		snd_intel8x0_setup_pcm_out(chip, runtime);
-		if (chip->device_type == DEVICE_INTEL_ICH4) {
+		if (chip->device_type == DEVICE_INTEL_ICH4)
 			ichdev->pos_shift = (runtime->sample_bits > 16) ? 2 : 1;
-		}
 	}
 	snd_intel8x0_setup_periods(chip, ichdev);
-	spin_unlock_irq(&chip->reg_lock);
 	return 0;
 }
 
@@ -2424,6 +2433,20 @@
 		}
 	}
 
+	/* resume status */
+	for (i = 0; i < chip->bdbars_count; i++) {
+		ichdev_t *ichdev = &chip->ichd[i];
+		unsigned long port = ichdev->reg_offset;
+		if (! ichdev->substream || ! ichdev->suspended)
+			continue;
+		if (ichdev->ichd == ICHD_PCMOUT)
+			snd_intel8x0_setup_pcm_out(chip, ichdev->substream->runtime);
+		iputdword(chip, port + ICH_REG_OFF_BDBAR, ichdev->bdbar_addr);
+		iputbyte(chip, port + ICH_REG_OFF_LVI, ichdev->lvi);
+		iputbyte(chip, port + ICH_REG_OFF_CIV, ichdev->civ);
+		iputbyte(chip, port + ichdev->roff_sr, ICH_FIFOE | ICH_BCIS | ICH_LVBCI);
+	}
+
 	return 0;
 }
 #endif /* CONFIG_PM */