diff options
Diffstat (limited to 'sound/pci/ca0106/ca0106_main.c')
-rw-r--r-- | sound/pci/ca0106/ca0106_main.c | 136 |
1 files changed, 93 insertions, 43 deletions
diff --git a/sound/pci/ca0106/ca0106_main.c b/sound/pci/ca0106/ca0106_main.c index 0a3d3d6e77b4..d2d12c08f937 100644 --- a/sound/pci/ca0106/ca0106_main.c +++ b/sound/pci/ca0106/ca0106_main.c | |||
@@ -227,7 +227,7 @@ static struct snd_ca0106_details ca0106_chip_details[] = { | |||
227 | .name = "Audigy SE [SB0570]", | 227 | .name = "Audigy SE [SB0570]", |
228 | .gpio_type = 1, | 228 | .gpio_type = 1, |
229 | .i2c_adc = 1, | 229 | .i2c_adc = 1, |
230 | .spi_dac = 1 } , | 230 | .spi_dac = 0x4021 } , |
231 | /* New Audigy LS. Has a different DAC. */ | 231 | /* New Audigy LS. Has a different DAC. */ |
232 | /* SB0570: | 232 | /* SB0570: |
233 | * CTRL:CA0106-DAT | 233 | * CTRL:CA0106-DAT |
@@ -238,7 +238,17 @@ static struct snd_ca0106_details ca0106_chip_details[] = { | |||
238 | .name = "Audigy SE OEM [SB0570a]", | 238 | .name = "Audigy SE OEM [SB0570a]", |
239 | .gpio_type = 1, | 239 | .gpio_type = 1, |
240 | .i2c_adc = 1, | 240 | .i2c_adc = 1, |
241 | .spi_dac = 1 } , | 241 | .spi_dac = 0x4021 } , |
242 | /* Sound Blaster 5.1vx | ||
243 | * Tested: Playback on front, rear, center/lfe speakers | ||
244 | * Not-Tested: Capture | ||
245 | */ | ||
246 | { .serial = 0x10041102, | ||
247 | .name = "Sound Blaster 5.1vx [SB1070]", | ||
248 | .gpio_type = 1, | ||
249 | .i2c_adc = 0, | ||
250 | .spi_dac = 0x0124 | ||
251 | } , | ||
242 | /* MSI K8N Diamond Motherboard with onboard SB Live 24bit without AC97 */ | 252 | /* MSI K8N Diamond Motherboard with onboard SB Live 24bit without AC97 */ |
243 | /* SB0438 | 253 | /* SB0438 |
244 | * CTRL:CA0106-DAT | 254 | * CTRL:CA0106-DAT |
@@ -254,7 +264,7 @@ static struct snd_ca0106_details ca0106_chip_details[] = { | |||
254 | .name = "MSI K8N Diamond MB", | 264 | .name = "MSI K8N Diamond MB", |
255 | .gpio_type = 2, | 265 | .gpio_type = 2, |
256 | .i2c_adc = 1, | 266 | .i2c_adc = 1, |
257 | .spi_dac = 1 } , | 267 | .spi_dac = 0x4021 } , |
258 | /* Giga-byte GA-G1975X mobo | 268 | /* Giga-byte GA-G1975X mobo |
259 | * Novell bnc#395807 | 269 | * Novell bnc#395807 |
260 | */ | 270 | */ |
@@ -483,16 +493,18 @@ static void snd_ca0106_pcm_free_substream(struct snd_pcm_runtime *runtime) | |||
483 | } | 493 | } |
484 | 494 | ||
485 | static const int spi_dacd_reg[] = { | 495 | static const int spi_dacd_reg[] = { |
486 | [PCM_FRONT_CHANNEL] = SPI_DACD4_REG, | 496 | SPI_DACD0_REG, |
487 | [PCM_REAR_CHANNEL] = SPI_DACD0_REG, | 497 | SPI_DACD1_REG, |
488 | [PCM_CENTER_LFE_CHANNEL]= SPI_DACD2_REG, | 498 | SPI_DACD2_REG, |
489 | [PCM_UNKNOWN_CHANNEL] = SPI_DACD1_REG, | 499 | 0, |
500 | SPI_DACD4_REG, | ||
490 | }; | 501 | }; |
491 | static const int spi_dacd_bit[] = { | 502 | static const int spi_dacd_bit[] = { |
492 | [PCM_FRONT_CHANNEL] = SPI_DACD4_BIT, | 503 | SPI_DACD0_BIT, |
493 | [PCM_REAR_CHANNEL] = SPI_DACD0_BIT, | 504 | SPI_DACD1_BIT, |
494 | [PCM_CENTER_LFE_CHANNEL]= SPI_DACD2_BIT, | 505 | SPI_DACD2_BIT, |
495 | [PCM_UNKNOWN_CHANNEL] = SPI_DACD1_BIT, | 506 | 0, |
507 | SPI_DACD4_BIT, | ||
496 | }; | 508 | }; |
497 | 509 | ||
498 | static void restore_spdif_bits(struct snd_ca0106 *chip, int idx) | 510 | static void restore_spdif_bits(struct snd_ca0106 *chip, int idx) |
@@ -504,6 +516,45 @@ static void restore_spdif_bits(struct snd_ca0106 *chip, int idx) | |||
504 | } | 516 | } |
505 | } | 517 | } |
506 | 518 | ||
519 | static int snd_ca0106_channel_dac(struct snd_ca0106_details *details, | ||
520 | int channel_id) | ||
521 | { | ||
522 | switch (channel_id) { | ||
523 | case PCM_FRONT_CHANNEL: | ||
524 | return (details->spi_dac & 0xf000) >> (4 * 3); | ||
525 | case PCM_REAR_CHANNEL: | ||
526 | return (details->spi_dac & 0x0f00) >> (4 * 2); | ||
527 | case PCM_CENTER_LFE_CHANNEL: | ||
528 | return (details->spi_dac & 0x00f0) >> (4 * 1); | ||
529 | case PCM_UNKNOWN_CHANNEL: | ||
530 | return (details->spi_dac & 0x000f) >> (4 * 0); | ||
531 | default: | ||
532 | snd_printk(KERN_DEBUG "ca0106: unknown channel_id %d\n", | ||
533 | channel_id); | ||
534 | } | ||
535 | return 0; | ||
536 | } | ||
537 | |||
538 | static int snd_ca0106_pcm_power_dac(struct snd_ca0106 *chip, int channel_id, | ||
539 | int power) | ||
540 | { | ||
541 | if (chip->details->spi_dac) { | ||
542 | const int dac = snd_ca0106_channel_dac(chip->details, | ||
543 | channel_id); | ||
544 | const int reg = spi_dacd_reg[dac]; | ||
545 | const int bit = spi_dacd_bit[dac]; | ||
546 | |||
547 | if (power) | ||
548 | /* Power up */ | ||
549 | chip->spi_dac_reg[reg] &= ~bit; | ||
550 | else | ||
551 | /* Power down */ | ||
552 | chip->spi_dac_reg[reg] |= bit; | ||
553 | return snd_ca0106_spi_write(chip, chip->spi_dac_reg[reg]); | ||
554 | } | ||
555 | return 0; | ||
556 | } | ||
557 | |||
507 | /* open_playback callback */ | 558 | /* open_playback callback */ |
508 | static int snd_ca0106_pcm_open_playback_channel(struct snd_pcm_substream *substream, | 559 | static int snd_ca0106_pcm_open_playback_channel(struct snd_pcm_substream *substream, |
509 | int channel_id) | 560 | int channel_id) |
@@ -543,12 +594,9 @@ static int snd_ca0106_pcm_open_playback_channel(struct snd_pcm_substream *substr | |||
543 | return err; | 594 | return err; |
544 | snd_pcm_set_sync(substream); | 595 | snd_pcm_set_sync(substream); |
545 | 596 | ||
546 | if (chip->details->spi_dac && channel_id != PCM_FRONT_CHANNEL) { | 597 | /* Front channel dac should already be on */ |
547 | const int reg = spi_dacd_reg[channel_id]; | 598 | if (channel_id != PCM_FRONT_CHANNEL) { |
548 | 599 | err = snd_ca0106_pcm_power_dac(chip, channel_id, 1); | |
549 | /* Power up dac */ | ||
550 | chip->spi_dac_reg[reg] &= ~spi_dacd_bit[channel_id]; | ||
551 | err = snd_ca0106_spi_write(chip, chip->spi_dac_reg[reg]); | ||
552 | if (err < 0) | 600 | if (err < 0) |
553 | return err; | 601 | return err; |
554 | } | 602 | } |
@@ -568,13 +616,14 @@ static int snd_ca0106_pcm_close_playback(struct snd_pcm_substream *substream) | |||
568 | 616 | ||
569 | restore_spdif_bits(chip, epcm->channel_id); | 617 | restore_spdif_bits(chip, epcm->channel_id); |
570 | 618 | ||
571 | if (chip->details->spi_dac && epcm->channel_id != PCM_FRONT_CHANNEL) { | 619 | /* Front channel dac should stay on */ |
572 | const int reg = spi_dacd_reg[epcm->channel_id]; | 620 | if (epcm->channel_id != PCM_FRONT_CHANNEL) { |
573 | 621 | int err; | |
574 | /* Power down DAC */ | 622 | err = snd_ca0106_pcm_power_dac(chip, epcm->channel_id, 0); |
575 | chip->spi_dac_reg[reg] |= spi_dacd_bit[epcm->channel_id]; | 623 | if (err < 0) |
576 | snd_ca0106_spi_write(chip, chip->spi_dac_reg[reg]); | 624 | return err; |
577 | } | 625 | } |
626 | |||
578 | /* FIXME: maybe zero others */ | 627 | /* FIXME: maybe zero others */ |
579 | return 0; | 628 | return 0; |
580 | } | 629 | } |
@@ -1002,29 +1051,27 @@ snd_ca0106_pcm_pointer_playback(struct snd_pcm_substream *substream) | |||
1002 | struct snd_ca0106 *emu = snd_pcm_substream_chip(substream); | 1051 | struct snd_ca0106 *emu = snd_pcm_substream_chip(substream); |
1003 | struct snd_pcm_runtime *runtime = substream->runtime; | 1052 | struct snd_pcm_runtime *runtime = substream->runtime; |
1004 | struct snd_ca0106_pcm *epcm = runtime->private_data; | 1053 | struct snd_ca0106_pcm *epcm = runtime->private_data; |
1005 | snd_pcm_uframes_t ptr, ptr1, ptr2,ptr3,ptr4 = 0; | 1054 | unsigned int ptr, prev_ptr; |
1006 | int channel = epcm->channel_id; | 1055 | int channel = epcm->channel_id; |
1056 | int timeout = 10; | ||
1007 | 1057 | ||
1008 | if (!epcm->running) | 1058 | if (!epcm->running) |
1009 | return 0; | 1059 | return 0; |
1010 | 1060 | ||
1011 | ptr3 = snd_ca0106_ptr_read(emu, PLAYBACK_LIST_PTR, channel); | 1061 | prev_ptr = -1; |
1012 | ptr1 = snd_ca0106_ptr_read(emu, PLAYBACK_POINTER, channel); | 1062 | do { |
1013 | ptr4 = snd_ca0106_ptr_read(emu, PLAYBACK_LIST_PTR, channel); | 1063 | ptr = snd_ca0106_ptr_read(emu, PLAYBACK_LIST_PTR, channel); |
1014 | if (ptr3 != ptr4) ptr1 = snd_ca0106_ptr_read(emu, PLAYBACK_POINTER, channel); | 1064 | ptr = (ptr >> 3) * runtime->period_size; |
1015 | ptr2 = bytes_to_frames(runtime, ptr1); | 1065 | ptr += bytes_to_frames(runtime, |
1016 | ptr2+= (ptr4 >> 3) * runtime->period_size; | 1066 | snd_ca0106_ptr_read(emu, PLAYBACK_POINTER, channel)); |
1017 | ptr=ptr2; | 1067 | if (ptr >= runtime->buffer_size) |
1018 | if (ptr >= runtime->buffer_size) | 1068 | ptr -= runtime->buffer_size; |
1019 | ptr -= runtime->buffer_size; | 1069 | if (prev_ptr == ptr) |
1020 | /* | 1070 | return ptr; |
1021 | printk(KERN_DEBUG "ptr1 = 0x%lx, ptr2=0x%lx, ptr=0x%lx, " | 1071 | prev_ptr = ptr; |
1022 | "buffer_size = 0x%x, period_size = 0x%x, bits=%d, rate=%d\n", | 1072 | } while (--timeout); |
1023 | ptr1, ptr2, ptr, (int)runtime->buffer_size, | 1073 | snd_printk(KERN_WARNING "ca0106: unstable DMA pointer!\n"); |
1024 | (int)runtime->period_size, (int)runtime->frame_bits, | 1074 | return 0; |
1025 | (int)runtime->rate); | ||
1026 | */ | ||
1027 | return ptr; | ||
1028 | } | 1075 | } |
1029 | 1076 | ||
1030 | /* pointer_capture callback */ | 1077 | /* pointer_capture callback */ |
@@ -1362,7 +1409,7 @@ static unsigned int spi_dac_init[] = { | |||
1362 | SPI_REG(12, 0x00), | 1409 | SPI_REG(12, 0x00), |
1363 | SPI_REG(SPI_LDA4_REG, SPI_DA_BIT_0dB), | 1410 | SPI_REG(SPI_LDA4_REG, SPI_DA_BIT_0dB), |
1364 | SPI_REG(SPI_RDA4_REG, SPI_DA_BIT_0dB | SPI_DA_BIT_UPDATE), | 1411 | SPI_REG(SPI_RDA4_REG, SPI_DA_BIT_0dB | SPI_DA_BIT_UPDATE), |
1365 | SPI_REG(SPI_DACD4_REG, 0x00), | 1412 | SPI_REG(SPI_DACD4_REG, SPI_DACD4_BIT), |
1366 | }; | 1413 | }; |
1367 | 1414 | ||
1368 | static unsigned int i2c_adc_init[][2] = { | 1415 | static unsigned int i2c_adc_init[][2] = { |
@@ -1541,7 +1588,7 @@ static void ca0106_init_chip(struct snd_ca0106 *chip, int resume) | |||
1541 | /* snd_ca0106_i2c_write(chip, ADC_MUX, ADC_MUX_LINEIN); */ | 1588 | /* snd_ca0106_i2c_write(chip, ADC_MUX, ADC_MUX_LINEIN); */ |
1542 | } | 1589 | } |
1543 | 1590 | ||
1544 | if (chip->details->spi_dac == 1) { | 1591 | if (chip->details->spi_dac) { |
1545 | /* The SB0570 use SPI to control DAC. */ | 1592 | /* The SB0570 use SPI to control DAC. */ |
1546 | int size, n; | 1593 | int size, n; |
1547 | 1594 | ||
@@ -1553,6 +1600,9 @@ static void ca0106_init_chip(struct snd_ca0106 *chip, int resume) | |||
1553 | if (reg < ARRAY_SIZE(chip->spi_dac_reg)) | 1600 | if (reg < ARRAY_SIZE(chip->spi_dac_reg)) |
1554 | chip->spi_dac_reg[reg] = spi_dac_init[n]; | 1601 | chip->spi_dac_reg[reg] = spi_dac_init[n]; |
1555 | } | 1602 | } |
1603 | |||
1604 | /* Enable front dac only */ | ||
1605 | snd_ca0106_pcm_power_dac(chip, PCM_FRONT_CHANNEL, 1); | ||
1556 | } | 1606 | } |
1557 | } | 1607 | } |
1558 | 1608 | ||