ALSA: ca0106: Move enabling of front dac out of hardcoded setup sequence.
[deliverable/linux.git] / sound / pci / ca0106 / ca0106_main.c
index 0a3d3d6e77b4d668bad27a929cda8fa174d1cd1c..46ae98d9cb49c7278145f9d318d4d64aa9833cfc 100644 (file)
@@ -239,6 +239,16 @@ static struct snd_ca0106_details ca0106_chip_details[] = {
           .gpio_type = 1,
           .i2c_adc = 1,
           .spi_dac = 1 } ,
+       /* Sound Blaster 5.1vx
+        * Tested: Playback on front, rear, center/lfe speakers
+        * Not-Tested: Capture
+        */
+       { .serial = 0x10041102,
+         .name   = "Sound Blaster 5.1vx [SB1070]",
+         .gpio_type = 1,
+         .i2c_adc = 0,
+         .spi_dac = 1
+        } ,
         /* MSI K8N Diamond Motherboard with onboard SB Live 24bit without AC97 */
         /* SB0438
          * CTRL:CA0106-DAT
@@ -504,6 +514,23 @@ static void restore_spdif_bits(struct snd_ca0106 *chip, int idx)
        }
 }
 
+static int snd_ca0106_pcm_power_dac(struct snd_ca0106 *chip, int channel_id,
+                                   int power)
+{
+       if (chip->details->spi_dac) {
+               const int reg = spi_dacd_reg[channel_id];
+
+               if (power)
+                       /* Power up */
+                       chip->spi_dac_reg[reg] &= ~spi_dacd_bit[channel_id];
+               else
+                       /* Power down */
+                       chip->spi_dac_reg[reg] |= spi_dacd_bit[channel_id];
+               return snd_ca0106_spi_write(chip, chip->spi_dac_reg[reg]);
+       }
+       return 0;
+}
+
 /* open_playback callback */
 static int snd_ca0106_pcm_open_playback_channel(struct snd_pcm_substream *substream,
                                                int channel_id)
@@ -543,12 +570,9 @@ static int snd_ca0106_pcm_open_playback_channel(struct snd_pcm_substream *substr
                 return err;
        snd_pcm_set_sync(substream);
 
-       if (chip->details->spi_dac && channel_id != PCM_FRONT_CHANNEL) {
-               const int reg = spi_dacd_reg[channel_id];
-
-               /* Power up dac */
-               chip->spi_dac_reg[reg] &= ~spi_dacd_bit[channel_id];
-               err = snd_ca0106_spi_write(chip, chip->spi_dac_reg[reg]);
+       /* Front channel dac should already be on */
+       if (channel_id != PCM_FRONT_CHANNEL) {
+               err = snd_ca0106_pcm_power_dac(chip, channel_id, 1);
                if (err < 0)
                        return err;
        }
@@ -568,13 +592,14 @@ static int snd_ca0106_pcm_close_playback(struct snd_pcm_substream *substream)
 
        restore_spdif_bits(chip, epcm->channel_id);
 
-       if (chip->details->spi_dac && epcm->channel_id != PCM_FRONT_CHANNEL) {
-               const int reg = spi_dacd_reg[epcm->channel_id];
-
-               /* Power down DAC */
-               chip->spi_dac_reg[reg] |= spi_dacd_bit[epcm->channel_id];
-               snd_ca0106_spi_write(chip, chip->spi_dac_reg[reg]);
+       /* Front channel dac should stay on */
+       if (epcm->channel_id != PCM_FRONT_CHANNEL) {
+               int err;
+               err = snd_ca0106_pcm_power_dac(chip, epcm->channel_id, 0);
+               if (err < 0)
+                       return err;
        }
+
        /* FIXME: maybe zero others */
        return 0;
 }
@@ -1002,29 +1027,27 @@ snd_ca0106_pcm_pointer_playback(struct snd_pcm_substream *substream)
        struct snd_ca0106 *emu = snd_pcm_substream_chip(substream);
        struct snd_pcm_runtime *runtime = substream->runtime;
        struct snd_ca0106_pcm *epcm = runtime->private_data;
-       snd_pcm_uframes_t ptr, ptr1, ptr2,ptr3,ptr4 = 0;
+       unsigned int ptr, prev_ptr;
        int channel = epcm->channel_id;
+       int timeout = 10;
 
        if (!epcm->running)
                return 0;
 
-       ptr3 = snd_ca0106_ptr_read(emu, PLAYBACK_LIST_PTR, channel);
-       ptr1 = snd_ca0106_ptr_read(emu, PLAYBACK_POINTER, channel);
-       ptr4 = snd_ca0106_ptr_read(emu, PLAYBACK_LIST_PTR, channel);
-       if (ptr3 != ptr4) ptr1 = snd_ca0106_ptr_read(emu, PLAYBACK_POINTER, channel);
-       ptr2 = bytes_to_frames(runtime, ptr1);
-       ptr2+= (ptr4 >> 3) * runtime->period_size;
-       ptr=ptr2;
-        if (ptr >= runtime->buffer_size)
-               ptr -= runtime->buffer_size;
-       /*
-       printk(KERN_DEBUG "ptr1 = 0x%lx, ptr2=0x%lx, ptr=0x%lx, "
-              "buffer_size = 0x%x, period_size = 0x%x, bits=%d, rate=%d\n",
-              ptr1, ptr2, ptr, (int)runtime->buffer_size,
-              (int)runtime->period_size, (int)runtime->frame_bits,
-              (int)runtime->rate);
-       */
-       return ptr;
+       prev_ptr = -1;
+       do {
+               ptr = snd_ca0106_ptr_read(emu, PLAYBACK_LIST_PTR, channel);
+               ptr = (ptr >> 3) * runtime->period_size;
+               ptr += bytes_to_frames(runtime,
+                       snd_ca0106_ptr_read(emu, PLAYBACK_POINTER, channel));
+               if (ptr >= runtime->buffer_size)
+                       ptr -= runtime->buffer_size;
+               if (prev_ptr == ptr)
+                       return ptr;
+               prev_ptr = ptr;
+       } while (--timeout);
+       snd_printk(KERN_WARNING "ca0106: unstable DMA pointer!\n");
+       return 0;
 }
 
 /* pointer_capture callback */
@@ -1362,7 +1385,7 @@ static unsigned int spi_dac_init[] = {
        SPI_REG(12,             0x00),
        SPI_REG(SPI_LDA4_REG,   SPI_DA_BIT_0dB),
        SPI_REG(SPI_RDA4_REG,   SPI_DA_BIT_0dB | SPI_DA_BIT_UPDATE),
-       SPI_REG(SPI_DACD4_REG,  0x00),
+       SPI_REG(SPI_DACD4_REG,  SPI_DACD4_BIT),
 };
 
 static unsigned int i2c_adc_init[][2] = {
@@ -1553,6 +1576,9 @@ static void ca0106_init_chip(struct snd_ca0106 *chip, int resume)
                        if (reg < ARRAY_SIZE(chip->spi_dac_reg))
                                chip->spi_dac_reg[reg] = spi_dac_init[n];
                }
+
+               /* Enable front dac only */
+               snd_ca0106_pcm_power_dac(chip, PCM_FRONT_CHANNEL, 1);
        }
 }
 
This page took 0.026596 seconds and 5 git commands to generate.