Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 1cfe43d2 authored by Takashi Iwai's avatar Takashi Iwai Committed by Jaroslav Kysela
Browse files

[ALSA] intel8x0 - Fix PM



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

Signed-off-by: default avatarTakashi Iwai <tiwai@suse.de>
parent 65d11d95
Loading
Loading
Loading
Loading
+31 −8
Original line number Diff line number Diff line
@@ -389,6 +389,7 @@ typedef struct {
	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 @@ static int snd_intel8x0_pcm_trigger(snd_pcm_substream_t *substream, int cmd)
	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 @@ static int snd_intel8x0_ali_trigger(snd_pcm_substream_t *substream, int cmd)

	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 @@ static int snd_intel8x0_ali_trigger(snd_pcm_substream_t *substream, int cmd)
		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 @@ static void snd_intel8x0_setup_pcm_out(intel8x0_t *chip,
{
	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 @@ static void snd_intel8x0_setup_pcm_out(intel8x0_t *chip,
		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 @@ static int snd_intel8x0_pcm_prepare(snd_pcm_substream_t * substream)
	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 @@ static int intel8x0_resume(snd_card_t *card)
		}
	}

	/* 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 */