diff options
author | Takashi Iwai <tiwai@suse.de> | 2017-02-07 10:17:06 -0500 |
---|---|---|
committer | Takashi Iwai <tiwai@suse.de> | 2017-02-07 10:27:41 -0500 |
commit | 40ce4b5d70b0c7e70c3e831e56d2586b57b54915 (patch) | |
tree | e3ec74431c5cb7c7a89691ef12792e9852b23ba3 | |
parent | 77531beeb97d079fb422d2b78a0d75c564384310 (diff) |
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>
-rw-r--r-- | sound/x86/intel_hdmi_audio.c | 39 | ||||
-rw-r--r-- | sound/x86/intel_hdmi_audio.h | 1 |
2 files changed, 13 insertions, 27 deletions
diff --git a/sound/x86/intel_hdmi_audio.c b/sound/x86/intel_hdmi_audio.c index 34750c54663a..15147fec1a7e 100644 --- a/sound/x86/intel_hdmi_audio.c +++ b/sound/x86/intel_hdmi_audio.c | |||
@@ -212,30 +212,13 @@ static void had_write_register(struct snd_intelhad *ctx, u32 reg, u32 val) | |||
212 | * bad audio. The fix is to always write the AUD_CONFIG[6:4] with | 212 | * bad audio. The fix is to always write the AUD_CONFIG[6:4] with |
213 | * appropriate value when doing read-modify of AUD_CONFIG register. | 213 | * appropriate value when doing read-modify of AUD_CONFIG register. |
214 | */ | 214 | */ |
215 | static void had_enable_audio(struct snd_pcm_substream *substream, | 215 | static void had_enable_audio(struct snd_intelhad *intelhaddata, |
216 | struct snd_intelhad *intelhaddata, | ||
217 | bool enable) | 216 | bool enable) |
218 | { | 217 | { |
219 | union aud_cfg cfg_val = {.regval = 0}; | 218 | /* update the cached value */ |
220 | u8 channels; | 219 | intelhaddata->aud_config.regx.aud_en = enable; |
221 | u32 mask, val; | 220 | had_write_register(intelhaddata, AUD_CONFIG, |
222 | 221 | intelhaddata->aud_config.regval); | |
223 | /* | ||
224 | * If substream is NULL, there is no active stream. | ||
225 | * In this case just set channels to 2 | ||
226 | */ | ||
227 | channels = substream ? substream->runtime->channels : 2; | ||
228 | dev_dbg(intelhaddata->dev, "enable %d, ch=%d\n", enable, channels); | ||
229 | |||
230 | cfg_val.regx.num_ch = channels - 2; | ||
231 | if (enable) | ||
232 | cfg_val.regx.aud_en = 1; | ||
233 | mask = AUD_CONFIG_CH_MASK | 1; | ||
234 | |||
235 | had_read_register(intelhaddata, AUD_CONFIG, &val); | ||
236 | val &= ~mask; | ||
237 | val |= cfg_val.regval; | ||
238 | had_write_register(intelhaddata, AUD_CONFIG, val); | ||
239 | } | 222 | } |
240 | 223 | ||
241 | /* forcibly ACKs to both BUFFER_DONE and BUFFER_UNDERRUN interrupts */ | 224 | /* 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, | |||
360 | } | 343 | } |
361 | 344 | ||
362 | had_write_register(intelhaddata, AUD_CONFIG, cfg_val.regval); | 345 | had_write_register(intelhaddata, AUD_CONFIG, cfg_val.regval); |
346 | intelhaddata->aud_config = cfg_val; | ||
363 | return 0; | 347 | return 0; |
364 | } | 348 | } |
365 | 349 | ||
@@ -1004,6 +988,7 @@ static void had_process_buffer_underrun(struct snd_intelhad *intelhaddata) | |||
1004 | 988 | ||
1005 | /* Handle Underrun interrupt within Audio Unit */ | 989 | /* Handle Underrun interrupt within Audio Unit */ |
1006 | had_write_register(intelhaddata, AUD_CONFIG, 0); | 990 | had_write_register(intelhaddata, AUD_CONFIG, 0); |
991 | intelhaddata->aud_config.regval = 0; | ||
1007 | /* Reset buffer pointers */ | 992 | /* Reset buffer pointers */ |
1008 | had_reset_audio(intelhaddata); | 993 | had_reset_audio(intelhaddata); |
1009 | 994 | ||
@@ -1169,7 +1154,7 @@ static int had_pcm_trigger(struct snd_pcm_substream *substream, int cmd) | |||
1169 | 1154 | ||
1170 | /* Enable Audio */ | 1155 | /* Enable Audio */ |
1171 | had_ack_irqs(intelhaddata); /* FIXME: do we need this? */ | 1156 | had_ack_irqs(intelhaddata); /* FIXME: do we need this? */ |
1172 | had_enable_audio(substream, intelhaddata, true); | 1157 | had_enable_audio(intelhaddata, true); |
1173 | break; | 1158 | break; |
1174 | 1159 | ||
1175 | case SNDRV_PCM_TRIGGER_STOP: | 1160 | case SNDRV_PCM_TRIGGER_STOP: |
@@ -1182,7 +1167,7 @@ static int had_pcm_trigger(struct snd_pcm_substream *substream, int cmd) | |||
1182 | intelhaddata->stream_info.running = false; | 1167 | intelhaddata->stream_info.running = false; |
1183 | spin_unlock(&intelhaddata->had_spinlock); | 1168 | spin_unlock(&intelhaddata->had_spinlock); |
1184 | /* Disable Audio */ | 1169 | /* Disable Audio */ |
1185 | had_enable_audio(substream, intelhaddata, false); | 1170 | had_enable_audio(intelhaddata, false); |
1186 | /* Reset buffer pointers */ | 1171 | /* Reset buffer pointers */ |
1187 | had_reset_audio(intelhaddata); | 1172 | had_reset_audio(intelhaddata); |
1188 | break; | 1173 | break; |
@@ -1315,7 +1300,7 @@ static int had_process_mode_change(struct snd_intelhad *intelhaddata) | |||
1315 | return 0; | 1300 | return 0; |
1316 | 1301 | ||
1317 | /* Disable Audio */ | 1302 | /* Disable Audio */ |
1318 | had_enable_audio(substream, intelhaddata, false); | 1303 | had_enable_audio(intelhaddata, false); |
1319 | 1304 | ||
1320 | /* Update CTS value */ | 1305 | /* Update CTS value */ |
1321 | disp_samp_freq = intelhaddata->tmds_clock_speed; | 1306 | disp_samp_freq = intelhaddata->tmds_clock_speed; |
@@ -1334,7 +1319,7 @@ static int had_process_mode_change(struct snd_intelhad *intelhaddata) | |||
1334 | n_param, intelhaddata); | 1319 | n_param, intelhaddata); |
1335 | 1320 | ||
1336 | /* Enable Audio */ | 1321 | /* Enable Audio */ |
1337 | had_enable_audio(substream, intelhaddata, true); | 1322 | had_enable_audio(intelhaddata, true); |
1338 | 1323 | ||
1339 | out: | 1324 | out: |
1340 | had_substream_put(intelhaddata); | 1325 | had_substream_put(intelhaddata); |
@@ -1389,7 +1374,7 @@ static void had_process_hot_unplug(struct snd_intelhad *intelhaddata) | |||
1389 | } | 1374 | } |
1390 | 1375 | ||
1391 | /* Disable Audio */ | 1376 | /* Disable Audio */ |
1392 | had_enable_audio(substream, intelhaddata, false); | 1377 | had_enable_audio(intelhaddata, false); |
1393 | 1378 | ||
1394 | intelhaddata->connected = false; | 1379 | intelhaddata->connected = false; |
1395 | dev_dbg(intelhaddata->dev, | 1380 | dev_dbg(intelhaddata->dev, |
diff --git a/sound/x86/intel_hdmi_audio.h b/sound/x86/intel_hdmi_audio.h index fe8d99cb839f..a96728a4e7bc 100644 --- a/sound/x86/intel_hdmi_audio.h +++ b/sound/x86/intel_hdmi_audio.h | |||
@@ -127,6 +127,7 @@ struct snd_intelhad { | |||
127 | int irq; | 127 | int irq; |
128 | void __iomem *mmio_start; | 128 | void __iomem *mmio_start; |
129 | unsigned int had_config_offset; | 129 | unsigned int had_config_offset; |
130 | union aud_cfg aud_config; /* AUD_CONFIG reg value cache */ | ||
130 | struct work_struct hdmi_audio_wq; | 131 | struct work_struct hdmi_audio_wq; |
131 | struct mutex mutex; /* for protecting chmap and eld */ | 132 | struct mutex mutex; /* for protecting chmap and eld */ |
132 | }; | 133 | }; |