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

Commit a74a8216 authored by Takashi Iwai's avatar Takashi Iwai
Browse files

ALSA: rme96: Fix unexpected volume reset after rate changes



rme96 driver needs to reset DAC depending on the sample rate, and this
results in resetting to the max volume suddenly.  It's because of the
missing call of snd_rme96_apply_dac_volume().

However, calling this function right after the DAC reset still may not
work, and we need some delay before this call.  Since the DAC reset
and the procedure after that are performed in the spinlock, we delay
the DAC volume restore at the end after the spinlock.

Reported-and-tested-by: default avatarSylvain LABOISNE <maeda1@free.fr>
Cc: <stable@vger.kernel.org>
Signed-off-by: default avatarTakashi Iwai <tiwai@suse.de>
parent bcdda2ec
Loading
Loading
Loading
Loading
+26 −15
Original line number Diff line number Diff line
@@ -741,11 +741,12 @@ snd_rme96_playback_setrate(struct rme96 *rme96,
	{
		/* change to/from double-speed: reset the DAC (if available) */
		snd_rme96_reset_dac(rme96);
		return 1; /* need to restore volume */
	} else {
		writel(rme96->wcreg, rme96->iobase + RME96_IO_CONTROL_REGISTER);
	}
		return 0;
	}
}

static int
snd_rme96_capture_analog_setrate(struct rme96 *rme96,
@@ -980,6 +981,7 @@ snd_rme96_playback_hw_params(struct snd_pcm_substream *substream,
	struct rme96 *rme96 = snd_pcm_substream_chip(substream);
	struct snd_pcm_runtime *runtime = substream->runtime;
	int err, rate, dummy;
	bool apply_dac_volume = false;

	runtime->dma_area = (void __force *)(rme96->iobase +
					     RME96_IO_PLAY_BUFFER);
@@ -993,24 +995,26 @@ snd_rme96_playback_hw_params(struct snd_pcm_substream *substream,
	{
                /* slave clock */
                if ((int)params_rate(params) != rate) {
			spin_unlock_irq(&rme96->lock);
			return -EIO;                    
			err = -EIO;
			goto error;
		}
	} else if ((err = snd_rme96_playback_setrate(rme96, params_rate(params))) < 0) {
		spin_unlock_irq(&rme96->lock);
		return err;
	}
	if ((err = snd_rme96_playback_setformat(rme96, params_format(params))) < 0) {
		spin_unlock_irq(&rme96->lock);
		return err;
	} else {
		err = snd_rme96_playback_setrate(rme96, params_rate(params));
		if (err < 0)
			goto error;
		apply_dac_volume = err > 0; /* need to restore volume later? */
	}

	err = snd_rme96_playback_setformat(rme96, params_format(params));
	if (err < 0)
		goto error;
	snd_rme96_setframelog(rme96, params_channels(params), 1);
	if (rme96->capture_periodsize != 0) {
		if (params_period_size(params) << rme96->playback_frlog !=
		    rme96->capture_periodsize)
		{
			spin_unlock_irq(&rme96->lock);
			return -EBUSY;
			err = -EBUSY;
			goto error;
		}
	}
	rme96->playback_periodsize =
@@ -1021,9 +1025,16 @@ snd_rme96_playback_hw_params(struct snd_pcm_substream *substream,
		rme96->wcreg &= ~(RME96_WCR_PRO | RME96_WCR_DOLBY | RME96_WCR_EMP);
		writel(rme96->wcreg |= rme96->wcreg_spdif_stream, rme96->iobase + RME96_IO_CONTROL_REGISTER);
	}

	err = 0;
 error:
	spin_unlock_irq(&rme96->lock);
	if (apply_dac_volume) {
		usleep_range(3000, 10000);
		snd_rme96_apply_dac_volume(rme96);
	}

	return 0;
	return err;
}

static int