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

Commit 5bdb6a16 authored by Takashi Iwai's avatar Takashi Iwai Committed by Jaroslav Kysela
Browse files

[ALSA] Add PM support to SB-support code



Modules: SB drivers,SB16/AWE driver

Add PM support to SB-support code.

Signed-off-by: default avatarTakashi Iwai <tiwai@suse.de>
parent cb60e5f5
Loading
Loading
Loading
Loading
+8 −0
Original line number Diff line number Diff line
@@ -107,6 +107,10 @@ struct snd_sb {
	spinlock_t midi_input_lock;

	struct snd_info_entry *proc_entry;

#ifdef CONFIG_PM
	unsigned char saved_regs[0x20];
#endif
};

/* I/O ports */
@@ -290,6 +294,10 @@ int snd_sbdsp_create(struct snd_card *card,
void snd_sbmixer_write(struct snd_sb *chip, unsigned char reg, unsigned char data);
unsigned char snd_sbmixer_read(struct snd_sb *chip, unsigned char reg);
int snd_sbmixer_new(struct snd_sb *chip);
#ifdef CONFIG_PM
void snd_sbmixer_suspend(struct snd_sb *chip);
void snd_sbmixer_resume(struct snd_sb *chip);
#endif

/* sb8_init.c */
int snd_sb8dsp_pcm(struct snd_sb *chip, int device, struct snd_pcm ** rpcm);
+4 −0
Original line number Diff line number Diff line
@@ -307,10 +307,12 @@ static int snd_sb16_playback_trigger(struct snd_pcm_substream *substream,
	spin_lock(&chip->reg_lock);
	switch (cmd) {
	case SNDRV_PCM_TRIGGER_START:
	case SNDRV_PCM_TRIGGER_RESUME:
		chip->mode |= SB_RATE_LOCK_PLAYBACK;
		snd_sbdsp_command(chip, chip->mode & SB_MODE_PLAYBACK_16 ? SB_DSP_DMA16_ON : SB_DSP_DMA8_ON);
		break;
	case SNDRV_PCM_TRIGGER_STOP:
	case SNDRV_PCM_TRIGGER_SUSPEND:
		snd_sbdsp_command(chip, chip->mode & SB_MODE_PLAYBACK_16 ? SB_DSP_DMA16_OFF : SB_DSP_DMA8_OFF);
		/* next two lines are needed for some types of DSP4 (SB AWE 32 - 4.13) */
		if (chip->mode & SB_RATE_LOCK_CAPTURE)
@@ -374,10 +376,12 @@ static int snd_sb16_capture_trigger(struct snd_pcm_substream *substream,
	spin_lock(&chip->reg_lock);
	switch (cmd) {
	case SNDRV_PCM_TRIGGER_START:
	case SNDRV_PCM_TRIGGER_RESUME:
		chip->mode |= SB_RATE_LOCK_CAPTURE;
		snd_sbdsp_command(chip, chip->mode & SB_MODE_CAPTURE_16 ? SB_DSP_DMA16_ON : SB_DSP_DMA8_ON);
		break;
	case SNDRV_PCM_TRIGGER_STOP:
	case SNDRV_PCM_TRIGGER_SUSPEND:
		snd_sbdsp_command(chip, chip->mode & SB_MODE_CAPTURE_16 ? SB_DSP_DMA16_OFF : SB_DSP_DMA8_OFF);
		/* next two lines are needed for some types of DSP4 (SB AWE 32 - 4.13) */
		if (chip->mode & SB_RATE_LOCK_PLAYBACK)
+4 −0
Original line number Diff line number Diff line
@@ -293,6 +293,10 @@ EXPORT_SYMBOL(snd_sbmixer_write);
EXPORT_SYMBOL(snd_sbmixer_read);
EXPORT_SYMBOL(snd_sbmixer_new);
EXPORT_SYMBOL(snd_sbmixer_add_ctl);
#ifdef CONFIG_PM
EXPORT_SYMBOL(snd_sbmixer_suspend);
EXPORT_SYMBOL(snd_sbmixer_resume);
#endif

/*
 *  INIT part
+137 −0
Original line number Diff line number Diff line
@@ -853,3 +853,140 @@ int snd_sbmixer_new(struct snd_sb *chip)
	}
	return 0;
}

#ifdef CONFIG_PM
static unsigned char sb20_saved_regs[] = {
	SB_DSP20_MASTER_DEV,
	SB_DSP20_PCM_DEV,
	SB_DSP20_FM_DEV,
	SB_DSP20_CD_DEV,
};

static unsigned char sbpro_saved_regs[] = {
	SB_DSP_MASTER_DEV,
	SB_DSP_PCM_DEV,
	SB_DSP_PLAYBACK_FILT,
	SB_DSP_FM_DEV,
	SB_DSP_CD_DEV,
	SB_DSP_LINE_DEV,
	SB_DSP_MIC_DEV,
	SB_DSP_CAPTURE_SOURCE,
	SB_DSP_CAPTURE_FILT,
};

static unsigned char sb16_saved_regs[] = {
	SB_DSP4_MASTER_DEV, SB_DSP4_MASTER_DEV + 1,
	SB_DSP4_3DSE,
	SB_DSP4_BASS_DEV, SB_DSP4_BASS_DEV + 1,
	SB_DSP4_TREBLE_DEV, SB_DSP4_TREBLE_DEV + 1,
	SB_DSP4_PCM_DEV, SB_DSP4_PCM_DEV + 1,
	SB_DSP4_INPUT_LEFT, SB_DSP4_INPUT_RIGHT,
	SB_DSP4_SYNTH_DEV, SB_DSP4_SYNTH_DEV + 1,
	SB_DSP4_OUTPUT_SW,
	SB_DSP4_CD_DEV, SB_DSP4_CD_DEV + 1,
	SB_DSP4_LINE_DEV, SB_DSP4_LINE_DEV + 1,
	SB_DSP4_MIC_DEV,
	SB_DSP4_SPEAKER_DEV,
	SB_DSP4_IGAIN_DEV, SB_DSP4_IGAIN_DEV + 1,
	SB_DSP4_OGAIN_DEV, SB_DSP4_OGAIN_DEV + 1,
	SB_DSP4_MIC_AGC
};

static unsigned char dt019x_saved_regs[] = {
	SB_DT019X_MASTER_DEV,
	SB_DT019X_PCM_DEV,
	SB_DT019X_SYNTH_DEV,
	SB_DT019X_CD_DEV,
	SB_DT019X_MIC_DEV,
	SB_DT019X_SPKR_DEV,
	SB_DT019X_LINE_DEV,
	SB_DSP4_OUTPUT_SW,
	SB_DT019X_OUTPUT_SW2,
	SB_DT019X_CAPTURE_SW,
};

static unsigned char als4000_saved_regs[] = {
	SB_DSP4_MASTER_DEV, SB_DSP4_MASTER_DEV + 1,
	SB_DSP4_OUTPUT_SW,
	SB_DSP4_PCM_DEV, SB_DSP4_PCM_DEV + 1,
	SB_DSP4_INPUT_LEFT, SB_DSP4_INPUT_RIGHT,
	SB_DSP4_SYNTH_DEV, SB_DSP4_SYNTH_DEV + 1,
	SB_DSP4_CD_DEV, SB_DSP4_CD_DEV + 1,
	SB_DSP4_MIC_AGC,
	SB_DSP4_MIC_DEV,
	SB_DSP4_SPEAKER_DEV,
	SB_DSP4_IGAIN_DEV, SB_DSP4_IGAIN_DEV + 1,
	SB_DSP4_OGAIN_DEV, SB_DSP4_OGAIN_DEV + 1,
	SB_DT019X_OUTPUT_SW2,
	SB_ALS4000_MONO_IO_CTRL,
	SB_ALS4000_MIC_IN_GAIN,
	SB_ALS4000_3D_SND_FX,
	SB_ALS4000_3D_TIME_DELAY,
};

static void save_mixer(struct snd_sb *chip, unsigned char *regs, int num_regs)
{
	unsigned char *val = chip->saved_regs;
	snd_assert(num_regs > ARRAY_SIZE(chip->saved_regs), return);
	for (; num_regs; num_regs--)
		*val++ = snd_sbmixer_read(chip, *regs++);
}

static void restore_mixer(struct snd_sb *chip, unsigned char *regs, int num_regs)
{
	unsigned char *val = chip->saved_regs;
	snd_assert(num_regs > ARRAY_SIZE(chip->saved_regs), return);
	for (; num_regs; num_regs--)
		snd_sbmixer_write(chip, *regs++, *val++);
}

void snd_sbmixer_suspend(struct snd_sb *chip)
{
	switch (chip->hardware) {
	case SB_HW_20:
	case SB_HW_201:
		save_mixer(chip, sb20_saved_regs, ARRAY_SIZE(sb20_saved_regs));
		break;
	case SB_HW_PRO:
		save_mixer(chip, sbpro_saved_regs, ARRAY_SIZE(sbpro_saved_regs));
		break;
	case SB_HW_16:
	case SB_HW_ALS100:
		save_mixer(chip, sb16_saved_regs, ARRAY_SIZE(sb16_saved_regs));
		break;
	case SB_HW_ALS4000:
		save_mixer(chip, als4000_saved_regs, ARRAY_SIZE(als4000_saved_regs));
		break;
	case SB_HW_DT019X:
		save_mixer(chip, dt019x_saved_regs, ARRAY_SIZE(dt019x_saved_regs));
		break;
	default:
		break;
	}
}

void snd_sbmixer_resume(struct snd_sb *chip)
{
	switch (chip->hardware) {
	case SB_HW_20:
	case SB_HW_201:
		restore_mixer(chip, sb20_saved_regs, ARRAY_SIZE(sb20_saved_regs));
		break;
	case SB_HW_PRO:
		restore_mixer(chip, sbpro_saved_regs, ARRAY_SIZE(sbpro_saved_regs));
		break;
	case SB_HW_16:
	case SB_HW_ALS100:
		restore_mixer(chip, sb16_saved_regs, ARRAY_SIZE(sb16_saved_regs));
		break;
	case SB_HW_ALS4000:
		restore_mixer(chip, als4000_saved_regs, ARRAY_SIZE(als4000_saved_regs));
		break;
	case SB_HW_DT019X:
		restore_mixer(chip, dt019x_saved_regs, ARRAY_SIZE(dt019x_saved_regs));
		break;
	default:
		break;
	}
}
#endif