summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTakashi Iwai <tiwai@suse.de>2017-02-07 10:17:06 -0500
committerTakashi Iwai <tiwai@suse.de>2017-02-07 10:27:41 -0500
commit40ce4b5d70b0c7e70c3e831e56d2586b57b54915 (patch)
treee3ec74431c5cb7c7a89691ef12792e9852b23ba3
parent77531beeb97d079fb422d2b78a0d75c564384310 (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.c39
-rw-r--r--sound/x86/intel_hdmi_audio.h1
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 */
215static void had_enable_audio(struct snd_pcm_substream *substream, 215static 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
1339out: 1324out:
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};