1
0
Fork 0

ALSA: x86: Cache AUD_CONFIG register value

At enabling the audio, we modify AUD_CONFIG register bit 0.  So far,
it does read-modify-write procedure with a special hack for the
channel bits due to the silicon bug.  But we can optimize it by
remembering the AUD_CONFIG register value privately.  This simplifies
the things a lot.

Signed-off-by: Takashi Iwai <tiwai@suse.de>
hifive-unleashed-5.1
Takashi Iwai 2017-02-07 16:17:06 +01:00
parent 77531beeb9
commit 40ce4b5d70
2 changed files with 13 additions and 27 deletions

View File

@ -212,30 +212,13 @@ static void had_write_register(struct snd_intelhad *ctx, u32 reg, u32 val)
* bad audio. The fix is to always write the AUD_CONFIG[6:4] with * bad audio. The fix is to always write the AUD_CONFIG[6:4] with
* appropriate value when doing read-modify of AUD_CONFIG register. * appropriate value when doing read-modify of AUD_CONFIG register.
*/ */
static void had_enable_audio(struct snd_pcm_substream *substream, static void had_enable_audio(struct snd_intelhad *intelhaddata,
struct snd_intelhad *intelhaddata,
bool enable) bool enable)
{ {
union aud_cfg cfg_val = {.regval = 0}; /* update the cached value */
u8 channels; intelhaddata->aud_config.regx.aud_en = enable;
u32 mask, val; had_write_register(intelhaddata, AUD_CONFIG,
intelhaddata->aud_config.regval);
/*
* If substream is NULL, there is no active stream.
* In this case just set channels to 2
*/
channels = substream ? substream->runtime->channels : 2;
dev_dbg(intelhaddata->dev, "enable %d, ch=%d\n", enable, channels);
cfg_val.regx.num_ch = channels - 2;
if (enable)
cfg_val.regx.aud_en = 1;
mask = AUD_CONFIG_CH_MASK | 1;
had_read_register(intelhaddata, AUD_CONFIG, &val);
val &= ~mask;
val |= cfg_val.regval;
had_write_register(intelhaddata, AUD_CONFIG, val);
} }
/* forcibly ACKs to both BUFFER_DONE and BUFFER_UNDERRUN interrupts */ /* forcibly ACKs to both BUFFER_DONE and BUFFER_UNDERRUN interrupts */
@ -360,6 +343,7 @@ static int had_init_audio_ctrl(struct snd_pcm_substream *substream,
} }
had_write_register(intelhaddata, AUD_CONFIG, cfg_val.regval); had_write_register(intelhaddata, AUD_CONFIG, cfg_val.regval);
intelhaddata->aud_config = cfg_val;
return 0; return 0;
} }
@ -1004,6 +988,7 @@ static void had_process_buffer_underrun(struct snd_intelhad *intelhaddata)
/* Handle Underrun interrupt within Audio Unit */ /* Handle Underrun interrupt within Audio Unit */
had_write_register(intelhaddata, AUD_CONFIG, 0); had_write_register(intelhaddata, AUD_CONFIG, 0);
intelhaddata->aud_config.regval = 0;
/* Reset buffer pointers */ /* Reset buffer pointers */
had_reset_audio(intelhaddata); had_reset_audio(intelhaddata);
@ -1169,7 +1154,7 @@ static int had_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
/* Enable Audio */ /* Enable Audio */
had_ack_irqs(intelhaddata); /* FIXME: do we need this? */ had_ack_irqs(intelhaddata); /* FIXME: do we need this? */
had_enable_audio(substream, intelhaddata, true); had_enable_audio(intelhaddata, true);
break; break;
case SNDRV_PCM_TRIGGER_STOP: case SNDRV_PCM_TRIGGER_STOP:
@ -1182,7 +1167,7 @@ static int had_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
intelhaddata->stream_info.running = false; intelhaddata->stream_info.running = false;
spin_unlock(&intelhaddata->had_spinlock); spin_unlock(&intelhaddata->had_spinlock);
/* Disable Audio */ /* Disable Audio */
had_enable_audio(substream, intelhaddata, false); had_enable_audio(intelhaddata, false);
/* Reset buffer pointers */ /* Reset buffer pointers */
had_reset_audio(intelhaddata); had_reset_audio(intelhaddata);
break; break;
@ -1315,7 +1300,7 @@ static int had_process_mode_change(struct snd_intelhad *intelhaddata)
return 0; return 0;
/* Disable Audio */ /* Disable Audio */
had_enable_audio(substream, intelhaddata, false); had_enable_audio(intelhaddata, false);
/* Update CTS value */ /* Update CTS value */
disp_samp_freq = intelhaddata->tmds_clock_speed; disp_samp_freq = intelhaddata->tmds_clock_speed;
@ -1334,7 +1319,7 @@ static int had_process_mode_change(struct snd_intelhad *intelhaddata)
n_param, intelhaddata); n_param, intelhaddata);
/* Enable Audio */ /* Enable Audio */
had_enable_audio(substream, intelhaddata, true); had_enable_audio(intelhaddata, true);
out: out:
had_substream_put(intelhaddata); had_substream_put(intelhaddata);
@ -1389,7 +1374,7 @@ static void had_process_hot_unplug(struct snd_intelhad *intelhaddata)
} }
/* Disable Audio */ /* Disable Audio */
had_enable_audio(substream, intelhaddata, false); had_enable_audio(intelhaddata, false);
intelhaddata->connected = false; intelhaddata->connected = false;
dev_dbg(intelhaddata->dev, dev_dbg(intelhaddata->dev,

View File

@ -127,6 +127,7 @@ struct snd_intelhad {
int irq; int irq;
void __iomem *mmio_start; void __iomem *mmio_start;
unsigned int had_config_offset; unsigned int had_config_offset;
union aud_cfg aud_config; /* AUD_CONFIG reg value cache */
struct work_struct hdmi_audio_wq; struct work_struct hdmi_audio_wq;
struct mutex mutex; /* for protecting chmap and eld */ struct mutex mutex; /* for protecting chmap and eld */
}; };