ALSA: x86: Cache AUD_CONFIG register value
authorTakashi Iwai <tiwai@suse.de>
Tue, 7 Feb 2017 15:17:06 +0000 (16:17 +0100)
committerTakashi Iwai <tiwai@suse.de>
Tue, 7 Feb 2017 15:27:41 +0000 (16:27 +0100)
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>
sound/x86/intel_hdmi_audio.c
sound/x86/intel_hdmi_audio.h

index 34750c54663a8907ae45e15929a2606f889cbc39..15147fec1a7ea930fa68ea7b7f5be3d704cd7138 100644 (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
  * appropriate value when doing read-modify of AUD_CONFIG register.
  */
-static void had_enable_audio(struct snd_pcm_substream *substream,
-                            struct snd_intelhad *intelhaddata,
+static void had_enable_audio(struct snd_intelhad *intelhaddata,
                             bool enable)
 {
-       union aud_cfg cfg_val = {.regval = 0};
-       u8 channels;
-       u32 mask, val;
-
-       /*
-        * 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);
+       /* update the cached value */
+       intelhaddata->aud_config.regx.aud_en = enable;
+       had_write_register(intelhaddata, AUD_CONFIG,
+                          intelhaddata->aud_config.regval);
 }
 
 /* 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);
+       intelhaddata->aud_config = cfg_val;
        return 0;
 }
 
@@ -1004,6 +988,7 @@ static void had_process_buffer_underrun(struct snd_intelhad *intelhaddata)
 
        /* Handle Underrun interrupt within Audio Unit */
        had_write_register(intelhaddata, AUD_CONFIG, 0);
+       intelhaddata->aud_config.regval = 0;
        /* Reset buffer pointers */
        had_reset_audio(intelhaddata);
 
@@ -1169,7 +1154,7 @@ static int had_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
 
                /* Enable Audio */
                had_ack_irqs(intelhaddata); /* FIXME: do we need this? */
-               had_enable_audio(substream, intelhaddata, true);
+               had_enable_audio(intelhaddata, true);
                break;
 
        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;
                spin_unlock(&intelhaddata->had_spinlock);
                /* Disable Audio */
-               had_enable_audio(substream, intelhaddata, false);
+               had_enable_audio(intelhaddata, false);
                /* Reset buffer pointers */
                had_reset_audio(intelhaddata);
                break;
@@ -1315,7 +1300,7 @@ static int had_process_mode_change(struct snd_intelhad *intelhaddata)
                return 0;
 
        /* Disable Audio */
-       had_enable_audio(substream, intelhaddata, false);
+       had_enable_audio(intelhaddata, false);
 
        /* Update CTS value */
        disp_samp_freq = intelhaddata->tmds_clock_speed;
@@ -1334,7 +1319,7 @@ static int had_process_mode_change(struct snd_intelhad *intelhaddata)
                     n_param, intelhaddata);
 
        /* Enable Audio */
-       had_enable_audio(substream, intelhaddata, true);
+       had_enable_audio(intelhaddata, true);
 
 out:
        had_substream_put(intelhaddata);
@@ -1389,7 +1374,7 @@ static void had_process_hot_unplug(struct snd_intelhad *intelhaddata)
        }
 
        /* Disable Audio */
-       had_enable_audio(substream, intelhaddata, false);
+       had_enable_audio(intelhaddata, false);
 
        intelhaddata->connected = false;
        dev_dbg(intelhaddata->dev,
index fe8d99cb839f0fbc5b56f6454b18e7d7145e4dd9..a96728a4e7bccb940996d98b79d7fa18eaca0ecb 100644 (file)
@@ -127,6 +127,7 @@ struct snd_intelhad {
        int irq;
        void __iomem *mmio_start;
        unsigned int had_config_offset;
+       union aud_cfg aud_config;       /* AUD_CONFIG reg value cache */
        struct work_struct hdmi_audio_wq;
        struct mutex mutex; /* for protecting chmap and eld */
 };