diff options
Diffstat (limited to 'sound/isa/wss/wss_lib.c')
-rw-r--r-- | sound/isa/wss/wss_lib.c | 126 |
1 files changed, 100 insertions, 26 deletions
diff --git a/sound/isa/wss/wss_lib.c b/sound/isa/wss/wss_lib.c index 1688f07a14b0..57d1e8ee6bbb 100644 --- a/sound/isa/wss/wss_lib.c +++ b/sound/isa/wss/wss_lib.c | |||
@@ -380,7 +380,7 @@ static void snd_wss_busy_wait(struct snd_wss *chip) | |||
380 | for (timeout = 5; timeout > 0; timeout--) | 380 | for (timeout = 5; timeout > 0; timeout--) |
381 | wss_inb(chip, CS4231P(REGSEL)); | 381 | wss_inb(chip, CS4231P(REGSEL)); |
382 | /* end of cleanup sequence */ | 382 | /* end of cleanup sequence */ |
383 | for (timeout = 250; | 383 | for (timeout = 25000; |
384 | timeout > 0 && (wss_inb(chip, CS4231P(REGSEL)) & CS4231_INIT); | 384 | timeout > 0 && (wss_inb(chip, CS4231P(REGSEL)) & CS4231_INIT); |
385 | timeout--) | 385 | timeout--) |
386 | udelay(10); | 386 | udelay(10); |
@@ -413,6 +413,7 @@ void snd_wss_mce_down(struct snd_wss *chip) | |||
413 | unsigned long flags; | 413 | unsigned long flags; |
414 | unsigned long end_time; | 414 | unsigned long end_time; |
415 | int timeout; | 415 | int timeout; |
416 | int hw_mask = WSS_HW_CS4231_MASK | WSS_HW_CS4232_MASK | WSS_HW_AD1848; | ||
416 | 417 | ||
417 | snd_wss_busy_wait(chip); | 418 | snd_wss_busy_wait(chip); |
418 | 419 | ||
@@ -427,10 +428,8 @@ void snd_wss_mce_down(struct snd_wss *chip) | |||
427 | spin_unlock_irqrestore(&chip->reg_lock, flags); | 428 | spin_unlock_irqrestore(&chip->reg_lock, flags); |
428 | if (timeout == 0x80) | 429 | if (timeout == 0x80) |
429 | snd_printk("mce_down [0x%lx]: serious init problem - codec still busy\n", chip->port); | 430 | snd_printk("mce_down [0x%lx]: serious init problem - codec still busy\n", chip->port); |
430 | if ((timeout & CS4231_MCE) == 0 || | 431 | if ((timeout & CS4231_MCE) == 0 || !(chip->hardware & hw_mask)) |
431 | !(chip->hardware & (WSS_HW_CS4231_MASK | WSS_HW_CS4232_MASK))) { | ||
432 | return; | 432 | return; |
433 | } | ||
434 | 433 | ||
435 | /* | 434 | /* |
436 | * Wait for (possible -- during init auto-calibration may not be set) | 435 | * Wait for (possible -- during init auto-calibration may not be set) |
@@ -601,12 +600,14 @@ static void snd_wss_calibrate_mute(struct snd_wss *chip, int mute) | |||
601 | mute ? 0x80 : chip->image[CS4231_LEFT_OUTPUT]); | 600 | mute ? 0x80 : chip->image[CS4231_LEFT_OUTPUT]); |
602 | snd_wss_dout(chip, CS4231_RIGHT_OUTPUT, | 601 | snd_wss_dout(chip, CS4231_RIGHT_OUTPUT, |
603 | mute ? 0x80 : chip->image[CS4231_RIGHT_OUTPUT]); | 602 | mute ? 0x80 : chip->image[CS4231_RIGHT_OUTPUT]); |
604 | snd_wss_dout(chip, CS4231_LEFT_LINE_IN, | 603 | if (!(chip->hardware & WSS_HW_AD1848_MASK)) { |
605 | mute ? 0x80 : chip->image[CS4231_LEFT_LINE_IN]); | 604 | snd_wss_dout(chip, CS4231_LEFT_LINE_IN, |
606 | snd_wss_dout(chip, CS4231_RIGHT_LINE_IN, | 605 | mute ? 0x80 : chip->image[CS4231_LEFT_LINE_IN]); |
607 | mute ? 0x80 : chip->image[CS4231_RIGHT_LINE_IN]); | 606 | snd_wss_dout(chip, CS4231_RIGHT_LINE_IN, |
608 | snd_wss_dout(chip, CS4231_MONO_CTRL, | 607 | mute ? 0x80 : chip->image[CS4231_RIGHT_LINE_IN]); |
609 | mute ? 0xc0 : chip->image[CS4231_MONO_CTRL]); | 608 | snd_wss_dout(chip, CS4231_MONO_CTRL, |
609 | mute ? 0xc0 : chip->image[CS4231_MONO_CTRL]); | ||
610 | } | ||
610 | if (chip->hardware == WSS_HW_INTERWAVE) { | 611 | if (chip->hardware == WSS_HW_INTERWAVE) { |
611 | snd_wss_dout(chip, CS4231_LEFT_MIC_INPUT, | 612 | snd_wss_dout(chip, CS4231_LEFT_MIC_INPUT, |
612 | mute ? 0x80 : chip->image[CS4231_LEFT_MIC_INPUT]); | 613 | mute ? 0x80 : chip->image[CS4231_LEFT_MIC_INPUT]); |
@@ -706,7 +707,10 @@ static void snd_wss_capture_format(struct snd_wss *chip, | |||
706 | snd_wss_mce_up(chip); | 707 | snd_wss_mce_up(chip); |
707 | spin_lock_irqsave(&chip->reg_lock, flags); | 708 | spin_lock_irqsave(&chip->reg_lock, flags); |
708 | } | 709 | } |
709 | snd_wss_out(chip, CS4231_REC_FORMAT, cdfr); | 710 | if (chip->hardware & WSS_HW_AD1848_MASK) |
711 | snd_wss_out(chip, CS4231_PLAYBK_FORMAT, cdfr); | ||
712 | else | ||
713 | snd_wss_out(chip, CS4231_REC_FORMAT, cdfr); | ||
710 | spin_unlock_irqrestore(&chip->reg_lock, flags); | 714 | spin_unlock_irqrestore(&chip->reg_lock, flags); |
711 | snd_wss_mce_down(chip); | 715 | snd_wss_mce_down(chip); |
712 | } | 716 | } |
@@ -818,7 +822,9 @@ static void snd_wss_init(struct snd_wss *chip) | |||
818 | 822 | ||
819 | snd_wss_mce_up(chip); | 823 | snd_wss_mce_up(chip); |
820 | spin_lock_irqsave(&chip->reg_lock, flags); | 824 | spin_lock_irqsave(&chip->reg_lock, flags); |
821 | snd_wss_out(chip, CS4231_REC_FORMAT, chip->image[CS4231_REC_FORMAT]); | 825 | if (!(chip->hardware & WSS_HW_AD1848_MASK)) |
826 | snd_wss_out(chip, CS4231_REC_FORMAT, | ||
827 | chip->image[CS4231_REC_FORMAT]); | ||
822 | spin_unlock_irqrestore(&chip->reg_lock, flags); | 828 | spin_unlock_irqrestore(&chip->reg_lock, flags); |
823 | snd_wss_mce_down(chip); | 829 | snd_wss_mce_down(chip); |
824 | 830 | ||
@@ -844,20 +850,24 @@ static int snd_wss_open(struct snd_wss *chip, unsigned int mode) | |||
844 | } | 850 | } |
845 | /* ok. now enable and ack CODEC IRQ */ | 851 | /* ok. now enable and ack CODEC IRQ */ |
846 | spin_lock_irqsave(&chip->reg_lock, flags); | 852 | spin_lock_irqsave(&chip->reg_lock, flags); |
847 | snd_wss_out(chip, CS4231_IRQ_STATUS, | 853 | if (!(chip->hardware & WSS_HW_AD1848_MASK)) { |
848 | CS4231_PLAYBACK_IRQ | | 854 | snd_wss_out(chip, CS4231_IRQ_STATUS, |
849 | CS4231_RECORD_IRQ | | 855 | CS4231_PLAYBACK_IRQ | |
850 | CS4231_TIMER_IRQ); | 856 | CS4231_RECORD_IRQ | |
851 | snd_wss_out(chip, CS4231_IRQ_STATUS, 0); | 857 | CS4231_TIMER_IRQ); |
858 | snd_wss_out(chip, CS4231_IRQ_STATUS, 0); | ||
859 | } | ||
852 | wss_outb(chip, CS4231P(STATUS), 0); /* clear IRQ */ | 860 | wss_outb(chip, CS4231P(STATUS), 0); /* clear IRQ */ |
853 | wss_outb(chip, CS4231P(STATUS), 0); /* clear IRQ */ | 861 | wss_outb(chip, CS4231P(STATUS), 0); /* clear IRQ */ |
854 | chip->image[CS4231_PIN_CTRL] |= CS4231_IRQ_ENABLE; | 862 | chip->image[CS4231_PIN_CTRL] |= CS4231_IRQ_ENABLE; |
855 | snd_wss_out(chip, CS4231_PIN_CTRL, chip->image[CS4231_PIN_CTRL]); | 863 | snd_wss_out(chip, CS4231_PIN_CTRL, chip->image[CS4231_PIN_CTRL]); |
856 | snd_wss_out(chip, CS4231_IRQ_STATUS, | 864 | if (!(chip->hardware & WSS_HW_AD1848_MASK)) { |
857 | CS4231_PLAYBACK_IRQ | | 865 | snd_wss_out(chip, CS4231_IRQ_STATUS, |
858 | CS4231_RECORD_IRQ | | 866 | CS4231_PLAYBACK_IRQ | |
859 | CS4231_TIMER_IRQ); | 867 | CS4231_RECORD_IRQ | |
860 | snd_wss_out(chip, CS4231_IRQ_STATUS, 0); | 868 | CS4231_TIMER_IRQ); |
869 | snd_wss_out(chip, CS4231_IRQ_STATUS, 0); | ||
870 | } | ||
861 | spin_unlock_irqrestore(&chip->reg_lock, flags); | 871 | spin_unlock_irqrestore(&chip->reg_lock, flags); |
862 | 872 | ||
863 | chip->mode = mode; | 873 | chip->mode = mode; |
@@ -879,7 +889,8 @@ static void snd_wss_close(struct snd_wss *chip, unsigned int mode) | |||
879 | 889 | ||
880 | /* disable IRQ */ | 890 | /* disable IRQ */ |
881 | spin_lock_irqsave(&chip->reg_lock, flags); | 891 | spin_lock_irqsave(&chip->reg_lock, flags); |
882 | snd_wss_out(chip, CS4231_IRQ_STATUS, 0); | 892 | if (!(chip->hardware & WSS_HW_AD1848_MASK)) |
893 | snd_wss_out(chip, CS4231_IRQ_STATUS, 0); | ||
883 | wss_outb(chip, CS4231P(STATUS), 0); /* clear IRQ */ | 894 | wss_outb(chip, CS4231P(STATUS), 0); /* clear IRQ */ |
884 | wss_outb(chip, CS4231P(STATUS), 0); /* clear IRQ */ | 895 | wss_outb(chip, CS4231P(STATUS), 0); /* clear IRQ */ |
885 | chip->image[CS4231_PIN_CTRL] &= ~CS4231_IRQ_ENABLE; | 896 | chip->image[CS4231_PIN_CTRL] &= ~CS4231_IRQ_ENABLE; |
@@ -902,7 +913,8 @@ static void snd_wss_close(struct snd_wss *chip, unsigned int mode) | |||
902 | } | 913 | } |
903 | 914 | ||
904 | /* clear IRQ again */ | 915 | /* clear IRQ again */ |
905 | snd_wss_out(chip, CS4231_IRQ_STATUS, 0); | 916 | if (!(chip->hardware & WSS_HW_AD1848_MASK)) |
917 | snd_wss_out(chip, CS4231_IRQ_STATUS, 0); | ||
906 | wss_outb(chip, CS4231P(STATUS), 0); /* clear IRQ */ | 918 | wss_outb(chip, CS4231P(STATUS), 0); /* clear IRQ */ |
907 | wss_outb(chip, CS4231P(STATUS), 0); /* clear IRQ */ | 919 | wss_outb(chip, CS4231P(STATUS), 0); /* clear IRQ */ |
908 | spin_unlock_irqrestore(&chip->reg_lock, flags); | 920 | spin_unlock_irqrestore(&chip->reg_lock, flags); |
@@ -1023,7 +1035,13 @@ static int snd_wss_capture_prepare(struct snd_pcm_substream *substream) | |||
1023 | chip->c_dma_size = size; | 1035 | chip->c_dma_size = size; |
1024 | chip->image[CS4231_IFACE_CTRL] &= ~(CS4231_RECORD_ENABLE | CS4231_RECORD_PIO); | 1036 | chip->image[CS4231_IFACE_CTRL] &= ~(CS4231_RECORD_ENABLE | CS4231_RECORD_PIO); |
1025 | snd_dma_program(chip->dma2, runtime->dma_addr, size, DMA_MODE_READ | DMA_AUTOINIT); | 1037 | snd_dma_program(chip->dma2, runtime->dma_addr, size, DMA_MODE_READ | DMA_AUTOINIT); |
1026 | count = snd_wss_get_count(chip->image[CS4231_REC_FORMAT], count) - 1; | 1038 | if (chip->hardware & WSS_HW_AD1848_MASK) |
1039 | count = snd_wss_get_count(chip->image[CS4231_PLAYBK_FORMAT], | ||
1040 | count); | ||
1041 | else | ||
1042 | count = snd_wss_get_count(chip->image[CS4231_REC_FORMAT], | ||
1043 | count); | ||
1044 | count--; | ||
1027 | if (chip->single_dma && chip->hardware != WSS_HW_INTERWAVE) { | 1045 | if (chip->single_dma && chip->hardware != WSS_HW_INTERWAVE) { |
1028 | snd_wss_out(chip, CS4231_PLY_LWR_CNT, (unsigned char) count); | 1046 | snd_wss_out(chip, CS4231_PLY_LWR_CNT, (unsigned char) count); |
1029 | snd_wss_out(chip, CS4231_PLY_UPR_CNT, | 1047 | snd_wss_out(chip, CS4231_PLY_UPR_CNT, |
@@ -1341,6 +1359,11 @@ static int snd_wss_playback_open(struct snd_pcm_substream *substream) | |||
1341 | 1359 | ||
1342 | runtime->hw = snd_wss_playback; | 1360 | runtime->hw = snd_wss_playback; |
1343 | 1361 | ||
1362 | /* hardware limitation of older chipsets */ | ||
1363 | if (chip->hardware & WSS_HW_AD1848_MASK) | ||
1364 | runtime->hw.formats &= ~(SNDRV_PCM_FMTBIT_IMA_ADPCM | | ||
1365 | SNDRV_PCM_FMTBIT_S16_BE); | ||
1366 | |||
1344 | /* hardware bug in InterWave chipset */ | 1367 | /* hardware bug in InterWave chipset */ |
1345 | if (chip->hardware == WSS_HW_INTERWAVE && chip->dma1 > 3) | 1368 | if (chip->hardware == WSS_HW_INTERWAVE && chip->dma1 > 3) |
1346 | runtime->hw.formats &= ~SNDRV_PCM_FMTBIT_MU_LAW; | 1369 | runtime->hw.formats &= ~SNDRV_PCM_FMTBIT_MU_LAW; |
@@ -1379,6 +1402,11 @@ static int snd_wss_capture_open(struct snd_pcm_substream *substream) | |||
1379 | 1402 | ||
1380 | runtime->hw = snd_wss_capture; | 1403 | runtime->hw = snd_wss_capture; |
1381 | 1404 | ||
1405 | /* hardware limitation of older chipsets */ | ||
1406 | if (chip->hardware & WSS_HW_AD1848_MASK) | ||
1407 | runtime->hw.formats &= ~(SNDRV_PCM_FMTBIT_IMA_ADPCM | | ||
1408 | SNDRV_PCM_FMTBIT_S16_BE); | ||
1409 | |||
1382 | /* hardware limitation of cheap chips */ | 1410 | /* hardware limitation of cheap chips */ |
1383 | if (chip->hardware == WSS_HW_CS4235 || | 1411 | if (chip->hardware == WSS_HW_CS4235 || |
1384 | chip->hardware == WSS_HW_CS4239) | 1412 | chip->hardware == WSS_HW_CS4239) |
@@ -1423,6 +1451,26 @@ static int snd_wss_capture_close(struct snd_pcm_substream *substream) | |||
1423 | return 0; | 1451 | return 0; |
1424 | } | 1452 | } |
1425 | 1453 | ||
1454 | static void snd_wss_thinkpad_twiddle(struct snd_wss *chip, int on) | ||
1455 | { | ||
1456 | int tmp; | ||
1457 | |||
1458 | if (!chip->thinkpad_flag) | ||
1459 | return; | ||
1460 | |||
1461 | outb(0x1c, AD1848_THINKPAD_CTL_PORT1); | ||
1462 | tmp = inb(AD1848_THINKPAD_CTL_PORT2); | ||
1463 | |||
1464 | if (on) | ||
1465 | /* turn it on */ | ||
1466 | tmp |= AD1848_THINKPAD_CS4248_ENABLE_BIT; | ||
1467 | else | ||
1468 | /* turn it off */ | ||
1469 | tmp &= ~AD1848_THINKPAD_CS4248_ENABLE_BIT; | ||
1470 | |||
1471 | outb(tmp, AD1848_THINKPAD_CTL_PORT2); | ||
1472 | } | ||
1473 | |||
1426 | #ifdef CONFIG_PM | 1474 | #ifdef CONFIG_PM |
1427 | 1475 | ||
1428 | /* lowlevel suspend callback for CS4231 */ | 1476 | /* lowlevel suspend callback for CS4231 */ |
@@ -1436,6 +1484,8 @@ static void snd_wss_suspend(struct snd_wss *chip) | |||
1436 | for (reg = 0; reg < 32; reg++) | 1484 | for (reg = 0; reg < 32; reg++) |
1437 | chip->image[reg] = snd_wss_in(chip, reg); | 1485 | chip->image[reg] = snd_wss_in(chip, reg); |
1438 | spin_unlock_irqrestore(&chip->reg_lock, flags); | 1486 | spin_unlock_irqrestore(&chip->reg_lock, flags); |
1487 | if (chip->thinkpad_flag) | ||
1488 | snd_wss_thinkpad_twiddle(chip, 0); | ||
1439 | } | 1489 | } |
1440 | 1490 | ||
1441 | /* lowlevel resume callback for CS4231 */ | 1491 | /* lowlevel resume callback for CS4231 */ |
@@ -1445,6 +1495,8 @@ static void snd_wss_resume(struct snd_wss *chip) | |||
1445 | unsigned long flags; | 1495 | unsigned long flags; |
1446 | /* int timeout; */ | 1496 | /* int timeout; */ |
1447 | 1497 | ||
1498 | if (chip->thinkpad_flag) | ||
1499 | snd_wss_thinkpad_twiddle(chip, 1); | ||
1448 | snd_wss_mce_up(chip); | 1500 | snd_wss_mce_up(chip); |
1449 | spin_lock_irqsave(&chip->reg_lock, flags); | 1501 | spin_lock_irqsave(&chip->reg_lock, flags); |
1450 | for (reg = 0; reg < 32; reg++) { | 1502 | for (reg = 0; reg < 32; reg++) { |
@@ -1542,6 +1594,14 @@ const char *snd_wss_chip_id(struct snd_wss *chip) | |||
1542 | return "AD1845"; | 1594 | return "AD1845"; |
1543 | case WSS_HW_OPTI93X: | 1595 | case WSS_HW_OPTI93X: |
1544 | return "OPTi 93x"; | 1596 | return "OPTi 93x"; |
1597 | case WSS_HW_AD1847: | ||
1598 | return "AD1847"; | ||
1599 | case WSS_HW_AD1848: | ||
1600 | return "AD1848"; | ||
1601 | case WSS_HW_CS4248: | ||
1602 | return "CS4248"; | ||
1603 | case WSS_HW_CMI8330: | ||
1604 | return "CMI8330/C3D"; | ||
1545 | default: | 1605 | default: |
1546 | return "???"; | 1606 | return "???"; |
1547 | } | 1607 | } |
@@ -1704,7 +1764,8 @@ int snd_wss_pcm(struct snd_wss *chip, int device, struct snd_pcm **rpcm) | |||
1704 | struct snd_pcm *pcm; | 1764 | struct snd_pcm *pcm; |
1705 | int err; | 1765 | int err; |
1706 | 1766 | ||
1707 | if ((err = snd_pcm_new(chip->card, "CS4231", device, 1, 1, &pcm)) < 0) | 1767 | err = snd_pcm_new(chip->card, "WSS", device, 1, 1, &pcm); |
1768 | if (err < 0) | ||
1708 | return err; | 1769 | return err; |
1709 | 1770 | ||
1710 | spin_lock_init(&chip->reg_lock); | 1771 | spin_lock_init(&chip->reg_lock); |
@@ -1714,6 +1775,12 @@ int snd_wss_pcm(struct snd_wss *chip, int device, struct snd_pcm **rpcm) | |||
1714 | snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &snd_wss_playback_ops); | 1775 | snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &snd_wss_playback_ops); |
1715 | snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_wss_capture_ops); | 1776 | snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_wss_capture_ops); |
1716 | 1777 | ||
1778 | /* temporary */ | ||
1779 | if (chip->hardware & WSS_HW_AD1848_MASK) { | ||
1780 | chip->rate_constraint = snd_wss_xrate; | ||
1781 | chip->set_playback_format = snd_wss_playback_format; | ||
1782 | chip->set_capture_format = snd_wss_capture_format; | ||
1783 | } | ||
1717 | /* global setup */ | 1784 | /* global setup */ |
1718 | pcm->private_data = chip; | 1785 | pcm->private_data = chip; |
1719 | pcm->info_flags = 0; | 1786 | pcm->info_flags = 0; |
@@ -2134,6 +2201,13 @@ int snd_wss_mixer(struct snd_wss *chip) | |||
2134 | } | 2201 | } |
2135 | EXPORT_SYMBOL(snd_wss_mixer); | 2202 | EXPORT_SYMBOL(snd_wss_mixer); |
2136 | 2203 | ||
2204 | const struct snd_pcm_ops *snd_wss_get_pcm_ops(int direction) | ||
2205 | { | ||
2206 | return direction == SNDRV_PCM_STREAM_PLAYBACK ? | ||
2207 | &snd_wss_playback_ops : &snd_wss_capture_ops; | ||
2208 | } | ||
2209 | EXPORT_SYMBOL(snd_wss_get_pcm_ops); | ||
2210 | |||
2137 | /* | 2211 | /* |
2138 | * INIT part | 2212 | * INIT part |
2139 | */ | 2213 | */ |